Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

IRRemote/IRProtocols.h

Committer:
arnoz
Date:
2021-10-01
Revision:
116:7a67265d7c19
Parent:
97:fc7727303038

File content as of revision 116:7a67265d7c19:

// IR Remote Protocols
//
// This file implements a handlers for specific IR protocols.  A protocol
// is the set of rules that a particular IR remote uses to convert binary
// data to and from a series of timed infrared pulses.  A protocol generally
// encompasses a bit-level encoding scheme (how each data bit is represented 
// as one or more pulses of IR light) and a message or packet format (how a 
// series of bits is assembled to form a higher level datatype, which in the 
// case of an IR remote usually amounts to a representation of a key press 
// on a remote control).
//
// Lots of companies make CE products with remotes, and many of them use
// their own custom protocols.  There's some commonality; a few proprietary
// protocols, such as those from NEC and Philips, are quasi industry
// standards that multiple companies adopted, more or less intact.  On
// the other hand, other companies not only have their own systems but
// use multiple proprietary systems across different products.  So it'll
// never be possible for us to recognize every remote code out there.
// So we'll cover the widely used ones, and then add the rarer ones as
// needed.
//
// For each protocol we recognize, we define a subclass of IRReceiver
// that implements the code to encode and decode signals for the protocol.
// To send a command, we call the sender function for the protocol we want
// to use for the transmission.  When we receive a signal, we run it through
// each protocol class's decode routine, to determine which protocol the
// signal was encoded with and what the signal means.  The decoders can
// usually tell if a signal uses their protocol, since there's enough
// structure in most of the protocols that you can distinguish signals that
// use the protocol from those that don't.  This allows the decoders to 
// serve the dual purposes of decoding signals and also classifying them
// by protocol.
//
// To add support for a new protocol, we (a) define a class for it here,
// and (b) add an entry for the class to IRProtocolList.h.  The list entry
// automatically adds the new protocol to the tables we use to look up the
// desired protocol class when sending, and to check each supported protocol
// when receiving.
//
// The protocol decoders operate in parallel: as a transmission is received,
// we run the signal through all of the decoders at the same time.  This
// allows each decoder to keep track of the incoming pulse stream and 
// recognize messages that conform to its protocol.  The parallel operation
// means that each protocol object needs its own complete, independent
// receiver state.
//
// In contrast, there can only be one transmission in progress at a time,
// since a transmission obviously requires exclusive access to the IR LED.
// (You can't eve interleave two transmissions in theory, since the coding 
// is all about pulse timing and order.)  That means that we *don't* need
// separate independent transmitter state per object.  That lets us save
// a little memory by using a single, shared transmitter state object,
// managed by the global transmitter class and passed to the current
// transmitter on each send.  The exception would be any state that has
// to be maintained across, which would have to be tracked per protocol.
// The only common example is "toggle bits".
//

#ifndef _IRPROTOCOLS_H_
#define _IRPROTOCOLS_H_

#include <ctype.h>
#include "NewPwm.h"
#include "IRRemote.h"
#include "IRReceiver.h"
#include "IRProtocolID.h"
#include "IRCommand.h"

using namespace IRRemote;

struct DebugItem { char c; int t; DebugItem(char c, int t) : c(c),t(t) {} 
    DebugItem(char c) : c(c), t(0) { } DebugItem() : c(0), t(0) { }
};
extern CircBuf<DebugItem,256> debug;


// IR transmitter state object.
//
// We can only transmit one signal at a time, so we only need to keep
// track of the state of one transmission at a time.  This lets us 
// save a little memory by using a single combined state object that's
// shared by all transmitters.  The transmitter currently operating 
// uses the shared object for as long as the transmission takes.
struct IRTXState
{
    // Time since the transmission started
    Timer txTime;
    
    // The command code we're transmitting
    uint64_t cmdCode;
    
    // Bit stream to transmit.  Many of the protocols use a universal
    // command representation (in IRCommand.code) that rearranges the
    // bits from the transmission order.  This is a scratch pad where the
    // protocol handler can translate a command code back into transmission
    // order once at the start of the transmission, then just shift bits out 
    // of here to transmit them in sequence.
    uint64_t bitstream;
    
    // The IR LED control pin
    NewPwmOut *pin;
    
    // Protocol ID
    uint8_t protocolId;
    
    // Transmission step.  The meaning is up to the individual protocols,
    // but generally this is used to keep track of the current structural
    // part of the pulse stream we're generating.  E.g., a protocol might
    // use 0 for the header mark, 1 for the header space, etc.
    uint8_t step;
    
    // number of bits to transmit
    uint8_t nbits;
    
    // Current bit position within the data
    uint8_t bit;
    
    // Substep within the current bit.  Many of the protocols represent each 
    // bit as multiple IR symbols, such as mark+space.  This keeps track of 
    // the step within the current bit.
    uint8_t bitstep;
    
    // Repeat phase.  Some protocols have rules about minimum repeat counts,
    // or use different coding for auto-repeats.  This lets the sender keep
    // track of the current step.  For example, the Sony protocol requires
    // each message to be sent a minimum of 3 times.  The NEC protocol uses
    // a "ditto" code for each repeat of a code after the initial command.
    // The OrtekMCE protocol requires a minimum of 2 sends per code, and has 
    // a position counter within the code that indicates which copy we're on.
    uint8_t rep;
    
    // Is the virtual button that initiated this transmission still pressed?  
    // The global transmitter sets this before each call to txStep() to let
    // the protocol know if it should auto-repeat at the end of the code.
    uint8_t pressed : 1;

    // Use "ditto" codes when sending repeats?  Some protocols use special
    // coding for auto-repeats, so that receivers can tell whether a key
    // is being held down or pressed repeatedly.  But in some cases, the
    // same protocol may be used with dittos on some devices but without
    // dittos on other devices.  It's therefore not always enough to know
    // that the protocol supports dittos; we have to know separately whether
    // the device we're sending to wants them.  This flag lets the caller
    // tell us which format to use.  This is ignored if the protocol either
    // never uses dittos or always does: in that case we'll do whatever the
    // protocol specifies.  To implement a "learning remote", you should
    // make sure that the user holds down each key long enough for several
    // repeats when learning codes, so that the learning remote can determine
    // when dittos are used by observing how the repeats are sent from the
    // reference remote.  Then you can set this bit if you saw any ditto
    // codes during training for a given key.
    uint8_t dittos : 1;
    
    // TX toggle bit.  We provide this for protocols that need it.  Note
    // that this is a global toggle bit, so if we switch from transmitting
    // one protocol to another and then return to the first, we'll lose 
    // continuity with the toggle sequence in the original protocol.  But
    // that shouldn't be a problem: the protocols with toggles only use it
    // to distinguish two rapid presses of the same key in succession from 
    // auto-repeat while the key is held down.  If we had an intervening
    // transmission to another protocol, the original receiver will see a
    // long gap between the earlier and later messages; the toggle bit isn't
    // necessary in this case to tell that these were two key presses.
    uint8_t toggle : 1;    
};


// Base class for all protocols
//
// Note that most of the data parameters are set through virtuals rather
// than member variables.  This helps minimize the RAM footprint.
//
class IRProtocol
{
public:
    IRProtocol() { }
    virtual ~IRProtocol() { }
    
    // look up a protocol by ID
    static IRProtocol *senderForId(int id);
    
    // name and ID
    virtual const char *name() const = 0;
    virtual int id() const = 0;
    
    // Are we a transmitter for the given protocol?  Some protocol
    // handlers send and receive variations on a protocol that have
    // distinct protocol IDs, such as the various Sony codes at
    // different bit sizes.  By default, we assume we handle only
    // our nominal protocol as returned by id().
    virtual bool isSenderFor(int protocolId) const { return protocolId == id(); }

    // parse a pulse on receive
    virtual void rxPulse(IRRecvProIfc *receiver, uint32_t t, bool mark) = 0;
    
    // PWM carrier frequency used for the IR signal, expressed as a PWM
    // cycle period in seconds.  We use this to set the appropriate PWM
    // frequency for transmissions.  The most common carrier is 38kHz.
    //
    // We can't use adjust the carrier frequency for receiving signals, since 
    // the TSOP sensor we use does the demodulation at a fixed frequency.
    // You can choose a frequency by choosing your sensor, since TSOP sensors
    // are available in a range of carrier frequencies, but once you choose a
    // sensor we can't change its frequency in software.  Fortunately, the 
    // TSOP384xx seems tolerant in practice of a fairly wide range around
    // its nominal 38kHz carrier.  I've successfully tested it with remotes
    // documented to use frequencies from 36 to 40 kHz.  Most CE remotes 
    // fall within this range, so the 38kHz sensor makes a good universal
    // receiver.
    virtual float pwmPeriod(IRTXState *state) const { return 26.31578947e-6f; } // 38kHz
    
    // PWM duty cycle when transmitting.  This is the proportion of On to
    // Off time for each PWM pulse.  A few of the IR protocols that have
    // official documentation do specify a duty cycle, so when this is laid
    // out in the spec, it's probably a good idea to use the same value in
    // our protocol implementation.  In practice, though, it doesn't seem 
    // to be an important parameter as far as the receivers are concerned,
    // and I'm not sure it actually matters for any of the protocols.  To 
    // the extent it's specified at all, they might just be documenting the 
    // original manufacturer's implementation rather than specifying a
    // requirement.
    virtual float pwmDutyCycle() const { return .3f; }
    
    // Begin transmitting the given command.  Before calling, the caller
    // turns off the IR LED and sets its PWM period to the one given by
    // our pwmPeriod() method.  The caller also clears 'state', and then
    // sets the 'cmd', 'pin', and 'pressed' fields.  The rest of the struct
    // is for the protocol handler's private use during the transmission.
    // handler is free to store its interim state here to pass information
    // from txStart() to txStep() and from one txStep() to the next.
    // 
    // Subclass implementations should start by setting up 'state' with any
    // data they need during the transmission.  E.g., convert the code word
    // value into a series of bits to transmit, and store this in the
    // 'bitstream' field.  Once that's set up, determine how long the initial
    // gap should be (the IR off time between transmissions in the protocol),
    // and return this time in microseconds.  The caller will return to
    // other work while the gap time is elapsing, then it will call txStep()
    // to advance to the next step of the transmission.
    //
    // DON'T do a timer pause or spin wait here.  This routine is called in
    // interrupt context, so it must return as quickly as possible.  All
    // waits should be done simply by returning the desired wait time.
    //
    // By convention, implementations should start each transmission with a
    // sufficient gap time (IR off) to allow senders to recognize the new
    // transmission.  It's best to put the gap time at the *start* of each
    // new transmission rather than at the end because two consecutive
    // transmissions might use different protocols with different timing
    // requirements.  If the first protocol has a short gap time and the
    // second has a long gap time, putting the gap at the end of the first
    // transmission would only use the shorter time, which might not be
    // sufficient for the second protocol's receiver.
    virtual int txStart(IRTXState *state) = 0;
        
    // Continue a transmission with the next pulse step.  This carries
    // out the next step of the transmission, then returns a time value
    // with the number of microseconds until the next event.  For example,
    // if the current step in the transmission is a 600us mark, turn on the
    // IR transmitter, update 'state' to indicate that we're in the mark,
    // and return 600 to tell the caller to go do other work while the
    // mark is being sent.  Don't wait or spin here, since this is called
    // in interrupt context and should thus return as quickly as possible.
    //
    // Before calling this, the caller will update the 'pressed' field in
    // 'state' to let us know if the virtual button is still being pressed.
    // The protocol handler can auto-repeat if the button is still pressed
    // at the end of the current transmission, if that's appropriate for
    // the protocol.  We let the handlers choose how to handle auto-repeat
    // rather than trying to manage it globally, since there's a lot of
    // variation in how it needs to be handled.  Some protocols, for example,
    // use "ditto" codes (distinct codes that mean "same as last time"
    // rather than actually re-transmitting a full command), while others
    // have internal position markers to indicate a series of repeats
    // for one key press.
    virtual int txStep(IRTXState *state) = 0;
    
    // protocol singletons
    static class IRProtocols *protocols;
    
    // allocate the protocol singletons, if we haven't already
    static void allocProtocols();
        
protected:
    // report code with a specific protocol and sub-protocol
    void reportCode(IRRecvProIfc *receiver, int pro, uint64_t code, bool3 toggle, bool3 ditto);
};

