enum QDECODER_EVENT {
    QDECODER_EVENT_NONE   = 0x00u,
    QDECODER_EVENT_CW     = 0x80u,
    QDECODER_EVENT_CCW    = 0x40u,
};

// state is internal... needs never be exposed to callers
enum QDECODER_STATE {
    QDECODER_STATE_START      = 0x00u,
    QDECODER_STATE_CW_A       = 0x01u,
    QDECODER_STATE_CW_B       = 0x02u,
    QDECODER_STATE_CW_C       = 0x03u,
    QDECODER_STATE_MID        = 0x04u,
    QDECODER_STATE_CCW_A      = 0x05u,
    QDECODER_STATE_CCW_B      = 0x06u, 
    QDECODER_STATE_CCW_C      = 0x07u,
};

const uint8_t QDECODER_EVENT_BITMASK    = 0xC0; // events are the most significant two bits
const uint8_t QDECODER_STATE_BITMASK    = 0x07; // states are in the least significant three bits

const uint8_t HALF_STEP_STATE_TRANSITIONS[8][4] = {
    // 0 = start
    {QDECODER_STATE_MID,   QDECODER_STATE_CW_A,  QDECODER_STATE_CCW_A, QDECODER_STATE_START },
    // 1 = CW_A
    {QDECODER_EVENT_CW |
     QDECODER_STATE_MID,   QDECODER_STATE_CW_A,  QDECODER_STATE_START, QDECODER_STATE_START },
    // 2 = CW_B (unused in half-step mode)
    {QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START },
    // 3 = CW_C
    {QDECODER_STATE_MID,   QDECODER_STATE_MID,   QDECODER_STATE_CW_C,  QDECODER_STATE_START | QDECODER_EVENT_CW },
    // 4 = mid
    {QDECODER_STATE_MID,   QDECODER_STATE_CCW_C, QDECODER_STATE_CW_C,  QDECODER_STATE_START },
    // 5 = CCW_A
    {QDECODER_EVENT_CCW |
    QDECODER_STATE_MID,   QDECODER_STATE_START, QDECODER_STATE_CCW_A, QDECODER_STATE_START },
    // 6 = CCW_B (unused in half-step mode)
    {QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START },
    // 7 = CCW_C
    {QDECODER_STATE_MID,   QDECODER_STATE_CCW_C, QDECODER_STATE_MID,   QDECODER_STATE_START | QDECODER_EVENT_CCW},
};

const uint8_t FULL_STEP_STATE_TRANSITIONS[8][4] = {
    // 0 = start
    {QDECODER_STATE_START, QDECODER_STATE_CW_A,  QDECODER_STATE_CCW_A, QDECODER_STATE_START },
    // 1 = CW_A
    {QDECODER_STATE_CW_B,  QDECODER_STATE_CW_A,  QDECODER_STATE_START, QDECODER_STATE_START },
    // 2 = CW_B
    {QDECODER_STATE_CW_B,  QDECODER_STATE_CW_A,  QDECODER_STATE_CW_C,  QDECODER_STATE_START },
    // 3 = CW_C
    {QDECODER_STATE_CW_B,  QDECODER_STATE_START, QDECODER_STATE_CW_C,  QDECODER_STATE_START | QDECODER_EVENT_CW },
    // 4 = mid (unused in full step mode ...)
    {QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START },
    // 5 = CCW_A
    {QDECODER_STATE_CCW_B, QDECODER_STATE_START, QDECODER_STATE_CCW_A, QDECODER_STATE_START },
    // 6 = CCW_B
    {QDECODER_STATE_CCW_B, QDECODER_STATE_CCW_C, QDECODER_STATE_CCW_A, QDECODER_STATE_START },
    // 7 = CCW_C
    {QDECODER_STATE_CCW_B, QDECODER_STATE_CCW_C, QDECODER_STATE_START, QDECODER_STATE_START | QDECODER_EVENT_CCW },
};
