The wait in mci_WaitForEvent will delay all card transactions.

Dependencies:   FATFileSystem

Fork of EALib by EmbeddedArtists AB

Revision:
7:e431d9d47db6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XBee.cpp	Mon Nov 11 09:39:58 2013 +0000
@@ -0,0 +1,751 @@
+
+#include "mbed.h"
+#include "mbed_debug.h"
+#include "XBee.h"
+
+#define XBEE_END_CMD ("\r")
+#define CR (0x0D)
+#define RESP_OK ("OK")
+
+#define XBEE_START_DEL (0x7E)
+
+#define XBEE_API_ID_TX_64    (0x00)
+#define XBEE_API_ID_AT_CMD   (0x08)
+#define XBEE_API_ID_AT_RESP  (0x88)
+#define XBEE_API_ID_TX_STAT  (0x89)
+#define XBEE_API_ID_RX_64    (0x80)
+#define XBEE_API_ID_RX_16    (0x81)
+#define XBEE_API_ID_MOD_STAT (0x8A)
+
+#define XBEE_MOD_STAT_HW_RESET    (0)
+#define XBEE_MOD_STAT_WD_RESET    (1)
+#define XBEE_MOD_STAT_ASSOC       (2)
+#define XBEE_MOD_STAT_DIASSOC     (3)
+#define XBEE_MOD_STAT_SYNC_LOST   (4)
+#define XBEE_MOD_STAT_COORD_REALG (5)
+#define XBEE_MOD_STAT_COORD_START (6)
+
+#define XBEE_TX_STAT_SUCCESS  (0)
+#define XBEE_TX_STAT_NOACK    (1)
+#define XBEE_TX_STAT_CCA_FAIL (2)
+#define XBEE_TX_STAT_PURGED   (3)
+
+#define XBEE_RECV_FRAME_TO (2000)
+
+XBee::XBee(PinName tx, PinName rx, PinName reset, PinName sleep) :
+    _serial(tx, rx), _reset(reset), _sleep(sleep) {
+    _serial.baud(9600);
+    _serial.format(8, Serial::None, 1);
+
+    _serial.attach(this, &XBee::uartRxIrq, Serial::RxIrq);
+
+    rxqIn = 0;
+    rxqOut = 0;
+    _rfFrameTimeout = 0;
+    _rfFrameTimer.reset();
+
+    _rfState = RfStateFrame;
+    _rfPos = 0;
+    _rfFrameLen = 0;
+    _rfFrameId = 0;
+
+    _initialized = false;
+    _type = Coordinator;
+
+    _addrHi = 0;
+    _addrLo = 0;
+    _rssi = 0;
+    _frameId = 0;
+    _txStatus = TxStatusOk;
+    _recvData = NULL;
+    _recvLen = 0;
+
+    // we enter sleep when sleep pin is high
+    _sleep = 0;
+}
+
+XBee::XBeeError XBee::init(XBeeType type, const char* panId) {
+    XBeeError err = Ok;
+    char idBuf[10];
+
+    resetModule();
+
+   _type = type;
+
+    do {
+
+        if (panId == NULL || strlen(panId) != 4) {
+            err = ArgumentError;
+            break;
+        }
+
+        err = commandMode();
+        if (err != Ok) {
+            debug("XBee: +++ failed\n");
+            break;
+        }
+
+        // set the sleep mode to Hibernate
+        err = atSet("ATSM1");
+        if (err != Ok) {
+            debug("Xbee: ATSM1 failed\r\n");
+            break;
+        }
+
+        // change PAN ID to EAEA
+        sprintf(idBuf, "ATID%s", panId);
+        err = atSet(idBuf);
+        if (err != Ok) {
+            debug("Xbee: ATID failed\r\n");
+            break;
+        }
+
+        // use 64-bit addressing
+        err = atSet("ATMYFFFE");
+        if (err != Ok) {
+            debug("Xbee: ATMYFFFE failed\r\n");
+            break;
+        }
+
+        // Coordinator
+        if (type == Coordinator) {
+
+            // - will not perform Active Scan to locate PAN ID
+            // - will not perform Energy Scan to determine free channel
+            // - allow End devices to associate with this coordinator
+            err = atSet("ATA24");
+            if (err != Ok) {
+                debug("Xbee: ATA24 failed\r\n");
+                break;
+            }
+
+            // set this node as coordinator
+            err = atSet("ATCE1");
+            if (err != Ok) {
+                debug("Xbee: ATCE1 failed\r\n");
+                break;
+            }
+        }
+        else {
+            // - only associates with Coordinator on matching PAN ID
+            // - only associates with Coordinator on matching channel
+            // - device attempts association until success
+            err = atSet("ATA14");
+            if (err != Ok) {
+                debug("Xbee: ATA14 failed\r\n");
+                break;
+            }
+        }
+
+
+        // change to API mode
+        err = atSet("ATAP1");
+        if (err != Ok) {
+            debug("Xbee: ATAP1 failed\r\n");
+            break;
+        }
+
+    } while(0);
+
+
+    return err;
+}
+
+void XBee::process() {
+    uint32_t len = 0;
+    char data = 0;
+
+    if (_rfFrameTimeout > 0 && (int)_rfFrameTimeout < _rfFrameTimer.read_ms()) {
+        _rfState = RfStateFrame;
+        debug("Xbee: Frame timer expired\r\n");
+        _rfFrameTimeout = 0;
+        _rfFrameTimer.stop();
+    }
+
+    if (!uartRxQIsEmpty()) {
+
+        len = uartReceive(&data, 1);
+        if (len > 0) {
+            processByte(data);
+        }
+
+    }
+}
+
+XBee::XBeeError XBee::getRemoteAddress(uint32_t* addrHi, uint32_t* addrLo) {
+    if (!_initialized) {
+        return NotInitializedError;
+    }
+
+    if (addrHi == NULL || addrLo == NULL) {
+        return ArgumentError;
+    }
+
+    *addrHi = _addrHi;
+    *addrLo = _addrLo;
+
+    return Ok;
+}
+
+XBee::XBeeError XBee::getRssi(uint8_t* rssi ) {
+    if (!_initialized) {
+        return NotInitializedError;
+    }
+
+    if (rssi == NULL) {
+        return ArgumentError;
+    }
+
+    *rssi = _rssi;
+
+    return Ok;
+}
+
+XBee::XBeeError XBee::getTxStatus(uint8_t* frameId, XBeeTxStatus* status) {
+    if (!_initialized) {
+        return NotInitializedError;
+    }
+
+    if (frameId == NULL || status == NULL) {
+        return ArgumentError;
+    }
+
+    *frameId = _frameId;
+    *status = _txStatus;
+
+    return Ok;
+}
+
+XBee::XBeeError XBee::getData(char** data, uint8_t* len) {
+    if (!_initialized) {
+        return NotInitializedError;
+    }
+
+    if (data == NULL || len == NULL) {
+        return ArgumentError;
+    }
+
+    *data = _recvData;
+    *len = _recvLen;
+
+    return Ok;
+}
+
+XBee::XBeeError XBee::send(uint32_t addrHi, uint32_t addrLo, char* data,
+    uint8_t len, uint8_t* frameId)
+{
+  if (!_initialized) {
+    return NotInitializedError;
+  }
+
+  return apiTx64(addrHi, addrLo, data, len, frameId);
+}
+
+XBee::XBeeError XBee::discoverNodes() {
+    if (!_initialized) {
+      return NotInitializedError;
+    }
+
+    return apiAtCmd("ND", 0, false);
+}
+
+
+XBee::XBeeError XBee::enterSleep() {
+    _sleep = 1;
+
+    return Ok;
+}
+
+XBee::XBeeError XBee::exitSleep() {
+    _sleep = 0;
+
+    return Ok;
+}
+
+
+void XBee::uartRxIrq() {
+    while(_serial.readable()) {
+        uartRxQPut(_serial.getc());
+    }
+}
+
+void XBee::uartRxQPut(uint8_t data)
+{
+  // full
+  if (rxqOut == (rxqIn + 1) % RX_BUF_SIZE) {
+    return;
+  }
+
+  rxq[rxqIn] = data;
+  rxqIn = (rxqIn + 1) % RX_BUF_SIZE;
+}
+
+uint8_t XBee::uartRxQGet()
+{
+  uint8_t d = 0;
+  // empty
+  if (rxqIn == rxqOut) {
+    return 0;
+  }
+
+  d = rxq[rxqOut];
+  rxqOut = (rxqOut + 1) % RX_BUF_SIZE;
+
+  return d;
+}
+
+bool XBee::uartRxQIsEmpty()
+{
+  return (rxqIn == rxqOut);
+}
+
+uint32_t XBee::uartReceive(char *buf, uint32_t buflen)
+{
+
+  uint32_t pos = 0;
+
+  while(buflen > 0 && !uartRxQIsEmpty()) {
+    buf[pos] = uartRxQGet();
+    pos++;
+    buflen--;
+  }
+
+  return pos;
+}
+
+int32_t XBee::uartReadLine(char* buf, uint32_t bufLen, uint32_t timeout)
+{
+  uint32_t pos = 0;
+  uint32_t len = 0;
+  Timer tim;
+
+  tim.reset();
+  tim.start();
+
+  while(pos < bufLen && tim.read_ms() < (int)timeout) {
+
+    len = uartReceive(&buf[pos], 1);
+    if (len > 0 && buf[pos] == CR) {
+      buf[pos] = '\0';
+      break;
+    }
+
+    pos += len;
+  }
+
+  if (pos >= bufLen) {
+    return BufTooSmallError;
+  }
+
+  if (tim.read_ms() > (int)timeout) {
+    return TimeOutError;
+  }
+
+  return pos;
+}
+
+void XBee::resetModule() {
+    // reset pulse must be at least 200 ns. Using 1 ms.
+    _reset = 0;
+    wait_ms(1);
+    _reset = 1;
+
+    // wait to make sure the module has started
+    wait_ms(500);
+    rxqIn = 0;
+    rxqOut = 0;
+}
+
+XBee::XBeeError XBee::commandMode() {
+    XBeeError err = Ok;
+    int32_t lineLen = 0;
+    char ebuf[10];
+
+    _serial.printf("+++");
+
+    lineLen = uartReadLine(ebuf, 10, 1200);
+
+    do {
+      if (lineLen < 0) {
+        // error while reading
+        err = ReadError;
+        break;
+      }
+
+      if (strcmp(RESP_OK, (char*)ebuf) != 0) {
+        // didn't receive OK
+        err = CmdError;
+        break;
+      }
+    } while(0);
+
+    return err;
+}
+
+XBee::XBeeError XBee::atGet(const char* atCmd, char* resp, uint32_t respLen)
+{
+
+    int32_t lineLen = 0;
+    XBeeError err = Ok;
+
+    _serial.printf("%s%s", atCmd, XBEE_END_CMD);
+
+    do {
+
+      // a response is expected
+      if (resp != NULL && respLen > 0) {
+        lineLen = uartReadLine(resp, respLen, 1000);
+
+        if (lineLen < 0) {
+          // error while reading
+          err = ReadError;
+          break;
+        }
+
+      }
+
+    } while(0);
+
+    return err;
+}
+
+XBee::XBeeError XBee::atSet(const char* atCmd)
+{
+  char b[10];
+  XBeeError err = Ok;
+
+  err = atGet(atCmd, b, 10);
+  if (err == Ok) {
+
+    if (strcmp(RESP_OK, (char*)b) != 0) {
+      // didn't receive OK
+      err = CmdError;
+    }
+  }
+
+  return err;
+}
+
+void XBee::processByte(char data)
+{
+    switch(_rfState) {
+    case RfStateFrame:
+        if (data == XBEE_START_DEL) {
+            _rfPos = 0;
+            _rfFrameLen = 0;
+            _rfState = RfStateLength;
+
+            // start timer to make sure an entire frame is received
+            // within a specific time
+            _rfFrameTimeout = XBEE_RECV_FRAME_TO;
+            _rfFrameTimer.reset();
+            _rfFrameTimer.start();
+        }
+
+        break;
+    case RfStateLength:
+        _rfFrameLen |= (data << (8*(1-_rfPos)));
+        _rfPos++;
+        if (_rfPos == 2) {
+            _rfPos = 0;
+            _rfState = RfStateData;
+
+            if (_rfFrameLen > XBEE_BUF_SZ) {
+                debug("Xbee: Frame len %d > max buffer len %d\r\n",
+                        (int)_rfFrameLen, (int)XBEE_BUF_SZ);
+                _rfFrameLen = XBEE_BUF_SZ;
+            }
+
+        }
+        break;
+    case RfStateData:
+        _rfBuf[_rfPos++] = data;
+        // read up until checksum (1 byte)
+        if (_rfPos == _rfFrameLen+1) {
+            _rfState = RfStateFrame;
+
+            // cancel timer
+            _rfFrameTimeout = 0;
+            _rfFrameTimer.stop();
+
+            processFrame(_rfBuf, _rfPos);
+        }
+        break;
+
+    }
+}
+
+void XBee::processFrame(char* buf, uint32_t len)
+{
+
+    uint32_t addrLo = 0;
+    uint32_t addrHi = 0;
+    char* b = NULL;
+    uint32_t bLen = 0;
+
+    if (len < 2) {
+        debug("Xbee: Invalid frame length (%d)\r\n", (int)len);
+        return;
+    }
+
+    // verify checksum
+    if (checksum(buf, len) != 0) {
+        debug("Xbee: Invalid checksum\r\n");
+        return;
+    }
+
+    switch(buf[0]) {
+    case XBEE_API_ID_AT_RESP:
+        if (len < 5) {
+            debug("Xbee: AT resp data too small: %d\r\n ", (int)len);
+            return;
+        }
+
+        // there is a value
+        if (len > 6) {
+            b = &buf[5];
+            bLen = len-5-1;
+        }
+
+        handleAtResponse(buf[1], &buf[2], buf[4], b, bLen);
+        break;
+    case XBEE_API_ID_TX_STAT:
+        handleTxStatus(buf[1], buf[2]);
+        break;
+    case XBEE_API_ID_RX_64:
+        if (len < 12) {
+            debug("Xbee: RX data too small: %d\r\n ", (int)len);
+            return;
+        }
+        addrHi = bufTo32bitInt(&buf[1]);
+        addrLo = bufTo32bitInt(&buf[5]);
+
+        processData(addrHi, addrLo, buf[9], buf[10], &buf[11], len-11-1);
+        break;
+    case XBEE_API_ID_RX_16:
+        debug("Xbee: RX 16 bit (unhandled)\r\n");
+        break;
+    case XBEE_API_ID_MOD_STAT:
+        handleModemStatus(buf[1]);
+        break;
+    default:
+        debug("Xbee: Unhandled API ID: %x\r\n ", buf[0]);
+
+        break;
+    }
+
+}
+
+void XBee::handleAtResponse(uint8_t frameId, char* atBuf, uint8_t status,
+    char* valueBuf, uint32_t valueLen)
+{
+
+  if (strncmp("ND", (char*)atBuf, 2) == 0) {
+    handleDiscovery(status, valueBuf, valueLen);
+  }
+
+}
+
+void XBee::handleDiscovery(uint8_t status, char* buf, uint32_t len)
+{
+
+  if (status == 0 && len >= 11) {
+    _addrHi = bufTo32bitInt(&buf[2]);
+    _addrLo = bufTo32bitInt(&buf[6]);
+    _rssi = buf[10];
+
+    _callbacks[CbNodeFound].call();
+
+  }
+}
+
+void XBee::handleTxStatus(uint8_t frameId, uint8_t status)
+{
+    _frameId = frameId;
+    switch(status)  {
+    case XBEE_TX_STAT_SUCCESS:
+      _txStatus = TxStatusOk;
+      break;
+    case XBEE_TX_STAT_NOACK:
+      _txStatus = TxStatusNoAck;
+      break;
+    case XBEE_TX_STAT_CCA_FAIL:
+      _txStatus = TxStatusCCA;
+      break;
+    case XBEE_TX_STAT_PURGED:
+      _txStatus = TxStatusPurged;
+      break;
+    }
+
+    _callbacks[CbTxStat].call();
+
+}
+
+void XBee::processData(uint32_t addrHi, uint32_t addrLo, uint8_t rssi,
+    uint8_t opt, char* buf, uint32_t len)
+{
+    _addrHi = addrHi;
+    _addrLo = addrLo;
+    _rssi = rssi;
+    _recvData = buf;
+    _recvLen = len;
+
+    _callbacks[CbDataAvailable].call();
+}
+
+void XBee::handleModemStatus(uint8_t status) {
+
+    if (_type == Coordinator && status == XBEE_MOD_STAT_COORD_START) {
+        _initialized = true;
+        _callbacks[CbDeviceUp].call();
+    }
+    else if (_type == EndDevice && status == XBEE_MOD_STAT_ASSOC) {
+        _initialized = 1;
+        _callbacks[CbDeviceUp].call();
+    }
+    else if (_type == EndDevice && status == XBEE_MOD_STAT_DIASSOC) {
+        _initialized = false;
+        _callbacks[CbDeviceDown].call();
+    }
+
+}
+
+char XBee::checksum(char* buf, uint32_t len)
+{
+    int i = 0;
+    char cs = 0;
+
+    for (i = 0; i < (int)len; i++) {
+        cs += buf[i];
+    }
+
+    return (0xFF - cs);
+}
+
+uint32_t XBee::bufTo32bitInt(const char* buf)
+{
+    uint32_t v = 0;
+
+    v |= (buf[0] << 24);
+    v |= (buf[1] << 16);
+    v |= (buf[2] << 8);
+    v |= (buf[3]);
+
+    return v;
+}
+
+void XBee::int32bitToBuf(uint32_t v, char* buf)
+{
+
+  buf[0] = ((v >> 24) & 0xff);
+  buf[1] = ((v >> 16) & 0xff);
+  buf[2] = ((v >> 8) & 0xff);
+  buf[3] = ((v >> 0) & 0xff);
+
+}
+
+
+XBee::XBeeError XBee::apiTx64(uint32_t addrHi, uint32_t addrLo, char* data,
+    uint32_t len, uint8_t* frameId)
+{
+    char buf[100];
+
+
+    // limiting to 85 bytes data. Remaining 15 bytes belong to the
+    // frame
+    if (len > 85) {
+        return ArgumentError;
+    }
+
+    buf[0] = XBEE_START_DEL;
+
+    // length
+    buf[1] = 0;
+    buf[2] = 11+len;
+
+    // AP ID
+    buf[3] = XBEE_API_ID_TX_64;
+
+    // frame ID
+    buf[4] = getFrameId();
+
+
+    // address
+    int32bitToBuf(addrHi, &buf[5]);
+    int32bitToBuf(addrLo, &buf[9]);
+
+    // options
+    buf[13] = 0;
+
+    // data
+    memcpy(&buf[14], data, len);
+
+    // checksum
+    buf[14+len] = checksum(&buf[3], buf[2]);
+
+    if (frameId != NULL) {
+        *frameId = buf[4];
+    }
+
+
+    for (int i = 0; i < (15+len); i++) {
+        _serial.putc(buf[i]);
+    }
+
+
+    return Ok;
+}
+
+XBee::XBeeError XBee::apiAtCmd(const char* atCmd, uint32_t param, bool useParameter)
+{
+    char buf[12];
+    int pos = 0;
+
+    buf[0] = XBEE_START_DEL;
+
+    // length
+    buf[1] = 0;
+    buf[2] = 4;
+    if (useParameter) {
+      buf[2] += 4;
+    }
+
+    // AP ID
+    buf[3] = XBEE_API_ID_AT_CMD;
+
+    // frame ID
+    buf[4] = getFrameId();
+
+    // AT cmd
+    buf[5] = atCmd[0];
+    buf[6] = atCmd[1];
+    pos = 7;
+
+    // AT parameter
+    if (useParameter) {
+      buf[pos++] = ((param >> 24) & 0xff);
+      buf[pos++] = ((param >> 16) & 0xff);
+      buf[pos++] = ((param >> 8) & 0xff);
+      buf[pos++] = ((param >> 0) & 0xff);
+    }
+
+    // checksum
+    buf[pos] = checksum(&buf[3], pos-3);
+    pos++;
+
+    for (int i = 0; i < pos; i++) {
+        _serial.putc(buf[i]);
+    }
+
+    return Ok;
+}
+
+uint8_t XBee::getFrameId(void)
+{
+    _rfFrameId++;
+    if (_rfFrameId == 0) {
+        _rfFrameId = 1;
+    }
+
+    return _rfFrameId;
+}