// -----------------------------------------------------------------------
//
// Protocol containing a decoded command value
//
template<class CodeType> class IRPWithCode: public IRProtocol
{
public:
    IRPWithCode() 
    {
        rxState = 0;
        bit = 0;
        code = 0;
    }
    
    // Minimum gap on receive (space before header)
    virtual uint32_t minRxGap() const = 0;
    
    // Gap time to send on transmit between before the first code, and
    // between repeats.  By default, we use the the generic txGap() in
    // both cases.
    virtual uint32_t txGap(IRTXState *state) const = 0;
    virtual uint32_t txPreGap(IRTXState *state) const { return txGap(state); }
    virtual uint32_t txPostGap(IRTXState *state) const { return txGap(state); }
    
    // Minimum number of repetitions when transmitting.  Some codes
    // (e.g., Sony) require a minimum repeat count, no matter how
    // quickly the button was released.  1 means that only a single
    // transmission is required, which is true of most codes.
    virtual int txMinReps(IRTXState *state) const { return 1; }
    
    // Header mark and space length.  Most IR protocols have an initial
    // mark and space of fixed length as a lead-in or header.  Being of
    // fixed length, they carry no data themselves, but they serve three
    // useful functions: the initial mark can be used to set an AGC level
    // if the receiver needs it (the TSOP sensors don't, but some older
    // devices did); they can help distinguish one protocol from another
    // by observing the distinctive timing of the header; and they serve
    // as synchronization markers, by using timing that can't possibly
    // occur in the middle of a code word to tell us unambiguously that
    // we're at the start of a code word.
    //
    // Not all protocols have the lead-in mark and/or space.  Some
    // protocols simply open with the initial data bit, and others use
    // an AGC mark but follow it immediately with a data bit, with no
    // intervening fixed space.
    //
    // * If the protocol doesn't use a header mark at all but opens with
    // a mark that's part of a data bit, set tHeaderMark() to 0.
    //
    // * If the protocol has a fixed AGC mark, but follows it with a 
    // varying-length space that's part of the first data bit, set 
    // tHeaderMark() to the fixed mark length and set tHeaderSpace() to 0.
    //
    virtual uint32_t tHeaderMark() const = 0;
    virtual uint32_t tHeaderSpace() const = 0;
    
    // Can the header space be adjacent to a data space?  In most protocols,
    // the header space is of constant length because it's always followed
    // by a mark.  This is accomplished in some protocols with explicit
    // structural marks; in some, it happens naturally because all bits start
    // with marks (e.g., NEC, Sony); and in others, the protocol requires a
    // a "start bit" with a fixed 0 or 1 value whose representation starts
    // with a mark (e.g., RC6).  But in a few protocols (e.g., OrtekMCE),
    // there's no such care taken, so the header space can flow into a space 
    // at the start of the first data bit.  Set this to true for such
    // protocols, and we'll divvy up the space after the header mark into
    // a fixed part and a data portion for the first bit.
    virtual bool headerSpaceToData() const { return false; }
    
    // Ditto header.  For codes with dittos that use a distinct header
    // format, this gives the header timing that identifies a ditto.
    // Return zero for a code that doesn't use dittos at all or encodes
    // them in some other way than a distinctive header (e.g., in the
    // payload data).
    virtual uint32_t tDittoMark() const { return 0; }
    virtual uint32_t tDittoSpace() const { return 0; }
    
    // Stop mark length.  Many codes have a fixed-length mark following
    // the data bits.  Return 0 if there's no final mark.
    virtual uint32_t tStopMark() const { return 0; }
    
    // Number of bits in the code.  For protocols with multiple bit
    // lengths, use the longest here.
    virtual int nbits() const = 0;
    
    // true -> bits arrive LSB-first, false -> MSB first
    virtual bool lsbFirst() const { return true; }

    // Pulse processing state machine.
    // This state machine handles the basic protocol structure used by
    // most IR remotes:
    //
    //   Header mark of fixed duration
    //   Header space (possibly followed directly by the first bit's space)
    //   Data bits
    //   Stop mark
    //   Gap between codes
    //   Ditto header mark   }  a pattern that's distinguishable from
    //   Ditto header space  }   the standard header mark
    //   Ditto data bits
    //   Gap betwee codes
    //
    // The state machine can handle protocols that use all of these sections,
    // or only a subset of them.  For example, a few protocols (Denon, RC5)
    // have no header at all and start directly wtih the data bits.  Most
    // protocols have no "ditto" coding and just repeat the main code to
    // signal auto-repeat.  
    //
    // The monolithic state machine switch looks kind of ugly, but it seems
    // to be the cleanest way to handle this.  My initial design was more OO,
    // using virtual subroutines to handle each step.  But that turned out to
    // be fragile, because there was too much interaction between the handlers
    // and the overall state machine sequencing.  The monolithic switch actually
    // seems much cleaner in practice.  The variations are all handled through
    // simple data parameters.  The resulting design isn't as flexible in
    // principle as something more virtualized at each step, but nearly all
    // of the IR protocols I've seen so far are so close to the same basic
    // structure that this routine works for practically everything.  Any
    // protocols that don't fit the same structure will be best served by
    // replacing the whole state machine for the individual protocols.
    virtual void rxPulse(IRRecvProIfc *receiver, uint32_t t, bool mark)
    {
        uint32_t tRef;
        switch (rxState)
        {
        case 0:
        s0:
            // Initial gap or inter-code gap.  When we see a space of
            // sufficient length, switch to Header Mark mode.
            rxState = (!mark && t > minRxGap() ? 1 : 0);
            break;
            
        case 1:
        s1:
            // Header mark.  If the protocol has no header mark, go
            // straight to the data section.  Otherwise, if we have
            // a mark that matches the header mark we're expecting, 
            // go to Header Space mode.  Otherwise, we're probably in
            // the middle of a code that we missed the beginning of, or
            // we're just receiving a code using another protocol.  Go
            // back to Gap mode - that will ignore everything until we
            // get radio silence for long enough to be sure we're 
            // starting a brand new code word.
            if ((tRef = tHeaderMark()) == 0)
                goto s3;
            rxState = (mark && inRange(t, tRef) ? 2 : 0);
            break;
            
        case 2:
        s2:
            // Header space.  If the protocol doesn't have a header
            // space, go straight to the data.
            if ((tRef = tHeaderSpace()) == 0)
                goto s3;            
                
            // If this protocol has an undelimited header space, make
            // sure this space is long enough to qualify, but allow it
            // to be longer.  If it qualifies, deduct the header space
            // span from it and apply the balance as the first data bit.
            if (headerSpaceToData() && aboveRange(t, tRef, tRef))
            {
                t -= tRef;
                goto s3;
            }
            
            // If we have a space matching the header space, enter the
            // data section. 
            if (!mark && inRange(t, tRef))
            {
                rxState = 3;
                break;
            }
            
            // Not a match - go back to gap mode
            goto s0;
            
        case 3:
        s3:
            // enter data section
            rxReset();
            if (mark) 
                goto s4;
            else 
                goto s5;
            
        case 4:
        s4:
            // data mark
            if (mark && rxMark(receiver, t))
            {
                rxState = bit < nbits() ? 5 : 7;
                break;
            }
            goto s0;
            
        case 5:
        s5:
            // data space
            if (!mark && rxSpace(receiver, t))
            {
                rxState = bit < nbits() ? 4 : 6;
                break;
            }
            else if (!mark && t > minRxGap())
                goto s7;
            goto s0;
            
        case 6:
            // stop mark - if we don't have a mark, go to the gap instead
            if (!mark)
                goto s7;
                
            // check to see if the protocol even has a stop mark
            if ((tRef = tStopMark()) == 0)
            {
                // The protocol has no stop mark, and we've processed
                // the last data bit.  Close the data section and go
                // straight to the next header.
                rxClose(receiver, false);
                goto s8;
            }
            
            // there is a mark - make sure it's in range
            if (inRange(t, tRef))
            {
                rxState = 7;
                break;
            }
            goto s0;
            
        case 7: 
        s7:
            // end of data - require minimum gap
            if (!mark && t > minRxGap())
            {
                // close the data section
                rxClose(receiver, false);
                rxState = 8;
                break;
            }
            goto s0;
                
        case 8:
        s8:
            // Ditto header.  If the protocol has a ditto header at all,
            // and this mark matches, proceed to the ditto space.  Otherwise
            // try interepreting this as a new regular header instead.
            if (mark && (tRef = tDittoMark()) != 0 && inRange(t, tRef))
            {
                rxState = 9;
                break;
            }
            goto s1;
            
        case 9:
            // Ditto space.  If this doesn't match the ditto space, and
            // the ditto header and regular header are the same, try
            // re-interpreting the space as a new regular header space.
            if (!mark && (tRef = tDittoSpace()) != 0 && inRange(t, tRef))
            {
                rxState = 10;
                break;
            }
            else if (!mark && tDittoMark() == tHeaderMark())
                goto s2;
            goto s0;
                
        case 10:
            // Enter ditto data
            rxDittoReset();
            goto s11;
            
        case 11:
        s11:
            // Ditto data - mark
            if (mark && rxMark(receiver, t))
            {
                rxState = bit < nbits() ? 12 : 13;
                break;
            }
            goto s0;
            
        case 12:
            // data space
            if (!mark && rxSpace(receiver, t))
            {
                rxState = bit < nbits() ? 11 : 13;
                break;
            }
            else if (!mark && t > minRxGap())
                goto s13;
            goto s0;
            
        case 13:
        s13:
            // end ditto data
            if (!mark && t > minRxGap())
            {
                // close the ditto data section
                rxClose(receiver, true);
                rxState = 8;
                break;
            }
            goto s0;
        }

        // if this is a space longer than the timeout, go into idle mode
        if (!mark && t >= IRReceiver::MAX_PULSE)
            rxIdle(receiver);
    }

    // Start transmission.  By convention, we start each transmission with
    // a gap of sufficient length to allow receivers to recognize a new
    // transmission.  The only protocol-specific work we usually have to
    // do here is to prepare a bit string to send.
    virtual int txStart(IRTXState *state)
    {
        // convert the code into a bitstream to send
        codeToBitstream(state);
        
        // transmit the initial gap to make sure we've been silent long enough
        return txPreGap(state);
    }
    
    // Continue transmission.  Most protocols have a similar structure,
    // with a header mark, header gap, data section, and trailing gap.
    // We implement the framework for this common structure with a
    // simple state machine:
    //
    //   state 0 = done with gap, transmitting header mark
    //   state 1 = done with header, transmitting header space
    //   state 2 = transmitting data bits, via txDataStep() in subclasses
    //   state 3 = done with data, sending post-code gap
    //
    // Subclasses for protocols that don't follow the usual structure can 
    // override this entire routine as needed and redefine these internal 
    // states.  Protocols that match the common structure will only have
    // to define txDataStep().
    //
    // Returns the time to the next step, or a negative value if we're
    // done with the transmission.
    virtual int txStep(IRTXState *state)
    {
        // The individual step handlers can return 0 to indicate
        // that we should go immediately to the next step without
        // a delay, so iterate as long as they return 0.
        for (;;)
        {
            // Use the first-code or "ditto" handling, as appropriate
            int t = state->rep > 0 && state->dittos ?
                txDittoStep(state) : 
                txMainStep(state);
            
            // If it's a positive time, it's a delay; if it's a negative
            // time, it's the end of the transmission.  In either case,
            // return the time to the main transmitter routine.  If it's
            // zero, though, it means to proceed without delay, so we'll
            // simply continue iterating.
            if (t != 0)
                return t;
        }
    }
    
    // Main transmission handler.  This handles the txStep() work for
    // the first code in a repeat group.
    virtual int txMainStep(IRTXState *state)
    {        
        // One state might transition directly to the next state
        // without any time delay, so keep going until we come to
        // a wait state.
        int t;
        for (;;)
        {
            switch (state->step)
            {
            case 0:
                // Finished the pre-code gap.  This is the actual start
                // of the transmission, so mark the time.
                state->txTime.reset();
                
                // if there's a header mark, transmit it
                state->step++;
                if ((t = this->tHeaderMark()) > 0)
                {
                    state->pin->write(pwmDutyCycle());
                    return t;
                }
                break;
                
            case 1:
                // finished header mark, start header space
                state->step++;
                if ((t = this->tHeaderSpace()) > 0)
                {
                    state->pin->write(0);
                    return this->tHeaderSpace();
                }
                break;
                
            case 2:
                // data section - this is up to the subclass
                if ((t = txDataStep(state)) != 0)
                    return t;
                break;
                
            case 3:
                // done with data; send the stop mark, if applicable
                state->step++;
                if ((t = tStopMark()) > 0)
                {
                    state->pin->write(pwmDutyCycle());
                    return t;
                }
                break;
                
            case 4:
                // post-code gap
                state->step++;
                state->pin->write(0);
                if ((t = this->txPostGap(state)) > 0)
                    return t;
                break;
                
            default:
                // Done with the iteration.  Finalize the transmission;
                // this will figure out if we're going to repeat.
                return this->txEnd(state);
            }
        }
    }
    
    // Ditto step handler.  This handles txStep() work for a repeated
    // code.  Most protocols just re-transmit the same code each time,
    // so by default we use the main step handling.  Subclasses for
    // protocols that transmit different codes on repeat (such as NEC)
    // can override this to send the ditto code instead.
    virtual int txDittoStep(IRTXState *state)
    {
        return txMainStep(state);
    }
    
    // Handle a txStep() iteration for a data bit.  Subclasses must
    // override this to handle the particulars of sending the data bits.
    // At the end of the data transmission, the subclass should increment
    // state->step to tell us that we've reached the post-code gap.
    virtual int txDataStep(IRTXState *state)
    {
        state->step++;
        return 0;
    }
    
    // Send the stop bit, if applicable.  If there's no stop bit or
    // equivalent, simply increment state->step and return 0;
    int txStopBit(IRTXState *state)
    {
        state->step++;
        return 0;
    }
    
    // Handle the end of a transmission.  This figures out if we're
    // going to auto-repeat, and if so, resets for the next iteration.
    // If we're going to repeat, we return the time to the next tx step,
    // as usual.  If the transmission is done, we return -1 to indicate
    // that no more steps are required.
    int txEnd(IRTXState *state)
    {
        // count the repeat
        state->rep++;

        // If the button is still down, or we haven't reached our minimum
        // repetition count, repeat the code.
        if (state->pressed || state->rep < txMinReps(state))
        {
            // return to the first transmission step
            state->step = 0;
            state->bit = 0;
            state->bitstep = 0;
            
            // re-generate the bitstream, in case we need to encode positional
            // information such as a toggle bit or position counter
            codeToBitstream(state);
            
            // restart the transmission timer
            state->txTime.reset();
            
            // we can go immediately to the next step, so return a zero delay
            return 0;
        }
        
        // we're well and truly done - tell the caller not to call us
        // again by returning a negative time interval
        return -1;
    }

protected:
    // Reset the receiver.  This is called when the receiver enters
    // the data section of the frame, after parsing the header (or
    // after a gap, if the protocol doesn't use a header).
    virtual void rxReset()
    {
        bit = 0;
        code = 0;
    }
    
    // Reset on entering a new ditto frame.  This is called after
    // parsing a "ditto" header.  This is only needed for protocols
    // that use distinctive ditto framing.
    virtual void rxDittoReset() { }
    
    // Receiver is going idle.  This is called any time we get a space
    // (IR OFF) that exceeds the general receiver timeout, regardless
    // of protocol state.  
    virtual void rxIdle(IRRecvProIfc *receiver) { }
    
    // Parse a data mark or space.  If the symbol is valid, shifts the
    // bit into 'code' (the code word under construction) and returns
    // true.  If the symbol is invalid, returns false.  Updates the
    // bit counter in 'bit' if this symbol finishes a bit.
    virtual bool rxMark(IRRecvProIfc *receiver, uint32_t t) { return false; }
    virtual bool rxSpace(IRRecvProIfc *receiver, uint32_t t) { return false; }
    
    // Report the decoded value in our internal register, if it's valid.
    // By default, we'll report the code value as stored in 'code', with
    // no toggle bit, if the number of bits we've decoded matches the
    // expected number of bits as given by nbits().  Subclasses can 
    // override as needed to do other validation checks; e.g., protocols
    // with varying bit lengths will need to check for all of the valid
    // bit lengths, and protocols that contain error-checking information
    // can validate that.
    //
    // Unless the protocol subclass overrides the basic pulse handler
    // (rxPulse()), this is called when we end the data section of the
    // code.
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        if (bit == nbits())
            reportCode(receiver, id(), code, bool3::null, ditto);
    }
    
    // Encode a universal code value into a bit string in preparation
    // for transmission.  This should take the code value in state->cmdCode,
    // convert it to the string of bits to serially, and store the result
    // in state->bitstream.
    virtual void codeToBitstream(IRTXState *state)
    {
        // by default, simply store the code as-is
        state->bitstream = state->cmdCode;
        state->nbits = nbits();
    }
    
    // Get the next bit for transmission from the bitstream object
    int getBit(IRTXState *state)
    {
        // get the number of bits and the current bit position
        int nbits = state->nbits;
        int bit = state->bit;
        
        // figure the bit position according to the bit order
        int bitpos = (lsbFirst() ? bit : nbits - bit - 1);
        
        // pull out the bit
        return int((state->bitstream >> bitpos) & 1);
    }
    
    // Set the next bit to '1', optionally incrementing the bit counter
    void setBit(bool inc = true)
    {
        // ignore overflow
        int nbits = this->nbits();
        if (bit >= nbits)
            return;

        // Figure the starting bit position in 'code' for the bit,
        // according to whether we're adding them LSB-first or MSB-first.
        int bitpos = (lsbFirst() ? bit : nbits - bit - 1);
        
        // mask in the bit
        code |= (CodeType(1) << bitpos);
        
        // advance the bit position
        if (inc)
            ++bit;
    }
    
    // Set the next N bits to '1'
    void setBits(int n)
    {
        // ignore overflow
        int nbits = this->nbits();
        if (bit + n - 1 >= nbits)
            return;
        
        // Figure the starting bit position in 'code' for the bits we're 
        // setting.  If bits arrive LSB-first, the 'bit' counter gives us
        // the bit position directly.  If bits arrive MSB-first, we need
        // to start from the high end instead, so we're starting at
        // ((nbits()-1) - bit).  However, we want to set multiple bits
        // left-to-right in any case, so move our starting position to
        // the "end" of the window by moving right n-1 addition bits.
        int bitpos = (lsbFirst() ?  bit : nbits - bit - n);
        
        // turn that into a bit mask for the first bit
        uint64_t mask = (CodeType(1) << bitpos);
        
        // advance our 'bit' counter past the added bits
        bit += n;
        
        // set each added bit to 1
        for ( ; n != 0 ; --n, mask <<= 1)
            code |= mask;
    }

    // decoding state   
    uint8_t rxState; 

    // next bit position
    uint8_t bit;
    
    // command code under construction
    CodeType code;
};

