Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of XBee by
XBee.cpp
- Committer:
- FalconOnishi
- Date:
- 2013-01-18
- Revision:
- 6:dc1f35defd71
- Parent:
- 4:f6d73acc1f75
File content as of revision 6:dc1f35defd71:
/** * XBee-mbed library * Modified for mbed, 2011 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/>. */ /** @file * @brief XBee library for mbed */ #define DEBUG #include "dbg.h" #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; } uint16_t XBeeResponse::getFrameDataLength() { return _frameLength; } void XBeeResponse::setFrameLength(uint16_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; } uint16_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)) { if (isAnalogEnabled(i)) { 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; } uint16_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; } uint16_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]; } uint16_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 ((uint16_t)_msbLength << 8) + _lsbLength; } 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; _epos = 0; _escape = false; _checksumTotal = 0; _response.reset(); } XBee::XBee(PinName p_tx, PinName p_rx): _xbee(p_tx, p_rx) { _pos = 0; _epos = 0; _escape = false; _checksumTotal = 0; _nextFrameId = 0; _response.init(); _response.setFrameData(_responseFrameData); } XBee::XBee(PinName p_tx, PinName p_rx, PinName p_cts, PinName p_rts): _xbee(p_tx, p_rx) { _pos = 0; _epos = 0; _escape = false; _checksumTotal = 0; _nextFrameId = 0; #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) if (p_cts == p12) { // CTS (P0_17) LPC_UART1->MCR |= (1<<7); // CTSEN LPC_PINCON->PINSEL1 &= ~(3 << 2); LPC_PINCON->PINSEL1 |= (1 << 2); // UART CTS } if (p_rts == P0_22) { // RTS (P0_22) LPC_UART1->MCR |= (1<<6); // RTSEN LPC_PINCON->PINSEL1 &= ~(3 << 12); LPC_PINCON->PINSEL1 |= (1 << 12); // UART RTS _xbee.attach(this, &XBee::isr_recv, Serial::RxIrq); _rts = true; } else { _rts = false; } #elif defined(TARGET_LPC11U24) if (p_cts == p21) { // CTS (P0_7) LPC_UART->MCR = (1<<7); // CTSEN LPC_IOCON->PIO0_7 &= ~0x07; LPC_IOCON->PIO0_7 |= 0x01; // UART CTS } if (p_rts == p22) { // RTS (P0_17) LPC_UART->MCR = (1<<6); // RTSEN LPC_IOCON->PIO0_17 &= ~0x07; LPC_IOCON->PIO0_17 |= 0x01; // UART RTS _xbee.attach(this, &XBee::isr_recv, Serial::RxIrq); _rts = true; } else { _rts = false; } #endif _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.reset(); t.start(); while (t.read_ms() < timeout) { readPacket(); if (getResponse().isAvailable()) { t.stop(); return true; } else if (getResponse().isError()) { t.stop(); return false; } } DBG("(timeout %d %d)\r\n", _pos, _epos); // timed out t.stop(); return false; } void XBee::isr_recv () { _rxbuf[_rxaddr_w] = _xbee.getc(); _rxaddr_w = (_rxaddr_w + 1) % MAX_RXBUF_SIZE; } int XBee::getbuf () { int r; __disable_irq(); r = _rxbuf[_rxaddr_r]; _rxaddr_r = (_rxaddr_r + 1) % MAX_RXBUF_SIZE; __enable_irq(); return r; } int XBee::bufreadable () { return _rxaddr_w != _rxaddr_r; } void XBee::readPacket() { // reset previous response if (_response.isAvailable() || _response.isError()) { // discard previous packet and start over resetResponse(); } // while (_xbee.readable()) { while ((! _rts && _xbee.readable()) || (_rts && bufreadable())) { // b = _xbee.getc(); if (_rts) { b = getbuf(); } else { b = _xbee.getc(); } if (_pos > 0 && b == START_BYTE && ATAP == 2) { // new packet start before previous packeted completed -- discard previous packet and start over DBG("error: %02x %d %d\r\n", b, _pos, _epos); _response.setErrorCode(UNEXPECTED_START_BYTE); return; } if (_pos > 0 && b == ESCAPE) { if (_xbee.readable()) { // b = _xbee.getc(); if (_rts) { b = getbuf(); } else { b = _xbee.getc(); } b = 0x20 ^ b; _epos ++; } else { // escape byte. next byte will be _escape = true; continue; } } //DBG("%02x_", b); if (_escape == true) { b = 0x20 ^ b; _escape = false; _epos ++; } // 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)) { // if (_pos + _epos == (_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 DBG("error: checksum %02x %02x %d %d\r\n", b, _checksumTotal, _pos, _epos); _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; _epos = 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, uint16_t payloadLength) : XBeeRequest(apiId, frameId) { _payloadPtr = payload; _payloadLength = payloadLength; } uint8_t* PayloadRequest::getPayload() { return _payloadPtr; } void PayloadRequest::setPayload(uint8_t* payload) { _payloadPtr = payload; } uint16_t PayloadRequest::getPayloadLength() { return _payloadLength; } void PayloadRequest::setPayloadLength(uint16_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, uint16_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, uint16_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(uint16_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]; } } uint16_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, uint16_t dataLength, uint8_t frameId) : PayloadRequest(TX_16_REQUEST, frameId, data, dataLength) { _addr16 = addr16; _option = option; } Tx16Request::Tx16Request(uint16_t addr16, uint8_t *data, uint16_t dataLength) : PayloadRequest(TX_16_REQUEST, DEFAULT_FRAME_ID, data, dataLength) { _addr16 = addr16; _option = ACK_OPTION; } uint8_t Tx16Request::getFrameData(uint16_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]; } } uint16_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, uint16_t dataLength, uint8_t frameId) : PayloadRequest(TX_64_REQUEST, frameId, data, dataLength) { _addr64 = addr64; _option = option; } Tx64Request::Tx64Request(XBeeAddress64 &addr64, uint8_t *data, uint16_t dataLength) : PayloadRequest(TX_64_REQUEST, DEFAULT_FRAME_ID, data, dataLength) { _addr64 = addr64; _option = ACK_OPTION; } uint8_t Tx64Request::getFrameData(uint16_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]; } } uint16_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(uint16_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(); //} uint16_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(uint16_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]; } } uint16_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 flushSerialBuffer(Serial &device) { char c = 0; while (device.readable()) { c = device.getc(); c = c;//escape warning } return; } 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(); */ flushSerialBuffer(_xbee); // DBG("\r\n"); } 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); } // DBG("%02x ", b); }