The wait in mci_WaitForEvent will delay all card transactions.

Dependencies:   FATFileSystem

Fork of EALib by EmbeddedArtists AB

Files at this revision

API Documentation at this revision

Comitter:
embeddedartists
Date:
Mon Nov 11 09:39:58 2013 +0000
Parent:
6:405c6e5a4eaf
Child:
8:fe3cb3fbb64e
Commit message:
Added XBee class. Tested with XBee S1

Changed in this revision

XBee.cpp Show annotated file Show diff for this revision Revisions of this file
XBee.h Show annotated file Show diff for this revision Revisions of this file
--- /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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XBee.h	Mon Nov 11 09:39:58 2013 +0000
@@ -0,0 +1,266 @@
+
+#ifndef XBEE_H
+#define XBEE_H
+
+#define RX_BUF_SIZE (512)
+#define XBEE_BUF_SZ (200)
+
+#define XBEE_ADDRLO_BROADCAST (0x0000FFFF)
+#define XBEE_ADDRHI_BROADCAST (0x00000000)
+
+/**
+ * Interface to Digi International's XBee module. The XBee S1 module has
+ * been used during testing of this interface.
+ */
+class XBee {
+public:
+
+    /** Error codes returned from public methods */
+    enum XBeeError {
+        Ok = 0,
+        ReadError = -1,
+        CmdError = -2,
+        BufTooSmallError = -3,
+        TimeOutError = -4,
+        NotInitializedError = -5,
+        ArgumentError = -6
+
+    };
+
+    /** Callback function/method types. See registerCallback() */
+    enum CallbackType {
+        /** Device is up and ready */
+        CbDeviceUp = 0,
+        /** Device is down (disconnected) */
+        CbDeviceDown,
+        /** A node has been found */
+        CbNodeFound,
+        /** Transmit status */
+        CbTxStat,
+        /** Data is available */
+        CbDataAvailable,
+        CbNum // must be last
+
+    };
+
+    /** Xbee types */
+    enum XBeeType {
+        EndDevice = 0,
+        Coordinator
+    };
+
+    /** Transmit status */
+    enum XBeeTxStatus {
+        TxStatusOk = 0,
+        TxStatusNoAck,
+        TxStatusCCA,
+        TxStatusPurged
+    };
+
+    /**
+     * Create an interface to an XBee module.
+     *
+     * @param tx UART TX line
+     * @param tx UART rx line
+     * @param reset reset pin
+     * @param sleep sleep request pin
+     */
+    XBee(PinName tx, PinName rx, PinName reset, PinName sleep);
+
+    /**
+     * Initialize the XBee module and configure it to be of a
+     * specific type.
+     *
+     * Note: This implementation will always configure the XBee module to
+     * work in API mode.
+     *
+     * @param type the type of this XBee node
+     * @param panId the PAN ID to use for the XBee network. This  argument
+     * must contain 4 characters representing hexadecimal values
+     * (e.g. "A1E0" means the hexadecimal value 0xA1E0);
+     */
+    XBeeError init(XBeeType type, const char* panId);
+
+    /**
+     * Register a callback function
+     *
+     * @param fptr Callback function to register
+     * @param type The type of event that will trigger a call to the function.
+     */
+    void registerCallback(void (*fptr)(void), CallbackType type) {
+        if (fptr) {
+            _callbacks[type].attach(fptr);
+        }
+    }
+
+    /**
+     * Register a callback method
+     *
+     * @param tptr pointer to the object to call the member function on
+     * @param mptr pointer to the member function to be called
+     * @param type The type of event that will trigger a call to the method.
+     */
+    template<typename T>
+    void registerCallback(T* tptr, void (T::*mptr)(void), CallbackType type) {
+        if((mptr != NULL) && (tptr != NULL)) {
+            _callbacks[type].attach(tptr, mptr);
+        }
+    }
+
+    /**
+     * Call this method repeatedly to process incoming data.
+     */
+    void process();
+
+    /**
+     * Get address of remote node. This method will only return valid data
+     * when called in the context of the CbDataAvailable and CbNodeFound
+     * callbacks
+     *
+     * @param addrHi Top 32 bits of address will be written to this argument
+     * @param addrLo Bottom 32 bits of address will be written to this argument
+     */
+    XBeeError getRemoteAddress(uint32_t* addrHi, uint32_t* addrLo);
+
+    /**
+     * Get signal strength indicator value (RSSI). This method will only
+     * return valid data when called in the context of the
+     * CbDataAvailable and CbNodeFound callbacks
+     *
+     * @param rssi RSSI value will be written to this argument
+     */
+    XBeeError getRssi(uint8_t* rssi );
+
+    /**
+     * Get the transmit status. This method will only return valid data when
+     * called in the context of the CbTxStat callback.
+     *
+     * @param frameId the frame ID will be written to this argument
+     * @param status the status will be written to this argument
+     */
+    XBeeError getTxStatus(uint8_t* frameId, XBeeTxStatus* status);
+
+    /**
+     * Get received data. This method will only return valid data when called
+     * in the context of the CbDataAvailable callback
+     *
+     * @param data will point to a buffer with received data
+     * @param len will contain the length of the received data
+     */
+    XBeeError getData(char** data, uint8_t* len);
+
+    /**
+     * Send data to a node with specified address. It is also possible to
+     * broadcast a message using broadcast address (XBEE_ADDRHI_BROADCAST,
+     * XBEE_ADDRLO_BROADCAST).
+     *
+     * @param addrHi Top 32 bits of address
+     * @param addrLo Bottom 32 bits of address
+     * @param data buffer containing data to send
+     * @param len number of bytes to send
+     * @param frameId the ID of the frame will be written to this argument.
+     * The ID can then be used to match this request with the status returned
+     * in the CbTxStat callback.
+     */
+    XBeeError send(uint32_t addrHi, uint32_t addrLo, char* data,
+        uint8_t len, uint8_t* frameId);
+
+    /**
+     * Send a Node Discover request. All modules on the operating channel and
+     * PAN ID should respond. The responses will be reported in the CbNodeFound
+     * callback.
+     */
+    XBeeError discoverNodes();
+
+    /**
+     * Request the module to enter sleep mode.
+     */
+    XBeeError enterSleep();
+
+    /**
+     * Request the module to exit sleep mode.
+     */
+    XBeeError exitSleep();
+
+
+protected:
+
+
+private:
+
+    enum RfState {
+        RfStateFrame = 0,
+        RfStateLength,
+        RfStateData
+    };
+
+
+    bool _initialized;
+    Serial _serial;
+    XBeeType _type;
+    DigitalOut _reset;
+    DigitalOut _sleep;
+
+    uint8_t rxqIn;
+    uint8_t rxqOut;
+    uint8_t rxq[RX_BUF_SIZE];
+
+    uint32_t _rfFrameTimeout;
+    Timer _rfFrameTimer;
+
+    RfState _rfState;
+    uint32_t _rfPos;
+    uint32_t _rfFrameLen;
+    char _rfBuf[XBEE_BUF_SZ];
+    uint8_t _rfFrameId;
+
+    uint32_t _addrHi;
+    uint32_t _addrLo;
+    uint8_t _rssi;
+    uint8_t _frameId;
+    XBeeTxStatus _txStatus;
+    char* _recvData;
+    uint8_t _recvLen;
+
+
+    FunctionPointer _callbacks[CbNum];
+
+
+    void uartRxIrq();
+    void uartRxQPut(uint8_t data);
+    uint8_t uartRxQGet();
+    bool uartRxQIsEmpty();
+    uint32_t uartReceive(char *buf, uint32_t buflen);
+    int32_t uartReadLine(char* buf, uint32_t bufLen, uint32_t timeout);
+
+    void resetModule();
+    XBeeError commandMode();
+    XBeeError atGet(const char* atCmd, char* resp, uint32_t respLen);
+    XBeeError atSet(const char* atCmd);
+
+    void processByte(char data);
+    void processFrame(char* buf, uint32_t len);
+
+    void handleAtResponse(uint8_t frameId, char* atBuf, uint8_t status,
+        char* valueBuf, uint32_t valueLen);
+
+    void handleDiscovery(uint8_t status, char* buf, uint32_t len);
+    void handleTxStatus(uint8_t frameId, uint8_t status);
+    void processData(uint32_t addrHi, uint32_t addrLo, uint8_t rssi,
+        uint8_t opt, char* buf, uint32_t len);
+    void handleModemStatus(uint8_t status);
+
+    char checksum(char* buf, uint32_t len);
+    uint32_t bufTo32bitInt(const char* buf);
+    void int32bitToBuf(uint32_t v, char* buf);
+
+    XBeeError apiTx64(uint32_t addrHi, uint32_t addrLo, char* data,
+        uint32_t len, uint8_t* frameId);
+    XBeeError apiAtCmd(const char* atCmd, uint32_t param, bool useParameter);
+
+    uint8_t getFrameId();
+
+
+};
+
+#endif