// -----------------------------------------------------------------------
//
// Basic asynchronous encoding
// 
// This is essentially the IR equivalent of a wired UART.  The transmission 
// for a code word is divided into a fixed number of bit time periods of 
// fixed length, with each period containing one bit, signified by IR ON for 
// 1 or IR OFF for 0.
// 
// Simple async coding doesn't have any inherent structure other than the
// bit length.  That makes it hard to distinguish from other IR remotes that
// might share the environment, and even from random noise, which is why
// most CE manufacturers use more structured protocols.  In practice, remotes
// using this coding are likely have to impose some sort of structure on the
// bits, such as long bit strings, error checking bits, or distinctive prefixes
// or suffixes.  The only example of a pure async code I've seen in the wild 
// is Lutron, and they do in fact use fairly long codes (36 bits) with set 
// prefixes.  Their prefixes aren't only distinctive as bit sequences, but
// also in the raw space/mark timing, which makes them effectively serve the
// function that header marks do in most of the structured protocols.
//
template<class CodeType> class IRPAsync: public IRPWithCode<CodeType>
{
public:
    IRPAsync() { }
    
    // duration of each bit in microseconds
    virtual int tBit() const = 0;
    
    // maximum legal mark in a data section, if applicable
    virtual uint32_t maxMark() const { return IRReceiver::MAX_PULSE; }
    
    // Async codes lack the structure of the more typical codes, so we
    // use a completely custom pulse handler
    virtual void rxPulse(IRRecvProIfc *receiver, uint32_t t, bool mark)
    {
        uint32_t tRef, tRef2;
        switch (this->rxState)
        {
        case 0:
        s0:
            // Gap - if this is a long enough space, switch to header mode.
            this->rxState = (!mark && t > this->minRxGap() ? 1 : 0);
            break;
            
        case 1:
            // Header mode.  Async protocols don't necessarily have headers,
            // but some (e.g., Lutron) do start all codes with a distinctively
            // long series of bits.  If the subclass defines a header space,
            // apply it to sense the start of a code.
            if ((tRef = this->tHeaderMark()) == 0)
                goto s2;
                
            // we have a defined header mark - make sure this is long enough
            tRef2 = tBit();
            if (mark && inRangeOrAbove(t, tRef, tRef2))
            {
                // deduct the header time
                t = t > tRef ? t - tRef : 0;
                
                // if that leaves us with a single bit time or better,
                // treat it as the first data bit
                if (inRangeOrAbove(t, tRef2, tRef2))
                    goto s2;
                    
                // that consumes the whole mark, so just switch to data
                // mode starting with the next space
                this->rxState = 2;
                break;
            }
            
            // doesn't look like the start of a code; back to gap mode
            goto s0;
                
        case 2:
        s2:
            // Enter data mode
            this->rxReset();
            goto s3;
            
        case 3:
        s3:
            // Data mode.  Process the mark or space as a number of bits.
            {
                // figure how many bits this symbol represents
                int tb = tBit();
                int n = (t + tb/2)/tb;
                
                // figure how many bits remain in the code
                int rem = this->nbits() - this->bit;
                
                // check to see if this symbol overflows the bits remaining
                if (n > rem)
                {
                    // marks simply can't exceed the bits remaining
                    if (mark)
                        goto s0;
                        
                    // Spaces can exceed the remaining bits, since we can 
                    // have a string of 0 bits followed by a gap between 
                    // codes.  Use up the remaining bits as 0's, and apply 
                    // the balance as a gap.
                    this->bit += rem;
                    t -= rem*tb;
                    goto s4;
                }
                
                // check if it exceeds the code's maximum mark length
                if (mark && t > maxMark())
                    goto s0;
                
                // Make sure that it actually looks like an integral
                // number of bits.  If it's not, take it as a bad code.
                if (!inRange(t, n*tb, tb))
                    goto s0;
                    
                // Add the bits
                if (mark)
                    this->setBits(n);
                else
                    this->bit += n;
                    
                // we've consumed the whole interval as bits
                t = 0;
                
                // if that's enough bits, we have a decode
                if (this->bit == this->nbits())
                    goto s4;
                    
                // stay in data mode
                this->rxState = 3;
            }
            break;
            
        case 4:
        s4:
            // done with the code - close it out and start over
            this->rxClose(receiver, false);
            goto s0;
        }
    }
    
    // send data
    virtual int txDataStep(IRTXState *state) 
    { 
        // get the next bit
        int b = this->getBit(state);
        state->bit++;
        
        // count how many consecutive matching bits follow
        int n = 1;
        int nbits = state->nbits;
        for ( ; state->bit < nbits && this->getBit(state) == b ; 
            ++n, ++state->bit) ;
        
        // if we're out of bits, advance to the next step
        if (state->bit >= nbits)
            ++state->step;
        
        // 0 bits are IR OFF and 1 bits are IR ON
        state->pin->write(b ? this->pwmDutyCycle() : 0);
        
        // stay on for the number of bits times the time per bit
        return n * this->tBit();
    }
};


// -----------------------------------------------------------------------
//
// Space-length encoding
//
// This type of encoding uses the lengths of the spaces to encode the bit
// values.  Marks are all the same length, and spaces come in two lengths,
// short and long, usually T and 2T for a vendor-specific time T (typically
// on the order of 500us).  The short space encodes 0 and the long space
// encodes 1, or vice versa.
//
// The widely used NEC protocol is a space-length encoding, and in practice
// it seems that most of the ad hoc proprietary protocols are also space-
// length encodings, mostly with similar parameters to NEC.
//
template<class CodeType> class IRPSpaceLength: public IRPWithCode<CodeType>
{
public:
    IRPSpaceLength() { }

    // mark length, in microseconds
    virtual int tMark() const = 0;
    
    // 0 and 1 bit space lengths, in microseconds
    virtual int tZero() const = 0;
    virtual int tOne() const = 0;
    
    // Space-length codings almost always need a mark after the last
    // bit, since otherwise the last bit's space (the significant part)
    // would just flow into the gap that follows.
    virtual uint32_t tStopMark() const { return tMark(); }

    // process a mark
    virtual bool rxMark(IRRecvProIfc *receiver, uint32_t t)
    {
        // marks simply delimit spaces in this protocol and thus
        // carry no bit information
        if (inRange(t, tMark()))
            return true;
        else
            return false;
    }
     
    // process a space   
    virtual bool rxSpace(IRRecvProIfc *receiver, uint32_t t)
    {
        // a short space represents a '0' bit, a long space is a '1'
        if (inRange(t, tZero()))
            return this->bit++, true;
        else if (inRange(t, tOne()))
            return this->setBit(), true;
        else
            return false;
    }

    // continue a transmission
    virtual int txDataStep(IRTXState *state)
    {
        // Data section.
        if (state->bitstep == 0)
        {
            // mark - these are fixed length
            state->pin->write(this->pwmDutyCycle());
            state->bitstep = 1;
            return tMark();
        }
        else
        {
            // space - these are variable length according to the data
            state->pin->write(0);
            int t = this->getBit(state) ? tOne() : tZero();
            state->bitstep = 0;

            // advance to the next bit; stop if we're done
            if (++state->bit >= state->nbits)
                ++state->step;
                
            // return the space time
            return t;
        }
    }
    
};


// -----------------------------------------------------------------------
//
// Mark-length encoding
//
// This is the inverse of space-length coding.  In this scheme, the bit
// values are encoded in the mark length.  Spaces are fixed length, and
// marks come in short (0) and long (1) lengths, usually of time T and 2T
// for a protocol-specific time T.
//
// Sony uses this type of encoding.
template<class CodeType> class IRPMarkLength: public IRPWithCode<CodeType>
{
public:
    IRPMarkLength() { }

    // space length, in microseconds
    virtual int tSpace() const = 0;
    
    // 0 and 1 bit mark lengths, in microseconds
    virtual int tZero() const = 0;
    virtual int tOne() const = 0;

    // process a mark
    virtual bool rxMark(IRRecvProIfc *receiver, uint32_t t)
    {
        // a short mark represents a '0' bit, a long space is a '1'
        if (inRange(t, tZero()))
            this->bit++;
        else if (inRange(t, tOne()))
            this->setBit();
        else
            return false;
        return true;
    }
     
    // process a space   
    virtual bool rxSpace(IRRecvProIfc *receiver, uint32_t t)
    {
        // spaces simply delimit marks in this protocol and carry
        // no bit information of their own
        return inRange(t, tSpace());
    }

    // continue a transmission
    virtual int txDataStep(IRTXState *state)
    {
        // check if we're on a mark (step 0) or space (step 1)
        if (state->bitstep == 0)
        {
            // space - these are variable length according to the data
            state->pin->write(this->pwmDutyCycle());
            int t = this->getBit(state) ? tOne() : tZero();
            state->bitstep = 1;
                
            // return the mark time
            return t;
        }
        else
        {
            // Space - fixed length
            state->pin->write(0);
            state->bitstep = 0;
            
            // advance to the next bit; stop if we're done
            if (++state->bit >= state->nbits)
                state->step = 3;
            return tSpace();
        }
    }
    
};


