Embedded system Fun Blog
























































Find out all the best information, libraries and circuit about the latest Embedded systems.

Sunday 8 January 2012

MBED: RemoteIR and TransmitterIR using DAC

.info: http://mbed.org/users/shintamainjp/libraries/RemoteIR/lg7h90

XxXxXxXxXxXxXxXxXxXxXxXxXxXx ReceiverIR.cpp XxXxXxXxXxXxXxXxXxXxXxXxXxXx

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

#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;
    }
}

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) {
    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;
                } else {
                    init_state();
                }
            }
            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();
            }
            break;
        case Received:
            break;
        default:
            break;
    }
    UNLOCK();
}

void ReceiverIR::isr_rise(void) {
    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();
            } 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;
        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
    if (work.state == Receiving) {
        work.state = Received;
        work.c1 = -1;
        work.c2 = -1;
        work.c3 = -1;
        work.d1 = -1;
        work.d2 = -1;
    }
    UNLOCK();
}

XxXxXxXxXxXxXxXxXxXxXxXxXxXx ReceiverIR.h XxXxXxXxXxXxXxXxXxXxXxXxXxXx

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

#ifndef _RECEIVER_IR_H_
#define _RECEIVER_IR_H_

#include <mbed.h>

#include "RemoteIR.h"

/**
 * IR receiver class.
 */
class ReceiverIR {
public:

    /**
     * Constructor.
     *
     * @param rxpin Pin for receive IR signal.
     */
    explicit ReceiverIR(PinName rxpin);
   
    /**
     * Destructor.
     */
    ~ReceiverIR();

    /**
     * State.
     */
    typedef enum {
        Idle,
        Receiving,
        Received
    } State;
   
    /**
     * Get state.
     *
     * @return Current state.
     */
    State getState();
   
    /**
     * 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 getData(RemoteIR::Format *format, uint8_t *buf, int bitlength);
   
private:
   
    typedef struct {
        RemoteIR::Format format;
        int bitcount;
        uint8_t buffer[64];
    } data_t;
   
    typedef struct {
        State state;
        int c1;
        int c2;
        int c3;
        int d1;
        int d2;
    } work_t;

    InterruptIn evt;    /**< Interrupt based input for input. */
    Timer timer;        /**< Timer for WDT. */
    Ticker ticker;      /**< Tciker for tick. */
    Timeout timeout;    /**< Timeout for tail. */

    data_t data;
    work_t work;
   
    void init_state(void);

    void isr_wdt(void);
    void isr_fall(void);
    void isr_rise(void);
   
    /**
     * ISR timeout for tail detection.
     */
    void isr_timeout(void);

};

#endif

XxXxXxXxXxXxXxXxXxXxXxXxXxXx TransmitterIR.cpp XxXxXxXxXxXxXxXxXxXxXxXxXxXx

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

#include "TransmitterIR.h"

#define LOCK()
#define UNLOCK()

/**
 * Constructor.
 *
 * @param txpin Pin for transmit IR signal.
 */
TransmitterIR::TransmitterIR(PinName txpin) : tx(txpin) {
    tx.write(0.0);
    tx.period_us(26.3);

    work.state = Idle;
    work.bitcount = 0;
    work.leader = 0;
    work.data = 0;
    work.trailer = 0;

    data.format = RemoteIR::UNKNOWN;
    data.bitlength = 0;
}

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

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

/**
 * Set data.
 *
 * @param format Format.
 * @param buf Buffer of a data.
 * @param bitlength Bit length of the data.
 *
 * @return Data bit length.
 */
int TransmitterIR::setData(RemoteIR::Format format, uint8_t *buf, int bitlength) {
    LOCK();
    if (work.state != Idle) {
        UNLOCK();
        return -1;
    }

    work.state = Leader;
    work.bitcount = 0;
    work.leader = 0;
    work.data = 0;
    work.trailer = 0;

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

    switch (format) {
        case RemoteIR::NEC:
            ticker.detach();
            ticker.attach_us(this, &TransmitterIR::tick, RemoteIR::TUS_NEC);
            break;
        case RemoteIR::AEHA:
            ticker.detach();
            ticker.attach_us(this, &TransmitterIR::tick, RemoteIR::TUS_AEHA);
            break;
        case RemoteIR::SONY:
            ticker.detach();
            ticker.attach_us(this, &TransmitterIR::tick, RemoteIR::TUS_SONY);
            break;
    }

    UNLOCK();
    return bitlength;
}

