XBee-mbed library http://mbed.org/users/okini3939/notebook/xbee-mbed/

Dependents:   device_server_udp led_sender_post XBee_API_ex1 XBee_API_ex2 ... more

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Mon Nov 22 10:51:06 2010 +0000
Child:
1:e3b2027e685c
Commit message:

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 22 10:51:06 2010 +0000
@@ -0,0 +1,1362 @@
+/**
+ * XBee-mbed library
+ * Modified for mbed, 2010 Suga.
+ *
+ *
+ * Copyright (c) 2009 Andrew Rapp. All rights reserved.
+ *
+ * This file is part of XBee-Arduino.
+ *
+ * XBee-Arduino is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * XBee-Arduino is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBee-Arduino.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mbed.h"
+#include "XBee.h"
+
+XBeeResponse::XBeeResponse() {
+
+}
+
+uint8_t XBeeResponse::getApiId() {
+    return _apiId;
+}
+
+void XBeeResponse::setApiId(uint8_t apiId) {
+    _apiId = apiId;
+}
+
+uint8_t XBeeResponse::getMsbLength() {
+    return _msbLength;
+}
+
+void XBeeResponse::setMsbLength(uint8_t msbLength) {
+    _msbLength = msbLength;
+}
+
+uint8_t XBeeResponse::getLsbLength() {
+    return _lsbLength;
+}
+
+void XBeeResponse::setLsbLength(uint8_t lsbLength) {
+    _lsbLength = lsbLength;
+}
+
+uint8_t XBeeResponse::getChecksum() {
+    return _checksum;
+}
+
+void XBeeResponse::setChecksum(uint8_t checksum) {
+    _checksum = checksum;
+}
+
+uint8_t XBeeResponse::getFrameDataLength() {
+    return _frameLength;
+}
+
+void XBeeResponse::setFrameLength(uint8_t frameLength) {
+    _frameLength = frameLength;
+}
+
+bool XBeeResponse::isAvailable() {
+    return _complete;
+}
+
+void XBeeResponse::setAvailable(bool complete) {
+    _complete = complete;
+}
+
+bool XBeeResponse::isError() {
+    return _errorCode > 0;
+}
+
+uint8_t XBeeResponse::getErrorCode() {
+    return _errorCode;
+}
+
+void XBeeResponse::setErrorCode(uint8_t errorCode) {
+    _errorCode = errorCode;
+}
+
+// copy common fields from xbee response to target response
+void XBeeResponse::setCommon(XBeeResponse &target) {
+    target.setApiId(getApiId());
+    target.setAvailable(isAvailable());
+    target.setChecksum(getChecksum());
+    target.setErrorCode(getErrorCode());
+    target.setFrameLength(getFrameDataLength());
+    target.setMsbLength(getMsbLength());
+    target.setLsbLength(getLsbLength());
+}
+
+#ifdef SERIES_2
+
+ZBTxStatusResponse::ZBTxStatusResponse() : FrameIdResponse() {
+
+}
+
+uint16_t ZBTxStatusResponse::getRemoteAddress() {
+    return  (getFrameData()[1] << 8) + getFrameData()[2];
+}
+
+uint8_t ZBTxStatusResponse::getTxRetryCount() {
+    return getFrameData()[3];
+}
+
+uint8_t ZBTxStatusResponse::getDeliveryStatus() {
+    return getFrameData()[4];
+}
+
+uint8_t ZBTxStatusResponse::getDiscoveryStatus() {
+    return getFrameData()[5];
+}
+
+bool ZBTxStatusResponse::isSuccess() {
+    return getDeliveryStatus() == SUCCESS;
+}
+
+void XBeeResponse::getZBTxStatusResponse(XBeeResponse &zbXBeeResponse) {
+
+    // way off?
+    ZBTxStatusResponse* zb = static_cast<ZBTxStatusResponse*>(&zbXBeeResponse);
+    // pass pointer array to subclass
+    zb->setFrameData(getFrameData());
+    setCommon(zbXBeeResponse);
+}
+
+ZBRxResponse::ZBRxResponse(): RxDataResponse() {
+    _remoteAddress64 = XBeeAddress64();
+}
+
+uint16_t ZBRxResponse::getRemoteAddress16() {
+    return     (getFrameData()[8] << 8) + getFrameData()[9];
+}
+
+uint8_t ZBRxResponse::getOption() {
+    return getFrameData()[10];
+}
+
+// markers to read data from packet array.  this is the index, so the 12th item in the array
+uint8_t ZBRxResponse::getDataOffset() {
+    return 11;
+}
+
+uint8_t ZBRxResponse::getDataLength() {
+    return getPacketLength() - getDataOffset() - 1;
+}
+
+XBeeAddress64& ZBRxResponse::getRemoteAddress64() {
+    return _remoteAddress64;
+}
+
+void XBeeResponse::getZBRxResponse(XBeeResponse &rxResponse) {
+
+    ZBRxResponse* zb = static_cast<ZBRxResponse*>(&rxResponse);
+
+    //TODO verify response api id matches this api for this response
+
+    // pass pointer array to subclass
+    zb->setFrameData(getFrameData());
+    setCommon(rxResponse);
+
+    zb->getRemoteAddress64().setMsb((uint32_t(getFrameData()[0]) << 24) + (uint32_t(getFrameData()[1]) << 16) + (uint16_t(getFrameData()[2]) << 8) + getFrameData()[3]);
+    zb->getRemoteAddress64().setLsb((uint32_t(getFrameData()[4]) << 24) + (uint32_t(getFrameData()[5]) << 16) + (uint16_t(getFrameData()[6]) << 8) + (getFrameData()[7]));
+}
+
+
+ZBRxIoSampleResponse::ZBRxIoSampleResponse() : ZBRxResponse() {
+
+}
+
+// 64 + 16 addresses, sample size, option = 12 (index 11), so this starts at 12
+uint8_t ZBRxIoSampleResponse::getDigitalMaskMsb() {
+    return getFrameData()[12] & 0x1c;
+}
+
+uint8_t ZBRxIoSampleResponse::getDigitalMaskLsb() {
+    return getFrameData()[13];
+}
+
+uint8_t ZBRxIoSampleResponse::getAnalogMask() {
+    return getFrameData()[14] & 0x8f;
+}
+
+bool ZBRxIoSampleResponse::containsAnalog() {
+    return getAnalogMask() > 0;
+}
+
+bool ZBRxIoSampleResponse::containsDigital() {
+    return getDigitalMaskMsb() > 0 || getDigitalMaskLsb() > 0;
+}
+
+bool ZBRxIoSampleResponse::isAnalogEnabled(uint8_t pin) {
+    return ((getAnalogMask() >> pin) & 1) == 1;
+}
+
+bool ZBRxIoSampleResponse::isDigitalEnabled(uint8_t pin) {
+    if (pin <= 7) {
+        // added extra parens to calm avr compiler
+        return ((getDigitalMaskLsb() >> pin) & 1) == 1;
+    } else {
+        return ((getDigitalMaskMsb() >> (pin - 8)) & 1) == 1;
+    }
+}
+
+uint16_t ZBRxIoSampleResponse::getAnalog(uint8_t pin) {
+    // analog starts 13 bytes after sample size, if no dio enabled
+    uint8_t start = 15;
+
+    if (containsDigital()) {
+        // make room for digital i/o
+        start+=2;
+    }
+
+//    std::cout << "spacing is " << static_cast<unsigned int>(spacing) << std::endl;
+
+    // start depends on how many pins before this pin are enabled
+    for (int i = 0; i < pin; i++) {
+        if (isAnalogEnabled(pin)) {
+            start+=2;
+        }
+    }
+
+//    std::cout << "start for analog pin ["<< static_cast<unsigned int>(pin) << "]/sample " << static_cast<unsigned int>(sample) << " is " << static_cast<unsigned int>(start) << std::endl;
+
+//    std::cout << "returning index " << static_cast<unsigned int>(getSampleOffset() + start) << " and index " <<  static_cast<unsigned int>(getSampleOffset() + start + 1) << ", val is " << static_cast<unsigned int>(getFrameData()[getSampleOffset() + start] << 8) <<  " and " <<  + static_cast<unsigned int>(getFrameData()[getSampleOffset() + start + 1]) << std::endl;
+
+    return (uint16_t)((getFrameData()[start] << 8) + getFrameData()[start + 1]);
+}
+
+bool ZBRxIoSampleResponse::isDigitalOn(uint8_t pin) {
+    if (pin <= 7) {
+        // D0-7
+        // DIO LSB is index 5
+        return ((getFrameData()[16] >> pin) & 1) == 1;
+    } else {
+        // D10-12
+        // DIO MSB is index 4
+        return ((getFrameData()[15] >> (pin - 8)) & 1) == 1;
+    }
+}
+
+void XBeeResponse::getZBRxIoSampleResponse(XBeeResponse &response) {
+    ZBRxIoSampleResponse* zb = static_cast<ZBRxIoSampleResponse*>(&response);
+
+
+    // pass pointer array to subclass
+    zb->setFrameData(getFrameData());
+    setCommon(response);
+
+    zb->getRemoteAddress64().setMsb((uint32_t(getFrameData()[0]) << 24) + (uint32_t(getFrameData()[1]) << 16) + (uint16_t(getFrameData()[2]) << 8) + getFrameData()[3]);
+    zb->getRemoteAddress64().setLsb((uint32_t(getFrameData()[4]) << 24) + (uint32_t(getFrameData()[5]) << 16) + (uint16_t(getFrameData()[6]) << 8) + (getFrameData()[7]));
+}
+
+#endif
+
+#ifdef SERIES_1
+
+RxResponse::RxResponse() : RxDataResponse() {
+
+}
+
+uint16_t Rx16Response::getRemoteAddress16() {
+    return (getFrameData()[0] << 8) + getFrameData()[1];
+}
+
+XBeeAddress64& Rx64Response::getRemoteAddress64() {
+    return _remoteAddress;
+}
+
+Rx64Response::Rx64Response() : RxResponse() {
+    _remoteAddress = XBeeAddress64();
+}
+
+Rx16Response::Rx16Response() : RxResponse() {
+
+}
+
+RxIoSampleBaseResponse::RxIoSampleBaseResponse() : RxResponse() {
+
+}
+
+uint8_t RxIoSampleBaseResponse::getSampleOffset() {
+    // sample starts 2 bytes after rssi
+    return getRssiOffset() + 2;
+}
+
+
+uint8_t RxIoSampleBaseResponse::getSampleSize() {
+    return getFrameData()[getSampleOffset()];
+}
+
+bool RxIoSampleBaseResponse::containsAnalog() {
+    return (getFrameData()[getSampleOffset() + 1] & 0x7e) > 0;
+}
+
+bool RxIoSampleBaseResponse::containsDigital() {
+    return (getFrameData()[getSampleOffset() + 1] & 0x1) > 0 || getFrameData()[getSampleOffset() + 2] > 0;
+}
+
+//uint16_t RxIoSampleBaseResponse::getAnalog0(uint8_t sample) {
+//    return getAnalog(0, sample);
+//}
+
+bool RxIoSampleBaseResponse::isAnalogEnabled(uint8_t pin) {
+    return (((getFrameData()[getSampleOffset() + 1] >> (pin + 1)) & 1) == 1);
+}
+
+bool RxIoSampleBaseResponse::isDigitalEnabled(uint8_t pin) {
+    if (pin < 8) {
+        return ((getFrameData()[getSampleOffset() + 4] >> pin) & 1) == 1;
+    } else {
+        return (getFrameData()[getSampleOffset() + 3] & 1) == 1;
+    }
+}
+
+uint16_t RxIoSampleBaseResponse::getAnalog(uint8_t pin, uint8_t sample) {
+
+    // analog starts 3 bytes after sample size, if no dio enabled
+    uint8_t start = 3;
+
+    if (containsDigital()) {
+        // make room for digital i/o sample (2 bytes per sample)
+        start+=2*(sample + 1);
+    }
+
+    uint8_t spacing = 0;
+
+    // spacing between samples depends on how many are enabled. add one for each analog that's enabled
+    for (int i = 0; i <= 5; i++) {
+        if (isAnalogEnabled(i)) {
+            // each analog is two bytes
+            spacing+=2;
+        }
+    }
+
+//    std::cout << "spacing is " << static_cast<unsigned int>(spacing) << std::endl;
+
+    // start depends on how many pins before this pin are enabled
+    for (int i = 0; i < pin; i++) {
+        if (isAnalogEnabled(pin)) {
+            start+=2;
+        }
+    }
+
+    start+= sample * spacing;
+
+//    std::cout << "start for analog pin ["<< static_cast<unsigned int>(pin) << "]/sample " << static_cast<unsigned int>(sample) << " is " << static_cast<unsigned int>(start) << std::endl;
+
+//    std::cout << "returning index " << static_cast<unsigned int>(getSampleOffset() + start) << " and index " <<  static_cast<unsigned int>(getSampleOffset() + start + 1) << ", val is " << static_cast<unsigned int>(getFrameData()[getSampleOffset() + start] << 8) <<  " and " <<  + static_cast<unsigned int>(getFrameData()[getSampleOffset() + start + 1]) << std::endl;
+
+    return (uint16_t)((getFrameData()[getSampleOffset() + start] << 8) + getFrameData()[getSampleOffset() + start + 1]);
+}
+
+bool RxIoSampleBaseResponse::isDigitalOn(uint8_t pin, uint8_t sample) {
+    if (pin < 8) {
+        return ((getFrameData()[getSampleOffset() + 4] >> pin) & 1) == 1;
+    } else {
+        return (getFrameData()[getSampleOffset() + 3] & 1) == 1;
+    }
+}
+
+
+//bool RxIoSampleBaseResponse::isDigital0On(uint8_t sample) {
+//    return isDigitalOn(0, sample);
+//}
+
+Rx16IoSampleResponse::Rx16IoSampleResponse() : RxIoSampleBaseResponse() {
+
+}
+
+uint16_t Rx16IoSampleResponse::getRemoteAddress16() {
+    return (uint16_t)((getFrameData()[0] << 8) + getFrameData()[1]);
+}
+
+uint8_t Rx16IoSampleResponse::getRssiOffset() {
+    return 2;
+}
+
+void XBeeResponse::getRx16IoSampleResponse(XBeeResponse &response) {
+    Rx16IoSampleResponse* rx = static_cast<Rx16IoSampleResponse*>(&response);
+
+    rx->setFrameData(getFrameData());
+    setCommon(response);
+}
+
+
+Rx64IoSampleResponse::Rx64IoSampleResponse() : RxIoSampleBaseResponse() {
+    _remoteAddress = XBeeAddress64();
+}
+
+XBeeAddress64& Rx64IoSampleResponse::getRemoteAddress64() {
+    return _remoteAddress;
+}
+
+uint8_t Rx64IoSampleResponse::getRssiOffset() {
+    return 8;
+}
+
+void XBeeResponse::getRx64IoSampleResponse(XBeeResponse &response) {
+    Rx64IoSampleResponse* rx = static_cast<Rx64IoSampleResponse*>(&response);
+
+    rx->setFrameData(getFrameData());
+    setCommon(response);
+
+    rx->getRemoteAddress64().setMsb((uint32_t(getFrameData()[0]) << 24) + (uint32_t(getFrameData()[1]) << 16) + (uint16_t(getFrameData()[2]) << 8) + getFrameData()[3]);
+    rx->getRemoteAddress64().setLsb((uint32_t(getFrameData()[4]) << 24) + (uint32_t(getFrameData()[5]) << 16) + (uint16_t(getFrameData()[6]) << 8) + getFrameData()[7]);
+}
+
+TxStatusResponse::TxStatusResponse() : FrameIdResponse() {
+
+}
+
+uint8_t TxStatusResponse::getStatus() {
+    return getFrameData()[1];
+}
+
+bool TxStatusResponse::isSuccess() {
+    return getStatus() == SUCCESS;
+}
+
+void XBeeResponse::getTxStatusResponse(XBeeResponse &txResponse) {
+
+    TxStatusResponse* txStatus = static_cast<TxStatusResponse*>(&txResponse);
+
+    // pass pointer array to subclass
+    txStatus->setFrameData(getFrameData());
+    setCommon(txResponse);
+}
+
+uint8_t RxResponse::getRssi() {
+    return getFrameData()[getRssiOffset()];
+}
+
+uint8_t RxResponse::getOption() {
+    return getFrameData()[getRssiOffset() + 1];
+}
+
+bool RxResponse::isAddressBroadcast() {
+    return (getOption() & 2) == 2;
+}
+
+bool RxResponse::isPanBroadcast() {
+    return (getOption() & 4) == 4;
+}
+
+uint8_t RxResponse::getDataLength() {
+    return getPacketLength() - getDataOffset() - 1;
+}
+
+uint8_t RxResponse::getDataOffset() {
+    return getRssiOffset() + 2;
+}
+
+uint8_t Rx16Response::getRssiOffset() {
+    return RX_16_RSSI_OFFSET;
+}
+
+void XBeeResponse::getRx16Response(XBeeResponse &rx16Response) {
+
+    Rx16Response* rx16 = static_cast<Rx16Response*>(&rx16Response);
+
+    // pass pointer array to subclass
+    rx16->setFrameData(getFrameData());
+    setCommon(rx16Response);
+
+//    rx16->getRemoteAddress16().setAddress((getFrameData()[0] << 8) + getFrameData()[1]);
+}
+
+uint8_t Rx64Response::getRssiOffset() {
+    return RX_64_RSSI_OFFSET;
+}
+
+void XBeeResponse::getRx64Response(XBeeResponse &rx64Response) {
+
+    Rx64Response* rx64 = static_cast<Rx64Response*>(&rx64Response);
+
+    // pass pointer array to subclass
+    rx64->setFrameData(getFrameData());
+    setCommon(rx64Response);
+
+    rx64->getRemoteAddress64().setMsb((uint32_t(getFrameData()[0]) << 24) + (uint32_t(getFrameData()[1]) << 16) + (uint16_t(getFrameData()[2]) << 8) + getFrameData()[3]);
+    rx64->getRemoteAddress64().setLsb((uint32_t(getFrameData()[4]) << 24) + (uint32_t(getFrameData()[5]) << 16) + (uint16_t(getFrameData()[6]) << 8) + getFrameData()[7]);
+}
+
+#endif
+
+RemoteAtCommandResponse::RemoteAtCommandResponse() : AtCommandResponse() {
+
+}
+
+uint8_t* RemoteAtCommandResponse::getCommand() {
+    return getFrameData() + 11;
+}
+
+uint8_t RemoteAtCommandResponse::getStatus() {
+    return getFrameData()[13];
+}
+
+bool RemoteAtCommandResponse::isOk() {
+    // weird c++ behavior.  w/o this method, it calls AtCommandResponse::isOk(), which calls the AtCommandResponse::getStatus, not this.getStatus!!!
+    return getStatus() == AT_OK;
+}
+
+uint8_t RemoteAtCommandResponse::getValueLength() {
+    return getFrameDataLength() - 14;
+}
+
+uint8_t* RemoteAtCommandResponse::getValue() {
+    if (getValueLength() > 0) {
+        // value is only included for query commands.  set commands does not return a value
+        return getFrameData() + 14;
+    }
+
+    return NULL;
+}
+
+uint16_t RemoteAtCommandResponse::getRemoteAddress16() {
+    return uint16_t((getFrameData()[9] << 8) + getFrameData()[10]);
+}
+
+XBeeAddress64& RemoteAtCommandResponse::getRemoteAddress64() {
+    return _remoteAddress64;
+}
+
+void XBeeResponse::getRemoteAtCommandResponse(XBeeResponse &response) {
+
+    // TODO no real need to cast.  change arg to match expected class
+    RemoteAtCommandResponse* at = static_cast<RemoteAtCommandResponse*>(&response);
+
+    // pass pointer array to subclass
+    at->setFrameData(getFrameData());
+    setCommon(response);
+
+    at->getRemoteAddress64().setMsb((uint32_t(getFrameData()[1]) << 24) + (uint32_t(getFrameData()[2]) << 16) + (uint16_t(getFrameData()[3]) << 8) + getFrameData()[4]);
+    at->getRemoteAddress64().setLsb((uint32_t(getFrameData()[5]) << 24) + (uint32_t(getFrameData()[6]) << 16) + (uint16_t(getFrameData()[7]) << 8) + (getFrameData()[8]));
+
+}
+
+RxDataResponse::RxDataResponse() : XBeeResponse() {
+
+}
+
+uint8_t RxDataResponse::getData(int index) {
+    return getFrameData()[getDataOffset() + index];
+}
+
+uint8_t* RxDataResponse::getData() {
+    return getFrameData() + getDataOffset();
+}
+
+FrameIdResponse::FrameIdResponse() {
+
+}
+
+uint8_t FrameIdResponse::getFrameId() {
+    return getFrameData()[0];
+}
+
+
+ModemStatusResponse::ModemStatusResponse() {
+
+}
+
+uint8_t ModemStatusResponse::getStatus() {
+    return getFrameData()[0];
+}
+
+void XBeeResponse::getModemStatusResponse(XBeeResponse &modemStatusResponse) {
+
+    ModemStatusResponse* modem = static_cast<ModemStatusResponse*>(&modemStatusResponse);
+
+    // pass pointer array to subclass
+    modem->setFrameData(getFrameData());
+    setCommon(modemStatusResponse);
+
+}
+
+AtCommandResponse::AtCommandResponse() {
+
+}
+
+uint8_t* AtCommandResponse::getCommand() {
+    return getFrameData() + 1;
+}
+
+uint8_t AtCommandResponse::getStatus() {
+    return getFrameData()[3];
+}
+
+uint8_t AtCommandResponse::getValueLength() {
+    return getFrameDataLength() - 4;
+}
+
+uint8_t* AtCommandResponse::getValue() {
+    if (getValueLength() > 0) {
+        // value is only included for query commands.  set commands does not return a value
+        return getFrameData() + 4;
+    }
+
+    return NULL;
+}
+
+bool AtCommandResponse::isOk() {
+    return getStatus() == AT_OK;
+}
+
+void XBeeResponse::getAtCommandResponse(XBeeResponse &atCommandResponse) {
+
+    AtCommandResponse* at = static_cast<AtCommandResponse*>(&atCommandResponse);
+
+    // pass pointer array to subclass
+    at->setFrameData(getFrameData());
+    setCommon(atCommandResponse);
+}
+
+uint16_t XBeeResponse::getPacketLength() {
+    return ((_msbLength << 8) & 0xff) + (_lsbLength & 0xff);
+}
+
+uint8_t* XBeeResponse::getFrameData() {
+    return _frameDataPtr;
+}
+
+void XBeeResponse::setFrameData(uint8_t* frameDataPtr) {
+    _frameDataPtr = frameDataPtr;
+}
+
+void XBeeResponse::init() {
+    _complete = false;
+    _errorCode = NO_ERROR;
+    _checksum = 0;
+}
+
+void XBeeResponse::reset() {
+    init();
+    _apiId = 0;
+    _msbLength = 0;
+    _lsbLength = 0;
+    _checksum = 0;
+    _frameLength = 0;
+
+    for (int i = 0; i < MAX_FRAME_DATA_SIZE; i++) {
+        getFrameData()[i] = 0;
+    }
+}
+
+void XBee::resetResponse() {
+    _pos = 0;
+    _escape = false;
+    _response.reset();
+}
+
+XBee::XBee(PinName p_tx, PinName p_rx): _xbee(p_tx, p_rx), _response(XBeeResponse()) {
+    _pos = 0;
+    _escape = false;
+    _checksumTotal = 0;
+    _nextFrameId = 0;
+
+    _response.init();
+    _response.setFrameData(_responseFrameData);
+}
+
+uint8_t XBee::getNextFrameId() {
+
+    _nextFrameId++;
+
+    if (_nextFrameId == 0) {
+        // can't send 0 because that disables status response
+        _nextFrameId = 1;
+    }
+
+    return _nextFrameId;
+}
+
+void XBee::begin(long baud) {
+    _xbee.baud(baud);
+}
+
+/*
+void XBee::setSerial(HardwareSerial serial) {
+    Serial = serial;
+}
+*/
+
+XBeeResponse& XBee::getResponse() {
+    return _response;
+}
+
+// TODO how to convert response to proper subclass?
+void XBee::getResponse(XBeeResponse &response) {
+
+    response.setMsbLength(_response.getMsbLength());
+    response.setLsbLength(_response.getLsbLength());
+    response.setApiId(_response.getApiId());
+    response.setFrameLength(_response.getFrameDataLength());
+
+    response.setFrameData(_response.getFrameData());
+}
+
+void XBee::readPacketUntilAvailable() {
+    while (!(getResponse().isAvailable() || getResponse().isError())) {
+        // read some more
+        readPacket();
+    }
+}
+
+bool XBee::readPacket(int timeout) {
+    Timer t;
+
+    if (timeout < 0) {
+        return false;
+    }
+
+/*
+    unsigned long start = millis();
+
+    while (int((millis() - start)) < timeout) {
+*/
+    t.start();
+    while (t.read_ms() < timeout) {
+         readPacket();
+
+         if (getResponse().isAvailable()) {
+             t.stop();
+             return true;
+         } else if (getResponse().isError()) {
+             t.stop();
+             return false;
+         }
+    }
+
+    // timed out
+    t.stop();
+    return false;
+}
+
+void XBee::readPacket() {
+    // reset previous response
+    if (_response.isAvailable() || _response.isError()) {
+        // discard previous packet and start over
+        resetResponse();
+    }
+
+    while (_xbee.readable()) {
+
+        b = _xbee.getc();
+
+        if (_pos > 0 && b == START_BYTE && ATAP == 2) {
+            // new packet start before previous packeted completed -- discard previous packet and start over
+            _response.setErrorCode(UNEXPECTED_START_BYTE);
+            return;
+        }
+
+        if (_pos > 0 && b == ESCAPE) {
+            if (_xbee.readable()) {
+                b = _xbee.getc();
+                b = 0x20 ^ b;
+            } else {
+                // escape byte.  next byte will be
+                _escape = true;
+                continue;
+            }
+        }
+
+        if (_escape == true) {
+            b = 0x20 ^ b;
+            _escape = false;
+        }
+
+        // checksum includes all bytes starting with api id
+        if (_pos >= API_ID_INDEX) {
+            _checksumTotal+= b;
+        }
+
+        switch(_pos) {
+            case 0:
+                if (b == START_BYTE) {
+                    _pos++;
+                }
+
+                break;
+            case 1:
+                // length msb
+                _response.setMsbLength(b);
+                _pos++;
+
+                break;
+            case 2:
+                // length lsb
+                _response.setLsbLength(b);
+                _pos++;
+
+                break;
+            case 3:
+                _response.setApiId(b);
+                _pos++;
+
+                break;
+            default:
+                // starts at fifth byte
+
+                if (_pos > MAX_FRAME_DATA_SIZE) {
+                    // exceed max size.  should never occur
+                    _response.setErrorCode(PACKET_EXCEEDS_BYTE_ARRAY_LENGTH);
+                    return;
+                }
+
+                // check if we're at the end of the packet
+                // packet length does not include start, length, or checksum bytes, so add 3
+                if (_pos == (_response.getPacketLength() + 3)) {
+                    // verify checksum
+
+                    //std::cout << "read checksum " << static_cast<unsigned int>(b) << " at pos " << static_cast<unsigned int>(_pos) << std::endl;
+
+                    if ((_checksumTotal & 0xff) == 0xff) {
+                        _response.setChecksum(b);
+                        _response.setAvailable(true);
+
+                        _response.setErrorCode(NO_ERROR);
+                    } else {
+                        // checksum failed
+                        _response.setErrorCode(CHECKSUM_FAILURE);
+                    }
+
+                    // minus 4 because we start after start,msb,lsb,api and up to but not including checksum
+                    // e.g. if frame was one byte, _pos=4 would be the byte, pos=5 is the checksum, where end stop reading
+                    _response.setFrameLength(_pos - 4);
+
+                    // reset state vars
+                    _pos = 0;
+
+                    _checksumTotal = 0;
+
+                    return;
+                } else {
+                    // add to packet array, starting with the fourth byte of the apiFrame
+                    _response.getFrameData()[_pos - 4] = b;
+                    _pos++;
+                }
+        }
+    }
+}
+
+// it's peanut butter jelly time!!
+
+XBeeRequest::XBeeRequest(uint8_t apiId, uint8_t frameId) {
+    _apiId = apiId;
+    _frameId = frameId;
+}
+
+void XBeeRequest::setFrameId(uint8_t frameId) {
+    _frameId = frameId;
+}
+
+uint8_t XBeeRequest::getFrameId() {
+    return _frameId;
+}
+
+uint8_t XBeeRequest::getApiId() {
+    return _apiId;
+}
+
+void XBeeRequest::setApiId(uint8_t apiId) {
+    _apiId = apiId;
+}
+
+//void XBeeRequest::reset() {
+//    _frameId = DEFAULT_FRAME_ID;
+//}
+
+//uint8_t XBeeRequest::getPayloadOffset() {
+//    return _payloadOffset;
+//}
+//
+//uint8_t XBeeRequest::setPayloadOffset(uint8_t payloadOffset) {
+//    _payloadOffset = payloadOffset;
+//}
+
+
+PayloadRequest::PayloadRequest(uint8_t apiId, uint8_t frameId, uint8_t *payload, uint8_t payloadLength) : XBeeRequest(apiId, frameId) {
+    _payloadPtr = payload;
+    _payloadLength = payloadLength;
+}
+
+uint8_t* PayloadRequest::getPayload() {
+    return _payloadPtr;
+}
+
+void PayloadRequest::setPayload(uint8_t* payload) {
+    _payloadPtr = payload;
+}
+
+uint8_t PayloadRequest::getPayloadLength() {
+    return _payloadLength;
+}
+
+void PayloadRequest::setPayloadLength(uint8_t payloadLength) {
+    _payloadLength = payloadLength;
+}
+
+
+XBeeAddress::XBeeAddress() {
+
+}
+
+XBeeAddress64::XBeeAddress64() : XBeeAddress() {
+
+}
+
+XBeeAddress64::XBeeAddress64(uint32_t msb, uint32_t lsb) : XBeeAddress() {
+    _msb = msb;
+    _lsb = lsb;
+}
+
+uint32_t XBeeAddress64::getMsb() {
+    return _msb;
+}
+
+void XBeeAddress64::setMsb(uint32_t msb) {
+    _msb = msb;
+}
+
+uint32_t XBeeAddress64::getLsb() {
+    return _lsb;
+}
+
+void XBeeAddress64::setLsb(uint32_t lsb) {
+    _lsb = lsb;
+}
+
+
+#ifdef SERIES_2
+
+ZBTxRequest::ZBTxRequest() : PayloadRequest(ZB_TX_REQUEST, DEFAULT_FRAME_ID, NULL, 0) {
+
+}
+
+ZBTxRequest::ZBTxRequest(XBeeAddress64 &addr64, uint16_t addr16, uint8_t broadcastRadius, uint8_t option, uint8_t *data, uint8_t dataLength, uint8_t frameId): PayloadRequest(ZB_TX_REQUEST, frameId, data, dataLength) {
+    _addr64 = addr64;
+    _addr16 = addr16;
+    _broadcastRadius = broadcastRadius;
+    _option = option;
+}
+
+ZBTxRequest::ZBTxRequest(XBeeAddress64 &addr64, uint8_t *data, uint8_t dataLength): PayloadRequest(ZB_TX_REQUEST, DEFAULT_FRAME_ID, data, dataLength) {
+    _addr64 = addr64;
+    _addr16 = ZB_BROADCAST_ADDRESS;
+    _broadcastRadius = ZB_BROADCAST_RADIUS_MAX_HOPS;
+    _option = ZB_TX_UNICAST;
+}
+
+uint8_t ZBTxRequest::getFrameData(uint8_t pos) {
+    if (pos == 0) {
+        return (_addr64.getMsb() >> 24) & 0xff;
+    } else if (pos == 1) {
+        return (_addr64.getMsb() >> 16) & 0xff;
+    } else if (pos == 2) {
+        return (_addr64.getMsb() >> 8) & 0xff;
+    } else if (pos == 3) {
+        return _addr64.getMsb() & 0xff;
+    } else if (pos == 4) {
+        return (_addr64.getLsb() >> 24) & 0xff;
+    } else if (pos == 5) {
+        return  (_addr64.getLsb() >> 16) & 0xff;
+    } else if (pos == 6) {
+        return (_addr64.getLsb() >> 8) & 0xff;
+    } else if (pos == 7) {
+        return _addr64.getLsb() & 0xff;
+    } else if (pos == 8) {
+        return (_addr16 >> 8) & 0xff;
+    } else if (pos == 9) {
+        return _addr16 & 0xff;
+    } else if (pos == 10) {
+        return _broadcastRadius;
+    } else if (pos == 11) {
+        return _option;
+    } else {
+        return getPayload()[pos - ZB_TX_API_LENGTH];
+    }
+}
+
+uint8_t ZBTxRequest::getFrameDataLength() {
+    return ZB_TX_API_LENGTH + getPayloadLength();
+}
+
+XBeeAddress64& ZBTxRequest::getAddress64() {
+    return _addr64;
+}
+
+uint16_t ZBTxRequest::getAddress16() {
+    return _addr16;
+}
+
+uint8_t ZBTxRequest::getBroadcastRadius() {
+    return _broadcastRadius;
+}
+
+uint8_t ZBTxRequest::getOption() {
+    return _option;
+}
+
+void ZBTxRequest::setAddress64(XBeeAddress64& addr64) {
+    _addr64 = addr64;
+}
+
+void ZBTxRequest::setAddress16(uint16_t addr16) {
+    _addr16 = addr16;
+}
+
+void ZBTxRequest::setBroadcastRadius(uint8_t broadcastRadius) {
+    _broadcastRadius = broadcastRadius;
+}
+
+void ZBTxRequest::setOption(uint8_t option) {
+    _option = option;
+}
+
+#endif
+
+#ifdef SERIES_1
+
+Tx16Request::Tx16Request() : PayloadRequest(TX_16_REQUEST, DEFAULT_FRAME_ID, NULL, 0) {
+
+}
+
+Tx16Request::Tx16Request(uint16_t addr16, uint8_t option, uint8_t *data, uint8_t dataLength, uint8_t frameId) : PayloadRequest(TX_16_REQUEST, frameId, data, dataLength) {
+    _addr16 = addr16;
+    _option = option;
+}
+
+Tx16Request::Tx16Request(uint16_t addr16, uint8_t *data, uint8_t dataLength) : PayloadRequest(TX_16_REQUEST, DEFAULT_FRAME_ID, data, dataLength) {
+    _addr16 = addr16;
+    _option = ACK_OPTION;
+}
+
+uint8_t Tx16Request::getFrameData(uint8_t pos) {
+
+    if (pos == 0) {
+        return (_addr16 >> 8) & 0xff;
+    } else if (pos == 1) {
+        return _addr16 & 0xff;
+    } else if (pos == 2) {
+        return _option;
+    } else {
+        return getPayload()[pos - TX_16_API_LENGTH];
+    }
+}
+
+uint8_t Tx16Request::getFrameDataLength() {
+    return TX_16_API_LENGTH + getPayloadLength();
+}
+
+uint16_t Tx16Request::getAddress16() {
+    return _addr16;
+}
+
+void Tx16Request::setAddress16(uint16_t addr16) {
+    _addr16 = addr16;
+}
+
+uint8_t Tx16Request::getOption() {
+    return _option;
+}
+
+void Tx16Request::setOption(uint8_t option) {
+    _option = option;
+}
+
+Tx64Request::Tx64Request() : PayloadRequest(TX_64_REQUEST, DEFAULT_FRAME_ID, NULL, 0) {
+
+}
+
+Tx64Request::Tx64Request(XBeeAddress64 &addr64, uint8_t option, uint8_t *data, uint8_t dataLength, uint8_t frameId) : PayloadRequest(TX_64_REQUEST, frameId, data, dataLength) {
+    _addr64 = addr64;
+    _option = option;
+}
+
+Tx64Request::Tx64Request(XBeeAddress64 &addr64, uint8_t *data, uint8_t dataLength) : PayloadRequest(TX_64_REQUEST, DEFAULT_FRAME_ID, data, dataLength) {
+    _addr64 = addr64;
+    _option = ACK_OPTION;
+}
+
+uint8_t Tx64Request::getFrameData(uint8_t pos) {
+
+    if (pos == 0) {
+        return (_addr64.getMsb() >> 24) & 0xff;
+    } else if (pos == 1) {
+        return (_addr64.getMsb() >> 16) & 0xff;
+    } else if (pos == 2) {
+        return (_addr64.getMsb() >> 8) & 0xff;
+    } else if (pos == 3) {
+        return _addr64.getMsb() & 0xff;
+    } else if (pos == 4) {
+        return (_addr64.getLsb() >> 24) & 0xff;
+    } else if (pos == 5) {
+        return (_addr64.getLsb() >> 16) & 0xff;
+    } else if (pos == 6) {
+        return(_addr64.getLsb() >> 8) & 0xff;
+    } else if (pos == 7) {
+        return _addr64.getLsb() & 0xff;
+    } else if (pos == 8) {
+        return _option;
+    } else {
+        return getPayload()[pos - TX_64_API_LENGTH];
+    }
+}
+
+uint8_t Tx64Request::getFrameDataLength() {
+    return TX_64_API_LENGTH + getPayloadLength();
+}
+
+XBeeAddress64& Tx64Request::getAddress64() {
+    return _addr64;
+}
+
+void Tx64Request::setAddress64(XBeeAddress64& addr64) {
+    _addr64 = addr64;
+}
+
+uint8_t Tx64Request::getOption() {
+    return _option;
+}
+
+void Tx64Request::setOption(uint8_t option) {
+    _option = option;
+}
+
+#endif
+
+AtCommandRequest::AtCommandRequest() : XBeeRequest(AT_COMMAND_REQUEST, DEFAULT_FRAME_ID) {
+    _command = NULL;
+    clearCommandValue();
+}
+
+AtCommandRequest::AtCommandRequest(uint8_t *command, uint8_t *commandValue, uint8_t commandValueLength) : XBeeRequest(AT_COMMAND_REQUEST, DEFAULT_FRAME_ID) {
+    _command = command;
+    _commandValue = commandValue;
+    _commandValueLength = commandValueLength;
+}
+
+AtCommandRequest::AtCommandRequest(uint8_t *command) : XBeeRequest(AT_COMMAND_REQUEST, DEFAULT_FRAME_ID) {
+    _command = command;
+    clearCommandValue();
+}
+
+uint8_t* AtCommandRequest::getCommand() {
+    return _command;
+}
+
+uint8_t* AtCommandRequest::getCommandValue() {
+    return _commandValue;
+}
+
+uint8_t AtCommandRequest::getCommandValueLength() {
+    return _commandValueLength;
+}
+
+void AtCommandRequest::setCommand(uint8_t* command) {
+    _command = command;
+}
+
+void AtCommandRequest::setCommandValue(uint8_t* value) {
+    _commandValue = value;
+}
+
+void AtCommandRequest::setCommandValueLength(uint8_t length) {
+    _commandValueLength = length;
+}
+
+uint8_t AtCommandRequest::getFrameData(uint8_t pos) {
+
+    if (pos == 0) {
+        return _command[0];
+    } else if (pos == 1) {
+        return _command[1];
+    } else {
+        return _commandValue[pos - AT_COMMAND_API_LENGTH];
+    }
+}
+
+void AtCommandRequest::clearCommandValue() {
+    _commandValue = NULL;
+    _commandValueLength = 0;
+}
+
+//void AtCommandRequest::reset() {
+//     XBeeRequest::reset();
+//}
+
+uint8_t AtCommandRequest::getFrameDataLength() {
+    // command is 2 byte + length of value
+    return AT_COMMAND_API_LENGTH + _commandValueLength;
+}
+
+XBeeAddress64 RemoteAtCommandRequest::broadcastAddress64 = XBeeAddress64(0x0, BROADCAST_ADDRESS);
+
+RemoteAtCommandRequest::RemoteAtCommandRequest() : AtCommandRequest(NULL, NULL, 0) {
+    _remoteAddress16 = 0;
+    _applyChanges = false;
+    setApiId(REMOTE_AT_REQUEST);
+}
+
+RemoteAtCommandRequest::RemoteAtCommandRequest(uint16_t remoteAddress16, uint8_t *command, uint8_t *commandValue, uint8_t commandValueLength) : AtCommandRequest(command, commandValue, commandValueLength) {
+    _remoteAddress64 = broadcastAddress64;
+    _remoteAddress16 = remoteAddress16;
+    _applyChanges = true;
+    setApiId(REMOTE_AT_REQUEST);
+}
+
+RemoteAtCommandRequest::RemoteAtCommandRequest(uint16_t remoteAddress16, uint8_t *command) : AtCommandRequest(command, NULL, 0) {
+    _remoteAddress64 = broadcastAddress64;
+    _remoteAddress16 = remoteAddress16;
+    _applyChanges = false;
+    setApiId(REMOTE_AT_REQUEST);
+}
+
+RemoteAtCommandRequest::RemoteAtCommandRequest(XBeeAddress64 &remoteAddress64, uint8_t *command, uint8_t *commandValue, uint8_t commandValueLength) : AtCommandRequest(command, commandValue, commandValueLength) {
+    _remoteAddress64 = remoteAddress64;
+    // don't worry.. works for series 1 too!
+    _remoteAddress16 = ZB_BROADCAST_ADDRESS;
+    _applyChanges = true;
+    setApiId(REMOTE_AT_REQUEST);
+}
+
+RemoteAtCommandRequest::RemoteAtCommandRequest(XBeeAddress64 &remoteAddress64, uint8_t *command) : AtCommandRequest(command, NULL, 0) {
+    _remoteAddress64 = remoteAddress64;
+    _remoteAddress16 = ZB_BROADCAST_ADDRESS;
+    _applyChanges = false;
+    setApiId(REMOTE_AT_REQUEST);
+}
+
+uint16_t RemoteAtCommandRequest::getRemoteAddress16() {
+    return _remoteAddress16;
+}
+
+void RemoteAtCommandRequest::setRemoteAddress16(uint16_t remoteAddress16) {
+    _remoteAddress16 = remoteAddress16;
+}
+
+XBeeAddress64& RemoteAtCommandRequest::getRemoteAddress64() {
+    return _remoteAddress64;
+}
+
+void RemoteAtCommandRequest::setRemoteAddress64(XBeeAddress64 &remoteAddress64) {
+    _remoteAddress64 = remoteAddress64;
+}
+
+bool RemoteAtCommandRequest::getApplyChanges() {
+    return _applyChanges;
+}
+
+void RemoteAtCommandRequest::setApplyChanges(bool applyChanges) {
+    _applyChanges = applyChanges;
+}
+
+
+uint8_t RemoteAtCommandRequest::getFrameData(uint8_t pos) {
+    if (pos == 0) {
+        return (_remoteAddress64.getMsb() >> 24) & 0xff;
+    } else if (pos == 1) {
+        return (_remoteAddress64.getMsb() >> 16) & 0xff;
+    } else if (pos == 2) {
+        return (_remoteAddress64.getMsb() >> 8) & 0xff;
+    } else if (pos == 3) {
+        return _remoteAddress64.getMsb() & 0xff;
+    } else if (pos == 4) {
+        return (_remoteAddress64.getLsb() >> 24) & 0xff;
+    } else if (pos == 5) {
+        return (_remoteAddress64.getLsb() >> 16) & 0xff;
+    } else if (pos == 6) {
+        return(_remoteAddress64.getLsb() >> 8) & 0xff;
+    } else if (pos == 7) {
+        return _remoteAddress64.getLsb() & 0xff;
+    } else if (pos == 8) {
+        return (_remoteAddress16 >> 8) & 0xff;
+    } else if (pos == 9) {
+        return _remoteAddress16 & 0xff;
+    } else if (pos == 10) {
+        return _applyChanges ? 2: 0;
+    } else if (pos == 11) {
+        return getCommand()[0];
+    } else if (pos == 12) {
+        return getCommand()[1];
+    } else {
+        return getCommandValue()[pos - REMOTE_AT_COMMAND_API_LENGTH];
+    }
+}
+
+uint8_t RemoteAtCommandRequest::getFrameDataLength() {
+    return REMOTE_AT_COMMAND_API_LENGTH + getCommandValueLength();
+}
+
+
+// TODO
+//GenericRequest::GenericRequest(uint8_t* frame, uint8_t len, uint8_t apiId): XBeeRequest(apiId, *(frame), len) {
+//    _frame = frame;
+//}
+
+void XBee::send(XBeeRequest &request) {
+    // the new new deal
+
+    sendByte(START_BYTE, false);
+
+    // send length
+    uint8_t msbLen = ((request.getFrameDataLength() + 2) >> 8) & 0xff;
+    uint8_t lsbLen = (request.getFrameDataLength() + 2) & 0xff;
+
+    sendByte(msbLen, true);
+    sendByte(lsbLen, true);
+
+    // api id
+    sendByte(request.getApiId(), true);
+    sendByte(request.getFrameId(), true);
+
+    uint8_t checksum = 0;
+
+    // compute checksum, start at api id
+    checksum+= request.getApiId();
+    checksum+= request.getFrameId();
+
+    //std::cout << "frame length is " << static_cast<unsigned int>(request.getFrameDataLength()) << std::endl;
+
+    for (int i = 0; i < request.getFrameDataLength(); i++) {
+//        std::cout << "sending byte [" << static_cast<unsigned int>(i) << "] " << std::endl;
+        sendByte(request.getFrameData(i), true);
+        checksum+= request.getFrameData(i);
+    }
+
+    // perform 2s complement
+    checksum = 0xff - checksum;
+
+//    std::cout << "checksum is " << static_cast<unsigned int>(checksum) << std::endl;
+
+    // send checksum
+    sendByte(checksum, true);
+/*
+    // send packet
+    Serial.flush();
+*/
+}
+
+void XBee::sendByte(uint8_t b, bool escape) {
+
+    if (escape && (b == START_BYTE || b == ESCAPE || b == XON || b == XOFF)) {
+//        std::cout << "escaping byte [" << toHexString(b) << "] " << std::endl;
+        _xbee.putc(ESCAPE);
+        _xbee.putc(b ^ 0x20);
+    } else {
+        _xbee.putc(b);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XBee.h	Mon Nov 22 10:51:06 2010 +0000
@@ -0,0 +1,955 @@
+/**
+ * XBee-mbed library
+ * Modified for mbed, 2010 Suga.
+ *
+ *
+ * Copyright (c) 2009 Andrew Rapp. All rights reserved.
+ *
+ * This file is part of XBee-Arduino.
+ *
+ * XBee-Arduino is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * XBee-Arduino is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBee-Arduino.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef XBee_h
+#define XBee_h
+
+#include "mbed.h"
+#include <inttypes.h>
+
+#define SERIES_1
+#define SERIES_2
+
+// set to ATAP value of XBee. AP=2 is recommended
+#define ATAP 2
+
+#define START_BYTE 0x7e
+#define ESCAPE 0x7d
+#define XON 0x11
+#define XOFF 0x13
+
+// This value determines the size of the byte array for receiving RX packets
+// Most users won't be dealing with packets this large so you can adjust this
+// value to reduce memory consumption. But, remember that
+// if a RX packet exceeds this size, it cannot be parsed!
+
+// This value is determined by the largest packet size (100 byte payload + 64-bit address + option byte and rssi byte) of a series 1 radio
+#define MAX_FRAME_DATA_SIZE 110
+
+#define BROADCAST_ADDRESS 0xffff
+#define ZB_BROADCAST_ADDRESS 0xfffe
+
+// the non-variable length of the frame data (not including frame id or api id or variable data size (e.g. payload, at command set value)
+#define ZB_TX_API_LENGTH 12
+#define TX_16_API_LENGTH 3
+#define TX_64_API_LENGTH 9
+#define AT_COMMAND_API_LENGTH 2
+#define REMOTE_AT_COMMAND_API_LENGTH 13
+// start/length(2)/api/frameid/checksum bytes
+#define PACKET_OVERHEAD_LENGTH 6
+// api is always the third byte in packet
+#define API_ID_INDEX 3
+
+// frame position of rssi byte
+#define RX_16_RSSI_OFFSET 2
+#define RX_64_RSSI_OFFSET 8
+
+#define DEFAULT_FRAME_ID 1
+#define NO_RESPONSE_FRAME_ID 0
+
+// TODO put in tx16 class
+#define ACK_OPTION 0
+#define DISABLE_ACK_OPTION 1
+#define BROADCAST_OPTION 4
+
+// RX options
+#define ZB_PACKET_ACKNOWLEDGED 0x01
+#define ZB_BROADCAST_PACKET 0x02
+
+// not everything is implemented!
+/**
+ * Api Id constants
+ */
+#define TX_64_REQUEST 0x0
+#define TX_16_REQUEST 0x1
+#define AT_COMMAND_REQUEST 0x08
+#define AT_COMMAND_QUEUE_REQUEST 0x09
+#define REMOTE_AT_REQUEST 0x17
+#define ZB_TX_REQUEST 0x10
+#define ZB_EXPLICIT_TX_REQUEST 0x11
+#define RX_64_RESPONSE 0x80
+#define RX_16_RESPONSE 0x81
+#define RX_64_IO_RESPONSE 0x82
+#define RX_16_IO_RESPONSE 0x83
+#define AT_RESPONSE 0x88
+#define TX_STATUS_RESPONSE 0x89
+#define MODEM_STATUS_RESPONSE 0x8a
+#define ZB_RX_RESPONSE 0x90
+#define ZB_EXPLICIT_RX_RESPONSE 0x91
+#define ZB_TX_STATUS_RESPONSE 0x8b
+#define ZB_IO_SAMPLE_RESPONSE 0x92
+#define ZB_IO_NODE_IDENTIFIER_RESPONSE 0x95
+#define AT_COMMAND_RESPONSE 0x88
+#define REMOTE_AT_COMMAND_RESPONSE 0x97
+
+
+/**
+ * TX STATUS constants
+ */
+#define    SUCCESS 0x0
+#define CCA_FAILURE 0x2
+#define INVALID_DESTINATION_ENDPOINT_SUCCESS 0x15
+#define    NETWORK_ACK_FAILURE 0x21
+#define NOT_JOINED_TO_NETWORK 0x22
+#define    SELF_ADDRESSED 0x23
+#define ADDRESS_NOT_FOUND 0x24
+#define ROUTE_NOT_FOUND 0x25
+#define PAYLOAD_TOO_LARGE 0x74
+
+// modem status
+#define HARDWARE_RESET 0
+#define WATCHDOG_TIMER_RESET 1
+#define ASSOCIATED 2
+#define DISASSOCIATED 3
+#define SYNCHRONIZATION_LOST 4
+#define COORDINATOR_REALIGNMENT 5
+#define COORDINATOR_STARTED 6
+
+#define ZB_BROADCAST_RADIUS_MAX_HOPS 0
+
+#define ZB_TX_UNICAST 0
+#define ZB_TX_BROADCAST 8
+
+#define AT_OK 0
+#define AT_ERROR  1
+#define AT_INVALID_COMMAND 2
+#define AT_INVALID_PARAMETER 3
+#define AT_NO_RESPONSE 4
+
+#define NO_ERROR 0
+#define CHECKSUM_FAILURE 1
+#define PACKET_EXCEEDS_BYTE_ARRAY_LENGTH 2
+#define UNEXPECTED_START_BYTE 3
+
+/**
+ * The super class of all XBee responses (RX packets)
+ * Users should never attempt to create an instance of this class; instead
+ * create an instance of a subclass
+ * It is recommend to reuse subclasses to conserve memory
+ */
+class XBeeResponse {
+public:
+    //static const int MODEM_STATUS = 0x8a;
+    /**
+     * Default constructor
+     */
+    XBeeResponse();
+    /**
+     * Returns Api Id of the response
+     */
+    uint8_t getApiId();
+    void setApiId(uint8_t apiId);
+    /**
+     * Returns the MSB length of the packet
+     */
+    uint8_t getMsbLength();
+    void setMsbLength(uint8_t msbLength);
+    /**
+     * Returns the LSB length of the packet
+     */
+    uint8_t getLsbLength();
+    void setLsbLength(uint8_t lsbLength);
+    /**
+     * Returns the packet checksum
+     */
+    uint8_t getChecksum();
+    void setChecksum(uint8_t checksum);
+    /**
+     * Returns the length of the frame data: all bytes after the api id, and prior to the checksum
+     * Note up to release 0.1.2, this was incorrectly including the checksum in the length.
+     */
+    uint8_t getFrameDataLength();
+    void setFrameData(uint8_t* frameDataPtr);
+    /**
+     * Returns the buffer that contains the response.
+     * Starts with byte that follows API ID and includes all bytes prior to the checksum
+     * Length is specified by getFrameDataLength()
+     * Note: Unlike Digi's definition of the frame data, this does not start with the API ID..
+     * The reason for this is all responses include an API ID, whereas my frame data
+     * includes only the API specific data.
+     */
+    uint8_t* getFrameData();
+
+    void setFrameLength(uint8_t frameLength);
+    // to support future 65535 byte packets I guess
+    /**
+     * Returns the length of the packet
+     */
+    uint16_t getPacketLength();
+    /**
+     * Resets the response to default values
+     */
+    void reset();
+    /**
+     * Initializes the response
+     */
+    void init();
+#ifdef SERIES_2
+    /**
+     * Call with instance of ZBTxStatusResponse class only if getApiId() == ZB_TX_STATUS_RESPONSE
+     * to populate response
+     */
+    void getZBTxStatusResponse(XBeeResponse &response);
+    /**
+     * Call with instance of ZBRxResponse class only if getApiId() == ZB_RX_RESPONSE
+     * to populate response
+     */
+    void getZBRxResponse(XBeeResponse &response);
+    /**
+     * Call with instance of ZBRxIoSampleResponse class only if getApiId() == ZB_IO_SAMPLE_RESPONSE
+     * to populate response
+     */
+    void getZBRxIoSampleResponse(XBeeResponse &response);
+#endif
+#ifdef SERIES_1
+    /**
+     * Call with instance of TxStatusResponse only if getApiId() == TX_STATUS_RESPONSE
+     */
+    void getTxStatusResponse(XBeeResponse &response);
+    /**
+     * Call with instance of Rx16Response only if getApiId() == RX_16_RESPONSE
+     */
+    void getRx16Response(XBeeResponse &response);
+    /**
+     * Call with instance of Rx64Response only if getApiId() == RX_64_RESPONSE
+     */
+    void getRx64Response(XBeeResponse &response);
+    /**
+     * Call with instance of Rx16IoSampleResponse only if getApiId() == RX_16_IO_RESPONSE
+     */
+    void getRx16IoSampleResponse(XBeeResponse &response);
+    /**
+     * Call with instance of Rx64IoSampleResponse only if getApiId() == RX_64_IO_RESPONSE
+     */
+    void getRx64IoSampleResponse(XBeeResponse &response);
+#endif
+    /**
+     * Call with instance of AtCommandResponse only if getApiId() == AT_COMMAND_RESPONSE
+     */
+    void getAtCommandResponse(XBeeResponse &responses);
+    /**
+     * Call with instance of RemoteAtCommandResponse only if getApiId() == REMOTE_AT_COMMAND_RESPONSE
+     */
+    void getRemoteAtCommandResponse(XBeeResponse &response);
+    /**
+     * Call with instance of ModemStatusResponse only if getApiId() == MODEM_STATUS_RESPONSE
+     */
+    void getModemStatusResponse(XBeeResponse &response);
+    /**
+     * Returns true if the response has been successfully parsed and is complete and ready for use
+     */
+    bool isAvailable();
+    void setAvailable(bool complete);
+    /**
+     * Returns true if the response contains errors
+     */
+    bool isError();
+    /**
+     * Returns an error code, or zero, if successful.
+     * Error codes include: CHECKSUM_FAILURE, PACKET_EXCEEDS_BYTE_ARRAY_LENGTH, UNEXPECTED_START_BYTE
+     */
+    uint8_t getErrorCode();
+    void setErrorCode(uint8_t errorCode);
+protected:
+    // pointer to frameData
+    uint8_t* _frameDataPtr;
+private:
+    void setCommon(XBeeResponse &target);
+    uint8_t _apiId;
+    uint8_t _msbLength;
+    uint8_t _lsbLength;
+    uint8_t _checksum;
+    uint8_t _frameLength;
+    bool _complete;
+    uint8_t _errorCode;
+};
+
+class XBeeAddress {
+public:
+    XBeeAddress();
+};
+
+/**
+ * Represents a 64-bit XBee Address
+ */
+class XBeeAddress64 : public XBeeAddress {
+public:
+    XBeeAddress64(uint32_t msb, uint32_t lsb);
+    XBeeAddress64();
+    uint32_t getMsb();
+    uint32_t getLsb();
+    void setMsb(uint32_t msb);
+    void setLsb(uint32_t lsb);
+private:
+    uint32_t _msb;
+    uint32_t _lsb;
+};
+
+//class XBeeAddress16 : public XBeeAddress {
+//public:
+//    XBeeAddress16(uint16_t addr);
+//    XBeeAddress16();
+//    uint16_t getAddress();
+//    void setAddress(uint16_t addr);
+//private:
+//    uint16_t _addr;
+//};
+
+/**
+ * This class is extended by all Responses that include a frame id
+ */
+class FrameIdResponse : public XBeeResponse {
+public:
+    FrameIdResponse();
+    uint8_t getFrameId();
+private:
+    uint8_t _frameId;
+};
+
+/**
+ * Common functionality for both Series 1 and 2 data RX data packets
+ */
+class RxDataResponse : public XBeeResponse {
+public:
+    RxDataResponse();
+    /**
+     * Returns the specified index of the payload.  The index may be 0 to getDataLength() - 1
+     * This method is deprecated; use uint8_t* getData()
+     */
+    uint8_t getData(int index);
+    /**
+     * Returns the payload array.  This may be accessed from index 0 to getDataLength() - 1
+     */
+    uint8_t* getData();
+    /**
+     * Returns the length of the payload
+     */
+    virtual uint8_t getDataLength() = 0;
+    /**
+     * Returns the position in the frame data where the data begins
+     */
+    virtual uint8_t getDataOffset() = 0;
+};
+
+// getResponse to return the proper subclass:
+// we maintain a pointer to each type of response, when a response is parsed, it is allocated only if NULL
+// can we allocate an object in a function?
+
+#ifdef SERIES_2
+/**
+ * Represents a Series 2 TX status packet
+ */
+class ZBTxStatusResponse : public FrameIdResponse {
+    public:
+        ZBTxStatusResponse();
+        uint16_t getRemoteAddress();
+        uint8_t getTxRetryCount();
+        uint8_t getDeliveryStatus();
+        uint8_t getDiscoveryStatus();
+        bool isSuccess();
+};
+
+/**
+ * Represents a Series 2 RX packet
+ */
+class ZBRxResponse : public RxDataResponse {
+public:
+    ZBRxResponse();
+    XBeeAddress64& getRemoteAddress64();
+    uint16_t getRemoteAddress16();
+    uint8_t getOption();
+    virtual uint8_t getDataLength();
+    // frame position where data starts
+    virtual uint8_t getDataOffset();
+private:
+    XBeeAddress64 _remoteAddress64;
+};
+
+/**
+ * Represents a Series 2 RX I/O Sample packet
+ */
+class ZBRxIoSampleResponse : public ZBRxResponse {
+public:
+    ZBRxIoSampleResponse();
+    bool containsAnalog();
+    bool containsDigital();
+    /**
+     * Returns true if the pin is enabled
+     */
+    bool isAnalogEnabled(uint8_t pin);
+    /**
+     * Returns true if the pin is enabled
+     */
+    bool isDigitalEnabled(uint8_t pin);
+    /**
+     * Returns the 10-bit analog reading of the specified pin.
+     * Valid pins include ADC:xxx.
+     */
+    uint16_t getAnalog(uint8_t pin);
+    /**
+     * Returns true if the specified pin is high/on.
+     * Valid pins include DIO:xxx.
+     */
+    bool isDigitalOn(uint8_t pin);
+    uint8_t getDigitalMaskMsb();
+    uint8_t getDigitalMaskLsb();
+    uint8_t getAnalogMask();
+};
+
+#endif
+
+#ifdef SERIES_1
+/**
+ * Represents a Series 1 TX Status packet
+ */
+class TxStatusResponse : public FrameIdResponse {
+    public:
+        TxStatusResponse();
+        uint8_t getStatus();
+        bool isSuccess();
+};
+
+/**
+ * Represents a Series 1 RX packet
+ */
+class RxResponse : public RxDataResponse {
+public:
+    RxResponse();
+    // remember rssi is negative but this is unsigned byte so it's up to you to convert
+    uint8_t getRssi();
+    uint8_t getOption();
+    bool isAddressBroadcast();
+    bool isPanBroadcast();
+    virtual uint8_t getDataLength();
+    virtual uint8_t getDataOffset();
+    virtual uint8_t getRssiOffset() = 0;
+};
+
+/**
+ * Represents a Series 1 16-bit address RX packet
+ */
+class Rx16Response : public RxResponse {
+public:
+    Rx16Response();
+    virtual uint8_t getRssiOffset();
+    uint16_t getRemoteAddress16();
+protected:
+    uint16_t _remoteAddress;
+};
+
+/**
+ * Represents a Series 1 64-bit address RX packet
+ */
+class Rx64Response : public RxResponse {
+public:
+    Rx64Response();
+    virtual uint8_t getRssiOffset();
+    XBeeAddress64& getRemoteAddress64();
+private:
+    XBeeAddress64 _remoteAddress;
+};
+
+/**
+ * Represents a Series 1 RX I/O Sample packet
+ */
+class RxIoSampleBaseResponse : public RxResponse {
+    public:
+        RxIoSampleBaseResponse();
+        /**
+         * Returns the number of samples in this packet
+         */
+        uint8_t getSampleSize();
+        bool containsAnalog();
+        bool containsDigital();
+        /**
+         * Returns true if the specified analog pin is enabled
+         */
+        bool isAnalogEnabled(uint8_t pin);
+        /**
+         * Returns true if the specified digital pin is enabled
+         */
+        bool isDigitalEnabled(uint8_t pin);
+        /**
+         * Returns the 10-bit analog reading of the specified pin.
+         * Valid pins include ADC:0-5.  Sample index starts at 0
+         */
+        uint16_t getAnalog(uint8_t pin, uint8_t sample);
+        /**
+         * Returns true if the specified pin is high/on.
+         * Valid pins include DIO:0-8.  Sample index starts at 0
+         */
+        bool isDigitalOn(uint8_t pin, uint8_t sample);
+        uint8_t getSampleOffset();
+    private:
+};
+
+class Rx16IoSampleResponse : public RxIoSampleBaseResponse {
+public:
+    Rx16IoSampleResponse();
+    uint16_t getRemoteAddress16();
+    virtual uint8_t getRssiOffset();
+
+};
+
+class Rx64IoSampleResponse : public RxIoSampleBaseResponse {
+public:
+    Rx64IoSampleResponse();
+    XBeeAddress64& getRemoteAddress64();
+    virtual uint8_t getRssiOffset();
+private:
+    XBeeAddress64 _remoteAddress;
+};
+
+#endif
+
+/**
+ * Represents a Modem Status RX packet
+ */
+class ModemStatusResponse : public XBeeResponse {
+public:
+    ModemStatusResponse();
+    uint8_t getStatus();
+};
+
+/**
+ * Represents an AT Command RX packet
+ */
+class AtCommandResponse : public FrameIdResponse {
+    public:
+        AtCommandResponse();
+        /**
+         * Returns an array containing the two character command
+         */
+        uint8_t* getCommand();
+        /**
+         * Returns the command status code.
+         * Zero represents a successful command
+         */
+        uint8_t getStatus();
+        /**
+         * Returns an array containing the command value.
+         * This is only applicable to query commands.
+         */
+        uint8_t* getValue();
+        /**
+         * Returns the length of the command value array.
+         */
+        uint8_t getValueLength();
+        /**
+         * Returns true if status equals AT_OK
+         */
+        bool isOk();
+};
+
+/**
+ * Represents a Remote AT Command RX packet
+ */
+class RemoteAtCommandResponse : public AtCommandResponse {
+    public:
+        RemoteAtCommandResponse();
+        /**
+         * Returns an array containing the two character command
+         */
+        uint8_t* getCommand();
+        /**
+         * Returns the command status code.
+         * Zero represents a successful command
+         */
+        uint8_t getStatus();
+        /**
+         * Returns an array containing the command value.
+         * This is only applicable to query commands.
+         */
+        uint8_t* getValue();
+        /**
+         * Returns the length of the command value array.
+         */
+        uint8_t getValueLength();
+        /**
+         * Returns the 16-bit address of the remote radio
+         */
+        uint16_t getRemoteAddress16();
+        /**
+         * Returns the 64-bit address of the remote radio
+         */
+        XBeeAddress64& getRemoteAddress64();
+        /**
+         * Returns true if command was successful
+         */
+        bool isOk();
+    private:
+        XBeeAddress64 _remoteAddress64;
+};
+
+
+/**
+ * Super class of all XBee requests (TX packets)
+ * Users should never create an instance of this class; instead use an subclass of this class
+ * It is recommended to reuse Subclasses of the class to conserve memory
+ * <p/>
+ * This class allocates a buffer to
+ */
+class XBeeRequest {
+public:
+    /**
+     * Constructor
+     * TODO make protected
+     */
+    XBeeRequest(uint8_t apiId, uint8_t frameId);
+    /**
+     * Sets the frame id.  Must be between 1 and 255 inclusive to get a TX status response.
+     */
+    void setFrameId(uint8_t frameId);
+    /**
+     * Returns the frame id
+     */
+    uint8_t getFrameId();
+    /**
+     * Returns the API id
+     */
+    uint8_t getApiId();
+    // setting = 0 makes this a pure virtual function, meaning the subclass must implement, like abstract in java
+    /**
+     * Starting after the frame id (pos = 0) and up to but not including the checksum
+     * Note: Unlike Digi's definition of the frame data, this does not start with the API ID.
+     * The reason for this is the API ID and Frame ID are common to all requests, whereas my definition of
+     * frame data is only the API specific data.
+     */
+    virtual uint8_t getFrameData(uint8_t pos) = 0;
+    /**
+     * Returns the size of the api frame (not including frame id or api id or checksum).
+     */
+    virtual uint8_t getFrameDataLength() = 0;
+    //void reset();
+protected:
+    void setApiId(uint8_t apiId);
+private:
+    uint8_t _apiId;
+    uint8_t _frameId;
+};
+
+// TODO add reset/clear method since responses are often reused
+/**
+ * Primary interface for communicating with an XBee Radio.
+ * This class provides methods for sending and receiving packets with an XBee radio via the serial port.
+ * The XBee radio must be configured in API (packet) mode (AP=2)
+ * in order to use this software.
+ * <p/>
+ * Since this code is designed to run on a microcontroller, with only one thread, you are responsible for reading the
+ * data off the serial buffer in a timely manner.  This involves a call to a variant of readPacket(...).
+ * If your serial port is receiving data faster than you are reading, you can expect to lose packets.
+ * Arduino only has a 128 byte serial buffer so it can easily overflow if two or more packets arrive
+ * without a call to readPacket(...)
+ * <p/>
+ * In order to conserve resources, this class only supports storing one response packet in memory at a time.
+ * This means that you must fully consume the packet prior to calling readPacket(...), because calling
+ * readPacket(...) overwrites the previous response.
+ * <p/>
+ * This class creates an array of size MAX_FRAME_DATA_SIZE for storing the response packet.  You may want
+ * to adjust this value to conserve memory.
+ *
+ * \author Andrew Rapp
+ */
+class XBee : public Base {
+public:
+    XBee(PinName p_tx, PinName p_rx);
+    // for eclipse dev only
+//    void setSerial(HardwareSerial serial);
+    /**
+     * Reads all available serial bytes until a packet is parsed, an error occurs, or the buffer is empty.
+     * You may call <i>xbee</i>.getResponse().isAvailable() after calling this method to determine if
+     * a packet is ready, or <i>xbee</i>.getResponse().isError() to determine if
+     * a error occurred.
+     * <p/>
+     * This method should always return quickly since it does not wait for serial data to arrive.
+     * You will want to use this method if you are doing other timely stuff in your loop, where
+     * a delay would cause problems.
+     * NOTE: calling this method resets the current response, so make sure you first consume the
+     * current response
+     */
+    void readPacket();
+    /**
+     * Waits a maximum of <i>timeout</i> milliseconds for a response packet before timing out; returns true if packet is read.
+     * Returns false if timeout or error occurs.
+     */
+    bool readPacket(int timeout);
+    /**
+     * Reads until a packet is received or an error occurs.
+     * Caution: use this carefully since if you don't get a response, your Arduino code will hang on this
+     * call forever!! often it's better to use a timeout: readPacket(int)
+     */
+    void readPacketUntilAvailable();
+    /**
+     * Starts the serial connection at the supplied baud rate
+     */
+    void begin(long baud);
+    void getResponse(XBeeResponse &response);
+    /**
+     * Returns a reference to the current response
+     * Note: once readPacket is called again this response will be overwritten!
+     */
+    XBeeResponse& getResponse();
+    /**
+     * Sends a XBeeRequest (TX packet) out the serial port
+     */
+    void send(XBeeRequest &request);
+    //uint8_t sendAndWaitForResponse(XBeeRequest &request, int timeout);
+    /**
+     * Returns a sequential frame id between 1 and 255
+     */
+    uint8_t getNextFrameId();
+private:
+    Serial _xbee;
+    void sendByte(uint8_t b, bool escape);
+    void resetResponse();
+    XBeeResponse _response;
+    bool _escape;
+    // current packet position for response.  just a state variable for packet parsing and has no relevance for the response otherwise
+    uint8_t _pos;
+    // last byte read
+    uint8_t b;
+    uint8_t _checksumTotal;
+    uint8_t _nextFrameId;
+    // buffer for incoming RX packets.  holds only the api specific frame data, starting after the api id byte and prior to checksum
+    uint8_t _responseFrameData[MAX_FRAME_DATA_SIZE];
+};
+
+/**
+ * All TX packets that support payloads extend this class
+ */
+class PayloadRequest : public XBeeRequest {
+public:
+    PayloadRequest(uint8_t apiId, uint8_t frameId, uint8_t *payload, uint8_t payloadLength);
+    /**
+     * Returns the payload of the packet, if not null
+     */
+    uint8_t* getPayload();
+    /**
+     * Sets the payload array
+     */
+    void setPayload(uint8_t* payloadPtr);
+    /**
+     * Returns the length of the payload array, as specified by the user.
+     */
+    uint8_t getPayloadLength();
+    /**
+     * Sets the length of the payload to include in the request.  For example if the payload array
+     * is 50 bytes and you only want the first 10 to be included in the packet, set the length to 10.
+     * Length must be <= to the array length.
+     */
+    void setPayloadLength(uint8_t payloadLength);
+private:
+    uint8_t* _payloadPtr;
+    uint8_t _payloadLength;
+};
+
+#ifdef SERIES_1
+
+/**
+ * Represents a Series 1 TX packet that corresponds to Api Id: TX_16_REQUEST
+ * <p/>
+ * Be careful not to send a data array larger than the max packet size of your radio.
+ * This class does not perform any validation of packet size and there will be no indication
+ * if the packet is too large, other than you will not get a TX Status response.
+ * The datasheet says 100 bytes is the maximum, although that could change in future firmware.
+ */
+class Tx16Request : public PayloadRequest {
+public:
+    Tx16Request(uint16_t addr16, uint8_t option, uint8_t *payload, uint8_t payloadLength, uint8_t frameId);
+    /**
+     * Creates a Unicast Tx16Request with the ACK option and DEFAULT_FRAME_ID
+     */
+    Tx16Request(uint16_t addr16, uint8_t *payload, uint8_t payloadLength);
+    /**
+     * Creates a default instance of this class.  At a minimum you must specify
+     * a payload, payload length and a destination address before sending this request.
+     */
+    Tx16Request();
+    uint16_t getAddress16();
+    void setAddress16(uint16_t addr16);
+    uint8_t getOption();
+    void setOption(uint8_t option);
+    virtual uint8_t getFrameData(uint8_t pos);
+    virtual uint8_t getFrameDataLength();
+protected:
+private:
+    uint16_t _addr16;
+    uint8_t _option;
+};
+
+/**
+ * Represents a Series 1 TX packet that corresponds to Api Id: TX_64_REQUEST
+ *
+ * Be careful not to send a data array larger than the max packet size of your radio.
+ * This class does not perform any validation of packet size and there will be no indication
+ * if the packet is too large, other than you will not get a TX Status response.
+ * The datasheet says 100 bytes is the maximum, although that could change in future firmware.
+ */
+class Tx64Request : public PayloadRequest {
+public:
+    Tx64Request(XBeeAddress64 &addr64, uint8_t option, uint8_t *payload, uint8_t payloadLength, uint8_t frameId);
+    /**
+     * Creates a unicast Tx64Request with the ACK option and DEFAULT_FRAME_ID
+     */
+    Tx64Request(XBeeAddress64 &addr64, uint8_t *payload, uint8_t payloadLength);
+    /**
+     * Creates a default instance of this class.  At a minimum you must specify
+     * a payload, payload length and a destination address before sending this request.
+     */
+    Tx64Request();
+    XBeeAddress64& getAddress64();
+    void setAddress64(XBeeAddress64& addr64);
+    // TODO move option to superclass
+    uint8_t getOption();
+    void setOption(uint8_t option);
+    virtual uint8_t getFrameData(uint8_t pos);
+    virtual uint8_t getFrameDataLength();
+private:
+    XBeeAddress64 _addr64;
+    uint8_t _option;
+};
+
+#endif
+
+
+#ifdef SERIES_2
+
+/**
+ * Represents a Series 2 TX packet that corresponds to Api Id: ZB_TX_REQUEST
+ *
+ * Be careful not to send a data array larger than the max packet size of your radio.
+ * This class does not perform any validation of packet size and there will be no indication
+ * if the packet is too large, other than you will not get a TX Status response.
+ * The datasheet says 72 bytes is the maximum for ZNet firmware and ZB Pro firmware provides
+ * the ATNP command to get the max supported payload size.  This command is useful since the
+ * maximum payload size varies according to certain settings, such as encryption.
+ * ZB Pro firmware provides a PAYLOAD_TOO_LARGE that is returned if payload size
+ * exceeds the maximum.
+ */
+class ZBTxRequest : public PayloadRequest {
+public:
+    /**
+     * Creates a unicast ZBTxRequest with the ACK option and DEFAULT_FRAME_ID
+     */
+    ZBTxRequest(XBeeAddress64 &addr64, uint8_t *payload, uint8_t payloadLength);
+    ZBTxRequest(XBeeAddress64 &addr64, uint16_t addr16, uint8_t broadcastRadius, uint8_t option, uint8_t *payload, uint8_t payloadLength, uint8_t frameId);
+    /**
+     * Creates a default instance of this class.  At a minimum you must specify
+     * a payload, payload length and a destination address before sending this request.
+     */
+    ZBTxRequest();
+    XBeeAddress64& getAddress64();
+    uint16_t getAddress16();
+    uint8_t getBroadcastRadius();
+    uint8_t getOption();
+    void setAddress64(XBeeAddress64& addr64);
+    void setAddress16(uint16_t addr16);
+    void setBroadcastRadius(uint8_t broadcastRadius);
+    void setOption(uint8_t option);
+protected:
+    // declare virtual functions
+    virtual uint8_t getFrameData(uint8_t pos);
+    virtual uint8_t getFrameDataLength();
+private:
+    XBeeAddress64 _addr64;
+    uint16_t _addr16;
+    uint8_t _broadcastRadius;
+    uint8_t _option;
+};
+
+#endif
+
+/**
+ * Represents an AT Command TX packet
+ * The command is used to configure the serially connected XBee radio
+ */
+class AtCommandRequest : public XBeeRequest {
+public:
+    AtCommandRequest();
+    AtCommandRequest(uint8_t *command);
+    AtCommandRequest(uint8_t *command, uint8_t *commandValue, uint8_t commandValueLength);
+    virtual uint8_t getFrameData(uint8_t pos);
+    virtual uint8_t getFrameDataLength();
+    uint8_t* getCommand();
+    void setCommand(uint8_t* command);
+    uint8_t* getCommandValue();
+    void setCommandValue(uint8_t* command);
+    uint8_t getCommandValueLength();
+    void setCommandValueLength(uint8_t length);
+    /**
+     * Clears the optional commandValue and commandValueLength so that a query may be sent
+     */
+    void clearCommandValue();
+    //void reset();
+private:
+    uint8_t *_command;
+    uint8_t *_commandValue;
+    uint8_t _commandValueLength;
+};
+
+/**
+ * Represents an Remote AT Command TX packet
+ * The command is used to configure a remote XBee radio
+ */
+class RemoteAtCommandRequest : public AtCommandRequest {
+public:
+    RemoteAtCommandRequest();
+    /**
+     * Creates a RemoteAtCommandRequest with 16-bit address to set a command.
+     * 64-bit address defaults to broadcast and applyChanges is true.
+     */
+    RemoteAtCommandRequest(uint16_t remoteAddress16, uint8_t *command, uint8_t *commandValue, uint8_t commandValueLength);
+    /**
+     * Creates a RemoteAtCommandRequest with 16-bit address to query a command.
+     * 64-bit address defaults to broadcast and applyChanges is true.
+     */
+    RemoteAtCommandRequest(uint16_t remoteAddress16, uint8_t *command);
+    /**
+     * Creates a RemoteAtCommandRequest with 64-bit address to set a command.
+     * 16-bit address defaults to broadcast and applyChanges is true.
+     */
+    RemoteAtCommandRequest(XBeeAddress64 &remoteAddress64, uint8_t *command, uint8_t *commandValue, uint8_t commandValueLength);
+    /**
+     * Creates a RemoteAtCommandRequest with 16-bit address to query a command.
+     * 16-bit address defaults to broadcast and applyChanges is true.
+     */
+    RemoteAtCommandRequest(XBeeAddress64 &remoteAddress64, uint8_t *command);
+    uint16_t getRemoteAddress16();
+    void setRemoteAddress16(uint16_t remoteAddress16);
+    XBeeAddress64& getRemoteAddress64();
+    void setRemoteAddress64(XBeeAddress64 &remoteAddress64);
+    bool getApplyChanges();
+    void setApplyChanges(bool applyChanges);
+    virtual uint8_t getFrameData(uint8_t pos);
+    virtual uint8_t getFrameDataLength();
+    static XBeeAddress64 broadcastAddress64;
+//    static uint16_t broadcast16Address;
+private:
+    XBeeAddress64 _remoteAddress64;
+    uint16_t _remoteAddress16;
+    bool _applyChanges;
+};
+
+
+
+#endif //XBee_h