// -----------------------------------------------------------------------
//
// Manchester coding
//
// This type of coding uses a fixed time per bit, and encodes the bit
// value in a mark/space or space/mark transition within each bit's
// time window.  
//
// The decoding process is a little tricky to grap when you're looking
// at just the raw data, because the raw data renders things in terms of 
// monolithic marks and spaces of different lengths, whereas the coding 
// divides the time axis into even chunks and looks at what's going on
// in each chunk.  In terms of the raw data, we can think of it this way.
// Because every bit time window has a transition (mark/space or space/mark)
// in the middle of it, there has to be at least one transition per window.
// There can also be a transition between each window, or not, as needed
// to get the transmitter into the right initial state for the next bit.  
// This means that each mark and each space is either T or 2T long, where
// T is the half the bit window time.  So we can simply count these units.
// If we see a mark or space of approximate length T, we count one unit;
// if the length is around 2T, we count two units.  On each ODD count, we
// look at the state just before the count.  If we were in a space just
// before the count, the bit is a 1; if it was a mark, the bit is a 0.
//
// Manchester coding is used in the Philips RC5 and RC6 protocols, which
// are in turn used by most other European CE companies.
template<class CodeType> class IRPManchester: public IRPWithCode<CodeType>
{
public:
    IRPManchester() { }
    
    // Half-bit time.  This is half of the time interval of one bit,
    // so it's equal to the time on each side of the mark/space or
    // space/mark transition in the middle of each bit.
    virtual int tHalfBit(int bit) const = 0;
    
    // Bit value (0 or 1) of a space-to-mark transition.  A mark-to-space
    // transition always has the opposite sense.
    virtual int spaceToMarkBit() const { return 1; }
    inline int markToSpaceBit() const { return !spaceToMarkBit(); }
    
    // reset the decoder state
    virtual void rxReset()
    {
        IRPWithCode<CodeType>::rxReset();
        halfBitPos = 0;
    }

    // process a mark
    virtual bool rxMark(IRRecvProIfc *receiver, uint32_t t)
    {
        // transitioning from mark to space, so this is a 
        return processTransition(t, spaceToMarkBit());
    }
    
    // process a space
    virtual bool rxSpace(IRRecvProIfc *receiver, uint32_t t)
    {
        return (processTransition(t, markToSpaceBit()));
    }
    
    // Process a space/mark or mark/space transition.  Returns true on
    // success, false on failure.
    bool processTransition(uint32_t t, int bitval)
    {
        // If this time is close to zero, ignore it.
        int thb = tHalfBit(this->bit);
        if (t < ((thb*toleranceShl8) >> 8))
            return true;
        
        // If the current time is the middle of a bit, the transition
        // specifies a bit value, so set the bit.  Transitions between
        // bits are just clocking.
        if (halfBitPos == 1)
        {
            if (bitval)
            {
                // set the bit, but keep the bit counter where it is, since
                // we manage it ourselves
                this->setBit();
                this->bit--;
            }
        }
        
        // Advance by the time interval.  Check that we have at least one
        // half-bit interval to work with.
        if (t < ((thb * (256 - toleranceShl8)) >> 8))
            return false;
        
        // If we're at a half-bit position, start by advancing to the next
        // bit boundary.
        if (halfBitPos)
        {
            // deduct the half-bit time
            t = (t > thb ? t - thb : 0);

            // advance our position counters to the next bit boundary
            halfBitPos = 0;
            this->bit++;
            
            // Some subprotocols (e.g., RC6) have variable bit timing,
            // so the timing for this bit might be different than for
            // the previous bit.  Re-fetch the time.
            thb = tHalfBit(this->bit);
        }
        
        // If we have another half-interval left to process, advance
        // to the middle of the current bit.
        if (t < ((thb * toleranceShl8) >> 8))
        {
            // we already used up the symbol time, so we're done
            return true;
        }
        else if (inRange(t, thb))
        {
            // we have another half-bit time to use, so advance to
            // the middle of the bit
            halfBitPos = true;
            return true;
        }
        else
        {
            // The time remaining is wrong, so terminate decoding.
            // Note that this could simply be because we've reached
            // the gap at the end of the code word, in which case we'll
            // already have all of the bits stored and will generate
            // the finished code value.
            return false;
        }
    }
    
    virtual int txDataStep(IRTXState *state) 
    { 
        // Get the current bit
        int b = this->getBit(state);
        
        // Determine if this bit uses a space-to-mark or mark-to-space
        // transition.  It uses a space-to-mark transition if it matches
        // the space-to-mark bit.
        int stm = (b == spaceToMarkBit());
        
        // Check to see if we're at the start or middle of the bit
        if (state->bitstep == 0)
        {
            // Start of the current bit.  Set the level for the first
            // half of the bit.  If we're doing a space-to-mark bit,
            // the first half is a space, otherwise it's a mark.
            state->pin->write(stm ? 0 : this->pwmDutyCycle());
            
            // leave this on for a half-bit time to get to the 
            // middle of the bit
            state->bitstep = 1;
            return tHalfBit(state->bit);
        }
        else
        {
            // Middle of the current bit.  Set the level for the second
            // half of the bit.  If we're in a space-to-mark bit, the
            // second half is the mark, otherwise it's the space.
            state->pin->write(stm ? this->pwmDutyCycle() : 0);
            
            // figure the time to the start of the next bit
            int t = tHalfBit(state->bit);
            
            // advance to the start of the next bit
            state->bit++;
            state->bitstep = 0;
            
            // If the next bit is the inverse of the current bit, it will
            // lead in with the same level we're going out with.  That 
            // means we can go straight to the middle of the next bit
            // without another interrupt.
            if (state->bit < state->nbits && this->getBit(state) != b)
            {
                // proceed to the middle of the next bit
                state->bitstep = 1;
                
                // add the half-bit time
                t += tHalfBit(state->bit);
            }
            
            // if this was the last bit, advance to the next state
            if (state->bit >= state->nbits)
                state->step++;
            
            // return the time to the next transition
            return t;
        }
    }

    // Current half-bit position.  If the last transition was on the
    // border between two bits, this is 0.  If it was in the middle
    // of a bit, this is 1.
    uint8_t halfBitPos : 1;
};

// -----------------------------------------------------------------------
// 
// NEC protocol family.  This is one of the more important proprietary 
// protocols, since many CE companies use the standard NEC code or a 
// variation of it.  This class handles the following variations on the
// basic NEC code:
//
//   NEC-32:   32-bit payload, 9000us header mark, 4500us header space
//   NEC-32X:  32-bit payload, 4500us header mark, 4500us header space
//   NEC-48:   48-bit payload, 9000us header mark, 4500us header space
//   Pioneer:  NEC-32 with address A0..AF + possible "shift" prefixes
//   TCL/Roku: NEC-32 with address EAC7 + doubled code XOR 0x8080
//
// Each of the three NEC-nn protocol types comes in two sub-types: one
// that uses "ditto" codes for repeated keys, and one that simply sends
// the same code again on repeats.  The ditto code, when used, varies with 
// the main protocol type:
//
//   NEC-32:   9000us mark + 2250us space + 564us mark
//   NEC-32x:  4500us mark + 4500us space + one data bit + 564us mark
//   NEC-48:   9000us mark + 2250us space + 564us mark
//   Pioneer:  no dittos
//   TCL/Roku: no dittos
//
// The NEC-32 and NEC-48 dittos can be detected from the header space
// length.  The NEC-32x dittos can be detected by the one-bit code length.
//
// All variations of the NEC code are space-length encodings with 564us
// marks between bits, 564us '0' spaces, and 3*564us '1' spaces.  All
// variations use a long header mark and a 564us stop mark.  With those
// fixed features, there are three main variations:
//
// The bits in the NEC 32-bit codes are structured into four 8-bit fields, 
// with the first bit transmitted in the most significant position:
//
//   A1 A0 C1 C0
//
// A1 is the high 8 bits of the address, and A0 is the low 8 bits of the
// address.  The address specifies a particular type of device, such as
// "NEC VCR" or "Vizio TV".  These are assigned by NEC.  C1 and C0 form the
// command code, which has a meaning specific to the device type specified 
// by the address field.
//
// In the original NEC protocol, the nominal address is in A1, and A0 is
// the 1's complement of A1 (A0 = ~A1), for error checking.  This was removed
// in a later revision to expand the address space.  Most modern equipment
// uses the newer system, so A0 is typically an independent value in remotes
// you'll find in use today.
//
// In the official version of the protocol, C1 is the nominal command code,
// and C0 = ~C1, for error checking.  However, some other manufacturers who
// use the basic NEC protocol, notably Yamaha and Onkyo, violate this by using
// C0 as an independent byte to expand the command space.  We therefore don't
// test for the complemented byte, so that we don't reject codes from devices
// that treat it as independent. 
// 
// Pioneer uses the NEC protocol with two changes.  First, the carrier is
// 40kHz instead of 38kHz.  The TSOP384xx seems to receive the 40kHz signal
// reliably, so the frequency doesn't matter on receive, but it might matter
// on transmit if the target equipment isn't as tolerant.  Second, Pioneer
// sometimes transmits a second code for the same key.  In these cases, the
// first code is a sort of "shift" code (shared among many keys), and the
// second code has the actual key-specific meaning.  To learn or recognize
// these extended codes, we have to treat the pair of code words as a single 
// command.  We sense Pioneer codes based on the address field, and use
// special handling when we find a Pioneer address code.
//
// TCL's Roku models (that is, their TVs that contain embedded Roku features)
// use yet another proprietary variant.  They use the standard low-level
// protocol elements (PWM freq and bit timing), but they layer a high-level 
// protocol variation where every command consists of two 32-bit code words 
// in succession.  The second code word repeats the first code word, but with 
// the last two bytes (the "command field") each XOR'd with 0x80.  TCL's codes 
// are recognizable by EAC7 in the command field.  The repeated code scheme is
// presumably a redundancy check.  Dittos aren't used in this scheme.
//
class IRPNEC: public IRPSpaceLength<uint64_t>
{
public:
    // code parameters
    virtual uint32_t minRxGap() const { return 3400; }
    virtual uint32_t txGap(IRTXState *state) const 
        { return 108000 - state->txTime.read_us(); }

    // The post-code transmit gap is special for TCL Roku for the gap between
    // the first and second half of the code.  These appear to use a fixed
    // 37842us gap.  The receiver interprets the normal NEC inter-code gap 
    // of (108ms minus code transmit time) as a gap between repeats of the
    // code rather than as half-codes.
    virtual uint32_t txPostGap(IRTXState *state) const 
    { 
        // Check for TCL Roku models on even reps.  An even rep is the
        // first half of a code pair, so we need to use the shorter
        // post-code gap for these.
        if (state->protocolId == IRPRO_TCLROKU
            && (state->rep == 0 || state->rep == 2))
            return 37842;
    
        // use the standard NEC timing for others
        return txGap(state); 
    }

    // space length encoding parameters
    virtual int tMark() const { return 560; }
    virtual int tZero() const { return 560; }
    virtual int tOne() const { return 1680; }
    
    // PWM period is 40kHz for Pioneer, 38kHz for everyone else
    virtual float pwmPeriod(IRTXState *state) const 
    { 
        return state->protocolId == IRPRO_PIONEER ? 25.0e-6f : 26.31578947e-6f; 
    }
    
    // For Pioneer, we have to send two codes if we have a shift field.  
    // For TCL Roku models, we always send two codes.
    virtual int txMinReps(IRTXState *state) const
    {
        if (state->protocolId == IRPRO_PIONEER 
            && (state->cmdCode & 0xFFFF0000) != 0)
            return 2;
        else if (state->protocolId == IRPRO_TCLROKU)
            return 2;
        else
            return 1;
    }
    
    // get the protocol to report for a given data packet bit count
    virtual int necPro(int bits) const = 0;
    
