[LoRaWAN] Rework bands, official Rx windows, support ADR, confirm frames, improve EEPROM handling, support clock drift (#867)
* [LoRaWAN] rework bands, add ADR, partial MAC support Known problem: terribly bad at receiving downlinks Mask-list bands (e.g. US915) untested, likely a few bugs * [LoRaWAN] Change Rx windows from CAD to RxSingle * [LoRaWAN] improve persistence, better Rx windows, wear leveling, confirmed frames * [LoRaWAN] Module-independent (OTAA) Rx windows, fix confirming downlinks * [LoRaWAN] Implement SX127x support, fix MAC uplinking, support clock drift * [ArduinoHal] fix clock drift calculation * [LoRaWAN] Improve band & ADR logic, allow setting ADR, DR, subband, update examples * [LoRaWAN] Fix EU868 coding rate, improve example * [LoRaWAN] fix unused channel index * [LoRaWAN] fix merge issue (deleted line) * [LoRaWAN] fix CSMA calling now incorrect function * [LoRaWAN] fix include logic * [LoRaWAN] fix warnings, remove duplicate function * [LoRaWAN] improve examples, add unified sendReceive, bugfixes, add FSK * [LoRaWAN] improve examples * [LoRaWAN] add new keywords, add debug guard * [SX127x] Updated startReceive interface to be more in line with SX126x * [SX127x] Added public method to convert from bytes to symbols * [LoRaWAN] Update start receive for SX127x * Added note about LoRaWAN beta * [SX127x] Fixed potential float overflow --------- Co-authored-by: jgromes <jan.gromes@gmail.com>
This commit is contained in:
parent
ce202deb7f
commit
82258105b7
20 changed files with 2596 additions and 1807 deletions
|
@ -43,7 +43,8 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
|
|||
* [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules:
|
||||
SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x
|
||||
* [__LoRaWAN__](https://lora-alliance.org/) using LoRa for modules:
|
||||
SX127x, RFM9x, SX126x and SX128x
|
||||
SX127x, RFM9x, SX126x and SX128x
|
||||
* NOTE: LoRaWAN support is currently in beta, feedback via [Issues](https://github.com/jgromes/RadioLib/issues) and [Discussions](https://github.com/jgromes/RadioLib/discussions) is appreciated!
|
||||
|
||||
### Supported Arduino platforms:
|
||||
* __Arduino__
|
||||
|
|
|
@ -7,14 +7,12 @@
|
|||
After your device is registered, you can run this example.
|
||||
The device will join the network and start uploading data.
|
||||
|
||||
NOTE: LoRaWAN requires storing some parameters persistently!
|
||||
RadioLib does this by using EEPROM, by default
|
||||
starting at address 0 and using 32 bytes.
|
||||
If you already use EEPROM in your application,
|
||||
you will have to either avoid this range, or change it
|
||||
by setting a different start address by changing the value of
|
||||
RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either
|
||||
during build or in src/BuildOpt.h.
|
||||
LoRaWAN v1.1 requires the use of EEPROM (persistent storage).
|
||||
Please refer to the 'persistent' example once you are familiar
|
||||
with LoRaWAN.
|
||||
Running this examples REQUIRES you to check "Resets DevNonces"
|
||||
on your LoRaWAN dashboard. Refer to the network's
|
||||
documentation on how to do this.
|
||||
|
||||
For default module settings, see the wiki page
|
||||
https://github.com/jgromes/RadioLib/wiki/Default-configuration
|
||||
|
@ -53,13 +51,6 @@ void setup() {
|
|||
while(true);
|
||||
}
|
||||
|
||||
// first we need to initialize the device storage
|
||||
// this will reset all persistently stored parameters
|
||||
// NOTE: This should only be done once prior to first joining a network!
|
||||
// After wiping persistent storage, you will also have to reset
|
||||
// the end device in TTN and perform the join procedure again!
|
||||
//node.wipe();
|
||||
|
||||
// application identifier - pre-LoRaWAN 1.1.0, this was called appEUI
|
||||
// when adding new end device in TTN, you will have to enter this number
|
||||
// you can pick any number you want, but it has to be unique
|
||||
|
@ -87,17 +78,23 @@ void setup() {
|
|||
// and can be set to NULL
|
||||
|
||||
// some frequency bands only use a subset of the available channels
|
||||
// you can set the starting channel and their number
|
||||
// for example, the following corresponds to US915 FSB2 in TTN
|
||||
// you can select the specific band or set the first channel and last channel
|
||||
// for example, either of the following corresponds to US915 FSB2 in TTN
|
||||
/*
|
||||
node.startChannel = 8;
|
||||
node.numChannels = 8;
|
||||
node.selectSubband(2);
|
||||
node.selectSubband(8, 15);
|
||||
*/
|
||||
|
||||
// now we can start the activation
|
||||
// this can take up to 20 seconds, and requires a LoRaWAN gateway in range
|
||||
// this can take up to 10 seconds, and requires a LoRaWAN gateway in range
|
||||
// a specific starting-datarate can be selected in dynamic bands (e.g. EU868):
|
||||
/*
|
||||
uint8_t joinDr = 4;
|
||||
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr);
|
||||
*/
|
||||
Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
||||
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
|
||||
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
|
@ -106,20 +103,6 @@ void setup() {
|
|||
while(true);
|
||||
}
|
||||
|
||||
// after the device has been activated,
|
||||
// network can be rejoined after device power cycle
|
||||
// by calling "begin"
|
||||
/*
|
||||
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
||||
state = node.begin();
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while(true);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// counter to keep track of transmitted packets
|
||||
|
@ -129,23 +112,10 @@ void loop() {
|
|||
// send uplink to port 10
|
||||
Serial.print(F("[LoRaWAN] Sending uplink packet ... "));
|
||||
String strUp = "Hello World! #" + String(count++);
|
||||
int state = node.uplink(strUp, 10);
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
|
||||
// after uplink, you can call downlink(),
|
||||
// to receive any possible reply from the server
|
||||
// this function must be called within a few seconds
|
||||
// after uplink to receive the downlink!
|
||||
Serial.print(F("[LoRaWAN] Waiting for downlink ... "));
|
||||
String strDown;
|
||||
state = node.downlink(strDown);
|
||||
int state = node.sendReceive(strUp, 10, strDown);
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
Serial.println(F("received a downlink!"));
|
||||
|
||||
// print data of the packet (if there are any)
|
||||
Serial.print(F("[LoRaWAN] Data:\t\t"));
|
||||
|
@ -171,7 +141,7 @@ void loop() {
|
|||
Serial.println(F(" Hz"));
|
||||
|
||||
} else if(state == RADIOLIB_ERR_RX_TIMEOUT) {
|
||||
Serial.println(F("timeout!"));
|
||||
Serial.println(F("no downlink!"));
|
||||
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
|
@ -179,5 +149,5 @@ void loop() {
|
|||
}
|
||||
|
||||
// wait before sending another packet
|
||||
delay(10000);
|
||||
delay(30000);
|
||||
}
|
||||
|
|
|
@ -8,15 +8,13 @@
|
|||
The device will start uploading data directly,
|
||||
without having to join the network.
|
||||
|
||||
NOTE: LoRaWAN requires storing some parameters persistently!
|
||||
RadioLib does this by using EEPROM, by default
|
||||
starting at address 0 and using 32 bytes.
|
||||
If you already use EEPROM in your application,
|
||||
you will have to either avoid this range, or change it
|
||||
by setting a different start address by changing the value of
|
||||
RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either
|
||||
during build or in src/BuildOpt.h.
|
||||
|
||||
LoRaWAN v1.1 requires the use of EEPROM (persistent storage).
|
||||
Please refer to the 'persistent' example once you are familiar
|
||||
with LoRaWAN.
|
||||
Running this examples REQUIRES you to check "Resets DevNonces"
|
||||
on your LoRaWAN dashboard. Refer to the network's
|
||||
documentation on how to do this.
|
||||
|
||||
For default module settings, see the wiki page
|
||||
https://github.com/jgromes/RadioLib/wiki/Default-configuration
|
||||
|
||||
|
@ -54,13 +52,6 @@ void setup() {
|
|||
while(true);
|
||||
}
|
||||
|
||||
// first we need to initialize the device storage
|
||||
// this will reset all persistently stored parameters
|
||||
// NOTE: This should only be done once prior to first joining a network!
|
||||
// After wiping persistent storage, you will also have to reset
|
||||
// the end device in TTN!
|
||||
//node.wipe();
|
||||
|
||||
// device address - this number can be anything
|
||||
// when adding new end device in TTN, you can generate this number,
|
||||
// or you can set any value you want, provided it is unique
|
||||
|
@ -83,16 +74,27 @@ void setup() {
|
|||
// and can be set to NULL
|
||||
|
||||
// some frequency bands only use a subset of the available channels
|
||||
// you can set the starting channel and their number
|
||||
// for example, the following corresponds to US915 FSB2 in TTN
|
||||
// you can select the specific band or set the first channel and last channel
|
||||
// for example, either of the following corresponds to US915 FSB2 in TTN
|
||||
/*
|
||||
node.startChannel = 8;
|
||||
node.numChannels = 8;
|
||||
node.selectSubband(2);
|
||||
node.selectSubband(8, 15);
|
||||
*/
|
||||
|
||||
// if using EU868 on ABP in TTN, you need to set the SF for RX2 window manually
|
||||
/*
|
||||
node.rx2.drMax = 3;
|
||||
*/
|
||||
|
||||
// to start a LoRaWAN v1.1 session, the user should also provide
|
||||
// fNwkSIntKey and sNwkSIntKey similar to nwkSKey and appSKey
|
||||
/*
|
||||
state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey);
|
||||
*/
|
||||
|
||||
// start the device by directly providing the encryption keys and device address
|
||||
Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
||||
state = node.beginAPB(devAddr, (uint8_t*)nwkSKey, (uint8_t*)appSKey);
|
||||
state = node.beginABP(devAddr, nwkSKey, appSKey);
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
|
@ -101,20 +103,6 @@ void setup() {
|
|||
while(true);
|
||||
}
|
||||
|
||||
// after the device has been activated,
|
||||
// network can be rejoined after device power cycle
|
||||
// by calling "begin"
|
||||
/*
|
||||
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
||||
state = node.begin();
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while(true);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// counter to keep track of transmitted packets
|
||||
|
@ -124,23 +112,10 @@ void loop() {
|
|||
// send uplink to port 10
|
||||
Serial.print(F("[LoRaWAN] Sending uplink packet ... "));
|
||||
String strUp = "Hello World! #" + String(count++);
|
||||
int state = node.uplink(strUp, 10);
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
|
||||
// after uplink, you can call downlink(),
|
||||
// to receive any possible reply from the server
|
||||
// this function must be called within a few seconds
|
||||
// after uplink to receive the downlink!
|
||||
Serial.print(F("[LoRaWAN] Waiting for downlink ... "));
|
||||
String strDown;
|
||||
state = node.downlink(strDown);
|
||||
int state = node.sendReceive(strUp, 10, strDown);
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
Serial.println(F("received a downlink!"));
|
||||
|
||||
// print data of the packet (if there are any)
|
||||
Serial.print(F("[LoRaWAN] Data:\t\t"));
|
||||
|
@ -166,7 +141,7 @@ void loop() {
|
|||
Serial.println(F(" Hz"));
|
||||
|
||||
} else if(state == RADIOLIB_ERR_RX_TIMEOUT) {
|
||||
Serial.println(F("timeout!"));
|
||||
Serial.println(F("no downlink!"));
|
||||
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
|
@ -174,5 +149,5 @@ void loop() {
|
|||
}
|
||||
|
||||
// wait before sending another packet
|
||||
delay(10000);
|
||||
delay(30000);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
RadioLib LoRaWAN End Device Example
|
||||
|
||||
This example assumes you have tried one of the OTAA or ABP
|
||||
examples and are familiar with the required keys and procedures.
|
||||
This example restores and saves a session such that you can use
|
||||
deepsleep or survive power cycles. Before you start, you will
|
||||
have to register your device at https://www.thethingsnetwork.org/
|
||||
and join the network using either OTAA or ABP.
|
||||
Please refer to one of the other examples for more
|
||||
information regarding joining a network.
|
||||
|
||||
NOTE: LoRaWAN requires storing some parameters persistently!
|
||||
RadioLib does this by using EEPROM, by default
|
||||
starting at address 0 and using 384 bytes.
|
||||
If you already use EEPROM in your application,
|
||||
you will have to either avoid this range, or change it
|
||||
by setting a different start address by changing the value of
|
||||
RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either
|
||||
during build or in src/BuildOpt.h.
|
||||
|
||||
For default module settings, see the wiki page
|
||||
https://github.com/jgromes/RadioLib/wiki/Default-configuration
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// RESET pin: 9
|
||||
// DIO1 pin: 3
|
||||
SX1278 radio = new Module(10, 2, 9, 3);
|
||||
|
||||
// create the node instance on the EU-868 band
|
||||
// using the radio module and the encryption key
|
||||
// make sure you are using the correct band
|
||||
// based on your geographical location!
|
||||
LoRaWANNode node(&radio, &EU868);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize SX1278 with default settings
|
||||
Serial.print(F("[SX1278] Initializing ... "));
|
||||
int state = radio.begin();
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while(true);
|
||||
}
|
||||
|
||||
// first we need to initialize the device storage
|
||||
// this will reset all persistently stored parameters
|
||||
// NOTE: This should only be done once prior to first joining a network!
|
||||
// After wiping persistent storage, you will also have to reset
|
||||
// the end device in TTN and perform the join procedure again!
|
||||
// Here, a delay is added to make sure that during re-flashing
|
||||
// the .wipe() is not triggered and the session is lost
|
||||
//delay(5000);
|
||||
//node.wipe();
|
||||
|
||||
// now we can start the activation
|
||||
// Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
||||
// uint64_t joinEUI = 0x12AD1011B0C0FFEE;
|
||||
// uint64_t devEUI = 0x70B3D57ED005E120;
|
||||
// uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65,
|
||||
// 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 };
|
||||
// uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65,
|
||||
// 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 };
|
||||
// state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
|
||||
|
||||
// after the device has been activated,
|
||||
// the session can be restored without rejoining after device power cycle
|
||||
// on EEPROM-enabled boards by calling "restore"
|
||||
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
||||
state = node.restore();
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// counter to keep track of transmitted packets
|
||||
int count = 0;
|
||||
|
||||
void loop() {
|
||||
// send uplink to port 10
|
||||
Serial.print(F("[LoRaWAN] Sending uplink packet ... "));
|
||||
String strUp = "Hello World! #" + String(count++);
|
||||
String strDown;
|
||||
int state = node.sendReceive(strUp, 10, strDown);
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("received a downlink!"));
|
||||
|
||||
// print data of the packet (if there are any)
|
||||
Serial.print(F("[LoRaWAN] Data:\t\t"));
|
||||
if(strDown.length() > 0) {
|
||||
Serial.println(strDown);
|
||||
} else {
|
||||
Serial.println(F("<MAC commands only>"));
|
||||
}
|
||||
|
||||
// print RSSI (Received Signal Strength Indicator)
|
||||
Serial.print(F("[LoRaWAN] RSSI:\t\t"));
|
||||
Serial.print(radio.getRSSI());
|
||||
Serial.println(F(" dBm"));
|
||||
|
||||
// print SNR (Signal-to-Noise Ratio)
|
||||
Serial.print(F("[LoRaWAN] SNR:\t\t"));
|
||||
Serial.print(radio.getSNR());
|
||||
Serial.println(F(" dB"));
|
||||
|
||||
// print frequency error
|
||||
Serial.print(F("[LoRaWAN] Frequency error:\t"));
|
||||
Serial.print(radio.getFrequencyError());
|
||||
Serial.println(F(" Hz"));
|
||||
|
||||
} else if(state == RADIOLIB_ERR_RX_TIMEOUT) {
|
||||
Serial.println(F("no downlink!"));
|
||||
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
|
||||
// on EEPROM enabled boards, you can save the current session
|
||||
// by calling "saveSession" which allows retrieving the session after reboot or deepsleep
|
||||
node.saveSession();
|
||||
|
||||
// wait before sending another packet
|
||||
// alternatively, call a deepsleep function here
|
||||
// make sure to send the radio to sleep as well using radio.sleep()
|
||||
delay(30000);
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
RadioLib LoRaWAN End Device Example
|
||||
|
||||
This example joins a LoRaWAN network and will send
|
||||
uplink packets. Before you start, you will have to
|
||||
register your device at https://www.thethingsnetwork.org/
|
||||
After your device is registered, you can run this example.
|
||||
The device will join the network and start uploading data.
|
||||
|
||||
Also, most of the possible and available functions are
|
||||
shown here for reference.
|
||||
|
||||
LoRaWAN v1.1 requires the use of EEPROM (persistent storage).
|
||||
Please refer to the 'persistent' example once you are familiar
|
||||
with LoRaWAN.
|
||||
Running this examples REQUIRES you to check "Resets DevNonces"
|
||||
on your LoRaWAN dashboard. Refer to the network's
|
||||
documentation on how to do this.
|
||||
|
||||
For default module settings, see the wiki page
|
||||
https://github.com/jgromes/RadioLib/wiki/Default-configuration
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// RESET pin: 9
|
||||
// DIO1 pin: 3
|
||||
SX1278 radio = new Module(10, 2, 9, 3);
|
||||
|
||||
// create the node instance on the EU-868 band
|
||||
// using the radio module and the encryption key
|
||||
// make sure you are using the correct band
|
||||
// based on your geographical location!
|
||||
LoRaWANNode node(&radio, &EU868);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize SX1278 with default settings
|
||||
Serial.print(F("[SX1278] Initializing ... "));
|
||||
int state = radio.begin();
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while(true);
|
||||
}
|
||||
|
||||
// application identifier - pre-LoRaWAN 1.1.0, this was called appEUI
|
||||
// when adding new end device in TTN, you will have to enter this number
|
||||
// you can pick any number you want, but it has to be unique
|
||||
uint64_t joinEUI = 0x12AD1011B0C0FFEE;
|
||||
|
||||
// device identifier - this number can be anything
|
||||
// when adding new end device in TTN, you can generate this number,
|
||||
// or you can set any value you want, provided it is also unique
|
||||
uint64_t devEUI = 0x70B3D57ED005E120;
|
||||
|
||||
// select some encryption keys which will be used to secure the communication
|
||||
// there are two of them - network key and application key
|
||||
// because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long
|
||||
|
||||
// network key is the ASCII string "topSecretKey1234"
|
||||
uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65,
|
||||
0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 };
|
||||
|
||||
// application key is the ASCII string "aDifferentKeyABC"
|
||||
uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65,
|
||||
0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 };
|
||||
|
||||
// prior to LoRaWAN 1.1.0, only a single "nwkKey" is used
|
||||
// when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded
|
||||
// and can be set to NULL
|
||||
|
||||
// some frequency bands only use a subset of the available channels
|
||||
// you can select the specific band or set the first channel and last channel
|
||||
// for example, either of the following corresponds to US915 FSB2 in TTN
|
||||
/*
|
||||
node.selectSubband(2);
|
||||
node.selectSubband(8, 15);
|
||||
*/
|
||||
|
||||
// now we can start the activation
|
||||
// this can take up to 10 seconds, and requires a LoRaWAN gateway in range
|
||||
// a specific starting-datarate can be selected in dynamic bands (e.g. EU868):
|
||||
/*
|
||||
uint8_t joinDr = 4;
|
||||
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr);
|
||||
*/
|
||||
Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
||||
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
|
||||
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while(true);
|
||||
}
|
||||
|
||||
// after the device has been activated,
|
||||
// the session can be restored without rejoining after device power cycle
|
||||
// on EEPROM-enabled boards by calling "restore"
|
||||
/*
|
||||
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
||||
state = node.restore();
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while(true);
|
||||
}
|
||||
*/
|
||||
|
||||
// disable the ADR algorithm
|
||||
node.setADR(false);
|
||||
|
||||
// set a fixed datarate
|
||||
node.setDatarate(5);
|
||||
|
||||
// enable CSMA
|
||||
// this tries to minimize packet loss by searching for a free channel
|
||||
// before actually sending an uplink
|
||||
node.setCSMA(6, 2, true);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
int state = RADIOLIB_ERR_NONE;
|
||||
|
||||
// set battery fill level,
|
||||
// 0 = external power source
|
||||
// 1 = lowest (empty battery)
|
||||
// 254 = highest (full battery)
|
||||
// 255 = unable to measure
|
||||
uint8_t battLevel = 146;
|
||||
node.setDeviceStatus(battLevel);
|
||||
|
||||
// retrieve the last uplink frame counter
|
||||
uint32_t fcntUp = node.getFcntUp();
|
||||
|
||||
Serial.print(F("[LoRaWAN] Sending uplink packet ... "));
|
||||
String strUp = "Hello World! #" + String(fcntUp);
|
||||
|
||||
// send a confirmed uplink to port 10 every 64th frame
|
||||
if(fcntUp % 64 == 0) {
|
||||
state = node.uplink(strUp, 10, true);
|
||||
} else {
|
||||
state = node.uplink(strUp, 10);
|
||||
}
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
|
||||
// after uplink, you can call downlink(),
|
||||
// to receive any possible reply from the server
|
||||
// this function must be called within a few seconds
|
||||
// after uplink to receive the downlink!
|
||||
Serial.print(F("[LoRaWAN] Waiting for downlink ... "));
|
||||
String strDown;
|
||||
state = node.downlink(strDown);
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
|
||||
// print data of the packet (if there are any)
|
||||
Serial.print(F("[LoRaWAN] Data:\t\t"));
|
||||
if(strDown.length() > 0) {
|
||||
Serial.println(strDown);
|
||||
} else {
|
||||
Serial.println(F("<MAC commands only>"));
|
||||
}
|
||||
|
||||
// print RSSI (Received Signal Strength Indicator)
|
||||
Serial.print(F("[LoRaWAN] RSSI:\t\t"));
|
||||
Serial.print(radio.getRSSI());
|
||||
Serial.println(F(" dBm"));
|
||||
|
||||
// print SNR (Signal-to-Noise Ratio)
|
||||
Serial.print(F("[LoRaWAN] SNR:\t\t"));
|
||||
Serial.print(radio.getSNR());
|
||||
Serial.println(F(" dB"));
|
||||
|
||||
// print frequency error
|
||||
Serial.print(F("[LoRaWAN] Frequency error:\t"));
|
||||
Serial.print(radio.getFrequencyError());
|
||||
Serial.println(F(" Hz"));
|
||||
|
||||
} else if(state == RADIOLIB_ERR_RX_TIMEOUT) {
|
||||
Serial.println(F("timeout!"));
|
||||
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
|
||||
// on EEPROM enabled boards, you can save the current session
|
||||
// by calling "saveSession" which allows retrieving the session after reboot or deepsleep
|
||||
/*
|
||||
node.saveSession();
|
||||
*/
|
||||
|
||||
// wait before sending another packet
|
||||
delay(30000);
|
||||
}
|
15
keywords.txt
15
keywords.txt
|
@ -124,7 +124,6 @@ setSyncWord KEYWORD2
|
|||
setOutputPower KEYWORD2
|
||||
setCurrentLimit KEYWORD2
|
||||
setPreambleLength KEYWORD2
|
||||
invertPreamble KEYWORD2
|
||||
setGain KEYWORD2
|
||||
getFrequencyError KEYWORD2
|
||||
getRSSI KEYWORD2
|
||||
|
@ -222,7 +221,6 @@ spectralScanStart KEYWORD2
|
|||
spectralScanAbort KEYWORD2
|
||||
spectralScanGetStatus KEYWORD2
|
||||
spectralScanGetResult KEYWORD2
|
||||
setPaConfig KEYWORD2
|
||||
|
||||
# nRF24
|
||||
setIrqAction KEYWORD2
|
||||
|
@ -291,12 +289,18 @@ setModem KEYWORD2
|
|||
|
||||
# LoRaWAN
|
||||
wipe KEYWORD2
|
||||
restoreOTAA KEYWORD2
|
||||
restore KEYWORD2
|
||||
beginOTAA KEYWORD2
|
||||
beginABP KEYWORD2
|
||||
saveSession KEYWORD2
|
||||
uplink KEYWORD2
|
||||
downlink KEYWORD2
|
||||
configureChannel KEYWORD2
|
||||
sendReceive KEYWORD2
|
||||
setDeviceStatus KEYWORD2
|
||||
setDatarate KEYWORD2
|
||||
setADR KEYWORD2
|
||||
selectSubband KEYWORD2
|
||||
setCSMA KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
|
@ -408,4 +412,5 @@ RADIOLIB_ERR_COMMAND_QUEUE_EMPTY LITERAL1
|
|||
RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1
|
||||
RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1
|
||||
RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1
|
||||
RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1
|
||||
RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1
|
||||
RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1
|
|
@ -58,19 +58,35 @@ void inline ArduinoHal::detachInterrupt(uint32_t interruptNum) {
|
|||
}
|
||||
|
||||
void inline ArduinoHal::delay(unsigned long ms) {
|
||||
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
|
||||
::delay(ms);
|
||||
#else
|
||||
::delay(ms * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS));
|
||||
#endif
|
||||
}
|
||||
|
||||
void inline ArduinoHal::delayMicroseconds(unsigned long us) {
|
||||
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
|
||||
::delayMicroseconds(us);
|
||||
#else
|
||||
::delayMicroseconds(us * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS));
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long inline ArduinoHal::millis() {
|
||||
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
|
||||
return(::millis());
|
||||
#else
|
||||
return(::millis() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS));
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long inline ArduinoHal::micros() {
|
||||
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
|
||||
return(::micros());
|
||||
#else
|
||||
return(::micros() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS));
|
||||
#endif
|
||||
}
|
||||
|
||||
long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) {
|
||||
|
|
|
@ -442,7 +442,19 @@
|
|||
|
||||
// the amount of space allocated to the persistent storage
|
||||
#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE)
|
||||
#define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0xD0)
|
||||
#define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x0180)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Uncomment on boards whose clock runs too slow or too fast
|
||||
* Set the value according to the following scheme:
|
||||
* Enable timestamps on your terminal
|
||||
* Print something to terminal, wait 1000 milliseconds, print something again
|
||||
* If the difference is e.g. 1014 milliseconds between the prints, set this value to 14
|
||||
* Or, for more accuracy, wait for 100,000 milliseconds and divide the total drift by 100
|
||||
*/
|
||||
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
|
||||
//#define RADIOLIB_CLOCK_DRIFT_MS (0)
|
||||
#endif
|
||||
|
||||
// This only compiles on STM32 boards with SUBGHZ module, but also
|
||||
|
|
10
src/Hal.cpp
10
src/Hal.cpp
|
@ -60,14 +60,14 @@ uint32_t RadioLibHal::getPersistentAddr(uint32_t id) {
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void RadioLibHal::setPersistentParameter(uint32_t id, T val) {
|
||||
void RadioLibHal::setPersistentParameter(uint32_t id, T val, uint32_t offset) {
|
||||
uint8_t *ptr = (uint8_t*)&val;
|
||||
this->writePersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + RadioLibPersistentParamTable[id], ptr, sizeof(T));
|
||||
this->writePersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + RadioLibPersistentParamTable[id] + offset, ptr, sizeof(T));
|
||||
}
|
||||
|
||||
template void RadioLibHal::setPersistentParameter(uint32_t id, uint8_t val);
|
||||
template void RadioLibHal::setPersistentParameter(uint32_t id, uint16_t val);
|
||||
template void RadioLibHal::setPersistentParameter(uint32_t id, uint32_t val);
|
||||
template void RadioLibHal::setPersistentParameter(uint32_t id, uint8_t val, uint32_t offset);
|
||||
template void RadioLibHal::setPersistentParameter(uint32_t id, uint16_t val, uint32_t offset);
|
||||
template void RadioLibHal::setPersistentParameter(uint32_t id, uint32_t val, uint32_t offset);
|
||||
|
||||
template<typename T>
|
||||
T RadioLibHal::getPersistentParameter(uint32_t id) {
|
||||
|
|
83
src/Hal.h
83
src/Hal.h
|
@ -7,47 +7,59 @@
|
|||
#include "BuildOpt.h"
|
||||
|
||||
// list of persistent parameters
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID (0) // this is NOT the LoRaWAN version, but version of this table
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID (1)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (2)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID (3)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID (4)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (5)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (6)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (7)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID (8)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID (9)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID (10)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID (11)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID (12)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (13)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID (14)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID (15)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_ID (16)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_ID (17)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID (18)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID (0) // this is NOT the LoRaWAN version, but version of this table
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID (1)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID (2)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID (3)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID (4)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID (5)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID (6)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID (7)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID (8)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (9)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID (10)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID (11)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (12)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (13)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID (14)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (15)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID (16)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID (17)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID (18)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID (19)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID (20)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID (21)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (22)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID (23)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID (24)
|
||||
|
||||
static const uint32_t RadioLibPersistentParamTable[] = {
|
||||
0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION
|
||||
0x08, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID
|
||||
0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID
|
||||
0x01, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID
|
||||
0x03, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION
|
||||
0x04, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID
|
||||
0x05, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID
|
||||
0x06, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID
|
||||
0x07, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID
|
||||
0x0A, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID
|
||||
0x0B, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID
|
||||
0x0C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID
|
||||
0x10, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID
|
||||
0x20, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID
|
||||
0x30, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID
|
||||
0x40, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID
|
||||
0x50, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID
|
||||
0x54, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID
|
||||
0x58, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID
|
||||
0x5C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID
|
||||
0x60, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST
|
||||
0x70, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID
|
||||
0x74, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID
|
||||
0x78, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_AFCNT_DOWN_ID
|
||||
0x7C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NFCNT_DOWN_ID
|
||||
0x80, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_ID
|
||||
0x84, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_ID
|
||||
0x88, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID
|
||||
0xD0, // end
|
||||
0x50, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID
|
||||
0x54, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID
|
||||
0x58, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID
|
||||
0x5C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID
|
||||
0x60, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID
|
||||
0x64, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID
|
||||
0x68, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID
|
||||
0x6C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID
|
||||
0x70, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID
|
||||
0x8E, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID
|
||||
0xD0, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID
|
||||
0x0180, // end
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -287,9 +299,10 @@ class RadioLibHal {
|
|||
will be stored in the system endian!
|
||||
\param id Parameter ID to save at.
|
||||
\param val Value to set.
|
||||
\param offset An additional offset added to the address.
|
||||
*/
|
||||
template<typename T>
|
||||
void setPersistentParameter(uint32_t id, T val);
|
||||
void setPersistentParameter(uint32_t id, T val, uint32_t offset = 0);
|
||||
|
||||
/*!
|
||||
\brief Method to get arbitrary parameter from persistent storage.
|
||||
|
|
|
@ -553,6 +553,11 @@
|
|||
*/
|
||||
#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1114)
|
||||
|
||||
/*!
|
||||
\brief Datarate requested by user is invalid.
|
||||
*/
|
||||
#define RADIOLIB_ERR_DATA_RATE_INVALID (-1115)
|
||||
|
||||
/*!
|
||||
\}
|
||||
*/
|
||||
|
|
|
@ -1436,6 +1436,25 @@ uint32_t SX126x::getTimeOnAir(size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t SX126x::calculateRxTimeout(uint32_t timeoutUs) {
|
||||
// the timeout value is given in units of 15.625 microseconds
|
||||
// the calling function should provide some extra width, as this number of units is truncated to integer
|
||||
uint32_t timeout = timeoutUs / 15.625;
|
||||
return(timeout);
|
||||
}
|
||||
|
||||
int16_t SX126x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) {
|
||||
irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT; // flags that can appear in the IRQ register
|
||||
irqMask = RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT; // flags that will trigger DIO0
|
||||
return(RADIOLIB_ERR_NONE);
|
||||
}
|
||||
|
||||
bool SX126x::isRxTimeout() {
|
||||
uint16_t irq = getIrqStatus();
|
||||
bool rxTimedOut = irq & RADIOLIB_SX126X_IRQ_TIMEOUT;
|
||||
return(rxTimedOut);
|
||||
}
|
||||
|
||||
int16_t SX126x::implicitHeader(size_t len) {
|
||||
return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C
|
||||
#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88
|
||||
#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F
|
||||
#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0x0A
|
||||
#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0
|
||||
|
||||
// status commands
|
||||
#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0
|
||||
|
@ -219,7 +219,7 @@
|
|||
#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error
|
||||
#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received
|
||||
#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected
|
||||
#define RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected
|
||||
#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected
|
||||
#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received
|
||||
#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed
|
||||
#define RADIOLIB_SX126X_IRQ_RX_DEFAULT 0b0000001001100010 // 14 0 default for Rx (RX_DONE, TIMEOUT, CRC_ERR and HEADER_ERR)
|
||||
|
@ -949,6 +949,27 @@ class SX126x: public PhysicalLayer {
|
|||
*/
|
||||
uint32_t getTimeOnAir(size_t len) override;
|
||||
|
||||
/*!
|
||||
\brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
|
||||
\param timeoutUs Timeout in microseconds to listen for
|
||||
\returns Timeout value in a unit that is specific for the used module
|
||||
*/
|
||||
uint32_t calculateRxTimeout(uint32_t timeoutUs);
|
||||
|
||||
/*!
|
||||
\brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks
|
||||
\param irqFlags The flags for which IRQs must be triggered
|
||||
\param irqMask Mask indicating which IRQ triggers a DIO
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask);
|
||||
|
||||
/*!
|
||||
\brief Check whether the IRQ bit for RxTimeout is set
|
||||
\returns \ref RxTimeout IRQ is set
|
||||
*/
|
||||
bool isRxTimeout();
|
||||
|
||||
/*!
|
||||
\brief Set implicit header mode for future reception/transmission.
|
||||
\param len Payload length in bytes.
|
||||
|
|
|
@ -432,10 +432,20 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) {
|
|||
return(setMode(mode));
|
||||
}
|
||||
|
||||
int16_t SX127x::startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, size_t len) {
|
||||
int16_t SX127x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) {
|
||||
(void)irqFlags;
|
||||
(void)irqMask;
|
||||
return(startReceive((uint8_t)len, (uint8_t)mode));
|
||||
uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS;
|
||||
if(timeout != 0) {
|
||||
// for non-zero timeout value, change mode to Rx single and set the timeout
|
||||
mode = RADIOLIB_SX127X_RXSINGLE;
|
||||
uint8_t msb_sym = (timeout > 0x3FF) ? 0x3 : (uint8_t)(timeout >> 8);
|
||||
uint8_t lsb_sym = (timeout > 0x3FF) ? 0xFF : (uint8_t)(timeout & 0xFF);
|
||||
int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0);
|
||||
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym);
|
||||
RADIOLIB_ASSERT(state);
|
||||
}
|
||||
return(startReceive((uint8_t)len, mode));
|
||||
}
|
||||
|
||||
void SX127x::setDio0Action(void (*func)(void), uint32_t dir) {
|
||||
|
@ -1221,28 +1231,45 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) {
|
|||
return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen));
|
||||
}
|
||||
|
||||
float SX127x::getNumSymbols(size_t len) {
|
||||
// get symbol length in us
|
||||
float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
|
||||
|
||||
// get Low Data Rate optimization flag
|
||||
float de = 0;
|
||||
if (symbolLength >= 16.0) {
|
||||
de = 1;
|
||||
}
|
||||
|
||||
// get explicit/implicit header enabled flag
|
||||
float ih = (float) this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0);
|
||||
|
||||
// get CRC enabled flag
|
||||
float crc = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2);
|
||||
|
||||
// get number of preamble symbols
|
||||
float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB));
|
||||
|
||||
// get number of payload symbols
|
||||
float n_pay = 8.0 + RADIOLIB_MAX(ceil((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0);
|
||||
|
||||
// add 4.25 symbols for the sync
|
||||
return(n_pre + n_pay + 4.25f);
|
||||
}
|
||||
|
||||
uint32_t SX127x::getTimeOnAir(size_t len) {
|
||||
// check active modem
|
||||
uint8_t modem = getActiveModem();
|
||||
if (modem == RADIOLIB_SX127X_LORA) {
|
||||
// Get symbol length in us
|
||||
// get symbol length in us
|
||||
float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
|
||||
// Get Low Data Rate optimization flag
|
||||
float de = 0;
|
||||
if (symbolLength >= 16.0) {
|
||||
de = 1;
|
||||
}
|
||||
// Get explicit/implicit header enabled flag
|
||||
float ih = (float) this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0);
|
||||
// Get CRC enabled flag
|
||||
float crc = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2);
|
||||
// Get number of bits preamble
|
||||
float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB));
|
||||
// Get number of bits payload
|
||||
float n_pay = 8.0 + RADIOLIB_MAX(ceil((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0);
|
||||
|
||||
// get number of symbols
|
||||
float n_sym = getNumSymbols(len);
|
||||
|
||||
// Get time-on-air in us
|
||||
return ceil(symbolLength * (n_pre + n_pay + 4.25)) * 1000;
|
||||
return ceil((double)symbolLength * (double)n_sym) * 1000;
|
||||
|
||||
} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
|
||||
// Get number of bits preamble
|
||||
float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8;
|
||||
|
@ -1267,6 +1294,28 @@ uint32_t SX127x::getTimeOnAir(size_t len) {
|
|||
|
||||
}
|
||||
|
||||
uint32_t SX127x::calculateRxTimeout(uint32_t timeoutUs) {
|
||||
// the timeout is given as the number of symbols
|
||||
// the calling function should provide some extra width, as this number of symbols is truncated to integer
|
||||
// the order of operators is swapped here to decrease the effects of this truncation error
|
||||
float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
|
||||
uint32_t numSymbols = (timeoutUs / symbolLength) / 1000;
|
||||
return(numSymbols);
|
||||
}
|
||||
|
||||
int16_t SX127x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) {
|
||||
// IRQ flags/masks are inverted to what seems logical for SX127x (0 being activated, 1 being deactivated)
|
||||
irqFlags = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT;
|
||||
irqMask = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE & RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT;
|
||||
return(RADIOLIB_ERR_NONE);
|
||||
}
|
||||
|
||||
bool SX127x::isRxTimeout() {
|
||||
uint16_t irq = getIRQFlags();
|
||||
bool rxTimedOut = irq & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT;
|
||||
return(rxTimedOut);
|
||||
}
|
||||
|
||||
int16_t SX127x::setCrcFiltering(bool enable) {
|
||||
this->crcOn = enable;
|
||||
|
||||
|
|
|
@ -160,6 +160,7 @@
|
|||
#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete
|
||||
#define RADIOLIB_SX127X_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel
|
||||
#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation
|
||||
#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT 0b00011111 // 7 0 default for Rx (RX_TIMEOUT, RX_DONE, CRC_ERR)
|
||||
|
||||
// RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR
|
||||
#define RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only
|
||||
|
@ -824,13 +825,16 @@ class SX127x: public PhysicalLayer {
|
|||
|
||||
/*!
|
||||
\brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer.
|
||||
\param mode Receive mode to be used.
|
||||
\param timeout Receive mode type and/or raw timeout value in symbols.
|
||||
When set to 0, the timeout will be infinite and the device will remain
|
||||
in Rx mode until explicitly commanded to stop (Rx continuous mode).
|
||||
When non-zero (maximum 1023), the device will be set to Rx single mode and timeout will be set.
|
||||
\param irqFlags Ignored.
|
||||
\param irqMask Ignored.
|
||||
\param len Expected length of packet to be received. Required for LoRa spreading factor 6.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, size_t len);
|
||||
int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len);
|
||||
|
||||
/*!
|
||||
\brief Reads data that was received after calling startReceive method. When the packet length is not known in advance,
|
||||
|
@ -1041,6 +1045,13 @@ class SX127x: public PhysicalLayer {
|
|||
*/
|
||||
int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK);
|
||||
|
||||
/*!
|
||||
\brief Convert from bytes to LoRa symbols.
|
||||
\param len Payload length in bytes.
|
||||
\returns The total number of LoRa symbols, including preamble, sync and possible header.
|
||||
*/
|
||||
float getNumSymbols(size_t len);
|
||||
|
||||
/*!
|
||||
\brief Get expected time-on-air for a given size of payload.
|
||||
\param len Payload length in bytes.
|
||||
|
@ -1048,6 +1059,27 @@ class SX127x: public PhysicalLayer {
|
|||
*/
|
||||
uint32_t getTimeOnAir(size_t len) override;
|
||||
|
||||
/*!
|
||||
\brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
|
||||
\param timeoutUs Timeout in microseconds to listen for
|
||||
\returns Timeout value in a unit that is specific for the used module
|
||||
*/
|
||||
uint32_t calculateRxTimeout(uint32_t timeoutUs);
|
||||
|
||||
/*!
|
||||
\brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks
|
||||
\param irqFlags The flags for which IRQs must be triggered
|
||||
\param irqMask Mask indicating which IRQ triggers a DIO
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask);
|
||||
|
||||
/*!
|
||||
\brief Check whether the IRQ bit for RxTimeout is set
|
||||
\returns \ref RxTimeout IRQ is set
|
||||
*/
|
||||
bool isRxTimeout();
|
||||
|
||||
/*!
|
||||
\brief Enable CRC filtering and generation.
|
||||
\param enable Set or unset CRC filtering and generation.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,7 @@
|
|||
#include "../../utils/Cryptography.h"
|
||||
|
||||
// version of NVM table layout (NOT the LoRaWAN version)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION (0x01)
|
||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION (0x01)
|
||||
|
||||
// preamble format
|
||||
#define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34)
|
||||
|
@ -69,9 +69,10 @@
|
|||
#define RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK (0x01 << 0)
|
||||
#define RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH (0x02 << 0)
|
||||
#define RADIOLIB_LORAWAN_CHANNEL_DIR_NONE (0x03 << 0)
|
||||
#define RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES (0)
|
||||
#define RADIOLIB_LORAWAN_CFLIST_TYPE_MASK (1)
|
||||
#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (16)
|
||||
#define RADIOLIB_LORAWAN_BAND_DYNAMIC (0)
|
||||
#define RADIOLIB_LORAWAN_BAND_FIXED (1)
|
||||
#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15)
|
||||
#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF >> 1) // reserve first bit for enable-flag
|
||||
|
||||
// recommended default settings
|
||||
#define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000)
|
||||
|
@ -81,8 +82,8 @@
|
|||
#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000)
|
||||
#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000)
|
||||
#define RADIOLIB_LORAWAN_MAX_FCNT_GAP (16384)
|
||||
#define RADIOLIB_LORAWAN_ADR_ACK_LIMIT (64)
|
||||
#define RADIOLIB_LORAWAN_ADR_ACK_DELAY (32)
|
||||
#define RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP (0x06)
|
||||
#define RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP (0x05)
|
||||
#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000)
|
||||
#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS (3000)
|
||||
#define RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM (-2)
|
||||
|
@ -134,6 +135,7 @@
|
|||
|
||||
// payload encryption/MIC blocks common layout
|
||||
#define RADIOLIB_LORAWAN_BLOCK_MAGIC_POS (0)
|
||||
#define RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS (1)
|
||||
#define RADIOLIB_LORAWAN_BLOCK_DIR_POS (5)
|
||||
#define RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS (6)
|
||||
#define RADIOLIB_LORAWAN_BLOCK_FCNT_POS (10)
|
||||
|
@ -150,7 +152,7 @@
|
|||
#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4)
|
||||
|
||||
// magic word saved in persistent memory upon activation
|
||||
#define RADIOLIB_LORAWAN_MAGIC (0x12AD101B)
|
||||
#define RADIOLIB_LORAWAN_MAGIC (0x39EA)
|
||||
|
||||
// MAC commands
|
||||
#define RADIOLIB_LORAWAN_MAC_CMD_RESET (0x01)
|
||||
|
@ -170,11 +172,39 @@
|
|||
#define RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP (0x0F)
|
||||
#define RADIOLIB_LORAWAN_MAC_CMD_PROPRIETARY (0x80)
|
||||
|
||||
// unused frame counter value
|
||||
#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF)
|
||||
|
||||
// the length of internal MAC command queue - hopefully this is enough for most use cases
|
||||
#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (8)
|
||||
|
||||
// the maximum number of simultaneously available channels
|
||||
#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (8)
|
||||
#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16)
|
||||
|
||||
/*!
|
||||
\struct LoRaWANChannelSpan_t
|
||||
\brief Structure to save information about LoRaWAN channels.
|
||||
To save space, adjacent channels are saved in "spans".
|
||||
*/
|
||||
struct LoRaWANChannel_t {
|
||||
/*! \brief Whether this channel is enabled (can be used) or is disabled */
|
||||
bool enabled;
|
||||
|
||||
/*! \brief The channel number, as specified by defaults or the network */
|
||||
uint8_t idx;
|
||||
|
||||
/*! \brief The channel frequency */
|
||||
float freq;
|
||||
|
||||
/*! \brief Minimum allowed datarate for this channel */
|
||||
uint8_t drMin;
|
||||
|
||||
/*! \brief Maximum allowed datarate for this channel (inclusive) */
|
||||
uint8_t drMax;
|
||||
};
|
||||
|
||||
// alias for unused channel
|
||||
#define RADIOLIB_LORAWAN_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE, .freq = 0, .drMin = 0, .drMax = 0 }
|
||||
|
||||
/*!
|
||||
\struct LoRaWANChannelSpan_t
|
||||
|
@ -182,12 +212,6 @@
|
|||
To save space, adjacent channels are saved in "spans".
|
||||
*/
|
||||
struct LoRaWANChannelSpan_t {
|
||||
/*! \brief Whether this channel span is for uplink, downlink, or both directions*/
|
||||
uint8_t direction;
|
||||
|
||||
/*! \brief Allowed data rates for a join request message */
|
||||
uint8_t joinRequestDataRate;
|
||||
|
||||
/*! \brief Total number of channels in the span */
|
||||
uint8_t numChannels;
|
||||
|
||||
|
@ -197,23 +221,26 @@ struct LoRaWANChannelSpan_t {
|
|||
/*! \brief Frequency step between adjacent channels */
|
||||
float freqStep;
|
||||
|
||||
/*! \brief Array of datarates supported by all channels in the span */
|
||||
uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES];
|
||||
/*! \brief Minimum allowed datarate for all channels in this span */
|
||||
uint8_t drMin;
|
||||
|
||||
/*! \brief Maximum allowed datarate for all channels in this span (inclusive) */
|
||||
uint8_t drMax;
|
||||
|
||||
/*! \brief Allowed data rates for a join request message */
|
||||
uint8_t joinRequestDataRate;
|
||||
};
|
||||
|
||||
// alias for unused channel span
|
||||
#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_NONE, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, .numChannels = 0, .freqStart = 0, .freqStep = 0, .dataRates = { 0 } }
|
||||
#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED }
|
||||
|
||||
/*!
|
||||
\struct LoRaWANBand_t
|
||||
\brief Structure to save information about LoRaWAN band
|
||||
*/
|
||||
struct LoRaWANBand_t {
|
||||
/*! \brief The base downlink data rate. Used to calculate data rate changes for adaptive data rate */
|
||||
uint8_t downlinkDataRateBase;
|
||||
|
||||
/*! \brief The minimum allowed downlink data rate. Used to calculate data rate changes for adaptive data rate */
|
||||
uint8_t downlinkDataRateMin;
|
||||
/*! \brief Whether the channels are fixed per specification, or dynamically allocated through the network (plus defaults) */
|
||||
uint8_t bandType;
|
||||
|
||||
/*! \brief Array of allowed maximum payload lengths for each data rate */
|
||||
uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES];
|
||||
|
@ -224,20 +251,29 @@ struct LoRaWANBand_t {
|
|||
/*! \brief Number of power steps in this band */
|
||||
int8_t powerNumSteps;
|
||||
|
||||
/*! \brief Whether the optional channels are defined as list of frequencies or bit mask */
|
||||
uint8_t cfListType;
|
||||
/*! \brief A set of default uplink (TX) channels for frequency-type bands */
|
||||
LoRaWANChannel_t txFreqs[3];
|
||||
|
||||
/*! \brief FSK channel frequency */
|
||||
float fskFreq;
|
||||
/*! \brief A set of possible extra channels for the Join-Request message for frequency-type bands */
|
||||
LoRaWANChannel_t txJoinReq[3];
|
||||
|
||||
/*! \brief Number of channel spans in the band */
|
||||
uint8_t numChannelSpans;
|
||||
/*! \brief The number of TX channel spans for mask-type bands */
|
||||
uint8_t numTxSpans;
|
||||
|
||||
/*! \brief Default uplink (TX/RX1) channels defined by LoRaWAN Regional Parameters */
|
||||
LoRaWANChannelSpan_t defaultChannels[3];
|
||||
/*! \brief Default uplink (TX) channel spans for mask-type bands, including Join-Request parameters */
|
||||
LoRaWANChannelSpan_t txSpans[2];
|
||||
|
||||
/*! \brief Default downlink (RX1) channel span for mask-type bands */
|
||||
LoRaWANChannelSpan_t rx1Span;
|
||||
|
||||
/*! \brief The base downlink data rate. Used to calculate data rate changes for adaptive data rate */
|
||||
uint8_t rx1DataRateBase;
|
||||
|
||||
/*! \brief Backup channel for downlink (RX2) window */
|
||||
LoRaWANChannel_t rx2;
|
||||
|
||||
/*! \brief Backup downlink (RX2) channel - just a single channel, but using the same structure for convenience */
|
||||
LoRaWANChannelSpan_t backupChannel;
|
||||
/*! \brief The corresponding datarates, bandwidths and coding rates for DR index */
|
||||
uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES];
|
||||
};
|
||||
|
||||
// supported bands
|
||||
|
@ -259,20 +295,20 @@ struct LoRaWANMacCommand_t {
|
|||
/*! \brief The command ID */
|
||||
uint8_t cid;
|
||||
|
||||
/*! \brief Length of the payload */
|
||||
uint8_t len;
|
||||
|
||||
/*! \brief Payload buffer (5 bytes is the longest possible) */
|
||||
uint8_t payload[5];
|
||||
|
||||
/*! \brief Length of the payload */
|
||||
uint8_t len;
|
||||
|
||||
/*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */
|
||||
uint8_t repeat;
|
||||
};
|
||||
|
||||
struct LoRaWANMacCommandQueue_t {
|
||||
uint8_t numCommands;
|
||||
uint8_t len;
|
||||
LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE];
|
||||
size_t numCommands;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -281,31 +317,12 @@ struct LoRaWANMacCommandQueue_t {
|
|||
*/
|
||||
class LoRaWANNode {
|
||||
public:
|
||||
/*! \brief Set to true to force the node to only use FSK channels. Set to false by default. */
|
||||
bool FSK;
|
||||
|
||||
/*! \brief Starting channel offset.
|
||||
Some band plans only support a subset of available channels.
|
||||
Set to a positive value to set the first channel that will be used (e.g. 8 for US915 FSB2 used by TTN).
|
||||
By default -1 (no channel offset). */
|
||||
int8_t startChannel;
|
||||
// Offset between TX and RX1 (such that RX1 has equal or lower DR)
|
||||
uint8_t rx1DrOffset;
|
||||
|
||||
/*! \brief Number of supported channels.
|
||||
Some band plans only support a subset of available channels.
|
||||
Set to a positive value to set the number of channels that will be used
|
||||
(e.g. 8 for US915 FSB2 used by TTN). By default -1 (no channel offset). */
|
||||
int8_t numChannels;
|
||||
|
||||
/*! \brief Num of Back Off(BO) slots to be decremented after DIFS phase. 0 to disable BO.
|
||||
A random BO avoids collisions in the case where two or more nodes start the CSMA
|
||||
process at the same time. */
|
||||
uint8_t backoffMax;
|
||||
|
||||
/*! \brief Num of CADs to estimate a clear CH. */
|
||||
uint8_t difsSlots;
|
||||
|
||||
/*! \brief enable/disable CSMA for LoRaWAN. */
|
||||
bool enableCSMA;
|
||||
// RX2 channel properties - may be changed by MAC command
|
||||
LoRaWANChannel_t rx2;
|
||||
|
||||
/*!
|
||||
\brief Default constructor.
|
||||
|
@ -314,6 +331,7 @@ class LoRaWANNode {
|
|||
*/
|
||||
LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band);
|
||||
|
||||
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
|
||||
/*!
|
||||
\brief Wipe internal persistent parameters.
|
||||
This will reset all counters and saved variables, so the device will have to rejoin the network.
|
||||
|
@ -321,18 +339,11 @@ class LoRaWANNode {
|
|||
void wipe();
|
||||
|
||||
/*!
|
||||
\brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance.
|
||||
\param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO.
|
||||
\param difsSlots Num of CADs to estimate a clear CH.
|
||||
\param enableCSMA enable/disable CSMA for LoRaWAN.
|
||||
*/
|
||||
void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false);
|
||||
|
||||
/*!
|
||||
\brief Restore OTAA session by loading information from persistent storage.
|
||||
\brief Restore session by loading information from persistent storage.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t restoreOTAA();
|
||||
int16_t restore();
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\brief Join network by performing over-the-air activation. By this procedure,
|
||||
|
@ -341,10 +352,12 @@ class LoRaWANNode {
|
|||
\param devEUI 8-byte device identifier.
|
||||
\param nwkKey Pointer to the network AES-128 key.
|
||||
\param appKey Pointer to the application AES-128 key.
|
||||
\param joinDr (OTAA:) The datarate at which to send the join-request; (ABP:) ignored
|
||||
\param force Set to true to force joining even if previously joined.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false);
|
||||
int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, bool force = false);
|
||||
|
||||
/*!
|
||||
\brief Join network by performing activation by personalization.
|
||||
|
@ -354,36 +367,50 @@ class LoRaWANNode {
|
|||
\param appSKey Pointer to the application session AES-128 key.
|
||||
\param fNwkSIntKey Pointer to the network session F key (LoRaWAN 1.1), unused for LoRaWAN 1.0.
|
||||
\param sNwkSIntKey Pointer to the network session S key (LoRaWAN 1.1), unused for LoRaWAN 1.0.
|
||||
\param force Set to true to force a new session, even if one exists.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL);
|
||||
int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL, bool force = false);
|
||||
|
||||
/*! \brief Whether there is an ongoing session active */
|
||||
bool isJoined();
|
||||
|
||||
/*!
|
||||
\brief Save the current state of the session.
|
||||
All variables are compared to what is saved and only the differences are rewritten.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t saveSession();
|
||||
|
||||
#if defined(RADIOLIB_BUILD_ARDUINO)
|
||||
/*!
|
||||
\brief Send a message to the server.
|
||||
\param str Address of Arduino String that will be transmitted.
|
||||
\param port Port number to send the message to.
|
||||
\param isConfirmed Whether to send a confirmed uplink or not.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t uplink(String& str, uint8_t port);
|
||||
int16_t uplink(String& str, uint8_t port, bool isConfirmed = false);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\brief Send a message to the server.
|
||||
\param str C-string that will be transmitted.
|
||||
\param port Port number to send the message to.
|
||||
\param isConfirmed Whether to send a confirmed uplink or not.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t uplink(const char* str, uint8_t port);
|
||||
int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false);
|
||||
|
||||
/*!
|
||||
\brief Send a message to the server.
|
||||
\param data Data to send.
|
||||
\param len Length of the data.
|
||||
\param port Port number to send the message to.
|
||||
\param isConfirmed Whether to send a confirmed uplink or not.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t uplink(uint8_t* data, size_t len, uint8_t port);
|
||||
int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false);
|
||||
|
||||
#if defined(RADIOLIB_BUILD_ARDUINO)
|
||||
/*!
|
||||
|
@ -402,6 +429,41 @@ class LoRaWANNode {
|
|||
*/
|
||||
int16_t downlink(uint8_t* data, size_t* len);
|
||||
|
||||
#if defined(RADIOLIB_BUILD_ARDUINO)
|
||||
/*!
|
||||
\brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window.
|
||||
\param strUp Address of Arduino String that will be transmitted.
|
||||
\param port Port number to send the message to.
|
||||
\param strDown Address of Arduino String to save the received data.
|
||||
\param isConfirmed Whether to send a confirmed uplink or not.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed = false);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window.
|
||||
\param strUp C-string that will be transmitted.
|
||||
\param port Port number to send the message to.
|
||||
\param dataDown Buffer to save received data into.
|
||||
\param lenDown Pointer to variable that will be used to save the number of received bytes.
|
||||
\param isConfirmed Whether to send a confirmed uplink or not.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false);
|
||||
|
||||
/*!
|
||||
\brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window.
|
||||
\param dataUp Data to send.
|
||||
\param lenUp Length of the data.
|
||||
\param port Port number to send the message to.
|
||||
\param dataDown Buffer to save received data into.
|
||||
\param lenDown Pointer to variable that will be used to save the number of received bytes.
|
||||
\param isConfirmed Whether to send a confirmed uplink or not.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false);
|
||||
|
||||
/*!
|
||||
\brief Set device status.
|
||||
\param battLevel Battery level to set. 0 for external power source, 1 for lowest battery,
|
||||
|
@ -409,6 +471,47 @@ class LoRaWANNode {
|
|||
*/
|
||||
void setDeviceStatus(uint8_t battLevel);
|
||||
|
||||
/*! \brief Returns the last uplink's frame counter */
|
||||
uint32_t getFcntUp();
|
||||
|
||||
/*!
|
||||
\brief Set uplink datarate. This should not be used when ADR is enabled.
|
||||
\param dr Datarate to use for uplinks.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setDatarate(uint8_t drUp);
|
||||
|
||||
/*!
|
||||
\brief Toggle ADR to on or off
|
||||
\param enable Whether to disable ADR or not
|
||||
*/
|
||||
void setADR(bool enable = true);
|
||||
|
||||
/*!
|
||||
\brief Select a single subband (8 channels) for fixed bands such as US915.
|
||||
Only available before joining a network.
|
||||
\param idx The subband to be used (starting from 1!)
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t selectSubband(uint8_t idx);
|
||||
|
||||
/*!
|
||||
\brief Select a set of channels for fixed bands such as US915.
|
||||
Only available before joining a network.
|
||||
\param startChannel The first channel of the band to be used (inclusive)
|
||||
\param endChannel The last channel of the band to be used (inclusive)
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t selectSubband(uint8_t startChannel, uint8_t endChannel);
|
||||
|
||||
/*!
|
||||
\brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance.
|
||||
\param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO.
|
||||
\param difsSlots Num of CADs to estimate a clear CH.
|
||||
\param enableCSMA enable/disable CSMA for LoRaWAN.
|
||||
*/
|
||||
void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false);
|
||||
|
||||
#if !defined(RADIOLIB_GODMODE)
|
||||
private:
|
||||
#endif
|
||||
|
@ -416,14 +519,14 @@ class LoRaWANNode {
|
|||
const LoRaWANBand_t* band = NULL;
|
||||
|
||||
LoRaWANMacCommandQueue_t commandsUp = {
|
||||
.commands = { { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, } },
|
||||
.numCommands = 0,
|
||||
.len = 0,
|
||||
.commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } },
|
||||
};
|
||||
LoRaWANMacCommandQueue_t commandsDown = {
|
||||
.commands = { { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, } },
|
||||
.numCommands = 0,
|
||||
.len = 0,
|
||||
.commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } },
|
||||
};
|
||||
|
||||
// the following is either provided by the network server (OTAA)
|
||||
|
@ -434,29 +537,62 @@ class LoRaWANNode {
|
|||
uint8_t sNwkSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 };
|
||||
uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE] = { 0 };
|
||||
uint8_t jSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 };
|
||||
|
||||
// device-specific parameters, persistent through sessions
|
||||
uint16_t devNonce = 0;
|
||||
uint32_t joinNonce = 0;
|
||||
|
||||
// session-specific parameters
|
||||
uint32_t homeNetId = 0;
|
||||
uint8_t adrLimitExp = RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP;
|
||||
uint8_t adrDelayExp = RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP;
|
||||
uint8_t nbTrans = 1; // Number of allowed frame retransmissions
|
||||
uint8_t txPwrCur = 0;
|
||||
uint32_t fcntUp = 0;
|
||||
uint32_t aFcntDown = 0;
|
||||
uint32_t nFcntDown = 0;
|
||||
uint32_t confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE;
|
||||
uint32_t confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE;
|
||||
uint32_t adrFcnt = 0;
|
||||
|
||||
// whether the current configured channel is in FSK mode
|
||||
bool FSK;
|
||||
|
||||
// flag that shows whether the device is joined and there is an ongoing session
|
||||
bool isJoinedFlag = false;
|
||||
|
||||
// ADR is enabled by default
|
||||
bool adrEnabled = true;
|
||||
|
||||
// enable/disable CSMA for LoRaWAN
|
||||
bool enableCSMA;
|
||||
|
||||
// number of backoff slots to be decremented after DIFS phase. 0 to disable BO.
|
||||
// A random BO avoids collisions in the case where two or more nodes start the CSMA
|
||||
// process at the same time.
|
||||
uint8_t backoffMax;
|
||||
|
||||
// number of CADs to estimate a clear CH
|
||||
uint8_t difsSlots;
|
||||
|
||||
// available channel frequencies from list passed during OTA activation
|
||||
float availableChannelsFreq[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } };
|
||||
LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } };
|
||||
|
||||
// currently configured channel frequency
|
||||
float channelFreq[2] = { 0 };
|
||||
// currently configured channels for TX and RX1
|
||||
LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE };
|
||||
|
||||
// currently configured datarates for TX and RX1
|
||||
uint8_t dataRates[2] = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED };
|
||||
|
||||
// LoRaWAN revision (1.0 vs 1.1)
|
||||
uint8_t rev = 0;
|
||||
|
||||
// currently configured data rate for uplink and downlink: DR0 - DR15 (band-dependent!)
|
||||
uint8_t dataRate[2] = { 0 };
|
||||
|
||||
// currently configured channel for uplink and downlink (band-dependent!)
|
||||
uint8_t chIndex[2] = { 0 };
|
||||
|
||||
// backup channel properties - may be changed by MAC command
|
||||
float backupFreq = 0;
|
||||
uint8_t backupDataRate = 0;
|
||||
|
||||
// timestamp to measure the RX1/2 delay (from uplink end)
|
||||
uint32_t rxDelayStart = 0;
|
||||
|
||||
// timestamp when the Rx1/2 windows were closed (timeout or uplink received)
|
||||
uint32_t rxDelayEnd = 0;
|
||||
|
||||
// delays between the uplink and RX1/2 windows
|
||||
uint32_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS };
|
||||
|
||||
|
@ -466,6 +602,25 @@ class LoRaWANNode {
|
|||
// indicates whether an uplink has MAC commands as payload
|
||||
bool isMACPayload = false;
|
||||
|
||||
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
|
||||
/*!
|
||||
\brief Save the current uplink frame counter.
|
||||
Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t saveFcntUp();
|
||||
|
||||
/*!
|
||||
\brief Restore frame counter for uplinks from persistent storage.
|
||||
Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t restoreFcntUp();
|
||||
#endif
|
||||
|
||||
// wait for, open and listen during Rx1 and Rx2 windows; only performs listening
|
||||
int16_t downlinkCommon();
|
||||
|
||||
// method to generate message integrity code
|
||||
uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key);
|
||||
|
||||
|
@ -479,37 +634,40 @@ class LoRaWANNode {
|
|||
|
||||
// setup uplink/downlink channel data rates and frequencies
|
||||
// will attempt to randomly select based on currently used band plan
|
||||
int16_t setupChannels();
|
||||
int16_t setupChannels(uint8_t* cfList);
|
||||
|
||||
// find the first usable data rate in a given channel span
|
||||
uint8_t findDataRate(uint8_t dr, DataRate_t* dataRate, const LoRaWANChannelSpan_t* span);
|
||||
// select a set of semi-random TX/RX channels for the join-request and -accept message
|
||||
int16_t selectChannelsJR(uint16_t devNonce, uint8_t drJoinSubband);
|
||||
|
||||
// find a channel ID that conforms to the requested direction and ID range
|
||||
int16_t findChannelId(uint8_t dir, uint8_t* ch, uint8_t* dr, int8_t min, int8_t max);
|
||||
// select a set of random TX/RX channels for up- and downlink
|
||||
int16_t selectChannels();
|
||||
|
||||
// find a channel span that any given channel id belongs to
|
||||
LoRaWANChannelSpan_t* findChannelSpan(uint8_t dir, uint8_t ch, uint8_t* spanChannelId);
|
||||
|
||||
// calculate channel frequency in MHz based on channel ID and direction
|
||||
int16_t findChannelFreq(uint8_t dir, uint8_t ch, float* freq);
|
||||
// find the first usable data rate for the given band
|
||||
int16_t findDataRate(uint8_t dr, DataRate_t* dataRate);
|
||||
|
||||
// configure channel based on cached data rate ID and frequency
|
||||
int16_t configureChannel(uint8_t dir);
|
||||
|
||||
// send a MAC command to the network server
|
||||
int16_t sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloadLen, uint8_t* reply, size_t replyLen);
|
||||
// save all available channels to persistent storage
|
||||
int16_t saveChannels();
|
||||
|
||||
// restore all available channels from persistent storage
|
||||
int16_t restoreChannels();
|
||||
|
||||
// push MAC command to queue, done by copy
|
||||
int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue);
|
||||
|
||||
// pop MAC command from queue, done by copy unless CMD is NULL
|
||||
int16_t popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue, size_t index);
|
||||
|
||||
// delete a specific MAC command from queue, indicated by the command ID
|
||||
int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue);
|
||||
|
||||
// execute mac command, return the number of processed bytes for sequential processing
|
||||
size_t execMacCommand(LoRaWANMacCommand_t* cmd);
|
||||
|
||||
// Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013).
|
||||
void performCSMA();
|
||||
|
||||
// perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise.
|
||||
bool performCAD();
|
||||
|
||||
// function to encrypt and decrypt payloads
|
||||
void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter);
|
||||
|
@ -521,12 +679,6 @@ class LoRaWANNode {
|
|||
// host-to-network conversion method - takes data from host variable and and converts it to network packet endians
|
||||
template<typename T>
|
||||
static void hton(uint8_t* buff, T val, size_t size = 0);
|
||||
|
||||
// perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise.
|
||||
bool performCAD();
|
||||
|
||||
// Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013).
|
||||
void performCSMA();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -293,7 +293,22 @@ uint32_t PhysicalLayer::getTimeOnAir(size_t len) {
|
|||
(void)len;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
uint32_t PhysicalLayer::calculateRxTimeout(uint32_t timeoutUs) {
|
||||
(void)timeoutUs;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int16_t PhysicalLayer::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) {
|
||||
(void)irqFlags;
|
||||
(void)irqMask;
|
||||
return(RADIOLIB_ERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
bool PhysicalLayer::isRxTimeout() {
|
||||
return(false);
|
||||
}
|
||||
|
||||
int16_t PhysicalLayer::startChannelScan() {
|
||||
return(RADIOLIB_ERR_UNSUPPORTED);
|
||||
}
|
||||
|
|
|
@ -309,7 +309,28 @@ class PhysicalLayer {
|
|||
\returns Expected time-on-air in microseconds.
|
||||
*/
|
||||
virtual uint32_t getTimeOnAir(size_t len);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
|
||||
\param timeoutUs Timeout in microseconds to listen for
|
||||
\returns Timeout value in a unit that is specific for the used module
|
||||
*/
|
||||
virtual uint32_t calculateRxTimeout(uint32_t timeoutUs);
|
||||
|
||||
/*!
|
||||
\brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks
|
||||
\param irqFlags The flags for which IRQs must be triggered
|
||||
\param irqMask Mask indicating which IRQ triggers a DIO
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
virtual int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask);
|
||||
|
||||
/*!
|
||||
\brief Check whether the IRQ bit for RxTimeout is set
|
||||
\returns \ref RxTimeout IRQ is set
|
||||
*/
|
||||
virtual bool isRxTimeout();
|
||||
|
||||
/*!
|
||||
\brief Interrupt-driven channel activity detection method. interrupt will be activated
|
||||
when packet is detected. Must be implemented in module class.
|
||||
|
|
Loading…
Add table
Reference in a new issue