Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
arnoz
Date:
Fri Oct 01 08:19:46 2021 +0000
Revision:
116:7a67265d7c19
Parent:
97:fc7727303038
- Correct information regarding your last merge

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 77:0b96f6867312 1 // IR Remote Receiver
mjr 77:0b96f6867312 2 //
mjr 77:0b96f6867312 3 // This is a multi-protocol receiver for IR remote control signals. The
mjr 77:0b96f6867312 4 // IR signals are physically received through an external sensor. Our
mjr 77:0b96f6867312 5 // reference device is the TSOP384xx, but most other IR remote sensors
mjr 77:0b96f6867312 6 // are similar in design and will proably work. We have two main requirements
mjr 77:0b96f6867312 7 // for the sensor: first, it has to demodulate the IR carrier wave; second,
mjr 77:0b96f6867312 8 // it has to present a single-wire digital signal representing the demodulated
mjr 77:0b96f6867312 9 // IR status. We assume active low signaling, where 0V on the signal line
mjr 77:0b96f6867312 10 // represents "IR ON" and Vcc represents "IR OFF". It would be fairly easy
mjr 77:0b96f6867312 11 // to adapt the code to the opposite signaling sense, but I haven't bothered
mjr 77:0b96f6867312 12 // to parameterize this because I haven't seen any active-high sensors. The
mjr 77:0b96f6867312 13 // sensor also obviously has to be electrically compatible with the KL25Z,
mjr 77:0b96f6867312 14 // which mostly means that it runs on a 3.3V supply. If your sensor uses
mjr 77:0b96f6867312 15 // a different supply voltage, it might still be workable, but you might
mjr 77:0b96f6867312 16 // need to interpose a voltage level converter on the logic input to make
mjr 77:0b96f6867312 17 // sure that the KL25Z GPIO pin doesn't go above 3.3V, as these pins aren't
mjr 77:0b96f6867312 18 // tolerant of higher voltages.
mjr 77:0b96f6867312 19 //
mjr 77:0b96f6867312 20 // How to wire the sensor
mjr 77:0b96f6867312 21 //
mjr 77:0b96f6867312 22 // To physically wire the sensor, you just need to connect the sensor's
mjr 77:0b96f6867312 23 // Vs and GND pins to the the 3.3V out (P3V3) and GND on the KL25Z,
mjr 77:0b96f6867312 24 // respectively, and connect its "OUT" or "data" pin (pin 1 on a TSOP384xx)
mjr 77:0b96f6867312 25 // to a free, interrupt-capable GPIO on the KL25Z. On the KL25Z, all PTAxx
mjr 77:0b96f6867312 26 // and PTDxx ports are interrupt-capable (and conversely, PTBxx, PTCxx, and
mjr 77:0b96f6867312 27 // PTExx ports aren't, so you can't use one of those). You should check the
mjr 77:0b96f6867312 28 // data sheet for the sensor you're using to see if any other external
mjr 77:0b96f6867312 29 // components are required; e.g., the TSOP384xx data sheet recommends a
mjr 77:0b96f6867312 30 // capacitor and resistor for ESD protection and power supply conditioning.
mjr 77:0b96f6867312 31 // The data sheet will include a diagram showing the suggested application
mjr 77:0b96f6867312 32 // wiring if there are any special considerations like that. Note that the
mjr 77:0b96f6867312 33 // TSOP384xx data sheet doesn't specify exact values for the resistor and
mjr 77:0b96f6867312 34 // capacitor, so I'll mention what I'm using in my test setup: 220 ohms for
mjr 77:0b96f6867312 35 // the resistor, 150nF for the capacitor.
mjr 77:0b96f6867312 36 //
mjr 77:0b96f6867312 37 // How to use it in your application
mjr 77:0b96f6867312 38 //
mjr 77:0b96f6867312 39 // To use the receiver in an application, first create an IRReceiver object,
mjr 77:0b96f6867312 40 // telling it which pin to use as the sensor input, and how big you want the
mjr 77:0b96f6867312 41 // raw sample buffer to be. The raw buffer needs to be big enough to hold
mjr 77:0b96f6867312 42 // samples that arrive during each iteration of your main loop, so you need
mjr 77:0b96f6867312 43 // approximately one buffer entry per 250us of your main loop's maximum
mjr 77:0b96f6867312 44 // iteration time. If RAM isn't tight in your app, just pick a fairly large
mjr 77:0b96f6867312 45 // size (maybe 200 entries); if RAM is tight, figure your worst-case main loop
mjr 77:0b96f6867312 46 // time, divide by 250us, and add maybe 25% or 50% padding. Once you create
mjr 77:0b96f6867312 47 // the receiver object, call enable() to enable reception. You can do this
mjr 77:0b96f6867312 48 // once at the outset, or you can selectively enable() and disable() it at
mjr 77:0b96f6867312 49 // any time if you only need reception at specific times. Reception takes
mjr 77:0b96f6867312 50 // a small amount of CPU time (in interrupt mode) whenever signals arrive,
mjr 77:0b96f6867312 51 // so if you have a time-critical task to do at a time when reception isn't
mjr 77:0b96f6867312 52 // useful, you can turn it off to avoid any latency from IR interrupts.
mjr 77:0b96f6867312 53 //
mjr 77:0b96f6867312 54 // IRReceiver *rx = new IRReceiver(PTA13, 32);
mjr 77:0b96f6867312 55 // rx->enable();
mjr 77:0b96f6867312 56 //
mjr 77:0b96f6867312 57 // If you're using the companion transmitter class in the same application
mjr 77:0b96f6867312 58 // to create a device that's both an IR transmitter and receiver, you might
mjr 77:0b96f6867312 59 // want to tell the receiver about the transmitter, via setTransmitter().
mjr 77:0b96f6867312 60 // This causes the receiver to ignore incoming signals whenever the
mjr 77:0b96f6867312 61 // transmitter is sending, so that you don't receive your own transmissions.
mjr 77:0b96f6867312 62 // This isn't necessary if the receiver is positioned so that it can't see
mjr 77:0b96f6867312 63 // the transmitter's signals.
mjr 77:0b96f6867312 64 //
mjr 77:0b96f6867312 65 // rx->setTransmitter(tx);
mjr 77:0b96f6867312 66 //
mjr 77:0b96f6867312 67 // Once you have a receiver set up and enabled, you need to call its process()
mjr 77:0b96f6867312 68 // method on each iteration of your main loop. This method takes all of the
mjr 77:0b96f6867312 69 // signals that have been received since the last call and runs them through
mjr 77:0b96f6867312 70 // the protocol decoders. To minimize time spent in interrupt handlers, the
mjr 77:0b96f6867312 71 // interrupt handlers merely queue the messages internally; this makes them
mjr 77:0b96f6867312 72 // return extremely quickly, so that they don't add any significant latency
mjr 77:0b96f6867312 73 // for other hardware or timer interrupts your application might use.
mjr 77:0b96f6867312 74 //
mjr 77:0b96f6867312 75 // rx->process();
mjr 77:0b96f6867312 76 //
mjr 77:0b96f6867312 77 // Also in your main loop, read incoming IR remote codes by calling
mjr 77:0b96f6867312 78 // readCommand() on the receiver. If a command is available, this will read
mjr 77:0b96f6867312 79 // it into an IRCommand object, which tells you the protocol the sender used
mjr 77:0b96f6867312 80 // (see IRProtocolID.h), and provides a "universal" representation of the
mjr 77:0b96f6867312 81 // command. The universal representation is protocol-specific mapping of
mjr 77:0b96f6867312 82 // the raw data bits to an integer value. We try to do this in a way that's
mjr 77:0b96f6867312 83 // most useful per protocol, with two main goals in mind. First, if there
mjr 77:0b96f6867312 84 // are any internal bits that are more structural than meaningful, such as
mjr 77:0b96f6867312 85 // checksums or other integrity checks, we generally remove them. Second,
mjr 77:0b96f6867312 86 // if there are published tables of codes from a manufacturer, we try to
mjr 77:0b96f6867312 87 // match the format used there, to make it easier to verify that codes are
mjr 77:0b96f6867312 88 // as expected and to make it easier to construct apps around specific types
mjr 77:0b96f6867312 89 // of remotes.
mjr 77:0b96f6867312 90 //
mjr 77:0b96f6867312 91 // IRCommand cmd;
mjr 77:0b96f6867312 92 // while (rx->readCommand(cmd)) { process the command; }
mjr 77:0b96f6867312 93 //
mjr 77:0b96f6867312 94 // You can also optionally read the raw incoming data, by calling processOne()
mjr 77:0b96f6867312 95 // instead of process(). processOne() runs a reading through the protocol
mjr 77:0b96f6867312 96 // decoders but also hands it back to you. Raw samples are simply "IR ON"
mjr 77:0b96f6867312 97 // and "IR OFF" signals with the time the IR was continuously on or off.
mjr 77:0b96f6867312 98 // The raw samples are useful if you want to build something like a repeater
mjr 77:0b96f6867312 99 // that only has to replicate the physical IR signals without regard to the
mjr 77:0b96f6867312 100 // underlying data bits. Raw signals are obviously also very useful if you
mjr 77:0b96f6867312 101 // want to analyze an unknown protocol and figure out how to write a new
mjr 77:0b96f6867312 102 // encoder/decoder for it. One thing that raw signals aren't great for,
mjr 77:0b96f6867312 103 // somewhat counterintuitively, is for building a learning remote. Many of
mjr 77:0b96f6867312 104 // the protocols have special ways of handling repeated codes (e.g., when
mjr 77:0b96f6867312 105 // holding down a key) that make verbatim repetition of a signal problematic
mjr 77:0b96f6867312 106 // for learning remote use. If you just repeat a raw code, the receiver
mjr 77:0b96f6867312 107 // might be confused into thinking that one key press looks like several
mjr 77:0b96f6867312 108 // key presses, or vice versa. It's better when possible to decode a signal
mjr 77:0b96f6867312 109 // into a recognized protocol, store the decoded bit data rather than the
mjr 77:0b96f6867312 110 // raw signals as the "learned" code, and then reconstruct the appropriate
mjr 77:0b96f6867312 111 // signal for transmission by re-encoding the learned bit code using the
mjr 77:0b96f6867312 112 // protocol's known structure.
mjr 77:0b96f6867312 113 //
mjr 77:0b96f6867312 114 //
mjr 77:0b96f6867312 115 // Internal architecture
mjr 77:0b96f6867312 116 //
mjr 77:0b96f6867312 117 // The IRReceiver object is simply a coordinator that manages the sensor
mjr 77:0b96f6867312 118 // hardware interface, reads the raw signals from the sensor, and passes
mjr 77:0b96f6867312 119 // the raw signals to the protocol objects for decoding. For each protocol
mjr 77:0b96f6867312 120 // we recognize, we define a specialized handler class for the protocol.
mjr 77:0b96f6867312 121 // Each protocol handler implements a state machine for decoding signals
mjr 77:0b96f6867312 122 // using its protocol. When IRReceiver reads a raw signal, it simply passes
mjr 77:0b96f6867312 123 // it to each of the protocol handlers in turn. They all operate as
mjr 77:0b96f6867312 124 // independent state machines, so in effect we have specialized receivers
mjr 77:0b96f6867312 125 // for all of the protocols operating in parallel, all eavesdropping on the
mjr 77:0b96f6867312 126 // same incoming stream of signals. When one of the protocol handlers
mjr 77:0b96f6867312 127 // successfully decodes a complete "command" (a key press on a remote, in
mjr 77:0b96f6867312 128 // most cases), it adds the command to our queue, using a universal
mjr 77:0b96f6867312 129 // representation that we define. Clients can then read the incoming
mjr 77:0b96f6867312 130 // commands from the queue without worrying about the raw signal details.
mjr 77:0b96f6867312 131 //
mjr 77:0b96f6867312 132 // It might sound chaotic to have all of these different protocol decoders
mjr 77:0b96f6867312 133 // working on the same data at the same time, but in practice the various
mjr 77:0b96f6867312 134 // protocols have enough internal structure that only the "right" handler
mjr 77:0b96f6867312 135 // will be able to do anything with a given signal, and the rest will just
mjr 97:fc7727303038 136 // ignore it, and bide their time until something shows up that they can make
mjr 77:0b96f6867312 137 // sense of. It might also sound like a lot of overhead, but in practice
mjr 77:0b96f6867312 138 // it's very lightweight: it takes about 4% CPU to service the decoding
mjr 77:0b96f6867312 139 // process while a signal is actually coming in, and essentially 0% when
mjr 77:0b96f6867312 140 // the IR airwaves are silent. What's more, that 4% CPU time is all in
mjr 77:0b96f6867312 141 // application context, not in interrupt context, so it doesn't contribute
mjr 77:0b96f6867312 142 // any latency to any other hardware interrupts you need to handle in your
mjr 77:0b96f6867312 143 // application.
mjr 77:0b96f6867312 144 //
mjr 77:0b96f6867312 145 // The individual protocol state machines are all very simple, typically
mjr 77:0b96f6867312 146 // doing just a few integer compares on the incoming timing data per signal.
mjr 77:0b96f6867312 147 // They also require very little state, usually on the order of a few 'int's
mjr 77:0b96f6867312 148 // per decoder, which translates to a small RAM footprint. The decoders
mjr 77:0b96f6867312 149 // operate incrementally and decode in near real time, so decoded commands
mjr 77:0b96f6867312 150 // appear essentially at the same time that their signals finish.
mjr 77:0b96f6867312 151 //
mjr 77:0b96f6867312 152 // Note that, unlike some other MCU IR libraries, we don't any have sort
mjr 77:0b96f6867312 153 // of global receiver state. In particular, we don't try to guess about
mjr 77:0b96f6867312 154 // message boundaries globally. All of the boundary detection and protocol
mjr 77:0b96f6867312 155 // state is in the individual protocol decoders. That eliminates the need
mjr 77:0b96f6867312 156 // for heuristics or special cases to guess about what "usually" indicates
mjr 77:0b96f6867312 157 // a message boundary across all protocols. There are enough special cases
mjr 77:0b96f6867312 158 // to make such guesses problematic, which becomes apparent if you look at
mjr 77:0b96f6867312 159 // the code in libraries that work that way. Since we don't need to know
mjr 77:0b96f6867312 160 // about message boundaries globally, we don't need to make such guesses or
mjr 77:0b96f6867312 161 // apply such special cases. We simply deal in the raw pulses and let
mjr 77:0b96f6867312 162 // each decoder separately judge for itself where its own message boundaries
mjr 77:0b96f6867312 163 // are. This might seem odd, because the implication is that one decoder
mjr 77:0b96f6867312 164 // might think we're in the middle of a message while another decoder
mjr 77:0b96f6867312 165 // thinks we're on a boundary. But that's just fine, and it's exactly
mjr 77:0b96f6867312 166 // why we shouldn't be making those judgments globally: if two protocols
mjr 77:0b96f6867312 167 // have contradictory rules like that, the way to reconcile it is to accept
mjr 77:0b96f6867312 168 // that there really is no correct global judgment, and leave it to the
mjr 77:0b96f6867312 169 // decoders to track their own states independently.
mjr 77:0b96f6867312 170 //
mjr 77:0b96f6867312 171 // We receive signals from the sensor via interrupts on the input GPIO pin.
mjr 77:0b96f6867312 172 // This allows for the most accurate timing possible, which is important
mjr 77:0b96f6867312 173 // because IR coding is entirely in the signal timing. Interrupts gives us
mjr 77:0b96f6867312 174 // much more accurate timing than polling would for obvious reasons. As
mjr 77:0b96f6867312 175 // mentioned above, though, we try to minimize the time we spend in IRQ
mjr 77:0b96f6867312 176 // context, since time spent in one interrupt handler translates to added
mjr 77:0b96f6867312 177 // latency for any other interrupts that occur at the same time. To
mjr 77:0b96f6867312 178 // accomplish this, the interrupt handlers don't do any decoding at all.
mjr 77:0b96f6867312 179 // They simply add the incoming signal data to an internal queue and then
mjr 77:0b96f6867312 180 // return. We do the decoding work back in application context, by having
mjr 77:0b96f6867312 181 // the main loop call our process() routine periodically. This takes signal
mjr 77:0b96f6867312 182 // readings off of the queue and runs them through the decoders. This
mjr 77:0b96f6867312 183 // introduces a small amount of lag time between physically receiving a
mjr 77:0b96f6867312 184 // signal and decoding it, but the lag time is only on the order of the
mjr 77:0b96f6867312 185 // main loop run time. In most MCU applications this is a very short
mjr 77:0b96f6867312 186 // time, perhaps only microseconds or perhaps as long as a few millseconds.
mjr 77:0b96f6867312 187 // But in any case it's almost always so short that a user can't perceive
mjr 77:0b96f6867312 188 // the delay, so for all practical purposes decoding is done in real time.
mjr 77:0b96f6867312 189 //
mjr 77:0b96f6867312 190 //
mjr 77:0b96f6867312 191 // How IR remotes work in general
mjr 77:0b96f6867312 192 //
mjr 77:0b96f6867312 193 // IR remote controls work by transmitting timed pulses of infrared light.
mjr 77:0b96f6867312 194 // These pulses are modulated in two ways: first, with a "carrier", which
mjr 77:0b96f6867312 195 // is a PWM signal operating at a fixed, relatively high frequency; and
mjr 77:0b96f6867312 196 // second, with a lower frequency data signal superimposed on the PWM
mjr 77:0b96f6867312 197 // signal. (And I suppose you could say there's a third layer of
mjr 97:fc7727303038 198 // modulation in the IR light itself, since that's an electromagnetic
mjr 97:fc7727303038 199 // wave operating at an even higher frequency of around 300 THz.)
mjr 77:0b96f6867312 200 //
mjr 77:0b96f6867312 201 // Carrier: The PWM carrier uses a fixed frequency, usually around 40kHz.
mjr 77:0b96f6867312 202 // The carrier doesn't encode any data, since it's just constant fixed-length
mjr 77:0b96f6867312 203 // pulses. Its function, rather, is to provide a regular oscillating signal
mjr 77:0b96f6867312 204 // that receivers can use to distinguish data signals from ambient light.
mjr 77:0b96f6867312 205 // This is necessary because the IR light wavelengths are also contained
mjr 77:0b96f6867312 206 // in sunlight and ordinary household lighting. (Fluourescent lights even
mjr 97:fc7727303038 207 // have their own characteristic oscillating frequencies in the IR band, so
mjr 77:0b96f6867312 208 // the receiver not only has to distinguish the signal from constant
mjr 77:0b96f6867312 209 // amgient light levels but also from other types of oscillating light
mjr 77:0b96f6867312 210 // levels. The PWM carrier frequencies used in remotes are chosen based
mjr 97:fc7727303038 211 // on the practical need to distinguish remote control signals from the
mjr 77:0b96f6867312 212 // common household interference sources.) Receivers can separate the
mjr 77:0b96f6867312 213 // an oscillating PWM signal at a particular frequency from other signals
mjr 77:0b96f6867312 214 // through a process known as demodulation, which is the same mechanism
mjr 97:fc7727303038 215 // that radio receivers use to pluck AM or FM signals from the jumble of
mjr 97:fc7727303038 216 // background noise in the radio spectrum.
mjr 77:0b96f6867312 217 //
mjr 77:0b96f6867312 218 // For our purposes, we don't worry about demodulation in the software,
mjr 77:0b96f6867312 219 // since the sensor hardware does that part of the job. Each type of sensor
mjr 77:0b96f6867312 220 // is designed to demodulate a particular carrier frequency, so you should
mjr 77:0b96f6867312 221 // choose a sensor based on the types of remotes you plan to use it with.
mjr 77:0b96f6867312 222 // Most CE manufacturers have more or less standardized on 38kHz, which is
mjr 77:0b96f6867312 223 // why we recommend the TSOP384xx series. Not everyone is at exactly 38kHz,
mjr 97:fc7727303038 224 // but most are within 2kHz plus or minus, and the TSOP seems to demodulate
mjr 97:fc7727303038 225 // signals within a few kHz of its nominal frequency very well. 38kHz seems
mjr 97:fc7727303038 226 // to be a good centerpoint for home electronics devices, which is why we
mjr 97:fc7727303038 227 // recommend the 38kHz part as a "universal" receiver. If your application
mjr 97:fc7727303038 228 // only needs to receive from one specific remote (rather than act as a
mjr 97:fc7727303038 229 // universal receiver), you might be better served with a different TSOP
mjr 97:fc7727303038 230 // part that's tuned to your transmitter's carrier frequency, if that's
mjr 97:fc7727303038 231 // something other than 38kHz.
mjr 77:0b96f6867312 232 //
mjr 77:0b96f6867312 233 // Data signal: The data signal is superimposed on the PWM carrier by
mjr 77:0b96f6867312 234 // turning the PWM'ed IR source on and off at a lower, variable frequency.
mjr 77:0b96f6867312 235 // These longer on/off pulses are of different lengths. The data bits are
mjr 77:0b96f6867312 236 // encoded in the varying lengths, although there's no one true way of
mjr 77:0b96f6867312 237 // doing this. Each protocol has its own way of representing bits as
mjr 77:0b96f6867312 238 // combinations of on times and off times, which we'll come to shortly.
mjr 77:0b96f6867312 239 //
mjr 77:0b96f6867312 240 // "On" pulses are called "marks", and "off" pulses are called "spaces".
mjr 77:0b96f6867312 241 // The terms come from wired asynchronous protocols, which share many
mjr 77:0b96f6867312 242 // properties with IR signals at this level.
mjr 77:0b96f6867312 243 //
mjr 77:0b96f6867312 244 // Note that each pulse has to be long enough to contain some minimum
mjr 77:0b96f6867312 245 // number (maybe 5-10) of PWM pulses, because otherwise the demodulator
mjr 77:0b96f6867312 246 // wouldn't be able to detect the presence or absence of the underlying
mjr 77:0b96f6867312 247 // PWM pulses. This makes IR remote codes fairly slow in terms of data
mjr 77:0b96f6867312 248 // rate, since the absolute minimum time per bit is the time in the shortest
mjr 77:0b96f6867312 249 // data pulse. Most codings actually use at least two pulses per bit for
mjr 77:0b96f6867312 250 // the sake of signal integrity, so the effective data rate lower still.
mjr 77:0b96f6867312 251 // Fortunately, this is all rather unimportant, since IR remotes don't
mjr 77:0b96f6867312 252 // need a very high data rate. They're mostly used to transmit button
mjr 77:0b96f6867312 253 // presses made by hand by a human user, which are at a fairly low rate
mjr 77:0b96f6867312 254 // to start with; plus, the amount of data per button is minuscule,
mjr 77:0b96f6867312 255 // usually from 8 to 32 bits.
mjr 77:0b96f6867312 256 //
mjr 77:0b96f6867312 257 // Encodings
mjr 77:0b96f6867312 258 //
mjr 77:0b96f6867312 259 // The timing of the marks and spaces carries the information, but exactly
mjr 77:0b96f6867312 260 // how it does this is a whole separate matter, known as an encoding. An
mjr 77:0b96f6867312 261 // encoding is a mapping from '0' and '1' bits to a pattern of marks and
mjr 77:0b96f6867312 262 // spaces, and vice versa. At first glance, it might seem that you could
mjr 77:0b96f6867312 263 // just use a mark as a '1' and a space as a '0', and in fact some protocols
mjr 77:0b96f6867312 264 // do something like this. But that simple approach has some big drawbacks
mjr 77:0b96f6867312 265 // arising from the lack of a shared clock between sender and receiver.
mjr 77:0b96f6867312 266 // Most encodings therefore do something to embed a timing signal of some
mjr 77:0b96f6867312 267 // sort within the data signal, by using the lengths of the pulses to encode
mjr 77:0b96f6867312 268 // bits rather than just the presence of the pulses.
mjr 77:0b96f6867312 269 //
mjr 77:0b96f6867312 270 // There are probably an infinite number of possible ways to do this in
mjr 77:0b96f6867312 271 // principle. Fortunately, the CE companies have only put a finite number
mjr 77:0b96f6867312 272 // of them into practice. In fact, it seems that we can cover practically
mjr 77:0b96f6867312 273 // all of the remotes out there by considering a small handful of encoding
mjr 77:0b96f6867312 274 // schemes. Here are the main ones, and the ones we can use in this
mjr 77:0b96f6867312 275 // receiver library:
mjr 77:0b96f6867312 276 //
mjr 77:0b96f6867312 277 // - Async bit stream. This is basically the IR equivalent of a wired
mjr 77:0b96f6867312 278 // UART. Each code word consists of a fixed number of bits. Each bit
mjr 77:0b96f6867312 279 // is represented by IR ON for '1' and IR OFF for '0', transmitted for
mjr 77:0b96f6867312 280 // a fixed time length. To transmit, simply turn the IR on and off in
mjr 77:0b96f6867312 281 // sequence for the fixed bit time per bit. To receive and decode,
mjr 77:0b96f6867312 282 // observe whether the IR signal is on or off in each time window.
mjr 77:0b96f6867312 283 // This type of protocol looks simple, but it presents some difficulties
mjr 77:0b96f6867312 284 // in implementation, because it doesn't provide any cues embedded in
mjr 77:0b96f6867312 285 // the IR signal to help the receiver synchronize with the sender or
mjr 77:0b96f6867312 286 // recognize the boundaries of code words, as all of the other common
mjr 77:0b96f6867312 287 // protocols do. That might be why this class seems to be rarely used
mjr 77:0b96f6867312 288 // in real applications. Protocols based on simple async bits usually
mjr 77:0b96f6867312 289 // add something at the protocol level that helps the reciever detect
mjr 77:0b96f6867312 290 // word boundaries and check signal integrity.
mjr 77:0b96f6867312 291 //
mjr 77:0b96f6867312 292 // - Pulse distance coding, also known as space length coding. In this
mjr 77:0b96f6867312 293 // scheme, marks are all of equal length, but spaces come in two lengths,
mjr 77:0b96f6867312 294 // A and B, where B is much longer than A (usually twice as long, but it
mjr 77:0b96f6867312 295 // could be even longer). A encodes 0 and B encodes 1. The marks serve
mjr 77:0b96f6867312 296 // as regular clock signals, allowing the receiver to keep in sync with
mjr 77:0b96f6867312 297 // the sender, and the long and short space times (A and B) are different
mjr 77:0b96f6867312 298 // enough that the receiver can easily distinguish them reliably, even
mjr 77:0b96f6867312 299 // with a low-precision clock. This scheme is probably the most widely
mjr 77:0b96f6867312 300 // used in CE products, because it's the encoding used by the NEC
mjr 77:0b96f6867312 301 // protocol, which most Japanese CE companies use.
mjr 77:0b96f6867312 302 //
mjr 77:0b96f6867312 303 // - Pulse length coding, also known as mark length coding. This is simply
mjr 77:0b96f6867312 304 // the inverse of pulse distance coding: spaces are all of equal length,
mjr 77:0b96f6867312 305 // and marks come in two lengths, with the short mark encoding 0 and the
mjr 77:0b96f6867312 306 // long mark encoding 1. This is practically the same in all meaningful
mjr 77:0b96f6867312 307 // ways as the space length coding; the only reason both kinds exist is
mjr 77:0b96f6867312 308 // probably that either someone had a bad case of NIH or they wanted to
mjr 77:0b96f6867312 309 // avoid paying a patent royalty. Mark length coding is the scheme Sony
mjr 77:0b96f6867312 310 // uses (in their SIRCS protocol).
mjr 77:0b96f6867312 311 //
mjr 77:0b96f6867312 312 // - Manchester coding. The message is divided into time slices of
mjr 77:0b96f6867312 313 // equal size, one bit per slice. Within each slice, the IR is on for
mjr 77:0b96f6867312 314 // half the window and off for half the window. The 0 and 1 bits are
mjr 77:0b96f6867312 315 // encoded by the direction of the transition: if a bit window starts
mjr 77:0b96f6867312 316 // with a mark (IR ON) and ends with a space (IR OFF), it's a '1'; if it
mjr 77:0b96f6867312 317 // starts with a space and ends with a mark, it's a '0'. Or vice versa.
mjr 77:0b96f6867312 318 // Each mark or space therefore lasts for either 1/2 or 1 bit time
mjr 77:0b96f6867312 319 // length, never longer. This makes it fairly easy for the receiver to
mjr 77:0b96f6867312 320 // distinguish the two time lengths, even with a fairly low-precision
mjr 77:0b96f6867312 321 // clock, since they're so different. It's also easy for the receiver
mjr 77:0b96f6867312 322 // to distinguish each bit, since there's always at least one transition
mjr 77:0b96f6867312 323 // (mark to space or space to mark) per bit. What's more, '0' and '1'
mjr 77:0b96f6867312 324 // bits take the same time to transmit (unlike the mark-length and
mjr 77:0b96f6867312 325 // space-length protocols), so every code word (assuming a fixed bit
mjr 77:0b96f6867312 326 // count) takes the same time regardless of the bit values within.
mjr 77:0b96f6867312 327 // Manchester modulation is used in the Philips RC5 and RC6 protocols,
mjr 77:0b96f6867312 328 // which are widely used among European CE companies.
mjr 77:0b96f6867312 329 //
mjr 77:0b96f6867312 330 // Protocols
mjr 77:0b96f6867312 331 //
mjr 77:0b96f6867312 332 // On top of the encoding scheme, there's another level of structure called
mjr 77:0b96f6867312 333 // a protocol. A given protocol uses a given encoding for the data bits,
mjr 77:0b96f6867312 334 // but then also adds some extra structure.
mjr 77:0b96f6867312 335 //
mjr 77:0b96f6867312 336 // For starters, the IR protocols all work in terms of "code words". In
mjr 77:0b96f6867312 337 // computer terms, a code word amounts to a datatype with a fixed number
mjr 77:0b96f6867312 338 // of bits. For example, the NEC protocol uses a 32-bit code word: each
mjr 77:0b96f6867312 339 // button press is represented by a 32-bit transmission. A single key
mjr 77:0b96f6867312 340 // press usually maps to a single code word, although not always; the
mjr 77:0b96f6867312 341 // Pioneer protocol, for example, transmits two words for certain buttons,
mjr 77:0b96f6867312 342 // using a special "shift" code for the first word to give a second meaning
mjr 77:0b96f6867312 343 // to the second word, to extend the possible number of commands that would
mjr 77:0b96f6867312 344 // be otherwise limited by the number of bits in a single code word.
mjr 77:0b96f6867312 345
mjr 77:0b96f6867312 346 // Second, most of the IR protocols add special non-data signals that
mjr 77:0b96f6867312 347 // mark the beginning and/or end of a code word. These are usually just
mjr 77:0b96f6867312 348 // extra-long marks or spaces, which are distinguishable from the marks
mjr 77:0b96f6867312 349 // and spaces within a code word because they're too long to be valid in
mjr 77:0b96f6867312 350 // the data encoding scheme. These are important to reliable communication
mjr 77:0b96f6867312 351 // because the sender and receiver don't have any other way to share state
mjr 77:0b96f6867312 352 // with each other. Consider what would happen if someone walked in the
mjr 77:0b96f6867312 353 // way while you were transmitting a remote code: the receiver would miss
mjr 77:0b96f6867312 354 // at least a few data bits, so it would be out of sync with the sender.
mjr 77:0b96f6867312 355 // If there weren't some way to distinguish the start of a code word from
mjr 77:0b96f6867312 356 // the IR pulses themselves, the receiver would now be permanently out
mjr 77:0b96f6867312 357 // of sync from the sender by however many bits it missed. But with the
mjr 77:0b96f6867312 358 // special "header" code, the receiver can sync up again as soon as the
mjr 77:0b96f6867312 359 // next code word starts, since it can tell from the timing that the
mjr 77:0b96f6867312 360 // header can't possibly be a bit in the middle of a code word.
mjr 77:0b96f6867312 361
mjr 77:0b96f6867312 362
mjr 77:0b96f6867312 363 #ifndef _IRRECEIVER_H_
mjr 77:0b96f6867312 364 #define _IRRECEIVER_H_
mjr 77:0b96f6867312 365
mjr 77:0b96f6867312 366 #include <mbed.h>
mjr 77:0b96f6867312 367
mjr 77:0b96f6867312 368 #include "IRRemote.h"
mjr 77:0b96f6867312 369 #include "IRCommand.h"
mjr 77:0b96f6867312 370 #include "circbuf.h"
mjr 82:4f6209cb5c33 371 #include "FastInterruptIn.h"
mjr 82:4f6209cb5c33 372
mjr 77:0b96f6867312 373
mjr 77:0b96f6867312 374 // IR receiver protocol interface. This contains functions that we only
mjr 77:0b96f6867312 375 // want to make accessible to the protocol decoders.
mjr 77:0b96f6867312 376 class IRRecvProIfc
mjr 77:0b96f6867312 377 {
mjr 77:0b96f6867312 378 public:
mjr 77:0b96f6867312 379 // write a command to the command queue
mjr 77:0b96f6867312 380 void writeCommand(IRCommand &cmd) { commands.write(cmd); }
mjr 77:0b96f6867312 381
mjr 77:0b96f6867312 382 protected:
mjr 77:0b96f6867312 383 // Decoded command queue. The protocol handlers add commands here
mjr 77:0b96f6867312 384 // as soon as they decode them.
mjr 77:0b96f6867312 385 CircBuf<IRCommand, 8> commands;
mjr 77:0b96f6867312 386 };
mjr 77:0b96f6867312 387
mjr 77:0b96f6867312 388
mjr 77:0b96f6867312 389 // IR Remote Receiver
mjr 77:0b96f6867312 390 class IRReceiver : protected IRRecvProIfc
mjr 77:0b96f6867312 391 {
mjr 77:0b96f6867312 392 public:
mjr 77:0b96f6867312 393 // Construct a receiver with the given data input pin. The receiver
mjr 77:0b96f6867312 394 // is initially disabled. To start receiving signals, call enable().
mjr 77:0b96f6867312 395 //
mjr 77:0b96f6867312 396 // Choose a raw buffer size according to the longest iteration time
mjr 77:0b96f6867312 397 // for your main application loop between the required periodic calls
mjr 77:0b96f6867312 398 // to our process() function. The interrupt handlers write pulse times
mjr 77:0b96f6867312 399 // to the raw buffer as the pulses arrive, and these are held in the
mjr 77:0b96f6867312 400 // buffer until they're removed by process(). The raw buffer only needs
mjr 77:0b96f6867312 401 // to be big enough for the "backlog" that occurs between the real-time
mjr 77:0b96f6867312 402 // incoming signals and the main loop's processing calls. The fastest
mjr 77:0b96f6867312 403 // IR pulses are about 250us long, so size the buffer according to how
mjr 77:0b96f6867312 404 // many 250us intervals will occur in the worst case, that is, the
mjr 77:0b96f6867312 405 // longest main loop iteration. If the main loop always runs in 2.5ms
mjr 77:0b96f6867312 406 // or shorter, that means you need about a 10-element buffer. To be
mjr 77:0b96f6867312 407 // conservative, size it at perhaps 2x the expected maximum.
mjr 77:0b96f6867312 408 //
mjr 77:0b96f6867312 409 IRReceiver(PinName rxpin, size_t rawBufCount);
mjr 77:0b96f6867312 410
mjr 77:0b96f6867312 411 // Destructor
mjr 77:0b96f6867312 412 ~IRReceiver();
mjr 77:0b96f6867312 413
mjr 77:0b96f6867312 414 // Optionally connect to a transmitter, to suppress reception while
mjr 77:0b96f6867312 415 // we're transmitting. This prevents spuriously receiving our own
mjr 77:0b96f6867312 416 // transmissions, if our IR LED and sensor are physically close enough
mjr 77:0b96f6867312 417 // to one another that our sensor would pick up light from our LED.
mjr 77:0b96f6867312 418 // If the two are physically isolated so that we can't receive our
mjr 77:0b96f6867312 419 // own transmissions, it's not necessary to connect the transmitter
mjr 77:0b96f6867312 420 // here, as there's no restriction on the software side on sending
mjr 77:0b96f6867312 421 // and receiving simultaneously - the suppression is only needed to
mjr 77:0b96f6867312 422 // avoid self-interference with the physical IR signals.
mjr 77:0b96f6867312 423 void setTransmitter(class IRTransmitter *transmitter)
mjr 77:0b96f6867312 424 {
mjr 77:0b96f6867312 425 this->transmitter = transmitter;
mjr 77:0b96f6867312 426 }
mjr 77:0b96f6867312 427
mjr 77:0b96f6867312 428 // Enable/disable our interrupt handlers. If the main program
mjr 77:0b96f6867312 429 // doesn't need IR input, it can disable the receiver so that
mjr 77:0b96f6867312 430 // it doesn't consume any CPU time handling interrupts.
mjr 77:0b96f6867312 431 void enable();
mjr 77:0b96f6867312 432 void disable();
mjr 77:0b96f6867312 433
mjr 77:0b96f6867312 434 // Read a command. Returns true if a command was available, filling
mjr 77:0b96f6867312 435 // in 'cmd'. Returns false (without blocking) if no commands are
mjr 77:0b96f6867312 436 // available.
mjr 77:0b96f6867312 437 bool readCommand(IRCommand &cmd) { return commands.read(cmd); }
mjr 77:0b96f6867312 438
mjr 77:0b96f6867312 439 // Is a command ready to read?
mjr 77:0b96f6867312 440 bool isCommandReady() { return commands.readReady(); }
mjr 77:0b96f6867312 441
mjr 77:0b96f6867312 442 // Process signals received. The application main loop must call this
mjr 77:0b96f6867312 443 // as frequently as possible to process incoming signals from the raw
mjr 77:0b96f6867312 444 // buffer. This processes all samples in the raw buffer before
mjr 77:0b96f6867312 445 // returning.
mjr 77:0b96f6867312 446 void process();
mjr 77:0b96f6867312 447
mjr 77:0b96f6867312 448 // Process and retrieve one raw pulse. The application main loop can
mjr 77:0b96f6867312 449 // optionally call this, instead of process(), if it wants to retrieve
mjr 77:0b96f6867312 450 // each raw sample for its own purposes in addition to running them
mjr 77:0b96f6867312 451 // through the protocol state machines. If no sample is available, we
mjr 77:0b96f6867312 452 // immediately return false - the routine doesn't block waiting for a
mjr 77:0b96f6867312 453 // sample. If a sample is available, we fill in 'sample' with the pulse
mjr 77:0b96f6867312 454 // time in microseconds, and set 'mark' to true if the sample was a mark,
mjr 77:0b96f6867312 455 // false if it's a space.
mjr 77:0b96f6867312 456 //
mjr 77:0b96f6867312 457 // To use this instead of process(), on each main loop iteration, call
mjr 77:0b96f6867312 458 // this function in an inner loop until it returns false. That'll ensure
mjr 77:0b96f6867312 459 // that all pending samples have been processed through the protocol
mjr 77:0b96f6867312 460 // state machines and that maximum buffer space is available for the next
mjr 77:0b96f6867312 461 // main loop iteration.
mjr 77:0b96f6867312 462 bool processOne(uint32_t &sample, bool &mark);
mjr 77:0b96f6867312 463
mjr 77:0b96f6867312 464 // Process and retrieve one raw pulse. This works the same as the
mjr 77:0b96f6867312 465 // two-argument version above, but returns the sample in our internal
mjr 77:0b96f6867312 466 // format: the sample value is a time reading in 2us units, and the low
mjr 77:0b96f6867312 467 // bit is 1 for a mark, 0 for a space. To convert to a time reading in
mjr 77:0b96f6867312 468 // microseconds, mask out the low bit and multiply by 2.
mjr 77:0b96f6867312 469 bool processOne(uint16_t &sample);
mjr 77:0b96f6867312 470
mjr 77:0b96f6867312 471 // Maximum pulse length in microseconds. Anything longer will simply
mjr 77:0b96f6867312 472 // be represented with this value. This is long enough that anything
mjr 77:0b96f6867312 473 // longer has equivalent meaning in any of our protocols. Generally,
mjr 77:0b96f6867312 474 // space longer than this will only occur in a silent interval between
mjr 77:0b96f6867312 475 // transmissions (that is, while no one is sending any codes), and a
mjr 77:0b96f6867312 476 // mark longer than this could only be interference or noise.
mjr 77:0b96f6867312 477 //
mjr 77:0b96f6867312 478 // This value should be chosen so that it's high enough to be readily
mjr 77:0b96f6867312 479 // distinguishable (in terms of our error tolerance) from the longest
mjr 77:0b96f6867312 480 // *meaningful* space or pulse in any protocol we need to handle, but
mjr 77:0b96f6867312 481 // not much higher than that. It shouldn't be too long because it has
mjr 77:0b96f6867312 482 // a role as an inactivity timeout on receive: we can't always know
mjr 77:0b96f6867312 483 // that a signal has ended until there's inactivity for this amount
mjr 77:0b96f6867312 484 // of time. If the timeout is too long, it can become noticable as
mjr 77:0b96f6867312 485 // lag time in recognizing signals. In practice, the longest gap time
mjr 77:0b96f6867312 486 // between repeating signals in commonly used protocols is in the
mjr 77:0b96f6867312 487 // neighboorhood of 100ms.
mjr 77:0b96f6867312 488 //
mjr 77:0b96f6867312 489 // This value is chosen to be the largest we can fit into a 16-bit
mjr 77:0b96f6867312 490 // int, taking into account our 2X scaling and our use of the low bit
mjr 77:0b96f6867312 491 // for a mark/space indicator. That leaves us with 14 bits and 2X scale.
mjr 77:0b96f6867312 492 static const uint32_t MAX_PULSE = 131068;
mjr 77:0b96f6867312 493
mjr 77:0b96f6867312 494 private:
mjr 82:4f6209cb5c33 495 // Input pin. Reads from a TSOP384xx or similar sensor. Any
mjr 77:0b96f6867312 496 // sensor should work that demodulates the carrier wave and
mjr 82:4f6209cb5c33 497 // gives us an active-low input on the pin.
mjr 82:4f6209cb5c33 498 //
mjr 82:4f6209cb5c33 499 // Note that we use our FastInterruptIn replacement instead of the
mjr 82:4f6209cb5c33 500 // mbed InterruptIn. We don't actually need the higher speed here of
mjr 82:4f6209cb5c33 501 // FastInterruptIn, but we have to use it anyway because other parts
mjr 82:4f6209cb5c33 502 // of the system use it. The two classes don't play nice together:
mjr 82:4f6209cb5c33 503 // the whole app has to use one or the other.
mjr 82:4f6209cb5c33 504 FastInterruptIn pin;
mjr 77:0b96f6867312 505
mjr 77:0b96f6867312 506 // IR raw data buffer. The interrupt handlers store the pulse
mjr 77:0b96f6867312 507 // timings here as they arrive, and the process() routine reads from
mjr 77:0b96f6867312 508 // the buffer.
mjr 77:0b96f6867312 509 //
mjr 77:0b96f6867312 510 // Samples here are limited to 16 bits, so the longest time that
mjr 77:0b96f6867312 511 // can be represented is 65535us. Anything longer is capped to this.
mjr 77:0b96f6867312 512 //
mjr 77:0b96f6867312 513 // To keep track of marks vs spaces, we set the low-order bit of
mjr 77:0b96f6867312 514 // each sample time to 1 for a mark and 0 for a space. That means
mjr 77:0b96f6867312 515 // that the times are only good to 2us precision, but that's plenty
mjr 77:0b96f6867312 516 // of precision for all of the IR protocols, since the shortest time
mjr 77:0b96f6867312 517 // bases are around 250us.
mjr 77:0b96f6867312 518 CircBufV<uint16_t> rawbuf;
mjr 77:0b96f6867312 519
mjr 77:0b96f6867312 520 // Pulse timer. We reset the timer at the start of each pulse, so
mjr 77:0b96f6867312 521 // it tells us the duration thus far of the current pulse at any
mjr 77:0b96f6867312 522 // given time. We stop the timer (without resetting) any time a
mjr 77:0b96f6867312 523 // pulse reaches the maximum length, to ensure that the timer never
mjr 77:0b96f6867312 524 // rolls over, even in the indefinite gap between codes.
mjr 77:0b96f6867312 525 Timer pulseTimer;
mjr 77:0b96f6867312 526
mjr 77:0b96f6867312 527 // flag: the pulse timer has reached IR_MAX_PULSE
mjr 77:0b96f6867312 528 bool pulseAtMax;
mjr 77:0b96f6867312 529
mjr 77:0b96f6867312 530 // current pulse state: mark = 1, space = 0
mjr 77:0b96f6867312 531 bool pulseState;
mjr 77:0b96f6867312 532
mjr 77:0b96f6867312 533 // start the pulse timers with the new pulse state (1=mark, 0=space)
mjr 77:0b96f6867312 534 void startPulse(bool newPulseState);
mjr 77:0b96f6867312 535
mjr 77:0b96f6867312 536 // end the current pulse, checking that the pulse state matches the
mjr 77:0b96f6867312 537 // current state
mjr 77:0b96f6867312 538 void endPulse(bool lastPulseState);
mjr 77:0b96f6867312 539
mjr 77:0b96f6867312 540 // process a pulse through our protocol handlers
mjr 77:0b96f6867312 541 void processProtocols(uint32_t t, bool mark);
mjr 77:0b96f6867312 542
mjr 77:0b96f6867312 543 // rise and fall interrupt handlers for the input pin
mjr 82:4f6209cb5c33 544 static void cbFall(void *obj) { ((IRReceiver *)obj)->fall(); }
mjr 82:4f6209cb5c33 545 static void cbRise(void *obj) { ((IRReceiver *)obj)->rise(); }
mjr 82:4f6209cb5c33 546 void fall();
mjr 82:4f6209cb5c33 547 void rise();
mjr 82:4f6209cb5c33 548
mjr 77:0b96f6867312 549 // timeout for time-limited states
mjr 77:0b96f6867312 550 Timeout timeout;
mjr 77:0b96f6867312 551
mjr 77:0b96f6867312 552 // timeout handler for a pulse (mark or space)
mjr 77:0b96f6867312 553 void pulseTimeout(void);
mjr 77:0b96f6867312 554
mjr 77:0b96f6867312 555 // Connected transmitter. If this is set, we'll suppress reception
mjr 77:0b96f6867312 556 // while the transmitter is sending a signal, to avoid receiving our
mjr 77:0b96f6867312 557 // own transmissions.
mjr 77:0b96f6867312 558 class IRTransmitter *transmitter;
mjr 77:0b96f6867312 559 };
mjr 77:0b96f6867312 560
mjr 77:0b96f6867312 561 #endif