    // close out a received bitstream
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        // Check the bit count.  If nbits() says we can accept 48 bits,
        // accept 48 bits, otherwise only accept 32.
        if (bit == 32 || (nbits() >= 48 && bit == 48))
        {
            uint64_t codeOut;
            if (ditto)
            {
                // report 0 for dittos
                codeOut = 0;
            }
            else
            {
                // Put the bytes in the right order.  The bits are LSB-first, but
                // we want the bytes to be ordered within the uint32 as (high to
                // low) A0 A1 C0 C1.
                uint8_t c1 = uint8_t((code >> 24) & 0xff);
                uint8_t c0 = uint8_t((code >> 16) & 0xff);
                uint8_t a1 = uint8_t((code >> 8) & 0xff);
                uint8_t a0 = uint8_t(code & 0xff);
                codeOut = (uint64_t(a0) << 24) | (uint64_t(a1) << 16)
                    | (uint64_t(c0) << 8) | uint64_t(c1);
                    
                // If it's a 48-bit code, add the additional 16 bits for E0 E1
                // (the extended command code) at the low end.
                if (bit == 48)
                {
                    // get the E1 and E0 bytes from the top end of the code                
                    uint8_t e1 = uint8_t((code >> 40) & 0xff);
                    uint8_t e0 = uint8_t((code >> 32) & 0xff);
                    
                    // insert them at the low end in E0 E1 order
                    codeOut <<= 16;
                    codeOut |= (uint64_t(e0) << 8) | uint64_t(e1);
                }
            }
    
            // report it
            reportCode(receiver, necPro(bit), codeOut, bool3::null, ditto);
        }
    }

    // convert a code to a bitstream for sending    
    virtual void codeToBitstream(IRTXState *state)
    {
        if (state->protocolId == IRPRO_PIONEER)
        {
            // Check if we have an extended code
            uint32_t c;
            if ((state->cmdCode & 0xFFFF0000) != 0)
            {
                // Extended code.  These are transmitted as two codes in
                // a row, one for the shift code in the high 16 bits, and
                // one for the subcode in the low 16 bits.  Transmit the
                // shift code on even reps and the subcode on odd reps.
                if (state->rep == 0 || state->rep == 2)
                {
                    // even rep - use the shift code
                    c = (state->cmdCode >> 16) & 0xFFFF;
                    
                    // wrap back to rep 0 on rep 2
                    state->rep = 0;
                }
                else
                {
                    // odd rep - use the subcode
                    c = state->cmdCode & 0xFFFF;
                }
            }
            else
            {
                // it's a single-part code
                c = state->cmdCode;
            }
            
            // encode it in the 32-bit original NEC format with the address
            // and command byte complemented
            uint8_t a0 = uint8_t((c >> 8) & 0xff);
            uint8_t a1 = uint8_t(~a0);
            uint8_t c0 = uint8_t(c & 0xff);
            uint8_t c1 = uint8_t(~c0);
            state->bitstream = (uint64_t(c1) << 24) | (uint64_t(c0) << 16)
                | (uint64_t(a1) << 8) | uint64_t(a0);
            state->nbits = 32;
            
            // Pioneer *can't* use NEC dittos even if the caller thinks we
            // should, because that breaks the shift-code model Pioneer uses
            state->dittos = false;
        }
        else if (state->protocolId == IRPRO_TCLROKU)
        {
            // TCL Roku models use doubled code words.  The second code
            // word in the pair is always the same as the first with
            // the two bytes of the command field XOR'd with 0x80.
            uint32_t c;
            if (state->rep == 0 || state->rep == 2)
            {
                // even rep - use the nominal command code
                c = state->cmdCode;
                    
                // wrap back to rep 0 on rep 2
                state->rep = 0;
            }
            else
            {
                // odd rep - use the code XOR'd with 0x8080
                c = state->cmdCode ^ 0x8080;
            }
            
            // use the normal NEC32 encoding, substituting the possibly
            // modified code field 'c' we calculated above
            uint32_t orig = uint32_t(state->cmdCode);
            uint8_t a0 = uint8_t((orig >> 24) & 0xff);
            uint8_t a1 = uint8_t((orig >> 16) & 0xff);
            uint8_t c0 = uint8_t((c >> 8) & 0xff);
            uint8_t c1 = uint8_t(c & 0xff);
            state->bitstream = 
                (uint64_t(c1) << 24) | (uint64_t(c0) << 16)
                | (uint64_t(a1) << 8) | uint64_t(a0);
            state->nbits = 32; 

            // this protocol doesn't use dittos
            state->dittos = false;
        }
        else if (state->protocolId == IRPRO_NEC48)
        {
            // NEC 48-bit code.  We store the bytes in the universal 
            // representation in order A0 A1 C0 C1 E0 E1.  Reverse this
            // order for transmission.
            uint64_t code = state->cmdCode;
            uint8_t a0 = uint8_t((code >> 40) & 0xff);
            uint8_t a1 = uint8_t((code >> 32) & 0xff);
            uint8_t c0 = uint8_t((code >> 24) & 0xff);
            uint8_t c1 = uint8_t((code >> 16)& 0xff);
            uint8_t e0 = uint8_t((code >> 8) & 0xff);
            uint8_t e1 = uint8_t((code) & 0xff);
            state->bitstream = 
                (uint64_t(e1) << 40) | (uint64_t(e0) << 32)
                | (uint64_t(c1) << 24) | (uint64_t(c0) << 16)
                | (uint64_t(a1) << 8) | uint64_t(a0);
            state->nbits = 48; 
        }
        else
        {
            // NEC 32-bit code.  The universal representation stores
            // the bytes in order A0 A1 C0 C1.  For transmission, we
            // need to reverse this to C1 C0 A1 A0.
            uint32_t code = uint32_t(state->cmdCode);
            uint8_t a0 = uint8_t((code >> 24) & 0xff);
            uint8_t a1 = uint8_t((code >> 16) & 0xff);
            uint8_t c0 = uint8_t((code >> 8) & 0xff);
            uint8_t c1 = uint8_t(code & 0xff);
            state->bitstream = 
                (uint64_t(c1) << 24) | (uint64_t(c0) << 16)
                | (uint64_t(a1) << 8) | uint64_t(a0);
            state->nbits = 32; 
        }
    }

    // NEC uses a special "ditto" code for repeats.  The ditto consists
    // of the normal header mark, half a header space, a regular data
    // mark.  After this, a standard inter-message gap follows, and then
    // we repeat the ditto as long as the button is held down.
    virtual int txDittoStep(IRTXState *state)
    {
        // send the ditto
        uint32_t t;
        switch (state->step)
        {
        case 0:
            // Ditto header mark
            state->step++;
            state->pin->write(pwmDutyCycle());
            
            // use the special ditto mark timing if it's different; 0 means
            // that we use the same timing as the standard data frame header
            return (t = tDittoMark()) != 0 ? t : tHeaderMark();
            
        case 1:
            // Ditto header space
            state->step++;
            state->pin->write(0);
            
            // use the special ditto timing if it's different
            return (t = tDittoSpace()) != 0 ? t : tHeaderSpace();
            
        case 2:
            // Data section.  NEC-32X sends one data bit.  The others
            // send no data bits, so go straight to the stop bit.
            if (state->protocolId == IRPRO_NEC32X && state->bit == 0)
                return txDataStep(state);
                
            // for others, fall through to the stop mark
            state->step++;
            // FALL THROUGH...
            
        case 3:
            // stop mark
            state->step++;
            state->pin->write(pwmDutyCycle());
            return tMark();
            
        case 4:
            // send a gap
            state->step++;
            state->pin->write(0);
            return 108000 - state->txTime.read_us();
            
        default:
            // done
            return txEnd(state);
        }
    }

};

// NEC-32, NEC-48, Pioneer, and TCL TVs with embedded Roku
class IRPNEC_32_48: public IRPNEC
{
public:
    IRPNEC_32_48()
    {
        pioneerPrvCode = 0;
        tclRokuPrvCode = 0;
    }

    // name and ID
    virtual const char *name() const { return "NEC"; }
    virtual int id() const { return IRPRO_NEC32; }
    virtual int necPro(int bits) const 
    { 
        return bits == 48 ? IRPRO_NEC48 : IRPRO_NEC32; 
    }
    
    // we encode several protocols
    virtual bool isSenderFor(int pro) const
    {
        return pro == IRPRO_NEC32 
            || pro == IRPRO_NEC48 
            || pro == IRPRO_PIONEER
            || pro == IRPRO_TCLROKU;
    }

    // NEC-32 and NEC-48 use the same framing
    virtual uint32_t tHeaderMark() const { return 9000; }
    virtual uint32_t tHeaderSpace() const { return 4500; }
    virtual uint32_t tDittoMark() const { return 9000; }
    virtual uint32_t tDittoSpace() const { return 2250; }
    virtual int nbits() const { return 48; }

    // receiver format descriptor
    // decode, check, and report a code value
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        // If we're in Pioneer mode, use special handling
        if (isPioneerCode())
        {
            rxClosePioneer(receiver);
            return;
        }
        
        // The new code isn't a pioneer code, so if we had a Pioneer
        // code stashed, it doesn't have a second half.  Report is as
        // a standalone code.
        if (pioneerPrvCode != 0)
        {
            reportPioneerFormat(receiver, pioneerPrvCode);
            pioneerPrvCode = 0;
        }

        // If we're in TCL/Roku mode, use special handling
        if (isTCLRokuCode())
        {
            rxCloseTCLRoku(receiver);
            return;
        }
        
        // The new code isn't a TCL/Roku code, so if we had a first half
        // code stashed, it doesn't have a second half forthcoming.  Report
        // it as a standalone code.
        if (tclRokuPrvCode != 0)
        {
            reportTCLRokuFormat(receiver, tclRokuPrvCode);
            tclRokuPrvCode = 0;
        }
        
        // use the generic NEC handling
        IRPNEC::rxClose(receiver, ditto);
    }
    
    virtual void rxIdle(IRRecvProIfc *receiver)
    {
        // if we have a stashed prior Pioneer code, close it out, since
        // no more codes are forthcoming
        if (pioneerPrvCode != 0)
        {
            reportPioneerFormat(receiver, pioneerPrvCode);
            pioneerPrvCode = 0;
        }
        
        // likewise for TCL/Roku stashed prior codes
        if (tclRokuPrvCode != 0)
        {
            reportTCLRokuFormat(receiver, tclRokuPrvCode);
            tclRokuPrvCode = 0;
        }
    }

    // close out a Pioneer code
    virtual void rxClosePioneer(IRRecvProIfc *receiver)
    {
        // Check to see if we have a valid previous code and/or
        // a valid new code.
        if (pioneerPrvCode != 0)
        {
            // We have a stashed Pioneer code plus the new one.  If
            // they're different, we must have an extended code with
            // a "shift" prefix.
            if (pioneerPrvCode != code)
            {
                // distinct code - it's an extended code with a shift
                reportPioneerFormat(receiver, pioneerPrvCode, code);
            }
            else
            {
                // same code - it's just a repeat, so report it twice
                reportPioneerFormat(receiver, code);
                reportPioneerFormat(receiver, code);
            }
            
            // we've now consumed the previous code
            pioneerPrvCode = 0;
        }
        else
        {
            // There's no stashed code.  Don't report the new one yet,
            // since it might be a "shift" prefix.  Stash it until we
            // find out if another code follows.
            pioneerPrvCode = code;
            bit = 0;
            code = 0;
        }
    }
    
    // determine if we have Pioneer address
    bool isPioneerCode()
    {
        // pull out the command and address fields
        uint8_t c1 = uint8_t((code >> 24) & 0xff);
        uint8_t c0 = uint8_t((code >> 16) & 0xff);
        uint8_t a1 = uint8_t((code >> 8) & 0xff);
        uint8_t a0 = uint8_t(code & 0xff);
            
        // Pioneer uses device codes A0..AF, with A1 complemented, and
        // uses only the 32-bit code format.  Pioneer also always uses
        // a complemented C0-C1 pair.
        return bit == 32 
            && (a0 >= 0xA0 && a0 <= 0xAF) 
            && a0 == uint8_t(~a1)
            && c0 == uint8_t(~c1);        
    }
    
    // Report a code in Pioneer format.  This takes the first address
    // byte and combines it with the first command byte to form a 16-bit
    // code.  Pioneer writes codes in this format because the second
    // address and command bytes are always the complements of the first,
    // so they contain no information, so it makes the codes more readable
    // for human consumption to drop the redundant bits.  
    void reportPioneerFormat(IRRecvProIfc *receiver, uint32_t code)
    {
        uint8_t a0 = uint8_t(code & 0xff);
        uint8_t c0 = uint8_t((code >> 16) & 0xff);
        reportCode(receiver, IRPRO_PIONEER, (uint64_t(a0) << 8) | c0, 
            bool3::null, bool3::null);
    }
    
    // Report an extended two-part code in Pioneer format.  code1 is the
    // first code received (the "shift" prefix code), and code2 is the
    // second (the key-specific subcode).  We'll convert each code to
    // the standard Pioneer 16-bit format (<address>:<key>), then pack
    // the two into a 32-bit int with the shift code in the high half.
    void reportPioneerFormat(IRRecvProIfc *receiver, uint32_t code1, uint32_t code2)
    {
        uint8_t a1 = code1 & 0xff;
        uint8_t c1 = (code1 >> 16) & 0xff;
        uint8_t a2 = code2 & 0xff;
        uint8_t c2 = (code2 >> 16) & 0xff;
        reportCode(
            receiver, IRPRO_PIONEER,
            (uint64_t(a1) << 24) | (uint64_t(c1) << 16) 
            | (uint64_t(a2) << 8) | c2,
             bool3::null, bool3::null);
    }
   
    // The previous Pioneer code value.  This is used in decoding Pioneer
    // codes, since some keys in the Pioneer scheme send a "shift" prefix 
    // code plus a subcode.
    uint32_t pioneerPrvCode;
    
    // close out a TCL/Roku code
    virtual void rxCloseTCLRoku(IRRecvProIfc *receiver)
    {
        // Check to see if we have a valid previous code and/or
        // a valid new code.
        if (tclRokuPrvCode != 0)
        {
            // We have a stashed code for the TCL/Roku double-code-word
            // scheme.  If this one matches the previous one with the
            // "command field" bytes XOR'd with 0x80, it's the second
            // code in the pair.  Otherwise it must be a new code.
            if (tclRokuPrvCode == code ^ 0x80800000)
            {
                // it's the matching code from the pair - report it as one code
                reportTCLRokuFormat(receiver, tclRokuPrvCode);
            }
            else
            {
                // it's not a match, so it must be a distinct code - report
                // the two codes separately
                reportTCLRokuFormat(receiver, tclRokuPrvCode);
                reportTCLRokuFormat(receiver, code);
            }
            
            // we've now consumed the previous code
            tclRokuPrvCode = 0;
        }
        else
        {
            // There's no stashed code.  Don't report the new one yet, since
            // it might be the first of a pair.
            tclRokuPrvCode = code;
            bit = 0;
            code = 0;
        }
    }

    // Report a code in TCL/Roku format.  This just uses the standard NEC
    // reporting.
    void reportTCLRokuFormat(IRRecvProIfc *receiver, uint32_t code)
    {
        // put the bytes in the reporting order for NEC: A0 A1 C0 C1
        uint8_t c1 = uint8_t((code >> 24) & 0xff);
        uint8_t c0 = uint8_t((code >> 16) & 0xff);
        uint8_t a1 = uint8_t((code >> 8) & 0xff);
        uint8_t a0 = uint8_t(code & 0xff);
        uint64_t codeOut = (uint64_t(a0) << 24) | (uint64_t(a1) << 16)
            | (uint64_t(c0) << 8) | uint64_t(c1);

        // report it
        reportCode(receiver, IRPRO_TCLROKU, codeOut, bool3::null, bool3::null);
    }
    
    // determine if we have a TCL/Roku address
    bool isTCLRokuCode()
    {
        // It's a TCL/Roku model if the address field is EA C7
        return (code & 0xFFFF) == 0xC7EA;            
    }

    // The previous TCL/Roku code value.  All codes in this protocol use
    // doubled code words, so we keep track of the first word here.
    uint32_t tclRokuPrvCode;
};

