IM920 (920MHz wireless module) protocol parser

IM920.h

Committer:
hideakitai
Date:
2016-04-11
Revision:
0:ee7d2910f5ea

File content as of revision 0:ee7d2910f5ea:

#pragma once
#include "mbed.h"
#include <queue>

    #define kAsciiCR    0x0D
    #define kAsciiLF    0x0A
    
class IM920 : public Serial
{
    typedef enum StateIm920 {
        kStateNode = 0,
        kStateParentId,
        kStateRssi,
        kStateData,
        kStateCRLF
    } StateIm920;
    
    typedef struct Im920Packet {
        int node;
        int parent_id;
        int rssi;
        int data[8];
    } Im920Packet;
    
    typedef struct Im920PacketAscii {
        char node[3];
        char parent_id[5];
        char rssi[3];
        char data[8][3];
    } Im920PacketAscii;

public:

    IM920(PinName tx, PinName rx, int baudrate)
    : mbed::Serial(tx, rx)
    , pc(NULL)
    {
        this->baud(baudrate);
        this->attach(this, &IM920::push_byte);
    }
    virtual ~IM920()
    {
        if (pc) delete pc;
    }
    
    void push_byte() { byte_buff.push(this->getc()); }
    void pop_byte() { byte_buff.pop(); }
    
    void pop() { readBuffer_.pop(); }
    
    int  available()      { return (int)readBuffer_.size(); }
    
    void dump()
    {
        while(byte_buff.size())
        {
            if(pc) pc->printf("%c", (char)byte_buff.front());
            byte_buff.pop();
        }
    }

    virtual void setDebugSerial(Serial* s) { pc = s; }
    
    void send(const char* format) 
    { this->Serial::printf(format); }
    template <typename A>
    void send(const char* format, A &a) 
    { this->Serial::printf(format, a); }
    template <typename A, typename B>
    void send(const char* format, A &a, B &b) 
    { this->Serial::printf(format, a, b); }
    template <typename A, typename B, typename C>
    void send(const char* format, A &a, B &b, C &c) 
    { this->Serial::printf(format, a, b, c); }
    
    const Im920Packet& getPacket() { return readBuffer_.front(); }
    const int&  getNwNode()      { return readBuffer_.front().node; }
    const int&  getNwParentId()  { return readBuffer_.front().parent_id; }
    const int&  getNwRssi()      { return readBuffer_.front().rssi; }
    const int* getDataPtr()     { return (int*)readBuffer_.front().data; }
    uint8_t  getData(int idx) { return readBuffer_.front().data[idx]; }
    
    void enableWriteFlash() { send("ENWR\r\n"); }
    void disableWriteFlash() { send("DSWR\r\n"); }
    void deleteParentId() { send("ERID\r\n"); }
    void writeParentId(int id) { send("SRID %04x\r\n", id); }
    void requestParentId() { send("RRID\r\n"); }
    void writeWirelessPower(int n) { send("STPO %1d\r\n", n); }
    void writeWirelessSpeed(int n) { send("STRT %1d\r\n", n); }
    void writeBaudrate(int n) { send("SBRT %1d\r\n", n); }
    void writeChannel(int n) { send("STCH %02d\r\n", n); }
    void reset() { send("SRST\r\n"); }
    
    void dumpPacket()
    {
        if(available())
        {
            if(pc)
            {
                Im920Packet& p = readBuffer_.front();
                pc->printf("packet dump >> %02x,%04x,%02x:", p.node, p.parent_id, p.rssi);
                for (int i=0; i<7; i++) pc->printf("%02x,", p.data[i]);
                pc->printf("%02x\r\n", p.data[7]);
            }
            readBuffer_.pop();
        }
        else
            if(pc) pc->printf("[Error] No Packet Available!!\n");
    }
    
    void parse()
    {
        if (byte_buff.size() <= 0)  return;

        static bool bUnderParsing = false;
        static int cnt = 0;
        static int dcnt = 0;
        static Im920PacketAscii pa;
        static StateIm920 state = kStateNode;

        while (byte_buff.size() > 0)
        {
            char data = (char)byte_buff.front();
            
            if (isCorrupted((int)data)) {
                state = kStateNode;
                bUnderParsing = false;
                return;
            }
            
            if (!bUnderParsing)
            {
                for (int i=0; i<5; i++) pa.parent_id[i] = (char)0;
                for (int i=0; i<3; i++) {
                    pa.node[i] = pa.rssi[i] = (char)0;
                    for (int j=0; j<8; j++) pa.data[j][i] = (char)0;
                }
                dcnt = cnt = 0;
                bUnderParsing = true;
            }

            switch(state)
            {
                case kStateNode:
                {
                    if (data == ',') {
                        state = kStateParentId;
                        dcnt = cnt = 0;
                    } else {
                        pa.node[cnt++] = data;
                    }
                    break;
                }
                case kStateParentId:
                {
                    if (data == ',') {
                        state = kStateRssi;
                        dcnt = cnt = 0;
                    } else {
                        pa.parent_id[cnt++] = data;
                    }
                    break;
                }
                case kStateRssi:
                {
                    if (data == ':') {
                        state = kStateData;
                        dcnt = cnt = 0;
                    } else {
                        pa.rssi[cnt++] = data;
                    }
                    break;
                }
                case kStateData:
                {
                    if (data == ',') {
                        ++dcnt;
                        cnt = 0;
                    } else if (data == (char)kAsciiCR) {
                        state = kStateCRLF;
                    } else {
                        pa.data[dcnt][cnt++] = data;
                    }
                    break;
                }
                case kStateCRLF:
                {
                    if (data == (char)kAsciiLF)
                    {
                        Im920Packet p;
                        p.node = (int)strtol(pa.node, NULL, 16);
                        p.parent_id = (int)strtol(pa.parent_id, NULL, 16);
                        p.rssi = (int)strtol(pa.rssi, NULL, 16);
                        for (int i = 0; i < 8; i++) {
                            p.data[i] = (int)strtol(pa.data[i], NULL, 16);
                        }
                        readBuffer_.push(p);
//        std::queue<int>().swap(q)
                    }
                    else
                    {
                        if(pc) pc->printf("invalid data order!!!\n");
                    }
                    state = kStateNode;
                    bUnderParsing = false;
                    dcnt = cnt = 0;
                    
                    break;
                }
                default:
                {
                    state = kStateNode;
                    bUnderParsing = false;
                    dcnt = cnt = 0;
                    break;
                }
            }
            pop_byte();
        }
    }    

    
private:
    bool isCorrupted(int ascii)
    {
        bool isCRLF = ((ascii == 13) || (ascii == 10)) ? true : false;
        bool isPunctuation = ((ascii == 44) || (ascii == 58)) ? true : false;
        bool is0to9 = ((ascii >= 48) && (ascii <= 57)) ? true : false;
        bool isAtoF = ((ascii >= 65) && (ascii <= 70)) ? true : false;
        if (!(isCRLF || isPunctuation || is0to9 || isAtoF)) {
            if(pc) pc->printf("Invalid Ascii!\r\n");
            return true;
        }
        return false;
    }
    
    queue<uint8_t> byte_buff;
    queue<Im920Packet> readBuffer_;
    Serial* pc;
};