Dropped support for ESP8266, HC05, JDY08, HTTP and MQTT

This commit is contained in:
jgromes 2021-11-14 11:29:51 +01:00
parent 5c538f31ea
commit 0d9718a603
28 changed files with 5 additions and 2998 deletions

View file

@ -13,9 +13,6 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
### Supported modules:
* __CC1101__ FSK radio module
* __ESP8266__ WiFi module
* __HC05__ Bluetooth module
* __JDY08__ BLE module
* __LLCC68__ LoRa module
* __nRF24L01__ 2.4 GHz module
* __RF69__ FSK/OOK radio module
@ -26,13 +23,8 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
* __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279)
* __SX128x__ series LoRa/GFSK/BLE/FLRC modules (SX1280, SX1281, SX1282)
* __SX1231__ FSK/OOK radio module
* __XBee__ modules (S2B)
### Supported protocols and digital modes:
* __MQTT__ for modules:
ESP8266
* __HTTP__ for modules:
ESP8266
* __AX.25__ using 2-FSK or AFSK for modules:
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x
* [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules:

View file

@ -1,43 +0,0 @@
/*
RadioLib HC05 Example
This example sends data using HC05 Bluetooth module.
HC05 works exactly like a Serial line, data are sent to the paired device.
The default pairing code for HC05 is 1234 or 1111.
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// HC05 has the following connections:
// TX pin: 9
// RX pin: 8
HC05 bluetooth = new SerialModule(9, 8);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//HC05 bluetooth = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize HC05
// baudrate: 9600 baud
bluetooth.begin(9600);
}
void loop() {
// HC05 supports all methods of the Serial class
// read data incoming from Serial port and write them to Bluetooth
while (Serial.available() > 0) {
bluetooth.write(Serial.read());
}
// read data incoming from Bluetooth and write them to Serial port
while (bluetooth.available() > 0) {
Serial.write(bluetooth.read());
}
}

View file

@ -1,83 +0,0 @@
/*
RadioLib HTTP GET Example
This example sends HTTP GET request using ESP8266 WiFi module.
Please note that the response will be saved including header. HTTP header size
can easily exceed Arduino resources and cause the program to behave erratically.
IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
AT firmware (can be found in the /extras folder of the library)!
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// ESP8266 has the following connections:
// TX pin: 9
// RX pin: 8
ESP8266 wifi = new SerialModule(9, 8);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//ESP8266 wifi = RadioShield.ModuleA;
// create HTTP client instance using the wifi module
// the default port used for HTTP is 80
HTTPClient http(&wifi, 80);
void setup() {
Serial.begin(9600);
// initialize ESP8266
Serial.print(F("[ESP8266] Initializing ... "));
// baudrate: 9600 baud
int state = wifi.begin(9600);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// join access point
Serial.print(F("[ESP8266] Joining AP ... "));
// name: SSID
// password: password
state = wifi.join("SSID", "password");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
// send HTTP GET request to www.httpbin.org/ip
// the response will contain origin IP address of the request
String response;
Serial.print(F("[ESP8266] Sending HTTP GET request ... "));
// URL: www.httpbin.org/ip
int http_code = http.get("www.httpbin.org/ip", response);
if (http_code > 0) {
Serial.print(F("HTTP code "));
Serial.println(http_code);
Serial.print(F("[ESP8266] Response is "));
Serial.print(response.length());
Serial.println(F(" bytes long."));
Serial.println(response);
} else {
Serial.print(F("failed, code "));
Serial.println(http_code);
}
// wait for a second before sending new request
delay(1000);
}

View file

@ -1,86 +0,0 @@
/*
RadioLib HTTP POST Example
This example sends HTTP POST request using ESP8266 WiFi module.
Please note that the response will be saved including header. HTTP header size
can easily exceed Arduino resources and cause the program to behave erratically.
IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
AT firmware (can be found in the /extras folder of the library)!
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// ESP8266 has the following connections:
// TX pin: 9
// RX pin: 8
ESP8266 wifi = new SerialModule(9, 8);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//ESP8266 wifi = RadioShield.ModuleA;
// create HTTP client instance using the wifi module
// the default port used for HTTP is 80
HTTPClient http(&wifi, 80);
void setup() {
Serial.begin(9600);
// initialize ESP8266
Serial.print(F("[ESP8266] Initializing ... "));
// baudrate: 9600 baud
int state = wifi.begin(9600);
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// join access point
Serial.print(F("[ESP8266] Joining AP ... "));
// name: SSID
// password: password
state = wifi.join("SSID", "password");
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
// send HTTP POST request to www.httpbin.org/status/404
// the server doesn't process the posted data, it just returns
// response with the status code 404
String response;
Serial.print(F("[ESP8266] Sending HTTP POST request ... "));
// URL: www.httpbin.org/status/404
// content: str
// content type: text/plain
int http_code = http.post("www.httpbin.org/status/404", "str", response);
if(http_code > 0) {
Serial.print(F("HTTP code "));
Serial.println(http_code);
Serial.print(F("[ESP8266] Response is "));
Serial.print(response.length());
Serial.println(F(" bytes long."));
Serial.println(response);
} else {
Serial.print(F("failed, code "));
Serial.println(http_code);
}
// wait for a second before sending new request
delay(1000);
}

View file

@ -1,42 +0,0 @@
/*
RadioLib JDY08 Example
This example sends data using JDY08 Bluetooth module.
JDY08 works exactly like a Serial line, data are sent to the paired device.
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// JDY08 has the following connections:
// TX pin: 9
// RX pin: 8
JDY08 ble = new SerialModule(9, 8);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//JDY08 ble = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize JDY08
// baudrate: 9600 baud
ble.begin(9600);
}
void loop() {
// JDY08 supports all methods of the Serial class
// read data incoming from Serial port and write them to Bluetooth
while (Serial.available() > 0) {
ble.write(Serial.read());
}
// read data incoming from Bluetooth and write them to Serial port
while (ble.available() > 0) {
Serial.write(ble.read());
}
}

View file

@ -1,91 +0,0 @@
/*
RadioLib MQTT Publish Example
This example publishes MQTT messages using ESP8266 WiFi module.
The messages are published to https://shiftr.io/try. You can use this namespace
for testing purposes, but remember that it is publicly accessible!
IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
AT firmware (can be found in the /extras folder of the library)!
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// ESP8266 has the following connections:
// TX pin: 9
// RX pin: 8
ESP8266 wifi = new SerialModule(9, 8);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//ESP8266 wifi = RadioShield.ModuleA;
// create MQTT client instance using the wifi module
// the default port used for MQTT is 1883
MQTTClient mqtt(&wifi, 1883);
void setup() {
Serial.begin(9600);
// initialize ESP8266
Serial.print(F("[ESP8266] Initializing ... "));
// baudrate: 9600 baud
int state = wifi.begin(9600);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// join access point
Serial.print(F("[ESP8266] Joining AP ... "));
// name: SSID
// password: password
state = wifi.join("SSID", "password");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// connect to MQTT server
Serial.print(F("[ESP8266] Connecting to MQTT server ... "));
// server URL: broker.shiftr.io
// client ID: arduino
// username: try
// password: try
state = mqtt.connect("broker.shiftr.io", "arduino", "try", "try");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
// publish MQTT message
Serial.print(F("[ESP8266] Publishing MQTT message ... "));
// topic name: hello
// application message: world
int state = mqtt.publish("hello", "world");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
// wait for a second before publishing again
delay(1000);
}

View file

@ -1,128 +0,0 @@
/*
RadioLib MQTT Subscribe Example
This example subscribes to MQTT topic using ESP8266 WiFi module.
The messages are pulled from https://shiftr.io/try. You can use this namespace
for testing purposes, but remember that it is publicly accessible!
IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
AT firmware (can be found in the /extras folder of the library)!
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// ESP8266 has the following connections:
// TX pin: 9
// RX pin: 8
ESP8266 wifi = new SerialModule(9, 8);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//ESP8266 wifi = RadioShield.ModuleA;
// create MQTT client instance using the wifi module
// the default port used for MQTT is 1883
MQTTClient mqtt(&wifi, 1883);
void setup() {
Serial.begin(9600);
// initialize ESP8266
Serial.print(F("[ESP8266] Initializing ... "));
// baudrate: 9600 baud
int state = wifi.begin(9600);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// join access point
Serial.print(F("[ESP8266] Joining AP ... "));
// name: SSID
// password: password
state = wifi.join("SSID", "password");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// connect to MQTT server
Serial.print(F("[ESP8266] Connecting to MQTT server ... "));
// server URL: broker.shiftr.io
// client ID: arduino
// username: try
// password: try
state = mqtt.connect("broker.shiftr.io", "arduino", "try", "try");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// subscribe to MQTT topic
// after calling this method, server will send PUBLISH packets
// to this client each time a new message was published at the topic
Serial.print(F("[ESP8266] Subscribing to MQTT topic ... "));
// topic name: hello
state = mqtt.subscribe("hello");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
// unsubscribe from MQTT topic
// after calling this method, server will stop sending PUBLISH packets
Serial.print(F("[ESP8266] Unsubscribing from MQTT topic ... "));
// topic filter: hello
state = mqtt.unsubscribe("hello");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
}
// create a function that will be called when a new PUBLISH packet
// arrives from the server
//
// IMPORTANT: This function MUST have two C-strings as arguments!
void onPublish(const char* topic, const char* message) {
Serial.println(F("[ESP8266] Received packet from MQTT server: "));
Serial.print(F("[ESP8266] Topic:\t"));
Serial.println(topic);
Serial.print(F("[ESP8266] Message:\t"));
Serial.println(message);
}
void loop() {
// check for new MQTT packets from server each time the loop() runs
// this will also send a PING packet, restarting the keep alive timer
int state = mqtt.check(onPublish);
Serial.print(F("[ESP8266] MQTT check "));
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
// the rest of your loop() code goes here
// make sure that the maximum time the loop() runs is less than 1.5x keep alive,
// otherwise the server will close the network connection
}

View file

@ -1,66 +0,0 @@
/*
RadioLib XBee API Receive Example
This example receives packets using XBee API mode.
In API mode, many XBee modules can form a mesh network.
IMPORTANT: Before uploading this example, make sure that the XBee module
is running API ROUTER/ENDPOINT firmware!
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// XBee has the following connections:
// TX pin: 9
// RX pin: 8
// RESET pin: 3
XBee bee = new SerialModule(9, 8, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//XBee bee = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize XBee module with baudrate 9600
Serial.print(F("[XBee] Initializing ... "));
int state = bee.begin(9600);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set PAN ID to 0x0123456789ABCDEF
Serial.print(F("[XBee] Setting PAN ID ... "));
uint8_t panId[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
state = bee.setPanId(panId);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
// check if XBee received some data
if (bee.available() > 0) {
// print source address
Serial.print(F("[XBee] Packet source:\t"));
Serial.println(bee.getPacketSource());
// print data
Serial.print(F("[XBee] Packet data:\t"));
Serial.println(bee.getPacketData());
}
}

View file

@ -1,69 +0,0 @@
/*
RadioLib XBee API Transmit Example
This example transmits packets using XBee API mode.
In API mode, many XBee modules can form a mesh network.
IMPORTANT: Before uploading this example, make sure that the XBee module
is running API COORDINATOR firmware!
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// XBee has the following connections:
// TX pin: 9
// RX pin: 8
// RESET pin: 3
XBee bee = new SerialModule(9, 8, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//XBee bee = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize XBee module with baudrate 9600
Serial.print(F("[XBee] Initializing ... "));
int state = bee.begin(9600);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set PAN ID to 0x0123456789ABCDEF
Serial.print(F("[XBee] Setting PAN ID ... "));
uint8_t panId[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
state = bee.setPanId(panId);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
// transmit data to the destination module
uint8_t dest[] = {0x00, 0x13, 0xA2, 0x00,
0x40, 0xA5, 0x8A, 0x6B};
Serial.print(F("[XBee] Transmitting message ... "));
int state = bee.transmit(dest, "Hello World!");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
delay(1000);
}

View file

@ -1,77 +0,0 @@
/*
RadioLib XBee Transparent Operation Example
This example transmits packets using XBee Transparent mode.
In Transparent mode, two XBee modules act like a Serial line.
Both modules must have the same PAN ID, and the destination
addresses have to be set properly.
IMPORTANT: Before uploading this example, make sure that the XBee modules
are running AT COORDINATOR and AT ROUTER firmware!
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// XBee has the following connections:
// TX pin: 9
// RX pin: 8
// RESET pin: 3
XBeeSerial bee = new SerialModule(9, 8, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//XBeeSerial bee = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize XBee module with baudrate 9600
Serial.print(F("[XBee] Initializing ... "));
int state = bee.begin(9600);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set PAN ID to 0123456789ABCDEF
Serial.print(F("[XBee] Setting PAN ID ... "));
state = bee.setPanId("0123456789ABCDEF");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set destination address to the address of the second module
Serial.print(F("[XBee] Setting destination address ... "));
state = bee.setDestinationAddress("0013A200", "40A58A5D");
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
// XBeeSerial supports all methods of the Serial class
// read data incoming from Serial port and write them to XBee
while (Serial.available() > 0) {
bee.write(Serial.read());
}
// read data incoming from XBee and write them to Serial port
while (bee.available() > 0) {
Serial.write(bee.read());
}
}

View file

@ -1,131 +0,0 @@
#include "ISerial.h"
ISerial::ISerial(Module* mod) {
_mod = mod;
}
void ISerial::begin(long speed) {
_mod->ModuleSerial->begin(speed);
}
#if !defined(__ASR6501__)
void ISerial::end() {
_mod->ModuleSerial->end();
}
#endif
int ISerial::peek() {
return(_mod->ModuleSerial->peek());
}
size_t ISerial::write(uint8_t b) {
return(_mod->ModuleSerial->write(b));
}
int ISerial::read() {
return(_mod->ModuleSerial->read());
}
int ISerial::available() {
return(_mod->ModuleSerial->available());
}
void ISerial::flush() {
_mod->ModuleSerial->flush();
}
#if !defined(ARDUINO_ARCH_MEGAAVR)
size_t ISerial::print(const __FlashStringHelper *ifsh) {
return(_mod->ModuleSerial->print(ifsh));
}
#endif
size_t ISerial::print(const String &s) {
return(_mod->ModuleSerial->print(s));
}
size_t ISerial::print(const char str[]) {
return(_mod->ModuleSerial->print(str));
}
size_t ISerial::print(char c) {
return(_mod->ModuleSerial->print(c));
}
size_t ISerial::print(unsigned char b, int base) {
return(_mod->ModuleSerial->print(b, base));
}
size_t ISerial::print(int n, int base) {
return(_mod->ModuleSerial->print(n, base));
}
size_t ISerial::print(unsigned int n, int base) {
return(_mod->ModuleSerial->print(n, base));
}
size_t ISerial::print(long n, int base) {
return(_mod->ModuleSerial->print(n, base));
}
size_t ISerial::print(unsigned long n, int base) {
return(_mod->ModuleSerial->print(n, base));
}
size_t ISerial::print(double n, int digits) {
return(_mod->ModuleSerial->print(n, digits));
}
size_t ISerial::print(const Printable& x) {
return(_mod->ModuleSerial->print(x));
}
#if !defined(ARDUINO_ARCH_MEGAAVR)
size_t ISerial::println(const __FlashStringHelper *ifsh) {
return(_mod->ModuleSerial->println(ifsh));
}
#endif
size_t ISerial::println(const String &s) {
return(_mod->ModuleSerial->println(s));
}
size_t ISerial::println(const char str[]) {
return(_mod->ModuleSerial->println(str));
}
size_t ISerial::println(char c) {
return(_mod->ModuleSerial->println(c));
}
size_t ISerial::println(unsigned char b, int base) {
return(_mod->ModuleSerial->println(b, base));
}
size_t ISerial::println(int n, int base) {
return(_mod->ModuleSerial->println(n, base));
}
size_t ISerial::println(unsigned int n, int base) {
return(_mod->ModuleSerial->println(n, base));
}
size_t ISerial::println(long n, int base) {
return(_mod->ModuleSerial->println(n, base));
}
size_t ISerial::println(unsigned long n, int base) {
return(_mod->ModuleSerial->println(n, base));
}
size_t ISerial::println(double n, int digits) {
return(_mod->ModuleSerial->println(n, digits));
}
size_t ISerial::println(const Printable& x) {
return(_mod->ModuleSerial->println(x));
}
size_t ISerial::println(void) {
return(_mod->ModuleSerial->println());
}

View file

@ -1,60 +0,0 @@
#if !defined(_RADIOLIB_ISERIAL_H)
#define _RADIOLIB_ISERIAL_H
#include "Module.h"
/*!
\class ISerial
\brief Interface class for Arduino Serial. Only calls the appropriate methods for the active UART interface.
*/
class ISerial {
public:
explicit ISerial(Module* mod);
void begin(long);
#if !defined(__ASR6501__)
void end();
#endif
int peek();
size_t write(uint8_t);
int read();
int available();
void flush();
#if !defined(ARDUINO_ARCH_MEGAAVR)
size_t print(const __FlashStringHelper *);
#endif
size_t print(const String &);
size_t print(const char[]);
size_t print(char);
size_t print(unsigned char, int = DEC);
size_t print(int, int = DEC);
size_t print(unsigned int, int = DEC);
size_t print(long, int = DEC);
size_t print(unsigned long, int = DEC);
size_t print(double, int = 2);
size_t print(const Printable&);
#if !defined(ARDUINO_ARCH_MEGAAVR)
size_t println(const __FlashStringHelper *);
#endif
size_t println(const String &s);
size_t println(const char[]);
size_t println(char);
size_t println(unsigned char, int = DEC);
size_t println(int, int = DEC);
size_t println(unsigned int, int = DEC);
size_t println(long, int = DEC);
size_t println(unsigned long, int = DEC);
size_t println(double, int = 2);
size_t println(const Printable&);
size_t println(void);
#if !(defined(RADIOLIB_LOW_LEVEL) || defined(RADIOLIB_GODMODE))
protected:
#endif
Module* _mod;
};
#endif

View file

@ -8,15 +8,12 @@
\par Currently Supported Wireless Modules and Protocols
- CC1101 FSK module
- HC05 Bluetooth module
- JDY08 BLE module
- RF69 FSK module
- Si443x FSK module
- SX126x LoRa/FSK module
- SX127x LoRa/FSK module
- SX128x LoRa/GFSK/BLE/FLRC module
- SX1231 FSK module
- XBee module (S2B)
- PhysicalLayer protocols
- RTTY (RTTYClient)
- Morse Code (MorseClient)
@ -24,9 +21,6 @@
- SSTV (SSTVClient)
- Hellschreiber (HellClient)
- 4-FSK (FSK4Client)
- TransportLayer protocols
- HTTP (HTTPClient)
- MQTT (MQTTClient)
\par Quick Links
Documentation for most common methods can be found in its reference page (see the list above).\n
@ -34,7 +28,6 @@
\ref status_codes have their own page.\n
Some modules implement methods of one or more compatibility layers, loosely based on the ISO/OSI model:
- PhysicalLayer - FSK and LoRa radio modules
- TransportLayer - Modules with Internet connectivity
\see https://github.com/jgromes/RadioLib
@ -47,24 +40,21 @@
// warnings are printed in this file since BuildOpt.h is compiled in multiple places
// check God mode
#ifdef RADIOLIB_GODMODE
#if defined(RADIOLIB_GODMODE)
#warning "God mode active, I hope it was intentional. Buckle up, lads."
#endif
// print debug info
#ifdef RADIOLIB_DEBUG
#if defined(RADIOLIB_DEBUG)
#pragma message "RADIOLIB_PLATFORM: " RADIOLIB_PLATFORM
#endif
// check unknown/unsupported platform
#ifdef RADIOLIB_UNKNOWN_PLATFORM
#if defined(RADIOLIB_UNKNOWN_PLATFORM)
#warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!"
#endif
#include "modules/CC1101/CC1101.h"
#include "modules/ESP8266/ESP8266.h"
#include "modules/HC05/HC05.h"
#include "modules/JDY08/JDY08.h"
#include "modules/LLCC68/LLCC68.h"
#include "modules/nRF24/nRF24.h"
#include "modules/RF69/RF69.h"
@ -89,7 +79,6 @@
#include "modules/SX128x/SX1280.h"
#include "modules/SX128x/SX1281.h"
#include "modules/SX128x/SX1282.h"
#include "modules/XBee/XBee.h"
// physical layer protocols
#include "protocols/PhysicalLayer/PhysicalLayer.h"
@ -101,13 +90,8 @@
#include "protocols/SSTV/SSTV.h"
#include "protocols/FSK4/FSK4.h"
// transport layer protocols
#include "protocols/TransportLayer/TransportLayer.h"
#include "protocols/HTTP/HTTP.h"
#include "protocols/MQTT/MQTT.h"
// only create Radio class when using RadioShield
#ifdef RADIOLIB_RADIOSHIELD
#if defined(RADIOLIB_RADIOSHIELD)
// RadioShield pin definitions
#define RADIOSHIELD_CS_A 10
@ -139,7 +123,7 @@ class Radio {
ModuleB = new Module(RADIOSHIELD_CS_B, RADIOSHIELD_INT_0, RADIOSHIELD_INT_1, RADIOSHIELD_RX_B, RADIOSHIELD_TX_B, SPI, SPISettings(2000000, MSBFIRST, SPI_MODE0), nullptr);
}
#ifndef RADIOLIB_GODMODE
#if defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -1,251 +0,0 @@
#include "ESP8266.h"
#if !defined(RADIOLIB_EXCLUDE_ESP8266) && !defined(ESP8266)
ESP8266::ESP8266(Module* module) {
_mod = module;
}
int16_t ESP8266::begin(long speed) {
// set module properties
char lf[3] = "\r\n";
memcpy(_mod->AtLineFeed, lf, strlen(lf));
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART);
// empty UART buffer (garbage data)
_mod->ATemptyBuffer();
// test AT setup
if(!_mod->ATsendCommand("AT")) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
int16_t ESP8266::reset() {
// send the reset command
if(!_mod->ATsendCommand("AT+RST")) {
return(ERR_AT_FAILED);
}
// wait for the module to start
Module::delay(2000);
// test AT setup
uint32_t start = Module::millis();
while (Module::millis() - start < 3000) {
if(!_mod->ATsendCommand("AT")) {
Module::delay(100);
} else {
return(ERR_NONE);
}
}
return(ERR_AT_FAILED);
}
int16_t ESP8266::join(const char* ssid, const char* password) {
// set mode to station + soft AP
if(!_mod->ATsendCommand("AT+CWMODE_CUR=3")) {
return(ERR_AT_FAILED);
}
// build AT command
const char* atStr = "AT+CWJAP_CUR=\"";
#ifdef RADIOLIB_STATIC_ONLY
char cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t cmdLen = strlen(atStr) + strlen(ssid) + strlen(password) + 4;
char* cmd = new char[cmdLen + 1];
#endif
strcpy(cmd, atStr);
strcat(cmd, ssid);
strcat(cmd, "\",\"");
strcat(cmd, password);
strcat(cmd, "\"");
// send command
bool res = _mod->ATsendCommand(cmd);
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
// disable multiple connection mode
if(!_mod->ATsendCommand("AT+CIPMUX=0")) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
int16_t ESP8266::openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive) {
char portStr[6];
sprintf(portStr, "%u", port);
char tcpKeepAliveStr[6];
sprintf(tcpKeepAliveStr, "%u", tcpKeepAlive);
// build AT command
const char* atStr = "AT+CIPSTART=\"";
#ifdef RADIOLIB_STATIC_ONLY
char cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t cmdLen = strlen(atStr) + strlen(protocol) + strlen(host) + strlen(portStr) + 5;
if((strcmp(protocol, "TCP") == 0) && (tcpKeepAlive > 0)) {
cmdLen += strlen(tcpKeepAliveStr) + 1;
}
char* cmd = new char[cmdLen + 1];
#endif
strcpy(cmd, atStr);
strcat(cmd, protocol);
strcat(cmd, "\",\"");
strcat(cmd, host);
strcat(cmd, "\",");
strcat(cmd, portStr);
if((strcmp(protocol, "TCP") == 0) && (tcpKeepAlive > 0)) {
strcat(cmd, ",");
strcat(cmd, tcpKeepAliveStr);
}
// send command
bool res = _mod->ATsendCommand(cmd);
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
int16_t ESP8266::closeTransportConnection() {
// send AT command
if(!_mod->ATsendCommand("AT+CIPCLOSE")) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
int16_t ESP8266::send(const char* data) {
// build AT command
char lenStr[12];
sprintf(lenStr, "%u", (uint16_t)strlen(data));
const char* atStr = "AT+CIPSEND=";
#ifdef RADIOLIB_STATIC_ONLY
char cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
#endif
strcpy(cmd, atStr);
strcat(cmd, lenStr);
// send command
bool res = _mod->ATsendCommand(cmd);
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
// send data
if(!_mod->ATsendCommand(data)) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
int16_t ESP8266::send(uint8_t* data, size_t len) {
// build AT command
char lenStr[8];
sprintf(lenStr, "%u", (uint16_t)len);
const char atStr[] = "AT+CIPSEND=";
#ifdef RADIOLIB_STATIC_ONLY
char cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
#endif
strcpy(cmd, atStr);
strcat(cmd, lenStr);
// send command
bool res = _mod->ATsendCommand(cmd);
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
// send data
if(!_mod->ATsendData(data, len)) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) {
size_t i = 0;
uint32_t start = Module::millis();
// wait until the required number of bytes is received or until timeout
while((Module::millis() - start < timeout) && (i < len)) {
Module::yield();
while(_mod->ModuleSerial->available() > 0) {
uint8_t b = _mod->ModuleSerial->read();
RADIOLIB_DEBUG_PRINT(b);
data[i] = b;
i++;
}
}
return(i);
}
size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) {
// wait for available data
uint32_t start = Module::millis();
while(_mod->ModuleSerial->available() < (int16_t)minBytes) {
Module::yield();
if(Module::millis() - start >= timeout) {
return(0);
}
}
// read response
char rawStr[20];
uint8_t i = 0;
start = Module::millis();
while(_mod->ModuleSerial->available() > 0) {
Module::yield();
char c = _mod->ModuleSerial->read();
rawStr[i++] = c;
if(c == ':') {
rawStr[i++] = 0;
break;
}
if(Module::millis() - start >= timeout) {
rawStr[i++] = 0;
break;
}
}
// get the number of bytes in response
char* pch = strtok(rawStr, ",:");
if(pch == NULL) {
return(0);
}
pch = strtok(NULL, ",:");
if(pch == NULL) {
return(0);
}
return(atoi(pch));
}
#endif

View file

@ -1,68 +0,0 @@
#if !defined(_RADIOLIB_ESP8266_H) && !defined(RADIOLIB_EXCLUDE_ESP8266) && !defined(ESP8266)
#define _RADIOLIB_ESP8266_H
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../../protocols/TransportLayer/TransportLayer.h"
/*!
\class ESP8266
\brief Control class for %ESP8266 module. Implements TransportLayer methods.
*/
class ESP8266: public TransportLayer {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
ESP8266(Module* module);
// basic methods
/*!
\brief Initialization method.
\param speed Baud rate to use for UART interface.
\returns \ref status_codes
*/
int16_t begin(long speed);
/*!
\brief Resets module using AT command.
\returns \ref status_codes
*/
int16_t reset();
/*!
\brief Joins access point.
\param ssid Access point SSID.
\param password Access point password.
*/
int16_t join(const char* ssid, const char* password);
// transport layer methods (implementations of purely virtual methods in TransportLayer class)
int16_t openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive = 0) override;
int16_t closeTransportConnection() override;
int16_t send(const char* data) override;
int16_t send(uint8_t* data, size_t len) override;
size_t receive(uint8_t* data, size_t len, uint32_t timeout = 10000) override;
size_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10) override;
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
};
#endif

View file

@ -1,14 +0,0 @@
#include "HC05.h"
#if !defined(RADIOLIB_EXCLUDE_HC05)
HC05::HC05(Module* mod) : ISerial(mod) {
}
void HC05::begin(long speed) {
// set module properties
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART);
}
#endif

