Solutions for the XBee experiments for LPC812 MAX

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
embeddedartists
Date:
Wed Nov 20 08:26:28 2013 +0000
Commit message:
First Version

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
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 54828b08e71d XBee.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XBee.cpp	Wed Nov 20 08:26:28 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;
+}
diff -r 000000000000 -r 54828b08e71d XBee.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XBee.h	Wed Nov 20 08:26:28 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
diff -r 000000000000 -r 54828b08e71d main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Nov 20 08:26:28 2013 +0000
@@ -0,0 +1,228 @@
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+#include "mbed.h"
+#include "XBee.h"
+
+/******************************************************************************
+ * Typedefs and defines
+ *****************************************************************************/
+
+// define NODE_IS_COORDINATOR if this board should act
+// as XBee coordinator. Make sure it is undefined it the board
+// should act as End-Device
+#define NODE_IS_COORDINATOR (1)
+
+#define CMD_BTN_MSG (0)
+#define CMD_ACK_MSG (1)
+
+/******************************************************************************
+ * Local variables
+ *****************************************************************************/
+
+static XBee xbee(P0_4, P0_0, P0_17, P0_7); //tx,rx,reset,sleep
+
+static Serial pc(USBTX, USBRX); // tx, rx
+
+// all LEDs active low
+static DigitalOut xbeeInitLed(D13);
+static DigitalOut remoteBtnLed(D12);
+static DigitalOut ackLed(D11);
+static DigitalOut led4(D10);
+
+static DigitalIn button(D3);
+static bool xbeeIsUp = false;
+
+/******************************************************************************
+ * Local functions
+ *****************************************************************************/
+
+static void xbeeDeviceUp(void) {
+    xbeeIsUp = true;
+}
+
+static void xbeeDeviceDown(void) {
+    xbeeIsUp = false;
+}
+
+static void xbeeNodeFound(void) {
+    uint32_t addrHi = 0;
+    uint32_t addrLo = 0;
+    uint8_t rssi = 0;
+
+    xbee.getRemoteAddress(&addrHi, &addrLo);
+    xbee.getRssi(&rssi);
+
+    pc.printf("XBee: node found: hi=%lx, lo=%lx, rssi=%d\n",
+            addrHi, addrLo, rssi);
+}
+
+static void xbeeTxStat(void) {
+
+    uint8_t frameId = 0;
+    XBee::XBeeTxStatus status = XBee::TxStatusOk;
+
+    xbee.getTxStatus(&frameId, &status);
+
+    pc.printf("XBee: Tx Stat. Id=%u, status=%d\n", frameId, (int)status);
+}
+
+
+
+static void xbeeDataAvailable(void) {
+    char* data = NULL;
+    char ackMsg = CMD_ACK_MSG;
+    uint8_t frameId = 0;
+    uint8_t len = 0;
+    uint32_t addrHi = 0;
+    uint32_t addrLo = 0;
+    uint8_t rssi = 0;
+
+    xbee.getRemoteAddress(&addrHi, &addrLo);
+    xbee.getData(&data, &len);
+    xbee.getRssi(&rssi);
+
+    pc.printf("XBee: Data available: len=%d hi=%lx, lo=%lx, rssi=%d\n",
+            (int)len, addrHi, addrLo, rssi);
+
+    if (len > 0) {
+
+        switch(data[0]) {
+        case CMD_BTN_MSG:
+            if (len > 1) {
+                // change led to indicate button state
+                remoteBtnLed = ((data[1] == 1) ? 1 : 0);
+
+
+                // Send an ACK directly to the remote node (only for
+                // buttons state == 0)
+                if (data[1] == 0) {
+                    xbee.send(addrHi, addrLo, &ackMsg, 1, &frameId);
+                }
+            }
+            break;
+        case CMD_ACK_MSG:
+            for (int i = 0; i < 3; i++) {
+                ackLed = 0;
+                wait_ms(100);
+                ackLed = 1;
+                wait_ms(100);
+            }
+            break;
+        }
+
+    }
+
+}
+
+static bool xbeeInit()
+{
+    xbee.registerCallback(xbeeDeviceUp, XBee::CbDeviceUp);
+    xbee.registerCallback(xbeeDeviceDown, XBee::CbDeviceDown);
+    xbee.registerCallback(xbeeNodeFound, XBee::CbNodeFound);
+    xbee.registerCallback(xbeeTxStat, XBee::CbTxStat);
+    xbee.registerCallback(xbeeDataAvailable, XBee::CbDataAvailable);
+
+#ifdef NODE_IS_COORDINATOR
+    XBee::XBeeError err = xbee.init(XBee::Coordinator, "EAEA");
+#else
+    XBee::XBeeError err = xbee.init(XBee::EndDevice, "EAEA");
+#endif
+    if (err != XBee::Ok) {
+        return false;
+    }
+
+    return true;
+
+}
+
+static void reportInitFailed() {
+    while (true) {
+        xbeeInitLed = !xbeeInitLed;
+        wait_ms(200);
+    }
+}
+
+static void ledInit() {
+    xbeeInitLed = 0;  // turn on
+    remoteBtnLed = 1; // turn off
+    ackLed = 1;       // turn off
+    led4 = 1;         // turn off
+}
+
+
+/******************************************************************************
+ * Main function
+ *****************************************************************************/
+
+int main() {
+
+    /*
+     * For this example to work at least two boards with XBee nodes must
+     * be available; one which is configured as Coordinator and another
+     * which is configured as End-Device.
+     *
+     * LED1 shows the state of XBee initialization. This LED is turned
+     * on when initialization starts and turned off when initialization
+     * is ready and the device us up. If initialization fails LED1
+     * will blink.
+     *
+     * When the Push-button on the LPC4088 QuickStart Board is pushed
+     * a message will be broadcasted. The board(s) that receives the message
+     * will show the state of the remote board's button by turning LED2
+     * on or off.
+     *
+     * The board that receives the button state message will send back
+     * an ACK message (only for button down). The board that receives
+     * the ACK message will blink with LED3. This can be used to verify
+     * that a board that is not close to you actually received a message
+     * without having to look at that board's LED2.
+     */
+
+    int buttonState = 1;
+    char data[2];
+    uint8_t frameId = 0;
+
+    // pull-up must be enabled for button
+    button.mode(PullUp);
+
+    ledInit();
+
+    pc.printf("Initializing\n");
+    if (!xbeeInit()) {
+        reportInitFailed();
+    }
+
+    // Wait until XBee node is reported to be up.
+    // - For End-device this means that the node is associated with a
+    //   coordinator
+    // - For a coordinator this means that the node is initialized and ready
+    pc.printf("Wait until up\n");
+    while(!xbeeIsUp) {
+        xbee.process();
+    }
+
+    // turn off led to indicate initialization is okay and node is up
+    xbeeInitLed = 1;
+
+    pc.printf("Node is Up\n");
+    while (1) {
+
+        if (button != buttonState) {
+            buttonState = button;
+
+            data[0] = CMD_BTN_MSG;
+            data[1] = buttonState;
+
+            // Send the button state. In this example we are broadcasting the
+            // message to all nodes on the same network (PAN ID). In reality
+            // direct messaging is preferred.
+            xbee.send(XBEE_ADDRHI_BROADCAST, XBEE_ADDRLO_BROADCAST,
+                    data, 2, &frameId);
+        }
+
+
+        xbee.process();
+
+    }
+}
diff -r 000000000000 -r 54828b08e71d mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Nov 20 08:26:28 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f
\ No newline at end of file