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
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
Generated on Wed Jul 13 2022 03:30:10 by 1.7.2