View file

@ -1,29 +0,0 @@
#if !defined(_RADIOLIB_HC05_H) && !defined(RADIOLIB_EXCLUDE_HC05)
#define _RADIOLIB_HC05_H
#include "../../ISerial.h"
/*!
\class HC05
\brief Control class for %HC05 module.
Most methods supported by this module are implemented in ISerial interface.
*/
class HC05: public ISerial {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
HC05(Module* mod);
/*!
\brief Initialization method.
\param speed Baud rate to use for UART interface.
*/
void begin(long speed);
};
#endif

View file

@ -1,16 +0,0 @@
#if !defined(_RADIOLIB_JDY08_H) && !defined(RADIOLIB_EXCLUDE_JDY08)
#include "JDY08.h"
JDY08::JDY08(Module* mod) : ISerial(mod) {
}
void JDY08::begin(long speed) {
// set module properties
char lf[3] = "";
memcpy(_mod->AtLineFeed, lf, strlen(lf));
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART);
}
#endif

View file

@ -1,29 +0,0 @@
#if !defined(_RADIOLIB_JDY08_H) && !defined(RADIOLIB_EXCLUDE_JDY08)
#define _RADIOLIB_JDY08_H
#include "../../ISerial.h"
/*!
\class JDY08
\brief Control class for %JDY08 module.
Most methods supported by this module are implemented in ISerial interface.
*/
class JDY08: public ISerial {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
JDY08(Module* mod);
/*!
\brief Initialization method.
\param speed Baud rate to use for UART interface.
*/
void begin(long speed);
};
#endif

View file

@ -1,485 +0,0 @@
#include "XBee.h"
#if !defined(RADIOLIB_EXCLUDE_XBEE)
XBee::XBee(Module* mod) {
_mod = mod;
_packetData[0] = '\0';
}
int16_t XBee::begin(long speed) {
// set module properties
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART);
// reset module
reset();
// empty UART buffer (garbage data)
_mod->ATemptyBuffer();
// try to find the XBee
bool flagFound = false;
uint8_t i = 0;
while((i < 10) && !flagFound) {
// hardware reset should return 2 modem status frames - 1st status 0x00, second status 0x06
int16_t state = readApiFrame(0x00, 1, 2000);
readApiFrame(0x00, 1, 2000);
if(state == ERR_NONE) {
flagFound = true;
} else {
RADIOLIB_DEBUG_PRINT(F("XBee not found! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) STATE == "));
RADIOLIB_DEBUG_PRINTLN(state);
RADIOLIB_DEBUG_PRINTLN(F("Resetting ..."));
reset();
Module::delay(10);
_mod->ATemptyBuffer();
i++;
}
}
if(!flagFound) {
RADIOLIB_DEBUG_PRINTLN(F("No XBee found!"));
return(ERR_CMD_MODE_FAILED);
} else {
RADIOLIB_DEBUG_PRINTLN(F("Found XBee!"));
}
return(ERR_NONE);
}
void XBee::reset() {
Module::pinMode(_mod->getRst(), OUTPUT);
Module::digitalWrite(_mod->getRst(), LOW);
Module::delay(1);
Module::digitalWrite(_mod->getRst(), HIGH);
}
int16_t XBee::transmit(uint8_t* dest, const char* payload, uint8_t radius) {
uint8_t destNetwork[] = {0xFF, 0xFE};
return(transmit(dest, destNetwork, payload, radius));
}
int16_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;
#ifdef RADIOLIB_STATIC_ONLY
uint8_t cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* cmd = new uint8_t[dataLen];
#endif
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);
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
// get response code
return(readApiFrame(frameID, 5));
}
size_t XBee::available() {
// check if there are data available in the buffer
size_t serialBytes = _mod->ModuleSerial->available();
if(serialBytes < 3) {
return(0);
}
if(!_frameHeaderProcessed) {
// read frame header
uint8_t header[3];
for(uint8_t i = 0; i < 3; i++) {
header[i] = _mod->ModuleSerial->read();
}
// check if we received API frame
if(header[0] != XBEE_API_START) {
return(0);
}
// get expected frame length
_frameLength = ((header[1] << 8) | header[2]) + 1;
_frameHeaderProcessed = true;
}
// check if the header is complete
if(serialBytes < _frameLength) {
return(0);
}
#ifdef RADIOLIB_STATIC_ONLY
char frame[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* frame = new uint8_t[_frameLength];
#endif
for(size_t i = 0; i < _frameLength; i++) {
frame[i] = _mod->ModuleSerial->read();
}
// save packet source and data
size_t payloadLength = _frameLength - 12;
#ifndef RADIOLIB_STATIC_ONLY
delete[] _packetData;
_packetData = new char[payloadLength];
#endif
memcpy(_packetData, frame + 12, payloadLength - 1);
_packetData[payloadLength - 1] = '\0';
memcpy(_packetSource, frame + 1, 8);
#ifndef RADIOLIB_STATIC_ONLY
delete[] frame;
#endif
_frameLength = 0;
_frameHeaderProcessed = false;
// return number of bytes in payload
return(payloadLength);
}
String XBee::getPacketSource() {
char buff[17];
sprintf(buff, "%02X%02X%02X%02X%02X%02X%02X%02X", _packetSource[0], _packetSource[1], _packetSource[2], _packetSource[3],
_packetSource[4], _packetSource[5], _packetSource[6], _packetSource[7]);
String str(buff);
return(str);
}
String XBee::getPacketData() {
String str(_packetData);
return(str);
}
int16_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_QUEUE, frameID, cmd, 10);
// get response code
int16_t state = readApiFrame(frameID, 4);
RADIOLIB_ASSERT(state);
// confirm changes
return(confirmChanges());
}
XBeeSerial::XBeeSerial(Module* mod) : ISerial(mod) {
}
int16_t XBeeSerial::begin(long speed) {
// set module properties
char lf[3] = "\r";
memcpy(_mod->AtLineFeed, lf, strlen(lf));
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART);
// reset module
reset();
// empty UART buffer (garbage data)
_mod->ATemptyBuffer();
// enter command mode
RADIOLIB_DEBUG_PRINTLN(F("Entering command mode ..."));
if(!enterCmdMode()) {
return(ERR_CMD_MODE_FAILED);
}
// test AT setup
RADIOLIB_DEBUG_PRINTLN(F("Sending test command ..."));
if(!_mod->ATsendCommand("AT")) {
return(ERR_AT_FAILED);
}
// exit command mode
RADIOLIB_DEBUG_PRINTLN(F("Exiting command mode ..."));
if(!_mod->ATsendCommand("ATCN")) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
void XBeeSerial::reset() {
Module::pinMode(_mod->getRst(), OUTPUT);
Module::digitalWrite(_mod->getRst(), LOW);
Module::delay(1);
Module::digitalWrite(_mod->getRst(), HIGH);
Module::pinMode(_mod->getRst(), INPUT);
}
int16_t XBeeSerial::setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow) {
// enter command mode
RADIOLIB_DEBUG_PRINTLN(F("Entering command mode ..."));
if(!enterCmdMode()) {
return(ERR_CMD_MODE_FAILED);
}
// set higher address bytes
RADIOLIB_DEBUG_PRINTLN(F("Setting address (high) ..."));
#ifdef RADIOLIB_STATIC_ONLY
char addressHigh[13];
#else
char* addressHigh = new char[strlen(destinationAddressHigh) + 4];
#endif
strcpy(addressHigh, "ATDH");
strcat(addressHigh, destinationAddressHigh);
bool res = _mod->ATsendCommand(addressHigh);
#ifndef RADIOLIB_STATIC_ONLY
delete[] addressHigh;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
// set lower address bytes
RADIOLIB_DEBUG_PRINTLN(F("Setting address (low) ..."));
#ifdef RADIOLIB_STATIC_ONLY
char addressLow[13];
#else
char* addressLow = new char[strlen(destinationAddressLow) + 4];
#endif
strcpy(addressLow, "ATDL");
strcat(addressLow, destinationAddressLow);
res = _mod->ATsendCommand(addressLow);
#ifndef RADIOLIB_STATIC_ONLY
delete[] addressLow;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
// exit command mode
RADIOLIB_DEBUG_PRINTLN(F("Exiting command mode ..."));
if(!_mod->ATsendCommand("ATCN")) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
int16_t XBeeSerial::setPanId(const char* panId) {
// enter command mode
RADIOLIB_DEBUG_PRINTLN(F("Entering command mode ..."));
if(!enterCmdMode()) {
return(ERR_CMD_MODE_FAILED);
}
// set PAN ID
RADIOLIB_DEBUG_PRINTLN(F("Setting PAN ID ..."));
#ifdef RADIOLIB_STATIC_ONLY
char cmd[21];
#else
char* cmd = new char[strlen(panId) + 4];
#endif
strcpy(cmd, "ATID");
strcat(cmd, panId);
bool res = _mod->ATsendCommand(cmd);
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
// exit command mode
RADIOLIB_DEBUG_PRINTLN(F("Exiting command mode ..."));
if(!_mod->ATsendCommand("ATCN")) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
bool XBeeSerial::enterCmdMode() {
for(uint8_t i = 0; i < 10; i++) {
Module::delay(1000);
_mod->ModuleSerial->write('+');
_mod->ModuleSerial->write('+');
_mod->ModuleSerial->write('+');
Module::delay(1000);
if(_mod->ATgetResponse()) {
return(true);
} else {
RADIOLIB_DEBUG_PRINT(F("Unable to enter command mode! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINTLN(F(" of 10 tries)"));
reset();
_mod->ATsendCommand("ATCN");
}
}
RADIOLIB_DEBUG_PRINTLN(F("Terminated, check your wiring. Is AT FW uploaded?"));
return(false);
}
int16_t XBee::confirmChanges() {
// save changes to non-volatile memory
uint8_t frameID = _frameID++;
sendApiFrame(XBEE_API_FRAME_AT_COMMAND_QUEUE, frameID, "WR");
// get response code
int16_t state = readApiFrame(frameID, 4);
RADIOLIB_ASSERT(state);
// apply changes
frameID = _frameID++;
sendApiFrame(XBEE_API_FRAME_AT_COMMAND_QUEUE, frameID, "AC");
// get response code
state = readApiFrame(frameID, 4);
return(state);
}
void XBee::sendApiFrame(uint8_t type, uint8_t id, const char* data) {
sendApiFrame(type, id, (uint8_t*)data, strlen(data));
}
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;
#ifdef RADIOLIB_STATIC_ONLY
uint8_t frame[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* frame = new uint8_t[frameLength];
#endif
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(size_t i = 3; i < frameLength - 1; i++) {
checksum += frame[i];
}
frame[5 + length] = 0xFF - checksum;
// send the frame
for(size_t i = 0; i < frameLength; i++) {
_mod->ModuleSerial->write(frame[i]);
}
// deallocate memory
#ifndef RADIOLIB_STATIC_ONLY
delete[] frame;
#endif
}
int16_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout) {
/// \todo modemStatus frames may be sent at any time, interfering with frame parsing. Add check to make sure this does not happen.
// get number of bytes in response (must be enough to read the length field
uint16_t numBytes = getNumBytes(timeout/2, 3);
if(numBytes == 0) {
return(ERR_FRAME_NO_RESPONSE);
}
// checksum byte is not included in length field
numBytes++;
// wait until all response bytes are available (5s timeout)
uint32_t start = Module::millis();
while(_mod->ModuleSerial->available() < (int16_t)numBytes) {
Module::yield();
if(Module::millis() - start >= timeout/2) {
return(ERR_FRAME_MALFORMED);
}
}
RADIOLIB_DEBUG_PRINT(F("frame data field length: "));
RADIOLIB_DEBUG_PRINTLN(numBytes);
// read the response
#ifdef RADIOLIB_STATIC_ONLY
uint8_t resp[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* resp = new uint8_t[numBytes];
#endif
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++) {
RADIOLIB_DEBUG_PRINT(resp[i], HEX);
RADIOLIB_DEBUG_PRINT('\t');
checksum += resp[i];
}
RADIOLIB_DEBUG_PRINTLN();
if(checksum != 0xFF) {
RADIOLIB_DEBUG_PRINTLN(checksum, HEX);
return(ERR_FRAME_INCORRECT_CHECKSUM);
}
// check frame ID
if(resp[1] != frameID) {
RADIOLIB_DEBUG_PRINT(F("received frame ID: "));
RADIOLIB_DEBUG_PRINTLN(resp[1]);
RADIOLIB_DEBUG_PRINT(F("expected frame ID: "));
RADIOLIB_DEBUG_PRINTLN(frameID);
return(ERR_FRAME_UNEXPECTED_ID);
}
// codePos does not include start delimiter and frame ID
uint8_t code = resp[codePos];
#ifndef RADIOLIB_STATIC_ONLY
delete[] resp;
#endif
return(code);
}
uint16_t XBee::getNumBytes(uint32_t timeout, size_t minBytes) {
// wait for available data
uint32_t start = Module::millis();
while((size_t)_mod->ModuleSerial->available() < minBytes) {
Module::yield();
if(Module::millis() - start >= timeout) {
return(0);
}
}
// read response
uint8_t resp[3];
uint8_t i = 0;
RADIOLIB_DEBUG_PRINT(F("reading frame length: "));
while(_mod->ModuleSerial->available() > 0) {
Module::yield();
uint8_t b = _mod->ModuleSerial->read();
RADIOLIB_DEBUG_PRINT(b, HEX);
RADIOLIB_DEBUG_PRINT('\t');
resp[i++] = b;
if(i == 3) {
break;
}
}
RADIOLIB_DEBUG_PRINTLN();
return((resp[1] << 8) | resp[2]);
}
#endif

View file

@ -1,204 +0,0 @@
#if !defined(_RADIOLIB_XBEE_H) && !defined(RADIOLIB_EXCLUDE_XBEE)
#define _RADIOLIB_XBEE_H
#include "../../ISerial.h"
#include "../../TypeDef.h"
// API reserved characters
#define XBEE_API_START 0x7E
#define XBEE_API_ESCAPE 0x7D
#define XBEE_API_XON 0x11
#define XBEE_API_XOFF 0x13
// API frame IDs
#define XBEE_API_FRAME_AT_COMMAND 0x08
#define XBEE_API_FRAME_AT_COMMAND_QUEUE 0x09
#define XBEE_API_FRAME_ZIGBEE_TRANSMIT_REQUEST 0x10
#define XBEE_API_FRAME_ZIGBEE_ADDRESS_EXPLICIT 0x11
#define XBEE_API_FRAME_REMOTE_COMMAND 0x17
#define XBEE_API_FRAME_CREATE_SOURCE_ROUTE 0x21
#define XBEE_API_FRAME_AT_COMMAND_RESPONSE 0x88
#define XBEE_API_FRAME_MODEM_STATUS 0x8A
#define XBEE_API_FRAME_ZIGBEE_TRANSMIT_STATUS 0x8B
#define XBEE_API_FRAME_ZIGBEE_RECEIVE_PACKET 0x90
#define XBEE_API_FRAME_ZIGBEE_EXPLICIT_RX 0x91
#define XBEE_API_FRAME_ZIGBEE_IO_DATA_SAMPLE_RX 0x92
#define XBEE_API_FRAME_SENSOR_READ 0x94
#define XBEE_API_FRAME_NODE_ID 0x95
#define XBEE_API_FRAME_REMOTE_COMMAND_RESPONSE 0x97
#define XBEE_API_FRAME_EXTENDED_MODEM_STATUS 0x98
#define XBEE_API_FRAME_OTA_FW_UPDATE_STATUS 0xA0
#define XBEE_API_FRAME_ROUTE_RECORD 0xA1
#define XBEE_API_FRAME_MANY_TO_ONE_ROUTE_REQUEST 0xA3
/*!
\class XBeeSerial
\brief %XBee Serial interface. This class is used for XBees in transparent mode, i.e. when two XBees act as a "wireless UART".
*/
class XBeeSerial: public ISerial {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
XBeeSerial(Module* mod);
// basic methods
/*!
\brief Initialization method.
\param speed Baud rate to use for UART interface.
\returns \ref status_codes
*/
int16_t begin(long speed);
/*!
\brief Resets module using interrupt/GPIO pin 1.
*/
void reset();
// configuration methods
/*!
\brief Sets destination XBee address.
\param destinationAddressHigh Higher 4 bytes of the destination XBee module, in the form of uppercase hexadecimal string (i.e. 8 characters).
\param destinationAddressLow Lower 4 bytes of the destination XBee module, in the form of uppercase hexadecimal string (i.e. 8 characters).
\returns \ref status_codes
*/
int16_t setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow);
/*!
\brief Sets PAN (Personal Area Network) ID. Both XBees must be in the same PAN in order to use transparent mode.
\param panId 8-byte PAN ID to be used, in the form of uppercase hexadecimal string (i.e. 16 characters).
*/
int16_t setPanId(const char* panId);
#if !defined(RADIOLIB_GODMODE)
private:
#endif
bool enterCmdMode();
};
/*!
\class XBee
\brief Control class for %XBee modules.
*/
class XBee {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
XBee(Module* mod);
// basic methods
/*!
\brief Initialization method.
\param speed Baud rate to use for UART interface.
\returns \ref status_codes
*/
int16_t begin(long speed);
/*!
\brief Resets module using interrupt/GPIO pin 1.
*/
void reset();
/*!
\brief Sends data to the destination 64-bit (global) address, when destination 16-bit (local) address is unknown.
\param dest Destination 64-bit address, in the form of 8-byte array.
\param payload String of payload bytes.
\param radius Number of maximum "hops" for a broadcast transmission. Defaults to 1, set to 0 for unlimited number of hops.
*/
int16_t transmit(uint8_t* dest, const char* payload, uint8_t radius = 1);
/*!
\brief Sends data to the destination 64-bit (global) address, when destination 16-bit (local) address is known.
\param dest Destination 64-bit address, in the form of 8-byte array.
\param destNetwork Destination 16-bit address, in the form of 2-byte array.
\param payload String of payload bytes.
\param radius Number of maximum "hops" for a broadcast transmission. Defaults to 1, set to 0 for unlimited number of hops.
*/
int16_t transmit(uint8_t* dest, uint8_t* destNetwork, const char* payload, uint8_t radius = 1);
/*!
\brief Gets the number of payload bytes received.
\returns Number of available payload bytes, or 0 if nothing was received.
*/
size_t available();
/*!
\brief Gets packet source 64-bit address.
\returns Packet source address, in the form of uppercase hexadecimal Arduino String (i.e. 16 characters).
*/
String getPacketSource();
/*!
\brief Gets packet payload.
\returns Packet payload, in the form of Arduino String.
*/
String getPacketData();
// configuration methods
/*!
\brief Sets PAN (Personal Area Network) ID. All XBees must be in the same PAN in order to communicate.
\param panId 8-byte PAN ID to be used, in the form of uppercase hexadecimal string (i.e. 16 characters).
*/
int16_t setPanId(uint8_t* panId);
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
uint8_t _frameID = 0x01;
size_t _frameLength = 0;
bool _frameHeaderProcessed = false;
#ifdef RADIOLIB_STATIC_ONLY
char _packetData[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* _packetData = new char[0];
#endif
uint8_t _packetSource[8] = {0, 0, 0, 0, 0, 0, 0, 0};
int16_t confirmChanges();
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);
int16_t readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout = 5000);
uint16_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10);
};
#endif

View file

@ -1,219 +0,0 @@
#include "HTTP.h"
#if !defined(RADIOLIB_EXCLUDE_HTTP)
HTTPClient::HTTPClient(TransportLayer* tl, uint16_t port) {
_tl = tl;
_port = port;
}
int16_t HTTPClient::get(String& url, String& response) {
return(HTTPClient::get(url.c_str(), response));
}
int16_t HTTPClient::get(const char* url, String& response) {
// get the host address and endpoint
char* httpPrefix = strstr(url, "http://");
char* endpoint;
char* host;
if(httpPrefix != NULL) {
// find the host string
char* hostStart = strchr(url, '/');
hostStart = strchr(hostStart + 1, '/');
char* hostEnd = strchr(hostStart + 1, '/');
host = new char[hostEnd - hostStart];
strncpy(host, hostStart + 1, hostEnd - hostStart - 1);
host[hostEnd - hostStart - 1] = '\0';
// find the endpoint string
endpoint = new char[url + strlen(url) - hostEnd + 1];
strcpy(endpoint, hostEnd);
} else {
// find the host string
char* hostEnd = strchr(url, '/');
host = new char[hostEnd - url + 1];
strncpy(host, url, hostEnd - url);
host[hostEnd - url] = '\0';
// find the endpoint string
endpoint = new char[url + strlen(url) - hostEnd + 1];
strcpy(endpoint, hostEnd);
}
// build the GET request
char* request = new char[strlen(endpoint) + strlen(host) + 25 + 1];
strcpy(request, "GET ");
strcat(request, endpoint);
strcat(request, " HTTP/1.1\r\nHost: ");
strcat(request, host);
strcat(request, "\r\n\r\n");
delete[] endpoint;
// create TCP connection
int16_t state = _tl->openTransportConnection(host, "TCP", _port);
delete[] host;
if(state != ERR_NONE) {
delete[] request;
return(state);
}
// send the GET request
state = _tl->send(request);
delete[] request;
if(state != ERR_NONE) {
return(state);
}
// get the response length
size_t numBytes = _tl->getNumBytes();
if(numBytes == 0) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
char* raw = new char[numBytes + 1];
size_t rawLength = _tl->receive((uint8_t*)raw, numBytes);
if(rawLength == 0) {
delete[] raw;
return(ERR_RESPONSE_MALFORMED);
}
// close the tl connection
state = _tl->closeTransportConnection();
if(state != ERR_NONE) {
delete[] raw;
return(state);
}
// get the response body
char* responseStart = strstr(raw, "\r\n");
if(responseStart == NULL) {
delete[] raw;
return(ERR_RESPONSE_MALFORMED);
}
char* responseStr = new char[raw + rawLength - responseStart - 1 + 1];
strncpy(responseStr, responseStart + 2, raw + rawLength - responseStart - 1);
responseStr[raw + rawLength - responseStart - 2] = '\0';
response = String(responseStr);
delete[] responseStr;
// return the HTTP status code
char* statusStart = strchr(raw, ' ');
delete[] raw;
if(statusStart == NULL) {
return(ERR_RESPONSE_MALFORMED);
}
char statusStr[4];
strncpy(statusStr, statusStart + 1, 3);
statusStr[3] = 0x00;
return(atoi(statusStr));
}
int16_t HTTPClient::post(const char* url, const char* content, String& response, const char* contentType) {
// get the host address and endpoint
char* httpPrefix = strstr(url, "http://");
char* endpoint;
char* host;
if(httpPrefix != NULL) {
// find the host string
char* hostStart = strchr(url, '/');
hostStart = strchr(hostStart + 1, '/');
char* hostEnd = strchr(hostStart + 1, '/');
host = new char[hostEnd - hostStart];
strncpy(host, hostStart + 1, hostEnd - hostStart - 1);
host[hostEnd - hostStart - 1] = '\0';
// find the endpoint string
endpoint = new char[url + strlen(url) - hostEnd + 1];
strcpy(endpoint, hostEnd);
} else {
// find the host string
char* hostEnd = strchr(url, '/');
host = new char[hostEnd - url + 1];
strncpy(host, url, hostEnd - url);
host[hostEnd - url] = '\0';
// find the endpoint string
endpoint = new char[url + strlen(url) - hostEnd + 1];
strcpy(endpoint, hostEnd);
}
// build the POST request
char contentLengthStr[12];
sprintf(contentLengthStr, "%u", (uint16_t)strlen(content));
char* request = new char[strlen(endpoint) + strlen(host) + strlen(contentType) + strlen(contentLengthStr) + strlen(content) + 64 + 1];
strcpy(request, "POST ");
strcat(request, endpoint);
strcat(request, " HTTP/1.1\r\nHost: ");
strcat(request, host);
strcat(request, "\r\nContent-Type: ");
strcat(request, contentType);
strcat(request, "\r\nContent-length: ");
strcat(request, contentLengthStr);
strcat(request, "\r\n\r\n");
strcat(request, content);
strcat(request, "\r\n\r\n");
delete[] endpoint;
// create TCP connection
int16_t state = _tl->openTransportConnection(host, "TCP", _port);
delete[] host;
if(state != ERR_NONE) {
delete[] request;
return(state);
}
// send the POST request
state = _tl->send(request);
delete[] request;
if(state != ERR_NONE) {
return(state);
}
// get the response length
size_t numBytes = _tl->getNumBytes();
if(numBytes == 0) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
char* raw = new char[numBytes];
size_t rawLength = _tl->receive((uint8_t*)raw, numBytes);
if(rawLength == 0) {
delete[] raw;
return(ERR_RESPONSE_MALFORMED);
}
// close the tl connection
state = _tl->closeTransportConnection();
if(state != ERR_NONE) {
delete[] raw;
return(state);
}
// get the response body
char* responseStart = strstr(raw, "\r\n");
if(responseStart == NULL) {
delete[] raw;
return(ERR_RESPONSE_MALFORMED);
}
char* responseStr = new char[raw + rawLength - responseStart - 1];
strncpy(responseStr, responseStart + 2, raw + rawLength - responseStart - 1);
responseStr[raw + rawLength - responseStart - 2] = 0x00;
response = String(responseStr);
delete[] responseStr;
// return the HTTP status code
char* statusStart = strchr(raw, ' ');
delete[] raw;
if(statusStart == NULL) {
return(ERR_RESPONSE_MALFORMED);
}
char statusStr[4];
strncpy(statusStr, statusStart + 1, 3);
statusStr[3] = 0x00;
return(atoi(statusStr));
}
#endif