void TransmitterIR::tick(void) {
    LOCK();
    switch (work.state) {
        case Idle:
            work.bitcount = 0;
            work.leader = 0;
            work.data = 0;
            work.trailer = 0;
            break;
        case Leader:
            if (data.format == RemoteIR::NEC) {
                /*
                 * NEC.
                 */
                static const int LEADER_NEC_HEAD = 16;
                static const int LEADER_NEC_TAIL = 8;
                if (work.leader < LEADER_NEC_HEAD) {
                    tx.write(0.5);
                } else {
                    tx.write(0.0);
                }
                work.leader++;
                if ((LEADER_NEC_HEAD + LEADER_NEC_TAIL) <= work.leader) {
                    work.state = Data;
                }
            } else if (data.format == RemoteIR::AEHA) {
                /*
                 * AEHA.
                 */
                static const int LEADER_AEHA_HEAD = 8;
                static const int LEADER_AEHA_TAIL = 4;
                if (work.leader < LEADER_AEHA_HEAD) {
                    tx.write(0.5);
                } else {
                    tx.write(0.0);
                }
                work.leader++;
                if ((LEADER_AEHA_HEAD + LEADER_AEHA_TAIL) <= work.leader) {
                    work.state = Data;
                }
            } else if (data.format == RemoteIR::SONY) {
                /*
                 * SONY.
                 */
                static const int LEADER_SONY_HEAD = 4;
                static const int LEADER_SONY_TAIL = 0;
                if (work.leader < LEADER_SONY_HEAD) {
                    tx.write(0.5);
                } else {
                    tx.write(0.0);
                }
                work.leader++;
                if ((LEADER_SONY_HEAD + LEADER_SONY_TAIL) <= work.leader) {
                    work.state = Data;
                }
            } else {
            }
            break;
        case Data:
            if (data.format == RemoteIR::NEC) {
                /*
                 * NEC.
                 */
                if (work.data == 0) {
                    tx.write(0.5);
                    work.data++;
                } else {
                    tx.write(0.0);
                    if (0 != (data.buffer[work.bitcount / 8] & (1 << work.bitcount % 8))) {
                        if (3 <= work.data) {
                            work.bitcount++;
                            work.data = 0;
                        } else {
                            work.data++;
                        }
                    } else {
                        if (1 <= work.data) {
                            work.bitcount++;
                            work.data = 0;
                        } else {
                            work.data++;
                        }
                    }
                }
                if (data.bitlength <= work.bitcount) {
                    work.state = Trailer;
                }
            } else if (data.format == RemoteIR::AEHA) {
                /*
                 * AEHA.
                 */
                if (work.data == 0) {
                    tx.write(0.5);
                    work.data++;
                } else {
                    tx.write(0.0);
                    if (0 != (data.buffer[work.bitcount / 8] & (1 << work.bitcount % 8))) {
                        if (3 <= work.data) {
                            work.bitcount++;
                            work.data = 0;
                        } else {
                            work.data++;
                        }
                    } else {
                        if (1 <= work.data) {
                            work.bitcount++;
                            work.data = 0;
                        } else {
                            work.data++;
                        }
                    }
                }
                if (data.bitlength <= work.bitcount) {
                    work.state = Trailer;
                }
            } else if (data.format == RemoteIR::SONY) {
                /*
                 * SONY.
                 */
                if (work.data == 0) {
                    tx.write(0.0);
                    work.data++;
                } else {
                    tx.write(0.5);
                    if (0 != (data.buffer[work.bitcount / 8] & (1 << work.bitcount % 8))) {
                        if (2 <= work.data) {
                            work.bitcount++;
                            work.data = 0;
                        } else {
                            work.data++;
                        }
                    } else {
                        if (1 <= work.data) {
                            work.bitcount++;
                            work.data = 0;
                        } else {
                            work.data++;
                        }
                    }
                }
                if (data.bitlength <= work.bitcount) {
                    work.state = Trailer;
                }
            } else {
            }
            break;
        case Trailer:
            if (data.format == RemoteIR::NEC) {
                /*
                 * NEC.
                 */
                static const int TRAILER_NEC_HEAD = 1;
                static const int TRAILER_NEC_TAIL = 2;
                if (work.trailer < TRAILER_NEC_HEAD) {
                    tx.write(0.5);
                } else {
                    tx.write(0.0);
                }
                work.trailer++;
                if ((TRAILER_NEC_HEAD + TRAILER_NEC_TAIL) <= work.trailer) {
                    work.state = Idle;
                    //ticker.detach();
                }
            } else if (data.format == RemoteIR::AEHA) {
                /*
                 * AEHA.
                 */
                static const int TRAILER_AEHA_HEAD = 1;
                static const int TRAILER_AEHA_TAIL = 8000 / RemoteIR::TUS_AEHA;
                if (work.trailer < TRAILER_AEHA_HEAD) {
                    tx.write(0.5);
                } else {
                    tx.write(0.0);
                }
                work.trailer++;
                if ((TRAILER_AEHA_HEAD + TRAILER_AEHA_TAIL) <= work.trailer) {
                    work.state = Idle;
                    //ticker.detach();
                }
            } else if (data.format == RemoteIR::SONY) {
                /*
                 * SONY.
                 */
                static const int TRAILER_SONY_HEAD = 0;
                static const int TRAILER_SONY_TAIL = 0;
                if (work.trailer < TRAILER_SONY_HEAD) {
                    tx.write(0.5);
                } else {
                    tx.write(0.0);
                }
                work.trailer++;
                if ((TRAILER_SONY_HEAD + TRAILER_SONY_TAIL) <= work.trailer) {
                    work.state = Idle;
                    //ticker.detach();
                }
            } else {
            }
            break;
        default:
            break;
    }
    UNLOCK();
}