// NEC-32x.  This is a minor variation on the standard NEC-32 protocol,
// with a slightly different header signature and a different ditto
// pattern.
class IRPNEC_32x: public IRPNEC
{
public:
    virtual int id() const { return IRPRO_NEC32X; }
    virtual const char *name() const { return "NEC32x"; }
    virtual int necPro(int bits) const { return IRPRO_NEC32X; }
    
    virtual int nbits() const { return 32; }
    virtual uint32_t tHeaderMark() const { return 4500; }
    virtual uint32_t tHeaderSpace() const { return 4500; }

    // Close out the code.  NEC-32x has an unusual variation of the
    // NEC ditto: it uses the same header as a regular code, but only
    // has a 1-bit payload.
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        if (bit == 1)
            reportCode(receiver, IRPRO_NEC32X, code, bool3::null, true);
        else
            IRPNEC::rxClose(receiver, ditto);
    }
    
};

// -----------------------------------------------------------------------
// 
// Kaseikyo protocol handler.  Like NEC, this is a quasi industry standard
// used by many companies.  Unlike NEC, it seems to be used consistently
// by just about everyone.  There are only two main variations: a 48-bit
// coding and a 56-bit coding.
//
// For all versions, the first 16 bits in serial order provide an OEM ID.
// We use this to report manufacturer-specific protocol IDs, even though
// the low-level coding is the same for all of them.  Differentiating
// by manufacturer is mostly for cosmetic reasons, so that human users
// looking at learned codes or looking for codes to program will see
// names matching their equipment.  In some cases it's also useful for
// interpreting the internal data fields within the bit string; some
// OEMs use checksums or other fields that clients might want to 
// interpret.
//
class IRPKaseikyo: public IRPSpaceLength<uint64_t>
{
public:
    IRPKaseikyo() { }

    // name and ID
    virtual const char *name() const { return "Kaseikyo"; }
    virtual int id() const { return IRPRO_KASEIKYO48; }
    
    // we handle all of the OEM-specific protocols
    virtual bool isSenderFor(int id) const
    {
        switch (id)
        {
        case IRPRO_KASEIKYO48:
        case IRPRO_KASEIKYO56:
        case IRPRO_DENONK:
        case IRPRO_FUJITSU48:
        case IRPRO_FUJITSU56:
        case IRPRO_JVC48:
        case IRPRO_JVC56:
        case IRPRO_MITSUBISHIK:
        case IRPRO_PANASONIC48:
        case IRPRO_PANASONIC56:
        case IRPRO_SHARPK:
        case IRPRO_TEACK:
            return true;
            
        default:
            return false;
        }
    }
    
    // code boundary parameters
    virtual uint32_t tHeaderMark() const { return 3500; }
    virtual uint32_t tHeaderSpace() const { return 1750; }
    virtual uint32_t minRxGap() const { return 2500; }
    virtual uint32_t txGap(IRTXState *state) const { return 173000; }
    
    // space length coding
    virtual int nbits() const { return 56; }
    virtual int tMark() const { return 420; }
    virtual int tZero() const { return 420; }
    virtual int tOne() const { return 1300; }
    
    // protocol/OEM mappings
    struct OEMMap
    {
        uint16_t oem;
        uint8_t pro;
        uint8_t bits;
    };
    static const OEMMap oemMap[];
    static const int nOemMap;

    // close code reception
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        // it must be a 48-bit or 56-bit code
        if (bit != 48 && bit != 56)
            return;
            
        // pull out the OEM code in the low 16 bits
        int oem = int(code & 0xFFFF);
        
        // Find the protocol based on the OEM
        uint8_t pro = bit == 48 ? IRPRO_KASEIKYO48 : IRPRO_KASEIKYO56;
        for (int i = 0 ; i < nOemMap ; ++i)
        {
            if (oemMap[i].oem == oem && oemMap[i].bits == bit)
            {
                pro = oemMap[i].pro;
                break;
            }
        }
                
        // report the code
        reportCode(receiver, pro, code, bool3::null, bool3::null);
    }

    virtual void codeToBitstream(IRTXState *state)
    {
        // presume no OEM and a 48-bit version of the protocol
        uint16_t oem = 0;
        state->nbits = 48;

        // find the protocol variation in the table
        for (int i = 0 ; i < nOemMap ; ++i)
        {
            if (state->protocolId == oemMap[i].pro)
            {
                state->nbits = oemMap[i].bits;
                oem = oemMap[i].oem;
                break;
            }
        }
        
        // if we found a non-zero OEM code, and it doesn't match the
        // low-order 16 data bits, replace the OEM code in the data
        uint64_t code = state->cmdCode;
        if (oem != 0 && int(code & 0xFFFF) != oem)
            code = (code & ~0xFFFFLL) | oem;
        
        // store the code (with possibly updated OEM coding)
        state->bitstream = code;
    }
};

// -----------------------------------------------------------------------
// 
// Philips RC5 protocol handler.  This (along with RC6) is a quasi industry 
// standard among European CE companies, so this protocol gives us 
// compatibility with many devices from companies besides Philips.
//
// RC5 is a 14-bit Manchester-coded protocol.  '1' bits are encoded as
// low->high transitions.
//
// The 14 bits of the command are internally structured as follows:
//
//   S F T AAAAA CCCCCC
//
// S = "start bit".  Always 1.  We omit this from the reported code
//     since it's always the same.
//
// F = "field bit", which selects a default (1) or extended (0) set of 
//     commands.  Note the reverse sensing, with '1' being the default.
//     This is because this position was a second stop bit in the original
//     code, always set to '1'.  When Philips repurposed the bit as the
//     field code in a later version of the protocol, they used '1' as
//     the default for compatibility with older devices.  We pass the bit
//     through as-is to the universal representation, so be aware that 
//     you might have to flip it to match some published code tables.
//
// T = "toggle bit".  This changes on each successive key press, to allow
//     the receiver to distinguish pressing the same key twice from auto-
//     repeat due to holding down the key.
//
// A = "address", most significant bit first; specifies which type of
//     device the command is for (e.g., "TV", "VCR", etc).  The meanings
//     of the possible numeric values are arbitrarily assigned by Philips; 
//     you can Philips; you can find tables online (e.g., at Wikipedia)
//     with the published assignments.
//
// C = "command", most significant bit first; the command code.  The
//     meaning of the command code varies according to the type of device 
//     in the address field.  Published tables with the standard codes can
//     be found online.
//
// Note that this protocol doesn't have a "header" per se; it just starts
// in directly with the first bit.  As soon as we see a long enough gap,
// we're ready for the start bit.
//
class IRPRC5: public IRPManchester<uint16_t>
{
public:
    IRPRC5() { }
    
    // name and ID
    virtual const char *name() const { return "Philips RC5"; }
    virtual int id() const { return IRPRO_RC5; }
    
    // code parameters
    virtual float pwmPeriod(IRTXState *state) const { return 27.7777778e-6; } // 36kHz
    virtual uint32_t minRxGap() const { return 3600; }
    virtual uint32_t txGap(IRTXState *state) const { return 114000; }
    virtual bool lsbFirst() const { return false; }
    virtual int nbits() const { return 14; }
    
    // RC5 has no header; the start bit immediately follows the gap
    virtual uint32_t tHeaderMark() const { return 0; }
    virtual uint32_t tHeaderSpace() const { return 0; }
    
    // Manchester coding parameters
    virtual int tHalfBit(int bit) const { return 1778/2; }
    
    // After the gap, the start of the next mark is in the middle
    // of the start bit.  A '1' start bit always follows the gap,
    // and a '1' bit is represented by a space-to-mark transition,
    // so the end of the gap is the middle of the start bit.
    virtual void rxReset()
    {
        IRPManchester<uint16_t>::rxReset();
        halfBitPos = 1;
    }

    virtual void codeToBitstream(IRTXState *state)
    {
        // add the start bit and toggle bit to the command code
        state->nbits = nbits();
        state->bitstream = (state->cmdCode & DataMask) | StartMask;
        if (state->toggle)
            state->bitstream |= ToggleMask;
    }
    
    // report the code 
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        // make sure we have the full code
        if (bit == 14)
        {
            // Pull out the toggle bit to report separately, and zero it
            // out in the code word, so that a given key always reports
            // the same code value.  Also zero out the start bit, since
            // it's really just structural.
            reportCode(
                receiver, id(),
                code & ~(StartMask | ToggleMask),
                (code & ToggleMask) != 0, bool3::null);
        }
    }

    // masks for the internal fields
    static const int CmdMask = 0x3F;
    static const int AddrMask = 0x1F << 6;
    static const int ToggleMask = 1 << 11;
    static const int FieldMask = 1 << 12;
    static const int StartMask = 1 << 13;
    static const int DataMask = FieldMask | AddrMask | CmdMask;
};

// -----------------------------------------------------------------------
// 
// RC6 protocol handler.  This (along with RC5) is a quasi industry 
// standard among European CE companies, so this protocol gives us 
// compatibility with many devices from companies besides Philips.
//
// RC6 is a 21-bit Manchester-coded protocol.  '1' bits are coded as
// High->Low transitions.  The bits are nominally structured into
// fields as follows:
//
//   S FFF T AAAAAAAA CCCCCCCC
//
// The fields are:
//
//   S = start bit; always 1.  We omit this from the reported value since
//       it's always the same.
//
//   F = "field".  These bits are used to select different command sets,
//       so they're effectively three additional bits (added as the three
//       most significant bits) for the command code.
//
//   A = "address", specifying the type of device the command is for.
//       This has the same meanings as the address field in RC5.
//
//   C = "command".  The command code, specific to the device type
//       in the address field.
//
// As with all protocols, we don't reproduce the internal field structure
// in the decoded command value; we simply pack all of the bits into a
// 18-bit integer, in the order shown above, field bits at the high end.
// (We omit the start bit, since it's a fixed element that's more properly
// part of the protocol than part of the code.)
//
// Note that this protocol contains an odd exception to normal Manchester 
// coding for the "toggle" bit.  This bit has a period 2X that of the other
// bits.
//
class IRPRC6: public IRPManchester<uint32_t>
{
public:
    IRPRC6() { }

    // name and ID
    virtual const char *name() const { return "Philips RC6"; }
    virtual int id() const { return IRPRO_RC6; }

    // code parameters
    virtual float pwmPeriod(IRTXState *state) const { return 27.7777778e-6; } // 36kHz
    virtual uint32_t tHeaderMark() const { return 2695; }
    virtual uint32_t tHeaderSpace() const { return 895; }
    virtual uint32_t minRxGap() const { return 2650; }
    virtual uint32_t txGap(IRTXState *state) const { return 107000; }
    virtual bool lsbFirst() const { return false; }
    virtual int nbits() const { return 21; }
    
    // Manchester coding parameters
    virtual int spaceToMarkBit() const { return 0; }

    // RC6 has the weird exception to the bit timing in the Toggle bit,
    // which is twice as long as the other bits.  The toggle bit is the
    // 5th bit (bit==4).
    virtual int tHalfBit(int bit) const { return bit == 4 ? 895 : 895/2; }

    // create the bit stream for the command code
    virtual void codeToBitstream(IRTXState *state)
    {
        // add the start bit and toggle bit to the command code
        state->nbits = nbits();
        state->bitstream = (state->cmdCode & DataMask) | StartMask;
        if (state->toggle)
            state->bitstream |= ToggleMask;
    }
    
    // report the code 
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        // make sure we have the full code
        if (bit == nbits())
        {
            // Pull out the toggle bit to report separately, and zero it
            // out in the code word, so that a given key always reports
            // the same code value.  Also clear the start bit, since it's
            // just structural.
            reportCode(
                receiver, id(),
                code & ~(ToggleMask | StartMask), 
                (code & ToggleMask) != 0, bool3::null);
        }
    }

    // field masks
    static const int CmdMask =   0xFF;
    static const int AddrMask =  0xFF << 8;
    static const int ToggleMask = 1 << 16;
    static const int FieldMask = 0x07 << 17;
    static const int StartMask = 1 << 20;
    static const int DataMask =  FieldMask | AddrMask | CmdMask;
};