View file

@ -1,73 +0,0 @@
#if !defined(_RADIOLIB_HTTP_H)
#define _RADIOLIB_HTTP_H
#include "../../TypeDef.h"
#if !defined(RADIOLIB_EXCLUDE_HTTP)
#include "../TransportLayer/TransportLayer.h"
/*!
\class HTTPClient
\brief Client for simple HTTP communication.
*/
class HTTPClient {
public:
/*!
\brief Default constructor.
\param tl Pointer to the wireless module providing TransportLayer communication.
\param port Port to be used for HTTP. Defaults to 80.
*/
explicit HTTPClient(TransportLayer* tl, uint16_t port = 80);
/*!
\brief Sends HTTP GET request.
\param url URL to send the request to.
\param response Arduino String object that will save the response.
\returns \ref status_codes
*/
int16_t get(String& url, String& response);
/*!
\brief Sends HTTP GET request.
\param url URL to send the request to.
\param response Arduino String object that will save the response.
\returns \ref status_codes
*/
int16_t get(const char* url, String& response);
/*!
\brief Sends HTTP POST request.
\param url URL to send the request to.
\param content Request content.
\param response Arduino String object that will save the response.
\param contentType MIME type of request content. Defaults to "text/plain".
\returns \ref status_codes
*/
int16_t post(const char* url, const char* content, String& response, const char* contentType = "text/plain");
#ifndef RADIOLIB_GODMODE
private:
#endif
TransportLayer* _tl;
uint16_t _port;
};
#endif
#endif

