RemotoIR Libraryに、IRC Helicopter Propo の受信処理と、受信パルス幅測定処理を追加したものです。

Dependents:   SwiftPropoIR_TestProgram irRawDataDisplay spinner2 LPC1114_ir-spinne_main-propo

Fork of RemoteIR by Shinichiro Nakamura

ReceiverIR.cpp

Committer:
suupen
Date:
2013-08-03
Revision:
13:ec76e93a4d7c
Parent:
12:2379e13b8b34

File content as of revision 13:ec76e93a4d7c:

/**
 * IR receiver (Version 0.0.4)
 *
 * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
 * http://shinta.main.jp/
 *
 * -------------------------------------------------------
 * 130616 suupen
 * IRC Helicopter "SWIFT" Propo support
 *  Conditional compilation
 *      "SWIFT_PROTCOL"
 *      "IR_RAW_DATA_ANALYSIS"
 *--------------------------------------------------------
 */

#include "ReceiverIR.h"

#define LOCK()
#define UNLOCK()

#define InRange(x,y)   ((((y) * 0.7) < (x)) && ((x) < ((y) * 1.3)))

/**
 * Constructor.
 *
 * @param rxpin Pin for receive IR signal.
 */
ReceiverIR::ReceiverIR(PinName rxpin) : evt(rxpin)
{
    init_state();
    evt.fall(this, &ReceiverIR::isr_fall);
    evt.rise(this, &ReceiverIR::isr_rise);
    evt.mode(PullUp);
    ticker.attach_us(this, &ReceiverIR::isr_wdt, 10 * 1000);
}

/**
 * Destructor.
 */
ReceiverIR::~ReceiverIR()
{
}

/**
 * Get state.
 *
 * @return Current state.
 */
ReceiverIR::State ReceiverIR::getState()
{
    LOCK();
    State s = work.state;
    UNLOCK();
    return s;
}

/**
 * Get data.
 *
 * @param format Pointer to format.
 * @param buf Buffer of a data.
 * @param bitlength Bit length of the buffer.
 *
 * @return Data bit length.
 */
int ReceiverIR::getData(RemoteIR::Format *format, uint8_t *buf, int bitlength)
{
    LOCK();

    if (bitlength < data.bitcount) {
        UNLOCK();
        return -1;
    }

    const int nbits = data.bitcount;
    const int nbytes = data.bitcount / 8 + (((data.bitcount % 8) != 0) ? 1 : 0);
    *format = data.format;
    for (int i = 0; i < nbytes; i++) {
        buf[i] = data.buffer[i];
    }

    init_state();

    UNLOCK();
    return nbits;
}

void ReceiverIR::init_state(void)
{
    work.c1 = -1;
    work.c2 = -1;
    work.c3 = -1;
    work.d1 = -1;
    work.d2 = -1;
    work.state = Idle;
    data.format = RemoteIR::UNKNOWN;
    data.bitcount = 0;
    timer.stop();
    timer.reset();
    for (int i = 0; i < sizeof(data.buffer); i++) {
        data.buffer[i] = 0;
    }
}

#ifdef ERRORWAIT
void ReceiverIR::errorWait(void)
{
    work.state = ErrorWait;
    timeout.detach();
    timeout.attach_us(this, &ReceiverIR::isr_timeout, 50 * 1000);   // 50[ms]wait
}
#endif //ERRORWAIT

void ReceiverIR::isr_wdt(void)
{
    LOCK();
    static int cnt = 0;
    if ((Idle != work.state) || ((0 <= work.c1) || (0 <= work.c2) || (0 <= work.c3) || (0 <= work.d1) || (0 <= work.d2))) {
        cnt++;
        if (cnt > 50) {
#if 0
            printf("# WDT [c1=%d, c2=%d, c3=%d, d1=%d, d2=%d, state=%d, format=%d, bitcount=%d]\n",
                   work.c1,
                   work.c2,
                   work.c3,
                   work.d1,
                   work.d2,
                   work.state,
                   data.format,
                   data.bitcount);
#endif
            init_state();
            cnt = 0;
        }
    } else {
        cnt = 0;
    }
    UNLOCK();
}

