1 | /*
|
---|
2 | * IRremote
|
---|
3 | * Version 0.11 August, 2009
|
---|
4 | * Copyright 2009 Ken Shirriff
|
---|
5 | * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
|
---|
6 | *
|
---|
7 | * Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
|
---|
8 | * Modified by Mitra Ardron <mitra@mitra.biz>
|
---|
9 | * Added Sanyo and Mitsubishi controllers
|
---|
10 | * Modified Sony to spot the repeat codes that some Sony's send
|
---|
11 | *
|
---|
12 | * Interrupt code based on NECIRrcv by Joe Knapp
|
---|
13 | * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
|
---|
14 | * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
|
---|
15 | *
|
---|
16 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
|
---|
17 | */
|
---|
18 |
|
---|
19 | #include "IRremote.h"
|
---|
20 | #include "IRremoteInt.h"
|
---|
21 |
|
---|
22 | // Provides ISR
|
---|
23 | #include <avr/interrupt.h>
|
---|
24 |
|
---|
25 | volatile irparams_t irparams;
|
---|
26 |
|
---|
27 | // These versions of MATCH, MATCH_MARK, and MATCH_SPACE are only for debugging.
|
---|
28 | // To use them, set DEBUG in IRremoteInt.h
|
---|
29 | // Normally macros are used for efficiency
|
---|
30 | #ifdef DEBUG
|
---|
31 | int MATCH(int measured, int desired) {
|
---|
32 | Serial.print("Testing: ");
|
---|
33 | Serial.print(TICKS_LOW(desired), DEC);
|
---|
34 | Serial.print(" <= ");
|
---|
35 | Serial.print(measured, DEC);
|
---|
36 | Serial.print(" <= ");
|
---|
37 | Serial.println(TICKS_HIGH(desired), DEC);
|
---|
38 | return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);
|
---|
39 | }
|
---|
40 |
|
---|
41 | int MATCH_MARK(int measured_ticks, int desired_us) {
|
---|
42 | Serial.print("Testing mark ");
|
---|
43 | Serial.print(measured_ticks * USECPERTICK, DEC);
|
---|
44 | Serial.print(" vs ");
|
---|
45 | Serial.print(desired_us, DEC);
|
---|
46 | Serial.print(": ");
|
---|
47 | Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC);
|
---|
48 | Serial.print(" <= ");
|
---|
49 | Serial.print(measured_ticks, DEC);
|
---|
50 | Serial.print(" <= ");
|
---|
51 | Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
|
---|
52 | return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
|
---|
53 | }
|
---|
54 |
|
---|
55 | int MATCH_SPACE(int measured_ticks, int desired_us) {
|
---|
56 | Serial.print("Testing space ");
|
---|
57 | Serial.print(measured_ticks * USECPERTICK, DEC);
|
---|
58 | Serial.print(" vs ");
|
---|
59 | Serial.print(desired_us, DEC);
|
---|
60 | Serial.print(": ");
|
---|
61 | Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC);
|
---|
62 | Serial.print(" <= ");
|
---|
63 | Serial.print(measured_ticks, DEC);
|
---|
64 | Serial.print(" <= ");
|
---|
65 | Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
|
---|
66 | return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
|
---|
67 | }
|
---|
68 | #else
|
---|
69 | int MATCH(int measured, int desired) {return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);}
|
---|
70 | int MATCH_MARK(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us + MARK_EXCESS));}
|
---|
71 | int MATCH_SPACE(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us - MARK_EXCESS));}
|
---|
72 | #endif
|
---|
73 |
|
---|
74 | IRrecv::IRrecv(int recvpin)
|
---|
75 | {
|
---|
76 | irparams.recvpin = recvpin;
|
---|
77 | irparams.blinkflag = 0;
|
---|
78 | }
|
---|
79 |
|
---|
80 | // initialization
|
---|
81 | void IRrecv::enableIRIn() {
|
---|
82 | cli();
|
---|
83 | // setup pulse clock timer interrupt
|
---|
84 | //Prescale /8 (16M/8 = 0.5 microseconds per tick)
|
---|
85 | // Therefore, the timer interval can range from 0.5 to 128 microseconds
|
---|
86 | // depending on the reset value (255 to 0)
|
---|
87 | TIMER_CONFIG_NORMAL();
|
---|
88 |
|
---|
89 | //Timer2 Overflow Interrupt Enable
|
---|
90 | TIMER_ENABLE_INTR;
|
---|
91 |
|
---|
92 | TIMER_RESET;
|
---|
93 |
|
---|
94 | sei(); // enable interrupts
|
---|
95 |
|
---|
96 | // initialize state machine variables
|
---|
97 | irparams.rcvstate = STATE_IDLE;
|
---|
98 | irparams.rawlen = 0;
|
---|
99 |
|
---|
100 | // set pin modes
|
---|
101 | pinMode(irparams.recvpin, INPUT);
|
---|
102 | }
|
---|
103 |
|
---|
104 | // enable/disable blinking of pin 13 on IR processing
|
---|
105 | void IRrecv::blink13(int blinkflag)
|
---|
106 | {
|
---|
107 | irparams.blinkflag = blinkflag;
|
---|
108 | if (blinkflag)
|
---|
109 | pinMode(BLINKLED, OUTPUT);
|
---|
110 | }
|
---|
111 |
|
---|
112 | // TIMER2 interrupt code to collect raw data.
|
---|
113 | // Widths of alternating SPACE, MARK are recorded in rawbuf.
|
---|
114 | // Recorded in ticks of 50 microseconds.
|
---|
115 | // rawlen counts the number of entries recorded so far.
|
---|
116 | // First entry is the SPACE between transmissions.
|
---|
117 | // As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
|
---|
118 | // As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
|
---|
119 | ISR(TIMER_INTR_NAME)
|
---|
120 | {
|
---|
121 | TIMER_RESET;
|
---|
122 |
|
---|
123 | uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);
|
---|
124 |
|
---|
125 | irparams.timer++; // One more 50us tick
|
---|
126 | if (irparams.rawlen >= RAWBUF) {
|
---|
127 | // Buffer overflow
|
---|
128 | irparams.rcvstate = STATE_STOP;
|
---|
129 | }
|
---|
130 | switch(irparams.rcvstate) {
|
---|
131 | case STATE_IDLE: // In the middle of a gap
|
---|
132 | if (irdata == MARK) {
|
---|
133 | if (irparams.timer < GAP_TICKS) {
|
---|
134 | // Not big enough to be a gap.
|
---|
135 | irparams.timer = 0;
|
---|
136 | }
|
---|
137 | else {
|
---|
138 | // gap just ended, record duration and start recording transmission
|
---|
139 | irparams.rawlen = 0;
|
---|
140 | irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
---|
141 | irparams.timer = 0;
|
---|
142 | irparams.rcvstate = STATE_MARK;
|
---|
143 | }
|
---|
144 | }
|
---|
145 | break;
|
---|
146 | case STATE_MARK: // timing MARK
|
---|
147 | if (irdata == SPACE) { // MARK ended, record time
|
---|
148 | irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
---|
149 | irparams.timer = 0;
|
---|
150 | irparams.rcvstate = STATE_SPACE;
|
---|
151 | }
|
---|
152 | break;
|
---|
153 | case STATE_SPACE: // timing SPACE
|
---|
154 | if (irdata == MARK) { // SPACE just ended, record it
|
---|
155 | irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
---|
156 | irparams.timer = 0;
|
---|
157 | irparams.rcvstate = STATE_MARK;
|
---|
158 | }
|
---|
159 | else { // SPACE
|
---|
160 | if (irparams.timer > GAP_TICKS) {
|
---|
161 | // big SPACE, indicates gap between codes
|
---|
162 | // Mark current code as ready for processing
|
---|
163 | // Switch to STOP
|
---|
164 | // Don't reset timer; keep counting space width
|
---|
165 | irparams.rcvstate = STATE_STOP;
|
---|
166 | }
|
---|
167 | }
|
---|
168 | break;
|
---|
169 | case STATE_STOP: // waiting, measuring gap
|
---|
170 | if (irdata == MARK) { // reset gap timer
|
---|
171 | irparams.timer = 0;
|
---|
172 | }
|
---|
173 | break;
|
---|
174 | }
|
---|
175 |
|
---|
176 | if (irparams.blinkflag) {
|
---|
177 | if (irdata == MARK) {
|
---|
178 | BLINKLED_ON(); // turn pin 13 LED on
|
---|
179 | }
|
---|
180 | else {
|
---|
181 | BLINKLED_OFF(); // turn pin 13 LED off
|
---|
182 | }
|
---|
183 | }
|
---|
184 | }
|
---|
185 |
|
---|
186 | void IRrecv::resume() {
|
---|
187 | irparams.rcvstate = STATE_IDLE;
|
---|
188 | irparams.rawlen = 0;
|
---|
189 | }
|
---|
190 |
|
---|
191 |
|
---|
192 |
|
---|
193 | // Decodes the received IR message
|
---|
194 | // Returns 0 if no data ready, 1 if data ready.
|
---|
195 | // Results of decoding are stored in results
|
---|
196 | int IRrecv::decode(decode_results *results) {
|
---|
197 | results->rawbuf = irparams.rawbuf;
|
---|
198 | results->rawlen = irparams.rawlen;
|
---|
199 | if (irparams.rcvstate != STATE_STOP) {
|
---|
200 | return ERR;
|
---|
201 | }
|
---|
202 |
|
---|
203 | #ifdef DEBUG
|
---|
204 | Serial.println("Attempting NEC decode");
|
---|
205 | #endif
|
---|
206 | if (decodeNEC(results)) {
|
---|
207 | return DECODED;
|
---|
208 | }
|
---|
209 | /*
|
---|
210 | #ifdef DEBUG
|
---|
211 | Serial.println("Attempting Sony decode");
|
---|
212 | #endif
|
---|
213 | if (decodeSony(results)) {
|
---|
214 | return DECODED;
|
---|
215 | }*/
|
---|
216 | /*
|
---|
217 | #ifdef DEBUG
|
---|
218 | Serial.println("Attempting Sanyo decode");
|
---|
219 | #endif
|
---|
220 | if (decodeSanyo(results)) {
|
---|
221 | return DECODED;
|
---|
222 | }
|
---|
223 | */
|
---|
224 | /*
|
---|
225 | #ifdef DEBUG
|
---|
226 | Serial.println("Attempting Mitsubishi decode");
|
---|
227 | #endif
|
---|
228 | if (decodeMitsubishi(results)) {
|
---|
229 | return DECODED;
|
---|
230 | }*/
|
---|
231 | /*
|
---|
232 | #ifdef DEBUG
|
---|
233 | Serial.println("Attempting RC5 decode");
|
---|
234 | #endif
|
---|
235 | if (decodeRC5(results)) {
|
---|
236 | return DECODED;
|
---|
237 | }
|
---|
238 | */
|
---|
239 | /*
|
---|
240 | #ifdef DEBUG
|
---|
241 | Serial.println("Attempting RC6 decode");
|
---|
242 | #endif
|
---|
243 | if (decodeRC6(results)) {
|
---|
244 | return DECODED;
|
---|
245 | }
|
---|
246 | */
|
---|
247 | /*
|
---|
248 | #ifdef DEBUG
|
---|
249 | Serial.println("Attempting Panasonic decode");
|
---|
250 | #endif
|
---|
251 | if (decodePanasonic(results)) {
|
---|
252 | return DECODED;
|
---|
253 | }
|
---|
254 | */
|
---|
255 | /*
|
---|
256 | #ifdef DEBUG
|
---|
257 | Serial.println("Attempting JVC decode");
|
---|
258 | #endif
|
---|
259 | if (decodeJVC(results)) {
|
---|
260 | return DECODED;
|
---|
261 | }*/
|
---|
262 | // decodeHash returns a hash on any input.
|
---|
263 | // Thus, it needs to be last in the list.
|
---|
264 | // If you add any decodes, add them before this.
|
---|
265 | if (decodeHash(results)) {
|
---|
266 | return DECODED;
|
---|
267 | }
|
---|
268 | // Throw away and start over
|
---|
269 | resume();
|
---|
270 | return ERR;
|
---|
271 | }
|
---|
272 |
|
---|
273 |
|
---|
274 | // NECs have a repeat only 4 items long
|
---|
275 | long IRrecv::decodeNEC(decode_results *results) {
|
---|
276 | long data = 0;
|
---|
277 | int offset = 1; // Skip first space
|
---|
278 | // Initial mark
|
---|
279 | if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) {
|
---|
280 | return ERR;
|
---|
281 | }
|
---|
282 | offset++;
|
---|
283 | // Check for repeat
|
---|
284 | if (irparams.rawlen == 4 &&
|
---|
285 | MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) &&
|
---|
286 | MATCH_MARK(results->rawbuf[offset+1], NEC_BIT_MARK)) {
|
---|
287 | results->bits = 0;
|
---|
288 | results->value = REPEAT;
|
---|
289 | results->decode_type = NEC;
|
---|
290 | return DECODED;
|
---|
291 | }
|
---|
292 | if (irparams.rawlen < 2 * NEC_BITS + 4) {
|
---|
293 | return ERR;
|
---|
294 | }
|
---|
295 | // Initial space
|
---|
296 | if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) {
|
---|
297 | return ERR;
|
---|
298 | }
|
---|
299 | offset++;
|
---|
300 | for (int i = 0; i < NEC_BITS; i++) {
|
---|
301 | if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) {
|
---|
302 | return ERR;
|
---|
303 | }
|
---|
304 | offset++;
|
---|
305 | if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) {
|
---|
306 | data = (data << 1) | 1;
|
---|
307 | }
|
---|
308 | else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) {
|
---|
309 | data <<= 1;
|
---|
310 | }
|
---|
311 | else {
|
---|
312 | return ERR;
|
---|
313 | }
|
---|
314 | offset++;
|
---|
315 | }
|
---|
316 | // Success
|
---|
317 | results->bits = NEC_BITS;
|
---|
318 | results->value = data;
|
---|
319 | results->decode_type = NEC;
|
---|
320 | return DECODED;
|
---|
321 | }
|
---|
322 | /*
|
---|
323 | long IRrecv::decodeSony(decode_results *results) {
|
---|
324 | long data = 0;
|
---|
325 | if (irparams.rawlen < 2 * SONY_BITS + 2) {
|
---|
326 | return ERR;
|
---|
327 | }
|
---|
328 | int offset = 0; // Dont skip first space, check its size
|
---|
329 |
|
---|
330 | // Some Sony's deliver repeats fast after first
|
---|
331 | // unfortunately can't spot difference from of repeat from two fast clicks
|
---|
332 | if (results->rawbuf[offset] < SONY_DOUBLE_SPACE_USECS) {
|
---|
333 | // Serial.print("IR Gap found: ");
|
---|
334 | results->bits = 0;
|
---|
335 | results->value = REPEAT;
|
---|
336 | results->decode_type = SANYO;
|
---|
337 | return DECODED;
|
---|
338 | }
|
---|
339 | offset++;
|
---|
340 |
|
---|
341 | // Initial mark
|
---|
342 | if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) {
|
---|
343 | return ERR;
|
---|
344 | }
|
---|
345 | offset++;
|
---|
346 |
|
---|
347 | while (offset + 1 < irparams.rawlen) {
|
---|
348 | if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) {
|
---|
349 | break;
|
---|
350 | }
|
---|
351 | offset++;
|
---|
352 | if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) {
|
---|
353 | data = (data << 1) | 1;
|
---|
354 | }
|
---|
355 | else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) {
|
---|
356 | data <<= 1;
|
---|
357 | }
|
---|
358 | else {
|
---|
359 | return ERR;
|
---|
360 | }
|
---|
361 | offset++;
|
---|
362 | }
|
---|
363 |
|
---|
364 | // Success
|
---|
365 | results->bits = (offset - 1) / 2;
|
---|
366 | if (results->bits < 12) {
|
---|
367 | results->bits = 0;
|
---|
368 | return ERR;
|
---|
369 | }
|
---|
370 | results->value = data;
|
---|
371 | results->decode_type = SONY;
|
---|
372 | return DECODED;
|
---|
373 | }*/
|
---|
374 |
|
---|
375 | /*
|
---|
376 | // I think this is a Sanyo decoder - serial = SA 8650B
|
---|
377 | // Looks like Sony except for timings, 48 chars of data and time/space different
|
---|
378 | long IRrecv::decodeSanyo(decode_results *results) {
|
---|
379 | long data = 0;
|
---|
380 | if (irparams.rawlen < 2 * SANYO_BITS + 2) {
|
---|
381 | return ERR;
|
---|
382 | }
|
---|
383 | int offset = 0; // Skip first space
|
---|
384 | // Initial space
|
---|
385 | // Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay
|
---|
386 | //Serial.print("IR Gap: ");
|
---|
387 | //Serial.println( results->rawbuf[offset]);
|
---|
388 | //Serial.println( "test against:");
|
---|
389 | //Serial.println(results->rawbuf[offset]);
|
---|
390 |
|
---|
391 | if (results->rawbuf[offset] < SANYO_DOUBLE_SPACE_USECS) {
|
---|
392 | // Serial.print("IR Gap found: ");
|
---|
393 | results->bits = 0;
|
---|
394 | results->value = REPEAT;
|
---|
395 | results->decode_type = SANYO;
|
---|
396 | return DECODED;
|
---|
397 | }
|
---|
398 | offset++;
|
---|
399 |
|
---|
400 | // Initial mark
|
---|
401 | if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) {
|
---|
402 | return ERR;
|
---|
403 | }
|
---|
404 | offset++;
|
---|
405 |
|
---|
406 | // Skip Second Mark
|
---|
407 | if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) {
|
---|
408 | return ERR;
|
---|
409 | }
|
---|
410 | offset++;
|
---|
411 |
|
---|
412 | while (offset + 1 < irparams.rawlen) {
|
---|
413 | if (!MATCH_SPACE(results->rawbuf[offset], SANYO_HDR_SPACE)) {
|
---|
414 | break;
|
---|
415 | }
|
---|
416 | offset++;
|
---|
417 | if (MATCH_MARK(results->rawbuf[offset], SANYO_ONE_MARK)) {
|
---|
418 | data = (data << 1) | 1;
|
---|
419 | }
|
---|
420 | else if (MATCH_MARK(results->rawbuf[offset], SANYO_ZERO_MARK)) {
|
---|
421 | data <<= 1;
|
---|
422 | }
|
---|
423 | else {
|
---|
424 | return ERR;
|
---|
425 | }
|
---|
426 | offset++;
|
---|
427 | }
|
---|
428 |
|
---|
429 | // Success
|
---|
430 | results->bits = (offset - 1) / 2;
|
---|
431 | if (results->bits < 12) {
|
---|
432 | results->bits = 0;
|
---|
433 | return ERR;
|
---|
434 | }
|
---|
435 | results->value = data;
|
---|
436 | results->decode_type = SANYO;
|
---|
437 | return DECODED;
|
---|
438 | }
|
---|
439 | */
|
---|
440 | /*
|
---|
441 | // Looks like Sony except for timings, 48 chars of data and time/space different
|
---|
442 | long IRrecv::decodeMitsubishi(decode_results *results) {
|
---|
443 | // Serial.print("?!? decoding Mitsubishi:");Serial.print(irparams.rawlen); Serial.print(" want "); Serial.println( 2 * MITSUBISHI_BITS + 2);
|
---|
444 | long data = 0;
|
---|
445 | if (irparams.rawlen < 2 * MITSUBISHI_BITS + 2) {
|
---|
446 | return ERR;
|
---|
447 | }
|
---|
448 | int offset = 0; // Skip first space
|
---|
449 | // Initial space
|
---|
450 | // Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay
|
---|
451 | //Serial.print("IR Gap: ");
|
---|
452 | //Serial.println( results->rawbuf[offset]);
|
---|
453 | //Serial.println( "test against:");
|
---|
454 | //Serial.println(results->rawbuf[offset]);
|
---|
455 |
|
---|
456 | // Not seeing double keys from Mitsubishi
|
---|
457 | //if (results->rawbuf[offset] < MITSUBISHI_DOUBLE_SPACE_USECS) {
|
---|
458 | // Serial.print("IR Gap found: ");
|
---|
459 | // results->bits = 0;
|
---|
460 | // results->value = REPEAT;
|
---|
461 | // results->decode_type = MITSUBISHI;
|
---|
462 | // return DECODED;
|
---|
463 | //}
|
---|
464 |
|
---|
465 | offset++;
|
---|
466 |
|
---|
467 | // Typical
|
---|
468 | // 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7
|
---|
469 |
|
---|
470 | // Initial Space
|
---|
471 | if (!MATCH_MARK(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) {
|
---|
472 | return ERR;
|
---|
473 | }
|
---|
474 | offset++;
|
---|
475 | while (offset + 1 < irparams.rawlen) {
|
---|
476 | if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ONE_MARK)) {
|
---|
477 | data = (data << 1) | 1;
|
---|
478 | }
|
---|
479 | else if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ZERO_MARK)) {
|
---|
480 | data <<= 1;
|
---|
481 | }
|
---|
482 | else {
|
---|
483 | // Serial.println("A"); Serial.println(offset); Serial.println(results->rawbuf[offset]);
|
---|
484 | return ERR;
|
---|
485 | }
|
---|
486 | offset++;
|
---|
487 | if (!MATCH_SPACE(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) {
|
---|
488 | // Serial.println("B"); Serial.println(offset); Serial.println(results->rawbuf[offset]);
|
---|
489 | break;
|
---|
490 | }
|
---|
491 | offset++;
|
---|
492 | }
|
---|
493 |
|
---|
494 | // Success
|
---|
495 | results->bits = (offset - 1) / 2;
|
---|
496 | if (results->bits < MITSUBISHI_BITS) {
|
---|
497 | results->bits = 0;
|
---|
498 | return ERR;
|
---|
499 | }
|
---|
500 | results->value = data;
|
---|
501 | results->decode_type = MITSUBISHI;
|
---|
502 | return DECODED;
|
---|
503 | }*/
|
---|
504 |
|
---|
505 |
|
---|
506 | // Gets one undecoded level at a time from the raw buffer.
|
---|
507 | // The RC5/6 decoding is easier if the data is broken into time intervals.
|
---|
508 | // E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
|
---|
509 | // successive calls to getRClevel will return MARK, MARK, SPACE.
|
---|
510 | // offset and used are updated to keep track of the current position.
|
---|
511 | // t1 is the time interval for a single bit in microseconds.
|
---|
512 | // Returns -1 for error (measured time interval is not a multiple of t1).
|
---|
513 | int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) {
|
---|
514 | if (*offset >= results->rawlen) {
|
---|
515 | // After end of recorded buffer, assume SPACE.
|
---|
516 | return SPACE;
|
---|
517 | }
|
---|
518 | int width = results->rawbuf[*offset];
|
---|
519 | int val = ((*offset) % 2) ? MARK : SPACE;
|
---|
520 | int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS;
|
---|
521 |
|
---|
522 | int avail;
|
---|
523 | if (MATCH(width, t1 + correction)) {
|
---|
524 | avail = 1;
|
---|
525 | }
|
---|
526 | else if (MATCH(width, 2*t1 + correction)) {
|
---|
527 | avail = 2;
|
---|
528 | }
|
---|
529 | else if (MATCH(width, 3*t1 + correction)) {
|
---|
530 | avail = 3;
|
---|
531 | }
|
---|
532 | else {
|
---|
533 | return -1;
|
---|
534 | }
|
---|
535 |
|
---|
536 | (*used)++;
|
---|
537 | if (*used >= avail) {
|
---|
538 | *used = 0;
|
---|
539 | (*offset)++;
|
---|
540 | }
|
---|
541 | #ifdef DEBUG
|
---|
542 | if (val == MARK) {
|
---|
543 | Serial.println("MARK");
|
---|
544 | }
|
---|
545 | else {
|
---|
546 | Serial.println("SPACE");
|
---|
547 | }
|
---|
548 | #endif
|
---|
549 | return val;
|
---|
550 | }
|
---|
551 | /*
|
---|
552 | long IRrecv::decodeRC5(decode_results *results) {
|
---|
553 | if (irparams.rawlen < MIN_RC5_SAMPLES + 2) {
|
---|
554 | return ERR;
|
---|
555 | }
|
---|
556 | int offset = 1; // Skip gap space
|
---|
557 | long data = 0;
|
---|
558 | int used = 0;
|
---|
559 | // Get start bits
|
---|
560 | if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
|
---|
561 | if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return ERR;
|
---|
562 | if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
|
---|
563 | int nbits;
|
---|
564 | for (nbits = 0; offset < irparams.rawlen; nbits++) {
|
---|
565 | int levelA = getRClevel(results, &offset, &used, RC5_T1);
|
---|
566 | int levelB = getRClevel(results, &offset, &used, RC5_T1);
|
---|
567 | if (levelA == SPACE && levelB == MARK) {
|
---|
568 | // 1 bit
|
---|
569 | data = (data << 1) | 1;
|
---|
570 | }
|
---|
571 | else if (levelA == MARK && levelB == SPACE) {
|
---|
572 | // zero bit
|
---|
573 | data <<= 1;
|
---|
574 | }
|
---|
575 | else {
|
---|
576 | return ERR;
|
---|
577 | }
|
---|
578 | }
|
---|
579 |
|
---|
580 | // Success
|
---|
581 | results->bits = nbits;
|
---|
582 | results->value = data;
|
---|
583 | results->decode_type = RC5;
|
---|
584 | return DECODED;
|
---|
585 | }*/
|
---|
586 | /*
|
---|
587 | long IRrecv::decodeRC6(decode_results *results) {
|
---|
588 | if (results->rawlen < MIN_RC6_SAMPLES) {
|
---|
589 | return ERR;
|
---|
590 | }
|
---|
591 | int offset = 1; // Skip first space
|
---|
592 | // Initial mark
|
---|
593 | if (!MATCH_MARK(results->rawbuf[offset], RC6_HDR_MARK)) {
|
---|
594 | return ERR;
|
---|
595 | }
|
---|
596 | offset++;
|
---|
597 | if (!MATCH_SPACE(results->rawbuf[offset], RC6_HDR_SPACE)) {
|
---|
598 | return ERR;
|
---|
599 | }
|
---|
600 | offset++;
|
---|
601 | long data = 0;
|
---|
602 | int used = 0;
|
---|
603 | // Get start bit (1)
|
---|
604 | if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return ERR;
|
---|
605 | if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return ERR;
|
---|
606 | int nbits;
|
---|
607 | for (nbits = 0; offset < results->rawlen; nbits++) {
|
---|
608 | int levelA, levelB; // Next two levels
|
---|
609 | levelA = getRClevel(results, &offset, &used, RC6_T1);
|
---|
610 | if (nbits == 3) {
|
---|
611 | // T bit is double wide; make sure second half matches
|
---|
612 | if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
|
---|
613 | }
|
---|
614 | levelB = getRClevel(results, &offset, &used, RC6_T1);
|
---|
615 | if (nbits == 3) {
|
---|
616 | // T bit is double wide; make sure second half matches
|
---|
617 | if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
|
---|
618 | }
|
---|
619 | if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5
|
---|
620 | // 1 bit
|
---|
621 | data = (data << 1) | 1;
|
---|
622 | }
|
---|
623 | else if (levelA == SPACE && levelB == MARK) {
|
---|
624 | // zero bit
|
---|
625 | data <<= 1;
|
---|
626 | }
|
---|
627 | else {
|
---|
628 | return ERR; // Error
|
---|
629 | }
|
---|
630 | }
|
---|
631 | // Success
|
---|
632 | results->bits = nbits;
|
---|
633 | results->value = data;
|
---|
634 | results->decode_type = RC6;
|
---|
635 | return DECODED;
|
---|
636 | }*/
|
---|
637 | /*
|
---|
638 | long IRrecv::decodePanasonic(decode_results *results) {
|
---|
639 | unsigned long long data = 0;
|
---|
640 | int offset = 1;
|
---|
641 |
|
---|
642 | if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_MARK)) {
|
---|
643 | return ERR;
|
---|
644 | }
|
---|
645 | offset++;
|
---|
646 | if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_SPACE)) {
|
---|
647 | return ERR;
|
---|
648 | }
|
---|
649 | offset++;
|
---|
650 |
|
---|
651 | // decode address
|
---|
652 | for (int i = 0; i < PANASONIC_BITS; i++) {
|
---|
653 | if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_BIT_MARK)) {
|
---|
654 | return ERR;
|
---|
655 | }
|
---|
656 | if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ONE_SPACE)) {
|
---|
657 | data = (data << 1) | 1;
|
---|
658 | } else if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ZERO_SPACE)) {
|
---|
659 | data <<= 1;
|
---|
660 | } else {
|
---|
661 | return ERR;
|
---|
662 | }
|
---|
663 | offset++;
|
---|
664 | }
|
---|
665 | results->value = (unsigned long)data;
|
---|
666 | results->panasonicAddress = (unsigned int)(data >> 32);
|
---|
667 | results->decode_type = PANASONIC;
|
---|
668 | results->bits = PANASONIC_BITS;
|
---|
669 | return DECODED;
|
---|
670 | }*/
|
---|
671 | /*
|
---|
672 | long IRrecv::decodeJVC(decode_results *results) {
|
---|
673 | long data = 0;
|
---|
674 | int offset = 1; // Skip first space
|
---|
675 | // Check for repeat
|
---|
676 | if (irparams.rawlen - 1 == 33 &&
|
---|
677 | MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK) &&
|
---|
678 | MATCH_MARK(results->rawbuf[irparams.rawlen-1], JVC_BIT_MARK)) {
|
---|
679 | results->bits = 0;
|
---|
680 | results->value = REPEAT;
|
---|
681 | results->decode_type = JVC;
|
---|
682 | return DECODED;
|
---|
683 | }
|
---|
684 | // Initial mark
|
---|
685 | if (!MATCH_MARK(results->rawbuf[offset], JVC_HDR_MARK)) {
|
---|
686 | return ERR;
|
---|
687 | }
|
---|
688 | offset++;
|
---|
689 | if (irparams.rawlen < 2 * JVC_BITS + 1 ) {
|
---|
690 | return ERR;
|
---|
691 | }
|
---|
692 | // Initial space
|
---|
693 | if (!MATCH_SPACE(results->rawbuf[offset], JVC_HDR_SPACE)) {
|
---|
694 | return ERR;
|
---|
695 | }
|
---|
696 | offset++;
|
---|
697 | for (int i = 0; i < JVC_BITS; i++) {
|
---|
698 | if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)) {
|
---|
699 | return ERR;
|
---|
700 | }
|
---|
701 | offset++;
|
---|
702 | if (MATCH_SPACE(results->rawbuf[offset], JVC_ONE_SPACE)) {
|
---|
703 | data = (data << 1) | 1;
|
---|
704 | }
|
---|
705 | else if (MATCH_SPACE(results->rawbuf[offset], JVC_ZERO_SPACE)) {
|
---|
706 | data <<= 1;
|
---|
707 | }
|
---|
708 | else {
|
---|
709 | return ERR;
|
---|
710 | }
|
---|
711 | offset++;
|
---|
712 | }
|
---|
713 | //Stop bit
|
---|
714 | if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)){
|
---|
715 | return ERR;
|
---|
716 | }
|
---|
717 | // Success
|
---|
718 | results->bits = JVC_BITS;
|
---|
719 | results->value = data;
|
---|
720 | results->decode_type = JVC;
|
---|
721 | return DECODED;
|
---|
722 | }*/
|
---|
723 |
|
---|
724 | /* -----------------------------------------------------------------------
|
---|
725 | * hashdecode - decode an arbitrary IR code.
|
---|
726 | * Instead of decoding using a standard encoding scheme
|
---|
727 | * (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value.
|
---|
728 | *
|
---|
729 | * The algorithm: look at the sequence of MARK signals, and see if each one
|
---|
730 | * is shorter (0), the same length (1), or longer (2) than the previous.
|
---|
731 | * Do the same with the SPACE signals. Hszh the resulting sequence of 0's,
|
---|
732 | * 1's, and 2's to a 32-bit value. This will give a unique value for each
|
---|
733 | * different code (probably), for most code systems.
|
---|
734 | *
|
---|
735 | * http://arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html
|
---|
736 | */
|
---|
737 |
|
---|
738 | // Compare two tick values, returning 0 if newval is shorter,
|
---|
739 | // 1 if newval is equal, and 2 if newval is longer
|
---|
740 | // Use a tolerance of 20%
|
---|
741 | int IRrecv::compare(unsigned int oldval, unsigned int newval) {
|
---|
742 | if (newval < oldval * .8) {
|
---|
743 | return 0;
|
---|
744 | }
|
---|
745 | else if (oldval < newval * .8) {
|
---|
746 | return 2;
|
---|
747 | }
|
---|
748 | else {
|
---|
749 | return 1;
|
---|
750 | }
|
---|
751 | }
|
---|
752 |
|
---|
753 | // Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
|
---|
754 | #define FNV_PRIME_32 16777619
|
---|
755 | #define FNV_BASIS_32 2166136261
|
---|
756 |
|
---|
757 | /* Converts the raw code values into a 32-bit hash code.
|
---|
758 | * Hopefully this code is unique for each button.
|
---|
759 | * This isn't a "real" decoding, just an arbitrary value.
|
---|
760 | */
|
---|
761 | long IRrecv::decodeHash(decode_results *results) {
|
---|
762 | // Require at least 6 samples to prevent triggering on noise
|
---|
763 | if (results->rawlen < 6) {
|
---|
764 | return ERR;
|
---|
765 | }
|
---|
766 | long hash = FNV_BASIS_32;
|
---|
767 | for (int i = 1; i+2 < results->rawlen; i++) {
|
---|
768 | int value = compare(results->rawbuf[i], results->rawbuf[i+2]);
|
---|
769 | // Add value into the hash
|
---|
770 | hash = (hash * FNV_PRIME_32) ^ value;
|
---|
771 | }
|
---|
772 | results->value = hash;
|
---|
773 | results->bits = 32;
|
---|
774 | results->decode_type = UNKNOWN;
|
---|
775 | return DECODED;
|
---|
776 | }
|
---|
777 |
|
---|