View file

@ -1,472 +0,0 @@
#include "MQTT.h"
#if !defined(RADIOLIB_EXCLUDE_MQTT)
MQTTClient::MQTTClient(TransportLayer* tl, uint16_t port) {
_tl = tl;
_port = port;
_packetId = 1;
}
int16_t MQTTClient::connect(const char* host, const char* clientId, const char* userName, const char* password, uint16_t keepAlive, bool cleanSession, const char* willTopic, const char* willMessage) {
// encode packet length
size_t clientIdLen = strlen(clientId);
size_t userNameLen = strlen(userName);
size_t passwordLen = strlen(password);
size_t willTopicLen = strlen(willTopic);
size_t willMessageLen = strlen(willMessage);
uint32_t remainingLength = 10 + (2 + clientIdLen);
if(userNameLen > 0) {
remainingLength += (2 + userNameLen);
}
if(passwordLen > 0) {
remainingLength += (2 + passwordLen);
}
if((willTopicLen > 0) && (willMessageLen > 0)) {
remainingLength += (2 + willTopicLen) + (2 + willMessageLen);
}
uint8_t encoded[] = {0, 0, 0, 0};
size_t encodedBytes = encodeLength(remainingLength, encoded);
// build the CONNECT packet
#ifdef RADIOLIB_STATIC_ONLY
uint8_t packet[256];
#else
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#endif
// fixed header
packet[0] = (MQTT_CONNECT << 4) | 0b0000;
memcpy(packet + 1, encoded, encodedBytes);
// variable header
// protocol name
size_t pos = encodedBytes + 1;
packet[pos++] = 0x00;
packet[pos++] = 0x04;
memcpy(packet + pos, "MQTT", 4);
pos += 4;
// protocol level
packet[pos++] = 0x04;
// flags
packet[pos++] = 0x00;
if(cleanSession) {
packet[encodedBytes + 8] |= MQTT_CONNECT_CLEAN_SESSION;
}
// keep alive interval in seconds
packet[pos++] = (keepAlive & 0xFF00) >> 8;
packet[pos++] = keepAlive & 0x00FF;
// payload
// clientId
packet[pos++] = (clientIdLen & 0xFF00) >> 8;
packet[pos++] = clientIdLen & 0x00FF;
memcpy(packet + pos, clientId, clientIdLen);
pos += clientIdLen;
// will topic and message
if((willTopicLen > 0) && (willMessageLen > 0)) {
packet[encodedBytes + 8] |= MQTT_CONNECT_WILL_FLAG;
packet[pos++] = (willTopicLen & 0xFF00) >> 8;
packet[pos++] = willTopicLen & 0x00FF;
memcpy(packet + pos, willTopic, willTopicLen);
pos += willTopicLen;
packet[pos++] = (willMessageLen & 0xFF00) >> 8;
packet[pos++] = willMessageLen & 0x00FF;
memcpy(packet + pos, willMessage, willMessageLen);
pos += willMessageLen;
}
// user name
if(userNameLen > 0) {
packet[encodedBytes + 8] |= MQTT_CONNECT_USER_NAME_FLAG;
packet[pos++] = (userNameLen & 0xFF00) >> 8;
packet[pos++] = userNameLen & 0x00FF;
memcpy(packet + pos, userName, userNameLen);
pos += userNameLen;
}
// password
if(passwordLen > 0) {
packet[encodedBytes + 8] |= MQTT_CONNECT_PASSWORD_FLAG;
packet[pos++] = (passwordLen & 0xFF00) >> 8;;
packet[pos++] = passwordLen & 0x00FF;
memcpy(packet + pos, password, passwordLen);
}
// create TCP connection
int16_t state = _tl->openTransportConnection(host, "TCP", _port, keepAlive);
if(state != ERR_NONE) {
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
return(state);
}
// send MQTT packet
state = _tl->send(packet, 1 + encodedBytes + remainingLength);
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
if(state != ERR_NONE) {
return(state);
}
// get the response length (MQTT CONNACK response has to be 4 bytes long)
size_t numBytes = _tl->getNumBytes();
if(numBytes != 4) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
#ifdef RADIOLIB_STATIC_ONLY
uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* response = new uint8_t[numBytes];
#endif
_tl->receive(response, numBytes);
if((response[0] == MQTT_CONNACK << 4) && (response[1] == 2)) {
uint8_t returnCode = response[3];
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(returnCode);
}
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_RESPONSE_MALFORMED);
}
int16_t MQTTClient::disconnect() {
// build the DISCONNECT packet
uint8_t packet[2];
// fixed header
packet[0] = (MQTT_DISCONNECT << 4) | 0b0000;
packet[1] = 0x00;
// send MQTT packet
int16_t state = _tl->send(packet, 2);
if(state != ERR_NONE) {
return(state);
}
// close tl connection
return(_tl->closeTransportConnection());
}
int16_t MQTTClient::publish(String& topic, String& message) {
return(MQTTClient::publish(topic.c_str(), message.c_str()));
}
int16_t MQTTClient::publish(const char* topic, const char* message) {
// encode packet length
size_t topicLen = strlen(topic);
size_t messageLen = strlen(message);
uint32_t remainingLength = (2 + topicLen) + messageLen;
uint8_t encoded[] = {0, 0, 0, 0};
size_t encodedBytes = encodeLength(remainingLength, encoded);
// build the PUBLISH packet
#ifdef RADIOLIB_STATIC_ONLY
uint8_t packet[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#endif
// fixed header
packet[0] = (MQTT_PUBLISH << 4) | 0b0000;
memcpy(packet + 1, encoded, encodedBytes);
// variable header
// topic name
size_t pos = encodedBytes + 1;
packet[pos++] = (topicLen & 0xFF00) >> 8;
packet[pos++] = topicLen & 0x00FF;
memcpy(packet + pos, topic, topicLen);
pos += topicLen;
// packet ID
// payload
// message
memcpy(packet + pos, message, messageLen);
// send MQTT packet
int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength);
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
return(state);
/// \todo implement QoS > 0 and PUBACK response checking
}
int16_t MQTTClient::subscribe(const char* topicFilter) {
// encode packet length
size_t topicFilterLen = strlen(topicFilter);
uint32_t remainingLength = 2 + (2 + topicFilterLen + 1);
uint8_t encoded[] = {0, 0, 0, 0};
size_t encodedBytes = encodeLength(remainingLength, encoded);
// build the SUBSCRIBE packet
#ifdef RADIOLIB_STATIC_ONLY
uint8_t packet[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#endif
// fixed header
packet[0] = (MQTT_SUBSCRIBE << 4) | 0b0010;
memcpy(packet + 1, encoded, encodedBytes);
// variable header
// packet ID
size_t pos = encodedBytes + 1;
uint16_t packetId = _packetId++;
packet[pos++] = (packetId & 0xFF00) >> 8;
packet[pos++] = packetId & 0x00FF;
// payload
// topic filter
packet[pos++] = (topicFilterLen & 0xFF00) >> 8;;
packet[pos++] = topicFilterLen & 0x00FF;
memcpy(packet + pos, topicFilter, topicFilterLen);
pos += topicFilterLen;
packet[pos++] = 0x00; // QoS 0
// send MQTT packet
int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength);
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
if(state != ERR_NONE) {
return(state);
}
// get the response length (MQTT SUBACK response has to be 5 bytes long for single subscription)
size_t numBytes = _tl->getNumBytes();
if(numBytes != 5) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
#ifdef RADIOLIB_STATIC_ONLY
uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* response = new uint8_t[numBytes];
#endif
_tl->receive(response, numBytes);
if((response[0] == MQTT_SUBACK << 4) && (response[1] == 3)) {
// check packet ID
uint16_t receivedId = response[3] | response[2] << 8;
int16_t returnCode = response[4];
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
if(receivedId != packetId) {
return(ERR_MQTT_UNEXPECTED_PACKET_ID);
}
return(returnCode);
}
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_RESPONSE_MALFORMED);
}
int16_t MQTTClient::unsubscribe(const char* topicFilter) {
// encode packet length
size_t topicFilterLen = strlen(topicFilter);
uint32_t remainingLength = 2 + (2 + topicFilterLen);
uint8_t encoded[] = {0, 0, 0, 0};
size_t encodedBytes = encodeLength(remainingLength, encoded);
// build the UNSUBSCRIBE packet
#ifdef RADIOLIB_STATIC_ONLY
uint8_t packet[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#endif
// fixed header
packet[0] = (MQTT_UNSUBSCRIBE << 4) | 0b0010;
memcpy(packet + 1, encoded, encodedBytes);
// variable header
// packet ID
size_t pos = encodedBytes + 1;
uint16_t packetId = _packetId++;
packet[pos++] = (packetId & 0xFF00) >> 8;
packet[pos++] = packetId & 0x00FF;
// payload
// topic filter
packet[pos++] = (topicFilterLen & 0xFF00) >> 8;;
packet[pos++] = topicFilterLen & 0x00FF;
memcpy(packet + pos, topicFilter, topicFilterLen);
// send MQTT packet
int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength);
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
if(state != ERR_NONE) {
return(state);
}
// get the response length (MQTT UNSUBACK response has to be 4 bytes long)
size_t numBytes = _tl->getNumBytes();
if(numBytes != 4) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
#ifdef RADIOLIB_STATIC_ONLY
uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* response = new uint8_t[numBytes];
#endif
_tl->receive(response, numBytes);
if((response[0] == MQTT_UNSUBACK << 4) && (response[1] == 2)) {
// check packet ID
uint16_t receivedId = response[3] | response[2] << 8;
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
if(receivedId != packetId) {
return(ERR_MQTT_UNEXPECTED_PACKET_ID);
}
return(ERR_NONE);
}
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_RESPONSE_MALFORMED);
}
int16_t MQTTClient::ping() {
// build the PINGREQ packet
uint8_t packet[2];
// fixed header
packet[0] = (MQTT_PINGREQ << 4) | 0b0000;
packet[1] = 0x00;
// send MQTT packet
int16_t state = _tl->send(packet, 2);
if(state != ERR_NONE) {
return(state);
}
// get the response length (MQTT PINGRESP response has to be 2 bytes long)
size_t numBytes = _tl->getNumBytes();
if(numBytes != 2) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
#ifdef RADIOLIB_STATIC_ONLY
uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* response = new uint8_t[numBytes];
#endif
_tl->receive(response, numBytes);
if((response[0] == MQTT_PINGRESP << 4) && (response[1] == 0)) {
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_NONE);
}
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_RESPONSE_MALFORMED);
}
int16_t MQTTClient::check(void (*func)(const char*, const char*)) {
// ping the server
int16_t state = ping();
if(state != ERR_NONE) {
return(state);
}
// check new data
size_t numBytes = _tl->getNumBytes();
if(numBytes == 0) {
return(ERR_MQTT_NO_NEW_PACKET_AVAILABLE);
}
// read the PUBLISH packet from server
uint8_t* dataIn = new uint8_t[numBytes];
_tl->receive(dataIn, numBytes);
if(dataIn[0] == MQTT_PUBLISH << 4) {
uint8_t remLenFieldLen = 0;
uint32_t remainingLength = decodeLength(dataIn + 1, remLenFieldLen);
// get the topic
size_t topicLength = dataIn[remLenFieldLen + 2] | dataIn[remLenFieldLen + 1] << 8;
char* topic = new char[topicLength + 1];
memcpy(topic, dataIn + 4, topicLength);
topic[topicLength] = 0x00;
// get the message
size_t messageLength = remainingLength - topicLength - 2;
char* message = new char[messageLength + 1];
memcpy(message, dataIn + remLenFieldLen + 3 + topicLength, messageLength);
message[messageLength] = 0x00;
// execute the callback function provided by user
func(topic, message);
delete[] topic;
delete[] message;
delete[] dataIn;
return(ERR_NONE);
}
delete[] dataIn;
return(ERR_MQTT_NO_NEW_PACKET_AVAILABLE);
}
size_t MQTTClient::encodeLength(uint32_t len, uint8_t* encoded) {
// algorithm to encode packet length as per MQTT specification 3.1.1
size_t i = 0;
do {
encoded[i] = len % 128;
len /= 128;
if(len > 0) {
encoded[i] |= 128;
}
i++;
} while(len > 0);
return(i);
}
uint32_t MQTTClient::decodeLength(uint8_t* encoded, uint8_t& numBytes) {
// algorithm to decode packet length as per MQTT specification 3.1.1
uint32_t mult = 1;
uint32_t len = 0;
uint8_t i = 0;
do {
len += (encoded[i] & 127) * mult;
mult *= 128;
if(mult > 2097152) {
// malformed remaining length
return(0);
}
} while((encoded[i++] & 128) != 0);
numBytes = i;
return len;
}
#endif