XxXxXxXxXxXxXxXxXxXxXxXxXxXx TransmitterIR.h XxXxXxXxXxXxXxXxXxXxXxXxXxXx

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

#ifndef _TRANSMITTER_IR_H_
#define _TRANSMITTER_IR_H_

#include <mbed.h>

#include "RemoteIR.h"

/**
 * IR transmitter class.
 */
class TransmitterIR {
public:

    /**
     * Constructor.
     *
     * @param txpin Pin for transmit IR signal.
     */
    explicit TransmitterIR(PinName txpin);

    /**
     * Destructor.
     */
    ~TransmitterIR();

    typedef enum {
        Idle,
        Leader,
        Data,
        Trailer
    } State;

    /**
     * Get state.
     *
     * @return Current state.
     */
    State getState(void);

    /**
     * Set data.
     *
     * @param format Format.
     * @param buf Buffer of a data.
     * @param bitlength Bit length of the data.
     *
     * @return Data bit length.
     */
    int setData(RemoteIR::Format format, uint8_t *buf, int bitlength);

private:

    typedef struct {
        State state;
        int bitcount;
        int leader;
        int data;
        int trailer;
    } work_t;

    typedef struct {
        RemoteIR::Format format;
        int bitlength;
        uint8_t buffer[64];
    } data_t;

    PwmOut tx;
    Ticker ticker;
    data_t data;
    work_t work;

    void tick();

};

#endif

XxXxXxXxXxXxXxXxXxXxXxXxXxXx RemoteIR.h XxXxXxXxXxXxXxXxXxXxXxXxXxXx

/**
 * IR remote common class (Version 0.0.4)
 *
 * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
 * http://shinta.main.jp/
 */

#ifndef _REMOTE_IR_H_
#define _REMOTE_IR_H_

class RemoteIR {
public:

    typedef enum {
        UNKNOWN,
        NEC,
        NEC_REPEAT,
        AEHA,
        AEHA_REPEAT,
        SONY
    } Format;

    static const int TUS_NEC = 562;
    static const int TUS_AEHA = 425;
    static const int TUS_SONY = 600;

private:
    RemoteIR();
};

#endif

XxXxXxXxXxXxXxXxXxXxXxXxXxXx EOF XxXxXxXxXxXxXxXxXxXxXxXxXxXx

No comments:

Post a Comment