void ReceiverIR::isr_fall(void)
{

#ifdef IR_RAW_DATA_ANALYSIS
    switch (work.state) {
        case Idle:
            if (work.c1 < 0) {
                check.bitcount = 0;
                check.timecount[check.bitcount++] = 0;
            } else {
                check.timecount[check.bitcount++] = timer.read_us() & ~1;
            }
            break;
        case Receiving:

            if ((check.bitcount < 1000))  {
                check.timecount[check.bitcount++] = timer.read_us() & ~1;
            }
            break;
        default:
            break;
    }
#endif //IR_RAW_DATA_ANALYSIS

    LOCK();
    switch (work.state) {
        case Idle:
            if (work.c1 < 0) {
                timer.start();
                work.c1 = timer.read_us();
            } else {
                work.c3 = timer.read_us();
                int a = work.c2 - work.c1;
                int b = work.c3 - work.c2;
                if (InRange(a, RemoteIR::TUS_NEC * 16) && InRange(b, RemoteIR::TUS_NEC * 8)) {
                    /*
                     * NEC.
                     */
                    data.format = RemoteIR::NEC;
                    work.state = Receiving;
                    data.bitcount = 0;
                } else if (InRange(a, RemoteIR::TUS_NEC * 16) && InRange(b, RemoteIR::TUS_NEC * 4)) {
                    /*
                     * NEC Repeat.
                     */
                    data.format = RemoteIR::NEC_REPEAT;
                    work.state = Received;
                    data.bitcount = 0;
                    work.c1 = -1;
                    work.c2 = -1;
                    work.c3 = -1;
                    work.d1 = -1;
                    work.d2 = -1;
                } else if (InRange(a, RemoteIR::TUS_AEHA * 8) && InRange(b, RemoteIR::TUS_AEHA * 4)) {
                    /*
                     * AEHA.
                     */
                    data.format = RemoteIR::AEHA;
                    work.state = Receiving;
                    data.bitcount = 0;
                } else if (InRange(a, RemoteIR::TUS_AEHA * 8) && InRange(b, RemoteIR::TUS_AEHA * 8)) {
                    /*
                     * AEHA Repeat.
                     */
                    data.format = RemoteIR::AEHA_REPEAT;
                    work.state = Received;
                    data.bitcount = 0;
                    work.c1 = -1;
                    work.c2 = -1;
                    work.c3 = -1;
                    work.d1 = -1;
                    work.d2 = -1;
#ifdef SWIFT_PROTCOL
                } else if (InRange(a, RemoteIR::TUS_SWIFT * 10) && InRange(b, RemoteIR::TUS_SWIFT * 3)) {
                    /*
                     * SWIFT.
                     */
                    data.format = RemoteIR::SWIFT;
                    work.state = Receiving;
                    data.bitcount = 0;
#endif  // SWIFT_PROTCOL                    
                } else {
#ifdef IR_RAW_DATA_ANALYSIS
                    data.format = RemoteIR::UNKNOWN;
                    work.state = Receiving;
                    data.bitcount = 0;
#else // ~IR_RAW_DATA_ANALYSIS
#ifdef ERRORWAIT
                    errorWait();
#else // ~ERRORWAIT                    
                    init_state();
#endif // ERRORWAIT
#endif // IR_RAW_DATA_ANALYSIS                
                }
            }
            break;
        case Receiving:
            if (RemoteIR::NEC == data.format) {
                work.d2 = timer.read_us();
                int a = work.d2 - work.d1;
                if (InRange(a, RemoteIR::TUS_NEC * 3)) {
                    data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
                } else if (InRange(a, RemoteIR::TUS_NEC * 1)) {
                    data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
                }
                data.bitcount++;
#if 0
                /*
                 * Length of NEC is always 32 bits.
                 */
                if (32 <= data.bitcount) {
                    data.state = Received;
                    work.c1 = -1;
                    work.c2 = -1;
                    work.c3 = -1;
                    work.d1 = -1;
                    work.d2 = -1;
                }
#else
                /*
                 * Set timeout for tail detection automatically.
                 */
                timeout.detach();
                timeout.attach_us(this, &ReceiverIR::isr_timeout, RemoteIR::TUS_NEC * 5);
#endif
            } else if (RemoteIR::AEHA == data.format) {
                work.d2 = timer.read_us();
                int a = work.d2 - work.d1;
                if (InRange(a, RemoteIR::TUS_AEHA * 3)) {
                    data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
                } else if (InRange(a, RemoteIR::TUS_AEHA * 1)) {
                    data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
                }
                data.bitcount++;
#if 0
                /*
                 * Typical length of AEHA is 48 bits.
                 * Please check a specification of your remote controller if you find a problem.
                 */
                if (48 <= data.bitcount) {
                    data.state = Received;
                    work.c1 = -1;
                    work.c2 = -1;
                    work.c3 = -1;
                    work.d1 = -1;
                    work.d2 = -1;
                }
#else
                /*
                 * Set timeout for tail detection automatically.
                 */
                timeout.detach();
                timeout.attach_us(this, &ReceiverIR::isr_timeout, RemoteIR::TUS_AEHA * 5);
#endif
            } else if (RemoteIR::SONY == data.format) {
                work.d1 = timer.read_us();
#ifdef SWIFT_PROTCOL
            } else if (RemoteIR::SWIFT == data.format) {
                work.d2 = timer.read_us();
                int a = work.d2 - work.d1;
                if (InRange(a, RemoteIR::TUS_SWIFT * 2)) {
                    data.buffer[data.bitcount / 8] |= (1 << (7 - (data.bitcount % 8)));
                } else if (InRange(a, RemoteIR::TUS_SWIFT * 1)) {
                    data.buffer[data.bitcount / 8] &= ~(1 << (7 - (data.bitcount % 8)));
                }
                data.bitcount++;
#if 0
                /*
                 * Length of SWIFT is always 32 bits.
                 */
                if (32 <= data.bitcount) {
                    work.state = Received;
                    work.c1 = -1;
                    work.c2 = -1;
                    work.c3 = -1;
                    work.d1 = -1;
                    work.d2 = -1;
                }
#else
                /*
                 * Set timeout for tail detection automatically.
                 */
                timeout.detach();
                timeout.attach_us(this, &ReceiverIR::isr_timeout, RemoteIR::TUS_SWIFT * 5);
#endif
#endif  // SWIFT_PROTCOL

#ifdef IR_RAW_DATA_ANALYSIS
            } else if (RemoteIR::SWIFT == data.format) {
                /*
                * Set timeout for tail detection automatically.
                */
                timeout.detach();
                timeout.attach_us(this, &ReceiverIR::isr_timeout, (work.c3 - work.c2) * 5);
#endif // IR_RAW_DATA_ANALYSIS
            }
            break;
        case Received:
            break;
#ifdef ERRORWAIT
        case ErrorWait:
            errorWait();
            break;
#endif //ERRORWAIT
        default:
            break;
    }
    UNLOCK();
}

