IM920 (920MHz wireless module) protocol parser

Files at this revision

API Documentation at this revision

Comitter:
hideakitai
Date:
Mon Apr 11 12:41:10 2016 +0000
Commit message:
IM920 (920MHz wireless module) protocol parser

Changed in this revision

IM920.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IM920.h	Mon Apr 11 12:41:10 2016 +0000
@@ -0,0 +1,242 @@
+#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;
+};
+
+