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
|
SX1278 KEYWORD1
|
||||||
SX1279 KEYWORD1
|
SX1279 KEYWORD1
|
||||||
XBee KEYWORD1
|
XBee KEYWORD1
|
||||||
|
XBeeSerial KEYWORD1
|
||||||
|
|
||||||
MQTTClient KEYWORD1
|
MQTTClient KEYWORD1
|
||||||
HTTPClient KEYWORD1
|
HTTPClient KEYWORD1
|
||||||
|
@ -70,6 +71,8 @@ reset KEYWORD2
|
||||||
# XBee
|
# XBee
|
||||||
setDestinationAddress KEYWORD2
|
setDestinationAddress KEYWORD2
|
||||||
setPanId KEYWORD2
|
setPanId KEYWORD2
|
||||||
|
getPacketSource KEYWORD2
|
||||||
|
getPacketData KEYWORD2
|
||||||
|
|
||||||
# HTTP
|
# HTTP
|
||||||
get KEYWORD2
|
get KEYWORD2
|
||||||
|
@ -136,3 +139,6 @@ MQTT_SUBS_SUCCESS_QOS_2 LITERAL1
|
||||||
ERR_MQTT_SUBS_FAILED LITERAL1
|
ERR_MQTT_SUBS_FAILED LITERAL1
|
||||||
|
|
||||||
ERR_CMD_MODE_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
|
// XBee status codes
|
||||||
#define ERR_CMD_MODE_FAILED 0x02
|
#define ERR_CMD_MODE_FAILED 0x02
|
||||||
|
#define ERR_FRAME_MALFORMED 0x03
|
||||||
|
#define ERR_FRAME_INCORRECT_CHECKSUM 0x04
|
||||||
|
#define ERR_FRAME_UNEXPECTED_ID 0x05
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,23 +1,88 @@
|
||||||
#include "XBee.h"
|
#include "XBee.h"
|
||||||
|
|
||||||
XBeeApiFrame::XBeeApiFrame(uint8_t apiId, uint8_t frameId) {
|
XBee::XBee(Module* mod) {
|
||||||
_apiId = apiId;
|
_mod = mod;
|
||||||
_frameId = frameId;
|
_frameID = 0x01;
|
||||||
}
|
|
||||||
|
|
||||||
XBee::XBee(Module* module) {
|
|
||||||
_mod = module;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t XBee::begin(long speed) {
|
uint8_t XBee::begin(long speed) {
|
||||||
// set Arduino pins
|
// set module properties
|
||||||
pinMode(A4, OUTPUT);
|
_mod->baudrate = speed;
|
||||||
pinMode(A5, OUTPUT);
|
_mod->init(USE_UART, INT_NONE);
|
||||||
pinMode(3, OUTPUT);
|
|
||||||
digitalWrite(A4, LOW);
|
|
||||||
digitalWrite(A5, LOW);
|
|
||||||
digitalWrite(3, HIGH);
|
|
||||||
|
|
||||||
|
// 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
|
// set module properties
|
||||||
_mod->AtLineFeed = "\r";
|
_mod->AtLineFeed = "\r";
|
||||||
_mod->baudrate = speed;
|
_mod->baudrate = speed;
|
||||||
|
@ -44,12 +109,10 @@ uint8_t XBee::begin(long speed) {
|
||||||
return(ERR_AT_FAILED);
|
return(ERR_AT_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(1000);
|
|
||||||
|
|
||||||
return(ERR_NONE);
|
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
|
// enter command mode
|
||||||
DEBUG_PRINTLN_STR("Entering command mode ...");
|
DEBUG_PRINTLN_STR("Entering command mode ...");
|
||||||
if(!enterCmdMode()) {
|
if(!enterCmdMode()) {
|
||||||
|
@ -87,7 +150,7 @@ uint8_t XBee::setDestinationAddress(const char* destinationAddressHigh, const ch
|
||||||
return(ERR_NONE);
|
return(ERR_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t XBee::setPanId(const char* panId) {
|
uint8_t XBeeSerial::setPanId(const char* panId) {
|
||||||
// enter command mode
|
// enter command mode
|
||||||
DEBUG_PRINTLN_STR("Entering command mode ...");
|
DEBUG_PRINTLN_STR("Entering command mode ...");
|
||||||
if(!enterCmdMode()) {
|
if(!enterCmdMode()) {
|
||||||
|
@ -114,7 +177,7 @@ uint8_t XBee::setPanId(const char* panId) {
|
||||||
return(ERR_NONE);
|
return(ERR_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XBee::enterCmdMode() {
|
bool XBeeSerial::enterCmdMode() {
|
||||||
for(uint8_t i = 0; i < 10; i++) {
|
for(uint8_t i = 0; i < 10; i++) {
|
||||||
delay(1000);
|
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) {
|
void XBee::sendApiFrame(uint8_t type, uint8_t id, const char* data) {
|
||||||
//build the API frame
|
sendApiFrame(type, id, (uint8_t*)data, strlen(data));
|
||||||
uint8_t frameLength = length + 12;
|
}
|
||||||
uint8_t * frameData = new uint8_t[frameLength];
|
|
||||||
|
|
||||||
//set the destination address
|
void XBee::sendApiFrame(uint8_t type, uint8_t id, uint8_t* data, uint16_t length) {
|
||||||
frameData[0] = (destinationAddressHigh >> 24) & 0xFF;
|
// build the API frame
|
||||||
frameData[1] = (destinationAddressHigh >> 16) & 0xFF;
|
size_t frameLength = 1 + 2 + length + 1 + 2;
|
||||||
frameData[2] = (destinationAddressHigh >> 8) & 0xFF;
|
uint8_t* frame = new uint8_t[frameLength];
|
||||||
frameData[3] = destinationAddressHigh & 0xFF;
|
|
||||||
|
|
||||||
frameData[4] = (destinationAddressLow >> 24) & 0xFF;
|
frame[0] = 0x7E; // start delimiter
|
||||||
frameData[5] = (destinationAddressLow >> 16) & 0xFF;
|
frame[1] = ((length + 2) & 0xFF00) >> 8; // length MSB
|
||||||
frameData[6] = (destinationAddressLow >> 8) & 0xFF;
|
frame[2] = (length + 2) & 0x00FF; // length LSB
|
||||||
frameData[7] = destinationAddressLow & 0xFF;
|
frame[3] = type; // frame type
|
||||||
|
frame[4] = id; // frame ID
|
||||||
|
memcpy(frame + 5, data, length); // data
|
||||||
|
|
||||||
//set the destination network address
|
// calculate the checksum
|
||||||
frameData[8] = 0xFF;
|
uint8_t checksum = 0;
|
||||||
frameData[9] = 0xFE;
|
for(uint16_t i = 3; i < frameLength - 1; i++) {
|
||||||
|
checksum += frame[i];
|
||||||
|
}
|
||||||
|
frame[5 + length] = 0xFF - checksum;
|
||||||
|
|
||||||
//set broadcast radius (number of allowed hops, 0 - maximum)
|
// send the frame
|
||||||
frameData[10] = 0x00;
|
for(uint16_t i = 0; i < frameLength; i++) {
|
||||||
|
_mod->ModuleSerial->write(frame[i]);
|
||||||
//set the options
|
|
||||||
frameData[11] = 0x00;
|
|
||||||
|
|
||||||
//copy payload data
|
|
||||||
for(uint8_t i = 0; i < length; i++) {
|
|
||||||
frameData[12 + i] = (uint8_t)data[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//send the frame to XBee
|
// deallocate memory
|
||||||
sendApiFrame(XBEE_API_FRAME_ZIGBEE_TRANSMIT_REQUEST, frameData, frameLength);
|
delete[] frame;
|
||||||
|
}
|
||||||
|
|
||||||
//deallocate memory
|
uint8_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos) {
|
||||||
delete frameData;
|
// get number of bytes in response
|
||||||
|
uint16_t numBytes = getNumBytes(10000, 5);
|
||||||
//wait for status frame
|
if(numBytes == 0) {
|
||||||
readApiFrame(1000);
|
return(ERR_FRAME_MALFORMED);
|
||||||
}*/
|
|
||||||
|
|
||||||
/*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];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//send the checksum
|
// checksum byte is not included in length field
|
||||||
checksum = 0xFF - checksum;
|
numBytes++;
|
||||||
write(checksum);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*uint8_t XBee::readApiFrame(uint16_t timeout) {
|
// read the response
|
||||||
//start the timer
|
uint8_t* resp = new uint8_t[numBytes];
|
||||||
unsigned long start = millis();
|
for(uint16_t i = 0; i < numBytes; i++) {
|
||||||
|
resp[i] = _mod->ModuleSerial->read();
|
||||||
|
}
|
||||||
|
|
||||||
Serial.println("reading");
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check frame ID
|
||||||
|
if(resp[1] != frameID) {
|
||||||
|
return(ERR_FRAME_UNEXPECTED_ID);
|
||||||
|
}
|
||||||
|
|
||||||
//array to store frame length, type and ID
|
uint8_t code = resp[codePos];
|
||||||
uint8_t header[4];
|
delete[] resp;
|
||||||
while(millis() - start < timeout) {
|
return(code);
|
||||||
Serial.println(_mod->ModuleSerial->available());
|
}
|
||||||
//check buffer for new data
|
|
||||||
while(_mod->ModuleSerial->available()) {
|
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();
|
uint8_t b = _mod->ModuleSerial->read();
|
||||||
|
resp[i++] = b;
|
||||||
Serial.write(b);
|
if(i == 3) {
|
||||||
Serial.print('\t');
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*void XBee::write(uint8_t b) {
|
return((resp[1] << 8) | resp[2]);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
#include "ISerial.h"
|
#include "ISerial.h"
|
||||||
#include "TypeDef.h"
|
#include "TypeDef.h"
|
||||||
|
|
||||||
//API reserved characters
|
// API reserved characters
|
||||||
#define XBEE_API_START 0x7E
|
#define XBEE_API_START 0x7E
|
||||||
#define XBEE_API_ESCAPE 0x7D
|
#define XBEE_API_ESCAPE 0x7D
|
||||||
#define XBEE_API_XON 0x11
|
#define XBEE_API_XON 0x11
|
||||||
#define XBEE_API_XOFF 0x13
|
#define XBEE_API_XOFF 0x13
|
||||||
|
|
||||||
//API frame IDs
|
// API frame IDs
|
||||||
#define XBEE_API_FRAME_AT_COMMAND 0x08
|
#define XBEE_API_FRAME_AT_COMMAND 0x08
|
||||||
#define XBEE_API_FRAME_AT_COMMAND_PARAMETER 0x09
|
#define XBEE_API_FRAME_AT_COMMAND_PARAMETER 0x09
|
||||||
#define XBEE_API_FRAME_ZIGBEE_TRANSMIT_REQUEST 0x10
|
#define XBEE_API_FRAME_ZIGBEE_TRANSMIT_REQUEST 0x10
|
||||||
|
@ -31,36 +31,48 @@
|
||||||
#define XBEE_API_FRAME_ROUTE_RECORD 0xA1
|
#define XBEE_API_FRAME_ROUTE_RECORD 0xA1
|
||||||
#define XBEE_API_FRAME_MANY_TO_ONE_ROUTE_REQUEST 0xA3
|
#define XBEE_API_FRAME_MANY_TO_ONE_ROUTE_REQUEST 0xA3
|
||||||
|
|
||||||
#define XBEE_API_DEFAULT_FRAME_ID 0x01
|
class XBeeSerial: public ISerial {
|
||||||
|
|
||||||
class XBeeApiFrame {
|
|
||||||
public:
|
public:
|
||||||
XBeeApiFrame(uint8_t apiId, uint8_t frameId);
|
// constructor
|
||||||
|
XBeeSerial(Module* mod);
|
||||||
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);
|
|
||||||
|
|
||||||
|
// basic methods
|
||||||
uint8_t begin(long speed);
|
uint8_t begin(long speed);
|
||||||
|
|
||||||
|
// configuration methods
|
||||||
uint8_t setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow);
|
uint8_t setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow);
|
||||||
uint8_t setPanId(const char* panId);
|
uint8_t setPanId(const char* panID);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool enterCmdMode();
|
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
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue