An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.

Dependencies:   mbed FastIO FastPWM USBDevice

Fork of Pinscape_Controller by Mike R

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers IRTransmitter.h Source File

IRTransmitter.h

00001 // IR Remote Transmitter
00002 //
00003 // This class lets you control an IR emitter LED connected to a GPIO port 
00004 // to transmit remote control codes using numerous standard and proprietary 
00005 // protocols.  You can use this to send remote codes to any device with
00006 // a typical IR remote, such as A/V equipment, home automation devices, etc.
00007 // You can also use this with the companion IR Receiver class running on
00008 // a separate KL25Z to send IR commands to the other device.
00009 //
00010 // We do all of our transmissions with specific protocols rather than raw
00011 // IR signals.  Every remote control has its own way of representing a
00012 // string of data bits as a series of timed IR flashes.  The exact mapping
00013 // between data bits and IR flashes is the protocol.  There are some quasi
00014 // industry standard protocols, where several companies use the same format
00015 // for their codes, but there are many proprietary protocols as well.  We
00016 // have handlers for the most widely used protocols:  NEC, Sony, Philips RC5
00017 // and RC6, Pioneer, Panasonic, and several others.  If your device isn't
00018 // covered yet, it could probably be added, since we've tried to design
00019 // the system to make it easy to add new protocols.
00020 //
00021 // When you transmit a code, you specify it in terms of the protocol to use 
00022 // and the "code" value to send.  A "code" is just the data value for a
00023 // particular key on a particular remote control, usually expressed as a 
00024 // hex number.  There are published tables of codes for many remotes, but
00025 // unfortunately they're not very consistent in how they represent the hex
00026 // code values, so you'll often see the same key represented with different
00027 // hex codes in different published tables.  We of course have our own way
00028 // of mapping the hex codes; we've tried to use the format that the original
00029 // manufacturer uses in their tales, if they publish them at all, but these
00030 // may or may not be consistent with what you find in any tables you consult.
00031 // So your best bet for finding the right codes to use here is usually to 
00032 // "learn" the codes using our companion class IRReceiver.  That class has a 
00033 // protocol decoder for each protocol transmitter we can use here, so if you
00034 // set that up and point a remote at it, it will tell you the exact code we
00035 // use for the key.
00036 //
00037 // The transmitter class provides a "virtual remote control" interface.
00038 // This gives you an imaginary remote control keypad, with a set of
00039 // virtual buttons programmed for individual remote control commands.
00040 // You specify the protocol and command code for each virtual button.
00041 // You can use different protocols for different buttons.
00042 //
00043 //
00044 // How to use the software
00045 //
00046 // First, create an instance of IRTransmitter, telling it which pin the
00047 // IR emitter is connected to (see below for wiring instructions) and how
00048 // many virtual remote control keys you want.  The pin must be PWM capable.
00049 //
00050 //    IRTransmitter *tx = new IRTransmitter(PTC9, 32);
00051 //
00052 // Next, program the virtual remote keys.  For each key, set the IR protocol
00053 // to use (an IRPRO_xxx code from IRProtocolID.h), the "ditto" mode (more on
00054 // this below), and the hex code for the command.
00055 //
00056 //    // program virtual button #0 with Sony 20-bit code 0x123, no dittos
00057 //    tx->programButton(0, IRPRO_SONY20, false, 0x123);
00058 //
00059 // Now you're set up to transmit.  In your main loop, decide when it's time
00060 // to transmit a button, such as by monitoring a physical pushbutton via a
00061 // GPIO DigitalIn pin.  When you want to transmit a code, just tell the
00062 // transmitter that your virtual button is pressed, by calling pushButton()
00063 // with the virtual button ID (corresponding to a virtual button ID you
00064 // previously programmed wtih programButton()) and a status of 'true',
00065 // meaning that the button is pressed.
00066 //
00067 //    tx->pushButton(0, true);  // push virtual button #0
00068 //
00069 // This starts the transmission and returns immediately.  The transmission
00070 // proceeds in the background (via timer interrupts), so your main loop can
00071 // go about its other business without waiting for the transmission to
00072 // finish.  Most remote codes take 50ms to 100ms to transmit, and you don't
00073 // usually want to stall an MCU app for that long.
00074 //
00075 // If a prior transmission is still in progress when you call pushButton(), 
00076 // the new transmission doesn't interrupt the previous one.  Every code is
00077 // sent as a complete unit to ensure data integrity, so the old one has to
00078 // finish before the new one starts.  Some protocols have minimum repeat
00079 // counts, and the transmitter takes this into account as well.  For example,
00080 // the Sony protocols require each command to be sent at least three times,
00081 // even if the button is only tapped for a brief instant.  So if you send
00082 // a Sony code, a new command won't start transmitting until the last command
00083 // has been sent completely, not just once, but at least three times.
00084 //
00085 // Once the transmitter starts sending the code for a new button, it keeps
00086 // sending the same code on auto-repeat until you either un-press the
00087 // virtual button or press a new virtual button.  Handling auto-repeat
00088 // in the transmitter like this has an important benefit, besides just making
00089 // the API simpler: it allows the transmitter to use the proper coding for
00090 // the repeats according to the rules of the protocol.  Some protocols use
00091 // a different format for the first code of a key press and auto-repeats
00092 // of the same key.  Some protocols also have other repetition features,
00093 // such as "toggle bits" or sequence counters.  The protocol handlers use
00094 // the appropriate handling for their protocols, so you only have to think
00095 // in terms of when the virtual buttons are pressed and un-pressed, without
00096 // worrying about whether a toggle bit or a "ditto" code or a sequence
00097 // counter is needed.
00098 //
00099 // When the button is no longer pressed, call pushButton() again with a
00100 // status of 'false':
00101 //
00102 //    tx->pushButton(0, false);
00103 //
00104 // Multiple button presses use simple PC keyboard-like semantics.  At any
00105 // given time, there can be only one pressed button.  When you call 
00106 // pushButton(N, true), N becomes the pressed button, which means that the
00107 // previous pressed button (if any) is forgotten.  As mentioned above, this
00108 // doesn't cancel the previous transmission if it's still in progress.  The
00109 // transmitter continues with the last code until it's finished.  When it
00110 // finishes with a code, the transmitter looks to see if the same button is
00111 // still pressed.  If so, it starts a new transmission for the same button,
00112 // using the appropriate repeat code.  If a new button is pressed, the
00113 // transmitter starts transmitting the new button's code.  If no button is
00114 // pressed, the transmitter stops sending and becomes idle until you press
00115 // another button.
00116 //
00117 // Note that button presses aren't queued.  Suppose you press button #0
00118 // (while no other code is being sent): this starts transmitting the code
00119 // for button #0 and returns.  Now suppose that a very short time later, 
00120 // while that first send is still in progress, you briefly press and release
00121 // button #1.  Button #1 will never be sent in this case.  When you press
00122 // button #1, the transmitter is still sending the first code, so all it
00123 // does at this point is mark button #1 as the currently pressed button,
00124 // replacing button #0.  But as explained above, this doesn't cancel the
00125 // button #0 code transmission in progress.  That continues until the
00126 // complete code has been sent.  At that point, the transmitter looks to
00127 // see which button is pressed, and discovers that NO button is pressed:
00128 // you already told it button #1 was released.  So the transmitter simply
00129 // stops sending and becomes idle.
00130 //
00131 //
00132 // How to determine command codes and the "ditto" mode
00133 //
00134 // Our command codes are expressed as 64-bit integers.  The code numbers
00135 // are in essence the data bits transmitted in the IR signal, but the mapping
00136 // between the IR data bits and the 64-bit code value is different for each
00137 // protocol.  We've tried to make our codes match the numbers shown in the
00138 // tables published by the respective manufacturers for any given remote,
00139 // but you might also find third-party tables that have completely different
00140 // mappings.  The easiest thing to do, really, is to ignore all of that and
00141 // just treat the codes as arbitrary, opaque identifiers, and identify the
00142 // codes for the remote you want to use by "learning" them.  That is, set up
00143 // a receiver with our companion class IRReceiver, point your remote at it,
00144 // and see what IRReceiver reports as the decoded value for each button. 
00145 // Simply use the same code value for each button when sending.
00146 //
00147 // The "ditto" flag is ignored for most protocols, but it's important for a
00148 // few, such as the various NEC protocols.  This tells the sender whether to
00149 // use the protocol's special repeat code for auto-repeats (true), or to send
00150 // send the same key code repeatedly (false).  The concept of dittos only
00151 // applies to a few protocols; most protocols just do the obvious thing and
00152 // send the same code repeatedly when you hold down a key.  But the NEC
00153 // protocols and a few others have special coding for repeated keys.  It's 
00154 // important to use the special coding for devices that expect it, because 
00155 // it lets them distinguish auto-repeat from multiple key presses, which
00156 // can affect how they respond to certain commands.  The tricky part is that 
00157 // manufacturers aren't always consistent about using dittos even when it's
00158 // a standard part of the protocol they're using, so you have to determine
00159 // whether or not to use it on a per-device basis.  The easiest way to do
00160 // this is just like learning codes: set up a receiever with IRReceiver and
00161 // see what it reports.  But this time, you're interested in what happens
00162 // when you hold down a key.  You'll always get one ordinary report first,
00163 // but check what happens for the repeats.  If IRReceiver reports the same 
00164 // code repeatedly, set dittos = false when sending those codes.  If the
00165 // repeats have the "ditto bit" set, though, set dittos = true when sending.
00166 //
00167 //
00168 // How to wire an IR emitter
00169 //
00170 // Any IR LED should work as the emitter.  I used a Vishay TSAL6400 for my
00171 // reference/testing implementation.  The TSAL6400 is quite bright, so it
00172 // should send signals well across fairly large distances.
00173 //
00174 // WARNING!  DON'T connect the LED directly to the GPIO pin.  KL25Z GPIO
00175 // pins have very low current limits - a typical IR emitter LED draws
00176 // enough current to damage or destroy the KL25Z.  You'll need to build a
00177 // simple transistor circuit to interface with the LED.  You'll need a
00178 // common small signal NPN transistor (such as a 2222 or 2N4401), a 2.2K
00179 // resistor, the IR LED, of course, and a current-limiting resistor for
00180 // the LED.  Choose the current-limiting resistor by plugging your LED's
00181 // specs into an LED resistor calculator, using a 5V supply voltage.  Now
00182 // connect the GPIO pin to the current-limiting resistor, connect the
00183 // resistor to the LED anode (+), connect the LED cathode (-) to the NPN
00184 // collector, connect the NPN emitter to ground, connect the NPN base to
00185 // the 2.2K resistor, and connect the 2.2K resistor to the GPIO pin.
00186 // It's simple enough for a schematic rendered in ASCII art:
00187 //
00188 //       +5V   (from the KL25Z +5V pin, or directly from
00189 //        |     the KL25Z's power supply)
00190 //        <
00191 //        >  R1 - use an LED resistor calculator to choose
00192 //        <       the resistor size based on your selected 
00193 //        |       LED's forward current & voltage and 5V source
00194 //       ---  +
00195 //       \ /  LED - Infrared emitter (e.g., Vishay TSAL6400)
00196 //       ---  -
00197 //        |
00198 //        |
00199 //         \|     2.2K
00200 //          |-----/\/\/\---> to this GPIO pin
00201 //         /|
00202 //        v
00203 //        |
00204 //      -----
00205 //       ---   Ground (KL25Z GND pin, or ground on the
00206 //        -            KL25Z's power supply)
00207 //
00208 // If you want to be able to see the transmitter in action, you can connect
00209 // another LED (a blue one, say) and its own current-limiting resistor in
00210 // parallel with the R1 + IR LED circuit.  Let's call the blue LED's
00211 // resistor R2.  Connect R2 to +5V, connect the other end of R2 to the
00212 // blue LED (+), and connect the blue LED (-) to the NPN collector.  This
00213 // will make the blue LED flash in sync with the IR LED.  IR remote control
00214 // codes are slow enough that you'll be able to see the blue LED come on
00215 // and flicker during each transmission, although the "bits" are too fast
00216 // to see individually with the naked eye.  The detector shouldn't be 
00217 // bothered by the extra light since these sensors have optical filters 
00218 // that block most of the incoming light outside of the IR band the sensor 
00219 // is looking for.
00220 
00221 #ifndef _IRTRANSMITTER_H_
00222 #define _IRTRANSMITTER_H_
00223 
00224 #include <mbed.h>
00225 
00226 #include "NewPwm.h"
00227 #include "IRRemote.h"
00228 #include "IRCommand.h"
00229 #include "IRProtocols.h"
00230 
00231 
00232 // IR Remote Transmitter
00233 class IRTransmitter
00234 {
00235 public:
00236     // Construct.  
00237     //
00238     // 'pin' is the GPIO pin controlling the IR LED.  The pin must be 
00239     // PWM-capable.  (Note also that each PWM channel on the KL25Z is 
00240     // shared among multiple pins, so be sure you're using a pin connected 
00241     // to a channel that isn't already used elsewhere in your application.)
00242     // Don't connect the LED directly to this pin; see the circuit diagram
00243     // at the top of the file for details of how to connect it through a
00244     // transistor to safely boost the current to LED levels.
00245     //
00246     // 'nButtons' is the number of virtual button slots to allocate.  Each
00247     // slot represents a virtual remote control button that can be programmed
00248     // with a remote code to transmit.  Allocate as many slots as you need
00249     // for unique commands or buttons.  Note that the caller is responsible
00250     // for deciding when a button is pressed; if you want to tie these to
00251     // physical buttons, you'll need to create your own DigitalIn objects
00252     // for the pins, monitor them, and call pushButton() to press and
00253     // release virtual buttons when the physical button states change.
00254     IRTransmitter(PinName pin, int nButtons) : ledPin(pin)
00255     {
00256         // make sure the protocol singletons are allocated
00257         IRProtocol::allocProtocols();
00258         
00259         // no command is active
00260         curBtnId = -1;
00261         
00262         // allocate the command list
00263         buttons = new ButtonCmd[nButtons];
00264         
00265         // the transmitter "thread" isn't yet running
00266         txRunning = false;
00267         txBtnId = -1;
00268         txProtocol = 0;
00269     }
00270     
00271     ~IRTransmitter()
00272     {
00273         delete[] buttons;
00274     }
00275     
00276     // Program the command code for a virtual button
00277     void programButton(int buttonId, int protocolId, bool dittos, uint64_t cmdCode)
00278     {
00279         ButtonCmd &btn = buttons[buttonId];
00280         btn.pro = protocolId;
00281         btn.dittos = dittos;
00282         btn.cmd = cmdCode;
00283     }
00284     
00285     // Push a virtual button.
00286     // 
00287     // When this is called, we'll start transmitting the command code
00288     // associated with the button immediately if no other transmission
00289     // is already in progress.  On the other hand, if a transmission of
00290     // a prior command code is already in progress, the previous command
00291     // isn't interrupted; we always send whole commands, and never
00292     // interrupt a command in progress.  Instead, the new button is
00293     // set as pending.  As soon as the prior transmission finishes,
00294     // the pending button becomes the current button and we start
00295     // transmitting its code - but only if the button is still pressed
00296     // when the previous code finishes.  This means that if you both 
00297     // press and release a button during the time that another 
00298     // transmission is in progress, the new button will never be 
00299     // transmitted.  We operate this way to keep things simple and
00300     // consistent when it comes to more than just one pending button.
00301     // This way we don't have to consider queues of pending buttons
00302     // or create mechanisms for canceling pending commands.
00303     //
00304     // If the button is still down when its first transmission ends,
00305     // and no other button has been pressed in the meantime, the button
00306     // will auto-repeat.  This continues as long as the button is still
00307     // pressed and no other button has been pressed.
00308     // 
00309     // Only one code can be transmitted at a time, obviously.  The
00310     // semantics for multiple simultaneous button presses are like those
00311     // of a PC keyboard.  Suppose you press button A, then a while later,
00312     // while A is still down, you press B.  Then a while later still,
00313     // you press C, continuing to hold both A and B down.  We transmit
00314     // A repeatedly until you press B, at which point we finish sending
00315     // the current repeat of A (we never interrupt a code in the middle:
00316     // once started, a code is always finished whole) and start sending
00317     // B.  B continues to repeat until you press C, at which point we
00318     // finish the last repetition of B and start sending C.  Once A or
00319     // B have been superseded, it makes no difference whether you continue
00320     // to hold them down or release them.  They'll never start repeating
00321     // again, even if you then release C while A and B are still down.
00322     void pushButton(int id, bool on)
00323     {
00324         if (on)
00325         {
00326             // make this the current command
00327             curBtnId = id;
00328 
00329             // start the transmitter
00330             txStart();
00331         }
00332         else
00333         {
00334             // if this is the current command, cancel it
00335             if (id == curBtnId)
00336                 curBtnId = -1;
00337         }
00338     }
00339     
00340     // Is a transmission in progress?
00341     bool isSending() const { return txRunning; }
00342     
00343 
00344 protected:
00345     // Start the transmitter "thread", if it's not already running.  The
00346     // thread is actually just a series of timer interrupts; each interrupt
00347     // sets the next interrupt at an appropriate interval, so the effect is
00348     // like a thread.
00349     void txStart()
00350     {
00351         if (!txRunning)
00352         {
00353             // The thread isn't running.  Note that this means that there's
00354             // no possibility that txRunning will change out from under us
00355             // asynchronously, since there's no pending interrupt handler
00356             // to change it.  Mark the thread as running.
00357             txRunning = true;
00358             
00359             // Directly invoke the thread handler for the first call.  It
00360             // will normally run in interrupt context, but since there's
00361             // no pending interrupt yet that would re-enter it, we can
00362             // launch it first in application context.  If there's work
00363             // pending, it'll kick off the transmission and schedule the
00364             // next timer interrupt to continue the thread.
00365             txThread();
00366         }
00367     }
00368     
00369     // Transmitter "thread" main.  This handles the timer interrupt for each
00370     // event in a transmission.
00371     void txThread()
00372     {
00373         // if we're working on a command, process the next step
00374         if (txProtocol != 0)
00375         {
00376             // Determine if the virtual button for the current transmission
00377             // is still pressed.  It's still pressed if we have a valid 
00378             // transmitting button ID, and the current pressed button is the 
00379             // same as the transmitting button.
00380             txState.pressed = (txBtnId != -1 && txBtnId == curBtnId);
00381 
00382             // Perform the next step via the protocol handler.  The handler
00383             // returns a positive time value for the next timeout if it still
00384             // has more work to do.
00385             int t = txProtocol->txStep(&txState);
00386             
00387             // check if the transmission is done
00388             if (t > 0)
00389             {
00390                 // The handler returned a positive time value, so it has
00391                 // more work to do.  That means we're done here - just set
00392                 // the next timeout and exit the interrupt handler.
00393                 txTimeout.attach_us(this, &IRTransmitter::txThread, t);
00394                 return;
00395             }
00396             else
00397             {
00398                 // The transmission is done.  Clear the send data.
00399                 txBtnId = -1;
00400                 txProtocol = 0;
00401             }
00402         }
00403         
00404         // If we made it here, the transmitter is now idle.  Check to
00405         // see if we have a new virtual button press.
00406         if (curBtnId != -1)
00407         {
00408             // load the command
00409             txBtnId = curBtnId;
00410             txCmd = buttons[curBtnId];
00411             txProtocol = IRProtocol::senderForId(txCmd.pro);
00412             
00413             // If we found a protocol handler, start the transmission
00414             if (txProtocol != 0)
00415             {
00416                 // fill in the transmission state object with the new command
00417                 // details
00418                 txState.cmdCode = txCmd.cmd;
00419                 txState.protocolId = txCmd.pro;
00420                 txState.dittos = txCmd.dittos;
00421                 txState.pin = &ledPin;
00422                 txState.pressed = true;
00423                 
00424                 // reset the transmission step counters
00425                 txState.step = 0;
00426                 txState.bit = 0;
00427                 txState.bitstep = 0;
00428                 txState.rep = 0;
00429                 
00430                 // this is a new transmission, so toggle the toggle bit
00431                 txState.toggle ^= 1;
00432                 
00433                 // Turn off the IR and set the PWM frequency of the IR LED to
00434                 // the carrier frequency for the chosen protocol
00435                 ledPin.write(0);
00436                 ledPin.getUnit()->period(txProtocol->pwmPeriod(&txState));
00437 
00438                 // start the transmission timer
00439                 txState.txTime.reset();
00440                 txState.txTime.start();
00441                 
00442                 // initiate the transmission
00443                 int t = txProtocol->txStart(&txState);
00444                 
00445                 // set the timer for the next step of the transmission, then
00446                 // we're done
00447                 txTimeout.attach_us(this, &IRTransmitter::txThread, t);
00448                 return;
00449             }
00450         }
00451         
00452         // If we made it here, there's no transmission in progress,
00453         // so the thread is no longer running.
00454         txRunning = false;
00455     }
00456 
00457     // LED output pin controlling the IR LED.  The pin must be PWM-capable.
00458     // WARNING!  Don't connect the IR LED directly to the pin.  See wiring
00459     // diagram at the top of the file.
00460     NewPwmOut ledPin;
00461     
00462     // Virtual button slots.  Each slot represents a virtual remote control
00463     // button, containing a preprogrammed IR command code to send when the 
00464     // button is pressed.  Program a button by calling programButton().
00465     // Press a button by calling pushButton().
00466     struct ButtonCmd
00467     {
00468         uint64_t cmd;           // command code
00469         uint8_t pro;            // protocol ID (IRPRO_xxx)
00470         uint8_t dittos : 1;     // use "ditto" codes for auto-repeat
00471     } __attribute__ ((packed));
00472     ButtonCmd *buttons;
00473     
00474     // Current active virtual button ID.   This is managed in application
00475     // context and read in interrupt context.  This represents the currently 
00476     // pushed button.
00477     int curBtnId;
00478     
00479     // Is the transmitter "thread" running?  This is true when a timer is
00480     // pending, false if not.  The timer interrupt handler clears this
00481     // before exiting on its last run of a transmission.
00482     //
00483     // Synchronization: if txRunning is false, no timer interrupt is either
00484     // running or pending, so there's no possibility that anyone else will
00485     // change it, so it's safe for the application to test and set it.  If
00486     // txRunning is true, only interrupt context can change it, so application
00487     // context can only read it.
00488     volatile bool txRunning;
00489     
00490     // Transmitter thread timeout
00491     Timeout txTimeout;
00492     
00493     // Command ID being transmitted in the background "thread".  The thread
00494     // loads this from curBtnID whenever it's out of other work to do.
00495     int txBtnId;
00496     
00497     // Protocol for the current transmission
00498     IRProtocol *txProtocol;
00499     
00500     // Command value we're currently transmitting
00501     ButtonCmd txCmd;
00502     
00503     // Protocol state.  This is for use by the individual protocol
00504     // classes to keep track of their state while the transmission
00505     // proceeds.
00506     IRTXState txState;
00507 };
00508 
00509 #endif