155
|
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 * LG added by Darryl Smith (based on the JVC protocol)
|
|
18 */
|
|
19
|
|
20 #include "IRremote.h"
|
|
21 #include "IRremoteInt.h"
|
|
22
|
|
23 // Provides ISR
|
|
24 #include <avr/interrupt.h>
|
|
25
|
|
26 volatile irparams_t irparams;
|
|
27
|
|
28 // These versions of MATCH, MATCH_MARK, and MATCH_SPACE are only for debugging.
|
|
29 // To use them, set DEBUG in IRremoteInt.h
|
|
30 // Normally macros are used for efficiency
|
|
31 #ifdef DEBUG
|
|
32 int MATCH(int measured, int desired) {
|
|
33 Serial.print("Testing: ");
|
|
34 Serial.print(TICKS_LOW(desired), DEC);
|
|
35 Serial.print(" <= ");
|
|
36 Serial.print(measured, DEC);
|
|
37 Serial.print(" <= ");
|
|
38 Serial.println(TICKS_HIGH(desired), DEC);
|
|
39 return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);
|
|
40 }
|
|
41
|
|
42 int MATCH_MARK(int measured_ticks, int desired_us) {
|
|
43 Serial.print("Testing mark ");
|
|
44 Serial.print(measured_ticks * USECPERTICK, DEC);
|
|
45 Serial.print(" vs ");
|
|
46 Serial.print(desired_us, DEC);
|
|
47 Serial.print(": ");
|
|
48 Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC);
|
|
49 Serial.print(" <= ");
|
|
50 Serial.print(measured_ticks, DEC);
|
|
51 Serial.print(" <= ");
|
|
52 Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
|
|
53 return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
|
|
54 }
|
|
55
|
|
56 int MATCH_SPACE(int measured_ticks, int desired_us) {
|
|
57 Serial.print("Testing space ");
|
|
58 Serial.print(measured_ticks * USECPERTICK, DEC);
|
|
59 Serial.print(" vs ");
|
|
60 Serial.print(desired_us, DEC);
|
|
61 Serial.print(": ");
|
|
62 Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC);
|
|
63 Serial.print(" <= ");
|
|
64 Serial.print(measured_ticks, DEC);
|
|
65 Serial.print(" <= ");
|
|
66 Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
|
|
67 return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
|
|
68 }
|
|
69 #else
|
|
70 int MATCH(int measured, int desired) {return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);}
|
|
71 int MATCH_MARK(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us + MARK_EXCESS));}
|
|
72 int MATCH_SPACE(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us - MARK_EXCESS));}
|
|
73 // Debugging versions are in IRremote.cpp
|
|
74 #endif
|
|
75
|
|
76 void IRsend::sendNEC(unsigned long data, int nbits)
|
|
77 {
|
|
78 enableIROut(38);
|
|
79 mark(NEC_HDR_MARK);
|
|
80 space(NEC_HDR_SPACE);
|
|
81 for (int i = 0; i < nbits; i++) {
|
|
82 if (data & TOPBIT) {
|
|
83 mark(NEC_BIT_MARK);
|
|
84 space(NEC_ONE_SPACE);
|
|
85 }
|
|
86 else {
|
|
87 mark(NEC_BIT_MARK);
|
|
88 space(NEC_ZERO_SPACE);
|
|
89 }
|
|
90 data <<= 1;
|
|
91 }
|
|
92 mark(NEC_BIT_MARK);
|
|
93 space(0);
|
|
94 }
|
|
95
|
|
96 void IRsend::sendSony(unsigned long data, int nbits) {
|
|
97 enableIROut(40);
|
|
98 mark(SONY_HDR_MARK);
|
|
99 space(SONY_HDR_SPACE);
|
|
100 data = data << (32 - nbits);
|
|
101 for (int i = 0; i < nbits; i++) {
|
|
102 if (data & TOPBIT) {
|
|
103 mark(SONY_ONE_MARK);
|
|
104 space(SONY_HDR_SPACE);
|
|
105 }
|
|
106 else {
|
|
107 mark(SONY_ZERO_MARK);
|
|
108 space(SONY_HDR_SPACE);
|
|
109 }
|
|
110 data <<= 1;
|
|
111 }
|
|
112 }
|
|
113
|
|
114 void IRsend::sendRaw(unsigned int buf[], int len, int hz)
|
|
115 {
|
|
116 enableIROut(hz);
|
|
117 for (int i = 0; i < len; i++) {
|
|
118 if (i & 1) {
|
|
119 space(buf[i]);
|
|
120 }
|
|
121 else {
|
|
122 mark(buf[i]);
|
|
123 }
|
|
124 }
|
|
125 space(0); // Just to be sure
|
|
126 }
|
|
127
|
|
128 // Note: first bit must be a one (start bit)
|
|
129 void IRsend::sendRC5(unsigned long data, int nbits)
|
|
130 {
|
|
131 enableIROut(36);
|
|
132 data = data << (32 - nbits);
|
|
133 mark(RC5_T1); // First start bit
|
|
134 space(RC5_T1); // Second start bit
|
|
135 mark(RC5_T1); // Second start bit
|
|
136 for (int i = 0; i < nbits; i++) {
|
|
137 if (data & TOPBIT) {
|
|
138 space(RC5_T1); // 1 is space, then mark
|
|
139 mark(RC5_T1);
|
|
140 }
|
|
141 else {
|
|
142 mark(RC5_T1);
|
|
143 space(RC5_T1);
|
|
144 }
|
|
145 data <<= 1;
|
|
146 }
|
|
147 space(0); // Turn off at end
|
|
148 }
|
|
149
|
|
150 // Caller needs to take care of flipping the toggle bit
|
|
151 void IRsend::sendRC6(unsigned long data, int nbits)
|
|
152 {
|
|
153 enableIROut(36);
|
|
154 data = data << (32 - nbits);
|
|
155 mark(RC6_HDR_MARK);
|
|
156 space(RC6_HDR_SPACE);
|
|
157 mark(RC6_T1); // start bit
|
|
158 space(RC6_T1);
|
|
159 int t;
|
|
160 for (int i = 0; i < nbits; i++) {
|
|
161 if (i == 3) {
|
|
162 // double-wide trailer bit
|
|
163 t = 2 * RC6_T1;
|
|
164 }
|
|
165 else {
|
|
166 t = RC6_T1;
|
|
167 }
|
|
168 if (data & TOPBIT) {
|
|
169 mark(t);
|
|
170 space(t);
|
|
171 }
|
|
172 else {
|
|
173 space(t);
|
|
174 mark(t);
|
|
175 }
|
|
176
|
|
177 data <<= 1;
|
|
178 }
|
|
179 space(0); // Turn off at end
|
|
180 }
|
|
181 void IRsend::sendPanasonic(unsigned int address, unsigned long data) {
|
|
182 enableIROut(35);
|
|
183 mark(PANASONIC_HDR_MARK);
|
|
184 space(PANASONIC_HDR_SPACE);
|
|
185
|
|
186 for(int i=0;i<16;i++)
|
|
187 {
|
|
188 mark(PANASONIC_BIT_MARK);
|
|
189 if (address & 0x8000) {
|
|
190 space(PANASONIC_ONE_SPACE);
|
|
191 } else {
|
|
192 space(PANASONIC_ZERO_SPACE);
|
|
193 }
|
|
194 address <<= 1;
|
|
195 }
|
|
196 for (int i=0; i < 32; i++) {
|
|
197 mark(PANASONIC_BIT_MARK);
|
|
198 if (data & TOPBIT) {
|
|
199 space(PANASONIC_ONE_SPACE);
|
|
200 } else {
|
|
201 space(PANASONIC_ZERO_SPACE);
|
|
202 }
|
|
203 data <<= 1;
|
|
204 }
|
|
205 mark(PANASONIC_BIT_MARK);
|
|
206 space(0);
|
|
207 }
|
|
208 void IRsend::sendJVC(unsigned long data, int nbits, int repeat)
|
|
209 {
|
|
210 enableIROut(38);
|
|
211 data = data << (32 - nbits);
|
|
212 if (!repeat){
|
|
213 mark(JVC_HDR_MARK);
|
|
214 space(JVC_HDR_SPACE);
|
|
215 }
|
|
216 for (int i = 0; i < nbits; i++) {
|
|
217 if (data & TOPBIT) {
|
|
218 mark(JVC_BIT_MARK);
|
|
219 space(JVC_ONE_SPACE);
|
|
220 }
|
|
221 else {
|
|
222 mark(JVC_BIT_MARK);
|
|
223 space(JVC_ZERO_SPACE);
|
|
224 }
|
|
225 data <<= 1;
|
|
226 }
|
|
227 mark(JVC_BIT_MARK);
|
|
228 space(0);
|
|
229 }
|
|
230
|
|
231 void IRsend::sendSAMSUNG(unsigned long data, int nbits)
|
|
232 {
|
|
233 enableIROut(38);
|
|
234 mark(SAMSUNG_HDR_MARK);
|
|
235 space(SAMSUNG_HDR_SPACE);
|
|
236 for (int i = 0; i < nbits; i++) {
|
|
237 if (data & TOPBIT) {
|
|
238 mark(SAMSUNG_BIT_MARK);
|
|
239 space(SAMSUNG_ONE_SPACE);
|
|
240 }
|
|
241 else {
|
|
242 mark(SAMSUNG_BIT_MARK);
|
|
243 space(SAMSUNG_ZERO_SPACE);
|
|
244 }
|
|
245 data <<= 1;
|
|
246 }
|
|
247 mark(SAMSUNG_BIT_MARK);
|
|
248 space(0);
|
|
249 }
|
|
250
|
|
251 void IRsend::mark(int time) {
|
|
252 // Sends an IR mark for the specified number of microseconds.
|
|
253 // The mark output is modulated at the PWM frequency.
|
|
254 TIMER_ENABLE_PWM; // Enable pin 3 PWM output
|
|
255 if (time > 0) delayMicroseconds(time);
|
|
256 }
|
|
257
|
|
258 /* Leave pin off for time (given in microseconds) */
|
|
259 void IRsend::space(int time) {
|
|
260 // Sends an IR space for the specified number of microseconds.
|
|
261 // A space is no output, so the PWM output is disabled.
|
|
262 TIMER_DISABLE_PWM; // Disable pin 3 PWM output
|
|
263 if (time > 0) delayMicroseconds(time);
|
|
264 }
|
|
265
|
|
266 void IRsend::enableIROut(int khz) {
|
|
267 // Enables IR output. The khz value controls the modulation frequency in kilohertz.
|
|
268 // The IR output will be on pin 3 (OC2B).
|
|
269 // This routine is designed for 36-40KHz; if you use it for other values, it's up to you
|
|
270 // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
|
|
271 // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
|
|
272 // controlling the duty cycle.
|
|
273 // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
|
|
274 // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
|
|
275 // A few hours staring at the ATmega documentation and this will all make sense.
|
|
276 // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
|
|
277
|
|
278
|
|
279 // Disable the Timer2 Interrupt (which is used for receiving IR)
|
|
280 TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
|
|
281
|
|
282 pinMode(TIMER_PWM_PIN, OUTPUT);
|
|
283 digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
|
|
284
|
|
285 // COM2A = 00: disconnect OC2A
|
|
286 // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
|
|
287 // WGM2 = 101: phase-correct PWM with OCRA as top
|
|
288 // CS2 = 000: no prescaling
|
|
289 // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
|
|
290 TIMER_CONFIG_KHZ(khz);
|
|
291 }
|
|
292
|
|
293 IRrecv::IRrecv(int recvpin)
|
|
294 {
|
|
295 irparams.recvpin = recvpin;
|
|
296 irparams.blinkflag = 0;
|
|
297 }
|
|
298
|
|
299 // initialization
|
|
300 void IRrecv::enableIRIn() {
|
|
301 cli();
|
|
302 // setup pulse clock timer interrupt
|
|
303 //Prescale /8 (16M/8 = 0.5 microseconds per tick)
|
|
304 // Therefore, the timer interval can range from 0.5 to 128 microseconds
|
|
305 // depending on the reset value (255 to 0)
|
|
306 TIMER_CONFIG_NORMAL();
|
|
307
|
|
308 //Timer2 Overflow Interrupt Enable
|
|
309 TIMER_ENABLE_INTR;
|
|
310
|
|
311 TIMER_RESET;
|
|
312
|
|
313 sei(); // enable interrupts
|
|
314
|
|
315 // initialize state machine variables
|
|
316 irparams.rcvstate = STATE_IDLE;
|
|
317 irparams.rawlen = 0;
|
|
318
|
|
319 // set pin modes
|
|
320 pinMode(irparams.recvpin, INPUT);
|
|
321 }
|
|
322
|
|
323 // enable/disable blinking of pin 13 on IR processing
|
|
324 void IRrecv::blink13(int blinkflag)
|
|
325 {
|
|
326 irparams.blinkflag = blinkflag;
|
|
327 if (blinkflag)
|
|
328 pinMode(BLINKLED, OUTPUT);
|
|
329 }
|
|
330
|
|
331 // TIMER2 interrupt code to collect raw data.
|
|
332 // Widths of alternating SPACE, MARK are recorded in rawbuf.
|
|
333 // Recorded in ticks of 50 microseconds.
|
|
334 // rawlen counts the number of entries recorded so far.
|
|
335 // First entry is the SPACE between transmissions.
|
|
336 // As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
|
|
337 // As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
|
|
338 ISR(TIMER_INTR_NAME)
|
|
339 {
|
|
340 TIMER_RESET;
|
|
341
|
|
342 uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);
|
|
343
|
|
344 irparams.timer++; // One more 50us tick
|
|
345 if (irparams.rawlen >= RAWBUF) {
|
|
346 // Buffer overflow
|
|
347 irparams.rcvstate = STATE_STOP;
|
|
348 }
|
|
349 switch(irparams.rcvstate) {
|
|
350 case STATE_IDLE: // In the middle of a gap
|
|
351 if (irdata == MARK) {
|
|
352 if (irparams.timer < GAP_TICKS) {
|
|
353 // Not big enough to be a gap.
|
|
354 irparams.timer = 0;
|
|
355 }
|
|
356 else {
|
|
357 // gap just ended, record duration and start recording transmission
|
|
358 irparams.rawlen = 0;
|
|
359 irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
|
360 irparams.timer = 0;
|
|
361 irparams.rcvstate = STATE_MARK;
|
|
362 }
|
|
363 }
|
|
364 break;
|
|
365 case STATE_MARK: // timing MARK
|
|
366 if (irdata == SPACE) { // MARK ended, record time
|
|
367 irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
|
368 irparams.timer = 0;
|
|
369 irparams.rcvstate = STATE_SPACE;
|
|
370 }
|
|
371 break;
|
|
372 case STATE_SPACE: // timing SPACE
|
|
373 if (irdata == MARK) { // SPACE just ended, record it
|
|
374 irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
|
375 irparams.timer = 0;
|
|
376 irparams.rcvstate = STATE_MARK;
|
|
377 }
|
|
378 else { // SPACE
|
|
379 if (irparams.timer > GAP_TICKS) {
|
|
380 // big SPACE, indicates gap between codes
|
|
381 // Mark current code as ready for processing
|
|
382 // Switch to STOP
|
|
383 // Don't reset timer; keep counting space width
|
|
384 irparams.rcvstate = STATE_STOP;
|
|
385 }
|
|
386 }
|
|
387 break;
|
|
388 case STATE_STOP: // waiting, measuring gap
|
|
389 if (irdata == MARK) { // reset gap timer
|
|
390 irparams.timer = 0;
|
|
391 }
|
|
392 break;
|
|
393 }
|
|
394
|
|
395 if (irparams.blinkflag) {
|
|
396 if (irdata == MARK) {
|
|
397 BLINKLED_ON(); // turn pin 13 LED on
|
|
398 }
|
|
399 else {
|
|
400 BLINKLED_OFF(); // turn pin 13 LED off
|
|
401 }
|
|
402 }
|
|
403 }
|
|
404
|
|
405 void IRrecv::resume() {
|
|
406 irparams.rcvstate = STATE_IDLE;
|
|
407 irparams.rawlen = 0;
|
|
408 }
|
|
409
|
|
410
|
|
411
|
|
412 // Decodes the received IR message
|
|
413 // Returns 0 if no data ready, 1 if data ready.
|
|
414 // Results of decoding are stored in results
|
|
415 int IRrecv::decode(decode_results *results) {
|
|
416 results->rawbuf = irparams.rawbuf;
|
|
417 results->rawlen = irparams.rawlen;
|
|
418 if (irparams.rcvstate != STATE_STOP) {
|
|
419 return ERR;
|
|
420 }
|
|
421 #ifdef DEBUG
|
|
422 Serial.println("Attempting NEC decode");
|
|
423 #endif
|
|
424 if (decodeNEC(results)) {
|
|
425 return DECODED;
|
|
426 }
|
|
427 #ifdef DEBUG
|
|
428 Serial.println("Attempting Sony decode");
|
|
429 #endif
|
|
430 if (decodeSony(results)) {
|
|
431 return DECODED;
|
|
432 }
|
|
433 #ifdef DEBUG
|
|
434 Serial.println("Attempting Sanyo decode");
|
|
435 #endif
|
|
436 if (decodeSanyo(results)) {
|
|
437 return DECODED;
|
|
438 }
|
|
439 #ifdef DEBUG
|
|
440 Serial.println("Attempting Mitsubishi decode");
|
|
441 #endif
|
|
442 if (decodeMitsubishi(results)) {
|
|
443 return DECODED;
|
|
444 }
|
|
445 #ifdef DEBUG
|
|
446 Serial.println("Attempting RC5 decode");
|
|
447 #endif
|
|
448 if (decodeRC5(results)) {
|
|
449 return DECODED;
|
|
450 }
|
|
451 #ifdef DEBUG
|
|
452 Serial.println("Attempting RC6 decode");
|
|
453 #endif
|
|
454 if (decodeRC6(results)) {
|
|
455 return DECODED;
|
|
456 }
|
|
457 #ifdef DEBUG
|
|
458 Serial.println("Attempting Panasonic decode");
|
|
459 #endif
|
|
460 if (decodePanasonic(results)) {
|
|
461 return DECODED;
|
|
462 }
|
|
463 #ifdef DEBUG
|
|
464 Serial.println("Attempting LG decode");
|
|
465 #endif
|
|
466 if (decodeLG(results)) {
|
|
467 return DECODED;
|
|
468 }
|
|
469 #ifdef DEBUG
|
|
470 Serial.println("Attempting JVC decode");
|
|
471 #endif
|
|
472 if (decodeJVC(results)) {
|
|
473 return DECODED;
|
|
474 }
|
|
475 #ifdef DEBUG
|
|
476 Serial.println("Attempting SAMSUNG decode");
|
|
477 #endif
|
|
478 if (decodeSAMSUNG(results)) {
|
|
479 return DECODED;
|
|
480 }
|
|
481 // decodeHash returns a hash on any input.
|
|
482 // Thus, it needs to be last in the list.
|
|
483 // If you add any decodes, add them before this.
|
|
484 if (decodeHash(results)) {
|
|
485 return DECODED;
|
|
486 }
|
|
487 // Throw away and start over
|
|
488 resume();
|
|
489 return ERR;
|
|
490 }
|
|
491
|
|
492 // NECs have a repeat only 4 items long
|
|
493 long IRrecv::decodeNEC(decode_results *results) {
|
|
494 long data = 0;
|
|
495 int offset = 1; // Skip first space
|
|
496 // Initial mark
|
|
497 if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) {
|
|
498 return ERR;
|
|
499 }
|
|
500 offset++;
|
|
501 // Check for repeat
|
|
502 if (irparams.rawlen == 4 &&
|
|
503 MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) &&
|
|
504 MATCH_MARK(results->rawbuf[offset+1], NEC_BIT_MARK)) {
|
|
505 results->bits = 0;
|
|
506 results->value = REPEAT;
|
|
507 results->decode_type = NEC;
|
|
508 return DECODED;
|
|
509 }
|
|
510 if (irparams.rawlen < 2 * NEC_BITS + 4) {
|
|
511 return ERR;
|
|
512 }
|
|
513 // Initial space
|
|
514 if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) {
|
|
515 return ERR;
|
|
516 }
|
|
517 offset++;
|
|
518 for (int i = 0; i < NEC_BITS; i++) {
|
|
519 if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) {
|
|
520 return ERR;
|
|
521 }
|
|
522 offset++;
|
|
523 if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) {
|
|
524 data = (data << 1) | 1;
|
|
525 }
|
|
526 else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) {
|
|
527 data <<= 1;
|
|
528 }
|
|
529 else {
|
|
530 return ERR;
|
|
531 }
|
|
532 offset++;
|
|
533 }
|
|
534 // Success
|
|
535 results->bits = NEC_BITS;
|
|
536 results->value = data;
|
|
537 results->decode_type = NEC;
|
|
538 return DECODED;
|
|
539 }
|
|
540
|
|
541 long IRrecv::decodeSony(decode_results *results) {
|
|
542 long data = 0;
|
|
543 if (irparams.rawlen < 2 * SONY_BITS + 2) {
|
|
544 return ERR;
|
|
545 }
|
|
546 int offset = 0; // Dont skip first space, check its size
|
|
547
|
|
548 // Some Sony's deliver repeats fast after first
|
|
549 // unfortunately can't spot difference from of repeat from two fast clicks
|
|
550 if (results->rawbuf[offset] < SONY_DOUBLE_SPACE_USECS) {
|
|
551 // Serial.print("IR Gap found: ");
|
|
552 results->bits = 0;
|
|
553 results->value = REPEAT;
|
|
554 results->decode_type = SANYO;
|
|
555 return DECODED;
|
|
556 }
|
|
557 offset++;
|
|
558
|
|
559 // Initial mark
|
|
560 if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) {
|
|
561 return ERR;
|
|
562 }
|
|
563 offset++;
|
|
564
|
|
565 while (offset + 1 < irparams.rawlen) {
|
|
566 if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) {
|
|
567 break;
|
|
568 }
|
|
569 offset++;
|
|
570 if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) {
|
|
571 data = (data << 1) | 1;
|
|
572 }
|
|
573 else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) {
|
|
574 data <<= 1;
|
|
575 }
|
|
576 else {
|
|
577 return ERR;
|
|
578 }
|
|
579 offset++;
|
|
580 }
|
|
581
|
|
582 // Success
|
|
583 results->bits = (offset - 1) / 2;
|
|
584 if (results->bits < 12) {
|
|
585 results->bits = 0;
|
|
586 return ERR;
|
|
587 }
|
|
588 results->value = data;
|
|
589 results->decode_type = SONY;
|
|
590 return DECODED;
|
|
591 }
|
|
592
|
|
593 // I think this is a Sanyo decoder - serial = SA 8650B
|
|
594 // Looks like Sony except for timings, 48 chars of data and time/space different
|
|
595 long IRrecv::decodeSanyo(decode_results *results) {
|
|
596 long data = 0;
|
|
597 if (irparams.rawlen < 2 * SANYO_BITS + 2) {
|
|
598 return ERR;
|
|
599 }
|
|
600 int offset = 0; // Skip first space
|
|
601 // Initial space
|
|
602 /* 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
|
|
603 Serial.print("IR Gap: ");
|
|
604 Serial.println( results->rawbuf[offset]);
|
|
605 Serial.println( "test against:");
|
|
606 Serial.println(results->rawbuf[offset]);
|
|
607 */
|
|
608 if (results->rawbuf[offset] < SANYO_DOUBLE_SPACE_USECS) {
|
|
609 // Serial.print("IR Gap found: ");
|
|
610 results->bits = 0;
|
|
611 results->value = REPEAT;
|
|
612 results->decode_type = SANYO;
|
|
613 return DECODED;
|
|
614 }
|
|
615 offset++;
|
|
616
|
|
617 // Initial mark
|
|
618 if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) {
|
|
619 return ERR;
|
|
620 }
|
|
621 offset++;
|
|
622
|
|
623 // Skip Second Mark
|
|
624 if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) {
|
|
625 return ERR;
|
|
626 }
|
|
627 offset++;
|
|
628
|
|
629 while (offset + 1 < irparams.rawlen) {
|
|
630 if (!MATCH_SPACE(results->rawbuf[offset], SANYO_HDR_SPACE)) {
|
|
631 break;
|
|
632 }
|
|
633 offset++;
|
|
634 if (MATCH_MARK(results->rawbuf[offset], SANYO_ONE_MARK)) {
|
|
635 data = (data << 1) | 1;
|
|
636 }
|
|
637 else if (MATCH_MARK(results->rawbuf[offset], SANYO_ZERO_MARK)) {
|
|
638 data <<= 1;
|
|
639 }
|
|
640 else {
|
|
641 return ERR;
|
|
642 }
|
|
643 offset++;
|
|
644 }
|
|
645
|
|
646 // Success
|
|
647 results->bits = (offset - 1) / 2;
|
|
648 if (results->bits < 12) {
|
|
649 results->bits = 0;
|
|
650 return ERR;
|
|
651 }
|
|
652 results->value = data;
|
|
653 results->decode_type = SANYO;
|
|
654 return DECODED;
|
|
655 }
|
|
656
|
|
657 // Looks like Sony except for timings, 48 chars of data and time/space different
|
|
658 long IRrecv::decodeMitsubishi(decode_results *results) {
|
|
659 // Serial.print("?!? decoding Mitsubishi:");Serial.print(irparams.rawlen); Serial.print(" want "); Serial.println( 2 * MITSUBISHI_BITS + 2);
|
|
660 long data = 0;
|
|
661 if (irparams.rawlen < 2 * MITSUBISHI_BITS + 2) {
|
|
662 return ERR;
|
|
663 }
|
|
664 int offset = 0; // Skip first space
|
|
665 // Initial space
|
|
666 /* 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
|
|
667 Serial.print("IR Gap: ");
|
|
668 Serial.println( results->rawbuf[offset]);
|
|
669 Serial.println( "test against:");
|
|
670 Serial.println(results->rawbuf[offset]);
|
|
671 */
|
|
672 /* Not seeing double keys from Mitsubishi
|
|
673 if (results->rawbuf[offset] < MITSUBISHI_DOUBLE_SPACE_USECS) {
|
|
674 // Serial.print("IR Gap found: ");
|
|
675 results->bits = 0;
|
|
676 results->value = REPEAT;
|
|
677 results->decode_type = MITSUBISHI;
|
|
678 return DECODED;
|
|
679 }
|
|
680 */
|
|
681 offset++;
|
|
682
|
|
683 // Typical
|
|
684 // 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
|
|
685
|
|
686 // Initial Space
|
|
687 if (!MATCH_MARK(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) {
|
|
688 return ERR;
|
|
689 }
|
|
690 offset++;
|
|
691 while (offset + 1 < irparams.rawlen) {
|
|
692 if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ONE_MARK)) {
|
|
693 data = (data << 1) | 1;
|
|
694 }
|
|
695 else if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ZERO_MARK)) {
|
|
696 data <<= 1;
|
|
697 }
|
|
698 else {
|
|
699 // Serial.println("A"); Serial.println(offset); Serial.println(results->rawbuf[offset]);
|
|
700 return ERR;
|
|
701 }
|
|
702 offset++;
|
|
703 if (!MATCH_SPACE(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) {
|
|
704 // Serial.println("B"); Serial.println(offset); Serial.println(results->rawbuf[offset]);
|
|
705 break;
|
|
706 }
|
|
707 offset++;
|
|
708 }
|
|
709
|
|
710 // Success
|
|
711 results->bits = (offset - 1) / 2;
|
|
712 if (results->bits < MITSUBISHI_BITS) {
|
|
713 results->bits = 0;
|
|
714 return ERR;
|
|
715 }
|
|
716 results->value = data;
|
|
717 results->decode_type = MITSUBISHI;
|
|
718 return DECODED;
|
|
719 }
|
|
720
|
|
721
|
|
722 // Gets one undecoded level at a time from the raw buffer.
|
|
723 // The RC5/6 decoding is easier if the data is broken into time intervals.
|
|
724 // E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
|
|
725 // successive calls to getRClevel will return MARK, MARK, SPACE.
|
|
726 // offset and used are updated to keep track of the current position.
|
|
727 // t1 is the time interval for a single bit in microseconds.
|
|
728 // Returns -1 for error (measured time interval is not a multiple of t1).
|
|
729 int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) {
|
|
730 if (*offset >= results->rawlen) {
|
|
731 // After end of recorded buffer, assume SPACE.
|
|
732 return SPACE;
|
|
733 }
|
|
734 int width = results->rawbuf[*offset];
|
|
735 int val = ((*offset) % 2) ? MARK : SPACE;
|
|
736 int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS;
|
|
737
|
|
738 int avail;
|
|
739 if (MATCH(width, t1 + correction)) {
|
|
740 avail = 1;
|
|
741 }
|
|
742 else if (MATCH(width, 2*t1 + correction)) {
|
|
743 avail = 2;
|
|
744 }
|
|
745 else if (MATCH(width, 3*t1 + correction)) {
|
|
746 avail = 3;
|
|
747 }
|
|
748 else {
|
|
749 return -1;
|
|
750 }
|
|
751
|
|
752 (*used)++;
|
|
753 if (*used >= avail) {
|
|
754 *used = 0;
|
|
755 (*offset)++;
|
|
756 }
|
|
757 #ifdef DEBUG
|
|
758 if (val == MARK) {
|
|
759 Serial.println("MARK");
|
|
760 }
|
|
761 else {
|
|
762 Serial.println("SPACE");
|
|
763 }
|
|
764 #endif
|
|
765 return val;
|
|
766 }
|
|
767
|
|
768 long IRrecv::decodeRC5(decode_results *results) {
|
|
769 if (irparams.rawlen < MIN_RC5_SAMPLES + 2) {
|
|
770 return ERR;
|
|
771 }
|
|
772 int offset = 1; // Skip gap space
|
|
773 long data = 0;
|
|
774 int used = 0;
|
|
775 // Get start bits
|
|
776 if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
|
|
777 if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return ERR;
|
|
778 if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
|
|
779 int nbits;
|
|
780 for (nbits = 0; offset < irparams.rawlen; nbits++) {
|
|
781 int levelA = getRClevel(results, &offset, &used, RC5_T1);
|
|
782 int levelB = getRClevel(results, &offset, &used, RC5_T1);
|
|
783 if (levelA == SPACE && levelB == MARK) {
|
|
784 // 1 bit
|
|
785 data = (data << 1) | 1;
|
|
786 }
|
|
787 else if (levelA == MARK && levelB == SPACE) {
|
|
788 // zero bit
|
|
789 data <<= 1;
|
|
790 }
|
|
791 else {
|
|
792 return ERR;
|
|
793 }
|
|
794 }
|
|
795
|
|
796 // Success
|
|
797 results->bits = nbits;
|
|
798 results->value = data;
|
|
799 results->decode_type = RC5;
|
|
800 return DECODED;
|
|
801 }
|
|
802
|
|
803 long IRrecv::decodeRC6(decode_results *results) {
|
|
804 if (results->rawlen < MIN_RC6_SAMPLES) {
|
|
805 return ERR;
|
|
806 }
|
|
807 int offset = 1; // Skip first space
|
|
808 // Initial mark
|
|
809 if (!MATCH_MARK(results->rawbuf[offset], RC6_HDR_MARK)) {
|
|
810 return ERR;
|
|
811 }
|
|
812 offset++;
|
|
813 if (!MATCH_SPACE(results->rawbuf[offset], RC6_HDR_SPACE)) {
|
|
814 return ERR;
|
|
815 }
|
|
816 offset++;
|
|
817 long data = 0;
|
|
818 int used = 0;
|
|
819 // Get start bit (1)
|
|
820 if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return ERR;
|
|
821 if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return ERR;
|
|
822 int nbits;
|
|
823 for (nbits = 0; offset < results->rawlen; nbits++) {
|
|
824 int levelA, levelB; // Next two levels
|
|
825 levelA = getRClevel(results, &offset, &used, RC6_T1);
|
|
826 if (nbits == 3) {
|
|
827 // T bit is double wide; make sure second half matches
|
|
828 if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
|
|
829 }
|
|
830 levelB = getRClevel(results, &offset, &used, RC6_T1);
|
|
831 if (nbits == 3) {
|
|
832 // T bit is double wide; make sure second half matches
|
|
833 if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
|
|
834 }
|
|
835 if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5
|
|
836 // 1 bit
|
|
837 data = (data << 1) | 1;
|
|
838 }
|
|
839 else if (levelA == SPACE && levelB == MARK) {
|
|
840 // zero bit
|
|
841 data <<= 1;
|
|
842 }
|
|
843 else {
|
|
844 return ERR; // Error
|
|
845 }
|
|
846 }
|
|
847 // Success
|
|
848 results->bits = nbits;
|
|
849 results->value = data;
|
|
850 results->decode_type = RC6;
|
|
851 return DECODED;
|
|
852 }
|
|
853 long IRrecv::decodePanasonic(decode_results *results) {
|
|
854 unsigned long long data = 0;
|
|
855 int offset = 1;
|
|
856
|
|
857 if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_MARK)) {
|
|
858 return ERR;
|
|
859 }
|
|
860 offset++;
|
|
861 if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_SPACE)) {
|
|
862 return ERR;
|
|
863 }
|
|
864 offset++;
|
|
865
|
|
866 // decode address
|
|
867 for (int i = 0; i < PANASONIC_BITS; i++) {
|
|
868 if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_BIT_MARK)) {
|
|
869 return ERR;
|
|
870 }
|
|
871 if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ONE_SPACE)) {
|
|
872 data = (data << 1) | 1;
|
|
873 } else if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ZERO_SPACE)) {
|
|
874 data <<= 1;
|
|
875 } else {
|
|
876 return ERR;
|
|
877 }
|
|
878 offset++;
|
|
879 }
|
|
880 results->value = (unsigned long)data;
|
|
881 results->panasonicAddress = (unsigned int)(data >> 32);
|
|
882 results->decode_type = PANASONIC;
|
|
883 results->bits = PANASONIC_BITS;
|
|
884 return DECODED;
|
|
885 }
|
|
886
|
|
887 long IRrecv::decodeLG(decode_results *results) {
|
|
888 long data = 0;
|
|
889 int offset = 1; // Skip first space
|
|
890
|
|
891 // Initial mark
|
|
892 if (!MATCH_MARK(results->rawbuf[offset], LG_HDR_MARK)) {
|
|
893 return ERR;
|
|
894 }
|
|
895 offset++;
|
|
896 if (irparams.rawlen < 2 * LG_BITS + 1 ) {
|
|
897 return ERR;
|
|
898 }
|
|
899 // Initial space
|
|
900 if (!MATCH_SPACE(results->rawbuf[offset], LG_HDR_SPACE)) {
|
|
901 return ERR;
|
|
902 }
|
|
903 offset++;
|
|
904 for (int i = 0; i < LG_BITS; i++) {
|
|
905 if (!MATCH_MARK(results->rawbuf[offset], LG_BIT_MARK)) {
|
|
906 return ERR;
|
|
907 }
|
|
908 offset++;
|
|
909 if (MATCH_SPACE(results->rawbuf[offset], LG_ONE_SPACE)) {
|
|
910 data = (data << 1) | 1;
|
|
911 }
|
|
912 else if (MATCH_SPACE(results->rawbuf[offset], LG_ZERO_SPACE)) {
|
|
913 data <<= 1;
|
|
914 }
|
|
915 else {
|
|
916 return ERR;
|
|
917 }
|
|
918 offset++;
|
|
919 }
|
|
920 //Stop bit
|
|
921 if (!MATCH_MARK(results->rawbuf[offset], LG_BIT_MARK)){
|
|
922 return ERR;
|
|
923 }
|
|
924 // Success
|
|
925 results->bits = LG_BITS;
|
|
926 results->value = data;
|
|
927 results->decode_type = LG;
|
|
928 return DECODED;
|
|
929 }
|
|
930
|
|
931
|
|
932 long IRrecv::decodeJVC(decode_results *results) {
|
|
933 long data = 0;
|
|
934 int offset = 1; // Skip first space
|
|
935 // Check for repeat
|
|
936 if (irparams.rawlen - 1 == 33 &&
|
|
937 MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK) &&
|
|
938 MATCH_MARK(results->rawbuf[irparams.rawlen-1], JVC_BIT_MARK)) {
|
|
939 results->bits = 0;
|
|
940 results->value = REPEAT;
|
|
941 results->decode_type = JVC;
|
|
942 return DECODED;
|
|
943 }
|
|
944 // Initial mark
|
|
945 if (!MATCH_MARK(results->rawbuf[offset], JVC_HDR_MARK)) {
|
|
946 return ERR;
|
|
947 }
|
|
948 offset++;
|
|
949 if (irparams.rawlen < 2 * JVC_BITS + 1 ) {
|
|
950 return ERR;
|
|
951 }
|
|
952 // Initial space
|
|
953 if (!MATCH_SPACE(results->rawbuf[offset], JVC_HDR_SPACE)) {
|
|
954 return ERR;
|
|
955 }
|
|
956 offset++;
|
|
957 for (int i = 0; i < JVC_BITS; i++) {
|
|
958 if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)) {
|
|
959 return ERR;
|
|
960 }
|
|
961 offset++;
|
|
962 if (MATCH_SPACE(results->rawbuf[offset], JVC_ONE_SPACE)) {
|
|
963 data = (data << 1) | 1;
|
|
964 }
|
|
965 else if (MATCH_SPACE(results->rawbuf[offset], JVC_ZERO_SPACE)) {
|
|
966 data <<= 1;
|
|
967 }
|
|
968 else {
|
|
969 return ERR;
|
|
970 }
|
|
971 offset++;
|
|
972 }
|
|
973 //Stop bit
|
|
974 if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)){
|
|
975 return ERR;
|
|
976 }
|
|
977 // Success
|
|
978 results->bits = JVC_BITS;
|
|
979 results->value = data;
|
|
980 results->decode_type = JVC;
|
|
981 return DECODED;
|
|
982 }
|
|
983
|
|
984 // SAMSUNGs have a repeat only 4 items long
|
|
985 long IRrecv::decodeSAMSUNG(decode_results *results) {
|
|
986 long data = 0;
|
|
987 int offset = 1; // Skip first space
|
|
988 // Initial mark
|
|
989 if (!MATCH_MARK(results->rawbuf[offset], SAMSUNG_HDR_MARK)) {
|
|
990 return ERR;
|
|
991 }
|
|
992 offset++;
|
|
993 // Check for repeat
|
|
994 if (irparams.rawlen == 4 &&
|
|
995 MATCH_SPACE(results->rawbuf[offset], SAMSUNG_RPT_SPACE) &&
|
|
996 MATCH_MARK(results->rawbuf[offset+1], SAMSUNG_BIT_MARK)) {
|
|
997 results->bits = 0;
|
|
998 results->value = REPEAT;
|
|
999 results->decode_type = SAMSUNG;
|
|
1000 return DECODED;
|
|
1001 }
|
|
1002 if (irparams.rawlen < 2 * SAMSUNG_BITS + 4) {
|
|
1003 return ERR;
|
|
1004 }
|
|
1005 // Initial space
|
|
1006 if (!MATCH_SPACE(results->rawbuf[offset], SAMSUNG_HDR_SPACE)) {
|
|
1007 return ERR;
|
|
1008 }
|
|
1009 offset++;
|
|
1010 for (int i = 0; i < SAMSUNG_BITS; i++) {
|
|
1011 if (!MATCH_MARK(results->rawbuf[offset], SAMSUNG_BIT_MARK)) {
|
|
1012 return ERR;
|
|
1013 }
|
|
1014 offset++;
|
|
1015 if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ONE_SPACE)) {
|
|
1016 data = (data << 1) | 1;
|
|
1017 }
|
|
1018 else if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ZERO_SPACE)) {
|
|
1019 data <<= 1;
|
|
1020 }
|
|
1021 else {
|
|
1022 return ERR;
|
|
1023 }
|
|
1024 offset++;
|
|
1025 }
|
|
1026 // Success
|
|
1027 results->bits = SAMSUNG_BITS;
|
|
1028 results->value = data;
|
|
1029 results->decode_type = SAMSUNG;
|
|
1030 return DECODED;
|
|
1031 }
|
|
1032
|
|
1033 /* -----------------------------------------------------------------------
|
|
1034 * hashdecode - decode an arbitrary IR code.
|
|
1035 * Instead of decoding using a standard encoding scheme
|
|
1036 * (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value.
|
|
1037 *
|
|
1038 * The algorithm: look at the sequence of MARK signals, and see if each one
|
|
1039 * is shorter (0), the same length (1), or longer (2) than the previous.
|
|
1040 * Do the same with the SPACE signals. Hszh the resulting sequence of 0's,
|
|
1041 * 1's, and 2's to a 32-bit value. This will give a unique value for each
|
|
1042 * different code (probably), for most code systems.
|
|
1043 *
|
|
1044 * http://arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html
|
|
1045 */
|
|
1046
|
|
1047 // Compare two tick values, returning 0 if newval is shorter,
|
|
1048 // 1 if newval is equal, and 2 if newval is longer
|
|
1049 // Use a tolerance of 20%
|
|
1050 int IRrecv::compare(unsigned int oldval, unsigned int newval) {
|
|
1051 if (newval < oldval * .8) {
|
|
1052 return 0;
|
|
1053 }
|
|
1054 else if (oldval < newval * .8) {
|
|
1055 return 2;
|
|
1056 }
|
|
1057 else {
|
|
1058 return 1;
|
|
1059 }
|
|
1060 }
|
|
1061
|
|
1062 // Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
|
|
1063 #define FNV_PRIME_32 16777619
|
|
1064 #define FNV_BASIS_32 2166136261
|
|
1065
|
|
1066 /* Converts the raw code values into a 32-bit hash code.
|
|
1067 * Hopefully this code is unique for each button.
|
|
1068 * This isn't a "real" decoding, just an arbitrary value.
|
|
1069 */
|
|
1070 long IRrecv::decodeHash(decode_results *results) {
|
|
1071 // Require at least 6 samples to prevent triggering on noise
|
|
1072 if (results->rawlen < 6) {
|
|
1073 return ERR;
|
|
1074 }
|
|
1075 long hash = FNV_BASIS_32;
|
|
1076 for (int i = 1; i+2 < results->rawlen; i++) {
|
|
1077 int value = compare(results->rawbuf[i], results->rawbuf[i+2]);
|
|
1078 // Add value into the hash
|
|
1079 hash = (hash * FNV_PRIME_32) ^ value;
|
|
1080 }
|
|
1081 results->value = hash;
|
|
1082 results->bits = 32;
|
|
1083 results->decode_type = UNKNOWN;
|
|
1084 return DECODED;
|
|
1085 }
|
|
1086
|
|
1087 /* Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand )
|
|
1088
|
|
1089 The Dish send function needs to be repeated 4 times, and the Sharp function
|
|
1090 has the necessary repeat built in because of the need to invert the signal.
|
|
1091
|
|
1092 Sharp protocol documentation:
|
|
1093 http://www.sbprojects.com/knowledge/ir/sharp.htm
|
|
1094
|
|
1095 Here are the LIRC files that I found that seem to match the remote codes
|
|
1096 from the oscilloscope:
|
|
1097
|
|
1098 Sharp LCD TV:
|
|
1099 http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
|
|
1100
|
|
1101 DISH NETWORK (echostar 301):
|
|
1102 http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx
|
|
1103
|
|
1104 For the DISH codes, only send the last for characters of the hex.
|
|
1105 i.e. use 0x1C10 instead of 0x0000000000001C10 which is listed in the
|
|
1106 linked LIRC file.
|
|
1107 */
|
|
1108
|
|
1109 void IRsend::sendSharpRaw(unsigned long data, int nbits) {
|
|
1110 enableIROut(38);
|
|
1111
|
|
1112 // Sending codes in bursts of 3 (normal, inverted, normal) makes transmission
|
|
1113 // much more reliable. That's the exact behaviour of CD-S6470 remote control.
|
|
1114 for (int n = 0; n < 3; n++) {
|
|
1115 for (int i = 1 << (nbits-1); i > 0; i>>=1) {
|
|
1116 if (data & i) {
|
|
1117 mark(SHARP_BIT_MARK);
|
|
1118 space(SHARP_ONE_SPACE);
|
|
1119 }
|
|
1120 else {
|
|
1121 mark(SHARP_BIT_MARK);
|
|
1122 space(SHARP_ZERO_SPACE);
|
|
1123 }
|
|
1124 }
|
|
1125
|
|
1126 mark(SHARP_BIT_MARK);
|
|
1127 space(SHARP_ZERO_SPACE);
|
|
1128 delay(40);
|
|
1129
|
|
1130 data = data ^ SHARP_TOGGLE_MASK;
|
|
1131 }
|
|
1132 }
|
|
1133
|
|
1134 // Sharp send compatible with data obtained through decodeSharp
|
|
1135 void IRsend::sendSharp(unsigned int address, unsigned int command) {
|
|
1136 sendSharpRaw((address << 10) | (command << 2) | 2, 15);
|
|
1137 }
|
|
1138
|
|
1139 void IRsend::sendDISH(unsigned long data, int nbits) {
|
|
1140 enableIROut(56);
|
|
1141 mark(DISH_HDR_MARK);
|
|
1142 space(DISH_HDR_SPACE);
|
|
1143 for (int i = 0; i < nbits; i++) {
|
|
1144 if (data & DISH_TOP_BIT) {
|
|
1145 mark(DISH_BIT_MARK);
|
|
1146 space(DISH_ONE_SPACE);
|
|
1147 }
|
|
1148 else {
|
|
1149 mark(DISH_BIT_MARK);
|
|
1150 space(DISH_ZERO_SPACE);
|
|
1151 }
|
|
1152 data <<= 1;
|
|
1153 }
|
|
1154 }
|