Suga koubou / IM920

Dependents:   IM920_sample IM920_SDlog IM920_sample IM920_sample3 ... more

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Fri Dec 26 15:35:20 2014 +0000
Child:
1:81b2fd407327
Commit message:
1st tiny build.;

Changed in this revision

CBuffer.h Show annotated file Show diff for this revision Revisions of this file
IM920.cpp Show annotated file Show diff for this revision Revisions of this file
IM920.h Show annotated file Show diff for this revision Revisions of this file
IM920_cmd.cpp Show annotated file Show diff for this revision Revisions of this file
IM920_conf.h Show annotated file Show diff for this revision Revisions of this file
IM920_hal.cpp Show annotated file Show diff for this revision Revisions of this file
IM920_msg.cpp Show annotated file Show diff for this revision Revisions of this file
IM920_util.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CBuffer.h	Fri Dec 26 15:35:20 2014 +0000
@@ -0,0 +1,82 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CIRCBUFFER_H_
+#define CIRCBUFFER_H_
+
+template <class T>
+class CircBuffer {
+public:
+    CircBuffer(int length, void *addr = NULL) {
+        write = 0;
+        read = 0;
+        size = length + 1;
+        if (addr) {
+            buf = (T *)addr;
+        } else {
+            buf = (T *)malloc(size * sizeof(T));
+        }
+        if (buf == NULL)
+            error("Can't allocate memory");
+    };
+
+    bool isFull() {
+        return (((write + 1) % size) == read);
+    };
+
+    bool isEmpty() {
+        return (read == write);
+    };
+
+    void queue(T k) {
+        if (isFull()) {
+//            read++;
+//            read %= size;
+            return;
+        }
+        buf[write++] = k;
+        write %= size;
+    }
+    
+    void flush() {
+        read = 0;
+        write = 0;
+    }
+    
+
+    uint32_t available() {
+        return (write >= read) ? write - read : size - read + write;
+    };
+
+    bool dequeue(T * c) {
+        bool empty = isEmpty();
+        if (!empty) {
+            *c = buf[read++];
+            read %= size;
+        }
+        return(!empty);
+    };
+
+private:
+    volatile uint32_t write;
+    volatile uint32_t read;
+    uint32_t size;
+    T * buf;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IM920.cpp	Fri Dec 26 15:35:20 2014 +0000
@@ -0,0 +1,54 @@
+#include "IM920.h"
+
+IM920::IM920 (PinName tx, PinName rx, PinName busy, PinName reset, int baud) : _im(tx, rx) {
+
+    memset(&_state, 0, sizeof(_state));
+    _state.data = new CircBuffer<char>(CFG_DATA_SIZE);
+
+    initUart(busy, reset, baud);
+    setReset(true);
+    wait_ms(100);
+    setReset(false);
+}
+
+int IM920::init (int node, void(*func)()) {
+
+    _state.node = node;
+    _state.func = func;
+
+    cmdRDID();
+    cmdSTNN(_state.node);
+    cmdSTPO(3);  // 10dBm
+    cmdSTRT(2);  // 1.25kbps
+    return 0;
+}
+
+void IM920::poll () {
+
+    if (_state.received && _state.buf != NULL)
+      if (_state.func != NULL && !_state.data->isEmpty()) {
+        _state.func();
+        if (_state.data->isEmpty()) {
+            _state.received = false;
+        }
+    }
+}
+
+int IM920::send (char *buf, int len) {
+
+    if (len > 64) len = 64;
+
+    return sendData(buf, len);
+}
+
+int IM920::recv (char *buf, int len) {
+    int i;
+
+    if (_state.data == NULL) return 0;
+    while (!_state.received && _state.mode != MODE_COMMAND);
+    _state.received = false;
+    for (i = 0; i < len; i ++) {
+        if (_state.data->dequeue(&buf[i]) == false) break;
+    }
+    return i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IM920.h	Fri Dec 26 15:35:20 2014 +0000
@@ -0,0 +1,126 @@
+#ifndef _IM920_h_
+#define _IM920_h_
+
+#include "IM920_conf.h"
+
+#include "mbed.h"
+#include "CBuffer.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+//Debug is disabled by default
+#if defined(DEBUG) and (!defined(TARGET_LPC11U24))
+#define DBG(x, ...) std::printf("[DBG]" x "\r\n", ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WARN]" x "\r\n", ##__VA_ARGS__);
+#define ERR(x, ...) std::printf("[ERR]" x "\r\n", ##__VA_ARGS__);
+#define INFO(x, ...) std::printf("[INFO]" x "\r\n", ##__VA_ARGS__);
+#else
+#define DBG(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#define INFO(x, ...)
+#endif
+
+class IM920 {
+public:
+    enum Response {
+        RES_NULL,
+        RES_RDID,
+        RES_RDNN,
+        RES_RDRS,
+    };
+
+    enum Mode {
+        MODE_COMMAND,
+        MODE_DATA_RX,
+    };
+
+    enum Status {
+        STAT_NONE,
+        STAT_SLEEP,
+    };
+
+    IM920 (PinName tx, PinName rx, PinName busy = NC, PinName reset = NC, int baud = IM920_BAUD);
+
+    int init (int node, void(*func)() = NULL);
+
+    void poll ();
+
+    int send (char *buf, int len);
+    int recv (char *buf, int len);
+
+    int setCh (int ch);
+    int getRssi ();
+    int sleep ();
+    int wakeup ();
+
+    // ----- GSwifi_cmd.cpp -----
+    int sendCommand(const char * cmd, Response res = RES_NULL, int timeout = DEFAULT_WAIT_RESP_TIMEOUT);
+    int sendData(const char * data, int len, int timeout = CFG_TIMEOUT);
+
+private:
+    RawSerial _im;
+    DigitalIn *_busy;
+    DigitalOut *_reset;
+    int _baud;
+
+    struct STATE {
+        int id, node, rssi;
+
+        time_t time;
+        bool initialized;
+        volatile Mode mode;
+        volatile Status status;
+        volatile bool ok, failure;
+        volatile Response res;
+        int n;
+        char buf[CFG_BUF_SIZE];
+
+        CircBuffer<char> *data;
+        volatile bool received;
+        void(*func)();
+    } _state;
+
+    // ----- GSwifi_util.cpp -----
+    int x2i (char c);
+    char i2x (int i);
+
+    // ----- GSwifi_msg.cpp -----
+    void recvData (char c);
+    int parseMessage ();
+    void msgOk (const char*);
+    void msgError (const char*);
+    void msgConnect (const char*);
+    void resRDID (const char *buf);
+    void resRDNN (const char *buf);
+    void resRDRS (const char *buf);
+
+    // ----- GSwifi_cmd.cpp -----
+    void clearFlags ();
+    int cmdENWR ();
+    int cmdDSWR ();
+    int cmdRDID ();
+    int cmdSTNN (int n);
+    int cmdRDNN ();
+    int cmdSRID (int n);
+    int cmdERID ();
+    int cmdSTCH (int n);
+    int cmdRDRS ();
+    int cmdSTPO (int n);
+    int cmdSTRT (int n);
+    int cmdSBRT (int n);
+    int cmdDSRX ();
+    int cmdENRX ();
+
+    // ----- GSwifi_hal.cpp -----
+    void setReset (bool flg);
+    void isrUart ();
+    int getUart ();
+    void putUart (char c);
+    int lockUart (int ms);
+    void unlockUart ();
+    void initUart (PinName busy, PinName reset, int baud);
+ };
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IM920_cmd.cpp	Fri Dec 26 15:35:20 2014 +0000
@@ -0,0 +1,146 @@
+#include "IM920.h"
+
+void IM920::clearFlags () {
+    _state.ok = false;
+    _state.failure = false;
+    _state.res = RES_NULL;
+    _state.n = 0;
+}
+
+int IM920::sendCommand (const char * cmd, Response res, int timeout) {
+    int i;
+    Timer t;
+
+    if (lockUart(timeout)) return -1;
+
+    clearFlags();
+    _state.res = res;
+    for (i = 0; i < strlen(cmd); i ++) {
+        putUart(cmd[i]);
+    }
+    putUart('\r');
+    putUart('\n');
+    unlockUart();
+    INFO("command: '%s'\r\n", cmd);
+
+    if (timeout) {
+        t.start();
+        for (;;) {
+            if (_state.ok && _state.res == RES_NULL) break;
+            if (_state.failure || t.read_ms() > timeout) {
+                WARN("failure or timeout\r\n");
+                _state.res = RES_NULL;
+                return -1;
+            }
+        }
+        t.stop();
+    }
+    INFO("ok\r\n");
+    _state.res = RES_NULL;
+
+    return 0;
+}
+
+int IM920::sendData(const char * data, int len, int timeout) {
+    int i;
+    Timer t;
+
+    if (lockUart(timeout)) return -1;
+
+    clearFlags();
+    putUart('T');
+    putUart('X');
+    putUart('D');
+    putUart('A');
+    putUart(' ');
+    for (i = 0; i < len; i ++) {
+        putUart(i2x((data[i]>>4) & 0x0f));
+        putUart(i2x(data[i] & 0x0f));
+    }
+    putUart('\r');
+    putUart('\n');
+    unlockUart();
+    INFO("data: TXDA %d\r\n", len);
+
+    if (timeout) {
+        t.start();
+        for (;;) {
+            if (_state.ok) break;
+            if (_state.failure || t.read_ms() > timeout) {
+                WARN("failure or timeout\r\n");
+                return -1;
+            }
+        }
+        t.stop();
+    }
+
+    return i;
+}
+
+int IM920::cmdENWR () {
+    return sendCommand("ENWR");
+}
+
+int IM920::cmdDSWR () {
+    return sendCommand("DSWR");
+}
+
+int IM920::cmdRDID () {
+    return sendCommand("RDID", RES_RDID);
+}
+
+int IM920::cmdSTNN (int n) {
+    char cmd[CFG_CMD_SIZE];
+    sprintf(cmd, "STNN %02X", n);
+    return sendCommand(cmd);
+}
+
+int IM920::cmdRDNN () {
+    return sendCommand("RDNN", RES_RDNN);
+}
+
+int IM920::cmdSRID (int n) {
+    char cmd[CFG_CMD_SIZE];
+    sprintf(cmd, "SRID %04X", n);
+    return sendCommand(cmd);
+}
+
+int IM920::cmdERID () {
+    return sendCommand("ERID");
+}
+
+int IM920::cmdSTCH (int n) {
+    char cmd[CFG_CMD_SIZE];
+    sprintf(cmd, "STCH %02d", n);
+    return sendCommand(cmd);
+}
+
+int IM920::cmdRDRS () {
+    return sendCommand("RDRS", RES_RDRS);
+}
+
+int IM920::cmdSTPO (int n) {
+    char cmd[CFG_CMD_SIZE];
+    sprintf(cmd, "STPO %d", n);
+    return sendCommand(cmd);
+}
+
+int IM920::cmdSTRT (int n) {
+    char cmd[CFG_CMD_SIZE];
+    sprintf(cmd, "STRT %d", n);
+    return sendCommand(cmd);
+}
+
+int IM920::cmdSBRT (int n) {
+    char cmd[CFG_CMD_SIZE];
+    sprintf(cmd, "SBRT %d", n);
+    return sendCommand(cmd);
+}
+
+int IM920::cmdDSRX () {
+    return sendCommand("DSRX");
+}
+
+int IM920::cmdENRX () {
+    return sendCommand("ENRX");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IM920_conf.h	Fri Dec 26 15:35:20 2014 +0000
@@ -0,0 +1,16 @@
+#ifndef _IM920_conf_h_
+#define _IM920_conf_h_
+
+#define DEBUG
+#define DEBUG_DUMP
+
+#define IM920_BAUD 19200
+
+#define CFG_BUF_SIZE 150
+#define CFG_DATA_SIZE 64
+#define CFG_CMD_SIZE 16
+
+#define DEFAULT_WAIT_RESP_TIMEOUT 500
+#define CFG_TIMEOUT 5000
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IM920_hal.cpp	Fri Dec 26 15:35:20 2014 +0000
@@ -0,0 +1,57 @@
+#include "IM920.h"
+
+void IM920::setReset (bool flg) {
+    if (_reset) {
+        if (flg) {
+            _reset->write(0);
+        } else {
+            _reset->write(1);
+        }
+    }
+}
+
+void IM920::isrUart () {
+    recvData(getUart());
+}
+
+int IM920::getUart () {
+    return _im.getc();
+}
+
+void IM920::putUart (char c) {
+    _im.putc(c);
+}
+
+int IM920::lockUart (int ms) {
+    Timer t;
+
+    if (_busy && _busy->read()) {
+        // CTS check
+        t.start();
+        while (_busy->read()) {
+            if (t.read_ms() >= ms) {
+                DBG("cts timeout\r\n");
+                return -1;
+            }
+        }
+    }
+    return 0;
+}
+
+void IM920::unlockUart () {
+}
+
+void IM920::initUart (PinName busy, PinName reset, int baud) {
+    _baud = baud;
+    if (_baud) _im.baud(_baud);
+    _im.attach(this, &IM920::isrUart, Serial::RxIrq);
+
+    _busy = NULL;
+    _reset = NULL;
+    if (busy != NC) {
+        _busy = new DigitalIn(busy);
+    }
+    if (reset != NC) {
+        _reset = new DigitalOut(reset);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IM920_msg.cpp	Fri Dec 26 15:35:20 2014 +0000
@@ -0,0 +1,136 @@
+#include "IM920.h"
+
+void IM920::recvData (char c) {
+    static int sub, len, count;
+    static char chr;
+
+#ifdef DEBUG_DUMP
+    if (c < 0x20 || c >= 0x7f) {
+        std::printf("_%02x", c);
+    } else {
+        std::printf("_%c", c);
+    }
+#endif
+    switch (_state.mode) {
+    case MODE_COMMAND:
+        switch (c) {
+        case 0:
+        case 0x0a: // LF
+        case 0x0d: // CR
+            _state.buf[len] = 0;
+            len = 0;
+            parseMessage();
+            break;
+        case ':':
+            if (_state.buf[2] == ',' && _state.buf[7] == ',' && len == 10) {
+                sub = 0;
+                _state.mode = MODE_DATA_RX;
+                break;
+            }
+            /* FALLTHROUGH */
+        default:
+            if (len < sizeof(_state.buf) - 1) {
+                _state.buf[len] = c;
+            }
+            len ++;
+            break;
+        }
+        break;
+
+    case MODE_DATA_RX:
+        if (c == '\r' || c == '\n') {
+            DBG("recv %d/%d\r\n", count, len);
+            _state.received = true;
+            _state.mode = MODE_COMMAND;
+            len = 0;
+            break;
+        }
+        switch (sub) {
+        case 0:
+            chr = x2i(c) << 4;
+            sub ++;
+            break;
+        case 1:
+            chr |= x2i(c);
+            sub ++;
+            if (_state.data!= NULL) {
+                _state.data->queue(chr);
+                if (_state.func != NULL && _state.data->available() >= CFG_DATA_SIZE) {
+                    _state.received = true;
+                    WARN("buf full");
+                }
+            }
+            count ++;
+            break;
+        case 2:
+            if (c == ',') {
+                sub = 0;
+            }
+            break;
+        }
+    }
+}
+
+#define RES_TABLE_NUM 4
+int IM920::parseMessage () {
+    int i;
+    static const struct RES_TABLE {
+        const Response res;
+        void (IM920::*func)(const char*);
+    } res_table[RES_TABLE_NUM] = {
+      {RES_NULL,        NULL},
+      {RES_RDID,        &IM920::resRDID},
+      {RES_RDNN,        &IM920::resRDNN},
+      {RES_RDRS,        &IM920::resRDRS},
+    };
+
+    if (_state.res != RES_NULL) {
+      for (i = 0; i < RES_TABLE_NUM; i ++) {
+        if (res_table[i].res == _state.res) {
+            DBG("parse res %d '%s'\r\n", i, _state.buf);
+            if (res_table[i].func != NULL) {
+                (this->*(res_table[i].func))(_state.buf);
+            }
+        }
+      }
+    }
+
+    if (strncmp(_state.buf, "OK", 2) == 0) {
+        _state.ok = true;
+        if (_state.status == STAT_SLEEP) {
+            _state.status = STAT_NONE;
+        }
+        return 0;
+    } else
+    if (strncmp(_state.buf, "NG", 2) == 0) {
+        _state.failure = true;
+        return 0;
+    }
+
+    return -1;
+}
+
+void IM920::resRDID (const char *buf) {
+
+    if (buf[0] < '0' || buf[0] > 'F') return;
+
+    _state.id = strtol(buf, NULL, 16);
+    _state.res = RES_NULL;
+}
+
+void IM920::resRDNN (const char *buf) {
+
+    if (buf[0] < '0' || buf[0] > 'F') return;
+
+    _state.node = strtol(buf, NULL, 16);
+    _state.res = RES_NULL;
+}
+
+void IM920::resRDRS (const char *buf) {
+
+    if (buf[0] < '0' || buf[0] > 'F') return;
+
+    _state.rssi = strtol(buf, NULL, 16);
+    _state.res = RES_NULL;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IM920_util.cpp	Fri Dec 26 15:35:20 2014 +0000
@@ -0,0 +1,50 @@
+#include "IM920.h"
+
+int IM920::setCh (int ch) {
+    if (ch < 1 || ch > 15) return false;
+    return cmdSTCH(ch);
+}
+
+int IM920::getRssi () {
+    cmdRDRS();
+    return _state.rssi;
+}
+
+int IM920::sleep () {
+    if (_state.status != STAT_NONE) return -1;
+
+    _state.status = STAT_SLEEP;
+    return cmdDSRX();
+}
+
+int IM920::wakeup () {
+    if (_state.status != STAT_SLEEP) return -1;
+
+    putUart('\r');
+    putUart('\n');
+    return cmdENRX();
+}
+
+
+int IM920::x2i (char c) {
+    if (c >= '0' && c <= '9') {
+        return c - '0';
+    } else
+    if (c >= 'A' && c <= 'F') {
+        return c - 'A' + 10;
+    } else
+    if (c >= 'a' && c <= 'f') {
+        return c - 'a' + 10;
+    }
+    return 0;
+}
+
+char IM920::i2x (int i) {
+    if (i >= 0 && i <= 9) {
+        return i + '0';
+    } else
+    if (i >= 10 && i <= 15) {
+        return i - 10 + 'A';
+    }
+    return 0;
+}