// -----------------------------------------------------------------------
//
// Ortek MCE remote.  This device uses Manchester coding, with either 16
// or 17 bits, depending on which keys are pressed.  The low-order 5 bits
// of either code are the device code.  The interpretation of the rest of
// the bits depends on the device code.  Bits are sent least-significant
// first (little-endian) for interpretation as integer values.
//
// Device code = 0x14 = Mouse.  This is a 16-bit code, with the fields
// as follows (low bit first):
//
//  DDDDD L R MMMMM CCCC
//
//  D = device code (common field for all codes)
//  L = left-click (1=pressed, 0=not pressed)
//  R = right-click (1=pressed, 0=not pressed)
//  M = mouse movement direction.  This type of device is a mouse stick
//      rather than a mouse, so it gives only the direction of travel rather
//      than X/Y motion in pixels.  There are 15 increments of motion numbered
//      0 to 15, starting with 0 at North (straight up), going clockwise:
//        0 = N
//        1 = NNE
//        2 = NE
//        3 = ENE
//        4 = E
//        5 = ESE
//        6 = SE
//        7 = SSE
//        8 = S
//        9 = SSW
//        10 = SW
//        11 = WSW
//        12 = W
//        13 = WNW
//        14 = NW
//        15 = NNW
//     The MMMMM field contains 0x10 | the value above when a mouse motion
//     direction is pressed, so the codes will be 0x10 (N), 0x11 (NNE), ...,
//     0x1F (NNW).  These are shifted left by two in the reported function
//     code, so you'll actually see 0x40 ... 0x7C.
//  C = checksum
//
// There's no equivalent of the "position" code (see device 0x15 below) for
// the mouse commands, so there's no coding for auto-repeat per se.  The
// remote does let the receiver when the last key is released, though, by
// sending one code word with the L, R, and M bits all set to zero; this
// apparently signifies "key up".  One of these is always sent after the 
// last key is released, but it's not sent between auto-repeated codes,
// so if you hold a key down you'll see a sequence of repeating codes
// for that key (or key combination), followed by one "key up" code when
// you release the last key.
//
// Receivers who interpret these codes will probably want to separate the
// L, R, and M bits and treat them separately, rather than treating any given
// combination as a discrete command.  The reason is that the L and R bits
// can combine with the mouse movement field when a left-click or right-click
// button is held down while the movement keys are pressed.  This can be used
// to perform click-and-drag operations on a GUI.
//
// Device code = 0x15 = MCE buttons.  This is a 17-bit code, with the
// fields as follows (low bit first):
//
//  DDDDD PP FFFFFF CCCC
//
//  D = device code (common field for all codes)
//  P = "position code", for sensing repeats: 00=first, 01=middle, 10=last
//  F = function (key code)
//  C = checksum
//
// The checksum is the 3 + the total number of '1' bits in the other fields
// combined.
//
// We report these codes in our own 16-bit format, with D in the high byte,
// and the function code in the low byte.  For the mouse commands (device 0x14),
// the low byte is (high bit to low bit) 0MMMMMRL.  For the MCE buttons, the
// low byte is the function code (F).  We drop the position code for uniformity
// with other protocols and instead report a synthetic toggle bit, which we
// flip whenever we see a new transmission as signified by P=0.  We don't do
// anything with the toggle bit on mouse commands.
//
class IRPOrtekMCE: public IRPManchester<uint32_t>
{
public:
    IRPOrtekMCE() 
    {
        toggle = 0;
    }

    // name and ID
    virtual const char *name() const { return "OrtekMCE"; }
    virtual int id() const { return IRPRO_ORTEKMCE; }
    
    // code parameters
    virtual float pwmPeriod(IRTXState *state) const { return 25.906736e-6; } // 38.6kHz
    virtual uint32_t tHeaderMark() const { return 4*480; }
    virtual uint32_t tHeaderSpace() const { return 1*480; }
    virtual bool headerSpaceToData() const { return true; }
    virtual uint32_t minRxGap() const { return 32000; }
    virtual uint32_t txGap(IRTXState *state) const { return 40000; }
    
    // We always require a final rep with position code 2, so
    // ask for a minimum of 3 reps (0, 1, 2).
    virtual int txMinReps(IRTXState *) const { return 3; }
    
    // Manchester coding parameters
    virtual int nbits() const { return 17; }
    virtual int spaceToMarkBit() const { return 1; }
    virtual int tHalfBit(int bit) const { return 480; }
    
    // encode the bitstream for a given code
    virtual void codeToBitstream(IRTXState *state)
    {
        // Set the repeat count.  If we're on any repeat > 0 and 
        // the key is still pressed, reset the repeat counter to 1.
        // All repeats are "1" as long as the key is down.  As soon
        // as the key is up, advance directly to "2", even if there
        // was never a "1".  Our txMinRep() count is 2, so this will
        // ensure that we always transmit that last position 2 code,
        // as required by the protocol.
        if (state->rep > 0)
            state->rep = state->pressed ? 1 : 2;

        // Function field and checksum bit position - we'll fill
        // these in momentarily according to the device type.
        uint32_t f;
        int c_shift;

        // check the product code to determine the encoding
        uint32_t cmdcode = uint32_t(state->cmdCode);
        int dev = (int(cmdcode) >> 8) & 0xff;
        if (dev == 0x14)
        {
            // Mouse function:  DDDDD L R MMMMM CCCC
            // There's no position field in the mouse messages, but
            // we always have to send a final message with all bits
            // zeroed.  Do this when our rep count is 2, indicating
            // that this is the final close-out rep.
            if (state->rep == 2)
                f = 0;
            else
                f = cmdcode & 0xff;
                
            // the checksum starts at the 12th bit
            c_shift = 12;
        }
        else if (dev == 0x15)
        {
            // MCE button:  DDDDD PP FFFFFF CCCC
            
            // Set the position field to the rep counter
            int p = state->rep;
            
            // fill in the function fields: PP FFFFFF
            f = (p) | ((cmdcode & 0x3F) << 2);
            
            // the checksum starts at the 13th bit
            c_shift = 13;
        }
        else
        {
            // unknown device code - just transmit the low byte as given
            f = cmdcode & 0xff;
            c_shift = 13;
        }
        
        // construct the bit vector with the device code in the low 5
        // bits and code in the next 7 or 8 bits
        uint32_t bitvec = dev | (f << 5);
            
        // figure the checksum: it's the number of '1' bits in
        // the rest of the fields, plus 3
        uint32_t checksum = 3;
        for (uint32_t v = bitvec ; v != 0 ; checksum += (v & 1), v >>= 1) ;
        
        // construct the bit stream
        state->bitstream = bitvec | (checksum << c_shift);
        state->nbits = c_shift + 4;
    }
        
    // report the code value    
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        // common field masks
        const uint32_t D_mask = 0x001F;   // lowest 5 bits = device code
        
        // pull out the common fields
        uint32_t d = code & D_mask;
        
        // assume no post-toggle
        bool postToggle = false;
        
        // check for the different code types, and pull out the fields
        uint32_t f, c, checkedBits;
        if (bit == 16 && d == 0x14)
        {
            // field masks for the mouse codes
            const int      F_shift = 5;
            const uint32_t F_mask = 0x7f << F_shift;  // next 7 bits
            const int      C_shift = 12;
            const uint32_t C_mask = 0x3F << C_shift;  // top 4 bits

            // separate the fields
            f = (code & F_mask) >> F_shift;
            c = (code & C_mask) >> C_shift;
            checkedBits = code & ~C_mask;
            
            // if the F bits are all zero, take it as a "key up" sequence,
            // so flip the toggle bit next time
            if (f == 0)
                postToggle = true;
        }
        else if (bit == 17 && d == 0x15)
        {
            // 17 bits with device code 0x15 = MCE keyboard commands
            
            // field masks for the keyboard codes
            const int      P_shift = 5;
            const uint32_t P_mask = 0x0003 << P_shift;  // next 2 bits
            const int      F_shift = 7;
            const uint32_t F_mask = 0x3F << F_shift;    // next 6 bits
            const int      C_shift = 13;
            const uint32_t C_mask = 0x0F << C_shift;    // top 4 bits

            // separate the fields
            uint32_t p = (code & P_mask) >> P_shift;
            f = (code & F_mask) >> F_shift;
            c = (code & C_mask) >> C_shift;
            checkedBits = code & ~C_mask;

            /// validate the position code - 0,1,2 are valid, 3 is invalid
            if (p == (0x03 << P_shift))
                return;
                
            // flip the toggle bit if this is the first frame in a group
            // as signified by P=0
            if (p == 0)
                toggle ^= 1;                
        }
        else
        {
            // invalid bit length or device code - reject the code
            return;
        }
            
        // count the '1' bits in the other fields to get the checksum value
        int ones = 0;
        for ( ; checkedBits != 0 ; checkedBits >>= 1)
            ones += (checkedBits & 1);
            
        // check the checksum
        if (c != ones + 3)
            return;
                
        // rearrange the code into our canonical format and report it
        // along with the synthetic toggle
        reportCode(receiver, id(), (d << 8) | f, toggle, bool3::null);
        
        // flip the toggle for next time, if desired
        if (postToggle)
            toggle ^= 1;
    }
    
    // synthetic toggle bit
    uint8_t toggle : 1;
};

// -----------------------------------------------------------------------
// 
// Sony protocol handler.  Sony uses mark-length encoding, with
// 8, 12, 15, and 20 bit code words.  We use a common receiver
// base class that determines how many bits are in the code from
// the input itself, plus separate base classes for each bit size.
// The common receiver class reports the appropriate sub-protocol
// ID for the bit size, so that the appropriate sender class is
// used if we want to transmit the captured code.
//
class IRPSony: public IRPMarkLength<uint32_t>
{
public:
    IRPSony() { }

    // Name and ID.  We handle all of the Sony bit size variations,
    // so we use IRPRO_NONE as our nominal ID, but set the actual code
    // on a successful receive based on the actual bit size.  We
    // transmit any of the Sony codes.
    virtual const char *name() const { return "Sony"; }
    virtual int id() const { return IRPRO_NONE; }
    virtual bool isSenderFor(int protocolId) const
    {
        return protocolId == IRPRO_SONY8
            || protocolId == IRPRO_SONY12
            || protocolId == IRPRO_SONY15
            || protocolId == IRPRO_SONY20;
    }
    
    // code boundary parameters
    virtual uint32_t tHeaderMark() const { return 2400; }
    virtual uint32_t tHeaderSpace() const { return 600; }
    virtual uint32_t minRxGap() const { return 5000; }
    virtual uint32_t txGap(IRTXState *state) const { return 45000; }
    
    // mark-length coding parameters
    virtual int nbits() const { return 20; }  // maximum - can also be 8, 12, or 15
    virtual int tSpace() const { return 600; }
    virtual int tZero() const { return 600; }
    virtual int tOne() const { return 1200; }
    
    // Sony requires at least 3 sends per key press
    virtual int txMinReps(IRTXState *state) const { return 3; }

    // set up the bitstream for a code value    
    virtual void codeToBitstream(IRTXState *state)
    {
        // store the code, and set the bit counter according to
        // the Sony protocol subtype
        state->bitstream = state->cmdCode;
        switch (state->protocolId)
        {
        case IRPRO_SONY8:
            state->nbits = 8;
            break;
            
        case IRPRO_SONY12:
            state->nbits = 12;
            break;
            
        case IRPRO_SONY15:
            state->nbits = 15;
            break;
            
        case IRPRO_SONY20:
        default:
            state->nbits = 20;
            break;
        }
    }
    
    // report a code value
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        // we have a valid code if we have 8, 12, 15, or 20 bits
        switch (bit)
        {
        case 8:
            reportCode(receiver, IRPRO_SONY8, code, bool3::null, bool3::null);
            break;
            
        case 12:
            reportCode(receiver, IRPRO_SONY12, code, bool3::null, bool3::null);
            break;
            
        case 15:
            reportCode(receiver, IRPRO_SONY15, code, bool3::null, bool3::null);
            break;
            
        case 20:
            reportCode(receiver, IRPRO_SONY20, code, bool3::null, bool3::null);
            break;
        }
    }
};

// -----------------------------------------------------------------------
// 
// Denon protocol handler.  Denon uses a 15-bit space-length coding, but 
// has two unusual features.  First, it has no header; it just starts
// right off with the data bits.  Second, every code is transmitted a
// second time, starting 65ms after the start of the first iteration,
// with the "F" and "S" fields inverted:
//
//   DDDDD FFFFFFFF SS
//
//   D = device code
//   F = function code (key)
//   S = sequence; 0 for the first half of the pair, 1 for the second half
//
// The first half-code is transmitted with the actual function code and 
// SS=00; the second half uses ~F (1's complement of the function code)
// and SS=11.
//
// Many learning remotes get this wrong, only learning one or the other
// half.  That's understandable, since learning remotes often only collect
// the raw bit codes and thus wouldn't be able to detect the multi-code
// structure.  It's a little less forgiveable that some pre-programmed
// universal remotes, such as the Logitech Harmony series, also miss the
// half-code nuance.  To be robust against errant remotes, we'll accept
// and report lone half-codes, and we'll invert the F bits if the S bits 
// indicate that a second half was learned, to ensure that the client sees
// the correct version of the codes.  We'll also internally track the
// pairs so that, when we *do* see a properly formed inverted pair, we'll
// only report one code out of the pair to the client.
//
class IRPDenon: public IRPSpaceLength<uint16_t>
{
public:
    IRPDenon() 
    {
        prvCode = 0;
    }

