diff --git a/lib/lib_rf/RadioLib/.gitignore b/lib/lib_rf/RadioLib/.gitignore index 226f5c8eb..b65463c98 100644 --- a/lib/lib_rf/RadioLib/.gitignore +++ b/lib/lib_rf/RadioLib/.gitignore @@ -23,3 +23,6 @@ extras/SX126x_Spectrum_Scan/out/* # cmake build/ + +# Compote build output +dist diff --git a/lib/lib_rf/RadioLib/README.md b/lib/lib_rf/RadioLib/README.md index e726a7ad6..d33794b37 100644 --- a/lib/lib_rf/RadioLib/README.md +++ b/lib/lib_rf/RadioLib/README.md @@ -1,4 +1,4 @@ -# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/jgromes/library/RadioLib.svg)](https://registry.platformio.org/libraries/jgromes/RadioLib) +# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/jgromes/library/RadioLib.svg)](https://registry.platformio.org/libraries/jgromes/RadioLib) [![Component Registry](https://components.espressif.com/components/jgromes/radiolib/badge.svg)](https://components.espressif.com/components/jgromes/radiolib) ### _One radio library to rule them all!_ diff --git a/lib/lib_rf/RadioLib/TasmotaAlert.md b/lib/lib_rf/RadioLib/TasmotaAlert.md deleted file mode 100644 index 04cf74d1b..000000000 --- a/lib/lib_rf/RadioLib/TasmotaAlert.md +++ /dev/null @@ -1,10 +0,0 @@ -TasmotaAlert - -Action to take in case of new release of RadioLib - -20240223 - -1 - Remove folder `RadioLibs/examples/NonArduino` (Fixes Github vulnerability alerts) -2 - Add ``#define RADIOLIB_EEPROM_UNSUPPORTED`` to file `RadioLib/src/BuildOpt.h` section ``defined(ESP8266)`` and ``defined(ESP32) || defined(ARDUINO_ARCH_ESP32)`` (Fixes safeboot compilation) -3 - Disable in files `RadioLib\src\protocols\LoRaWAN\LoRaWAN.cpp` and `RadioLib\src\protocols\Pager\Pager.cpp` inclusion of ``#include "esp_attr.h"`` (Fixes ESP8266 compilation) - diff --git a/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index 95777c5aa..d4ec506d1 100644 --- a/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -158,7 +158,7 @@ void loop() { Serial.println(state); } - // on EEPROM enabled boards, you can save the current session + // on EEPROM enabled boards, you should save the current session // by calling "saveSession" which allows retrieving the session after reboot or deepsleep node.saveSession(); diff --git a/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index cf765cb16..02089e4bc 100644 --- a/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino +++ b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -165,7 +165,7 @@ void loop() { Serial.println(state); } - // on EEPROM enabled boards, you can save the current session + // on EEPROM enabled boards, you should save the current session // by calling "saveSession" which allows retrieving the session after reboot or deepsleep node.saveSession(); diff --git a/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index 771890b51..207dd356d 100644 --- a/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -259,7 +259,7 @@ void loop() { uint8_t margin = 0; uint8_t gwCnt = 0; - if(node.getMacLinkCheckAns(&margin, &gwCnt)) { + if(node.getMacLinkCheckAns(&margin, &gwCnt) == RADIOLIB_ERR_NONE) { Serial.print(F("[LoRaWAN] LinkCheck margin:\t")); Serial.println(margin); Serial.print(F("[LoRaWAN] LinkCheck count:\t")); @@ -268,10 +268,10 @@ void loop() { uint32_t networkTime = 0; uint8_t fracSecond = 0; - if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true)) { + if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) { Serial.print(F("[LoRaWAN] DeviceTime Unix:\t")); Serial.println(networkTime); - Serial.print(F("[LoRaWAN] LinkCheck second:\t1/")); + Serial.print(F("[LoRaWAN] DeviceTime second:\t1/")); Serial.println(fracSecond); } @@ -283,11 +283,9 @@ void loop() { Serial.println(state); } - // on EEPROM enabled boards, you can save the current session + // on EEPROM enabled boards, you should save the current session // by calling "saveSession" which allows retrieving the session after reboot or deepsleep - /* - node.saveSession(); - */ + node.saveSession(); // wait before sending another packet uint32_t minimumDelay = 60000; // try to send once every minute diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino index fcdff8a21..99a962b27 100644 --- a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -42,6 +42,9 @@ volatile bool operationDone = false; // is transmitted or received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // we sent or received a packet, set the flag operationDone = true; diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino index 9e006639e..df025bc99 100644 --- a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -39,6 +39,9 @@ volatile bool operationDone = false; // is transmitted or received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // we sent or received packet, set the flag operationDone = true; diff --git a/lib/lib_rf/RadioLib/idf_component.yml b/lib/lib_rf/RadioLib/idf_component.yml new file mode 100644 index 000000000..09f82ad98 --- /dev/null +++ b/lib/lib_rf/RadioLib/idf_component.yml @@ -0,0 +1,11 @@ +version: "6.4.2" +description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." +tags: "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan" +url: "https://github.com/jgromes/RadioLib" +repository: "https://github.com/jgromes/RadioLib.git" +license: "MIT" +dependencies: + # Required IDF version + idf: ">=4.1" +maintainers: + "Jan Gromeš " diff --git a/lib/lib_rf/RadioLib/keywords.txt b/lib/lib_rf/RadioLib/keywords.txt index 6ee6222c8..48efe6325 100644 --- a/lib/lib_rf/RadioLib/keywords.txt +++ b/lib/lib_rf/RadioLib/keywords.txt @@ -293,6 +293,10 @@ setModem KEYWORD2 # LoRaWAN wipe KEYWORD2 +getBufferNonces KEYWORD2 +setBufferNonces KEYWORD2 +getBufferSession KEYWORD2 +setBufferSession KEYWORD2 restore KEYWORD2 beginOTAA KEYWORD2 beginABP KEYWORD2 @@ -426,9 +430,10 @@ RADIOLIB_ERR_INVALID_CHANNEL LITERAL1 RADIOLIB_ERR_INVALID_CID LITERAL1 RADIOLIB_ERR_UPLINK_UNAVAILABLE LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_FULL LITERAL1 -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_DATA_RATE_INVALID LITERAL1 \ No newline at end of file +RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 +RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1 +RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1 \ No newline at end of file diff --git a/lib/lib_rf/RadioLib/src/ArduinoHal.cpp b/lib/lib_rf/RadioLib/src/ArduinoHal.cpp index 11422d59d..9c5fd571a 100644 --- a/lib/lib_rf/RadioLib/src/ArduinoHal.cpp +++ b/lib/lib_rf/RadioLib/src/ArduinoHal.cpp @@ -2,10 +2,6 @@ #if defined(RADIOLIB_BUILD_ARDUINO) -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) -#include -#endif - ArduinoHal::ArduinoHal(): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&RADIOLIB_DEFAULT_SPI), initInterface(true) {} ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&spi), spiSettings(spiSettings) {} @@ -118,47 +114,6 @@ void inline ArduinoHal::spiEnd() { spi->end(); } -void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) - EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); - #elif defined(ARDUINO_ARCH_APOLLO3) - EEPROM.init(); - #endif - for(size_t i = 0; i < len; i++) { - buff[i] = EEPROM.read(addr + i); - } - #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) - EEPROM.end(); - #endif - #else - (void)addr; - (void)buff; - (void)len; - #endif -} - -void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) - EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); - #elif defined(ARDUINO_ARCH_APOLLO3) - EEPROM.init(); - #endif - for(size_t i = 0; i < len; i++) { - EEPROM.write(addr + i, buff[i]); - } - #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) - EEPROM.commit(); - EEPROM.end(); - #endif - #else - (void)addr; - (void)buff; - (void)len; - #endif -} - void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) if(pin == RADIOLIB_NC) { diff --git a/lib/lib_rf/RadioLib/src/ArduinoHal.h b/lib/lib_rf/RadioLib/src/ArduinoHal.h index bcda95aec..00074c1d3 100644 --- a/lib/lib_rf/RadioLib/src/ArduinoHal.h +++ b/lib/lib_rf/RadioLib/src/ArduinoHal.h @@ -51,9 +51,6 @@ class ArduinoHal : public RadioLibHal { void spiEndTransaction() override; void spiEnd() override; - void readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) override; - void writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) override; - // implementations of virtual RadioLibHal methods void init() override; void term() override; diff --git a/lib/lib_rf/RadioLib/src/BuildOpt.h b/lib/lib_rf/RadioLib/src/BuildOpt.h index ed71ec400..5653a1ef1 100644 --- a/lib/lib_rf/RadioLib/src/BuildOpt.h +++ b/lib/lib_rf/RadioLib/src/BuildOpt.h @@ -7,14 +7,18 @@ * Debug output enable. * Warning: Debug output will slow down the whole system significantly. * Also, it will result in larger compiled binary. - * Levels: debug - only main info - * verbose - full transcript of all SPI communication + * Levels: basic - only main info + * protocol - mainly LoRaWAN stuff, but other protocols as well + * SPI - full transcript of all SPI communication */ -#if !defined(RADIOLIB_DEBUG) - #define RADIOLIB_DEBUG (0) +#if !defined(RADIOLIB_DEBUG_BASIC) + #define RADIOLIB_DEBUG_BASIC (0) #endif -#if !defined(RADIOLIB_VERBOSE) - #define RADIOLIB_VERBOSE (0) +#if !defined(RADIOLIB_DEBUG_PROTOCOL) + #define RADIOLIB_DEBUG_PROTOCOL (0) +#endif +#if !defined(RADIOLIB_DEBUG_SPI) + #define RADIOLIB_DEBUG_SPI (0) #endif // set which output port should be used for debug output @@ -100,21 +104,6 @@ #define RADIOLIB_STATIC_ARRAY_SIZE (256) #endif -// the base address for persistent storage -// some protocols (e.g. LoRaWAN) require a method -// to store some data persistently -// on Arduino, this will use EEPROM, on non-Arduino platform, -// it will use anything provided by the hardware abstraction layer -// RadioLib will place these starting at this address -#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_BASE (0) -#endif - -// the amount of space allocated to the persistent storage -#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x01C0) -#endif - /* * Uncomment on boards whose clock runs too slow or too fast * Set the value according to the following scheme: @@ -216,14 +205,12 @@ #elif defined(ESP8266) // ESP8266 boards #define RADIOLIB_PLATFORM "ESP8266" - #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(ESP32) || defined(ARDUINO_ARCH_ESP32) #define RADIOLIB_ESP32 - + // ESP32 boards #define RADIOLIB_PLATFORM "ESP32" - #define RADIOLIB_EEPROM_UNSUPPORTED // ESP32 doesn't support tone(), but it can be emulated via LED control peripheral #define RADIOLIB_TONE_UNSUPPORTED @@ -236,7 +223,6 @@ #elif defined(SAMD_SERIES) // Adafruit SAMD boards (M0 and M4) #define RADIOLIB_PLATFORM "Adafruit SAMD" - #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(ARDUINO_ARCH_SAMD) // Arduino SAMD (Zero, MKR, etc.) @@ -244,18 +230,15 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(__SAM3X8E__) // Arduino Due #define RADIOLIB_PLATFORM "Arduino Due" #define RADIOLIB_TONE_UNSUPPORTED - #define RADIOLIB_EEPROM_UNSUPPORTED #elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) // Adafruit nRF52 boards #define RADIOLIB_PLATFORM "Adafruit nRF52" - #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(ARDUINO_ARC32_TOOLS) // Intel Curie @@ -278,7 +261,6 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_EEPROM_UNSUPPORTED // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED @@ -290,7 +272,6 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_EEPROM_UNSUPPORTED // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED @@ -312,7 +293,6 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_EEPROM_UNSUPPORTED // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED @@ -471,23 +451,35 @@ #define RADIOLIB_EXCLUDE_STM32WLX (1) #endif +// set the global debug mode flag +#if RADIOLIB_DEBUG_BASIC || RADIOLIB_DEBUG_PROTOCOL || RADIOLIB_DEBUG_SPI + #define RADIOLIB_DEBUG (1) +#else + #define RADIOLIB_DEBUG (0) +#endif + #if RADIOLIB_DEBUG #if defined(RADIOLIB_BUILD_ARDUINO) #define RADIOLIB_DEBUG_PRINT(...) Module::serialPrintf(__VA_ARGS__) #define RADIOLIB_DEBUG_PRINTLN(M, ...) Module::serialPrintf(M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) Module::serialPrintf(LEVEL "" M, ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) Module::serialPrintf(LEVEL "" M "\n", ##__VA_ARGS__) // some platforms do not support printf("%f"), so it has to be done this way - #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) + #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) #else #if !defined(RADIOLIB_DEBUG_PRINT) #define RADIOLIB_DEBUG_PRINT(...) fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M, ##__VA_ARGS__) #endif #if !defined(RADIOLIB_DEBUG_PRINTLN) #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M "\n", ##__VA_ARGS__) #endif - #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PRINT("%.3f", VAL) + #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL) #endif - #define RADIOLIB_DEBUG_HEXDUMP(...) Module::hexdump(__VA_ARGS__) + + #define RADIOLIB_DEBUG_HEXDUMP(LEVEL, ...) Module::hexdump(LEVEL, __VA_ARGS__) #else #define RADIOLIB_DEBUG_PRINT(...) {} #define RADIOLIB_DEBUG_PRINTLN(...) {} @@ -495,14 +487,49 @@ #define RADIOLIB_DEBUG_HEXDUMP(...) {} #endif -#if RADIOLIB_VERBOSE - #define RADIOLIB_VERBOSE_PRINT(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) - #define RADIOLIB_VERBOSE_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) +#if RADIOLIB_DEBUG_BASIC + #define RADIOLIB_DEBUG_BASIC_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_DBG: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_DBG: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_DBG: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_DBG: ", __VA_ARGS__); #else - #define RADIOLIB_VERBOSE_PRINT(...) {} - #define RADIOLIB_VERBOSE_PRINTLN(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) {} #endif +#if RADIOLIB_DEBUG_PROTOCOL + #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_PRO: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_PRO: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_PRO: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_PRO: ", __VA_ARGS__); +#else + #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) {} +#endif + +#if RADIOLIB_DEBUG_SPI + #define RADIOLIB_DEBUG_SPI_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_SPI: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_SPI: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN_LVL("", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_SPI: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_SPI: ", __VA_ARGS__); +#else + #define RADIOLIB_DEBUG_SPI_PRINT(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) {} + #define RADIOLIB_DEBUG_SPI_PRINTLN(...) {} + #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) {} +#endif + + /*! \brief A simple assert macro, will return on error. */ @@ -536,4 +563,4 @@ #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) -#endif +#endif \ No newline at end of file diff --git a/lib/lib_rf/RadioLib/src/BuildOptUser.h b/lib/lib_rf/RadioLib/src/BuildOptUser.h index fc1a56574..d81104d7d 100644 --- a/lib/lib_rf/RadioLib/src/BuildOptUser.h +++ b/lib/lib_rf/RadioLib/src/BuildOptUser.h @@ -5,7 +5,8 @@ // most commonly, RADIOLIB_EXCLUDE_* macros // or enabling debug output -//#define RADIOLIB_DEBUG (1) -//#define RADIOLIB_VERBOSE (1) +//#define RADIOLIB_DEBUG_BASIC (1) // basic debugging (e.g. reporting GPIO timeouts or module not being found) +//#define RADIOLIB_DEBUG_PROTOCOL (1) // protocol information (e.g. LoRaWAN internal information) +//#define RADIOLIB_DEBUG_SPI (1) // verbose transcription of all SPI communication - produces large debug logs! #endif diff --git a/lib/lib_rf/RadioLib/src/Hal.cpp b/lib/lib_rf/RadioLib/src/Hal.cpp index 1b4e818e2..1a42aa15a 100644 --- a/lib/lib_rf/RadioLib/src/Hal.cpp +++ b/lib/lib_rf/RadioLib/src/Hal.cpp @@ -33,50 +33,3 @@ void RadioLibHal::yield() { uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { return(pin); } - -void RadioLibHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - // these are only needed for some protocols, so it's not needed to have them by default - (void)addr; - (void)buff; - (void)len; -} - -void RadioLibHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - // these are only needed for some protocols, so it's not needed to have them by default - (void)addr; - (void)buff; - (void)len; -} - -void RadioLibHal::wipePersistentStorage() { - uint8_t dummy = 0; - for(size_t i = 0; i < RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE; i++) { - this->writePersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + i, &dummy, sizeof(uint8_t)); - } -} - -uint32_t RadioLibHal::getPersistentAddr(uint32_t id) { - return(RadioLibPersistentParamTable[id]); -} - -template -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] + offset, ptr, sizeof(T)); -} - -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 -T RadioLibHal::getPersistentParameter(uint32_t id) { - T val = 0; - uint8_t *ptr = (uint8_t*)&val; - this->readPersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + RadioLibPersistentParamTable[id], ptr, sizeof(T)); - return(val); -} - -template uint8_t RadioLibHal::getPersistentParameter(uint32_t id); -template uint16_t RadioLibHal::getPersistentParameter(uint32_t id); -template uint32_t RadioLibHal::getPersistentParameter(uint32_t id); diff --git a/lib/lib_rf/RadioLib/src/Hal.h b/lib/lib_rf/RadioLib/src/Hal.h index fbc8d5f75..03bf174ce 100644 --- a/lib/lib_rf/RadioLib/src/Hal.h +++ b/lib/lib_rf/RadioLib/src/Hal.h @@ -6,88 +6,6 @@ #include "BuildOpt.h" -#define RADIOLIB_EEPROM_TABLE_VERSION (0x0002) - -// list of persistent parameters -enum RADIOLIB_EEPROM_PARAMS { - RADIOLIB_EEPROM_TABLE_VERSION_ID, // table layout version - RADIOLIB_EEPROM_LORAWAN_CLASS_ID, // class A, B or C - RADIOLIB_EEPROM_LORAWAN_MODE_ID, // none, OTAA or ABP - RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, // checksum of keys used for device activation - RADIOLIB_EEPROM_LORAWAN_VERSION_ID, // LoRaWAN version - RADIOLIB_EEPROM_LORAWAN_LAST_TIME_ID, // last heard time through DeviceTimeReq or Beacon - RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, - RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID, - RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID, - RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID, - RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID, - RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, - RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, - RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, - RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, - RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, - RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, - RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, - RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, - RADIOLIB_EEPROM_LORAWAN_RJ_COUNT0_ID, - RADIOLIB_EEPROM_LORAWAN_RJ_COUNT1_ID, - RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, - RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID, - 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[] = { - 0x00, // RADIOLIB_EEPROM_LORAWAN_TABLE_VERSION_ID - 0x02, // RADIOLIB_EEPROM_LORAWAN_CLASS_ID - 0x03, // RADIOLIB_EEPROM_LORAWAN_MODE_ID - 0x05, // RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID - 0x07, // RADIOLIB_EEPROM_LORAWAN_VERSION_ID - 0x08, // RADIOLIB_EEPROM_LORAWAN_LAST_TIME_ID - 0x0C, // RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID - 0x10, // RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID - 0x20, // RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID - 0x30, // RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID - 0x40, // RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID - 0x50, // RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID - 0x54, // RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID - 0x58, // RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID - 0x5C, // RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID - 0x60, // RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID - 0x64, // RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID - 0x68, // RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID - 0x6C, // RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID - 0x70, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT0_ID - 0x72, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT1_ID - 0x74, // RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID - 0xA0, // RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID - 0xA4, // RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID - 0xA5, // RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID - 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 -}; - /*! \class RadioLibHal \brief Hardware abstraction library base interface. @@ -289,56 +207,6 @@ class RadioLibHal { \returns The interrupt number of a given pin. */ virtual uint32_t pinToInterrupt(uint32_t pin); - - /*! - \brief Method to read from persistent storage (e.g. EEPROM). - \param addr Address to start reading at. - \param buff Buffer to read into. - \param len Number of bytes to read. - */ - virtual void readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len); - - /*! - \brief Method to write to persistent storage (e.g. EEPROM). - \param addr Address to start writing to. - \param buff Buffer to write. - \param len Number of bytes to write. - */ - virtual void writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len); - - /*! - \brief Method to wipe the persistent storage by writing to 0. - Will write at most RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE bytes. - */ - void wipePersistentStorage(); - - /*! - \brief Method to convert from persistent parameter ID to its physical address. - \param id Parameter ID. - \returns Parameter physical address. - */ - uint32_t getPersistentAddr(uint32_t id); - - /*! - \brief Method to set arbitrary parameter to persistent storage. - This method DOES NOT perform any endianness conversion, so the value - 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 - void setPersistentParameter(uint32_t id, T val, uint32_t offset = 0); - - /*! - \brief Method to get arbitrary parameter from persistent storage. - This method DOES NOT perform any endianness conversion, so the value - will be retrieved in the system endian! - \param id Parameter ID to load from. - \returns The loaded value. - */ - template - T getPersistentParameter(uint32_t id); }; #endif diff --git a/lib/lib_rf/RadioLib/src/Module.cpp b/lib/lib_rf/RadioLib/src/Module.cpp index b6f8583d0..c46e26e9c 100644 --- a/lib/lib_rf/RadioLib/src/Module.cpp +++ b/lib/lib_rf/RadioLib/src/Module.cpp @@ -44,10 +44,10 @@ void Module::init() { this->hal->init(); this->hal->pinMode(csPin, this->hal->GpioModeOutput); this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh); - RADIOLIB_DEBUG_PRINTLN("\nRadioLib Debug Info"); - RADIOLIB_DEBUG_PRINTLN("Version: %d.%d.%d.%d", RADIOLIB_VERSION_MAJOR, RADIOLIB_VERSION_MINOR, RADIOLIB_VERSION_PATCH, RADIOLIB_VERSION_EXTRA); - RADIOLIB_DEBUG_PRINTLN("Platform: " RADIOLIB_PLATFORM); - RADIOLIB_DEBUG_PRINTLN("Compiled: " __DATE__ " " __TIME__ "\n"); + RADIOLIB_DEBUG_BASIC_PRINTLN("RadioLib Debug Info"); + RADIOLIB_DEBUG_BASIC_PRINTLN("Version: %d.%d.%d.%d", RADIOLIB_VERSION_MAJOR, RADIOLIB_VERSION_MINOR, RADIOLIB_VERSION_PATCH, RADIOLIB_VERSION_EXTRA); + RADIOLIB_DEBUG_BASIC_PRINTLN("Platform: " RADIOLIB_PLATFORM); + RADIOLIB_DEBUG_BASIC_PRINTLN("Compiled: " __DATE__ " " __TIME__ "\n"); } void Module::term() { @@ -89,14 +89,14 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t } // check failed, print debug info - RADIOLIB_DEBUG_PRINTLN(); - RADIOLIB_DEBUG_PRINTLN("address:\t0x%X", reg); - RADIOLIB_DEBUG_PRINTLN("bits:\t\t%d %d", msb, lsb); - RADIOLIB_DEBUG_PRINTLN("value:\t\t0x%X", value); - RADIOLIB_DEBUG_PRINTLN("current:\t0x%X", currentValue); - RADIOLIB_DEBUG_PRINTLN("mask:\t\t0x%X", mask); - RADIOLIB_DEBUG_PRINTLN("new:\t\t0x%X", newValue); - RADIOLIB_DEBUG_PRINTLN("read:\t\t0x%X", readValue); + RADIOLIB_DEBUG_SPI_PRINTLN(); + RADIOLIB_DEBUG_SPI_PRINTLN("address:\t0x%X", reg); + RADIOLIB_DEBUG_SPI_PRINTLN("bits:\t\t%d %d", msb, lsb); + RADIOLIB_DEBUG_SPI_PRINTLN("value:\t\t0x%X", value); + RADIOLIB_DEBUG_SPI_PRINTLN("current:\t0x%X", currentValue); + RADIOLIB_DEBUG_SPI_PRINTLN("mask:\t\t0x%X", mask); + RADIOLIB_DEBUG_SPI_PRINTLN("new:\t\t0x%X", newValue); + RADIOLIB_DEBUG_SPI_PRINTLN("read:\t\t0x%X", readValue); return(RADIOLIB_ERR_SPI_WRITE_FAILED); #else @@ -182,19 +182,19 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d } // print debug information - #if RADIOLIB_VERBOSE + #if RADIOLIB_DEBUG_SPI uint8_t* debugBuffPtr = NULL; if(cmd == SPIwriteCommand) { - RADIOLIB_VERBOSE_PRINT("W\t%X\t", reg); + RADIOLIB_DEBUG_SPI_PRINT("W\t%X\t", reg); debugBuffPtr = &buffOut[this->SPIaddrWidth/8]; } else if(cmd == SPIreadCommand) { - RADIOLIB_VERBOSE_PRINT("R\t%X\t", reg); + RADIOLIB_DEBUG_SPI_PRINT("R\t%X\t", reg); debugBuffPtr = &buffIn[this->SPIaddrWidth/8]; } for(size_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t", debugBuffPtr[n]); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", debugBuffPtr[n]); } - RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); #endif #if !RADIOLIB_STATIC_ONLY @@ -291,7 +291,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - RADIOLIB_DEBUG_PRINTLN("GPIO pre-transfer timeout, is it connected?"); + RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?"); #if !RADIOLIB_STATIC_ONLY delete[] buffOut; delete[] buffIn; @@ -318,7 +318,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - RADIOLIB_DEBUG_PRINTLN("GPIO post-transfer timeout, is it connected?"); + RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO post-transfer timeout, is it connected?"); #if !RADIOLIB_STATIC_ONLY delete[] buffOut; delete[] buffIn; @@ -342,31 +342,34 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } // print debug information - #if RADIOLIB_VERBOSE + #if RADIOLIB_DEBUG_SPI // print command byte(s) - RADIOLIB_VERBOSE_PRINT("CMD"); + RADIOLIB_DEBUG_SPI_PRINT("CMD"); if(write) { - RADIOLIB_VERBOSE_PRINT("W\t"); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("W\t"); } else { - RADIOLIB_VERBOSE_PRINT("R\t"); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("R\t"); } size_t n = 0; for(; n < cmdLen; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t", cmd[n]); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", cmd[n]); } - RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); // print data bytes - RADIOLIB_VERBOSE_PRINT("SI\t"); + RADIOLIB_DEBUG_SPI_PRINT("SI\t"); + for(n = 0; n < cmdLen; n++) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("\t"); + } for(; n < buffLen; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t", buffOut[n]); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffOut[n]); } - RADIOLIB_VERBOSE_PRINTLN(); - RADIOLIB_VERBOSE_PRINT("SO\t"); - for(n = cmdLen; n < buffLen; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t", buffIn[n]); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + RADIOLIB_DEBUG_SPI_PRINT("SO\t"); + for(n = 0; n < buffLen; n++) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffIn[n]); } - RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); #endif #if !RADIOLIB_STATIC_ONLY @@ -404,7 +407,7 @@ uint32_t Module::reflect(uint32_t in, uint8_t bits) { } #if RADIOLIB_DEBUG -void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { +void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { size_t rem_len = len; for(size_t i = 0; i < len; i+=16) { char str[80]; @@ -443,20 +446,23 @@ void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, for(size_t j = line_len; j < 16; j++) { sprintf(&str[58 + j], " "); } + if(level) { + RADIOLIB_DEBUG_PRINT(level); + } RADIOLIB_DEBUG_PRINT(str); RADIOLIB_DEBUG_PRINTLN(); rem_len -= 16; } } -void Module::regdump(uint16_t start, size_t len) { +void Module::regdump(const char* level, uint16_t start, size_t len) { #if RADIOLIB_STATIC_ONLY uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* buff = new uint8_t[len]; #endif SPIreadRegisterBurst(start, len, buff); - hexdump(buff, len, start); + hexdump(level, buff, len, start); #if !RADIOLIB_STATIC_ONLY delete[] buff; #endif diff --git a/lib/lib_rf/RadioLib/src/Module.h b/lib/lib_rf/RadioLib/src/Module.h index c67aaf6aa..9b5b78dbc 100644 --- a/lib/lib_rf/RadioLib/src/Module.h +++ b/lib/lib_rf/RadioLib/src/Module.h @@ -471,19 +471,21 @@ class Module { #if RADIOLIB_DEBUG /*! \brief Function to dump data as hex into the debug port. + \param level RadioLib debug level, set to NULL to not print. \param data Data to dump. \param len Number of bytes to dump. \param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t). \param be Print multi-byte data as big endian. Defaults to false. */ - static void hexdump(uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); + static void hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); /*! \brief Function to dump device registers as hex into the debug port. + \param level RadioLib debug level, set to NULL to not print. \param start First address to dump. \param len Number of bytes to dump. */ - void regdump(uint16_t start, size_t len); + void regdump(const char* level, uint16_t start, size_t len); #endif #if RADIOLIB_DEBUG and defined(RADIOLIB_BUILD_ARDUINO) diff --git a/lib/lib_rf/RadioLib/src/TypeDef.h b/lib/lib_rf/RadioLib/src/TypeDef.h index f82e787b1..818d99d59 100644 --- a/lib/lib_rf/RadioLib/src/TypeDef.h +++ b/lib/lib_rf/RadioLib/src/TypeDef.h @@ -528,30 +528,35 @@ */ #define RADIOLIB_ERR_COMMAND_QUEUE_FULL (-1109) -/*! - \brief Unable to pop existing MAC command because the queue is empty. -*/ -#define RADIOLIB_ERR_COMMAND_QUEUE_EMPTY (-1110) - /*! \brief Unable to delete MAC command because it was not found in the queue. */ -#define RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND (-1111) +#define RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND (-1110) /*! \brief Unable to join network because JoinNonce is not higher than saved value. */ -#define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1112) +#define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1111) /*! \brief Received downlink Network frame counter is invalid (lower than last heard value). */ -#define RADIOLIB_ERR_N_FCNT_DOWN_INVALID (-1113) +#define RADIOLIB_ERR_N_FCNT_DOWN_INVALID (-1112) /*! \brief Received downlink Application frame counter is invalid (lower than last heard value). */ -#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1114) +#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1113) + +/*! + \brief Uplink payload length at this datarate exceeds the active dwell time limitations. +*/ +#define RADIOLIB_ERR_DWELL_TIME_EXCEEDED (-1114) + +/*! + \brief The buffer integrity check did not match the supplied checksum value. +*/ +#define RADIOLIB_ERR_CHECKSUM_MISMATCH (-1115) /*! \} diff --git a/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.cpp b/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.cpp index fbfa212bc..447e0420e 100644 --- a/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.cpp +++ b/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.cpp @@ -21,18 +21,18 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pw if((version == RADIOLIB_CC1101_VERSION_CURRENT) || (version == RADIOLIB_CC1101_VERSION_LEGACY) || (version == RADIOLIB_CC1101_VERSION_CLONE)) { flagFound = true; } else { - RADIOLIB_DEBUG_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); this->mod->hal->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("No CC1101 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No CC1101 found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN("M\tCC1101"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tCC1101"); } // configure settings not accessible by API @@ -916,7 +916,6 @@ void CC1101::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], uint8_t CC1101::randomByte() { // set mode to Rx SPIsendCommand(RADIOLIB_CC1101_CMD_RX); - RADIOLIB_DEBUG_PRINTLN("CC1101::randomByte"); // wait a bit for the RSSI reading to stabilise this->mod->hal->delay(10); @@ -1113,7 +1112,7 @@ void CC1101::SPIsendCommand(uint8_t cmd) { // stop transfer this->mod->hal->spiEndTransaction(); this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); - RADIOLIB_VERBOSE_PRINTLN("CMD\tW\t%02X\t%02X", cmd, status); + RADIOLIB_DEBUG_SPI_PRINTLN("CMD\tW\t%02X\t%02X", cmd, status); (void)status; } diff --git a/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.h b/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.h index e3354ae10..9d2254a4c 100644 --- a/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.h +++ b/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.h @@ -599,14 +599,14 @@ class CC1101: public PhysicalLayer { int16_t standby(uint8_t mode) override; /*! - \brief Starts direct mode transmission. + \brief Starts synchronous direct mode transmission. \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. \returns \ref status_codes */ int16_t transmitDirect(uint32_t frf = 0) override; /*! - \brief Starts direct mode reception. + \brief Starts synchronous direct mode reception. \returns \ref status_codes */ int16_t receiveDirect() override; diff --git a/lib/lib_rf/RadioLib/src/modules/RF69/RF69.cpp b/lib/lib_rf/RadioLib/src/modules/RF69/RF69.cpp index 54e6cc749..a934898ed 100644 --- a/lib/lib_rf/RadioLib/src/modules/RF69/RF69.cpp +++ b/lib/lib_rf/RadioLib/src/modules/RF69/RF69.cpp @@ -23,18 +23,18 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, if(version == RADIOLIB_RF69_CHIP_VERSION) { flagFound = true; } else { - RADIOLIB_DEBUG_PRINTLN("RF69 not found! (%d of 10 tries) RADIOLIB_RF69_REG_VERSION == 0x%04X, expected 0x0024", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("RF69 not found! (%d of 10 tries) RADIOLIB_RF69_REG_VERSION == 0x%04X, expected 0x0024", i + 1, version); this->mod->hal->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("No RF69 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No RF69 found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN("M\tRF69"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tRF69"); } // configure settings not accessible by API diff --git a/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.cpp b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.cpp index 44ff904d7..11424eed3 100644 --- a/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.cpp +++ b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.cpp @@ -21,23 +21,23 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po flagFound = true; this->chipRevision = version; } else { - RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); mod->hal->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("No SX1231 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX1231 found!"); mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX1231"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX1231"); // configure settings not accessible by API int16_t state = config(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tRF69"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tRF69"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.cpp b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.cpp index ab8808f9a..16c4bca14 100644 --- a/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.cpp +++ b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.cpp @@ -22,23 +22,23 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po flagFound = true; this->chipRevision = version; } else { - RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); mod->hal->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("No SX1233 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX1233 found!"); mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX1233"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX1233"); // configure settings not accessible by API int16_t state = config(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tRF69"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tRF69"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.cpp b/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.cpp index 8ba17ac0c..161a52453 100644 --- a/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.cpp +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.cpp @@ -6,6 +6,7 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) { this->mod = mod; this->XTAL = false; + this->standbyXOSC = false; } int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { @@ -22,11 +23,11 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo // try to find the SX126x chip if(!SX126x::findChip(this->chipType)) { - RADIOLIB_DEBUG_PRINTLN("No SX126x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX126x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); // BW in kHz and SF are required in order to calculate LDRO for setModulationParams // set the defaults, this will get overwritten later anyway @@ -107,11 +108,11 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL // try to find the SX126x chip if(!SX126x::findChip(this->chipType)) { - RADIOLIB_DEBUG_PRINTLN("No SX126x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX126x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); // initialize configuration variables (will be overwritten during public settings configuration) this->bitRate = 21333; // 48.0 kbps @@ -246,7 +247,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_UNKNOWN); } - RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); // start transmission state = startTransmit(data, len, addr); @@ -295,7 +296,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { return(RADIOLIB_ERR_UNKNOWN); } - RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); @@ -463,7 +464,7 @@ int16_t SX126x::sleep(bool retainConfig) { } int16_t SX126x::standby() { - return(SX126x::standby(RADIOLIB_SX126X_STANDBY_RC)); + return(SX126x::standby(this->standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC : RADIOLIB_SX126X_STANDBY_RC)); } int16_t SX126x::standby(uint8_t mode, bool wakeup) { @@ -643,7 +644,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t symbolLength = ((uint32_t)(10 * 1000) << this->spreadingFactor) / (10 * this->bandwidthKhz); uint32_t sleepPeriod = symbolLength * sleepSymbols; - RADIOLIB_DEBUG_PRINTLN("Auto sleep period: %lu", sleepPeriod); + RADIOLIB_DEBUG_BASIC_PRINTLN("Auto sleep period: %lu", sleepPeriod); // when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time. // the duration is sleepPeriod + 2 * wakePeriod. @@ -654,7 +655,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t wakePeriod = RADIOLIB_MAX( (symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A) symbolLength * (minSymbols + 1)); //(B) - RADIOLIB_DEBUG_PRINTLN("Auto wake period: %lu", wakePeriod); + RADIOLIB_DEBUG_BASIC_PRINTLN("Auto wake period: %lu", wakePeriod); // If our sleep period is shorter than our transition time, just use the standard startReceive if(sleepPeriod < this->tcxoDelay + 1016) { @@ -1580,10 +1581,10 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) RADIOLIB_ASSERT(state); // check the version - #if RADIOLIB_DEBUG + #if RADIOLIB_DEBUG_BASIC char ver_pre[16]; this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); - RADIOLIB_DEBUG_PRINTLN("Pre-update version string: %s", ver_pre); + RADIOLIB_DEBUG_BASIC_PRINTLN("Pre-update version string: %s", ver_pre); #endif // enable patch update @@ -1612,10 +1613,10 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_PRAM_UPDATE, NULL, 0); // check the version again - #if RADIOLIB_DEBUG + #if RADIOLIB_DEBUG_BASIC char ver_post[16]; this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); - RADIOLIB_DEBUG_PRINTLN("Post-update version string: %s", ver_post); + RADIOLIB_DEBUG_BASIC_PRINTLN("Post-update version string: %s", ver_post); #endif return(state); @@ -1857,12 +1858,12 @@ int16_t SX126x::calibrateImage(float freqMin, float freqMax) { int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); // if something failed, show the device errors - #if RADIOLIB_DEBUG + #if RADIOLIB_DEBUG_BASIC if(state != RADIOLIB_ERR_NONE) { // unless mode is forced to standby, device errors will be 0 standby(); uint16_t errors = getDeviceErrors(); - RADIOLIB_DEBUG_PRINTLN("Calibration failed, device errors: 0x%X", errors); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); } #endif return(state); @@ -2086,7 +2087,7 @@ int16_t SX126x::config(uint8_t modem) { RADIOLIB_ASSERT(state); // set Rx/Tx fallback mode to STDBY_RC - data[0] = RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; + data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); RADIOLIB_ASSERT(state); @@ -2121,12 +2122,12 @@ int16_t SX126x::config(uint8_t modem) { state = this->mod->SPIcheckStream(); // if something failed, show the device errors - #if RADIOLIB_DEBUG + #if RADIOLIB_DEBUG_BASIC if(state != RADIOLIB_ERR_NONE) { // unless mode is forced to standby, device errors will be 0 standby(); uint16_t errors = getDeviceErrors(); - RADIOLIB_DEBUG_PRINTLN("Calibration failed, device errors: 0x%X", errors); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); } #endif @@ -2159,15 +2160,15 @@ bool SX126x::findChip(const char* verStr) { // check version register if(strncmp(verStr, version, 6) == 0) { - RADIOLIB_DEBUG_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:"); - RADIOLIB_DEBUG_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); - RADIOLIB_DEBUG_PRINTLN(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:"); + RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_PRINTLN(); flagFound = true; } else { - #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); - RADIOLIB_DEBUG_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); - RADIOLIB_DEBUG_PRINTLN("Expected string: %s", verStr); + #if RADIOLIB_DEBUG_BASIC + RADIOLIB_DEBUG_BASIC_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); + RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr); #endif this->mod->hal->delay(10); i++; diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.h b/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.h index f02d5f7d3..848433b8c 100644 --- a/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.h +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.h @@ -447,6 +447,11 @@ class SX126x: public PhysicalLayer { */ bool XTAL; + /*! + \brief Whether to use XOSC (true) or RC (false) oscillator in standby mode. Defaults to false. + */ + bool standbyXOSC; + // basic methods /*! diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.cpp b/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.cpp index bdf4bae51..7606f001b 100644 --- a/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.cpp +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.cpp @@ -14,11 +14,11 @@ int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWo // try to find the SX127x chip if(!SX127x::findChip(chipVersions, numVersions)) { - RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX127x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x"); // set mode to standby int16_t state = standby(); @@ -65,11 +65,11 @@ int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqD // try to find the SX127x chip if(!SX127x::findChip(chipVersions, numVersions)) { - RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX127x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x"); // set mode to standby int16_t state = standby(); @@ -1554,7 +1554,7 @@ bool SX127x::findChip(uint8_t* vers, uint8_t num) { } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X", i + 1, version); this->mod->hal->delay(10); i++; } diff --git a/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.cpp b/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.cpp index 07d8661bf..55b18dd96 100644 --- a/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.cpp +++ b/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.cpp @@ -17,7 +17,7 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; this->mod->SPIstreamType = true; this->mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize LoRa modulation variables this->bandwidthKhz = bw; @@ -78,7 +78,7 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, ui this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; this->mod->SPIstreamType = true; this->mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize GFSK modulation variables this->bitRateKbps = br; @@ -147,7 +147,7 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uin this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; this->mod->SPIstreamType = true; this->mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize BLE modulation variables this->bitRateKbps = br; @@ -202,7 +202,7 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint1 this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; this->mod->SPIstreamType = true; this->mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize FLRC modulation variables this->bitRateKbps = br; @@ -308,7 +308,7 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (500% of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 5; - RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); // start transmission state = startTransmit(data, len, addr); @@ -341,7 +341,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // calculate timeout (1000% of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 10; - RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.cpp b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.cpp index 45b553569..7f9ed5fbe 100644 --- a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.cpp +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.cpp @@ -9,7 +9,7 @@ int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t po // execute common part int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tSi4430"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi4430"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.cpp b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.cpp index 799cec763..c603e6f15 100644 --- a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.cpp +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.cpp @@ -9,7 +9,7 @@ int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t po // execute common part int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tSi4431"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi4431"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.cpp b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.cpp index 40a97226b..56690862f 100644 --- a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.cpp +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.cpp @@ -9,7 +9,7 @@ int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t po // execute common part int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tSi4432"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi4432"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.cpp b/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.cpp index 2097ee58c..541f3eb74 100644 --- a/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.cpp +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.cpp @@ -15,11 +15,11 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) // try to find the Si443x chip if(!Si443x::findChip()) { - RADIOLIB_DEBUG_PRINTLN("No Si443x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No Si443x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN("M\tSi443x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi443x"); } // reset the device @@ -700,7 +700,7 @@ bool Si443x::findChip() { if(version == RADIOLIB_SI443X_DEVICE_VERSION) { flagFound = true; } else { - RADIOLIB_DEBUG_PRINTLN("Si443x not found! (%d of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == 0x%02X, expected 0x0%X", i + 1, version, RADIOLIB_SI443X_DEVICE_VERSION); + RADIOLIB_DEBUG_BASIC_PRINTLN("Si443x not found! (%d of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == 0x%02X, expected 0x0%X", i + 1, version, RADIOLIB_SI443X_DEVICE_VERSION); this->mod->hal->delay(10); i++; } @@ -769,9 +769,9 @@ int16_t Si443x::updateClockRecovery() { uint16_t rxOsr_fixed = (uint16_t)rxOsr; // print that whole mess - RADIOLIB_DEBUG_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); - RADIOLIB_DEBUG_PRINT_FLOAT(rxOsr, 2); - RADIOLIB_DEBUG_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); + RADIOLIB_DEBUG_BASIC_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); + RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(rxOsr, 2); + RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); // update oversampling ratio int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); diff --git a/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.cpp b/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.cpp index 3f64f27f1..a54298844 100644 --- a/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.cpp +++ b/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.cpp @@ -23,11 +23,11 @@ int16_t nRF24::begin(int16_t freq, int16_t dr, int8_t pwr, uint8_t addrWidth) { // check SPI connection int16_t val = this->mod->SPIgetRegValue(RADIOLIB_NRF24_REG_SETUP_AW); if(!((val >= 0) && (val <= 3))) { - RADIOLIB_DEBUG_PRINTLN("No nRF24 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No nRF24 found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tnRF24"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tnRF24"); // configure settings inaccessible by public API int16_t state = config(); diff --git a/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp index c534484ae..0e7692c3a 100644 --- a/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1,15 +1,11 @@ #include "LoRaWAN.h" #include -//#if defined(ESP32) -//#include "esp_attr.h" -//#endif +#if defined(ESP_PLATFORM) +#include "esp_attr.h" +#endif #if !RADIOLIB_EXCLUDE_LORAWAN -//#if defined(RADIOLIB_EEPROM_UNSUPPORTED) -// #warning "Persistent storage not supported!" -//#endif - // flag to indicate whether there was some action during Rx mode (timeout or downlink) static volatile bool downlinkAction = false; @@ -48,169 +44,210 @@ void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA this->enableCSMA = enableCSMA; } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) void LoRaWANNode::wipe() { - Module* mod = this->phyLayer->getMod(); - mod->hal->wipePersistentStorage(); + memset(this->bufferNonces, 0, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); } -int16_t LoRaWANNode::restore() { - // if already joined, ignore - if(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE) { - return(this->activeMode); +uint8_t* LoRaWANNode::getBufferNonces() { + return(this->bufferNonces); +} + +int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { + if(this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); + return(RADIOLIB_ERR_NONE); } - Module* mod = this->phyLayer->getMod(); + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + RADIOLIB_ASSERT(state); - uint8_t nvm_table_version = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID); - // if (RADIOLIB_EEPROM_LORAWAN_TABLE_VERSION > nvm_table_version) { + // copy the whole buffer over + memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + + // revert to inactive as long as no session is restored + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + + return(state); +} + +uint8_t* LoRaWANNode::getBufferSession() { + // update buffer contents + this->saveSession(); + + return(this->bufferSession); +} + +int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { + if(this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); + return(RADIOLIB_ERR_NONE); + } + + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + RADIOLIB_ASSERT(state); + + // the Nonces buffer holds a checksum signature - compare this to the signature that is in the session buffer + uint16_t signatureNonces = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); + uint16_t signatureInSession = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE]); + if(signatureNonces != signatureInSession) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The supplied session buffer does not match the Nonces buffer"); + return(RADIOLIB_ERR_CHECKSUM_MISMATCH); + } + + // copy the whole buffer over + memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + + // as both the Nonces and session are restored, revert to active session + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + + return(state); +} + +int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { + // check if there are actually values in the buffer + size_t i = 0; + for(; i < size; i++) { + if(buffer[i]) { + break; + } + } + if(i == size) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // check integrity of the whole buffer (compare checksum to included checksum) + uint16_t checkSum = LoRaWANNode::checkSum16(buffer, size - 2); + uint16_t signature = LoRaWANNode::ntoh(&buffer[size - 2]); + if(signature != checkSum) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Calculated checksum: %04X, expected: %04X", checkSum, signature); + return(RADIOLIB_ERR_CHECKSUM_MISMATCH); + } + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan) { + // if already joined, ignore + if(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE) { + return(RADIOLIB_ERR_NONE); + } + + bool isSameKeys = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM]) == checkSum; + bool isSameMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]) == lwMode; + bool isSameClass = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS]) == lwClass; + bool isSamePlan = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN]) == freqPlan; + + // check if Nonces buffer matches the current configuration + if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) { + // if configuration did not match, discard whatever is currently in the buffers and start fresh + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (checksum: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Nonces buffer:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Clearing buffer and starting fresh"); + this->wipe(); + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + if(lwMode == RADIOLIB_LORAWAN_MODE_OTAA) { + // Nonces buffer is OK, so we can at least restore Nonces + this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE]); + this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], 3); + } + + // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION]; + // if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) { // // set default values for variables that are new or something // } - (void)nvm_table_version; - // check the mode value - uint16_t lwMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID); - if(lwMode == RADIOLIB_LORAWAN_MODE_NONE) { - #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("mode value not set (no saved session)"); - RADIOLIB_DEBUG_PRINTLN("first 16 bytes of NVM:"); - uint8_t nvmBuff[16]; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); - RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); - #endif - // the mode value is not set, user will have to do perform the join procedure + if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] == 0) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No active session in progress; please join the network"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } // pull all authentication keys from persistent storage - this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]); + memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); - // get session parameters - this->rev = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID); - RADIOLIB_DEBUG_PRINTLN("LoRaWAN session: v1.%d", this->rev); - this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); - this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); - this->aFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID); - this->nFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID); - this->confFcntUp = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID); - this->confFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID); - this->adrFcnt = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID); + // restore session parameters + this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN session: v1.%d", this->rev); + this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]); + this->aFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]); + this->nFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]); + this->confFcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP]); + this->confFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]); + this->adrFcnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT]); + this->fcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP]); - // fcntUp is stored in highly efficient wear-leveling system, so parse it - this->restoreFcntUp(); + int16_t state = RADIOLIB_ERR_UNKNOWN; - // get the defined channels - int16_t state = this->restoreChannels(); - RADIOLIB_ASSERT(state); + // for dynamic bands, first restore the defined channels before restoring ADR + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // restore the defined channels + state = this->restoreChannels(); + RADIOLIB_ASSERT(state); + } - // get MAC state + // restore the complete MAC state LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, .repeat = 0, }; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); - // only apply the single ADR command on dynamic bands; fixed bands is done through channel restore - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cmd.len); + (void)execMacCommand(&cmd); + + // for fixed bands, first restore ADR, then the defined channels + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + state = this->restoreChannels(); + RADIOLIB_ASSERT(state); } cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd.len); + (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); - - cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd.len); + (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); - uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - memcpy(&this->commandsUp, queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - RADIOLIB_DEBUG_PRINTLN("Number of MAC commands: %d", this->commandsUp.numCommands); + // copy uplink MAC command queue back in place + memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); state = this->setPhyProperties(); RADIOLIB_ASSERT(state); // full session is restored, so set joined flag to whichever mode is restored - this->activeMode = lwMode; + this->activeMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]); - return(this->activeMode); -} - -int16_t LoRaWANNode::restoreFcntUp() { - Module* mod = this->phyLayer->getMod(); - - uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); - uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID + 1); - uint8_t buffSize = fcntBuffEnd - fcntBuffStart; - #if RADIOLIB_STATIC_ONLY - uint8_t fcntBuff[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* fcntBuff = new uint8_t[buffSize]; - #endif - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID), fcntBuff, buffSize); - - // copy the two most significant bytes from the first two bytes - uint32_t bits_30_22 = (uint32_t)fcntBuff[0]; - uint32_t bits_22_14 = (uint32_t)fcntBuff[1]; - - // the next 7 bits must be retrieved from the byte to which was written most recently - // this is the last byte that has its state bit (most significant bit) set equal to its predecessor - // we find the first byte that has its state bit different, and subtract one - uint8_t idx = 2; - uint8_t state = fcntBuff[idx] >> 7; - for(; idx < 5; idx++) { - if(fcntBuff[idx] >> 7 != state) { - break; - } - } - uint32_t bits_14_7 = (uint32_t)fcntBuff[idx-1] & 0x7F; - - // equally, the last 7 bits must be retrieved from the byte to which was written most recently - // this is the last byte that has its state bit (most significant bit) set equal to its predecessor - // we find the first byte that has its state bit different, and subtract one - idx = 5; - state = fcntBuff[idx] >> 7; - for(; idx < buffSize; idx++) { - if(fcntBuff[idx] >> 7 != state) { - break; - } - } - uint32_t bits_7_0 = (uint32_t)fcntBuff[idx-1] & 0x7F; - #if !RADIOLIB_STATIC_ONLY - delete[] fcntBuff; - #endif - - this->fcntUp = (bits_30_22 << 22) | (bits_22_14 << 14) | (bits_14_7 << 7) | bits_7_0; - return(RADIOLIB_ERR_NONE); + return(state); } int16_t LoRaWANNode::restoreChannels() { @@ -221,43 +258,34 @@ int16_t LoRaWANNode::restoreChannels() { this->setupChannelsFix(this->subBand); } - Module* mod = this->phyLayer->getMod(); uint8_t bufferZeroes[5] = { 0 }; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - uint8_t numBytesUp = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - uint8_t bufferUp[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), bufferUp, numBytesUp); - + uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, .payload = { 0 }, .len = 0, .repeat = 0 }; for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - memcpy(cmd.payload, &(bufferUp[i * cmd.len]), cmd.len); + memcpy(cmd.payload, startChannelsUp + (i * cmd.len), cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes cmd.repeat = 1; - (void)execMacCommand(&cmd, false); + (void)execMacCommand(&cmd); } } - uint8_t numBytesDn = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; - uint8_t bufferDn[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID), bufferDn, numBytesDn); - + uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS]; + cmd.cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; - memcpy(cmd.payload, &bufferDn[i * cmd.len], cmd.len); + memcpy(cmd.payload, startChannelsDown + (i * cmd.len), cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes - (void)execMacCommand(&cmd, false); + (void)execMacCommand(&cmd); } } } else { // RADIOLIB_LORAWAN_BAND_FIXED - uint8_t numADRCommands = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); - uint8_t numBytes = numADRCommands * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - uint8_t buffer[RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); - + uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .payload = { 0 }, @@ -265,52 +293,87 @@ int16_t LoRaWANNode::restoreChannels() { .repeat = 0, }; - for(int i = 0; i < numADRCommands; i++) { + // there are at most 8 channel masks present + for(int i = 0; i < 8; i++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - memcpy(cmd.payload, &buffer[i * cmd.len], cmd.len); + memcpy(cmd.payload, startMACpayload + (i * cmd.len), cmd.len); // there COULD, according to spec, be an all zeroes ADR command - meh - if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { - cmd.repeat = (i+1); - execMacCommand(&cmd, false); + if(memcmp(cmd.payload, bufferZeroes, cmd.len) == 0) { + break; } + cmd.repeat = (i+1); + (void)execMacCommand(&cmd); } } return(RADIOLIB_ERR_NONE); } -#endif -void LoRaWANNode::beginCommon(uint8_t joinDr) { +void LoRaWANNode::beginCommon(uint8_t initialDr) { // in case a new session is started while there is an ongoing session // clear the MAC queues completely memset(&(this->commandsUp), 0, sizeof(LoRaWANMacCommandQueue_t)); memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); + uint8_t drUp = 0; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // if join datarate is user-specified and valid, select that value + if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(initialDr >= this->band->txFreqs[0].drMin && initialDr <= this->band->txFreqs[0].drMax) { + drUp = initialDr; + } else { + // if there is no channel that allowed the user-specified datarate, revert to default datarate + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); + initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + } + + // if there is no (channel that allowed the) user-specified datarate, use a default datarate + // we use the floor of the average datarate of the first default channel + if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax) / 2; + } + + } else { + // if the user specified a certain datarate, check if any of the configured channels allows it + if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + uint8_t i = 0; + for(; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + if(initialDr >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin + && initialDr <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { + break; + } + } + } + // if there is no channel that allowed the user-specified datarate, revert to default datarate + if(i == RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); + initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + } + + // if there is no (channel that allowed the) user-specified datarate, use a default datarate + // we use the join-request datarate for one of the available channels + if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + // randomly select one of 8 or 9 channels and find corresponding datarate + uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; + uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 + if(rand <= 8) { + drUp = this->band->txSpans[0].joinRequestDataRate; // if one of the first 8 channels, select datarate of span 0 + } else { + drUp = this->band->txSpans[1].joinRequestDataRate; // if ninth channel, select datarate of span 1 + } + } + + } + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .payload = { 0 }, .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, .repeat = 0, }; - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - uint8_t drUp = 0; - // if join datarate is user-specified and valid, select that value; otherwise use - if(joinDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - if(joinDr >= this->band->txFreqs[0].drMin && joinDr <= this->band->txFreqs[0].drMax) { - drUp = joinDr; - } else { - RADIOLIB_DEBUG_PRINTLN("Datarate %d is not valid (min: %d, max %d) - using default", - joinDr, this->band->txFreqs[0].drMin, this->band->txFreqs[0].drMax); - joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; - } - } - if(joinDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax) / 2; - } - cmd.payload[0] = (drUp << 4); - } else { - uint8_t drJr = this->band->txSpans[0].joinRequestDataRate; - cmd.payload[0] = (drJr << 4); - } + cmd.payload[0] = (drUp << 4); // set uplink datarate cmd.payload[0] |= 0; // default to max Tx Power cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored (void)execMacCommand(&cmd); @@ -389,52 +452,36 @@ void LoRaWANNode::beginCommon(uint8_t joinDr) { (void)execMacCommand(&cmd); } -int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t joinDr, bool force) { - // check if we actually need to send the join request - Module* mod = this->phyLayer->getMod(); +int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force, uint8_t joinDr) { + // if not forced and already joined, don't do anything + if(!force && this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginOTAA(): Did not rejoin: session already active"); + return(RADIOLIB_ERR_NONE); + } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // generate activation key checksum uint16_t checkSum = 0; checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&joinEUI), 8); checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&devEUI), 8); checkSum ^= LoRaWANNode::checkSum16(nwkKey, 16); checkSum ^= LoRaWANNode::checkSum16(appKey, 16); - bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; - bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; - - if(validCheckSum && validMode) { - if(!force) { - // the device has joined already, we can just pull the data from persistent storage - RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); - return(this->restore()); - - } else { - // the credentials are still the same, so restore only DevNonce and JoinNonce - this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); - this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); - } + // if The Force is used, disable the active session; + // as a result, restore() will only restore Nonces if they are available, not the session + if(force) { + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; } + + state = this->restore(checkSum, RADIOLIB_LORAWAN_MODE_OTAA, RADIOLIB_LORAWAN_CLASS_A, this->band->bandNum); - // if forced by user, keys are new or changed mode, wipe the previous session - if(force || !validCheckSum || !validMode) { - #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", validCheckSum, validMode); - RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); - uint8_t nvmBuff[16]; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); - RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); - RADIOLIB_DEBUG_PRINTLN("Wiping EEPROM and starting a clean session"); - #endif - - this->wipe(); + if(!force) { + return(state); } -#else - (void)force; -#endif - - int16_t state = RADIOLIB_ERR_NONE; + Module* mod = this->phyLayer->getMod(); + // setup join-request uplink/downlink frequencies and datarates if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { state = this->setupChannelsDyn(true); @@ -443,7 +490,12 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } RADIOLIB_ASSERT(state); - // setup all MAC properties to default values + // on fixed bands, the join-datarate is specified per specification + // therefore, we ignore the value that was specified by the user + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + // setup all MAC properties to default values this->beginCommon(joinDr); // set the physical layer configuration @@ -458,9 +510,13 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); + // copy devNonce currently in use + uint16_t devNonceUsed = this->devNonce; // increment devNonce as we are sending another join-request this->devNonce += 1; + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); + // build the join-request message uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; @@ -468,7 +524,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], this->devNonce); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); // add the authentication code uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); @@ -477,7 +533,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // send it state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); this->rxDelayStart = mod->hal->millis(); - RADIOLIB_DEBUG_PRINTLN("Join-request sent <-- Rx Delay start"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Join-request sent <-- Rx Delay start"); RADIOLIB_ASSERT(state); // configure Rx delay for join-accept message - these are re-configured once a valid join-request is received @@ -494,7 +550,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // check received length size_t lenRx = this->phyLayer->getPacketLength(true); if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { - RADIOLIB_DEBUG_PRINTLN("joinAccept reply length mismatch, expected %luB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %luB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -508,7 +564,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // check reply message type if((joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK) != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { - RADIOLIB_DEBUG_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -520,13 +576,13 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); - RADIOLIB_DEBUG_PRINTLN("joinAcceptMsg:"); - RADIOLIB_DEBUG_HEXDUMP(joinAcceptMsg, lenRx); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAcceptMsg:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinAcceptMsg, lenRx); // get current JoinNonce from downlink and previous JoinNonce from persistent storage uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); - RADIOLIB_DEBUG_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); // JoinNonce received must be greater than the last JoinNonce heard, else error if((this->joinNonce > 0) && (joinNonceNew <= this->joinNonce)) { return(RADIOLIB_ERR_JOIN_NONCE_INVALID); @@ -539,7 +595,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // check LoRaWAN revision (the MIC verification depends on this) uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; - RADIOLIB_DEBUG_PRINTLN("LoRaWAN revision: 1.%d", this->rev); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN revision: 1.%d", this->rev); // verify MIC if(this->rev == 1) { @@ -554,7 +610,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; LoRaWANNode::hton(&micBuff[1], joinEUI); - LoRaWANNode::hton(&micBuff[9], this->devNonce); + LoRaWANNode::hton(&micBuff[9], devNonceUsed); memcpy(&micBuff[11], joinAcceptMsg, lenRx); if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { @@ -605,7 +661,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe if(this->rev == 1) { // 1.1 version, derive the keys LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], this->devNonce); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(appKey); @@ -636,7 +692,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } else { // 1.0 version, just derive the keys LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], this->devNonce); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); @@ -658,36 +714,32 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFcnt = 0; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - - // save join-request parameters - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); - - this->saveSession(); - - // everything written to NVM, write current table version to persistent storage and set mode - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_OTAA); -#endif + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_OTAA); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], checkSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3); + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; this->activeMode = RADIOLIB_LORAWAN_MODE_OTAA; + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force) { -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - // only needed for persistent storage - Module* mod = this->phyLayer->getMod(); +int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force, uint8_t initialDr) { + // if not forced and already joined, don't do anything + if(!force && this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginABP(): Did not rejoin: session already active"); + return(RADIOLIB_ERR_NONE); + } + + int16_t state = RADIOLIB_ERR_UNKNOWN; // check if we actually need to restart from a clean session uint16_t checkSum = 0; @@ -697,29 +749,17 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } - bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; - bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP; - - if(!force && validCheckSum && validMode) { - // the device has joined already, we can just pull the data from persistent storage - RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); - - return(this->restore()); - } else { - #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", validCheckSum, validMode); - RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); - uint8_t nvmBuff[16]; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); - RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); - RADIOLIB_DEBUG_PRINTLN("Wiping EEPROM and starting a clean session"); - #endif - - this->wipe(); + // if The Force is used, disable the active session; + // as a result, restore() will not restore the session (and there are no Nonces in ABP mode) + if(force) { + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + } + + state = this->restore(checkSum, RADIOLIB_LORAWAN_MODE_ABP, RADIOLIB_LORAWAN_CLASS_A, this->band->bandNum); + + if(!force) { + return(state); } -#else - (void)force; -#endif this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); @@ -734,8 +774,6 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); } - int16_t state = RADIOLIB_ERR_NONE; - // setup the uplink/downlink channels and initial datarate if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { this->setupChannelsDyn(); @@ -744,31 +782,34 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, } // setup all MAC properties to default values - this->beginCommon(); + this->beginCommon(initialDr); // set the physical layer configuration state = this->setPhyProperties(); RADIOLIB_ASSERT(state); -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - // save the activation keys checksum, device address & keys - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + // reset all frame counters + this->fcntUp = 0; + this->aFcntDown = 0; + this->nFcntDown = 0; + this->confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->adrFcnt = 0; - // save all new frame counters - this->saveSession(); - - // everything written to NVM, write current table version to persistent storage and set mode - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_ABP); -#endif + // save the activation keys checksum, mode, class, frequency plan + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_ABP); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], checkSum); + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; this->activeMode = RADIOLIB_LORAWAN_MODE_ABP; + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + return(RADIOLIB_ERR_NONE); } @@ -776,112 +817,40 @@ bool LoRaWANNode::isJoined() { return(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE); } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) int16_t LoRaWANNode::saveSession() { - Module* mod = this->phyLayer->getMod(); + // store DevAddr and all keys + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID) != this->rev) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev); + // copy the signature of the Nonces buffer over to the Session buffer + uint16_t noncesSignature = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], noncesSignature); + + // store network parameters + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); // store all frame counters - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID) != this->aFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); - - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID) != this->nFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); - - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID) != this->confFcntUp) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN], this->aFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN], this->nFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP], this->confFcntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN], this->confFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFcnt); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fcntUp); - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID) != this->confFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown); - - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID) != this->adrFcnt) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, this->adrFcnt); - - // fcntUp is saved using highly efficient wear-leveling as this is by far going to be written most often - this->saveFcntUp(); + // save the current uplink MAC command queue + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); - // if there is, or was, any MAC command in the queue, overwrite with the current MAC queue - uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - LoRaWANMacCommandQueue_t cmdTemp; - memcpy(&cmdTemp, queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - if(this->commandsUp.numCommands > 0 || cmdTemp.numCommands > 0) { - memcpy(queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - } + // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SIGNATURE], signature); return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::saveFcntUp() { - Module* mod = this->phyLayer->getMod(); - - uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); - uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID + 1); - uint8_t buffSize = fcntBuffEnd - fcntBuffStart; - #if RADIOLIB_STATIC_ONLY - uint8_t fcntBuff[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* fcntBuff = new uint8_t[buffSize]; - #endif - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID), fcntBuff, buffSize); - - // we discard the first two bits - your flash will likely be far dead by the time you reach 2^30 uplinks - // the first two bytes of the remaining 30 bytes are stored straight into storage without additional wear leveling - // because they hardly ever change - uint8_t bits_30_22 = (uint8_t)(this->fcntUp >> 22); - if(fcntBuff[0] != bits_30_22) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_30_22, 0); - uint8_t bits_22_14 = (uint8_t)(this->fcntUp >> 14); - if(fcntBuff[1] != bits_22_14) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_22_14, 1); - - // the next 7 bits are stored into one of few indices - // this index is indicated by the first byte that has its state (most significant bit) different from its predecessor - // if all have an equal state, restart from the beginning - // always flip the state bit of the byte that we write to, to indicate that this is the most recently written byte - uint8_t idx = 2; - uint8_t state = fcntBuff[idx] >> 7; - for(; idx < 5; idx++) { - if(fcntBuff[idx] >> 7 != state) { - break; - } - } - // check if the last written byte is equal to current, only rewrite if different - uint8_t bits_14_7 = (this->fcntUp >> 7) & 0x7F; - if((fcntBuff[idx - 1] & 0x7F) != bits_14_7) { - // find next index to write - idx = idx < 5 ? idx : 2; - - // flip the first bit of this byte to indicate that we just wrote here - bits_14_7 |= (~(fcntBuff[idx] >> 7)) << 7; - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_14_7, idx); - } - - // equally, the last 7 bits are stored into one of many indices - // this index is indicated by the first byte that has its state (most significant bit) different from its predecessor - // if all have an equal state, restart from the beginning - // always flip the state bit of the byte that we write to, to indicate that this is the most recently written byte - idx = 5; - state = fcntBuff[idx] >> 7; - for(; idx < buffSize; idx++) { - if(fcntBuff[idx] >> 7 != state) { - break; - } - } - idx = idx < buffSize ? idx : 5; - uint8_t bits_7_0 = (this->fcntUp >> 0) & 0x7F; - - // flip the first bit of this byte to indicate that we just wrote here - bits_7_0 |= (~(fcntBuff[idx] >> 7)) << 7; - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_7_0, idx); - - return(RADIOLIB_ERR_NONE); -} -#endif // RADIOLIB_EEPROM_UNSUPPORTED - #if defined(RADIOLIB_BUILD_ARDUINO) int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { return(this->uplink(str.c_str(), port, isConfirmed, event)); @@ -893,6 +862,11 @@ int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed, LoR } int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { + // if not joined, don't do anything + if(!this->isJoined()) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + Module* mod = this->phyLayer->getMod(); // check if the Rx windows were closed after sending the previous uplink @@ -920,7 +894,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf this->isMACPayload = false; } - int16_t state = RADIOLIB_ERR_NONE; + int16_t state = RADIOLIB_ERR_UNKNOWN; // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) uint8_t foptsLen = 0; @@ -934,13 +908,10 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check maximum payload len as defined in phy if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { return(RADIOLIB_ERR_PACKET_TOO_LONG); - // if testing with TS008 specification verification protocol, don't throw error but clip the message + // if testing with TS009 specification verification protocol, don't throw error but clip the message // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; } - // increase frame counter by one - this->fcntUp += 1; - bool adrAckReq = false; if(this->adrEnabled) { // check if we need to do ADR stuff @@ -959,7 +930,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // if the TxPower field has some offset, remove it and switch to maximum power if(this->txPowerCur > 0) { // set the maximum power supported by both the module and the band - state = this->setTxPower(this->txPowerMax, true); + state = this->setTxPower(this->txPowerMax); if(state == RADIOLIB_ERR_NONE) { this->txPowerCur = 0; adrStage = 0; // successfully did some ADR stuff @@ -973,7 +944,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf case(2): { // try to decrease the datarate if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > 0) { - if(this->setDatarate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] - 1, true) == RADIOLIB_ERR_NONE) { + if(this->setDatarate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] - 1) == RADIOLIB_ERR_NONE) { adrStage = 0; // successfully did some ADR stuff } } @@ -1008,7 +979,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // if dwell time is imposed, calculated expected time on air and cancel if exceeds if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen) - 16)/1000 > this->dwellTimeUp) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); + return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); } // build the uplink message @@ -1061,8 +1032,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf memcpy(foptsPtr, &cmd, 1 + cmd.len); foptsPtr += cmd.len + 1; } - RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); - RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(foptsBuff, foptsLen); // pop the commands from back to front for (; i >= 0; i--) { @@ -1109,8 +1080,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; - RADIOLIB_DEBUG_PRINTLN("uplinkMsg pre-MIC:"); - RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FcntUp = %d) decoded:", this->fcntUp); + + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(uplinkMsg, uplinkMsgLen); // calculate authentication codes memcpy(uplinkMsg, block1, RADIOLIB_AES128_BLOCK_SIZE); @@ -1126,9 +1098,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); } - RADIOLIB_DEBUG_PRINTLN("uplinkMsg:"); - RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); - // perform CSMA if enabled. if (enableCSMA) { performCSMA(); @@ -1139,7 +1108,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // set the timestamp so that we can measure when to start receiving this->rxDelayStart = mod->hal->millis(); - RADIOLIB_DEBUG_PRINTLN("Uplink sent <-- Rx Delay start"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); // calculate Time on Air of this uplink in milliseconds this->lastToA = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; @@ -1164,6 +1133,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf event->port = port; } + // increase frame counter by one for the next uplink + this->fcntUp += 1; + return(RADIOLIB_ERR_NONE); } @@ -1220,11 +1192,11 @@ int16_t LoRaWANNode::downlinkCommon() { // open Rx window by starting receive with specified timeout state = this->phyLayer->startReceive(timeoutMod, irqFlags, irqMask, 0); - RADIOLIB_DEBUG_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, timeoutHost); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, timeoutHost); // wait for the timeout to complete (and a small additional delay) mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); - RADIOLIB_DEBUG_PRINTLN("closing"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", i+1); // check if the IRQ bit for Rx Timeout is set if(!this->phyLayer->isRxTimeout()) { @@ -1233,6 +1205,7 @@ int16_t LoRaWANNode::downlinkCommon() { } else if(i == 0) { // nothing in the first window, configure for the second this->phyLayer->standby(); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", 'D', this->rx2.freq); state = this->phyLayer->setFrequency(this->rx2.freq); RADIOLIB_ASSERT(state); @@ -1274,7 +1247,7 @@ int16_t LoRaWANNode::downlinkCommon() { #if defined(RADIOLIB_BUILD_ARDUINO) int16_t LoRaWANNode::downlink(String& str, LoRaWANEvent_t* event) { - int16_t state = RADIOLIB_ERR_NONE; + int16_t state = RADIOLIB_ERR_UNKNOWN; // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL @@ -1295,6 +1268,20 @@ int16_t LoRaWANNode::downlink(String& str, LoRaWANEvent_t* event) { } #endif +int16_t LoRaWANNode::downlink(LoRaWANEvent_t* event) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // build a temporary buffer + // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL + size_t length = 0; + uint8_t data[251]; + + // wait for downlink + state = this->downlink(data, &length, event); + + return(state); +} + int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) { // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received int16_t state = downlinkCommon(); @@ -1302,12 +1289,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // get the packet length size_t downlinkMsgLen = this->phyLayer->getPacketLength(); - RADIOLIB_DEBUG_PRINTLN("Downlink message length: %d", downlinkMsgLen); // check the minimum required frame length // an extra byte is subtracted because downlink frames may not have a port if(downlinkMsgLen < RADIOLIB_LORAWAN_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { - RADIOLIB_DEBUG_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -1352,15 +1338,10 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp); } - RADIOLIB_DEBUG_PRINTLN("downlinkMsg:"); - RADIOLIB_DEBUG_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); - // calculate length of FOpts and payload uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); - RADIOLIB_DEBUG_PRINTLN("FOpts: %02X", downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS]); - // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload // i.e., no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) // TODO "NFCntDown is used for MAC communication on port 0 and when the FPort field is missing" @@ -1377,7 +1358,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) isAppDownlink = false; } } - RADIOLIB_DEBUG_PRINTLN("FOptsLen: %d", foptsLen); + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFcntDown = %d) encoded:", isAppDownlink ? "A" : "N", fcnt16); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); // check the FcntDown value (Network or Application) uint32_t fcntDownPrev = 0; @@ -1387,8 +1370,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) fcntDownPrev = this->nFcntDown; } - RADIOLIB_DEBUG_PRINTLN("fcnt: %d, fcntPrev: %d, isAppDownlink: %d", fcnt16, fcntDownPrev, (int)isAppDownlink); - // if this is not the first downlink... // assume a 16-bit to 32-bit rollover if difference between counters in LSB is smaller than MAX_FCNT_GAP // if that isn't the case and the received fcnt is smaller or equal to the last heard fcnt, then error @@ -1434,7 +1415,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // check the address uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); if(addr != this->devAddr) { - RADIOLIB_DEBUG_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -1460,9 +1441,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); } - RADIOLIB_DEBUG_PRINTLN("fopts:"); - RADIOLIB_DEBUG_HEXDUMP(fopts, foptsLen); - bool hasADR = false; uint8_t numADR = 0; uint8_t lastCID = 0; @@ -1476,7 +1454,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { // if there was an earlier ADR command but it was not the last, ignore it if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { - RADIOLIB_DEBUG_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); remLen -= (macLen + 1); foptsPtr += (macLen + 1); lastCID = cid; @@ -1495,8 +1473,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), }; memcpy(cmd.payload, foptsPtr + 1, macLen); - RADIOLIB_DEBUG_PRINTLN("[%02X]: %02X %02X %02X %02X %02X (%d)", - cmd.cid, cmd.payload[0], cmd.payload[1], cmd.payload[2], cmd.payload[3], cmd.payload[4], cmd.len); // process the MAC command bool sendUp = execMacCommand(&cmd); @@ -1508,18 +1484,12 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) remLen -= (macLen + 1); foptsPtr += (macLen + 1); lastCID = cid; - RADIOLIB_DEBUG_PRINTLN("Processed: %d, remaining: %d", (macLen + 1), remLen); } #if !RADIOLIB_STATIC_ONLY delete[] fopts; #endif - RADIOLIB_DEBUG_PRINTLN("MAC response:"); - for (int i = 0; i < this->commandsUp.numCommands; i++) { - RADIOLIB_DEBUG_HEXDUMP(&(this->commandsUp.commands[i].cid), sizeof(LoRaWANMacCommand_t)); - } - // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(this->commandsUp.len > 15) { size_t foptsBufSize = this->commandsUp.len; @@ -1536,8 +1506,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) memcpy(foptsPtr, &cmd, 1 + cmd.len); foptsPtr += cmd.len + 1; } - RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); - RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsBufSize); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(foptsBuff, foptsBufSize); // pop the commands from back to front for (; i >= 0; i--) { @@ -1552,9 +1522,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // temporarily lift dutyCycle restrictions to allow immediate MAC response bool prevDC = this->dutyCycleEnabled; this->dutyCycleEnabled = false; - RADIOLIB_DEBUG_PRINTLN("Sending MAC-only uplink .. "); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Sending MAC-only uplink .. "); state = this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); - RADIOLIB_DEBUG_PRINTLN(" .. state: %d", state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); this->dutyCycleEnabled = prevDC; #if !RADIOLIB_STATIC_ONLY @@ -1567,9 +1537,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; #endif size_t lenDown = 0; - RADIOLIB_DEBUG_PRINTLN("Receiving after MAC-only uplink .. "); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Receiving after MAC-only uplink .. "); state = this->downlink(strDown, &lenDown); - RADIOLIB_DEBUG_PRINTLN(" .. state: %d", state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); #if !RADIOLIB_STATIC_ONLY delete[] strDown; #endif @@ -1578,8 +1548,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } - // a downlink was received, so reset the ADR counter to this uplink's fcnt - this->adrFcnt = this->fcntUp; + // a downlink was received, so reset the ADR counter to the last uplink's fcnt + this->adrFcnt = this->fcntUp - 1; // pass the extra info if requested if(event) { @@ -1590,7 +1560,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->freq = currentChannels[event->dir].freq; event->power = this->txPowerMax - this->txPowerCur * 2; event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown; - event->port = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)]; + event->port = isAppDownlink ? downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] : RADIOLIB_LORAWAN_FPORT_MAC_COMMAND; } // process Application payload (if there is any) @@ -1604,8 +1574,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) return(RADIOLIB_ERR_NONE); } - // there is payload, and so there should be a port too - // TODO pass the port? *len = payLen - 1; // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16 @@ -1630,6 +1598,16 @@ int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, b } #endif +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + // send the uplink + int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed, eventUp); + RADIOLIB_ASSERT(state); + + // wait for the downlink + state = this->downlink(eventDown); + return(state); +} + int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // send the uplink int16_t state = this->uplink(strUp, port, isConfirmed, eventUp); @@ -1654,8 +1632,12 @@ void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { this->battLevel = battLevel; } +// return Fcnt of last uplink; also return 0 if no uplink occured yet uint32_t LoRaWANNode::getFcntUp() { - return(this->fcntUp); + if(this->fcntUp == 0) { + return(0); + } + return(this->fcntUp - 1); } uint32_t LoRaWANNode::getNFcntDown() { @@ -1693,7 +1675,7 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { // calculate the expected value and compare uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); if(micCalculated != micReceived) { - RADIOLIB_DEBUG_PRINTLN("MIC mismatch, expected %08x, got %08x", micCalculated, micReceived); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MIC mismatch, expected %08x, got %08x", micCalculated, micReceived); return(false); } @@ -1735,14 +1717,13 @@ int16_t LoRaWANNode::setPhyProperties() { } int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { - RADIOLIB_DEBUG_PRINTLN("Setting up dynamic channels"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up dynamic channels"); size_t num = 0; // copy the default defined channels into the first slots (where Tx = Rx) for(; num < 3 && this->band->txFreqs[num].enabled; num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } // if we're about to send a join-request, copy the join-request channels to the next slots @@ -1751,7 +1732,6 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } } @@ -1759,6 +1739,24 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; } + + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } + } return(RADIOLIB_ERR_NONE); } @@ -1766,15 +1764,11 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { // setup a subband and its corresponding join-request datarate // WARNING: subBand starts at 1 (corresponds to all populair schemes) int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { - RADIOLIB_DEBUG_PRINTLN("Setting up fixed channels"); - // randomly select one of 8 or 9 channels and find corresponding datarate - uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; - uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 - uint8_t drJR = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; - if(rand <= 8) { - drJR = this->band->txSpans[0].joinRequestDataRate; // if one of the first 8 channels, select datarate of span 0 - } else { - drJR = this->band->txSpans[1].joinRequestDataRate; // if ninth channel, select datarate of span 1 + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up fixed channels (subband %d)", subBand); + + // clear all existing channels + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } // if no subband is selected by user, cycle through banks of 8 using devNonce value @@ -1782,55 +1776,33 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { uint8_t numBanks8 = this->band->txSpans[0].numChannels / 8; subBand = this->devNonce % numBanks8; } + + uint8_t chMaskCntl = 0; + uint16_t chMask = 0; - // chMask is set for 16 channels at once, so widen the Cntl value - uint8_t chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset - - uint8_t numADR = 1; - - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, - .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, - .repeat = 0, - }; - // if there are two channel spans, first set the channel from second span if(this->band->numTxSpans == 2) { - cmd.payload[0] = (drJR << 4); // set join-request datarate - cmd.payload[0] |= 0; // set Tx power to maximum - // enable channel that belongs to this subband - cmd.payload[1] = (1 << (subBand - 1)); // set channel mask - cmd.payload[2] = 0; - cmd.payload[3] = (7 << 4); // set the chMaskCntl value to all channels off - cmd.payload[3] |= 0; // keep NbTrans the same - cmd.repeat = numADR++; - (void)execMacCommand(&cmd, false); + chMaskCntl = 7; + chMask = (1 << (subBand - 1)); // set channel mask + this->applyChannelMaskFix(chMaskCntl, chMask); } - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - cmd.payload[0] = (drJR << 4); // set join-request datarate - cmd.payload[0] |= 0; // set Tx power to maximum + // chMask is set for 16 channels at once, so widen the Cntl value + chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset + // now select the correct bank of 8 channels - // 0x00 0xFF channel mask for subband = 2, 4.. (even) - // 0xFF 0x00 channel mask for subband = 1, 3.. (odd) - if(subBand % 2 == 0) { - cmd.payload[1] = 0x00; - cmd.payload[2] = 0xFF; + if(subBand % 2 == 0) { // even subbands + chMask = 0xFF00; } else { - cmd.payload[1] = 0xFF; - cmd.payload[2] = 0x00; + chMask = 0x00FF; // odd subbands } - cmd.payload[3] = (chMaskCntl << 4); // set the chMaskCntl value - cmd.payload[3] |= 0; // keep NbTrans the same - cmd.repeat = numADR++; - (void)execMacCommand(&cmd, false); + this->applyChannelMaskFix(chMaskCntl, chMask); return(RADIOLIB_ERR_NONE); } int16_t LoRaWANNode::processCFList(uint8_t* cfList) { - RADIOLIB_DEBUG_PRINTLN("Processing CFList"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // retrieve number of existing (default) channels @@ -1868,18 +1840,17 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { .len = 0, .repeat = 0, }; - cmd.payload[0] = 0xFF; // same datarate and payload // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels - size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span + size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - cmd.payload[3] = chMaskCntl << 4; // NbTrans = 0 -> keep the same + cmd.payload[0] = 0xFF; // same datarate and payload + memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); // copy mask + cmd.payload[3] = chMaskCntl << 4; // set chMaskCntl, set NbTrans = 0 -> keep the same cmd.repeat = (chMaskCntl + 1); - memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); (void)execMacCommand(&cmd); } - // delete the ADR response } return(RADIOLIB_ERR_NONE); @@ -1899,7 +1870,7 @@ int16_t LoRaWANNode::selectChannels() { } } if(numChannels == 0) { - RADIOLIB_DEBUG_PRINTLN("There are no channels defined - are you in ABP mode with no defined subband?"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("There are no channels defined - are you in ABP mode with no defined subband?"); return(RADIOLIB_ERR_INVALID_CHANNEL); } // select a random ID & channel from the list of enabled and possible channels @@ -1928,7 +1899,7 @@ int16_t LoRaWANNode::selectChannels() { return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { +int16_t LoRaWANNode::setDatarate(uint8_t drUp) { // scan through all enabled channels and check if the requested datarate is available bool isValidDR = false; for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { @@ -1941,7 +1912,7 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { } } if(!isValidDR) { - RADIOLIB_DEBUG_PRINTLN("No defined channel allows datarate %d", drUp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No defined channel allows datarate %d", drUp); return(RADIOLIB_ERR_INVALID_DATA_RATE); } @@ -1955,7 +1926,7 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { cmd.payload[0] |= 0x0F; // keep Tx Power the same cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored cmd.payload[3] |= 0; // keep NbTrans the same - (void)execMacCommand(&cmd, saveToEeprom); + (void)execMacCommand(&cmd); // check if ACK is set for Tx Power if((cmd.payload[0] >> 1) != 1) { @@ -2028,7 +1999,7 @@ uint8_t LoRaWANNode::maxPayloadDwellTime() { return(payLen - 13); // fixed 13-byte header } -int16_t LoRaWANNode::setTxPower(int8_t txPower, bool saveToEeprom) { +int16_t LoRaWANNode::setTxPower(int8_t txPower) { // only allow values within the band's (or MAC state) maximum if(txPower > this->txPowerMax) { return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); @@ -2048,7 +2019,7 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower, bool saveToEeprom) { cmd.payload[0] |= numSteps; // set the Tx Power cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored cmd.payload[3] |= 0; // keep NbTrans the same - (void)execMacCommand(&cmd, saveToEeprom); + (void)execMacCommand(&cmd); // check if ACK is set for Tx Power if((cmd.payload[0] >> 2) != 1) { @@ -2083,8 +2054,8 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; - RADIOLIB_DEBUG_PRINTLN("DR %d: LORA (SF: %d, BW: %f, CR: %d)", - dataRateBand, dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: SF = %d, BW = %6.3f kHz, CR = 4/%d", + dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); } return(RADIOLIB_ERR_NONE); @@ -2092,8 +2063,8 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { int16_t LoRaWANNode::configureChannel(uint8_t dir) { // set the frequency - RADIOLIB_DEBUG_PRINTLN(""); - RADIOLIB_DEBUG_PRINTLN("Channel frequency %cL = %f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); int state = this->phyLayer->setFrequency(this->currentChannels[dir].freq); RADIOLIB_ASSERT(state); @@ -2150,11 +2121,7 @@ int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQ return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t payload[5]) { - if(queue->numCommands == 0) { - return(RADIOLIB_ERR_COMMAND_QUEUE_EMPTY); - } - +int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload) { for(size_t index = 0; index < queue->numCommands; index++) { if(queue->commands[index].cid == cid) { // if a pointer to a payload is supplied, copy the command's payload over @@ -2176,14 +2143,9 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que return(RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND); } -bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { - RADIOLIB_DEBUG_PRINTLN("exe MAC CID = %02x, len = %d", cmd->cid, cmd->len); - - Module* mod = this->phyLayer->getMod(); -#if defined(RADIOLIB_EEPROM_UNSUPPORTED) - (void)saveToEeprom; - (void)mod; -#endif +bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[MAC] 0x%02X", cmd->cid); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(cmd->payload, cmd->len); if(cmd->cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { // TODO call user-provided callback for proprietary MAC commands? @@ -2194,7 +2156,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_RESET): { // get the server version uint8_t srvVersion = cmd->payload[0]; - RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ResetConf: server version 1.%d", srvVersion); if(srvVersion == this->rev) { // valid server version, stop sending the ResetInd MAC command deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->commandsUp); @@ -2203,6 +2165,11 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } break; case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkCheckAns: [user]"); + // delete any existing response (does nothing if there is none) + deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_CHECK, &this->commandsDown); + + // insert response into MAC downlink queue pushMacCommand(cmd, &this->commandsDown); return(false); } break; @@ -2214,10 +2181,12 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // but we don't bother and try to set each individual command uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; uint8_t txPower = cmd->payload[0] & 0x0F; + bool isInternalTxDr = cmd->payload[3] >> 7; + uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4; uint8_t nbTrans = cmd->payload[3] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("ADR REQ: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %02x, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans); // apply the configuration uint8_t drAck = 0; @@ -2240,7 +2209,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; drAck = 1; } else { - RADIOLIB_DEBUG_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); } } @@ -2255,6 +2224,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } else { int8_t pwr = this->txPowerMax - 2*txPower; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: TX = %d dBm", pwr); state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { // go from the highest power and lower it until we hit one supported by the module @@ -2270,23 +2240,26 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint8_t chMaskAck = 1; // only apply channel mask when the RFU bit is not set - // (which is set on the internal MAC command when creating new session) - if((cmd->payload[3] >> 7) == 0) { + // (which is only set in internal MAC commands for changing Tx/Dr) + if(!isInternalTxDr) { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); } else { // RADIOLIB_LORAWAN_BAND_FIXED - bool clearChannels = false; if(cmd->repeat == 1) { // if this is the first ADR command in the queue, clear all saved channels // so we can apply the new channel mask - clearChannels = true; - RADIOLIB_DEBUG_PRINTLN("ADR mask: clearing channels"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR mask: clearing channels"); + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } + // clear all previous channel masks + memset(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS], 0, 16*8); } else { // if this is not the first ADR command, clear the ADR response that was in the queue (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); } - chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask, clearChannels); + chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask); } } @@ -2297,72 +2270,58 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->nbTrans = nbTrans; } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte - if((cmd->payload[3] >> 7) == 1) { - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID) + 1, &(cmd->payload[1]), 3); + if(isInternalTxDr) { + memcpy(&(cmd->payload[1]), &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, 3); } + // if there was no channel mask (all zeroes), we should never apply that channel mask, so set RFU bit again if(cmd->payload[1] == 0 && cmd->payload[2] == 0) { cmd->payload[3] |= (1 << 7); } // save to the single ADR MAC location - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], &(cmd->payload[0]), cmd->len); } else { // RADIOLIB_LORAWAN_BAND_FIXED - RADIOLIB_DEBUG_PRINTLN("[1] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X", - cmd->repeat, (cmd->payload[3] >> 7), - cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); - // if RFU bit is set, this is just a change in Datarate or TxPower - // so read bytes 1..3 from last stored ADR command into the current MAC payload and re-store it - if((cmd->payload[3] >> 7) == 1) { - // read how many ADR masks are already stored - uint8_t numMacADR = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); - if(numMacADR > 0) { - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen + 1, &(cmd->payload[1]), 3); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen, &(cmd->payload[0]), payLen); - } + + // save Tx/Dr to the Link ADR position in the session buffer + uint8_t bufTxDr[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + bufTxDr[0] = cmd->payload[0]; + bufTxDr[3] = 1 << 7; + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], bufTxDr, cmd->len); - } else { - // save to the uplink channel location, to the cmd->repeat-th slot of 4 bytes - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (cmd->repeat - 1) * payLen, &(cmd->payload[0]), payLen); - // saved an ADR mask, so re-store counter - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, cmd->repeat); + // if RFU bit is set, this is just a change in Datarate or TxPower, in which case we don't save the channel masks + // if the RFU bit is not set, we must save this channel mask + if(!isInternalTxDr) { + // save the channel mask to the uplink channels position in session buffer, with Tx and DR set to 'same' + cmd->payload[0] = 0xFF; + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->payload, cmd->len); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Saving mask to ULChannels[%d]:", (cmd->repeat - 1) * cmd->len); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->len); } - RADIOLIB_DEBUG_PRINTLN("[2] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X", - cmd->repeat, (cmd->payload[3] >> 7), - cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); + } - } -#endif // send the reply cmd->len = 1; cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); cmd->repeat = 0; // discard any repeat value that may have been set - RADIOLIB_DEBUG_PRINTLN("ADR ANS: status = 0x%02x", cmd->payload[0]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRAns: status = 0x%02x", cmd->payload[0]); return(true); } break; case(RADIOLIB_LORAWAN_MAC_DUTY_CYCLE): { uint8_t maxDutyCycle = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("Max duty cycle: 1/2^%d", maxDutyCycle); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DutyCycleReq: max duty cycle = 1/2^%d", maxDutyCycle); if(maxDutyCycle == 0) { this->dutyCycle = this->band->dutyCycle; } else { this->dutyCycle = (uint32_t)60 * (uint32_t)60 * (uint32_t)1000 / (uint32_t)(1UL << maxDutyCycle); } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd->payload, cmd->len); cmd->len = 0; return(true); @@ -2376,7 +2335,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint8_t rx2Ack = 1; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); this->rx2.freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PRINTLN("Rx param REQ: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", this->rx1DrOffset, this->rx2.drMax, this->rx2.freq); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupReq: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", this->rx1DrOffset, this->rx2.drMax, this->rx2.freq); // apply the configuration uint8_t chanAck = 0; @@ -2385,29 +2344,24 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID), &(cmd->payload[0]), payLen); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd->payload, cmd->len); // TODO this should be sent repeatedly until the next downlink cmd->len = 1; cmd->payload[0] = (rx1OffsAck << 2) | (rx2Ack << 1) | (chanAck << 0); - RADIOLIB_DEBUG_PRINTLN("Rx param ANS: status = 0x%02x", cmd->payload[0]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupAns: status = 0x%02x", cmd->payload[0]); return(true); } break; case(RADIOLIB_LORAWAN_MAC_DEV_STATUS): { // set the uplink reply + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusReq"); cmd->len = 2; cmd->payload[1] = this->battLevel; int8_t snr = this->phyLayer->getSNR(); cmd->payload[0] = snr & 0x3F; - RADIOLIB_DEBUG_PRINTLN("DevStatus ANS: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusAns: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); return(true); } break; @@ -2418,7 +2372,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { float freq = (float)freqRaw/10000.0; uint8_t maxDr = (cmd->payload[4] & 0xF0) >> 4; uint8_t minDr = cmd->payload[4] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("New channel: index = %d, freq = %f MHz, maxDr = %d, minDr = %d", chIndex, freq, maxDr, minDr); + uint8_t newChAck = 0; uint8_t freqAck = 0; @@ -2438,7 +2392,8 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelReq:"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, @@ -2452,20 +2407,12 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMax ); -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - // save to uplink channels location, to the chIndex-th slot of 5 bytes - uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - RADIOLIB_DEBUG_PRINTLN("Saving channel:"); - RADIOLIB_DEBUG_HEXDUMP(&(cmd->payload[0]), payLen); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + chIndex * payLen, &(cmd->payload[0]), payLen); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); // send the reply cmd->len = 1; cmd->payload[0] = (newChAck << 1) | (freqAck << 0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelAns: status = 0x%02x", cmd->payload[0]); return(true); } break; @@ -2475,7 +2422,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); float freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PRINTLN("DL channel: index = %d, freq = %f MHz", chIndex, freq); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %f MHz", chIndex, freq); uint8_t freqDlAck = 0; uint8_t freqUlAck = 0; @@ -2496,18 +2443,12 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - // save to downlink channels location, to the chIndex-th slot of 4 bytes - uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID) + chIndex * payLen, &(cmd->payload[0]), payLen); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); // TODO send this repeatedly until a downlink is received cmd->len = 1; cmd->payload[0] = (freqUlAck << 1) | (freqDlAck << 0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelAns: status = 0x%02x", cmd->payload[0]); return(true); } break; @@ -2515,7 +2456,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP): { // get the configuration uint8_t delay = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("RX timing: delay = %d sec", delay); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXTimingSetupReq: delay = %d sec", delay); // apply the configuration if(delay == 0) { @@ -2524,12 +2465,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->rxDelays[0] = delay * 1000; this->rxDelays[1] = this->rxDelays[0] + 1000; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd->payload, cmd->len); // send the reply cmd->len = 0; @@ -2546,7 +2482,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // who the f came up with this ... const uint8_t eirpEncoding[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; this->txPowerMax = eirpEncoding[maxEirpRaw]; - RADIOLIB_DEBUG_PRINTLN("TX timing: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, this->txPowerMax); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TxParamSetupReq: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, eirpEncoding[maxEirpRaw]); this->dwellTimeEnabledUp = ulDwell ? true : false; this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; @@ -2554,12 +2490,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->dwellTimeEnabledDn = dlDwell ? true : false; this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; return(true); @@ -2568,7 +2499,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_REKEY): { // get the server version uint8_t srvVersion = cmd->payload[0]; - RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RekeyConf: server version = 1.%d", srvVersion); if((srvVersion > 0) && (srvVersion <= this->rev)) { // valid server version, stop sending the ReKey MAC command deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, &this->commandsUp); @@ -2579,32 +2510,32 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP): { this->adrLimitExp = (cmd->payload[0] & 0xF0) >> 4; this->adrDelayExp = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("ADR param setup: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADRParamSetupReq: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; return(true); } break; case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DeviceTimeAns: [user]"); + // delete any existing response (does nothing if there is none) + deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown); + + // insert response into MAC downlink queue pushMacCommand(cmd, &this->commandsDown); return(false); } break; case(RADIOLIB_LORAWAN_MAC_FORCE_REJOIN): { // TODO implement this - uint16_t rejoinReq = LoRaWANNode::ntoh(&cmd->payload[0]); + uint16_t rejoinReq = LoRaWANNode::ntoh(cmd->payload); uint8_t period = (rejoinReq & 0x3800) >> 11; uint8_t maxRetries = (rejoinReq & 0x0700) >> 8; uint8_t rejoinType = (rejoinReq & 0x0070) >> 4; uint8_t dr = rejoinReq & 0x000F; - RADIOLIB_DEBUG_PRINTLN("Force rejoin: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ForceRejoinReq: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); (void)period; (void)maxRetries; (void)rejoinType; @@ -2616,17 +2547,13 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // TODO implement this uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; uint8_t maxCount = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("Rejoin setup: maxTime = %d, maxCount = %d", maxTime, maxCount); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupReq: maxTime = %d, maxCount = %d", maxTime, maxCount); -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; cmd->payload[0] = (1 << 1) | 1; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupAns: status = 0x%02x", cmd->payload[0]); (void)maxTime; (void)maxCount; @@ -2641,7 +2568,6 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { if(chMaskCntl == 0) { // apply the mask by looking at each channel bit - RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01); if(chMask & (1UL << i)) { // if it should be enabled but is not currently defined, stop immediately if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { @@ -2662,31 +2588,29 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } } return(true); } -bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool clear) { - RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); - if(clear) { - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; - } - } +bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); + // find out how many channels have already been configured uint8_t idx = 0; for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { @@ -2702,14 +2626,13 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool uint16_t mask = 1 << i; if(mask & chMask) { uint8_t chNum = chMaskCntl * 16 + i; // 0 through 63 or 95 - this->subBand = chNum % 8; // keep track of configured subband in case we must reset the channels + this->subBand = chNum / 8 + 1; // save configured subband in case we must reset the channels (1-based) chnl.enabled = true; chnl.idx = chNum; chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2732,7 +2655,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx-1, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2744,7 +2666,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool uint16_t mask = 1 << i; if(mask & chMask) { // enable bank of 8 channels from first span - for(uint8_t j = 0; j < 8; i++) { + for(uint8_t j = 0; j < 8; j++) { uint8_t chNum = i * 8 + j; chnl.enabled = true; chnl.idx = chNum; @@ -2752,7 +2674,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } // enable single channel from second span uint8_t chNum = 64 + i; @@ -2762,16 +2683,14 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } } if(this->band->numTxSpans == 2 && chMaskCntl == 6) { // all channels on (but we revert to selected subband) - if(this->subBand >= 0) { - this->setupChannelsFix(this->subBand); - } + this->setupChannelsFix(this->subBand); + // a '1' enables a single channel from second span LoRaWANChannel_t chnl; for(uint8_t i = 0; i < 8; i++) { @@ -2785,7 +2704,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2810,26 +2728,27 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } } return(true); @@ -2852,7 +2771,7 @@ int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { if(margin) { *margin = payload[0]; } if(gwCnt) { *gwCnt = payload[1]; } - // RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt); + return(RADIOLIB_ERR_NONE); } @@ -2864,12 +2783,12 @@ int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, if(gpsEpoch) { *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); if(returnUnix) { - uint32_t unixOffset = 315964800; + uint32_t unixOffset = 315964800 - 18; // 18 leap seconds since GPS epoch (Jan. 6th 1980) *gpsEpoch += unixOffset; } } if(fraction) { *fraction = payload[4]; } - // RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)(*fraction)/256.0f); + return(RADIOLIB_ERR_NONE); } @@ -2891,7 +2810,7 @@ void LoRaWANNode::performCSMA() { bool channelFreeDuringDIFS = true; for (uint8_t i = 0; i < this->difsSlots; i++) { if (performCAD()) { - RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING DIFS"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Occupied channel during DIFS"); channelFreeDuringDIFS = false; // Channel is occupied during DIFS, hop to another. this->selectChannels(); @@ -2903,7 +2822,7 @@ void LoRaWANNode::performCSMA() { // Continue decrementing BO with per each CAD reporting free channel. while (BO > 0) { if (performCAD()) { - RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING BO"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Occupied channel during BO"); // Channel is busy during CAD, hop to another and return to DIFS state again. this->selectChannels(); break; // Exit loop. Go back to DIFS state. @@ -2962,16 +2881,14 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out } } -uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint8_t keyLen) { - if(keyLen > RADIOLIB_AES128_KEY_SIZE / 2) { - keyLen = RADIOLIB_AES128_KEY_SIZE / 2; - } - uint16_t buf16[RADIOLIB_AES128_KEY_SIZE / 2] = { 0 }; - uint8_t bufLen = keyLen / 2; - memcpy(buf16, key, keyLen); +uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint16_t keyLen) { uint16_t checkSum = 0; - for(int i = 0; i < bufLen; i++) { - checkSum ^= buf16[i]; + for(uint16_t i = 0; i < keyLen; i += 2) { + checkSum ^= ((uint16_t)key[i] << 8) | key[i + 1]; + } + if(keyLen % 2 == 1) { + uint16_t val = ((uint16_t)key[keyLen - 1] << 8); + checkSum ^= val; } return(checkSum); } diff --git a/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.h b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.h index 157945a0c..0aab1fa7a 100644 --- a/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.h +++ b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.h @@ -6,14 +6,14 @@ #include "../../utils/Cryptography.h" // activation mode -#define RADIOLIB_LORAWAN_MODE_OTAA (0x01AA) +#define RADIOLIB_LORAWAN_MODE_OTAA (0x07AA) #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) +#define RADIOLIB_LORAWAN_CLASS_A (0x0A) +#define RADIOLIB_LORAWAN_CLASS_B (0x0B) +#define RADIOLIB_LORAWAN_CLASS_C (0x0C) // preamble format #define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) @@ -179,6 +179,12 @@ #define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) #define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) +// maximum allowed dwell time on bands that implement dwell time limitations +#define RADIOLIB_LORAWAN_DWELL_TIME (400) + +// unused LoRaWAN version +#define RADIOLIB_LORAWAN_VERSION_NONE (0xFF) + // unused frame counter value #define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) @@ -188,10 +194,7 @@ // the maximum number of simultaneously available channels #define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) -// maximum allowed dwell time on bands that implement dwell time limitations -#define RADIOLIB_LORAWAN_DWELL_TIME (400) - -// Maximum MAC command sizes +// maximum MAC command sizes #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5) #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) #define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) @@ -223,6 +226,56 @@ const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true } }; +#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001) + +enum LoRaWANSchemeBase_t { + RADIOLIB_LORAWAN_NONCES_VERSION = 0x00, // 2 bytes + RADIOLIB_LORAWAN_NONCES_MODE = 0x02, // 2 bytes + RADIOLIB_LORAWAN_NONCES_CLASS = 0x04, // 1 byte + RADIOLIB_LORAWAN_NONCES_PLAN = 0x05, // 1 byte + RADIOLIB_LORAWAN_NONCES_CHECKSUM = 0x06, // 2 bytes + RADIOLIB_LORAWAN_NONCES_DEV_NONCE = 0x08, // 2 bytes + RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = 0x0A, // 3 bytes + RADIOLIB_LORAWAN_NONCES_ACTIVE = 0x0D, // 1 byte + RADIOLIB_LORAWAN_NONCES_SIGNATURE = 0x0E, // 2 bytes + RADIOLIB_LORAWAN_NONCES_BUF_SIZE = 0x10 // = 16 bytes +}; + +enum LoRaWANSchemeSession_t { + RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = 0x00, // 16 bytes + RADIOLIB_LORAWAN_SESSION_APP_SKEY = 0x10, // 16 bytes + RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = 0x20, // 16 bytes + RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = 0x30, // 16 bytes + RADIOLIB_LORAWAN_SESSION_DEV_ADDR = 0x40, // 4 bytes + RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = 0x44, // 2 bytes + RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = 0x46, // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = 0x4A, // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = 0x4E, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = 0x52, // 2 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = 0x54, // 2 bytes + RADIOLIB_LORAWAN_SESSION_HOMENET_ID = 0x56, // 4 bytes + RADIOLIB_LORAWAN_SESSION_VERSION = 0x5A, // 1 byte + RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = 0x5B, // 1 byte + RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = 0x5C, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = 0x60, // 1 byte + RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = 0x61, // 1 byte + RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = 0x62, // 1 byte + RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = 0x63, // 1 byte + RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = 0x64, // 3 bytes + RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = 0x67, // 4 bytes + RADIOLIB_LORAWAN_SESSION_PERIODICITY = 0x6B, // 1 byte + RADIOLIB_LORAWAN_SESSION_LAST_TIME = 0x6C, // 4 bytes + RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = 0x70, // 16*8 bytes + RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = 0xF0, // 16*4 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = 0x0130, // 9*8+2 bytes + RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = 0x017A, // 4 bytes + RADIOLIB_LORAWAN_SESSION_ADR_FCNT = 0x017E, // 4 bytes + RADIOLIB_LORAWAN_SESSION_LINK_ADR = 0x0182, // 4 bytes + RADIOLIB_LORAWAN_SESSION_FCNT_UP = 0x0186, // 4 bytes + RADIOLIB_LORAWAN_SESSION_SIGNATURE = 0x018A, // 2 bytes + RADIOLIB_LORAWAN_SESSION_BUF_SIZE = 0x018C // 396 bytes +}; + /*! \struct LoRaWANChannelSpan_t \brief Structure to save information about LoRaWAN channels. @@ -281,6 +334,9 @@ struct LoRaWANChannelSpan_t { \brief Structure to save information about LoRaWAN band */ struct LoRaWANBand_t { + /*! \brief Identier for this band */ + uint8_t bandNum; + /*! \brief Whether the channels are fixed per specification, or dynamically allocated through the network (plus defaults) */ uint8_t bandType; @@ -412,7 +468,6 @@ class LoRaWANNode { */ LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand = 0); -#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. @@ -420,12 +475,36 @@ class LoRaWANNode { void wipe(); /*! - \brief Restore session by loading information from persistent storage. - \returns \ref status_codes in case of error, - else LoRaWAN session mode (0 = no active session, 0xAA / 170 = OTAA, 0xAB / 171 = ABP) + \brief Returns the pointer to the internal buffer that holds the LW base parameters + \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_NONCES_BUF_SIZE */ - int16_t restore(); -#endif + uint8_t* getBufferNonces(); + + /*! + \brief Fill the internal buffer that holds the LW base parameters with a supplied buffer + \param persistentBuffer Buffer that should match the internal format (previously extracted using getBufferNonces) + \returns \ref status_codes + */ + int16_t setBufferNonces(uint8_t* persistentBuffer); + + /*! + \brief Returns the pointer to the internal buffer that holds the LW session parameters + \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_SESSION_BUF_SIZE + */ + uint8_t* getBufferSession(); + + /*! + \brief Fill the internal buffer that holds the LW session parameters with a supplied buffer + \param persistentBuffer Buffer that should match the internal format (previously extracted using getBufferSession) + \returns \ref status_codes + */ + int16_t setBufferSession(uint8_t* persistentBuffer); + + /*! + \brief Restore session by loading information from persistent storage. + \returns \ref status_codes + */ + int16_t restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan); /*! \brief Join network by performing over-the-air activation. By this procedure, @@ -434,12 +513,11 @@ 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. - + \param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - 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); + int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false, uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); /*! \brief Join network by performing activation by personalization. @@ -447,19 +525,19 @@ class LoRaWANNode { \param addr Device address. \param nwkSKey Pointer to the network session AES-128 key (LoRaWAN 1.0) or MAC command network session key (LoRaWAN 1.1). \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 fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. + \param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. \param force Set to true to force a new session, even if one exists. + \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL, bool force = false); + int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL, bool force = false, uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); /*! \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. + \brief Save the current state of the session to the session buffer. \returns \ref status_codes */ int16_t saveSession(); @@ -530,6 +608,14 @@ class LoRaWANNode { */ int16_t downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event = NULL); + /*! + \brief Wait for downlink, simplified to allow for simpler sendReceive + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t downlink(LoRaWANEvent_t* event = NULL); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. @@ -577,6 +663,20 @@ class LoRaWANNode { */ int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + /*! + \brief Send a message to the server and wait for a downlink but don't bother the user with downlink contents + \param dataUp Data to send. + \param lenUp Length of the data. + \param port Port number to send the message to. + \param isConfirmed Whether to send a confirmed uplink or not. + \param eventUp Pointer to a structure to store extra information about the uplink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \param eventDown Pointer to a structure to store extra information about the downlink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port = 1, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + /*! \brief Set device status. \param battLevel Battery level to set. 0 for external power source, 1 for lowest battery, @@ -584,28 +684,37 @@ class LoRaWANNode { */ void setDeviceStatus(uint8_t battLevel); - /*! \brief Returns the last uplink's frame counter */ + /*! + \brief Returns the last uplink's frame counter; + also 0 if no uplink occured yet. + */ uint32_t getFcntUp(); - /*! \brief Returns the last network downlink's frame counter */ + /*! + \brief Returns the last network downlink's frame counter; + also 0 if no network downlink occured yet. + */ uint32_t getNFcntDown(); - /*! \brief Returns the last application downlink's frame counter */ + /*! + \brief Returns the last application downlink's frame counter; + also 0 if no application downlink occured yet. + */ uint32_t getAFcntDown(); - /*! \brief Reset the downlink frame counters (application and network) + /*! + \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. + It mainly exists as part of the TS009 Specification Verification protocol. */ void resetFcntDown(); /*! \brief Set uplink datarate. This should not be used when ADR is enabled. \param dr Datarate to use for uplinks. - \param saveToEeprom Whether to save this setting to EEPROM or not (default false). \returns \ref status_codes */ - int16_t setDatarate(uint8_t drUp, bool saveToEeprom = false); + int16_t setDatarate(uint8_t drUp); /*! \brief Toggle ADR to on or off. @@ -651,10 +760,9 @@ class LoRaWANNode { /*! \brief Configure TX power of the radio module. \param txPower Output power during TX mode to be set in dBm. - \param saveToEeprom Whether to save this setting to EEPROM or not (default false). \returns \ref status_codes */ - int16_t setTxPower(int8_t txPower, bool saveToEeprom = false); + int16_t setTxPower(int8_t txPower); /*! \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. @@ -697,7 +805,15 @@ class LoRaWANNode { PhysicalLayer* phyLayer = NULL; const LoRaWANBand_t* band = NULL; - void beginCommon(uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size); + + void beginCommon(uint8_t initialDr); + + // a buffer that holds all LW base parameters that should persist at all times! + uint8_t bufferNonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE] = { 0 }; + + // a buffer that holds all LW session parameters that preferably persist, but can be afforded to get lost + uint8_t bufferSession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE] = { 0 }; LoRaWANMacCommandQueue_t commandsUp = { .numCommands = 0, @@ -741,7 +857,7 @@ class LoRaWANNode { bool FSK = false; // flag that shows whether the device is joined and there is an ongoing session (none, ABP or OTAA) - uint16_t activeMode = 0; + uint16_t activeMode = RADIOLIB_LORAWAN_MODE_NONE; // ADR is enabled by default bool adrEnabled = true; @@ -798,23 +914,7 @@ class LoRaWANNode { bool isMACPayload = false; // save the selected sub-band in case this must be restored in ADR control - int8_t subBand = -1; - -#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 + uint8_t subBand = 0; // wait for, open and listen during Rx1 and Rx2 windows; only performs listening int16_t downlinkCommon(); @@ -859,16 +959,16 @@ class LoRaWANNode { // delete a specific MAC command from queue, indicated by the command ID // 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); + int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload = NULL); // execute mac command, return the number of processed bytes for sequential processing - bool execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom = true); + bool execMacCommand(LoRaWANMacCommand_t* cmd); // apply a channel mask to a set of readily defined channels (dynamic bands only) bool applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask); // define or delete channels from a fixed set of channels (fixed bands only) - bool applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool clear); + bool applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask); // get the payload length for a specific MAC command uint8_t getMacPayloadLength(uint8_t cid); @@ -883,7 +983,7 @@ class LoRaWANNode { 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); // 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum - static uint16_t checkSum16(uint8_t *key, uint8_t keyLen); + static uint16_t checkSum16(uint8_t *key, uint16_t keyLen); // network-to-host conversion method - takes data from network packet and converts it to the host endians template diff --git a/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWANBands.cpp b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWANBands.cpp index e8b244bd9..ad0b1b9ee 100644 --- a/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -2,7 +2,21 @@ #if !RADIOLIB_EXCLUDE_LORAWAN +enum LoRaWANBandNum_t { + BandNone, + BandEU868, + BandUS915, + BandCN780, + BandEU433, + BandAU915, + BandCN500, + BandAS923, + BandKR920, + BandIN865 +}; + const LoRaWANBand_t EU868 = { + .bandNum = BandEU868, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, @@ -48,6 +62,7 @@ const LoRaWANBand_t EU868 = { }; const LoRaWANBand_t US915 = { + .bandNum = BandUS915, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, @@ -114,6 +129,7 @@ const LoRaWANBand_t US915 = { }; const LoRaWANBand_t CN780 = { + .bandNum = BandCN780, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, @@ -159,6 +175,7 @@ const LoRaWANBand_t CN780 = { }; const LoRaWANBand_t EU433 = { + .bandNum = BandEU433, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, @@ -204,6 +221,7 @@ const LoRaWANBand_t EU433 = { }; const LoRaWANBand_t AU915 = { + .bandNum = BandAU915, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, @@ -270,6 +288,7 @@ const LoRaWANBand_t AU915 = { }; const LoRaWANBand_t CN500 = { + .bandNum = BandCN500, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 19, @@ -329,6 +348,7 @@ const LoRaWANBand_t CN500 = { }; const LoRaWANBand_t AS923 = { + .bandNum = BandAS923, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, @@ -374,6 +394,7 @@ const LoRaWANBand_t AS923 = { }; const LoRaWANBand_t KR920 = { + .bandNum = BandKR920, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 14, @@ -419,6 +440,7 @@ const LoRaWANBand_t KR920 = { }; const LoRaWANBand_t IN865 = { + .bandNum = BandIN865, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 30, diff --git a/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.cpp b/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.cpp index 8ec0c469f..90cc2a68b 100644 --- a/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.cpp +++ b/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.cpp @@ -85,7 +85,7 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { if((pauseLen >= low*(float)letterSpace) && (pauseLen <= high*(float)letterSpace)) { return(RADIOLIB_MORSE_CHAR_COMPLETE); } else if(pauseLen > wordSpace) { - RADIOLIB_DEBUG_PRINTLN("\n"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("\n"); return(RADIOLIB_MORSE_WORD_COMPLETE); } @@ -96,15 +96,15 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { uint32_t signalLen = mod->hal->millis() - signalStart; if((signalLen >= low*(float)dotLength) && (signalLen <= high*(float)dotLength)) { - RADIOLIB_DEBUG_PRINT("."); + RADIOLIB_DEBUG_PROTOCOL_PRINT("."); (*symbol) |= (RADIOLIB_MORSE_DOT << (*len)); (*len)++; } else if((signalLen >= low*(float)dashLength) && (signalLen <= high*(float)dashLength)) { - RADIOLIB_DEBUG_PRINT("-"); + RADIOLIB_DEBUG_PROTOCOL_PRINT("-"); (*symbol) |= (RADIOLIB_MORSE_DASH << (*len)); (*len)++; } else { - RADIOLIB_DEBUG_PRINTLN("", signalLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("", signalLen); } } @@ -122,7 +122,7 @@ size_t MorseClient::write(uint8_t b) { // inter-word pause (space) if(b == ' ') { - RADIOLIB_DEBUG_PRINTLN("space"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("space"); standby(); mod->waitForMicroseconds(mod->hal->micros(), wordSpace*1000); return(1); @@ -141,11 +141,11 @@ size_t MorseClient::write(uint8_t b) { // send dot or dash if (code & RADIOLIB_MORSE_DASH) { - RADIOLIB_DEBUG_PRINT("-"); + RADIOLIB_DEBUG_PROTOCOL_PRINT("-"); transmitDirect(baseFreq, baseFreqHz); mod->waitForMicroseconds(mod->hal->micros(), dashLength*1000); } else { - RADIOLIB_DEBUG_PRINT("."); + RADIOLIB_DEBUG_PROTOCOL_PRINT("."); transmitDirect(baseFreq, baseFreqHz); mod->waitForMicroseconds(mod->hal->micros(), dotLength*1000); } @@ -161,7 +161,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); mod->waitForMicroseconds(mod->hal->micros(), letterSpace*1000 - dotLength*1000); - RADIOLIB_DEBUG_PRINTLN(); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(); return(1); } diff --git a/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.cpp b/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.cpp index d1bf0cf11..1db47da61 100644 --- a/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.cpp +++ b/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.cpp @@ -1,9 +1,9 @@ #include "Pager.h" #include #include -//#if defined(ESP32) -//#include "esp_attr.h" -//#endif +#if defined(ESP_PLATFORM) +#include "esp_attr.h" +#endif #if !RADIOLIB_EXCLUDE_PAGER @@ -28,6 +28,9 @@ PagerClient::PagerClient(PhysicalLayer* phy) { #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE readBitInstance = phyLayer; #endif + filterNumAddresses = 0; + filterAddresses = NULL; + filterMasks = NULL; } int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shift) { @@ -245,7 +248,24 @@ int16_t PagerClient::startReceive(uint32_t pin, uint32_t addr, uint32_t mask) { readBitPin = pin; filterAddr = addr; filterMask = mask; + filterAddresses = NULL; + filterMasks = NULL; + filterNumAddresses = 0; + return(startReceiveCommon()); +} +int16_t PagerClient::startReceive(uint32_t pin, uint32_t *addrs, uint32_t *masks, size_t numAddresses) { + // save the variables + readBitPin = pin; + filterAddr = 0; + filterMask = 0; + filterAddresses = addrs; + filterMasks = masks; + filterNumAddresses = numAddresses; + return(startReceiveCommon()); +} + +int16_t PagerClient::startReceiveCommon() { // set the carrier frequency int16_t state = phyLayer->setFrequency(baseFreq); RADIOLIB_ASSERT(state); @@ -260,7 +280,7 @@ int16_t PagerClient::startReceive(uint32_t pin, uint32_t addr, uint32_t mask) { // now set up the direct mode reception Module* mod = phyLayer->getMod(); - mod->hal->pinMode(pin, mod->hal->GpioModeInput); + mod->hal->pinMode(readBitPin, mod->hal->GpioModeInput); // set direct sync word to the frame sync word // the logic here is inverted, because modules like SX1278 @@ -356,8 +376,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { // should be an address code word, extract the address uint32_t addr_found = ((cw & RADIOLIB_PAGER_ADDRESS_BITS_MASK) >> (RADIOLIB_PAGER_ADDRESS_POS - 3)) | (framePos/2); - if((addr_found & filterMask) == (filterAddr & filterMask)) { - // we have a match! + if (addressMatched(addr_found)) { match = true; if(addr) { *addr = addr_found; @@ -460,6 +479,26 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { } #endif +bool PagerClient::addressMatched(uint32_t addr) { + // check whether to match single or multiple addresses/masks + if(filterNumAddresses == 0) { + return((addr & filterMask) == (filterAddr & filterMask)); + } + + // multiple addresses, check there are some to match + if((filterAddresses == NULL) || (filterMasks == NULL)) { + return(false); + } + + for(size_t i = 0; i < filterNumAddresses; i++) { + if((filterAddresses[i] & filterMasks[i]) == (addr & filterMasks[i])) { + return(true); + } + } + + return(false); +} + void PagerClient::write(uint32_t* data, size_t len) { // write code words from buffer for(size_t i = 0; i < len; i++) { @@ -515,7 +554,7 @@ uint32_t PagerClient::read() { codeWord = ~codeWord; } - RADIOLIB_VERBOSE_PRINTLN("R\t%lX", codeWord); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%lX", codeWord); // TODO BCH error correction here return(codeWord); } diff --git a/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.h b/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.h index 11b9c4dd0..f5cdb8190 100644 --- a/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.h +++ b/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.h @@ -130,6 +130,16 @@ class PagerClient { */ int16_t startReceive(uint32_t pin, uint32_t addr, uint32_t mask = 0xFFFFF); + /*! + \brief Start reception of POCSAG packets for multiple addresses and masks. + \param pin Pin to receive digital data on (e.g., DIO2 for SX127x). + \param addrs Array of addresses to receive. + \param masks Array of address masks to use for filtering. Masks will be applied to corresponding addresses in addr array. + \param numAddress Number of addresses/masks to match. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t pin, uint32_t *addrs, uint32_t *masks, size_t numAddress); + /*! \brief Get the number of POCSAG batches available in buffer. Limited by the size of direct mode buffer! \returns Number of available batches. @@ -175,10 +185,15 @@ class PagerClient { uint16_t bitDuration; uint32_t filterAddr; uint32_t filterMask; + uint32_t *filterAddresses; + uint32_t *filterMasks; + size_t filterNumAddresses; bool inv = false; void write(uint32_t* data, size_t len); void write(uint32_t codeWord); + int16_t startReceiveCommon(); + bool addressMatched(uint32_t addr); #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE uint32_t read(); diff --git a/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.cpp index f5ca56caf..a1b51730e 100644 --- a/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -413,7 +413,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { this->syncBuffer <<= 1; this->syncBuffer |= bit; - RADIOLIB_VERBOSE_PRINTLN("S\t%lu", this->syncBuffer); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("S\t%lu", this->syncBuffer); if((this->syncBuffer & this->directSyncWordMask) == this->directSyncWord) { this->gotSync = true; @@ -434,7 +434,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { // check complete byte if(this->bufferBitPos == 8) { this->buffer[this->bufferWritePos] = Module::reflect(this->buffer[this->bufferWritePos], 8); - RADIOLIB_VERBOSE_PRINTLN("R\t%X", this->buffer[this->bufferWritePos]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%X", this->buffer[this->bufferWritePos]); this->bufferWritePos++; this->bufferBitPos = 0; diff --git a/lib/lib_rf/RadioLibTasmotaAlert.md b/lib/lib_rf/RadioLibTasmotaAlert.md new file mode 100644 index 000000000..85fb51bc6 --- /dev/null +++ b/lib/lib_rf/RadioLibTasmotaAlert.md @@ -0,0 +1,8 @@ +TasmotaAlert + +Action to take in case of new release of RadioLib + +20240323 + +1 - Remove folder `RadioLibs/examples/NonArduino` (Fixes Github vulnerability alerts) +