View file

@ -1,147 +0,0 @@
#if !defined(_RADIOLIB_MQTT_H)
#define _RADIOLIB_MQTT_H
#include "../../TypeDef.h"
#if !defined(RADIOLIB_EXCLUDE_MQTT)
#include "../TransportLayer/TransportLayer.h"
// MQTT packet types
#define MQTT_CONNECT 0x01
#define MQTT_CONNACK 0x02
#define MQTT_PUBLISH 0x03
#define MQTT_PUBACK 0x04
#define MQTT_PUBREC 0x05
#define MQTT_PUBREL 0x06
#define MQTT_PUBCOMP 0x07
#define MQTT_SUBSCRIBE 0x08
#define MQTT_SUBACK 0x09
#define MQTT_UNSUBSCRIBE 0x0A
#define MQTT_UNSUBACK 0x0B
#define MQTT_PINGREQ 0x0C
#define MQTT_PINGRESP 0x0D
#define MQTT_DISCONNECT 0x0E
// MQTT CONNECT flags
#define MQTT_CONNECT_USER_NAME_FLAG 0b10000000
#define MQTT_CONNECT_PASSWORD_FLAG 0b01000000
#define MQTT_CONNECT_WILL_RETAIN 0b00100000
#define MQTT_CONNECT_WILL_FLAG 0b00000100
#define MQTT_CONNECT_CLEAN_SESSION 0b00000010
/*!
\class MQTTClient
\brief Client for simple MQTT communication.
*/
class MQTTClient {
public:
/*!
\brief Default constructor.
\param tl Pointer to the wireless module providing TransportLayer communication.
*/
explicit MQTTClient(TransportLayer* tl, uint16_t port = 1883);
// basic methods
/*!
\brief Connects to MQTT broker (/server).
\param host URL of the MQTT broker.
\param clientId ID of the client.
\param username Username to be used in the connection. Defaults to empty string (no username).
\param password Password to be used in the connection. Defaults to empty string (no password).
\param keepAlive Connection keep-alive period in seconds. Defaults to 60.
\param cleanSession MQTT CleanSession flag. Defaults to true.
\param willTopic MQTT will topic. Defaults to empty string (no will topic).
\param willMessage MQTT will message. Defaults to empty string (no will message).
\returns \ref status_codes
*/
int16_t connect(const char* host, const char* clientId, const char* userName = "", const char* password = "", uint16_t keepAlive = 60, bool cleanSession = true, const char* willTopic = "", const char* willMessage = "");
/*!
\brief Disconnect from MQTT broker.
\returns \ref status_codes
*/
int16_t disconnect();
/*!
\brief Publish MQTT message.
\param topic MQTT topic to which the message will be published.
\param message Message to be published.
\returns \ref status_codes
*/
int16_t publish(String& topic, String& message);
/*!
\brief Publish MQTT message.
\param topic MQTT topic to which the message will be published.
\param message Message to be published.
\returns \ref status_codes
*/
int16_t publish(const char* topic, const char* message);
/*!
\brief Subscribe to MQTT topic.
\param topicFilter Topic to subscribe to.
\returns \ref status_codes
*/
int16_t subscribe(const char* topicFilter);
/*!
\brief Unsubscribe from MQTT topic.
\param topicFilter Topic to unsubscribe from.
\returns \ref status_codes
*/
int16_t unsubscribe(const char* topicFilter);
/*!
\brief Ping MQTT broker. This method can be used to keep connection open.
\returns \ref status_codes
*/
int16_t ping();
/*!
\brief Set function to be called when checking new messages in subscribed topics.
\returns \ref status_codes
*/
int16_t check(void (*func)(const char*, const char*));
#ifndef RADIOLIB_GODMODE
private:
#endif
TransportLayer* _tl;
uint16_t _port;
uint16_t _packetId;
static size_t encodeLength(uint32_t len, uint8_t* encoded);
static uint32_t decodeLength(uint8_t* encoded, uint8_t& numBytes);
};
#endif
#endif

