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 IRReceiver.cpp Source File

IRReceiver.cpp

00001 // IR Receiver
00002 //
00003 #include "IRReceiver.h"
00004 #include "IRTransmitter.h"
00005 #include "IRProtocols.h"
00006 
00007 // utility macro
00008 #define countof(arr) (sizeof(arr)/sizeof((arr)[0]))
00009 
00010 // Constructor
00011 IRReceiver::IRReceiver(PinName rxpin, size_t rawBufCount) : 
00012     pin(rxpin),
00013     rawbuf(rawBufCount)
00014 {
00015     // the TSOP384xx has an internal pull-up resistor, so we don't
00016     // need one of our own
00017     pin.mode(PullNone);
00018     
00019     // make sure the protocol singletons are allocated
00020     IRProtocol::allocProtocols();
00021     
00022     // there's no transmitter connected yet
00023     transmitter = 0;
00024 }
00025 
00026 // Destructor
00027 IRReceiver::~IRReceiver() {
00028 }
00029 
00030 // Enable reception
00031 void IRReceiver::enable()
00032 {
00033     // start the pulse timers
00034     startPulse(pin.read() ? 0 : 1);
00035     
00036     // set interrupt handlers for edges on the input pin
00037     pin.fall(&IRReceiver::cbFall, this);
00038     pin.rise(&IRReceiver::cbRise, this);
00039 }
00040 
00041 // Disable reception
00042 void IRReceiver::disable()
00043 {
00044      // Shut down all of our asynchronous handlers: remove the pin level
00045      // interrupts, stop the pulse timer, and cancel the maximum pulse 
00046      // length timeout.
00047      pin.fall(0);
00048      pin.rise(0);
00049      pulseTimer.stop();
00050      timeout.detach();
00051 }
00052 
00053 // Start a new pulse of the given type.
00054 void IRReceiver::startPulse(bool newPulseState)
00055 {
00056     // set the new state
00057     pulseState = newPulseState;
00058     
00059     // reset the pulse timer
00060     pulseTimer.reset();
00061     pulseTimer.start();
00062     pulseAtMax = false;
00063     
00064     // cancel any prior pulse timeout
00065     timeout.detach();
00066     
00067     // Set a new pulse timeout for the maximum pulse length
00068     timeout.attach_us(this, &IRReceiver::pulseTimeout, MAX_PULSE);
00069 }
00070 
00071 // End the current pulse
00072 void IRReceiver::endPulse(bool lastPulseState)
00073 {
00074     // Add the pulse to the buffer.  If the pulse already timed out,
00075     // we already wrote it, so there's no need to write it again.
00076     if (!pulseAtMax)
00077     {
00078         // get the time of the ending space
00079         uint32_t t = pulseTimer.read_us();
00080         
00081         // Scale by 2X to give us more range in a 16-bit int.  Since we're
00082         // also discarding the low bit (for the mark/space indicator below),
00083         // round to the nearest 4us by adding 2us before dividing.
00084         t += 2;
00085         t >>= 1;
00086         
00087         // limit the stored value to the uint16 maximum value
00088         if (t > 65535)
00089             t = 65535;
00090             
00091         // set the low bit if it's a mark, clear it if it's a space
00092         t &= ~0x0001;
00093         t |= lastPulseState;
00094 
00095         // add it to the buffer
00096         rawbuf.write(uint16_t(t));
00097     }
00098 }
00099 
00100 // Falling-edge interrupt.  The sensors we work with use active-low 
00101 // outputs, so a high->low edge means that we're switching from a "space"
00102 //(IR off) to a "mark" (IR on).
00103 void IRReceiver::fall(void) 
00104 {
00105     // If the transmitter is sending, ignore new ON pulses, so that we
00106     // don't try to read our own transmissions.
00107     if (transmitter != 0 && transmitter->isSending())
00108         return;
00109 
00110     // if we were in a space, end the space and start a mark
00111     if (!pulseState)
00112     {
00113         endPulse(false);
00114         startPulse(true);
00115     }
00116 }
00117 
00118 // Rising-edge interrupt.  A low->high edge means we're switching from
00119 // a "mark" (IR on) to a "space" (IR off).
00120 void IRReceiver::rise(void) 
00121 {
00122     // if we were in a mark, end the mark and start a space
00123     if (pulseState)
00124     {
00125         endPulse(true);
00126         startPulse(false);
00127     }
00128 }
00129 
00130 // Pulse timeout.  
00131 void IRReceiver::pulseTimeout(void)
00132 {
00133     // End the current pulse, even though it hasn't physically ended,
00134     // so that the protocol processor can read it.  Pulses longer than
00135     // the maximum are all the same to the protocols, so we can process
00136     // these as soon as we reach the timeout.  However, don't start a
00137     // new pulse yet; we'll wait to do that until we get an actual
00138     // physical pulser.
00139     endPulse(pulseState);
00140 
00141     // note that we've reached the pulse timeout
00142     pulseAtMax = true;
00143 }
00144 
00145 // Process the buffer contents
00146 void IRReceiver::process()
00147 {
00148     // keep going until we run out of samples
00149     uint16_t t;
00150     while (rawbuf.read(t))
00151     {
00152         // Process it through the protocol handlers.  Note that the low
00153         // bit is the mark/space indicator, not a time bit, so pull it
00154         // out as the 'mark' argument and mask it out of the time.  And
00155         // note that the value in the buffer is in 2us units, so multiply
00156         // by 2 to get microseconds.
00157         processProtocols((t & ~0x0001) << 1, t & 0x0001);
00158     }
00159 }
00160 
00161 // Process one buffer pulse
00162 bool IRReceiver::processOne(uint16_t &sample)
00163 {
00164     // try reading a sample
00165     if (rawbuf.read(sample))
00166     {
00167         // Process it through the protocols - convert to microseconds
00168         // by masking out the low bit and mulitplying by the 2us units
00169         // we use in the sample buffer, and pull out the low bit as
00170         // the mark/space type.
00171         processProtocols((sample & ~0x0001) << 1, sample & 0x0001);
00172         
00173         // got a sample
00174         return true;
00175     }
00176     
00177     // no sample
00178     return false;
00179 }
00180 
00181 // Process one buffer pulse
00182 bool IRReceiver::processOne(uint32_t &t, bool &mark)
00183 {
00184     // try reading a sample
00185     uint16_t sample;
00186     if (rawbuf.read(sample))
00187     {
00188         // it's a mark if the low bit is set
00189         mark = sample & 0x0001;
00190         
00191         // remove the low bit, as it's not actually part of the time value,
00192         // and multiply by 2 to get from the 2us units in the buffer to
00193         // microseconds
00194         t = (sample & ~0x0001) << 1;
00195         
00196         // process it through the protocol handlers
00197         processProtocols(t, mark);
00198         
00199         // got a sample
00200         return true;
00201     }
00202     
00203     // no sample
00204     return false;
00205 }
00206 
00207 // Process a pulse through the protocol handlers
00208 void IRReceiver::processProtocols(uint32_t t, bool mark)
00209 {
00210     // generate a call to each sender in the RX list
00211     #define IR_PROTOCOL_RX(cls) IRProtocol::protocols->s_##cls.rxPulse(this, t, mark);
00212     #include "IRProtocolList.h"
00213 }