    // name and ID
    virtual const char *name() const { return "Denon"; }
    virtual int id() const { return IRPRO_DENON; }
    
    // Code parameters.  The Denon protocol has no header; it just
    // jumps right in with the first bit.
    virtual uint32_t tHeaderMark() const { return 0; }
    virtual uint32_t tHeaderSpace() const { return 0; }
    virtual uint32_t minRxGap() const { return 30000; }
    
    // use a short gap between paired complemented codes, and a longer
    // gap between repeats
    virtual uint32_t txGap(IRTXState *state) const { return 165000; }
    virtual uint32_t txPostGap(IRTXState *state) const 
    {
        if (state->rep == 0)
        {
            // Even rep - this is the gap between the two halves of a
            // complemented pair.  The next code starts 65ms from the
            // *start* of the last code, so the gap is 65ms minus the
            // transmission time for the last code.
            return 65000 - state->txTime.read_us();
        }
        else
        {
            // odd rep - use the normal long gap
            return 165000; 
        }
    }
    
    // on idle, clear the previous code
    virtual void rxIdle(IRRecvProIfc *receiver)
    {
        prvCode = 0;
    }
    
    // space length coding
    virtual int nbits() const { return 15; }
    virtual int tMark() const { return 264; }
    virtual int tZero() const { return 792; }
    virtual int tOne() const { return 1848; }
    
    // handle a space
    virtual bool rxSpace(IRRecvProIfc *receiver, uint32_t t)
    {
        // If this space is longer than the standard space between
        // adjacent codes, clear out any previous first-half code 
        // we've stored.  Complementary pairs have to be transmitted
        // with the standard inter-code gap between them.  Anything
        // longer must be separate key presses.
        if (t > 65000)
            prvCode = 0;

        // do the normal work
        return IRPSpaceLength<uint16_t>::rxSpace(receiver, t);
    }
    
    // always send twice, once for the base version, once for the
    // inverted follow-up version
    virtual int txMinReps(IRTXState *state) const { return 2; }
    
    // encode the bitstream
    virtual void codeToBitstream(IRTXState *state)
    {
        // If we're on an even repetition, just send the code
        // exactly as given.  If we're on an odd repetition,
        // send the inverted F and S fields.
        state->nbits = 15;
        if (state->rep == 0 || state->rep == 2)
        {
            // even rep - send the base version
            state->bitstream = state->cmdCode & (D_mask | F_mask);
            
            // If we're on rep 2, switch back to rep 0.  This will
            // combine with our minimum rep count of 2 to ensure that
            // we always transmit an even number of copies.  Note that
            // this loop terminates: when the key is up after we finish
            // rep 1, the rep counter will advance to 2 and we'll stop.
            // We'll only reset the rep counter here if we actually
            // enter rep 2, which means the key is still down at that
            // point, which means that we'll have to go at least another
            // two iterations.
            state->rep = 0;
        }
        else
        {
            // odd rep - invert the F field, and use all 1's in the S field
            uint32_t d = state->cmdCode & D_mask;
            uint32_t f = (~state->cmdCode) & F_mask;
            state->bitstream = d | f | S_mask;
        }
    }
            
    // report the code
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        // If this code matches the inverted prior code, we have
        // a matching pair.  Otherwise, hang onto this code until
        // next time.
        if (bit == 15)
        {
            // get the current and previous code's subfields
            uint16_t curD = code & D_mask;
            uint16_t curF = code & F_mask;
            uint16_t curS = code & S_mask;
            uint16_t prvD = prvCode & D_mask;
            uint16_t prvF = prvCode & F_mask;
            uint16_t prvS = prvCode & S_mask;
            
            // check to see if the current FS fields match the inverted
            // prior FS fields, to make up a complementary pair as required
            // by the protocol
            if (curD == prvD && curF == (~prvF & F_mask) && curS == (~prvS & S_mask))
            {
                // The current code is the second half of the first code.
                // Don't report the current code, since it's just an 
                // error-checking copy of the previous code, which we already
                // reported.  We've now seen both halves, so clear the 
                // previous code.
                prvCode = 0;
            }
            else
            {
                // This isn't the second half of an complementary pair, so
                // report it as a separate code.  If the 'S' bits are 1's
                // in this code, it's the second half of the pair, so invert
                // the F and S fields to get the original code.  It might
                // have been sent by a learning remote or universal remote
                // that only captured the second half field.
                if (curS == S_mask)
                {
                    // The S bits are 1's, so it's a second-half code.  We
                    // don't have a matching first-half code, so either the
                    // first half was lost, or it was never transmitted.  In
                    // either case, reconstruct the original first-half code
                    // by inverting the F bits and clearing the S bits.
                    reportCode(receiver, id(), curD | (~curF & F_mask),
                        bool3::null, bool3::null);
                    
                    // Forget any previous code.  This is a second-half
                    // code, so if we do get a first-half code after this,
                    // it's a brand new key press or repetition.
                    prvCode = 0;
                }
                else if (curS == 0)
                {
                    // The S bits are 0, so it's a first-half code.  Report
                    // the code, and save it for next time, so that we can
                    // check the next code to see if it's the second half.
                    reportCode(receiver, id(), code, bool3::null, bool3::null);
                    prvCode = code;
                }
                else
                {
                    // The S bits are invalid, so this isn't a valid code.
                    // Clear out any previous code and reject this one.
                    prvCode = 0;
                }
            }
        }
        else
        {
            // we seem to have an invalid code; clear out any
            // previous code so we can start from scratch
            prvCode = 0;
        }
    }
        
    // stored first code - we hang onto this until we see the
    // inverted second copy, so that we can verify a matching pair
    uint16_t prvCode;
    
    // masks for the subfields
    static const int F_shift = 5;
    static const int S_shift = 13;
    static const uint16_t D_mask = 0x1F;
    static const uint16_t F_mask = 0x00FF << F_shift;
    static const uint16_t S_mask = 0x0003 << S_shift;
};

// -----------------------------------------------------------------------
// 
// Samsung 20-bit protocol handler.  This is a simple space-length 
// encoding.
//
class IRPSamsung20: public IRPSpaceLength<uint32_t>
{
public:
    IRPSamsung20() { }
    
    // name and ID
    virtual const char *name() const { return "Samsung20"; }
    virtual int id() const { return IRPRO_SAMSUNG20; }
    
    // code parameters
    virtual float pwmPeriod(IRTXState *state) const { return 26.0416667e-6; } // 38.4 kHz
    virtual uint32_t tHeaderMark() const { return 8*564; }
    virtual uint32_t tHeaderSpace() const { return 8*564; }
    virtual uint32_t minRxGap() const { return 2*564; }
    virtual uint32_t txGap(IRTXState *state) const { return 118000; }
    
    // space length coding
    virtual int nbits() const { return 20; }
    virtual int tMark() const { return 1*564; }
    virtual int tZero() const { return 1*564; }
    virtual int tOne() const { return 3*564; }
};

// Samsung 36-bit protocol.  This is similar to the NEC protocol,
// with different header timing.
class IRPSamsung36: public IRPSpaceLength<uint32_t>
{
public:
    IRPSamsung36() { }

    // name and ID
    virtual const char *name() const { return "Samsung36"; }
    virtual int id() const { return IRPRO_SAMSUNG36; }
    
    // code parameters
    virtual uint32_t tHeaderMark() const { return 9*500; }
    virtual uint32_t tHeaderSpace() const { return 9*500; }
    virtual uint32_t minRxGap() const { return 40000; }
    virtual uint32_t txGap(IRTXState *state) const { return 118000; }
    
    // space length coding
    virtual int nbits() const { return 36; }
    virtual int tMark() const { return 1*500; }
    virtual int tZero() const { return 1*500; }
    virtual int tOne() const { return 3*500; }    
};

// -----------------------------------------------------------------------
//
// Lutron lights, fans, and home automation.  Lutron uses a simple async
// bit coding: a 2280us space represents '0', a 2280us mark represents '1'.
// Each code consists of 36 bits.  The start of a code word is indicated
// by a space of at least 4*2280us followed by a mark of at least 8*2280us.
// The mark amounts to 8 consecutive '1' bits, which Lutron includes as
// digits in the published codes, so we'll include them in our representation 
// as well (as opposed to treating them as a separate header).

// These raw 36-bit strings use an internal error correction coding.  This
// isn't mentioned in Lutron's technical documentation (they just list the
// raw async bit strings), but there's a description on the Web (see, e.g.,
// hifi-remote.com; the original source is unclear).  According to that,
// you start with a pair of 8-bit values (device code + function).  Append
// two parity bits for even parity in each byte.  This gives us 18 bits.
// Divide the 18 bits into 6 groups of 3 bits.  For each 3-bit group, take
// the binary value (0..7), recode the bits as a reflected Gray code for
// the same number (e.g., '111' binary = 7 = '100' Gray coded), then add
// an even parity bit.  We now have 24 bits.  Concatenate these together
// and sandwich them between the 8 x '1' start bits and the 4 x '0' stop
// bits, and we have the 36-bit async bit stream.
//
// The error correction code lets us apply at least one validation check:
// we can verify that each 4-bit group in the raw data has odd parity.  If
// it doesn't, we'll reject the code.  Ideally, we could also reverse the
// whole coding scheme above and check the two even parity bits for the
// recovered bytes.  Unfortunately, I haven't figured out how to do this;
// taking the Web description of the coding at face value doesn't yield
// correct parity bits for all of the codes published by Lutron.  Either
// the description is wrong, or I'm just misinterpreting it (which is
// likely given that it's pretty sketchy).  
// 
class IRPLutron: public IRPAsync<uint32_t>
{
public:
    IRPLutron() { }

    // name and ID
    virtual const char *name() const { return "Lutron"; }
    virtual int id() const { return IRPRO_LUTRON; }
    
    // carrier is 40kHz
    virtual float pwmPeriod(IRTXState *state) const { return 25.0e-6f; } // 40kHz

    // All codes end with 4 '0' bits, which is as much of a gap as these
    // remotes provide.
    virtual uint32_t minRxGap() const { return 2280*4 - 700; }
    virtual uint32_t txGap(IRTXState *state) const { return 2280*16; }
    
    // Lutron doesn't have a formal header, but there's a long mark at 
    // the beginning of every code.
    virtual uint32_t tHeaderMark() const { return 2280*8; }
    virtual uint32_t tHeaderSpace() const { return 0; }
    
    // Bit code parameters.  The Lutron codes are 36-bits, each bit
    // is 2280us long, and bits are stored MSB first.
    virtual bool lsbFirst() const { return false; }
    virtual int nbits() const { return 24; }
    virtual int tBit() const { return 2280; }
    
    // Validate a received code value, using the decoding process
    // described above.  The code value given here is the low-order
    // 32 bits of the 36-bit code, with the initial FF stripped.
    bool rxValidate(uint32_t c)
    {
        // the low 4 bits must be zeroes
        if ((c & 0x0000000F) != 0)
            return false;
            
        // drop the 4 '0' bits at the end
        c >>= 4;
        
        // parity table for 4-bit values 0x00..0x0F - 0=even, 1=odd
        static const int parity[] = {
            0, 1, 1, 0,     // 0, 1, 2, 3
            1, 0, 0, 1,     // 4, 5, 6, 7
            1, 0, 0, 1,     // 8, 9, A, B
            0, 1, 1, 0      // C, D, E, F
        };
        
        // add up the number of groups with odd parity
        int odds = 0;
        for (int i = 0 ; i < 6 ; ++i, c >>= 4)
            odds += parity[c & 0x0F];
            
        // we need all 6 groups to have odd parity
        return odds == 6;
    }

    // Return the code.  Lutron's code tables have all codes starting
    // with FF (8 consecutive '1' bits), but we treat this as a header,
    // since it can never occur within a code, so it doesn't show up
    // in the bit string.  We also count the tailing four '0' bits,
    // which Lutron also encodes in each string, as a gap.  So we only
    // actually capture 24 data bits.  To make our codes match the
    // Lutron tables, add the structural bits back in for reporting.
    virtual void rxClose(IRRecvProIfc *receiver, bool ditto)
    {
        if (bit == 24)
        {
            uint64_t report = 0xFF0000000LL | (code << 4);
            if (rxValidate(report))
                reportCode(receiver, id(), report, bool3::null, bool3::null);
        }
    }
    
    // For transmission, convert back to the 24 data bits, stripping out
    // the structural leading 8 '1' bits and trailing 4 '0' bits.
    virtual void codeToBitstream(IRTXState *state)
    {
        state->bitstream = (state->cmdCode >> 4) & 0x00FFFFFF;
        state->nbits = 24;
    }
};

// -------------------------------------------------------------------------
//
// Protocol singletons.  We combine these into a container structure
// so that we can allocate the whole set of protocol handlers in one
// 'new'.
//
struct IRProtocols
{
    #define IR_PROTOCOL_RXTX(cls) cls s_##cls;
    #include "IRProtocolList.h"
};

#endif