Shinichiro Nakamura / Mbed 2 deprecated StarBoardOrangeExample2

Dependencies:   mbed

RemoteIR/ReceiverIR.cpp

Committer:
shintamainjp
Date:
2010-08-15
Revision:
1:9370008ac96b
Parent:
0:5d79cd4ac81d
Child:
2:d4625043c895

File content as of revision 1:9370008ac96b:

/**
 * IR receiver (Version 0.0.2)
 *
 * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
 * http://shinta.main.jp/
 */

#include "ReceiverIR.h"

#define InRange(x,y)   ((((y) * 0.7) < (x)) && ((x) < ((y) * 1.3)))
#define IRQ_ENABLE()    sem.release(); __enable_irq()
#define IRQ_DISABLE()   __disable_irq(); sem.take()

ReceiverIR::ReceiverIR(PinName rx) : evt(rx) {
    IRQ_DISABLE();
    evt.fall(this, &ReceiverIR::isr_fall);
    evt.rise(this, &ReceiverIR::isr_rise);
    ticker.attach_us(this, &ReceiverIR::isr_wdt, 1 * 1000);
    init_state();
    IRQ_ENABLE();
}

ReceiverIR::~ReceiverIR() {}

ReceiverIR::State ReceiverIR::getState() {
    IRQ_DISABLE();
    State s = data.state;
    IRQ_ENABLE();
    return s;
}

int ReceiverIR::getData(ReceiverIR::Format *format, uint8_t *buf, int bufsiz) {
    IRQ_DISABLE();

    const int bc = data.bitcount;
    if (bufsiz < (bc / 8)) {
        IRQ_ENABLE();
        return -1;
    }

    *format = data.format;
    for (int i = 0; i < (bc / 8); i++) {
        buf[i] = data.buffer[i];
    }

    init_state();

    IRQ_ENABLE();
    return bc;
}

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

void ReceiverIR::isr_wdt(void) {
    IRQ_DISABLE();
    static int cnt = 0;
    if ((Receiving == data.state) || ((0 <= work.c1) || (0 <= work.c2) || (0 <= work.c3))) {
        cnt++;
        if (cnt > 500) {
            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,
                   data.state,
                   data.format,
                   data.bitcount);
            init_state();
            cnt = 0;
        }
    } else {
        cnt = 0;
    }
    IRQ_ENABLE();
}

void ReceiverIR::isr_fall(void) {
    IRQ_DISABLE();
    switch (data.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, TUS_NEC * 16) && InRange(b, TUS_NEC * 8)) {
                    /*
                     * NEC.
                     */
                    data.format = NEC;
                    data.state = Receiving;
                    data.bitcount = 0;
                } else if (InRange(a, TUS_NEC * 16) && InRange(b, TUS_NEC * 4)) {
                    /*
                     * NEC Repeat.
                     */
                    data.format = NEC;
                    data.state = Received;
                    data.bitcount = 0;
                } else if (InRange(a, TUS_AEHA * 8) && InRange(b, TUS_AEHA * 4)) {
                    /*
                     * AEHA.
                     */
                    data.format = AEHA;
                    data.state = Receiving;
                    data.bitcount = 0;
                } else if (InRange(a, TUS_AEHA * 8) && InRange(b, TUS_AEHA * 8)) {
                    /*
                     * AEHA Repeat.
                     */
                    data.format = AEHA;
                    data.state = Received;
                    data.bitcount = 0;
                } else {
                    init_state();
                }
            }
            break;
        case Receiving:
            if (NEC == data.format) {
                work.d2 = timer.read_us();
                int a = work.d2 - work.d1;
                if (InRange(a, TUS_NEC * 3)) {
                    data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
                } else if (InRange(a, TUS_NEC * 1)) {
                    data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
                }
                data.bitcount++;
                if (32 <= data.bitcount) {
                    data.state = Received;
                }
            } else if (AEHA == data.format) {
                work.d2 = timer.read_us();
                int a = work.d2 - work.d1;
                if (InRange(a, TUS_AEHA * 3)) {
                    data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
                } else if (InRange(a, TUS_AEHA * 1)) {
                    data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
                }
                data.bitcount++;
                /*
                 * 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 if (SONY == data.format) {
                work.d1 = timer.read_us();
            }
            break;
        case Received:
            break;
        default:
            break;
    }
    IRQ_ENABLE();
}

void ReceiverIR::isr_rise(void) {
    IRQ_DISABLE();
    switch (data.state) {
        case Idle:
            if (0 <= work.c1) {
                work.c2 = timer.read_us();
                int a = work.c2 - work.c1;
                if (InRange(a, TUS_SONY * 4)) {
                    data.format = SONY;
                    data.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 (NEC == data.format) {
                work.d1 = timer.read_us();
            } else if (AEHA == data.format) {
                work.d1 = timer.read_us();
            } else if (SONY == data.format) {
                work.d2 = timer.read_us();
                int a = work.d2 - work.d1;
                if (InRange(a, TUS_SONY * 2)) {
                    data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
                } else if (InRange(a, TUS_SONY * 1)) {
                    data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
                }
                data.bitcount++;
                /*
                 * How do we get the correct length? (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;
                }
            }
            break;
        case Received:
            break;
        default:
            break;
    }
    IRQ_ENABLE();
}