View file

@ -1,86 +0,0 @@
#ifndef _RADIOLIB_TRANSPORT_LAYER_H
#define _RADIOLIB_TRANSPORT_LAYER_H
#include "../../TypeDef.h"
/*!
\class TransportLayer
\brief Provides common interface for protocols that run on modules with Internet connectivity, such as HTTP or MQTT.
Because this class is used mainly as interface, all of its virtual members must be implemented in the module class.
*/
class TransportLayer {
public:
// constructor
// this class is purely virtual and does not require explicit constructor
// basic methods
/*!
\brief Open transport layer connection.
\param host Host to connect to.
\param protocol Transport protocol to use. Usually "TCP" or "UDP".
\param port to be used for the connection.
\param tcpKeepAlive TCP keep alive interval. Defaults to 0.
\returns \ref status_codes
*/
virtual int16_t openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive = 0) = 0;
/*!
\brief Close transport layer connection.
\returns \ref status_codes
*/
virtual int16_t closeTransportConnection() = 0;
/*!
\brief Send string-based data.
\param string String data to be sent.
\returns \ref status_codes
*/
virtual int16_t send(const char* data) = 0;
/*!
\brief Send arbitrary binary data.
\param data Data to be sent.
\param len Number of bytes to send.
\returns \ref status_codes
*/
virtual int16_t send(uint8_t* data, size_t len) = 0;
/*!
\brief Receive data.
\param data Pointer to array to save the received data.
\param len Number of bytes to read.
\param timeout Reception timeout in ms. Defaults to 10000.
\returns \ref status_codes
*/
virtual size_t receive(uint8_t* data, size_t len, uint32_t timeout = 10000) = 0;
/*!
\brief Get number of received bytes.
\param timeout Reception timeout in ms. Defaults to 10000.
\param minBytes Minimum required number of bytes that must be received.
\returns Number of received bytes, or 0 on timeout.
*/
virtual size_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10) = 0;
};
#endif