Infrared remote library for Arduino: send and receive infrared signals with multiple protocols Port from Arduino-IRremote https://github.com/z3t0/Arduino-IRremote
IRremote.cpp@0:70c8e56bac45, 2016-01-23 (annotated)
- Committer:
- yuhki50
- Date:
- Sat Jan 23 06:16:48 2016 +0000
- Revision:
- 0:70c8e56bac45
- Child:
- 3:17440cf7ab90
import https://github.com/z3t0/Arduino-IRremote e3ec11d
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
yuhki50 | 0:70c8e56bac45 | 1 | //****************************************************************************** |
yuhki50 | 0:70c8e56bac45 | 2 | // IRremote |
yuhki50 | 0:70c8e56bac45 | 3 | // Version 2.0.1 June, 2015 |
yuhki50 | 0:70c8e56bac45 | 4 | // Copyright 2009 Ken Shirriff |
yuhki50 | 0:70c8e56bac45 | 5 | // For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html |
yuhki50 | 0:70c8e56bac45 | 6 | // |
yuhki50 | 0:70c8e56bac45 | 7 | // Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers |
yuhki50 | 0:70c8e56bac45 | 8 | // Modified by Mitra Ardron <mitra@mitra.biz> |
yuhki50 | 0:70c8e56bac45 | 9 | // Added Sanyo and Mitsubishi controllers |
yuhki50 | 0:70c8e56bac45 | 10 | // Modified Sony to spot the repeat codes that some Sony's send |
yuhki50 | 0:70c8e56bac45 | 11 | // |
yuhki50 | 0:70c8e56bac45 | 12 | // Interrupt code based on NECIRrcv by Joe Knapp |
yuhki50 | 0:70c8e56bac45 | 13 | // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 |
yuhki50 | 0:70c8e56bac45 | 14 | // Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ |
yuhki50 | 0:70c8e56bac45 | 15 | // |
yuhki50 | 0:70c8e56bac45 | 16 | // JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) |
yuhki50 | 0:70c8e56bac45 | 17 | // LG added by Darryl Smith (based on the JVC protocol) |
yuhki50 | 0:70c8e56bac45 | 18 | // Whynter A/C ARC-110WD added by Francesco Meschia |
yuhki50 | 0:70c8e56bac45 | 19 | //****************************************************************************** |
yuhki50 | 0:70c8e56bac45 | 20 | |
yuhki50 | 0:70c8e56bac45 | 21 | #include <avr/interrupt.h> |
yuhki50 | 0:70c8e56bac45 | 22 | |
yuhki50 | 0:70c8e56bac45 | 23 | // Defining IR_GLOBAL here allows us to declare the instantiation of global variables |
yuhki50 | 0:70c8e56bac45 | 24 | #define IR_GLOBAL |
yuhki50 | 0:70c8e56bac45 | 25 | # include "IRremote.h" |
yuhki50 | 0:70c8e56bac45 | 26 | # include "IRremoteInt.h" |
yuhki50 | 0:70c8e56bac45 | 27 | #undef IR_GLOBAL |
yuhki50 | 0:70c8e56bac45 | 28 | |
yuhki50 | 0:70c8e56bac45 | 29 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 30 | // The match functions were (apparently) originally MACROs to improve code speed |
yuhki50 | 0:70c8e56bac45 | 31 | // (although this would have bloated the code) hence the names being CAPS |
yuhki50 | 0:70c8e56bac45 | 32 | // A later release implemented debug output and so they needed to be converted |
yuhki50 | 0:70c8e56bac45 | 33 | // to functions. |
yuhki50 | 0:70c8e56bac45 | 34 | // I tried to implement a dual-compile mode (DEBUG/non-DEBUG) but for some |
yuhki50 | 0:70c8e56bac45 | 35 | // reason, no matter what I did I could not get them to function as macros again. |
yuhki50 | 0:70c8e56bac45 | 36 | // I have found a *lot* of bugs in the Arduino compiler over the last few weeks, |
yuhki50 | 0:70c8e56bac45 | 37 | // and I am currently assuming that one of these bugs is my problem. |
yuhki50 | 0:70c8e56bac45 | 38 | // I may revisit this code at a later date and look at the assembler produced |
yuhki50 | 0:70c8e56bac45 | 39 | // in a hope of finding out what is going on, but for now they will remain as |
yuhki50 | 0:70c8e56bac45 | 40 | // functions even in non-DEBUG mode |
yuhki50 | 0:70c8e56bac45 | 41 | // |
yuhki50 | 0:70c8e56bac45 | 42 | int MATCH (int measured, int desired) |
yuhki50 | 0:70c8e56bac45 | 43 | { |
yuhki50 | 0:70c8e56bac45 | 44 | DBG_PRINT("Testing: "); |
yuhki50 | 0:70c8e56bac45 | 45 | DBG_PRINT(TICKS_LOW(desired), DEC); |
yuhki50 | 0:70c8e56bac45 | 46 | DBG_PRINT(" <= "); |
yuhki50 | 0:70c8e56bac45 | 47 | DBG_PRINT(measured, DEC); |
yuhki50 | 0:70c8e56bac45 | 48 | DBG_PRINT(" <= "); |
yuhki50 | 0:70c8e56bac45 | 49 | DBG_PRINTLN(TICKS_HIGH(desired), DEC); |
yuhki50 | 0:70c8e56bac45 | 50 | |
yuhki50 | 0:70c8e56bac45 | 51 | return ((measured >= TICKS_LOW(desired)) && (measured <= TICKS_HIGH(desired))); |
yuhki50 | 0:70c8e56bac45 | 52 | } |
yuhki50 | 0:70c8e56bac45 | 53 | |
yuhki50 | 0:70c8e56bac45 | 54 | //+======================================================== |
yuhki50 | 0:70c8e56bac45 | 55 | // Due to sensor lag, when received, Marks tend to be 100us too long |
yuhki50 | 0:70c8e56bac45 | 56 | // |
yuhki50 | 0:70c8e56bac45 | 57 | int MATCH_MARK (int measured_ticks, int desired_us) |
yuhki50 | 0:70c8e56bac45 | 58 | { |
yuhki50 | 0:70c8e56bac45 | 59 | DBG_PRINT("Testing mark "); |
yuhki50 | 0:70c8e56bac45 | 60 | DBG_PRINT(measured_ticks * USECPERTICK, DEC); |
yuhki50 | 0:70c8e56bac45 | 61 | DBG_PRINT(" vs "); |
yuhki50 | 0:70c8e56bac45 | 62 | DBG_PRINT(desired_us, DEC); |
yuhki50 | 0:70c8e56bac45 | 63 | DBG_PRINT(": "); |
yuhki50 | 0:70c8e56bac45 | 64 | DBG_PRINT(TICKS_LOW(desired_us + MARK_EXCESS), DEC); |
yuhki50 | 0:70c8e56bac45 | 65 | DBG_PRINT(" <= "); |
yuhki50 | 0:70c8e56bac45 | 66 | DBG_PRINT(measured_ticks, DEC); |
yuhki50 | 0:70c8e56bac45 | 67 | DBG_PRINT(" <= "); |
yuhki50 | 0:70c8e56bac45 | 68 | DBG_PRINTLN(TICKS_HIGH(desired_us + MARK_EXCESS), DEC); |
yuhki50 | 0:70c8e56bac45 | 69 | |
yuhki50 | 0:70c8e56bac45 | 70 | return ((measured_ticks >= TICKS_LOW (desired_us + MARK_EXCESS)) |
yuhki50 | 0:70c8e56bac45 | 71 | && (measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS))); |
yuhki50 | 0:70c8e56bac45 | 72 | } |
yuhki50 | 0:70c8e56bac45 | 73 | |
yuhki50 | 0:70c8e56bac45 | 74 | //+======================================================== |
yuhki50 | 0:70c8e56bac45 | 75 | // Due to sensor lag, when received, Spaces tend to be 100us too short |
yuhki50 | 0:70c8e56bac45 | 76 | // |
yuhki50 | 0:70c8e56bac45 | 77 | int MATCH_SPACE (int measured_ticks, int desired_us) |
yuhki50 | 0:70c8e56bac45 | 78 | { |
yuhki50 | 0:70c8e56bac45 | 79 | DBG_PRINT("Testing space "); |
yuhki50 | 0:70c8e56bac45 | 80 | DBG_PRINT(measured_ticks * USECPERTICK, DEC); |
yuhki50 | 0:70c8e56bac45 | 81 | DBG_PRINT(" vs "); |
yuhki50 | 0:70c8e56bac45 | 82 | DBG_PRINT(desired_us, DEC); |
yuhki50 | 0:70c8e56bac45 | 83 | DBG_PRINT(": "); |
yuhki50 | 0:70c8e56bac45 | 84 | DBG_PRINT(TICKS_LOW(desired_us - MARK_EXCESS), DEC); |
yuhki50 | 0:70c8e56bac45 | 85 | DBG_PRINT(" <= "); |
yuhki50 | 0:70c8e56bac45 | 86 | DBG_PRINT(measured_ticks, DEC); |
yuhki50 | 0:70c8e56bac45 | 87 | DBG_PRINT(" <= "); |
yuhki50 | 0:70c8e56bac45 | 88 | DBG_PRINTLN(TICKS_HIGH(desired_us - MARK_EXCESS), DEC); |
yuhki50 | 0:70c8e56bac45 | 89 | |
yuhki50 | 0:70c8e56bac45 | 90 | return ((measured_ticks >= TICKS_LOW (desired_us - MARK_EXCESS)) |
yuhki50 | 0:70c8e56bac45 | 91 | && (measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS))); |
yuhki50 | 0:70c8e56bac45 | 92 | } |
yuhki50 | 0:70c8e56bac45 | 93 | |
yuhki50 | 0:70c8e56bac45 | 94 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 95 | // Interrupt Service Routine - Fires every 50uS |
yuhki50 | 0:70c8e56bac45 | 96 | // TIMER2 interrupt code to collect raw data. |
yuhki50 | 0:70c8e56bac45 | 97 | // Widths of alternating SPACE, MARK are recorded in rawbuf. |
yuhki50 | 0:70c8e56bac45 | 98 | // Recorded in ticks of 50uS [microseconds, 0.000050 seconds] |
yuhki50 | 0:70c8e56bac45 | 99 | // 'rawlen' counts the number of entries recorded so far. |
yuhki50 | 0:70c8e56bac45 | 100 | // First entry is the SPACE between transmissions. |
yuhki50 | 0:70c8e56bac45 | 101 | // As soon as a the first [SPACE] entry gets long: |
yuhki50 | 0:70c8e56bac45 | 102 | // Ready is set; State switches to IDLE; Timing of SPACE continues. |
yuhki50 | 0:70c8e56bac45 | 103 | // As soon as first MARK arrives: |
yuhki50 | 0:70c8e56bac45 | 104 | // Gap width is recorded; Ready is cleared; New logging starts |
yuhki50 | 0:70c8e56bac45 | 105 | // |
yuhki50 | 0:70c8e56bac45 | 106 | ISR (TIMER_INTR_NAME) |
yuhki50 | 0:70c8e56bac45 | 107 | { |
yuhki50 | 0:70c8e56bac45 | 108 | TIMER_RESET; |
yuhki50 | 0:70c8e56bac45 | 109 | |
yuhki50 | 0:70c8e56bac45 | 110 | // Read if IR Receiver -> SPACE [xmt LED off] or a MARK [xmt LED on] |
yuhki50 | 0:70c8e56bac45 | 111 | // digitalRead() is very slow. Optimisation is possible, but makes the code unportable |
yuhki50 | 0:70c8e56bac45 | 112 | uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin); |
yuhki50 | 0:70c8e56bac45 | 113 | |
yuhki50 | 0:70c8e56bac45 | 114 | irparams.timer++; // One more 50uS tick |
yuhki50 | 0:70c8e56bac45 | 115 | if (irparams.rawlen >= RAWBUF) irparams.rcvstate = STATE_OVERFLOW ; // Buffer overflow |
yuhki50 | 0:70c8e56bac45 | 116 | |
yuhki50 | 0:70c8e56bac45 | 117 | switch(irparams.rcvstate) { |
yuhki50 | 0:70c8e56bac45 | 118 | //...................................................................... |
yuhki50 | 0:70c8e56bac45 | 119 | case STATE_IDLE: // In the middle of a gap |
yuhki50 | 0:70c8e56bac45 | 120 | if (irdata == MARK) { |
yuhki50 | 0:70c8e56bac45 | 121 | if (irparams.timer < GAP_TICKS) { // Not big enough to be a gap. |
yuhki50 | 0:70c8e56bac45 | 122 | irparams.timer = 0; |
yuhki50 | 0:70c8e56bac45 | 123 | |
yuhki50 | 0:70c8e56bac45 | 124 | } else { |
yuhki50 | 0:70c8e56bac45 | 125 | // Gap just ended; Record duration; Start recording transmission |
yuhki50 | 0:70c8e56bac45 | 126 | irparams.overflow = false; |
yuhki50 | 0:70c8e56bac45 | 127 | irparams.rawlen = 0; |
yuhki50 | 0:70c8e56bac45 | 128 | irparams.rawbuf[irparams.rawlen++] = irparams.timer; |
yuhki50 | 0:70c8e56bac45 | 129 | irparams.timer = 0; |
yuhki50 | 0:70c8e56bac45 | 130 | irparams.rcvstate = STATE_MARK; |
yuhki50 | 0:70c8e56bac45 | 131 | } |
yuhki50 | 0:70c8e56bac45 | 132 | } |
yuhki50 | 0:70c8e56bac45 | 133 | break; |
yuhki50 | 0:70c8e56bac45 | 134 | //...................................................................... |
yuhki50 | 0:70c8e56bac45 | 135 | case STATE_MARK: // Timing Mark |
yuhki50 | 0:70c8e56bac45 | 136 | if (irdata == SPACE) { // Mark ended; Record time |
yuhki50 | 0:70c8e56bac45 | 137 | irparams.rawbuf[irparams.rawlen++] = irparams.timer; |
yuhki50 | 0:70c8e56bac45 | 138 | irparams.timer = 0; |
yuhki50 | 0:70c8e56bac45 | 139 | irparams.rcvstate = STATE_SPACE; |
yuhki50 | 0:70c8e56bac45 | 140 | } |
yuhki50 | 0:70c8e56bac45 | 141 | break; |
yuhki50 | 0:70c8e56bac45 | 142 | //...................................................................... |
yuhki50 | 0:70c8e56bac45 | 143 | case STATE_SPACE: // Timing Space |
yuhki50 | 0:70c8e56bac45 | 144 | if (irdata == MARK) { // Space just ended; Record time |
yuhki50 | 0:70c8e56bac45 | 145 | irparams.rawbuf[irparams.rawlen++] = irparams.timer; |
yuhki50 | 0:70c8e56bac45 | 146 | irparams.timer = 0; |
yuhki50 | 0:70c8e56bac45 | 147 | irparams.rcvstate = STATE_MARK; |
yuhki50 | 0:70c8e56bac45 | 148 | |
yuhki50 | 0:70c8e56bac45 | 149 | } else if (irparams.timer > GAP_TICKS) { // Space |
yuhki50 | 0:70c8e56bac45 | 150 | // A long Space, indicates gap between codes |
yuhki50 | 0:70c8e56bac45 | 151 | // Flag the current code as ready for processing |
yuhki50 | 0:70c8e56bac45 | 152 | // Switch to STOP |
yuhki50 | 0:70c8e56bac45 | 153 | // Don't reset timer; keep counting Space width |
yuhki50 | 0:70c8e56bac45 | 154 | irparams.rcvstate = STATE_STOP; |
yuhki50 | 0:70c8e56bac45 | 155 | } |
yuhki50 | 0:70c8e56bac45 | 156 | break; |
yuhki50 | 0:70c8e56bac45 | 157 | //...................................................................... |
yuhki50 | 0:70c8e56bac45 | 158 | case STATE_STOP: // Waiting; Measuring Gap |
yuhki50 | 0:70c8e56bac45 | 159 | if (irdata == MARK) irparams.timer = 0 ; // Reset gap timer |
yuhki50 | 0:70c8e56bac45 | 160 | break; |
yuhki50 | 0:70c8e56bac45 | 161 | //...................................................................... |
yuhki50 | 0:70c8e56bac45 | 162 | case STATE_OVERFLOW: // Flag up a read overflow; Stop the State Machine |
yuhki50 | 0:70c8e56bac45 | 163 | irparams.overflow = true; |
yuhki50 | 0:70c8e56bac45 | 164 | irparams.rcvstate = STATE_STOP; |
yuhki50 | 0:70c8e56bac45 | 165 | break; |
yuhki50 | 0:70c8e56bac45 | 166 | } |
yuhki50 | 0:70c8e56bac45 | 167 | |
yuhki50 | 0:70c8e56bac45 | 168 | // If requested, flash LED while receiving IR data |
yuhki50 | 0:70c8e56bac45 | 169 | if (irparams.blinkflag) { |
yuhki50 | 0:70c8e56bac45 | 170 | if (irdata == MARK) |
yuhki50 | 0:70c8e56bac45 | 171 | if (irparams.blinkpin) digitalWrite(irparams.blinkpin, HIGH); // Turn user defined pin LED on |
yuhki50 | 0:70c8e56bac45 | 172 | else BLINKLED_ON() ; // if no user defined LED pin, turn default LED pin for the hardware on |
yuhki50 | 0:70c8e56bac45 | 173 | else if (irparams.blinkpin) digitalWrite(irparams.blinkpin, LOW); // Turn user defined pin LED on |
yuhki50 | 0:70c8e56bac45 | 174 | else BLINKLED_OFF() ; // if no user defined LED pin, turn default LED pin for the hardware on |
yuhki50 | 0:70c8e56bac45 | 175 | } |
yuhki50 | 0:70c8e56bac45 | 176 | } |