[LoRaWAN] Revamp internal processing, key checking, new MAC commands, implement DutyCycle & DwellTime
This commit is contained in:
parent
797b7a4323
commit
574555ca09
11 changed files with 1258 additions and 554 deletions
|
@ -24,11 +24,12 @@
|
||||||
// include the library
|
// include the library
|
||||||
#include <RadioLib.h>
|
#include <RadioLib.h>
|
||||||
|
|
||||||
// SX1278 has the following connections:
|
// SX1262 has the following pin order:
|
||||||
// NSS pin: 10
|
// Module(NSS/CS, DIO1, RESET, BUSY)
|
||||||
// DIO0 pin: 2
|
// SX1262 radio = new Module(8, 14, 12, 13);
|
||||||
// RESET pin: 9
|
|
||||||
// DIO1 pin: 3
|
// SX1278 has the following pin order:
|
||||||
|
// Module(NSS/CS, DIO0, RESET, DIO1)
|
||||||
SX1278 radio = new Module(10, 2, 9, 3);
|
SX1278 radio = new Module(10, 2, 9, 3);
|
||||||
|
|
||||||
// create the node instance on the EU-868 band
|
// create the node instance on the EU-868 band
|
||||||
|
@ -85,6 +86,11 @@ void setup() {
|
||||||
node.selectSubband(8, 15);
|
node.selectSubband(8, 15);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// on EEPROM-enabled boards, after the device has been activated,
|
||||||
|
// the session can be restored without rejoining after device power cycle
|
||||||
|
// this is intrinsically done when calling `beginOTAA()` with the same keys
|
||||||
|
// in that case, the function will not need to transmit a JoinRequest
|
||||||
|
|
||||||
// now we can start the activation
|
// now we can start the activation
|
||||||
// this can take up to 10 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):
|
// a specific starting-datarate can be selected in dynamic bands (e.g. EU868):
|
||||||
|
@ -149,5 +155,9 @@ void loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait before sending another packet
|
// wait before sending another packet
|
||||||
delay(30000);
|
uint32_t minimumDelay = 60000; // try to send once every minute
|
||||||
|
uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!)
|
||||||
|
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
|
||||||
|
|
||||||
|
delay(delayMs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,12 @@
|
||||||
// include the library
|
// include the library
|
||||||
#include <RadioLib.h>
|
#include <RadioLib.h>
|
||||||
|
|
||||||
// SX1278 has the following connections:
|
// SX1262 has the following pin order:
|
||||||
// NSS pin: 10
|
// Module(NSS/CS, DIO1, RESET, BUSY)
|
||||||
// DIO0 pin: 2
|
// SX1262 radio = new Module(8, 14, 12, 13);
|
||||||
// RESET pin: 9
|
|
||||||
// DIO1 pin: 3
|
// SX1278 has the following pin order:
|
||||||
|
// Module(NSS/CS, DIO0, RESET, DIO1)
|
||||||
SX1278 radio = new Module(10, 2, 9, 3);
|
SX1278 radio = new Module(10, 2, 9, 3);
|
||||||
|
|
||||||
// create the node instance on the EU-868 band
|
// create the node instance on the EU-868 band
|
||||||
|
@ -69,6 +70,14 @@ void setup() {
|
||||||
uint8_t appSKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65,
|
uint8_t appSKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65,
|
||||||
0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 };
|
0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 };
|
||||||
|
|
||||||
|
// network key 2 is the ASCII string "topSecretKey5678"
|
||||||
|
uint8_t fNwkSIntKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65,
|
||||||
|
0x6E, 0x74, 0x4B, 0x65, 0x35, 0x36, 0x37, 0x38 };
|
||||||
|
|
||||||
|
// network key 3 is the ASCII string "aDifferentKeyDEF"
|
||||||
|
uint8_t sNwkSIntKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65,
|
||||||
|
0x6E, 0x74, 0x4B, 0x65, 0x79, 0x44, 0x45, 0x46 };
|
||||||
|
|
||||||
// prior to LoRaWAN 1.1.0, only a single "nwkKey" is used
|
// prior to LoRaWAN 1.1.0, only a single "nwkKey" is used
|
||||||
// when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded
|
// when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded
|
||||||
// and can be set to NULL
|
// and can be set to NULL
|
||||||
|
@ -86,15 +95,20 @@ void setup() {
|
||||||
node.rx2.drMax = 3;
|
node.rx2.drMax = 3;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// to start a LoRaWAN v1.1 session, the user should also provide
|
// on EEPROM-enabled boards, after the device has been activated,
|
||||||
// fNwkSIntKey and sNwkSIntKey similar to nwkSKey and appSKey
|
// the session can be restored without rejoining after device power cycle
|
||||||
|
// this is intrinsically done when calling `beginABP()` with the same keys
|
||||||
|
// in that case, the function will not need to transmit a JoinRequest
|
||||||
|
|
||||||
|
// to start a LoRaWAN v1.0 session,
|
||||||
|
// the user can remove the fNwkSIntKey and sNwkSIntKey
|
||||||
/*
|
/*
|
||||||
state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey);
|
state = node.beginABP(devAddr, nwkSKey, appSKey);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// start the device by directly providing the encryption keys and device address
|
// start the device by directly providing the encryption keys and device address
|
||||||
Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
||||||
state = node.beginABP(devAddr, nwkSKey, appSKey);
|
state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey);
|
||||||
if(state == RADIOLIB_ERR_NONE) {
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
Serial.println(F("success!"));
|
Serial.println(F("success!"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -149,5 +163,9 @@ void loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait before sending another packet
|
// wait before sending another packet
|
||||||
delay(30000);
|
uint32_t minimumDelay = 60000; // try to send once every minute
|
||||||
|
uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!)
|
||||||
|
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
|
||||||
|
|
||||||
|
delay(delayMs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
NOTE: LoRaWAN requires storing some parameters persistently!
|
NOTE: LoRaWAN requires storing some parameters persistently!
|
||||||
RadioLib does this by using EEPROM, by default
|
RadioLib does this by using EEPROM, by default
|
||||||
starting at address 0 and using 384 bytes.
|
starting at address 0 and using 448 bytes.
|
||||||
If you already use EEPROM in your application,
|
If you already use EEPROM in your application,
|
||||||
you will have to either avoid this range, or change it
|
you will have to either avoid this range, or change it
|
||||||
by setting a different start address by changing the value of
|
by setting a different start address by changing the value of
|
||||||
|
@ -29,11 +29,12 @@
|
||||||
// include the library
|
// include the library
|
||||||
#include <RadioLib.h>
|
#include <RadioLib.h>
|
||||||
|
|
||||||
// SX1278 has the following connections:
|
// SX1262 has the following pin order:
|
||||||
// NSS pin: 10
|
// Module(NSS/CS, DIO1, RESET, BUSY)
|
||||||
// DIO0 pin: 2
|
// SX1262 radio = new Module(8, 14, 12, 13);
|
||||||
// RESET pin: 9
|
|
||||||
// DIO1 pin: 3
|
// SX1278 has the following pin order:
|
||||||
|
// Module(NSS/CS, DIO0, RESET, DIO1)
|
||||||
SX1278 radio = new Module(10, 2, 9, 3);
|
SX1278 radio = new Module(10, 2, 9, 3);
|
||||||
|
|
||||||
// create the node instance on the EU-868 band
|
// create the node instance on the EU-868 band
|
||||||
|
@ -56,17 +57,7 @@ void setup() {
|
||||||
while(true);
|
while(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// first we need to initialize the device storage
|
// start the activation
|
||||||
// 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 ... "));
|
// Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
|
||||||
// uint64_t joinEUI = 0x12AD1011B0C0FFEE;
|
// uint64_t joinEUI = 0x12AD1011B0C0FFEE;
|
||||||
// uint64_t devEUI = 0x70B3D57ED005E120;
|
// uint64_t devEUI = 0x70B3D57ED005E120;
|
||||||
|
@ -76,13 +67,21 @@ void setup() {
|
||||||
// 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 };
|
// 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 };
|
||||||
// state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
|
// state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
|
||||||
|
|
||||||
// after the device has been activated,
|
// on EEPROM-enabled boards, after the device has been activated,
|
||||||
// the session can be restored without rejoining after device power cycle
|
// the session can be restored without rejoining after device power cycle
|
||||||
// on EEPROM-enabled boards by calling "restore"
|
// by calling the same `beginOTAA()` or `beginABP()` function with the same keys
|
||||||
|
// or call `restore()` where it will restore any existing session
|
||||||
|
// `restore()` returns the active mode if it succeeded (OTAA or ABP)
|
||||||
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
||||||
state = node.restore();
|
state = node.restore();
|
||||||
if(state == RADIOLIB_ERR_NONE) {
|
if(state >= RADIOLIB_ERR_NONE) {
|
||||||
Serial.println(F("success!"));
|
Serial.println(F("success!"));
|
||||||
|
Serial.print(F("Restored an "));
|
||||||
|
if(state == RADIOLIB_LORAWAN_MODE_OTAA)
|
||||||
|
Serial.println(F("OTAA session."));
|
||||||
|
else {
|
||||||
|
Serial.println(F("ABP session."));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Serial.print(F("failed, code "));
|
Serial.print(F("failed, code "));
|
||||||
Serial.println(state);
|
Serial.println(state);
|
||||||
|
@ -141,5 +140,9 @@ void loop() {
|
||||||
// wait before sending another packet
|
// wait before sending another packet
|
||||||
// alternatively, call a deepsleep function here
|
// alternatively, call a deepsleep function here
|
||||||
// make sure to send the radio to sleep as well using radio.sleep()
|
// make sure to send the radio to sleep as well using radio.sleep()
|
||||||
delay(30000);
|
uint32_t minimumDelay = 60000; // try to send once every minute
|
||||||
|
uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!)
|
||||||
|
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
|
||||||
|
|
||||||
|
delay(delayMs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,12 @@
|
||||||
// include the library
|
// include the library
|
||||||
#include <RadioLib.h>
|
#include <RadioLib.h>
|
||||||
|
|
||||||
// SX1278 has the following connections:
|
// SX1262 has the following pin order:
|
||||||
// NSS pin: 10
|
// Module(NSS/CS, DIO1, RESET, BUSY)
|
||||||
// DIO0 pin: 2
|
// SX1262 radio = new Module(8, 14, 12, 13);
|
||||||
// RESET pin: 9
|
|
||||||
// DIO1 pin: 3
|
// SX1278 has the following pin order:
|
||||||
|
// Module(NSS/CS, DIO0, RESET, DIO1)
|
||||||
SX1278 radio = new Module(10, 2, 9, 3);
|
SX1278 radio = new Module(10, 2, 9, 3);
|
||||||
|
|
||||||
// create the node instance on the EU-868 band
|
// create the node instance on the EU-868 band
|
||||||
|
@ -106,9 +107,11 @@ void setup() {
|
||||||
while(true);
|
while(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// after the device has been activated,
|
// on EEPROM-enabled boards, after the device has been activated,
|
||||||
// the session can be restored without rejoining after device power cycle
|
// the session can be restored without rejoining after device power cycle
|
||||||
// on EEPROM-enabled boards by calling "restore"
|
// this is intrinsically done when calling `beginOTAA()` with the same keys
|
||||||
|
// or if you 'lost' the keys or don't want them included in your sketch
|
||||||
|
// you can call `restore()`
|
||||||
/*
|
/*
|
||||||
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
Serial.print(F("[LoRaWAN] Resuming previous session ... "));
|
||||||
state = node.restore();
|
state = node.restore();
|
||||||
|
@ -131,6 +134,19 @@ void setup() {
|
||||||
// this tries to minimize packet loss by searching for a free channel
|
// this tries to minimize packet loss by searching for a free channel
|
||||||
// before actually sending an uplink
|
// before actually sending an uplink
|
||||||
node.setCSMA(6, 2, true);
|
node.setCSMA(6, 2, true);
|
||||||
|
|
||||||
|
// enable or disable the dutycycle
|
||||||
|
// the second argument specific allowed airtime per hour in milliseconds
|
||||||
|
// 1250 = TTN FUP (30 seconds / 24 hours)
|
||||||
|
// if not called, this corresponds to setDutyCycle(true, 0)
|
||||||
|
// setting this to 0 corresponds to the band's maximum allowed dutycycle by law
|
||||||
|
node.setDutyCycle(true, 1250);
|
||||||
|
|
||||||
|
// enable or disable the dwell time limits
|
||||||
|
// the second argument specific allowed airtime per uplink in milliseconds
|
||||||
|
// if not called, this corresponds to setDwellTime(true, 0)
|
||||||
|
// setting this to 0 corresponds to the band's maximum allowed dwell time by law
|
||||||
|
node.setDwellTime(true, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
@ -152,8 +168,11 @@ void loop() {
|
||||||
String strUp = "Hello World! #" + String(fcntUp);
|
String strUp = "Hello World! #" + String(fcntUp);
|
||||||
|
|
||||||
// send a confirmed uplink to port 10 every 64th frame
|
// send a confirmed uplink to port 10 every 64th frame
|
||||||
|
// and also request the LinkCheck and DeviceTime MAC commands
|
||||||
if(fcntUp % 64 == 0) {
|
if(fcntUp % 64 == 0) {
|
||||||
state = node.uplink(strUp, 10, true);
|
state = node.uplink(strUp, 10, true);
|
||||||
|
node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK);
|
||||||
|
node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME);
|
||||||
} else {
|
} else {
|
||||||
state = node.uplink(strUp, 10);
|
state = node.uplink(strUp, 10);
|
||||||
}
|
}
|
||||||
|
@ -229,6 +248,24 @@ void loop() {
|
||||||
|
|
||||||
Serial.print(radio.getFrequencyError());
|
Serial.print(radio.getFrequencyError());
|
||||||
|
|
||||||
|
uint8_t margin = 0;
|
||||||
|
uint8_t gwCnt = 0;
|
||||||
|
if(node.getMacLinkCheckAns(&margin, &gwCnt)) {
|
||||||
|
Serial.print(F("[LoRaWAN] LinkCheck margin:\t"));
|
||||||
|
Serial.println(margin);
|
||||||
|
Serial.print(F("[LoRaWAN] LinkCheck count:\t"));
|
||||||
|
Serial.println(gwCnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t networkTime = 0;
|
||||||
|
uint8_t fracSecond = 0;
|
||||||
|
if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true)) {
|
||||||
|
Serial.print(F("[LoRaWAN] DeviceTime Unix:\t"));
|
||||||
|
Serial.println(networkTime);
|
||||||
|
Serial.print(F("[LoRaWAN] LinkCheck second:\t1/"));
|
||||||
|
Serial.println(fracSecond);
|
||||||
|
}
|
||||||
|
|
||||||
} else if(state == RADIOLIB_ERR_RX_TIMEOUT) {
|
} else if(state == RADIOLIB_ERR_RX_TIMEOUT) {
|
||||||
Serial.println(F("timeout!"));
|
Serial.println(F("timeout!"));
|
||||||
|
|
||||||
|
@ -244,5 +281,9 @@ void loop() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// wait before sending another packet
|
// wait before sending another packet
|
||||||
delay(30000);
|
uint32_t minimumDelay = 60000; // try to send once every minute
|
||||||
|
uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!)
|
||||||
|
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
|
||||||
|
|
||||||
|
delay(delayMs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,6 +295,7 @@ restore KEYWORD2
|
||||||
beginOTAA KEYWORD2
|
beginOTAA KEYWORD2
|
||||||
beginABP KEYWORD2
|
beginABP KEYWORD2
|
||||||
saveSession KEYWORD2
|
saveSession KEYWORD2
|
||||||
|
sendMacCommandReq KEYWORD2
|
||||||
uplink KEYWORD2
|
uplink KEYWORD2
|
||||||
downlink KEYWORD2
|
downlink KEYWORD2
|
||||||
sendReceive KEYWORD2
|
sendReceive KEYWORD2
|
||||||
|
@ -302,11 +303,19 @@ setDeviceStatus KEYWORD2
|
||||||
getFcntUp KEYWORD2
|
getFcntUp KEYWORD2
|
||||||
getNFcntDown KEYWORD2
|
getNFcntDown KEYWORD2
|
||||||
getAFcntDown KEYWORD2
|
getAFcntDown KEYWORD2
|
||||||
|
resetFcntDown KEYWORD2
|
||||||
setDatarate KEYWORD2
|
setDatarate KEYWORD2
|
||||||
setADR KEYWORD2
|
setADR KEYWORD2
|
||||||
|
setDutyCycle KEYWORD2
|
||||||
|
dutyCycleInterval KEYWORD2
|
||||||
|
timeUntilUplink KEYWORD2
|
||||||
|
setDwellTime KEYWORD2
|
||||||
|
maxPayloadDwellTime KEYWORD2
|
||||||
setTxPower KEYWORD2
|
setTxPower KEYWORD2
|
||||||
selectSubband KEYWORD2
|
selectSubband KEYWORD2
|
||||||
setCSMA KEYWORD2
|
setCSMA KEYWORD2
|
||||||
|
getMacLinkCheckAns KEYWORD2
|
||||||
|
getMacDeviceTimeAns KEYWORD2
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
|
|
|
@ -112,7 +112,7 @@
|
||||||
|
|
||||||
// the amount of space allocated to the persistent storage
|
// the amount of space allocated to the persistent storage
|
||||||
#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE)
|
#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE)
|
||||||
#define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x0180)
|
#define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x01C0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
128
src/Hal.h
128
src/Hal.h
|
@ -6,60 +6,86 @@
|
||||||
|
|
||||||
#include "BuildOpt.h"
|
#include "BuildOpt.h"
|
||||||
|
|
||||||
|
#define RADIOLIB_EEPROM_TABLE_VERSION (0x0002)
|
||||||
|
|
||||||
// list of persistent parameters
|
// list of persistent parameters
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID (0) // this is NOT the LoRaWAN version, but version of this table
|
enum RADIOLIB_EEPROM_PARAMS {
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID (1)
|
RADIOLIB_EEPROM_TABLE_VERSION_ID, // table layout version
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID (2)
|
RADIOLIB_EEPROM_LORAWAN_CLASS_ID, // class A, B or C
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID (3)
|
RADIOLIB_EEPROM_LORAWAN_MODE_ID, // none, OTAA or ABP
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID (4)
|
RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, // checksum of keys used for device activation
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID (5)
|
RADIOLIB_EEPROM_LORAWAN_VERSION_ID, // LoRaWAN version
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID (6)
|
RADIOLIB_EEPROM_LORAWAN_LAST_TIME_ID, // last heard time through DeviceTimeReq or Beacon
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID (7)
|
RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID (8)
|
RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (9)
|
RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID (10)
|
RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID (11)
|
RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (12)
|
RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (13)
|
RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID (14)
|
RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (15)
|
RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID (16)
|
RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID (17)
|
RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID (18)
|
RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID (19)
|
RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID (20)
|
RADIOLIB_EEPROM_LORAWAN_RJ_COUNT0_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID (21)
|
RADIOLIB_EEPROM_LORAWAN_RJ_COUNT1_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (22)
|
RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID (23)
|
RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID,
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID (24)
|
RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_BEACON_FREQ_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_PING_SLOT_CHANNEL_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_PERIODICITY_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID,
|
||||||
|
RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID
|
||||||
|
};
|
||||||
|
|
||||||
static const uint32_t RadioLibPersistentParamTable[] = {
|
static const uint32_t RadioLibPersistentParamTable[] = {
|
||||||
0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID
|
0x00, // RADIOLIB_EEPROM_LORAWAN_TABLE_VERSION_ID
|
||||||
0x01, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID
|
0x02, // RADIOLIB_EEPROM_LORAWAN_CLASS_ID
|
||||||
0x03, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION
|
0x03, // RADIOLIB_EEPROM_LORAWAN_MODE_ID
|
||||||
0x04, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID
|
0x05, // RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID
|
||||||
0x05, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID
|
0x07, // RADIOLIB_EEPROM_LORAWAN_VERSION_ID
|
||||||
0x06, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID
|
0x08, // RADIOLIB_EEPROM_LORAWAN_LAST_TIME_ID
|
||||||
0x07, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID
|
0x0C, // RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID
|
||||||
0x0A, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID
|
0x10, // RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID
|
||||||
0x0B, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID
|
0x20, // RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID
|
||||||
0x0C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID
|
0x30, // RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID
|
||||||
0x10, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID
|
0x40, // RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID
|
||||||
0x20, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID
|
0x50, // RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID
|
||||||
0x30, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID
|
0x54, // RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID
|
||||||
0x40, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID
|
0x58, // RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID
|
||||||
0x50, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID
|
0x5C, // RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID
|
||||||
0x54, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID
|
0x60, // RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID
|
||||||
0x58, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID
|
0x64, // RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID
|
||||||
0x5C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID
|
0x68, // RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID
|
||||||
0x60, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID
|
0x6C, // RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID
|
||||||
0x64, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID
|
0x70, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT0_ID
|
||||||
0x68, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID
|
0x72, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT1_ID
|
||||||
0x6C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID
|
0x74, // RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID
|
||||||
0x70, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID
|
0xA0, // RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID - NOTE change upon ADR Ack Req
|
||||||
0x8E, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID
|
0xA4, // RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID
|
||||||
0xD0, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID
|
0xA5, // RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID
|
||||||
0x0180, // end
|
0xA9, // RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID
|
||||||
|
0xAA, // RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID
|
||||||
|
0xAB, // RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID
|
||||||
|
0xAC, // RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID
|
||||||
|
0xAD, // RADIOLIB_EEPROM_LORAWAN_BEACON_FREQ_ID
|
||||||
|
0xB0, // RADIOLIB_EEPROM_LORAWAN_PING_SLOT_CHANNEL_ID
|
||||||
|
0xB4, // RADIOLIB_EEPROM_LORAWAN_PERIODICITY_ID
|
||||||
|
0xB5, // RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID
|
||||||
|
0xB6, // RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID
|
||||||
|
0x0100, // RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID
|
||||||
|
0x0180, // RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID
|
||||||
|
0x01C0, // end
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -519,7 +519,7 @@
|
||||||
#define RADIOLIB_ERR_INVALID_CID (-1107)
|
#define RADIOLIB_ERR_INVALID_CID (-1107)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief User requested to start uplink while still inside RX window.
|
\brief User requested to start uplink while still inside RX window or under dutycycle.
|
||||||
*/
|
*/
|
||||||
#define RADIOLIB_ERR_UPLINK_UNAVAILABLE (-1108)
|
#define RADIOLIB_ERR_UPLINK_UNAVAILABLE (-1108)
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,8 +5,15 @@
|
||||||
#include "../PhysicalLayer/PhysicalLayer.h"
|
#include "../PhysicalLayer/PhysicalLayer.h"
|
||||||
#include "../../utils/Cryptography.h"
|
#include "../../utils/Cryptography.h"
|
||||||
|
|
||||||
// version of NVM table layout (NOT the LoRaWAN version)
|
// activation mode
|
||||||
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION (0x01)
|
#define RADIOLIB_LORAWAN_MODE_OTAA (0x01AA)
|
||||||
|
#define RADIOLIB_LORAWAN_MODE_ABP (0x0AB9)
|
||||||
|
#define RADIOLIB_LORAWAN_MODE_NONE (0x0000)
|
||||||
|
|
||||||
|
// operation mode
|
||||||
|
#define RADIOLIB_LORAWAN_CLASS_A (0x00)
|
||||||
|
#define RADIOLIB_LORAWAN_CLASS_B (0x01)
|
||||||
|
#define RADIOLIB_LORAWAN_CLASS_C (0x02)
|
||||||
|
|
||||||
// preamble format
|
// preamble format
|
||||||
#define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34)
|
#define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34)
|
||||||
|
@ -77,7 +84,6 @@
|
||||||
// recommended default settings
|
// recommended default settings
|
||||||
#define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000)
|
#define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000)
|
||||||
#define RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS ((RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS) + 1000)
|
#define RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS ((RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS) + 1000)
|
||||||
#define RADIOLIB_LORAWAN_RX_WINDOW_LEN_MS (500)
|
|
||||||
#define RADIOLIB_LORAWAN_RX1_DR_OFFSET (0)
|
#define RADIOLIB_LORAWAN_RX1_DR_OFFSET (0)
|
||||||
#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000)
|
#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000)
|
||||||
#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000)
|
#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000)
|
||||||
|
@ -87,6 +93,8 @@
|
||||||
#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000)
|
#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000)
|
||||||
#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS (3000)
|
#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS (3000)
|
||||||
#define RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM (-2)
|
#define RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM (-2)
|
||||||
|
#define RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N (10) // send rejoin request 16384 uplinks
|
||||||
|
#define RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N (15) // once every year, not actually implemented
|
||||||
|
|
||||||
// join request message layout
|
// join request message layout
|
||||||
#define RADIOLIB_LORAWAN_JOIN_REQUEST_LEN (23)
|
#define RADIOLIB_LORAWAN_JOIN_REQUEST_LEN (23)
|
||||||
|
@ -155,32 +163,61 @@
|
||||||
#define RADIOLIB_LORAWAN_MAGIC (0x39EA)
|
#define RADIOLIB_LORAWAN_MAGIC (0x39EA)
|
||||||
|
|
||||||
// MAC commands
|
// MAC commands
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_RESET (0x01)
|
#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_LINK_CHECK (0x02)
|
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR (0x03)
|
#define RADIOLIB_LORAWAN_MAC_RESET (0x01)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_DUTY_CYCLE (0x04)
|
#define RADIOLIB_LORAWAN_MAC_LINK_CHECK (0x02)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_RX_PARAM_SETUP (0x05)
|
#define RADIOLIB_LORAWAN_MAC_LINK_ADR (0x03)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_DEV_STATUS (0x06)
|
#define RADIOLIB_LORAWAN_MAC_DUTY_CYCLE (0x04)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_NEW_CHANNEL (0x07)
|
#define RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP (0x05)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_RX_TIMING_SETUP (0x08)
|
#define RADIOLIB_LORAWAN_MAC_DEV_STATUS (0x06)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_TX_PARAM_SETUP (0x09)
|
#define RADIOLIB_LORAWAN_MAC_NEW_CHANNEL (0x07)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_DL_CHANNEL (0x0A)
|
#define RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP (0x08)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_REKEY (0x0B)
|
#define RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP (0x09)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_ADR_PARAM_SETUP (0x0C)
|
#define RADIOLIB_LORAWAN_MAC_DL_CHANNEL (0x0A)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_DEVICE_TIME (0x0D)
|
#define RADIOLIB_LORAWAN_MAC_REKEY (0x0B)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_FORCE_REJOIN (0x0E)
|
#define RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP (0x0C)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP (0x0F)
|
#define RADIOLIB_LORAWAN_MAC_DEVICE_TIME (0x0D)
|
||||||
#define RADIOLIB_LORAWAN_MAC_CMD_PROPRIETARY (0x80)
|
#define RADIOLIB_LORAWAN_MAC_FORCE_REJOIN (0x0E)
|
||||||
|
#define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F)
|
||||||
|
#define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80)
|
||||||
|
|
||||||
// unused frame counter value
|
// unused frame counter value
|
||||||
#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF)
|
#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF)
|
||||||
|
|
||||||
// the length of internal MAC command queue - hopefully this is enough for most use cases
|
// the length of internal MAC command queue - hopefully this is enough for most use cases
|
||||||
#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (8)
|
#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9)
|
||||||
|
|
||||||
// the maximum number of simultaneously available channels
|
// the maximum number of simultaneously available channels
|
||||||
#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16)
|
#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16)
|
||||||
|
|
||||||
|
struct LoRaWANMacSpec_t {
|
||||||
|
const uint8_t cid;
|
||||||
|
const uint8_t lenDn;
|
||||||
|
const uint8_t lenUp;
|
||||||
|
const bool user; // whether this MAC command can be issued by a user or not
|
||||||
|
};
|
||||||
|
|
||||||
|
const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = {
|
||||||
|
{ 0x00, 0, 0, false }, // not an actual MAC command, exists for offsetting
|
||||||
|
{ 0x01, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_RESET
|
||||||
|
{ 0x02, 2, 0, true }, // RADIOLIB_LORAWAN_MAC_LINK_CHECK
|
||||||
|
{ 0x03, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_LINK_ADR
|
||||||
|
{ 0x04, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_DUTY_CYCLE
|
||||||
|
{ 0x05, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP
|
||||||
|
{ 0x06, 0, 2, false }, // RADIOLIB_LORAWAN_MAC_DEV_STATUS
|
||||||
|
{ 0x07, 5, 1, false }, // RADIOLIB_LORAWAN_MAC_NEW_CHANNEL
|
||||||
|
{ 0x08, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP
|
||||||
|
{ 0x09, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP
|
||||||
|
{ 0x0A, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_DL_CHANNEL
|
||||||
|
{ 0x0B, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REKEY
|
||||||
|
{ 0x0C, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP
|
||||||
|
{ 0x0D, 5, 0, true }, // RADIOLIB_LORAWAN_MAC_DEVICE_TIME
|
||||||
|
{ 0x0E, 2, 0, false }, // RADIOLIB_LORAWAN_MAC_FORCE_REJOIN
|
||||||
|
{ 0x0F, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP
|
||||||
|
{ 0x80, 5, 0, true } // RADIOLIB_LORAWAN_MAC_PROPRIETARY
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\struct LoRaWANChannelSpan_t
|
\struct LoRaWANChannelSpan_t
|
||||||
\brief Structure to save information about LoRaWAN channels.
|
\brief Structure to save information about LoRaWAN channels.
|
||||||
|
@ -251,6 +288,13 @@ struct LoRaWANBand_t {
|
||||||
/*! \brief Number of power steps in this band */
|
/*! \brief Number of power steps in this band */
|
||||||
int8_t powerNumSteps;
|
int8_t powerNumSteps;
|
||||||
|
|
||||||
|
/*! \brief Number of milliseconds per hour of allowed Time-on-Air */
|
||||||
|
uint32_t dutyCycle;
|
||||||
|
|
||||||
|
/*! \brief Maximum dwell time per message in milliseconds */
|
||||||
|
uint32_t dwellTimeUp;
|
||||||
|
uint32_t dwellTimeDn;
|
||||||
|
|
||||||
/*! \brief A set of default uplink (TX) channels for frequency-type bands */
|
/*! \brief A set of default uplink (TX) channels for frequency-type bands */
|
||||||
LoRaWANChannel_t txFreqs[3];
|
LoRaWANChannel_t txFreqs[3];
|
||||||
|
|
||||||
|
@ -371,7 +415,8 @@ class LoRaWANNode {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Restore session by loading information from persistent storage.
|
\brief Restore session by loading information from persistent storage.
|
||||||
\returns \ref status_codes
|
\returns \ref status_codes in case of error,
|
||||||
|
else LoRaWAN session mode (0 = no active session, 0xAA / 170 = OTAA, 0xAB / 171 = ABP)
|
||||||
*/
|
*/
|
||||||
int16_t restore();
|
int16_t restore();
|
||||||
#endif
|
#endif
|
||||||
|
@ -413,6 +458,15 @@ class LoRaWANNode {
|
||||||
*/
|
*/
|
||||||
int16_t saveSession();
|
int16_t saveSession();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Add a MAC command to the uplink queue.
|
||||||
|
Only LinkCheck and DeviceTime are available to the user.
|
||||||
|
Other commands are ignored; duplicate MAC commands are discarded.
|
||||||
|
\param cid ID of the MAC command
|
||||||
|
\returns Whether or not the MAC command was added to the queue.
|
||||||
|
*/
|
||||||
|
bool sendMacCommandReq(uint8_t cid);
|
||||||
|
|
||||||
#if defined(RADIOLIB_BUILD_ARDUINO)
|
#if defined(RADIOLIB_BUILD_ARDUINO)
|
||||||
/*!
|
/*!
|
||||||
\brief Send a message to the server.
|
\brief Send a message to the server.
|
||||||
|
@ -533,6 +587,12 @@ class LoRaWANNode {
|
||||||
/*! \brief Returns the last application downlink's frame counter */
|
/*! \brief Returns the last application downlink's frame counter */
|
||||||
uint32_t getAFcntDown();
|
uint32_t getAFcntDown();
|
||||||
|
|
||||||
|
/*! \brief Reset the downlink frame counters (application and network)
|
||||||
|
This is unsafe and can possibly allow replay attacks using downlinks.
|
||||||
|
It mainly exists as part of the TS008 Specification Verification protocol.
|
||||||
|
*/
|
||||||
|
void resetFcntDown();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Set uplink datarate. This should not be used when ADR is enabled.
|
\brief Set uplink datarate. This should not be used when ADR is enabled.
|
||||||
\param dr Datarate to use for uplinks.
|
\param dr Datarate to use for uplinks.
|
||||||
|
@ -546,6 +606,41 @@ class LoRaWANNode {
|
||||||
*/
|
*/
|
||||||
void setADR(bool enable = true);
|
void setADR(bool enable = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Toggle adherence to dutyCycle limits to on or off.
|
||||||
|
\param enable Whether to adhere to dutyCycle limits or not (default true).
|
||||||
|
\param msPerHour The maximum allowed Time-on-Air per hour in milliseconds
|
||||||
|
(default 0 = maximum allowed for configured band).
|
||||||
|
*/
|
||||||
|
void setDutyCycle(bool enable = true, uint32_t msPerHour = 0);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Calculate the minimum interval to adhere to a certain dutyCycle.
|
||||||
|
This interval is based on the ToA of one uplink and does not actually keep track of total airtime.
|
||||||
|
\param msPerHour The maximum allowed dutycyle (in milliseconds per hour).
|
||||||
|
\param airtime The airtime of the uplink.
|
||||||
|
\returns Required interval (delay) in milliseconds between consecutive uplinks.
|
||||||
|
*/
|
||||||
|
uint32_t dutyCycleInterval(uint32_t msPerHour, uint32_t airtime);
|
||||||
|
|
||||||
|
/*! \brief Returns time in milliseconds until next uplink is available under dutyCycle limits */
|
||||||
|
uint32_t timeUntilUplink();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Toggle adherence to dwellTime limits to on or off.
|
||||||
|
\param enable Whether to adhere to dwellTime limits or not (default true).
|
||||||
|
\param msPerHour The maximum allowed Time-on-Air per uplink in milliseconds
|
||||||
|
(default 0 = maximum allowed for configured band).
|
||||||
|
*/
|
||||||
|
void setDwellTime(bool enable, uint32_t msPerUplink = 0);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Returns the maximum payload given the currently present dwelltime limits.
|
||||||
|
WARNING: the addition of MAC commands may cause uplink errors;
|
||||||
|
if you want to be sure that your payload fits within dwelltime limits, subtract 16 from the result!
|
||||||
|
*/
|
||||||
|
uint8_t maxPayloadDwellTime();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Configure TX power of the radio module.
|
\brief Configure TX power of the radio module.
|
||||||
\param txPower Output power during TX mode to be set in dBm.
|
\param txPower Output power during TX mode to be set in dBm.
|
||||||
|
@ -578,12 +673,35 @@ class LoRaWANNode {
|
||||||
*/
|
*/
|
||||||
void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false);
|
void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Returns the quality of connectivity after requesting a LinkCheck MAC command.
|
||||||
|
Returns 'true' if a network response was succesfully parsed.
|
||||||
|
Returns 'false' if there was no network response / parsing failed.
|
||||||
|
\param margin Link margin in dB of LinkCheckReq demodulation at gateway side.
|
||||||
|
\param gwCnt Number of gateways that received the LinkCheckReq.
|
||||||
|
\returns Whether the parameters where succesfully parsed.
|
||||||
|
*/
|
||||||
|
bool getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Returns the network time after requesting a DeviceTime MAC command.
|
||||||
|
Returns 'true' if a network response was succesfully parsed.
|
||||||
|
Returns 'false' if there was no network response / parsing failed.
|
||||||
|
\param gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980)
|
||||||
|
\param fraction Fractional-second, in 1/256-second steps
|
||||||
|
\param returnUnix If true, returns Unix timestamp instead of GPS (default true)
|
||||||
|
\returns Whether the parameters where succesfully parsed.
|
||||||
|
*/
|
||||||
|
bool getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true);
|
||||||
|
|
||||||
#if !RADIOLIB_GODMODE
|
#if !RADIOLIB_GODMODE
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
PhysicalLayer* phyLayer = NULL;
|
PhysicalLayer* phyLayer = NULL;
|
||||||
const LoRaWANBand_t* band = NULL;
|
const LoRaWANBand_t* band = NULL;
|
||||||
|
|
||||||
|
void beginCommon();
|
||||||
|
|
||||||
LoRaWANMacCommandQueue_t commandsUp = {
|
LoRaWANMacCommandQueue_t commandsUp = {
|
||||||
.numCommands = 0,
|
.numCommands = 0,
|
||||||
.len = 0,
|
.len = 0,
|
||||||
|
@ -613,7 +731,8 @@ class LoRaWANNode {
|
||||||
uint8_t adrLimitExp = RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP;
|
uint8_t adrLimitExp = RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP;
|
||||||
uint8_t adrDelayExp = RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP;
|
uint8_t adrDelayExp = RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP;
|
||||||
uint8_t nbTrans = 1; // Number of allowed frame retransmissions
|
uint8_t nbTrans = 1; // Number of allowed frame retransmissions
|
||||||
uint8_t txPwrCur = 0;
|
uint8_t txPowerCur = 0;
|
||||||
|
uint8_t txPowerMax = 0;
|
||||||
uint32_t fcntUp = 0;
|
uint32_t fcntUp = 0;
|
||||||
uint32_t aFcntDown = 0;
|
uint32_t aFcntDown = 0;
|
||||||
uint32_t nFcntDown = 0;
|
uint32_t nFcntDown = 0;
|
||||||
|
@ -624,12 +743,22 @@ class LoRaWANNode {
|
||||||
// whether the current configured channel is in FSK mode
|
// whether the current configured channel is in FSK mode
|
||||||
bool FSK = false;
|
bool FSK = false;
|
||||||
|
|
||||||
// flag that shows whether the device is joined and there is an ongoing session
|
// flag that shows whether the device is joined and there is an ongoing session (none, ABP or OTAA)
|
||||||
bool isJoinedFlag = false;
|
uint16_t activeMode = 0;
|
||||||
|
|
||||||
// ADR is enabled by default
|
// ADR is enabled by default
|
||||||
bool adrEnabled = true;
|
bool adrEnabled = true;
|
||||||
|
|
||||||
|
// duty cycle is set upon initialization and activated in regions that impose this
|
||||||
|
bool dutyCycleEnabled = false;
|
||||||
|
uint32_t dutyCycle = 0;
|
||||||
|
|
||||||
|
// dwell time is set upon initialization and activated in regions that impose this
|
||||||
|
bool dwellTimeEnabledUp = false;
|
||||||
|
uint16_t dwellTimeUp = 0;
|
||||||
|
bool dwellTimeEnabledDn = false;
|
||||||
|
uint16_t dwellTimeDn = 0;
|
||||||
|
|
||||||
// enable/disable CSMA for LoRaWAN
|
// enable/disable CSMA for LoRaWAN
|
||||||
bool enableCSMA;
|
bool enableCSMA;
|
||||||
|
|
||||||
|
@ -653,6 +782,9 @@ class LoRaWANNode {
|
||||||
// LoRaWAN revision (1.0 vs 1.1)
|
// LoRaWAN revision (1.0 vs 1.1)
|
||||||
uint8_t rev = 0;
|
uint8_t rev = 0;
|
||||||
|
|
||||||
|
// Time on Air of last uplink
|
||||||
|
uint32_t lastToA = 0;
|
||||||
|
|
||||||
// timestamp to measure the RX1/2 delay (from uplink end)
|
// timestamp to measure the RX1/2 delay (from uplink end)
|
||||||
uint32_t rxDelayStart = 0;
|
uint32_t rxDelayStart = 0;
|
||||||
|
|
||||||
|
@ -714,9 +846,6 @@ class LoRaWANNode {
|
||||||
// configure channel based on cached data rate ID and frequency
|
// configure channel based on cached data rate ID and frequency
|
||||||
int16_t configureChannel(uint8_t dir);
|
int16_t configureChannel(uint8_t dir);
|
||||||
|
|
||||||
// save all available channels to persistent storage
|
|
||||||
int16_t saveChannels();
|
|
||||||
|
|
||||||
// restore all available channels from persistent storage
|
// restore all available channels from persistent storage
|
||||||
int16_t restoreChannels();
|
int16_t restoreChannels();
|
||||||
|
|
||||||
|
@ -724,10 +853,14 @@ class LoRaWANNode {
|
||||||
int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue);
|
int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue);
|
||||||
|
|
||||||
// delete a specific MAC command from queue, indicated by the command ID
|
// delete a specific MAC command from queue, indicated by the command ID
|
||||||
int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue);
|
// if a payload pointer is supplied, this returns the payload of the MAC command
|
||||||
|
int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t payload[5] = NULL);
|
||||||
|
|
||||||
// execute mac command, return the number of processed bytes for sequential processing
|
// execute mac command, return the number of processed bytes for sequential processing
|
||||||
size_t execMacCommand(LoRaWANMacCommand_t* cmd);
|
bool execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom = true);
|
||||||
|
|
||||||
|
// get the payload length for a specific MAC command
|
||||||
|
uint8_t getMacPayloadLength(uint8_t cid);
|
||||||
|
|
||||||
// Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013).
|
// Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013).
|
||||||
void performCSMA();
|
void performCSMA();
|
||||||
|
|
|
@ -7,6 +7,9 @@ const LoRaWANBand_t EU868 = {
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 16,
|
.powerMax = 16,
|
||||||
.powerNumSteps = 7,
|
.powerNumSteps = 7,
|
||||||
|
.dutyCycle = 36000,
|
||||||
|
.dwellTimeUp = 0,
|
||||||
|
.dwellTimeDn = 0,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 868.100, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 868.100, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 868.300, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 868.300, .drMin = 0, .drMax = 5},
|
||||||
|
@ -49,6 +52,9 @@ const LoRaWANBand_t US915 = {
|
||||||
.payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 },
|
.payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 },
|
||||||
.powerMax = 30,
|
.powerMax = 30,
|
||||||
.powerNumSteps = 10,
|
.powerNumSteps = 10,
|
||||||
|
.dutyCycle = 0,
|
||||||
|
.dwellTimeUp = 400,
|
||||||
|
.dwellTimeDn = 0,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
|
@ -112,6 +118,9 @@ const LoRaWANBand_t CN780 = {
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 12,
|
.powerMax = 12,
|
||||||
.powerNumSteps = 5,
|
.powerNumSteps = 5,
|
||||||
|
.dutyCycle = 3600,
|
||||||
|
.dwellTimeUp = 0,
|
||||||
|
.dwellTimeDn = 0,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 779.500, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 779.500, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 779.700, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 779.700, .drMin = 0, .drMax = 5},
|
||||||
|
@ -154,6 +163,9 @@ const LoRaWANBand_t EU433 = {
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 12,
|
.powerMax = 12,
|
||||||
.powerNumSteps = 5,
|
.powerNumSteps = 5,
|
||||||
|
.dutyCycle = 36000,
|
||||||
|
.dwellTimeUp = 0,
|
||||||
|
.dwellTimeDn = 0,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 433.175, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 433.175, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 433.375, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 433.375, .drMin = 0, .drMax = 5},
|
||||||
|
@ -196,6 +208,9 @@ const LoRaWANBand_t AU915 = {
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 },
|
||||||
.powerMax = 30,
|
.powerMax = 30,
|
||||||
.powerNumSteps = 10,
|
.powerNumSteps = 10,
|
||||||
|
.dutyCycle = 0,
|
||||||
|
.dwellTimeUp = 0,
|
||||||
|
.dwellTimeDn = 0,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
|
@ -259,6 +274,9 @@ const LoRaWANBand_t CN500 = {
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 19,
|
.powerMax = 19,
|
||||||
.powerNumSteps = 7,
|
.powerNumSteps = 7,
|
||||||
|
.dutyCycle = 0,
|
||||||
|
.dwellTimeUp = 0,
|
||||||
|
.dwellTimeDn = 0,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
|
@ -315,6 +333,9 @@ const LoRaWANBand_t AS923 = {
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 16,
|
.powerMax = 16,
|
||||||
.powerNumSteps = 7,
|
.powerNumSteps = 7,
|
||||||
|
.dutyCycle = 36000,
|
||||||
|
.dwellTimeUp = 400,
|
||||||
|
.dwellTimeDn = 400,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5},
|
||||||
|
@ -357,6 +378,9 @@ const LoRaWANBand_t KR920 = {
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 14,
|
.powerMax = 14,
|
||||||
.powerNumSteps = 7,
|
.powerNumSteps = 7,
|
||||||
|
.dutyCycle = 0,
|
||||||
|
.dwellTimeUp = 0,
|
||||||
|
.dwellTimeDn = 0,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 922.100, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 922.100, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 922.300, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 922.300, .drMin = 0, .drMax = 5},
|
||||||
|
@ -399,6 +423,9 @@ const LoRaWANBand_t IN865 = {
|
||||||
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
.payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
.powerMax = 30,
|
.powerMax = 30,
|
||||||
.powerNumSteps = 10,
|
.powerNumSteps = 10,
|
||||||
|
.dutyCycle = 0,
|
||||||
|
.dwellTimeUp = 0,
|
||||||
|
.dwellTimeDn = 0,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 865.0625, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 865.0625, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 865.4025, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 865.4025, .drMin = 0, .drMax = 5},
|
||||||
|
|
Loading…
Add table
Reference in a new issue