XBee - Implemented API mode basics
This commit is contained in:
parent
77ac9533cb
commit
b227d0cd19
4 changed files with 204 additions and 148 deletions
|
@ -22,6 +22,7 @@ SX1277 KEYWORD1
|
|||
SX1278 KEYWORD1
|
||||
SX1279 KEYWORD1
|
||||
XBee KEYWORD1
|
||||
XBeeSerial KEYWORD1
|
||||
|
||||
MQTTClient KEYWORD1
|
||||
HTTPClient KEYWORD1
|
||||
|
@ -70,6 +71,8 @@ reset KEYWORD2
|
|||
# XBee
|
||||
setDestinationAddress KEYWORD2
|
||||
setPanId KEYWORD2
|
||||
getPacketSource KEYWORD2
|
||||
getPacketData KEYWORD2
|
||||
|
||||
# HTTP
|
||||
get KEYWORD2
|
||||
|
@ -136,3 +139,6 @@ MQTT_SUBS_SUCCESS_QOS_2 LITERAL1
|
|||
ERR_MQTT_SUBS_FAILED LITERAL1
|
||||
|
||||
ERR_CMD_MODE_FAILED LITERAL1
|
||||
ERR_FRAME_MALFORMED LITERAL1
|
||||
ERR_FRAME_INCORRECT_CHECKSUM LITERAL1
|
||||
ERR_FRAME_UNEXPECTED_ID LITERAL1
|
||||
|
|
|
@ -94,5 +94,8 @@
|
|||
|
||||
// XBee status codes
|
||||
#define ERR_CMD_MODE_FAILED 0x02
|
||||
#define ERR_FRAME_MALFORMED 0x03
|
||||
#define ERR_FRAME_INCORRECT_CHECKSUM 0x04
|
||||
#define ERR_FRAME_UNEXPECTED_ID 0x05
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,23 +1,88 @@
|
|||
#include "XBee.h"
|
||||
|
||||
XBeeApiFrame::XBeeApiFrame(uint8_t apiId, uint8_t frameId) {
|
||||
_apiId = apiId;
|
||||
_frameId = frameId;
|
||||
}
|
||||
|
||||
XBee::XBee(Module* module) {
|
||||
_mod = module;
|
||||
XBee::XBee(Module* mod) {
|
||||
_mod = mod;
|
||||
_frameID = 0x01;
|
||||
}
|
||||
|
||||
uint8_t XBee::begin(long speed) {
|
||||
// set Arduino pins
|
||||
pinMode(A4, OUTPUT);
|
||||
pinMode(A5, OUTPUT);
|
||||
pinMode(3, OUTPUT);
|
||||
digitalWrite(A4, LOW);
|
||||
digitalWrite(A5, LOW);
|
||||
digitalWrite(3, HIGH);
|
||||
// set module properties
|
||||
_mod->baudrate = speed;
|
||||
_mod->init(USE_UART, INT_NONE);
|
||||
|
||||
// wait for boot
|
||||
delay(2000);
|
||||
|
||||
// empty UART buffer (garbage data)
|
||||
_mod->ATemptyBuffer();
|
||||
|
||||
// send test frame (get baudrate setting)
|
||||
uint8_t frameID = _frameID++;
|
||||
sendApiFrame(XBEE_API_FRAME_AT_COMMAND, frameID, "BD");
|
||||
delay(20);
|
||||
|
||||
// get response code
|
||||
return(readApiFrame(frameID, 4));
|
||||
}
|
||||
|
||||
uint8_t XBee::transmit(uint8_t* dest, const char* payload, uint8_t radius) {
|
||||
uint8_t destNetwork[] = {0xFF, 0xFE};
|
||||
return(transmit(dest, destNetwork, payload));
|
||||
}
|
||||
|
||||
uint8_t XBee::transmit(uint8_t* dest, uint8_t* destNetwork, const char* payload, uint8_t radius) {
|
||||
// build the frame
|
||||
size_t payloadLen = strlen(payload);
|
||||
size_t dataLen = 8 + 2 + 1 + 1 + payloadLen;
|
||||
uint8_t* cmd = new uint8_t[dataLen];
|
||||
memcpy(cmd, dest, 8);
|
||||
memcpy(cmd + 8, destNetwork, 2);
|
||||
cmd[10] = radius;
|
||||
cmd[11] = 0x01; // options: no retries
|
||||
memcpy(cmd + 12, payload, payloadLen);
|
||||
|
||||
// send frame
|
||||
uint8_t frameID = _frameID++;
|
||||
sendApiFrame(XBEE_API_FRAME_ZIGBEE_TRANSMIT_REQUEST, frameID, cmd, dataLen);
|
||||
delete[] cmd;
|
||||
delay(40);
|
||||
|
||||
// get response code
|
||||
return(readApiFrame(frameID, 5));
|
||||
}
|
||||
|
||||
size_t XBee::available() {
|
||||
|
||||
}
|
||||
|
||||
String XBee::getPacketSource() {
|
||||
|
||||
}
|
||||
|
||||
String XBee::getPacketData() {
|
||||
|
||||
}
|
||||
|
||||
uint8_t XBee::setPanId(uint8_t* panId) {
|
||||
// build AT command
|
||||
uint8_t cmd[10];
|
||||
memcpy(cmd, "ID", 2);
|
||||
memcpy(cmd + 2, panId, 8);
|
||||
|
||||
// send frame
|
||||
uint8_t frameID = _frameID++;
|
||||
sendApiFrame(XBEE_API_FRAME_AT_COMMAND, frameID, cmd, 10);
|
||||
delay(40);
|
||||
|
||||
// get response code
|
||||
return(readApiFrame(frameID, 4));
|
||||
}
|
||||
|
||||
XBeeSerial::XBeeSerial(Module* mod) : ISerial(mod) {
|
||||
|
||||
}
|
||||
|
||||
uint8_t XBeeSerial::begin(long speed) {
|
||||
// set module properties
|
||||
_mod->AtLineFeed = "\r";
|
||||
_mod->baudrate = speed;
|
||||
|
@ -44,12 +109,10 @@ uint8_t XBee::begin(long speed) {
|
|||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
uint8_t XBee::setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow) {
|
||||
uint8_t XBeeSerial::setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow) {
|
||||
// enter command mode
|
||||
DEBUG_PRINTLN_STR("Entering command mode ...");
|
||||
if(!enterCmdMode()) {
|
||||
|
@ -87,7 +150,7 @@ uint8_t XBee::setDestinationAddress(const char* destinationAddressHigh, const ch
|
|||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
uint8_t XBee::setPanId(const char* panId) {
|
||||
uint8_t XBeeSerial::setPanId(const char* panId) {
|
||||
// enter command mode
|
||||
DEBUG_PRINTLN_STR("Entering command mode ...");
|
||||
if(!enterCmdMode()) {
|
||||
|
@ -114,7 +177,7 @@ uint8_t XBee::setPanId(const char* panId) {
|
|||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
bool XBee::enterCmdMode() {
|
||||
bool XBeeSerial::enterCmdMode() {
|
||||
for(uint8_t i = 0; i < 10; i++) {
|
||||
delay(1000);
|
||||
|
||||
|
@ -150,120 +213,92 @@ bool XBee::enterCmdMode() {
|
|||
}
|
||||
}
|
||||
|
||||
/*uint8_t XBee::transmit(uint32_t destinationAddressHigh, uint32_t destinationAddressLow, const char* data, uint8_t length) {
|
||||
//build the API frame
|
||||
uint8_t frameLength = length + 12;
|
||||
uint8_t * frameData = new uint8_t[frameLength];
|
||||
|
||||
//set the destination address
|
||||
frameData[0] = (destinationAddressHigh >> 24) & 0xFF;
|
||||
frameData[1] = (destinationAddressHigh >> 16) & 0xFF;
|
||||
frameData[2] = (destinationAddressHigh >> 8) & 0xFF;
|
||||
frameData[3] = destinationAddressHigh & 0xFF;
|
||||
|
||||
frameData[4] = (destinationAddressLow >> 24) & 0xFF;
|
||||
frameData[5] = (destinationAddressLow >> 16) & 0xFF;
|
||||
frameData[6] = (destinationAddressLow >> 8) & 0xFF;
|
||||
frameData[7] = destinationAddressLow & 0xFF;
|
||||
|
||||
//set the destination network address
|
||||
frameData[8] = 0xFF;
|
||||
frameData[9] = 0xFE;
|
||||
|
||||
//set broadcast radius (number of allowed hops, 0 - maximum)
|
||||
frameData[10] = 0x00;
|
||||
|
||||
//set the options
|
||||
frameData[11] = 0x00;
|
||||
|
||||
//copy payload data
|
||||
for(uint8_t i = 0; i < length; i++) {
|
||||
frameData[12 + i] = (uint8_t)data[i];
|
||||
void XBee::sendApiFrame(uint8_t type, uint8_t id, const char* data) {
|
||||
sendApiFrame(type, id, (uint8_t*)data, strlen(data));
|
||||
}
|
||||
|
||||
//send the frame to XBee
|
||||
sendApiFrame(XBEE_API_FRAME_ZIGBEE_TRANSMIT_REQUEST, frameData, frameLength);
|
||||
void XBee::sendApiFrame(uint8_t type, uint8_t id, uint8_t* data, uint16_t length) {
|
||||
// build the API frame
|
||||
size_t frameLength = 1 + 2 + length + 1 + 2;
|
||||
uint8_t* frame = new uint8_t[frameLength];
|
||||
|
||||
frame[0] = 0x7E; // start delimiter
|
||||
frame[1] = ((length + 2) & 0xFF00) >> 8; // length MSB
|
||||
frame[2] = (length + 2) & 0x00FF; // length LSB
|
||||
frame[3] = type; // frame type
|
||||
frame[4] = id; // frame ID
|
||||
memcpy(frame + 5, data, length); // data
|
||||
|
||||
// calculate the checksum
|
||||
uint8_t checksum = 0;
|
||||
for(uint16_t i = 3; i < frameLength - 1; i++) {
|
||||
checksum += frame[i];
|
||||
}
|
||||
frame[5 + length] = 0xFF - checksum;
|
||||
|
||||
// send the frame
|
||||
for(uint16_t i = 0; i < frameLength; i++) {
|
||||
_mod->ModuleSerial->write(frame[i]);
|
||||
}
|
||||
|
||||
// deallocate memory
|
||||
delete frameData;
|
||||
|
||||
//wait for status frame
|
||||
readApiFrame(1000);
|
||||
}*/
|
||||
|
||||
/*void XBee::sendApiFrame(uint8_t apiId, uint8_t* data, uint16_t length) {
|
||||
//send frame start delimiter
|
||||
_mod->ModuleSerial->write(XBEE_API_START);
|
||||
|
||||
//send frame length (API ID, frame ID and data length)
|
||||
write(((length + 2) >> 8) & 0xFF);
|
||||
write((length + 2) & 0xFF);
|
||||
|
||||
//send API ID
|
||||
write(apiId);
|
||||
|
||||
//send default frame ID (value 0x00 would disable some feedback)
|
||||
write(XBEE_API_DEFAULT_FRAME_ID);
|
||||
|
||||
//checksum is calculated from API ID, frame ID and data
|
||||
uint8_t checksum = apiId;
|
||||
checksum += XBEE_API_DEFAULT_FRAME_ID;
|
||||
|
||||
//send the data and calculate checksum
|
||||
for(uint16_t i = 0; i < length; i++) {
|
||||
write(data[i]);
|
||||
checksum += data[i];
|
||||
delete[] frame;
|
||||
}
|
||||
|
||||
//send the checksum
|
||||
checksum = 0xFF - checksum;
|
||||
write(checksum);
|
||||
}*/
|
||||
uint8_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos) {
|
||||
// get number of bytes in response
|
||||
uint16_t numBytes = getNumBytes(10000, 5);
|
||||
if(numBytes == 0) {
|
||||
return(ERR_FRAME_MALFORMED);
|
||||
}
|
||||
|
||||
/*uint8_t XBee::readApiFrame(uint16_t timeout) {
|
||||
//start the timer
|
||||
unsigned long start = millis();
|
||||
// checksum byte is not included in length field
|
||||
numBytes++;
|
||||
|
||||
Serial.println("reading");
|
||||
// read the response
|
||||
uint8_t* resp = new uint8_t[numBytes];
|
||||
for(uint16_t i = 0; i < numBytes; i++) {
|
||||
resp[i] = _mod->ModuleSerial->read();
|
||||
}
|
||||
|
||||
// verify checksum
|
||||
uint8_t checksum = 0;
|
||||
for(uint16_t i = 0; i < numBytes; i++) {
|
||||
checksum += resp[i];
|
||||
}
|
||||
if(checksum != 0xFF) {
|
||||
return(ERR_FRAME_INCORRECT_CHECKSUM);
|
||||
}
|
||||
|
||||
//array to store frame length, type and ID
|
||||
uint8_t header[4];
|
||||
while(millis() - start < timeout) {
|
||||
Serial.println(_mod->ModuleSerial->available());
|
||||
//check buffer for new data
|
||||
while(_mod->ModuleSerial->available()) {
|
||||
// check frame ID
|
||||
if(resp[1] != frameID) {
|
||||
return(ERR_FRAME_UNEXPECTED_ID);
|
||||
}
|
||||
|
||||
uint8_t code = resp[codePos];
|
||||
delete[] resp;
|
||||
return(code);
|
||||
}
|
||||
|
||||
uint16_t XBee::getNumBytes(uint32_t timeout, size_t minBytes) {
|
||||
// wait for available data
|
||||
uint32_t start = millis();
|
||||
while(_mod->ModuleSerial->available() < minBytes) {
|
||||
if(millis() - start >= timeout) {
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
// read response
|
||||
uint8_t resp[3];
|
||||
uint8_t i = 0;
|
||||
while(_mod->ModuleSerial->available() > 0) {
|
||||
uint8_t b = _mod->ModuleSerial->read();
|
||||
|
||||
Serial.write(b);
|
||||
Serial.print('\t');
|
||||
Serial.println(b, HEX);
|
||||
|
||||
if(b == XBEE_API_START) {
|
||||
//received the start character
|
||||
n = 0;
|
||||
} else {
|
||||
n++;
|
||||
}
|
||||
|
||||
//check escaped characters
|
||||
if(b == XBEE_API_ESCAPE) {
|
||||
//wait for the next byte
|
||||
while(!_mod->ModuleSerial->available());
|
||||
|
||||
//resolve the escaped character
|
||||
b =_mod->ModuleSerial->read();
|
||||
b = 0x20 ^ b;
|
||||
resp[i++] = b;
|
||||
if(i == 3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/*void XBee::write(uint8_t b) {
|
||||
if((b == XBEE_API_START) || (b == XBEE_API_ESCAPE) || (b == XBEE_API_XON) || (b == XBEE_API_XOFF)) {
|
||||
_mod->ModuleSerial->write(XBEE_API_ESCAPE);
|
||||
_mod->ModuleSerial->write(b ^ 0x20);
|
||||
} else {
|
||||
_mod->ModuleSerial->write(b);
|
||||
return((resp[1] << 8) | resp[2]);
|
||||
}
|
||||
}*/
|
||||
|
|
|
@ -31,36 +31,48 @@
|
|||
#define XBEE_API_FRAME_ROUTE_RECORD 0xA1
|
||||
#define XBEE_API_FRAME_MANY_TO_ONE_ROUTE_REQUEST 0xA3
|
||||
|
||||
#define XBEE_API_DEFAULT_FRAME_ID 0x01
|
||||
|
||||
class XBeeApiFrame {
|
||||
class XBeeSerial: public ISerial {
|
||||
public:
|
||||
XBeeApiFrame(uint8_t apiId, uint8_t frameId);
|
||||
|
||||
uint8_t getApiId();
|
||||
uint8_t getFrameId();
|
||||
|
||||
private:
|
||||
uint16_t _length;
|
||||
uint8_t _apiId;
|
||||
uint8_t _frameId;
|
||||
uint8_t* _data;
|
||||
};
|
||||
|
||||
class XBee: public ISerial {
|
||||
public:
|
||||
XBee(Module* module);
|
||||
// constructor
|
||||
XBeeSerial(Module* mod);
|
||||
|
||||
// basic methods
|
||||
uint8_t begin(long speed);
|
||||
|
||||
// configuration methods
|
||||
uint8_t setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow);
|
||||
uint8_t setPanId(const char* panId);
|
||||
uint8_t setPanId(const char* panID);
|
||||
|
||||
private:
|
||||
bool enterCmdMode();
|
||||
//void sendApiFrame(uint8_t id, uint8_t* data, uint16_t length);
|
||||
//uint8_t readApiFrame(uint16_t timeout);
|
||||
//void write(uint8_t b);
|
||||
|
||||
};
|
||||
|
||||
class XBee {
|
||||
public:
|
||||
// constructor
|
||||
XBee(Module* mod);
|
||||
|
||||
// basic methods
|
||||
uint8_t begin(long speed);
|
||||
uint8_t transmit(uint8_t* dest, const char* payload, uint8_t radius = 1);
|
||||
uint8_t transmit(uint8_t* dest, uint8_t* destNetwork, const char* payload, uint8_t radius = 1);
|
||||
size_t available();
|
||||
String getPacketSource();
|
||||
String getPacketData();
|
||||
|
||||
// configuration methods
|
||||
uint8_t setPanId(uint8_t* panID);
|
||||
|
||||
private:
|
||||
Module* _mod;
|
||||
uint8_t _frameID;
|
||||
|
||||
void sendApiFrame(uint8_t type, uint8_t id, const char* data);
|
||||
void sendApiFrame(uint8_t type, uint8_t id, uint8_t* data, uint16_t length);
|
||||
uint8_t readApiFrame(uint8_t frameID, uint8_t codePos);
|
||||
|
||||
uint16_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue