Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
IRRemote/IRReceiver.cpp@116:7a67265d7c19, 2021-10-01 (annotated)
- Committer:
- arnoz
- Date:
- Fri Oct 01 08:19:46 2021 +0000
- Revision:
- 116:7a67265d7c19
- Parent:
- 82:4f6209cb5c33
- Correct information regarding your last merge
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mjr | 77:0b96f6867312 | 1 | // IR Receiver |
mjr | 77:0b96f6867312 | 2 | // |
mjr | 77:0b96f6867312 | 3 | #include "IRReceiver.h" |
mjr | 77:0b96f6867312 | 4 | #include "IRTransmitter.h" |
mjr | 77:0b96f6867312 | 5 | #include "IRProtocols.h" |
mjr | 77:0b96f6867312 | 6 | |
mjr | 77:0b96f6867312 | 7 | // utility macro |
mjr | 77:0b96f6867312 | 8 | #define countof(arr) (sizeof(arr)/sizeof((arr)[0])) |
mjr | 77:0b96f6867312 | 9 | |
mjr | 77:0b96f6867312 | 10 | // Constructor |
mjr | 77:0b96f6867312 | 11 | IRReceiver::IRReceiver(PinName rxpin, size_t rawBufCount) : |
mjr | 77:0b96f6867312 | 12 | pin(rxpin), |
mjr | 77:0b96f6867312 | 13 | rawbuf(rawBufCount) |
mjr | 77:0b96f6867312 | 14 | { |
mjr | 77:0b96f6867312 | 15 | // the TSOP384xx has an internal pull-up resistor, so we don't |
mjr | 77:0b96f6867312 | 16 | // need one of our own |
mjr | 77:0b96f6867312 | 17 | pin.mode(PullNone); |
mjr | 77:0b96f6867312 | 18 | |
mjr | 77:0b96f6867312 | 19 | // make sure the protocol singletons are allocated |
mjr | 77:0b96f6867312 | 20 | IRProtocol::allocProtocols(); |
mjr | 77:0b96f6867312 | 21 | |
mjr | 77:0b96f6867312 | 22 | // there's no transmitter connected yet |
mjr | 77:0b96f6867312 | 23 | transmitter = 0; |
mjr | 77:0b96f6867312 | 24 | } |
mjr | 77:0b96f6867312 | 25 | |
mjr | 77:0b96f6867312 | 26 | // Destructor |
mjr | 77:0b96f6867312 | 27 | IRReceiver::~IRReceiver() { |
mjr | 77:0b96f6867312 | 28 | } |
mjr | 77:0b96f6867312 | 29 | |
mjr | 77:0b96f6867312 | 30 | // Enable reception |
mjr | 77:0b96f6867312 | 31 | void IRReceiver::enable() |
mjr | 77:0b96f6867312 | 32 | { |
mjr | 77:0b96f6867312 | 33 | // start the pulse timers |
mjr | 77:0b96f6867312 | 34 | startPulse(pin.read() ? 0 : 1); |
mjr | 77:0b96f6867312 | 35 | |
mjr | 77:0b96f6867312 | 36 | // set interrupt handlers for edges on the input pin |
mjr | 82:4f6209cb5c33 | 37 | pin.fall(&IRReceiver::cbFall, this); |
mjr | 82:4f6209cb5c33 | 38 | pin.rise(&IRReceiver::cbRise, this); |
mjr | 77:0b96f6867312 | 39 | } |
mjr | 77:0b96f6867312 | 40 | |
mjr | 77:0b96f6867312 | 41 | // Disable reception |
mjr | 77:0b96f6867312 | 42 | void IRReceiver::disable() |
mjr | 77:0b96f6867312 | 43 | { |
mjr | 77:0b96f6867312 | 44 | // Shut down all of our asynchronous handlers: remove the pin level |
mjr | 77:0b96f6867312 | 45 | // interrupts, stop the pulse timer, and cancel the maximum pulse |
mjr | 77:0b96f6867312 | 46 | // length timeout. |
mjr | 77:0b96f6867312 | 47 | pin.fall(0); |
mjr | 77:0b96f6867312 | 48 | pin.rise(0); |
mjr | 77:0b96f6867312 | 49 | pulseTimer.stop(); |
mjr | 77:0b96f6867312 | 50 | timeout.detach(); |
mjr | 77:0b96f6867312 | 51 | } |
mjr | 77:0b96f6867312 | 52 | |
mjr | 77:0b96f6867312 | 53 | // Start a new pulse of the given type. |
mjr | 77:0b96f6867312 | 54 | void IRReceiver::startPulse(bool newPulseState) |
mjr | 77:0b96f6867312 | 55 | { |
mjr | 77:0b96f6867312 | 56 | // set the new state |
mjr | 77:0b96f6867312 | 57 | pulseState = newPulseState; |
mjr | 77:0b96f6867312 | 58 | |
mjr | 77:0b96f6867312 | 59 | // reset the pulse timer |
mjr | 77:0b96f6867312 | 60 | pulseTimer.reset(); |
mjr | 77:0b96f6867312 | 61 | pulseTimer.start(); |
mjr | 77:0b96f6867312 | 62 | pulseAtMax = false; |
mjr | 77:0b96f6867312 | 63 | |
mjr | 77:0b96f6867312 | 64 | // cancel any prior pulse timeout |
mjr | 77:0b96f6867312 | 65 | timeout.detach(); |
mjr | 77:0b96f6867312 | 66 | |
mjr | 77:0b96f6867312 | 67 | // Set a new pulse timeout for the maximum pulse length |
mjr | 77:0b96f6867312 | 68 | timeout.attach_us(this, &IRReceiver::pulseTimeout, MAX_PULSE); |
mjr | 77:0b96f6867312 | 69 | } |
mjr | 77:0b96f6867312 | 70 | |
mjr | 77:0b96f6867312 | 71 | // End the current pulse |
mjr | 77:0b96f6867312 | 72 | void IRReceiver::endPulse(bool lastPulseState) |
mjr | 77:0b96f6867312 | 73 | { |
mjr | 77:0b96f6867312 | 74 | // Add the pulse to the buffer. If the pulse already timed out, |
mjr | 77:0b96f6867312 | 75 | // we already wrote it, so there's no need to write it again. |
mjr | 77:0b96f6867312 | 76 | if (!pulseAtMax) |
mjr | 77:0b96f6867312 | 77 | { |
mjr | 77:0b96f6867312 | 78 | // get the time of the ending space |
mjr | 77:0b96f6867312 | 79 | uint32_t t = pulseTimer.read_us(); |
mjr | 77:0b96f6867312 | 80 | |
mjr | 77:0b96f6867312 | 81 | // Scale by 2X to give us more range in a 16-bit int. Since we're |
mjr | 77:0b96f6867312 | 82 | // also discarding the low bit (for the mark/space indicator below), |
mjr | 77:0b96f6867312 | 83 | // round to the nearest 4us by adding 2us before dividing. |
mjr | 77:0b96f6867312 | 84 | t += 2; |
mjr | 77:0b96f6867312 | 85 | t >>= 1; |
mjr | 77:0b96f6867312 | 86 | |
mjr | 77:0b96f6867312 | 87 | // limit the stored value to the uint16 maximum value |
mjr | 77:0b96f6867312 | 88 | if (t > 65535) |
mjr | 77:0b96f6867312 | 89 | t = 65535; |
mjr | 77:0b96f6867312 | 90 | |
mjr | 77:0b96f6867312 | 91 | // set the low bit if it's a mark, clear it if it's a space |
mjr | 77:0b96f6867312 | 92 | t &= ~0x0001; |
mjr | 77:0b96f6867312 | 93 | t |= lastPulseState; |
mjr | 77:0b96f6867312 | 94 | |
mjr | 77:0b96f6867312 | 95 | // add it to the buffer |
mjr | 77:0b96f6867312 | 96 | rawbuf.write(uint16_t(t)); |
mjr | 77:0b96f6867312 | 97 | } |
mjr | 77:0b96f6867312 | 98 | } |
mjr | 77:0b96f6867312 | 99 | |
mjr | 77:0b96f6867312 | 100 | // Falling-edge interrupt. The sensors we work with use active-low |
mjr | 77:0b96f6867312 | 101 | // outputs, so a high->low edge means that we're switching from a "space" |
mjr | 77:0b96f6867312 | 102 | //(IR off) to a "mark" (IR on). |
mjr | 77:0b96f6867312 | 103 | void IRReceiver::fall(void) |
mjr | 77:0b96f6867312 | 104 | { |
mjr | 77:0b96f6867312 | 105 | // If the transmitter is sending, ignore new ON pulses, so that we |
mjr | 77:0b96f6867312 | 106 | // don't try to read our own transmissions. |
mjr | 77:0b96f6867312 | 107 | if (transmitter != 0 && transmitter->isSending()) |
mjr | 77:0b96f6867312 | 108 | return; |
mjr | 77:0b96f6867312 | 109 | |
mjr | 77:0b96f6867312 | 110 | // if we were in a space, end the space and start a mark |
mjr | 77:0b96f6867312 | 111 | if (!pulseState) |
mjr | 77:0b96f6867312 | 112 | { |
mjr | 77:0b96f6867312 | 113 | endPulse(false); |
mjr | 77:0b96f6867312 | 114 | startPulse(true); |
mjr | 77:0b96f6867312 | 115 | } |
mjr | 77:0b96f6867312 | 116 | } |
mjr | 77:0b96f6867312 | 117 | |
mjr | 77:0b96f6867312 | 118 | // Rising-edge interrupt. A low->high edge means we're switching from |
mjr | 77:0b96f6867312 | 119 | // a "mark" (IR on) to a "space" (IR off). |
mjr | 77:0b96f6867312 | 120 | void IRReceiver::rise(void) |
mjr | 77:0b96f6867312 | 121 | { |
mjr | 77:0b96f6867312 | 122 | // if we were in a mark, end the mark and start a space |
mjr | 77:0b96f6867312 | 123 | if (pulseState) |
mjr | 77:0b96f6867312 | 124 | { |
mjr | 77:0b96f6867312 | 125 | endPulse(true); |
mjr | 77:0b96f6867312 | 126 | startPulse(false); |
mjr | 77:0b96f6867312 | 127 | } |
mjr | 77:0b96f6867312 | 128 | } |
mjr | 77:0b96f6867312 | 129 | |
mjr | 77:0b96f6867312 | 130 | // Pulse timeout. |
mjr | 77:0b96f6867312 | 131 | void IRReceiver::pulseTimeout(void) |
mjr | 77:0b96f6867312 | 132 | { |
mjr | 77:0b96f6867312 | 133 | // End the current pulse, even though it hasn't physically ended, |
mjr | 77:0b96f6867312 | 134 | // so that the protocol processor can read it. Pulses longer than |
mjr | 77:0b96f6867312 | 135 | // the maximum are all the same to the protocols, so we can process |
mjr | 77:0b96f6867312 | 136 | // these as soon as we reach the timeout. However, don't start a |
mjr | 77:0b96f6867312 | 137 | // new pulse yet; we'll wait to do that until we get an actual |
mjr | 77:0b96f6867312 | 138 | // physical pulser. |
mjr | 77:0b96f6867312 | 139 | endPulse(pulseState); |
mjr | 77:0b96f6867312 | 140 | |
mjr | 77:0b96f6867312 | 141 | // note that we've reached the pulse timeout |
mjr | 77:0b96f6867312 | 142 | pulseAtMax = true; |
mjr | 77:0b96f6867312 | 143 | } |
mjr | 77:0b96f6867312 | 144 | |
mjr | 77:0b96f6867312 | 145 | // Process the buffer contents |
mjr | 77:0b96f6867312 | 146 | void IRReceiver::process() |
mjr | 77:0b96f6867312 | 147 | { |
mjr | 77:0b96f6867312 | 148 | // keep going until we run out of samples |
mjr | 77:0b96f6867312 | 149 | uint16_t t; |
mjr | 77:0b96f6867312 | 150 | while (rawbuf.read(t)) |
mjr | 77:0b96f6867312 | 151 | { |
mjr | 77:0b96f6867312 | 152 | // Process it through the protocol handlers. Note that the low |
mjr | 77:0b96f6867312 | 153 | // bit is the mark/space indicator, not a time bit, so pull it |
mjr | 77:0b96f6867312 | 154 | // out as the 'mark' argument and mask it out of the time. And |
mjr | 77:0b96f6867312 | 155 | // note that the value in the buffer is in 2us units, so multiply |
mjr | 77:0b96f6867312 | 156 | // by 2 to get microseconds. |
mjr | 77:0b96f6867312 | 157 | processProtocols((t & ~0x0001) << 1, t & 0x0001); |
mjr | 77:0b96f6867312 | 158 | } |
mjr | 77:0b96f6867312 | 159 | } |
mjr | 77:0b96f6867312 | 160 | |
mjr | 77:0b96f6867312 | 161 | // Process one buffer pulse |
mjr | 77:0b96f6867312 | 162 | bool IRReceiver::processOne(uint16_t &sample) |
mjr | 77:0b96f6867312 | 163 | { |
mjr | 77:0b96f6867312 | 164 | // try reading a sample |
mjr | 77:0b96f6867312 | 165 | if (rawbuf.read(sample)) |
mjr | 77:0b96f6867312 | 166 | { |
mjr | 77:0b96f6867312 | 167 | // Process it through the protocols - convert to microseconds |
mjr | 77:0b96f6867312 | 168 | // by masking out the low bit and mulitplying by the 2us units |
mjr | 77:0b96f6867312 | 169 | // we use in the sample buffer, and pull out the low bit as |
mjr | 77:0b96f6867312 | 170 | // the mark/space type. |
mjr | 77:0b96f6867312 | 171 | processProtocols((sample & ~0x0001) << 1, sample & 0x0001); |
mjr | 77:0b96f6867312 | 172 | |
mjr | 77:0b96f6867312 | 173 | // got a sample |
mjr | 77:0b96f6867312 | 174 | return true; |
mjr | 77:0b96f6867312 | 175 | } |
mjr | 77:0b96f6867312 | 176 | |
mjr | 77:0b96f6867312 | 177 | // no sample |
mjr | 77:0b96f6867312 | 178 | return false; |
mjr | 77:0b96f6867312 | 179 | } |
mjr | 77:0b96f6867312 | 180 | |
mjr | 77:0b96f6867312 | 181 | // Process one buffer pulse |
mjr | 77:0b96f6867312 | 182 | bool IRReceiver::processOne(uint32_t &t, bool &mark) |
mjr | 77:0b96f6867312 | 183 | { |
mjr | 77:0b96f6867312 | 184 | // try reading a sample |
mjr | 77:0b96f6867312 | 185 | uint16_t sample; |
mjr | 77:0b96f6867312 | 186 | if (rawbuf.read(sample)) |
mjr | 77:0b96f6867312 | 187 | { |
mjr | 77:0b96f6867312 | 188 | // it's a mark if the low bit is set |
mjr | 77:0b96f6867312 | 189 | mark = sample & 0x0001; |
mjr | 77:0b96f6867312 | 190 | |
mjr | 77:0b96f6867312 | 191 | // remove the low bit, as it's not actually part of the time value, |
mjr | 77:0b96f6867312 | 192 | // and multiply by 2 to get from the 2us units in the buffer to |
mjr | 77:0b96f6867312 | 193 | // microseconds |
mjr | 77:0b96f6867312 | 194 | t = (sample & ~0x0001) << 1; |
mjr | 77:0b96f6867312 | 195 | |
mjr | 77:0b96f6867312 | 196 | // process it through the protocol handlers |
mjr | 77:0b96f6867312 | 197 | processProtocols(t, mark); |
mjr | 77:0b96f6867312 | 198 | |
mjr | 77:0b96f6867312 | 199 | // got a sample |
mjr | 77:0b96f6867312 | 200 | return true; |
mjr | 77:0b96f6867312 | 201 | } |
mjr | 77:0b96f6867312 | 202 | |
mjr | 77:0b96f6867312 | 203 | // no sample |
mjr | 77:0b96f6867312 | 204 | return false; |
mjr | 77:0b96f6867312 | 205 | } |
mjr | 77:0b96f6867312 | 206 | |
mjr | 77:0b96f6867312 | 207 | // Process a pulse through the protocol handlers |
mjr | 77:0b96f6867312 | 208 | void IRReceiver::processProtocols(uint32_t t, bool mark) |
mjr | 77:0b96f6867312 | 209 | { |
mjr | 77:0b96f6867312 | 210 | // generate a call to each sender in the RX list |
mjr | 77:0b96f6867312 | 211 | #define IR_PROTOCOL_RX(cls) IRProtocol::protocols->s_##cls.rxPulse(this, t, mark); |
mjr | 77:0b96f6867312 | 212 | #include "IRProtocolList.h" |
mjr | 77:0b96f6867312 | 213 | } |