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
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
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/
16 * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
20 #include "IRremoteInt.h"
23 #include <avr/interrupt.h>
25 volatile irparams_t irparams;
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
31 int MATCH(int measured, int desired) {
32 Serial.print("Testing: ");
33 Serial.print(TICKS_LOW(desired), DEC);
35 Serial.print(measured, DEC);
37 Serial.println(TICKS_HIGH(desired), DEC);
38 return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);
41 int MATCH_MARK(int measured_ticks, int desired_us) {
42 Serial.print("Testing mark ");
43 Serial.print(measured_ticks * USECPERTICK, DEC);
45 Serial.print(desired_us, DEC);
47 Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC);
49 Serial.print(measured_ticks, DEC);
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);
55 int MATCH_SPACE(int measured_ticks, int desired_us) {
56 Serial.print("Testing space ");
57 Serial.print(measured_ticks * USECPERTICK, DEC);
59 Serial.print(desired_us, DEC);
61 Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC);
63 Serial.print(measured_ticks, DEC);
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);
70 void IRsend::sendNEC(unsigned long data, int nbits)
75 for (int i = 0; i < nbits; i++) {
82 space(NEC_ZERO_SPACE);
90 void IRsend::sendSony(unsigned long data, int nbits) {
93 space(SONY_HDR_SPACE);
94 data = data << (32 - nbits);
95 for (int i = 0; i < nbits; i++) {
98 space(SONY_HDR_SPACE);
101 mark(SONY_ZERO_MARK);
102 space(SONY_HDR_SPACE);
108 void IRsend::sendRaw(unsigned int buf[], int len, int hz)
111 for (int i = 0; i < len; i++) {
119 space(0); // Just to be sure
122 // Note: first bit must be a one (start bit)
123 void IRsend::sendRC5(unsigned long data, int nbits)
126 data = data << (32 - nbits);
127 mark(RC5_T1); // First start bit
128 space(RC5_T1); // Second start bit
129 mark(RC5_T1); // Second start bit
130 for (int i = 0; i < nbits; i++) {
132 space(RC5_T1); // 1 is space, then mark
141 space(0); // Turn off at end
144 // Caller needs to take care of flipping the toggle bit
145 void IRsend::sendRC6(unsigned long data, int nbits)
148 data = data << (32 - nbits);
150 space(RC6_HDR_SPACE);
151 mark(RC6_T1); // start bit
154 for (int i = 0; i < nbits; i++) {
156 // double-wide trailer bit
173 space(0); // Turn off at end
175 void IRsend::sendPanasonic(unsigned int address, unsigned long data) {
177 mark(PANASONIC_HDR_MARK);
178 space(PANASONIC_HDR_SPACE);
180 for(int i=0;i<16;i++)
182 mark(PANASONIC_BIT_MARK);
183 if (address & 0x8000) {
184 space(PANASONIC_ONE_SPACE);
186 space(PANASONIC_ZERO_SPACE);
190 for (int i=0; i < 32; i++) {
191 mark(PANASONIC_BIT_MARK);
193 space(PANASONIC_ONE_SPACE);
195 space(PANASONIC_ZERO_SPACE);
199 mark(PANASONIC_BIT_MARK);
202 void IRsend::sendJVC(unsigned long data, int nbits, int repeat)
205 data = data << (32 - nbits);
208 space(JVC_HDR_SPACE);
210 for (int i = 0; i < nbits; i++) {
213 space(JVC_ONE_SPACE);
217 space(JVC_ZERO_SPACE);
224 void IRsend::mark(int time) {
225 // Sends an IR mark for the specified number of microseconds.
226 // The mark output is modulated at the PWM frequency.
227 TIMER_ENABLE_PWM; // Enable pin 3 PWM output
228 delayMicroseconds(time);
231 /* Leave pin off for time (given in microseconds) */
232 void IRsend::space(int time) {
233 // Sends an IR space for the specified number of microseconds.
234 // A space is no output, so the PWM output is disabled.
235 TIMER_DISABLE_PWM; // Disable pin 3 PWM output
236 delayMicroseconds(time);
239 void IRsend::enableIROut(int khz) {
240 // Enables IR output. The khz value controls the modulation frequency in kilohertz.
241 // The IR output will be on pin 3 (OC2B).
242 // This routine is designed for 36-40KHz; if you use it for other values, it's up to you
243 // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
244 // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
245 // controlling the duty cycle.
246 // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
247 // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
248 // A few hours staring at the ATmega documentation and this will all make sense.
249 // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
252 // Disable the Timer2 Interrupt (which is used for receiving IR)
253 TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
255 pinMode(TIMER_PWM_PIN, OUTPUT);
256 digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
258 // COM2A = 00: disconnect OC2A
259 // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
260 // WGM2 = 101: phase-correct PWM with OCRA as top
261 // CS2 = 000: no prescaling
262 // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
263 TIMER_CONFIG_KHZ(khz);
266 IRrecv::IRrecv(int recvpin)
268 irparams.recvpin = recvpin;
269 irparams.blinkflag = 0;
273 void IRrecv::enableIRIn() {
275 // setup pulse clock timer interrupt
276 //Prescale /8 (16M/8 = 0.5 microseconds per tick)
277 // Therefore, the timer interval can range from 0.5 to 128 microseconds
278 // depending on the reset value (255 to 0)
279 TIMER_CONFIG_NORMAL();
281 //Timer2 Overflow Interrupt Enable
286 sei(); // enable interrupts
288 // initialize state machine variables
289 irparams.rcvstate = STATE_IDLE;
293 pinMode(irparams.recvpin, INPUT);
296 // enable/disable blinking of pin 13 on IR processing
297 void IRrecv::blink13(int blinkflag)
299 irparams.blinkflag = blinkflag;
301 pinMode(BLINKLED, OUTPUT);
304 // TIMER2 interrupt code to collect raw data.
305 // Widths of alternating SPACE, MARK are recorded in rawbuf.
306 // Recorded in ticks of 50 microseconds.
307 // rawlen counts the number of entries recorded so far.
308 // First entry is the SPACE between transmissions.
309 // As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
310 // As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
315 uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);
317 irparams.timer++; // One more 50us tick
318 if (irparams.rawlen >= RAWBUF) {
320 irparams.rcvstate = STATE_STOP;
322 switch(irparams.rcvstate) {
323 case STATE_IDLE: // In the middle of a gap
324 if (irdata == MARK) {
325 if (irparams.timer < GAP_TICKS) {
326 // Not big enough to be a gap.
330 // gap just ended, record duration and start recording transmission
332 irparams.rawbuf[irparams.rawlen++] = irparams.timer;
334 irparams.rcvstate = STATE_MARK;
338 case STATE_MARK: // timing MARK
339 if (irdata == SPACE) { // MARK ended, record time
340 irparams.rawbuf[irparams.rawlen++] = irparams.timer;
342 irparams.rcvstate = STATE_SPACE;
345 case STATE_SPACE: // timing SPACE
346 if (irdata == MARK) { // SPACE just ended, record it
347 irparams.rawbuf[irparams.rawlen++] = irparams.timer;
349 irparams.rcvstate = STATE_MARK;
352 if (irparams.timer > GAP_TICKS) {
353 // big SPACE, indicates gap between codes
354 // Mark current code as ready for processing
356 // Don't reset timer; keep counting space width
357 irparams.rcvstate = STATE_STOP;
361 case STATE_STOP: // waiting, measuring gap
362 if (irdata == MARK) { // reset gap timer
368 if (irparams.blinkflag) {
369 if (irdata == MARK) {
370 BLINKLED_ON(); // turn pin 13 LED on
373 BLINKLED_OFF(); // turn pin 13 LED off
378 void IRrecv::resume() {
379 irparams.rcvstate = STATE_IDLE;
385 // Decodes the received IR message
386 // Returns 0 if no data ready, 1 if data ready.
387 // Results of decoding are stored in results
388 int IRrecv::decode(decode_results *results) {
389 results->rawbuf = irparams.rawbuf;
390 results->rawlen = irparams.rawlen;
391 if (irparams.rcvstate != STATE_STOP) {
395 Serial.println("Attempting NEC decode");
397 if (decodeNEC(results)) {
401 Serial.println("Attempting Sony decode");
403 if (decodeSony(results)) {
407 Serial.println("Attempting Sanyo decode");
409 if (decodeSanyo(results)) {
413 Serial.println("Attempting Mitsubishi decode");
415 if (decodeMitsubishi(results)) {
419 Serial.println("Attempting RC5 decode");
421 if (decodeRC5(results)) {
425 Serial.println("Attempting RC6 decode");
427 if (decodeRC6(results)) {
431 Serial.println("Attempting Panasonic decode");
433 if (decodePanasonic(results)) {
437 Serial.println("Attempting JVC decode");
439 if (decodeJVC(results)) {
442 // decodeHash returns a hash on any input.
443 // Thus, it needs to be last in the list.
444 // If you add any decodes, add them before this.
445 if (decodeHash(results)) {
448 // Throw away and start over
453 // NECs have a repeat only 4 items long
454 long IRrecv::decodeNEC(decode_results *results) {
456 int offset = 1; // Skip first space
458 if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) {
463 if (irparams.rawlen == 4 &&
464 MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) &&
465 MATCH_MARK(results->rawbuf[offset+1], NEC_BIT_MARK)) {
467 results->value = REPEAT;
468 results->decode_type = NEC;
471 if (irparams.rawlen < 2 * NEC_BITS + 4) {
475 if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) {
479 for (int i = 0; i < NEC_BITS; i++) {
480 if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) {
484 if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) {
485 data = (data << 1) | 1;
487 else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) {
496 results->bits = NEC_BITS;
497 results->value = data;
498 results->decode_type = NEC;
502 long IRrecv::decodeSony(decode_results *results) {
504 if (irparams.rawlen < 2 * SONY_BITS + 2) {
507 int offset = 0; // Dont skip first space, check its size
509 // Some Sony's deliver repeats fast after first
510 // unfortunately can't spot difference from of repeat from two fast clicks
511 if (results->rawbuf[offset] < SONY_DOUBLE_SPACE_USECS) {
512 // Serial.print("IR Gap found: ");
514 results->value = REPEAT;
515 results->decode_type = SANYO;
521 if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) {
526 while (offset + 1 < irparams.rawlen) {
527 if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) {
531 if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) {
532 data = (data << 1) | 1;
534 else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) {
544 results->bits = (offset - 1) / 2;
545 if (results->bits < 12) {
549 results->value = data;
550 results->decode_type = SONY;
554 // I think this is a Sanyo decoder - serial = SA 8650B
555 // Looks like Sony except for timings, 48 chars of data and time/space different
556 long IRrecv::decodeSanyo(decode_results *results) {
558 if (irparams.rawlen < 2 * SANYO_BITS + 2) {
561 int offset = 0; // Skip first space
563 /* 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
564 Serial.print("IR Gap: ");
565 Serial.println( results->rawbuf[offset]);
566 Serial.println( "test against:");
567 Serial.println(results->rawbuf[offset]);
569 if (results->rawbuf[offset] < SANYO_DOUBLE_SPACE_USECS) {
570 // Serial.print("IR Gap found: ");
572 results->value = REPEAT;
573 results->decode_type = SANYO;
579 if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) {
585 if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) {
590 while (offset + 1 < irparams.rawlen) {
591 if (!MATCH_SPACE(results->rawbuf[offset], SANYO_HDR_SPACE)) {
595 if (MATCH_MARK(results->rawbuf[offset], SANYO_ONE_MARK)) {
596 data = (data << 1) | 1;
598 else if (MATCH_MARK(results->rawbuf[offset], SANYO_ZERO_MARK)) {
608 results->bits = (offset - 1) / 2;
609 if (results->bits < 12) {
613 results->value = data;
614 results->decode_type = SANYO;
618 // Looks like Sony except for timings, 48 chars of data and time/space different
619 long IRrecv::decodeMitsubishi(decode_results *results) {
620 // Serial.print("?!? decoding Mitsubishi:");Serial.print(irparams.rawlen); Serial.print(" want "); Serial.println( 2 * MITSUBISHI_BITS + 2);
622 if (irparams.rawlen < 2 * MITSUBISHI_BITS + 2) {
625 int offset = 0; // Skip first space
627 /* 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
628 Serial.print("IR Gap: ");
629 Serial.println( results->rawbuf[offset]);
630 Serial.println( "test against:");
631 Serial.println(results->rawbuf[offset]);
633 /* Not seeing double keys from Mitsubishi
634 if (results->rawbuf[offset] < MITSUBISHI_DOUBLE_SPACE_USECS) {
635 // Serial.print("IR Gap found: ");
637 results->value = REPEAT;
638 results->decode_type = MITSUBISHI;
645 // 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
648 if (!MATCH_MARK(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) {
652 while (offset + 1 < irparams.rawlen) {
653 if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ONE_MARK)) {
654 data = (data << 1) | 1;
656 else if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ZERO_MARK)) {
660 // Serial.println("A"); Serial.println(offset); Serial.println(results->rawbuf[offset]);
664 if (!MATCH_SPACE(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) {
665 // Serial.println("B"); Serial.println(offset); Serial.println(results->rawbuf[offset]);
672 results->bits = (offset - 1) / 2;
673 if (results->bits < MITSUBISHI_BITS) {
677 results->value = data;
678 results->decode_type = MITSUBISHI;
683 // Gets one undecoded level at a time from the raw buffer.
684 // The RC5/6 decoding is easier if the data is broken into time intervals.
685 // E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
686 // successive calls to getRClevel will return MARK, MARK, SPACE.
687 // offset and used are updated to keep track of the current position.
688 // t1 is the time interval for a single bit in microseconds.
689 // Returns -1 for error (measured time interval is not a multiple of t1).
690 int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) {
691 if (*offset >= results->rawlen) {
692 // After end of recorded buffer, assume SPACE.
695 int width = results->rawbuf[*offset];
696 int val = ((*offset) % 2) ? MARK : SPACE;
697 int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS;
700 if (MATCH(width, t1 + correction)) {
703 else if (MATCH(width, 2*t1 + correction)) {
706 else if (MATCH(width, 3*t1 + correction)) {
714 if (*used >= avail) {
720 Serial.println("MARK");
723 Serial.println("SPACE");
729 long IRrecv::decodeRC5(decode_results *results) {
730 if (irparams.rawlen < MIN_RC5_SAMPLES + 2) {
733 int offset = 1; // Skip gap space
737 if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
738 if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return ERR;
739 if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
741 for (nbits = 0; offset < irparams.rawlen; nbits++) {
742 int levelA = getRClevel(results, &offset, &used, RC5_T1);
743 int levelB = getRClevel(results, &offset, &used, RC5_T1);
744 if (levelA == SPACE && levelB == MARK) {
746 data = (data << 1) | 1;
748 else if (levelA == MARK && levelB == SPACE) {
758 results->bits = nbits;
759 results->value = data;
760 results->decode_type = RC5;
764 long IRrecv::decodeRC6(decode_results *results) {
765 if (results->rawlen < MIN_RC6_SAMPLES) {
768 int offset = 1; // Skip first space
770 if (!MATCH_MARK(results->rawbuf[offset], RC6_HDR_MARK)) {
774 if (!MATCH_SPACE(results->rawbuf[offset], RC6_HDR_SPACE)) {
781 if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return ERR;
782 if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return ERR;
784 for (nbits = 0; offset < results->rawlen; nbits++) {
785 int levelA, levelB; // Next two levels
786 levelA = getRClevel(results, &offset, &used, RC6_T1);
788 // T bit is double wide; make sure second half matches
789 if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
791 levelB = getRClevel(results, &offset, &used, RC6_T1);
793 // T bit is double wide; make sure second half matches
794 if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
796 if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5
798 data = (data << 1) | 1;
800 else if (levelA == SPACE && levelB == MARK) {
809 results->bits = nbits;
810 results->value = data;
811 results->decode_type = RC6;
814 long IRrecv::decodePanasonic(decode_results *results) {
815 unsigned long long data = 0;
818 if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_MARK)) {
822 if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_SPACE)) {
828 for (int i = 0; i < PANASONIC_BITS; i++) {
829 if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_BIT_MARK)) {
832 if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ONE_SPACE)) {
833 data = (data << 1) | 1;
834 } else if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ZERO_SPACE)) {
841 results->value = (unsigned long)data;
842 results->panasonicAddress = (unsigned int)(data >> 32);
843 results->decode_type = PANASONIC;
844 results->bits = PANASONIC_BITS;
847 long IRrecv::decodeJVC(decode_results *results) {
849 int offset = 1; // Skip first space
851 if (irparams.rawlen - 1 == 33 &&
852 MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK) &&
853 MATCH_MARK(results->rawbuf[irparams.rawlen-1], JVC_BIT_MARK)) {
855 results->value = REPEAT;
856 results->decode_type = JVC;
860 if (!MATCH_MARK(results->rawbuf[offset], JVC_HDR_MARK)) {
864 if (irparams.rawlen < 2 * JVC_BITS + 1 ) {
868 if (!MATCH_SPACE(results->rawbuf[offset], JVC_HDR_SPACE)) {
872 for (int i = 0; i < JVC_BITS; i++) {
873 if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)) {
877 if (MATCH_SPACE(results->rawbuf[offset], JVC_ONE_SPACE)) {
878 data = (data << 1) | 1;
880 else if (MATCH_SPACE(results->rawbuf[offset], JVC_ZERO_SPACE)) {
889 if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)){
893 results->bits = JVC_BITS;
894 results->value = data;
895 results->decode_type = JVC;
899 /* -----------------------------------------------------------------------
900 * hashdecode - decode an arbitrary IR code.
901 * Instead of decoding using a standard encoding scheme
902 * (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value.
904 * The algorithm: look at the sequence of MARK signals, and see if each one
905 * is shorter (0), the same length (1), or longer (2) than the previous.
906 * Do the same with the SPACE signals. Hszh the resulting sequence of 0's,
907 * 1's, and 2's to a 32-bit value. This will give a unique value for each
908 * different code (probably), for most code systems.
910 * http://arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html
913 // Compare two tick values, returning 0 if newval is shorter,
914 // 1 if newval is equal, and 2 if newval is longer
915 // Use a tolerance of 20%
916 int IRrecv::compare(unsigned int oldval, unsigned int newval) {
917 if (newval < oldval * .8) {
920 else if (oldval < newval * .8) {
928 // Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
929 #define FNV_PRIME_32 16777619
930 #define FNV_BASIS_32 2166136261
932 /* Converts the raw code values into a 32-bit hash code.
933 * Hopefully this code is unique for each button.
934 * This isn't a "real" decoding, just an arbitrary value.
936 long IRrecv::decodeHash(decode_results *results) {
937 // Require at least 6 samples to prevent triggering on noise
938 if (results->rawlen < 6) {
941 long hash = FNV_BASIS_32;
942 for (int i = 1; i+2 < results->rawlen; i++) {
943 int value = compare(results->rawbuf[i], results->rawbuf[i+2]);
944 // Add value into the hash
945 hash = (hash * FNV_PRIME_32) ^ value;
947 results->value = hash;
949 results->decode_type = UNKNOWN;
953 /* Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand )
955 The Dish send function needs to be repeated 4 times, and the Sharp function
956 has the necessary repeat built in because of the need to invert the signal.
958 Sharp protocol documentation:
959 http://www.sbprojects.com/knowledge/ir/sharp.htm
961 Here are the LIRC files that I found that seem to match the remote codes
962 from the oscilloscope:
965 http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
967 DISH NETWORK (echostar 301):
968 http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx
970 For the DISH codes, only send the last for characters of the hex.
971 i.e. use 0x1C10 instead of 0x0000000000001C10 which is listed in the
975 void IRsend::sendSharp(unsigned long data, int nbits) {
976 unsigned long invertdata = data ^ SHARP_TOGGLE_MASK;
978 for (int i = 0; i < nbits; i++) {
980 mark(SHARP_BIT_MARK);
981 space(SHARP_ONE_SPACE);
984 mark(SHARP_BIT_MARK);
985 space(SHARP_ZERO_SPACE);
990 mark(SHARP_BIT_MARK);
991 space(SHARP_ZERO_SPACE);
993 for (int i = 0; i < nbits; i++) {
994 if (invertdata & 0x4000) {
995 mark(SHARP_BIT_MARK);
996 space(SHARP_ONE_SPACE);
999 mark(SHARP_BIT_MARK);
1000 space(SHARP_ZERO_SPACE);
1004 mark(SHARP_BIT_MARK);
1005 space(SHARP_ZERO_SPACE);
1009 void IRsend::sendDISH(unsigned long data, int nbits)
1012 mark(DISH_HDR_MARK);
1013 space(DISH_HDR_SPACE);
1014 for (int i = 0; i < nbits; i++) {
1015 if (data & DISH_TOP_BIT) {
1016 mark(DISH_BIT_MARK);
1017 space(DISH_ONE_SPACE);
1020 mark(DISH_BIT_MARK);
1021 space(DISH_ZERO_SPACE);