void ReceiverIR::isr_rise(void)
{

#ifdef IR_RAW_DATA_ANALYSIS
    switch (work.state) {
        case Idle:
        case Receiving:
            check.timecount[check.bitcount++] = timer.read_us() | 1;
            break;
#ifdef ERRORWAIT
        case ErrorWait:
            // nothing
            break;
#endif //ERRORWAIT
        default:
            break;
    }
#endif //IR_RAW_DATA_ANALYSIS

    LOCK();
    switch (work.state) {
        case Idle:
            if (0 <= work.c1) {
                work.c2 = timer.read_us();
                int a = work.c2 - work.c1;
                if (InRange(a, RemoteIR::TUS_SONY * 4)) {
                    data.format = RemoteIR::SONY;
                    work.state = Receiving;
                    data.bitcount = 0;
                } else {
                    static const int MINIMUM_LEADER_WIDTH = 150;
                    if (a < MINIMUM_LEADER_WIDTH) {
                        init_state();
                    }
                }
            } else {
                init_state();
            }
            break;
        case Receiving:
            if (RemoteIR::NEC == data.format) {
                work.d1 = timer.read_us();
            } else if (RemoteIR::AEHA == data.format) {
                work.d1 = timer.read_us();
#ifdef SWIFT_PROTCOL
            } else if (RemoteIR::SWIFT == data.format) {
                work.d1 = timer.read_us();
#endif // SWIFT_PROTCOL
            } else if (RemoteIR::SONY == data.format) {
                work.d2 = timer.read_us();
                int a = work.d2 - work.d1;
                if (InRange(a, RemoteIR::TUS_SONY * 2)) {
                    data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
                } else if (InRange(a, RemoteIR::TUS_SONY * 1)) {
                    data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
                }
                data.bitcount++;
#if 0
                /*
                 * How do I know the correct length? (6bits, 12bits, 15bits, 20bits...)
                 * By a model only?
                 * Please check a specification of your remote controller if you find a problem.
                 */
                if (12 <= data.bitcount) {
                    data.state = Received;
                    work.c1 = -1;
                    work.c2 = -1;
                    work.c3 = -1;
                    work.d1 = -1;
                    work.d2 = -1;
                }
#else
                /*
                 * Set timeout for tail detection automatically.
                 */
                timeout.detach();
                timeout.attach_us(this, &ReceiverIR::isr_timeout, RemoteIR::TUS_SONY * 4);
#endif
            }
            break;
        case Received:
            break;
#ifdef ERRORWAIT
        case ErrorWait:
            // nothing
            break;
#endif //ERRORWAIT
        default:
            break;
    }
    UNLOCK();
}

void ReceiverIR::isr_timeout(void)
{
    LOCK();
#if 0
    printf("# TIMEOUT [c1=%d, c2=%d, c3=%d, d1=%d, d2=%d, state=%d, format=%d, bitcount=%d]\n",
           work.c1,
           work.c2,
           work.c3,
           work.d1,
           work.d2,
           work.state,
           data.format,
           data.bitcount);
#endif

#ifdef IR_RAW_DATA_ANALYSIS
#if 1 //debug
    for ( int i = 0; i < check.bitcount; i++) {
        printf("%02d : %06d , %06d , %04d \n",
               i,
               check.timecount[i],
               check.timecount[i + 1],
               (check.timecount[i + 1] - check.timecount[i]));

        if( (i % 2) != 0) {
            printf("\n");
        }
    }
    printf("\n");
#endif //debug
#endif //IR_RAW_DATA_ANALYSIS

    if (work.state == Receiving) {
        work.state = Received;
        work.c1 = -1;
        work.c2 = -1;
        work.c3 = -1;
        work.d1 = -1;
        work.d2 = -1;
    }
#ifdef ERRORWAIT
    else if(work.state == ErrorWait){
        init_state();
    }
#endif // ERRORWAIT
    UNLOCK();
}