From 45dc3fa44da07308b337694377a3b5de7654f87c Mon Sep 17 00:00:00 2001 From: Bernd Giesecke Date: Fri, 2 Aug 2019 19:42:34 +0800 Subject: [PATCH] Added ESp8266 Code cleanup --- .library.json | 64 +- README.md | 17 +- examples/LoRaWan/{main.ino => LoRaWan.ino} | 0 examples/LoRaWanPio/platformio.ini | 19 + examples/LoRaWanPio/src/ble.cpp | 54 +- examples/PingPong/PingPong.ino | 630 ++--- examples/PingPong/ble.ino | 54 +- examples/PingPongPio/platformio.ini | 21 +- examples/PingPongPio/src/ble.cpp | 54 +- examples/PingPongPio/src/main.cpp | 630 ++--- keywords.txt | 3 - library.properties | 6 +- src/boards/mcu/board.cpp | 26 +- src/boards/mcu/board.h | 29 +- src/boards/mcu/esp32/spi_board.cpp | 11 - src/boards/mcu/{esp32 => espressif}/board.cpp | 41 +- src/boards/mcu/espressif/spi_board.cpp | 15 + .../mcu/{esp32 => espressif}/spi_board.h | 0 src/boards/mcu/{esp32 => espressif}/timer.cpp | 13 +- src/boards/mcu/nrf52832/spi_board.cpp | 4 +- src/boards/mcu/nrf52832/timer.cpp | 700 +++--- src/boards/mcu/spi_board.h | 4 +- src/boards/mcu/timer.h | 62 +- src/boards/sx126x/sx126x-board.cpp | 8 +- src/mac/Commissioning.h | 37 +- src/mac/LoRaMac-definitions.h | 446 ++-- src/mac/LoRaMac.h | 1356 +++++------ src/mac/LoRaMacCrypto.cpp | 278 +-- src/mac/LoRaMacCrypto.h | 26 +- src/mac/LoRaMacHelper.cpp | 1 - src/mac/LoRaMacHelper.h | 182 +- src/mac/LoRaMacTest.h | 18 +- src/mac/region/Region.cpp | 1862 +++++++-------- src/mac/region/Region.h | 762 +++--- src/mac/region/RegionAS923.cpp | 2108 ++++++++--------- src/mac/region/RegionAS923.h | 207 +- src/mac/region/RegionAU915.cpp | 1630 ++++++------- src/mac/region/RegionAU915.h | 197 +- src/mac/region/RegionCN470.cpp | 1530 ++++++------ src/mac/region/RegionCN470.h | 173 +- src/mac/region/RegionCN779.cpp | 2006 ++++++++-------- src/mac/region/RegionCN779.h | 190 +- src/mac/region/RegionCommon.cpp | 644 ++--- src/mac/region/RegionCommon.h | 194 +- src/mac/region/RegionEU433.h | 190 +- src/mac/region/RegionEU868.cpp | 2072 ++++++++-------- src/mac/region/RegionEU868.h | 210 +- src/mac/region/RegionIN865.cpp | 2006 ++++++++-------- src/mac/region/RegionIN865.h | 194 +- src/mac/region/RegionKR920.h | 196 +- src/mac/region/RegionUS915-Hybrid.h | 189 +- src/mac/region/RegionUS915.cpp | 1644 ++++++------- src/mac/region/RegionUS915.h | 189 +- src/radio/sx126x/radio.cpp | 99 +- src/radio/sx126x/sx126x.cpp | 2 +- src/system/crypto/aes.cpp | 1743 +++++++------- src/system/crypto/aes.h | 126 +- src/system/crypto/cmac.cpp | 227 +- src/system/crypto/cmac.h | 44 +- src/system/delay.cpp | 51 - src/system/delay.h | 53 - 61 files changed, 12937 insertions(+), 12610 deletions(-) rename examples/LoRaWan/{main.ino => LoRaWan.ino} (100%) delete mode 100644 src/boards/mcu/esp32/spi_board.cpp rename src/boards/mcu/{esp32 => espressif}/board.cpp (69%) create mode 100644 src/boards/mcu/espressif/spi_board.cpp rename src/boards/mcu/{esp32 => espressif}/spi_board.h (100%) rename src/boards/mcu/{esp32 => espressif}/timer.cpp (96%) delete mode 100644 src/system/delay.cpp delete mode 100644 src/system/delay.h diff --git a/.library.json b/.library.json index 9c3a517..f4498d1 100644 --- a/.library.json +++ b/.library.json @@ -1,32 +1,36 @@ { - "name": "SX126x-Arduino", - "version": "1.0.0", - "keywords": [ - "lora", - "semtach", - "sx126x" - ], - "description": "Arduino library to use Semtech SX126x LoRa chips and modules to communicate", - "frameworks": [ - "arduino" - ], - "platforms": [ - "espressif32, nrf52" - ], - "license": [ - "MIT License" - ], - "authors": [ - { - "email": "beegee@giesecke.tk", - "url": "https://www.desire.giesecke.tk", - "maintainer": true, - "name": "Bernd Giesecke" - } - ], - "repository": { - "type": "git", - "url": "https://github.com/beegee-tokyo/SX126x-ESP32" - }, - "homepage": "https://github.com/beegee-tokyo/SX126x-ESP32" + "name": "SX126x-Arduino", + "version": "1.0.0", + "keywords": [ + "lora", + "Semtech", + "SX126x" + ], + "description": "Arduino library to use Semtech SX126x LoRa chips and modules to communicate", + "frameworks": [ + "arduino" + ], + "platforms": [ + "espressif32, nrf52, esp8266" + ], + "license": [ + "MIT License" + ], + "examples": + [ + "examples/*/*.ino" + ], + "authors": [ + { + "email": "beegee@giesecke.tk", + "url": "https://www.desire.giesecke.tk", + "maintainer": true, + "name": "Bernd Giesecke" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/beegee-tokyo/SX126x-Arduino" + }, + "homepage": "https://github.com/beegee-tokyo/SX126x-Arduino" } \ No newline at end of file diff --git a/README.md b/README.md index 4ba06db..689d298 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ SX126x-Arduino General info -------- -Arduino library for LoRa communication with Semtech SX126x chips. It is based on Semtech's SX126x libraries and adapted to the Arduino framework for ESP32 and nRF52832. It will not work with other uC's like AVR or Espressif 8266 (yet). +Arduino library for LoRa communication with Semtech SX126x chips. It is based on Semtech's SX126x libraries and adapted to the Arduino framework for ESP32. ESP8266 and nRF52832. It will not work with other uC's like AVR. I stumbled over the [SX126x LoRa family](https://www.semtech.com/products/wireless-rf/lora-transceivers) in a customer project. The existing Arduino libraries for Semtech's SX127x family are unfortunately not working with this new generation LoRa chip. I found a usefull base library from Insight SIP which is based on the original Semtech SX126x library and changed it to work with the ESP32. For now the library is tested with an [eByte E22-900M22S](http://www.ebyte.com/en/product-view-news.aspx?id=437) module connected to an ESP32 and an [Insight SIP ISP4520](https://www.insightsip.com/products/combo-smart-modules/isp4520) which combines a Nordic nRF52832 and a Semtech SX1262 in one module @@ -22,7 +22,7 @@ Licenses -------- Library published under MIT license -Semtech revised BSD license +Semtech revised BSD license for codeparts used from Semtech S.A. ``` --- Revised BSD License --- Copyright (c) 2013, SEMTECH S.A. @@ -53,7 +53,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Changelog -------- -- 2019-07-31: Added LoRaWan support +- 2019-08-01: Added Espressif ESP8266 support +- 2019-07-31: Added LoRaWan support (only partly tested) - 2019-07-28: Restructure of folders, added nRF52832 support - 2019-07-26: First commit. @@ -68,7 +69,7 @@ Functions ----- WORK IN PROGRESS **_Check out the example provided with this library to learn the basic functions._** -See [examples](https://github.com/beegee-tokyo/SX126x-ESP32/tree/master/examples) +See [examples](https://github.com/beegee-tokyo/SX126x-Android/tree/master/examples) Module specific setup -------- @@ -118,10 +119,10 @@ DIO3 as antenna switch is used by e.g. [Insight SIP ISP4520](https://www.insight Usage ----- -See [examples](https://github.com/beegee-tokyo/SX126x-ESP32/examples). -There is one example for [ArduinoIDE](https://github.com/beegee-tokyo/SX126x-ESP32/tree/master/examples/PingPong) and one example for [PlatformIO](https://github.com/beegee-tokyo/SX126x-ESP32/tree/master/examples/PingPongPio) available. +See [examples](https://github.com/beegee-tokyo/SX126x-Android/examples). +There is one example for [ArduinoIDE](https://github.com/beegee-tokyo/SX126x-Android/tree/master/examples/PingPong) and one example for [PlatformIO](https://github.com/beegee-tokyo/SX126x-Android/tree/master/examples/PingPongPio) available. The PingPong examples show how to define the HW connection between the MCU and the SX126x chip/module. -Another example is only partly tested. It is for LoRaWan and I could only test it as far as I know the application is sending out packages. But as I don't own a LoRaWan gateway I cannot test the functionality. Theoretically it should support Class A, B and C nodes. The examples can be found here: [ArduinoIDE](https://github.com/beegee-tokyo/SX126x-ESP32/tree/master/examples/LoRaWan) and one example for [PlatformIO](https://github.com/beegee-tokyo/SX126x-ESP32/tree/master/examples/LoRaWanPio) +Another example is only partly tested. It is for LoRaWan and I could only test it as far as I know the application is sending out packages. But as I don't own a LoRaWan gateway I cannot test the functionality. Theoretically it should support Class A, B and C nodes. The examples can be found here: [ArduinoIDE](https://github.com/beegee-tokyo/SX126x-Android/tree/master/examples/LoRaWan) and one example for [PlatformIO](https://github.com/beegee-tokyo/SX126x-Android/tree/master/examples/LoRaWanPio) To use these examples you need to edit the header file ```Commissioning.h``` in the library folder ```src/mac``` Structure to define the connection between the MCU and the SX126x @@ -325,6 +326,6 @@ Installation In Arduino IDE open Sketch->Include Library->Manage Libraries then search for _**SX126x-Arduino**_ In PlatformIO open PlatformIO Home, switch to libraries and search for _**SX126x-Arduino**_. Or install the library in the terminal with _**`platformio lib install SX126x-Arduino`**_ -For manual installation [download](https://github.com/beegee-tokyo/SX126x-Arduino) the archive, unzip it and place the SX126x-ESP32 folder into the library directory. +For manual installation [download](https://github.com/beegee-tokyo/SX126x-Arduino) the archive, unzip it and place the SX126x-Android folder into the library directory. In Arduino IDE this is usually _**`/libraries/`**_ In PlatformIO this is usually _**``**_ diff --git a/examples/LoRaWan/main.ino b/examples/LoRaWan/LoRaWan.ino similarity index 100% rename from examples/LoRaWan/main.ino rename to examples/LoRaWan/LoRaWan.ino diff --git a/examples/LoRaWanPio/platformio.ini b/examples/LoRaWanPio/platformio.ini index 76dce64..b9b7aca 100644 --- a/examples/LoRaWanPio/platformio.ini +++ b/examples/LoRaWanPio/platformio.ini @@ -8,6 +8,12 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html +[platformio] +default_envs = + esp32dev + nrf52 + esp8266 + [env:esp32dev] platform = https://github.com/platformio/platform-espressif32.git#feature/stage board = esp32dev @@ -25,3 +31,16 @@ framework = arduino build_flags = -DCFG_DEBUG=2 -DREGION_US915 + +[env:esp8266] +platform = https://github.com/platformio/platform-espressif8266.git#feature/stage +; platform = espressif8266 +board = nodemcuv2 +framework = arduino +upload_port = COM10 +upload_speed = 921600 +board_build.f_cpu = 160000000L +build_flags = + -Wl,-Tesp8266.flash.4m1m.ld + -Og + -DREGION_US915 diff --git a/examples/LoRaWanPio/src/ble.cpp b/examples/LoRaWanPio/src/ble.cpp index faac096..fef0128 100644 --- a/examples/LoRaWanPio/src/ble.cpp +++ b/examples/LoRaWanPio/src/ble.cpp @@ -14,34 +14,34 @@ bool bleUARTisConnected = false; void initBLE(void) { - Bluefruit.begin(); - // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 - Bluefruit.setTxPower(4); - Bluefruit.setName("PPG_LORA_SX126x_TEST"); + Bluefruit.begin(); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + Bluefruit.setName("PPG_LORA_SX126x_TEST"); - Bluefruit.autoConnLed(false); + Bluefruit.autoConnLed(false); - Bluefruit.Periph.setConnectCallback(connect_callback); - Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); - // To be consistent OTA DFU should be added first if it exists - bledfu.begin(); + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); - // Configure and Start BLE Uart Service - bleuart.begin(); + // Configure and Start BLE Uart Service + bleuart.begin(); - // Set up and start advertising - startAdv(); + // Set up and start advertising + startAdv(); } void startAdv(void) { - // Advertising packet - Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); - Bluefruit.Advertising.addTxPower(); - Bluefruit.Advertising.addName(); + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); - /* Start Advertising + /* Start Advertising * - Enable auto advertising if disconnected * - Interval: fast mode = 20 ms, slow mode = 152.5 ms * - Timeout for fast mode is 30 seconds @@ -50,17 +50,17 @@ void startAdv(void) * For recommended advertising interval * https://developer.apple.com/library/content/qa/qa1931/_index.html */ - Bluefruit.Advertising.restartOnDisconnect(true); - Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms - Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode - Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds } // callback invoked when central connects void connect_callback(uint16_t conn_handle) { - (void)conn_handle; - bleUARTisConnected = true; + (void)conn_handle; + bleUARTisConnected = true; } /** @@ -70,8 +70,8 @@ void connect_callback(uint16_t conn_handle) */ void disconnect_callback(uint16_t conn_handle, uint8_t reason) { - (void)conn_handle; - (void)reason; - bleUARTisConnected = false; + (void)conn_handle; + (void)reason; + bleUARTisConnected = false; } #endif diff --git a/examples/PingPong/PingPong.ino b/examples/PingPong/PingPong.ino index aaf63f5..10fc348 100644 --- a/examples/PingPong/PingPong.ino +++ b/examples/PingPong/PingPong.ino @@ -8,14 +8,26 @@ hw_config hwConfig; #ifdef ESP32 // ESP32 - SX126x pin configuration int PIN_LORA_RESET = 4; // LORA RESET -int PIN_LORA_NSS = 5; // LORA SPI CS +int PIN_LORA_NSS = 5; // LORA SPI CS int PIN_LORA_SCLK = 18; // LORA SPI CLK int PIN_LORA_MISO = 19; // LORA SPI MISO int PIN_LORA_DIO_1 = 21; // LORA DIO_1 int PIN_LORA_BUSY = 22; // LORA SPI BUSY int PIN_LORA_MOSI = 23; // LORA SPI MOSI -int RADIO_TXEN = 26; // LORA ANTENNA TX ENABLE -int RADIO_RXEN = 27; // LORA ANTENNA RX ENABLE +int RADIO_TXEN = 26; // LORA ANTENNA TX ENABLE +int RADIO_RXEN = 27; // LORA ANTENNA RX ENABLE +#endif +#ifdef ESP8266 +// ESP32 - SX126x pin configuration +int PIN_LORA_RESET = -1; // LORA RESET +int PIN_LORA_NSS = 15; // LORA SPI CS +int PIN_LORA_SCLK = 14; // LORA SPI CLK +int PIN_LORA_MISO = 12; // LORA SPI MISO +int PIN_LORA_DIO_1 = 4; // LORA DIO_1 +int PIN_LORA_BUSY = 5; // LORA SPI BUSY +int PIN_LORA_MOSI = 13; // LORA SPI MOSI +int RADIO_TXEN = 16; // LORA ANTENNA TX ENABLE +int RADIO_RXEN = 2; // LORA ANTENNA RX ENABLE #endif #ifdef NRF52 // nRF52832 - SX126x pin configuration @@ -26,15 +38,13 @@ int PIN_LORA_MISO = 14; // LORA SPI MISO int PIN_LORA_DIO_1 = 11; // LORA DIO_1 int PIN_LORA_BUSY = 29; // LORA SPI BUSY int PIN_LORA_MOSI = 13; // LORA SPI MOSI -int RADIO_TXEN = 31; // LORA ANTENNA TX ENABLE -int RADIO_RXEN = 27; // LORA ANTENNA RX ENABLE +int RADIO_TXEN = 31; // LORA ANTENNA TX ENABLE +int RADIO_RXEN = 27; // LORA ANTENNA RX ENABLE // Replace PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI with your SPIClass SPI_LORA(NRF_SPI2, 14, 12, 13); #endif // Function declarations -void enableRX(void); -void enableTX(void); void OnTxDone(void); void OnRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr); void OnTxTimeout(void); @@ -50,21 +60,22 @@ extern BLEUart bleuart; #endif // Check if the board has an LED port defined -#ifndef LED_BUILTIN #ifdef ESP32 #define LED_BUILTIN 2 #endif +#ifdef ESP8266 +#define LED_BUILTIN 2 +#endif #ifdef NRF52 #define LED_BUILTIN 17 #endif -#endif // Define LoRa parameters #define RF_FREQUENCY 868000000 // Hz -#define TX_OUTPUT_POWER 22 // dBm -#define LORA_BANDWIDTH 0 // [0: 125 kHz, 1: 250 kHz, 2: 500 kHz, 3: Reserved] +#define TX_OUTPUT_POWER 22 // dBm +#define LORA_BANDWIDTH 0 // [0: 125 kHz, 1: 250 kHz, 2: 500 kHz, 3: Reserved] #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] -#define LORA_CODINGRATE 1 // [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] +#define LORA_CODINGRATE 1 // [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx #define LORA_SYMBOL_TIMEOUT 0 // Symbols #define LORA_FIX_LENGTH_PAYLOAD_ON false @@ -91,362 +102,393 @@ uint8_t pongCnt = 0; void setup() { - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - - // Define the HW configuration between MCU and SX126x - hwConfig.CHIP_TYPE = SX1262_CHIP; // Example uses an eByte E22 module with an SX1262 - hwConfig.PIN_LORA_RESET = PIN_LORA_RESET; // LORA RESET - hwConfig.PIN_LORA_NSS = PIN_LORA_NSS; // LORA SPI CS - hwConfig.PIN_LORA_SCLK = PIN_LORA_SCLK; // LORA SPI CLK - hwConfig.PIN_LORA_MISO = PIN_LORA_MISO; // LORA SPI MISO - hwConfig.PIN_LORA_DIO_1 = PIN_LORA_DIO_1; // LORA DIO_1 - hwConfig.PIN_LORA_BUSY = PIN_LORA_BUSY; // LORA SPI BUSY - hwConfig.PIN_LORA_MOSI = PIN_LORA_MOSI; // LORA SPI MOSI - hwConfig.RADIO_TXEN = RADIO_TXEN; // LORA ANTENNA TX ENABLE - hwConfig.RADIO_RXEN = RADIO_RXEN; // LORA ANTENNA RX ENABLE - hwConfig.USE_DIO2_ANT_SWITCH = false; // Example uses an eByte E22 module which uses RXEN and TXEN pins as antenna control - hwConfig.USE_DIO3_TCXO = true; // Example uses an eByte E22 module which uses DIO3 to control oscillator voltage - hwConfig.USE_DIO3_ANT_SWITCH = false; // Only Insight ISP4520 module uses DIO3 as antenna control - - // Initialize Serial for debug output - Serial.begin(115200); - - Serial.println("====================================="); - Serial.println("SX126x PingPong test"); - Serial.println("====================================="); + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + // Define the HW configuration between MCU and SX126x + hwConfig.CHIP_TYPE = SX1262_CHIP; // Example uses an eByte E22 module with an SX1262 + hwConfig.PIN_LORA_RESET = PIN_LORA_RESET; // LORA RESET + hwConfig.PIN_LORA_NSS = PIN_LORA_NSS; // LORA SPI CS + hwConfig.PIN_LORA_SCLK = PIN_LORA_SCLK; // LORA SPI CLK + hwConfig.PIN_LORA_MISO = PIN_LORA_MISO; // LORA SPI MISO + hwConfig.PIN_LORA_DIO_1 = PIN_LORA_DIO_1; // LORA DIO_1 + hwConfig.PIN_LORA_BUSY = PIN_LORA_BUSY; // LORA SPI BUSY + hwConfig.PIN_LORA_MOSI = PIN_LORA_MOSI; // LORA SPI MOSI + hwConfig.RADIO_TXEN = RADIO_TXEN; // LORA ANTENNA TX ENABLE + hwConfig.RADIO_RXEN = RADIO_RXEN; // LORA ANTENNA RX ENABLE + hwConfig.USE_DIO2_ANT_SWITCH = false; // Example uses an eByte E22 module which uses RXEN and TXEN pins as antenna control + hwConfig.USE_DIO3_TCXO = true; // Example uses an eByte E22 module which uses DIO3 to control oscillator voltage + hwConfig.USE_DIO3_ANT_SWITCH = false; // Only Insight ISP4520 module uses DIO3 as antenna control + + // Initialize Serial for debug output + Serial.begin(115200); + + Serial.println("====================================="); + Serial.println("SX126x PingPong test"); + Serial.println("====================================="); #ifdef NRF52 - pinMode(30, OUTPUT); - digitalWrite(30, HIGH); - // Start BLE if we compile for nRF52 - initBLE(); + Serial.println("MCU Nordic nRF52832"); + pinMode(30, OUTPUT); + digitalWrite(30, HIGH); + // Start BLE if we compile for nRF52 + initBLE(); +#endif +#ifdef ESP32 + Serial.println("MCU Espressif ESP32"); +#endif +#ifdef ESP8266 + Serial.println("MCU Espressif ESP8266"); #endif - // Initialize the LoRa chip - Serial.println("Starting lora_hardware_init"); - lora_hardware_init(hwConfig); - - // Initialize the Radio callbacks - RadioEvents.TxDone = OnTxDone; - RadioEvents.RxDone = OnRxDone; - RadioEvents.TxTimeout = OnTxTimeout; - RadioEvents.RxTimeout = OnRxTimeout; - RadioEvents.RxError = OnRxError; - RadioEvents.CadDone = OnCadDone; - - // Initialize the Radio - Radio.Init(&RadioEvents); - - // Set Radio channel - Radio.SetChannel(RF_FREQUENCY); - - // Set Radio TX configuration - Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, - LORA_SPREADING_FACTOR, LORA_CODINGRATE, - LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, - true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE); - - // Set Radio RX configuration - Radio.SetRxConfig(MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, - LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, - LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, - 0, true, 0, 0, LORA_IQ_INVERSION_ON, true); - - // Start LoRa - Serial.println("Starting Radio.Rx"); - Radio.Rx(RX_TIMEOUT_VALUE); - - timeToSend = millis(); + uint8_t deviceId[8]; + + BoardGetUniqueId(deviceId); + Serial.printf("BoardId: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n", + deviceId[7], + deviceId[6], + deviceId[5], + deviceId[4], + deviceId[3], + deviceId[2], + deviceId[1], + deviceId[0]); + + // Initialize the LoRa chip + Serial.println("Starting lora_hardware_init"); + lora_hardware_init(hwConfig); + + // Initialize the Radio callbacks + RadioEvents.TxDone = OnTxDone; + RadioEvents.RxDone = OnRxDone; + RadioEvents.TxTimeout = OnTxTimeout; + RadioEvents.RxTimeout = OnRxTimeout; + RadioEvents.RxError = OnRxError; + RadioEvents.CadDone = OnCadDone; + + // Initialize the Radio + Radio.Init(&RadioEvents); + + // Set Radio channel + Radio.SetChannel(RF_FREQUENCY); + + // Set Radio TX configuration + Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, + LORA_SPREADING_FACTOR, LORA_CODINGRATE, + LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, + true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE); + + // Set Radio RX configuration + Radio.SetRxConfig(MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, + LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, + LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, + 0, true, 0, 0, LORA_IQ_INVERSION_ON, true); + + // Start LoRa + Serial.println("Starting Radio.Rx"); + Radio.Rx(RX_TIMEOUT_VALUE); + + timeToSend = millis(); } void loop() { - // Handle Radio events - Radio.IrqProcess(); + // Handle Radio events + Radio.IrqProcess(); + + // We are on FreeRTOS, give other tasks a chance to run + delay(100); + yield(); } /**@brief Function to be executed on Radio Tx Done event */ void OnTxDone(void) { - Serial.println("OnTxDone"); + Serial.println("OnTxDone"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnTxDone\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnTxDone\n"); + } #endif - Radio.Rx(RX_TIMEOUT_VALUE); + Radio.Rx(RX_TIMEOUT_VALUE); } /**@brief Function to be executed on Radio Rx Done event */ void OnRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) { - Serial.println("OnRxDone"); + Serial.println("OnRxDone"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnRxDone\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnRxDone\n"); + } #endif - delay(10); - BufferSize = size; - memcpy(RcvBuffer, payload, BufferSize); + delay(10); + BufferSize = size; + memcpy(RcvBuffer, payload, BufferSize); + + Serial.printf("RssiValue=%d dBm, SnrValue=%d\n", rssi, snr); + + for (int idx = 0; idx < size; idx++) + { + Serial.printf("%02X ", RcvBuffer[idx]); + } + Serial.println(""); - Serial.printf("RssiValue=%d dBm, SnrValue=%d\n", rssi, snr); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.printf("RssiValue=%d dBm, SnrValue=%d\n", rssi, snr); - } + if (bleUARTisConnected) + { + bleuart.printf("RssiValue=%d dBm, SnrValue=%d\n", rssi, snr); + } #endif - digitalWrite(LED_BUILTIN, HIGH); - - if (isMaster == true) - { - if (BufferSize > 0) - { - if (strncmp((const char *)RcvBuffer, (const char *)PongMsg, 4) == 0) - { - Serial.println("Received a PONG in OnRxDone as Master"); + digitalWrite(LED_BUILTIN, HIGH); + + if (isMaster == true) + { + if (BufferSize > 0) + { + if (strncmp((const char *)RcvBuffer, (const char *)PongMsg, 4) == 0) + { + Serial.println("Received a PONG in OnRxDone as Master"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Received a PONG in OnRxDone as Master\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Received a PONG in OnRxDone as Master\n"); + } #endif - // Wait 500ms before sending the next package - delay(500); - - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending next Ping will be started when the channel is free - } - else if (strncmp((const char *)RcvBuffer, (const char *)PingMsg, 4) == 0) - { // A master already exists then become a slave - Serial.println("Received a PING in OnRxDone as Master"); + // Wait 500ms before sending the next package + delay(500); + + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending next Ping will be started when the channel is free + } + else if (strncmp((const char *)RcvBuffer, (const char *)PingMsg, 4) == 0) + { // A master already exists then become a slave + Serial.println("Received a PING in OnRxDone as Master"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Received a PING in OnRxDone as Master\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Received a PING in OnRxDone as Master\n"); + } #endif - isMaster = false; - Radio.Rx(RX_TIMEOUT_VALUE); - } - else // valid reception but neither a PING or a PONG message - { // Set device as master and start again - isMaster = true; - Radio.Rx(RX_TIMEOUT_VALUE); - } - } - } - else - { - if (BufferSize > 0) - { - if (strncmp((const char *)RcvBuffer, (const char *)PingMsg, 4) == 0) - { - Serial.println("Received a PING in OnRxDone as Slave"); + isMaster = false; + Radio.Rx(RX_TIMEOUT_VALUE); + } + else // valid reception but neither a PING or a PONG message + { // Set device as master and start again + isMaster = true; + Radio.Rx(RX_TIMEOUT_VALUE); + } + } + } + else + { + if (BufferSize > 0) + { + if (strncmp((const char *)RcvBuffer, (const char *)PingMsg, 4) == 0) + { + Serial.println("Received a PING in OnRxDone as Slave"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Received a PING in OnRxDone as Slave\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Received a PING in OnRxDone as Slave\n"); + } #endif - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending Pong will be started when the channel is free - } - else // valid reception but not a PING as expected - { // Set device as master and start again - Serial.println("Received something in OnRxDone as Slave"); + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending Pong will be started when the channel is free + } + else // valid reception but not a PING as expected + { // Set device as master and start again + Serial.println("Received something in OnRxDone as Slave"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Received something in OnRxDone as Slave\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Received something in OnRxDone as Slave\n"); + } #endif - isMaster = true; - Radio.Rx(RX_TIMEOUT_VALUE); - } - } - } + isMaster = true; + Radio.Rx(RX_TIMEOUT_VALUE); + } + } + } } /**@brief Function to be executed on Radio Tx Timeout event */ void OnTxTimeout(void) { - // Radio.Sleep(); - Serial.println("OnTxTimeout"); + // Radio.Sleep(); + Serial.println("OnTxTimeout"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnTxTimeout\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnTxTimeout\n"); + } #endif - digitalWrite(LED_BUILTIN, LOW); + digitalWrite(LED_BUILTIN, LOW); - Radio.Rx(RX_TIMEOUT_VALUE); + Radio.Rx(RX_TIMEOUT_VALUE); } /**@brief Function to be executed on Radio Rx Timeout event */ void OnRxTimeout(void) { - Serial.println("OnRxTimeout"); + Serial.println("OnRxTimeout"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnRxTimeout\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnRxTimeout\n"); + } #endif - digitalWrite(LED_BUILTIN, LOW); - - if (isMaster == true) - { - // Wait 500ms before sending the next package - delay(500); - - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending the ping will be started when the channel is free - } - else - { - // No Ping received within timeout, switch to Master - isMaster = true; - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending the ping will be started when the channel is free - // Radio.Rx(RX_TIMEOUT_VALUE); - } + + digitalWrite(LED_BUILTIN, LOW); + + if (isMaster == true) + { + // Wait 500ms before sending the next package + delay(500); + + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending the ping will be started when the channel is free + } + else + { + // No Ping received within timeout, switch to Master + isMaster = true; + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending the ping will be started when the channel is free + } } /**@brief Function to be executed on Radio Rx Error event */ void OnRxError(void) { - Serial.println("OnRxError"); + Serial.println("OnRxError"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnRxError\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnRxError\n"); + } #endif - digitalWrite(LED_BUILTIN, LOW); - - if (isMaster == true) - { - // Wait 500ms before sending the next package - delay(500); - - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending the ping will be started when the channel is free - } - else - { - Radio.Rx(RX_TIMEOUT_VALUE); - } + digitalWrite(LED_BUILTIN, LOW); + + if (isMaster == true) + { + // Wait 500ms before sending the next package + delay(500); + + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending the ping will be started when the channel is free + } + else + { + Radio.Rx(RX_TIMEOUT_VALUE); + } } /**@brief Function to be executed on Radio Rx Error event */ void OnCadDone(bool cadResult) { - time_t duration = millis() - cadTime; - if (cadResult) - { - Serial.printf("CAD returned channel busy after %ldms\n", duration); + time_t duration = millis() - cadTime; + if (cadResult) + { + Serial.printf("CAD returned channel busy after %ldms\n", duration); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.printf("CAD returned channel busy after %ldms\n", duration); - } + if (bleUARTisConnected) + { + bleuart.printf("CAD returned channel busy after %ldms\n", duration); + } #endif - Radio.Rx(RX_TIMEOUT_VALUE); - } - else - { - Serial.printf("CAD returned channel free after %ldms\n", duration); + Radio.Rx(RX_TIMEOUT_VALUE); + } + else + { + Serial.printf("CAD returned channel free after %ldms\n", duration); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.printf("CAD returned channel free after %ldms\n", duration); - } + if (bleUARTisConnected) + { + bleuart.printf("CAD returned channel free after %ldms\n", duration); + } #endif - if (isMaster) - { - Serial.println("Sending a PING in OnCadDone as Master"); + if (isMaster) + { + Serial.println("Sending a PING in OnCadDone as Master"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Sending a PING in OnCadDone as Master\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Sending a PING in OnCadDone as Master\n"); + } #endif - // Send the next PING frame - TxdBuffer[0] = 'P'; - TxdBuffer[1] = 'I'; - TxdBuffer[2] = 'N'; - TxdBuffer[3] = 'G'; - } - else - { - Serial.println("Sending a PONG in OnCadDone as Slave"); + // Send the next PING frame + TxdBuffer[0] = 'P'; + TxdBuffer[1] = 'I'; + TxdBuffer[2] = 'N'; + TxdBuffer[3] = 'G'; + } + else + { + Serial.println("Sending a PONG in OnCadDone as Slave"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Sending a PONG in OnCadDone as Slave\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Sending a PONG in OnCadDone as Slave\n"); + } #endif - // Send the reply to the PONG string - TxdBuffer[0] = 'P'; - TxdBuffer[1] = 'O'; - TxdBuffer[2] = 'N'; - TxdBuffer[3] = 'G'; - } - // We fill the buffer with numbers for the payload - for (int i = 4; i < BufferSize; i++) - { - TxdBuffer[i] = i - 4; - } - - Radio.Send(TxdBuffer, BufferSize); - } + // Send the reply to the PONG string + TxdBuffer[0] = 'P'; + TxdBuffer[1] = 'O'; + TxdBuffer[2] = 'N'; + TxdBuffer[3] = 'G'; + } + // We fill the buffer with numbers for the payload + for (int i = 4; i < BufferSize; i++) + { + TxdBuffer[i] = i - 4; + } + + Radio.Send(TxdBuffer, BufferSize); + } } diff --git a/examples/PingPong/ble.ino b/examples/PingPong/ble.ino index faac096..fef0128 100644 --- a/examples/PingPong/ble.ino +++ b/examples/PingPong/ble.ino @@ -14,34 +14,34 @@ bool bleUARTisConnected = false; void initBLE(void) { - Bluefruit.begin(); - // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 - Bluefruit.setTxPower(4); - Bluefruit.setName("PPG_LORA_SX126x_TEST"); + Bluefruit.begin(); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + Bluefruit.setName("PPG_LORA_SX126x_TEST"); - Bluefruit.autoConnLed(false); + Bluefruit.autoConnLed(false); - Bluefruit.Periph.setConnectCallback(connect_callback); - Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); - // To be consistent OTA DFU should be added first if it exists - bledfu.begin(); + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); - // Configure and Start BLE Uart Service - bleuart.begin(); + // Configure and Start BLE Uart Service + bleuart.begin(); - // Set up and start advertising - startAdv(); + // Set up and start advertising + startAdv(); } void startAdv(void) { - // Advertising packet - Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); - Bluefruit.Advertising.addTxPower(); - Bluefruit.Advertising.addName(); + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); - /* Start Advertising + /* Start Advertising * - Enable auto advertising if disconnected * - Interval: fast mode = 20 ms, slow mode = 152.5 ms * - Timeout for fast mode is 30 seconds @@ -50,17 +50,17 @@ void startAdv(void) * For recommended advertising interval * https://developer.apple.com/library/content/qa/qa1931/_index.html */ - Bluefruit.Advertising.restartOnDisconnect(true); - Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms - Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode - Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds } // callback invoked when central connects void connect_callback(uint16_t conn_handle) { - (void)conn_handle; - bleUARTisConnected = true; + (void)conn_handle; + bleUARTisConnected = true; } /** @@ -70,8 +70,8 @@ void connect_callback(uint16_t conn_handle) */ void disconnect_callback(uint16_t conn_handle, uint8_t reason) { - (void)conn_handle; - (void)reason; - bleUARTisConnected = false; + (void)conn_handle; + (void)reason; + bleUARTisConnected = false; } #endif diff --git a/examples/PingPongPio/platformio.ini b/examples/PingPongPio/platformio.ini index 4971b6c..a8ffca5 100644 --- a/examples/PingPongPio/platformio.ini +++ b/examples/PingPongPio/platformio.ini @@ -8,6 +8,12 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html +[platformio] +default_envs = + esp32dev + nrf52 + esp8266 + [env:esp32dev] platform = https://github.com/platformio/platform-espressif32.git#feature/stage board = esp32dev @@ -20,4 +26,17 @@ build_flags = -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_ERROR platform = nordicnrf52 board = adafruit_feather_nrf52832 framework = arduino -build_flags = -DCFG_DEBUG=2 \ No newline at end of file +build_flags = -DCFG_DEBUG=2 + +[env:esp8266] +platform = https://github.com/platformio/platform-espressif8266.git#feature/stage +; platform = espressif8266 +board = nodemcuv2 +framework = arduino +upload_port = COM10 +upload_speed = 921600 +board_build.f_cpu = 160000000L +build_flags = + -Wl,-Tesp8266.flash.4m1m.ld + -Og + diff --git a/examples/PingPongPio/src/ble.cpp b/examples/PingPongPio/src/ble.cpp index faac096..fef0128 100644 --- a/examples/PingPongPio/src/ble.cpp +++ b/examples/PingPongPio/src/ble.cpp @@ -14,34 +14,34 @@ bool bleUARTisConnected = false; void initBLE(void) { - Bluefruit.begin(); - // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 - Bluefruit.setTxPower(4); - Bluefruit.setName("PPG_LORA_SX126x_TEST"); + Bluefruit.begin(); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + Bluefruit.setName("PPG_LORA_SX126x_TEST"); - Bluefruit.autoConnLed(false); + Bluefruit.autoConnLed(false); - Bluefruit.Periph.setConnectCallback(connect_callback); - Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); - // To be consistent OTA DFU should be added first if it exists - bledfu.begin(); + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); - // Configure and Start BLE Uart Service - bleuart.begin(); + // Configure and Start BLE Uart Service + bleuart.begin(); - // Set up and start advertising - startAdv(); + // Set up and start advertising + startAdv(); } void startAdv(void) { - // Advertising packet - Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); - Bluefruit.Advertising.addTxPower(); - Bluefruit.Advertising.addName(); + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); - /* Start Advertising + /* Start Advertising * - Enable auto advertising if disconnected * - Interval: fast mode = 20 ms, slow mode = 152.5 ms * - Timeout for fast mode is 30 seconds @@ -50,17 +50,17 @@ void startAdv(void) * For recommended advertising interval * https://developer.apple.com/library/content/qa/qa1931/_index.html */ - Bluefruit.Advertising.restartOnDisconnect(true); - Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms - Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode - Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds } // callback invoked when central connects void connect_callback(uint16_t conn_handle) { - (void)conn_handle; - bleUARTisConnected = true; + (void)conn_handle; + bleUARTisConnected = true; } /** @@ -70,8 +70,8 @@ void connect_callback(uint16_t conn_handle) */ void disconnect_callback(uint16_t conn_handle, uint8_t reason) { - (void)conn_handle; - (void)reason; - bleUARTisConnected = false; + (void)conn_handle; + (void)reason; + bleUARTisConnected = false; } #endif diff --git a/examples/PingPongPio/src/main.cpp b/examples/PingPongPio/src/main.cpp index aaf63f5..10fc348 100644 --- a/examples/PingPongPio/src/main.cpp +++ b/examples/PingPongPio/src/main.cpp @@ -8,14 +8,26 @@ hw_config hwConfig; #ifdef ESP32 // ESP32 - SX126x pin configuration int PIN_LORA_RESET = 4; // LORA RESET -int PIN_LORA_NSS = 5; // LORA SPI CS +int PIN_LORA_NSS = 5; // LORA SPI CS int PIN_LORA_SCLK = 18; // LORA SPI CLK int PIN_LORA_MISO = 19; // LORA SPI MISO int PIN_LORA_DIO_1 = 21; // LORA DIO_1 int PIN_LORA_BUSY = 22; // LORA SPI BUSY int PIN_LORA_MOSI = 23; // LORA SPI MOSI -int RADIO_TXEN = 26; // LORA ANTENNA TX ENABLE -int RADIO_RXEN = 27; // LORA ANTENNA RX ENABLE +int RADIO_TXEN = 26; // LORA ANTENNA TX ENABLE +int RADIO_RXEN = 27; // LORA ANTENNA RX ENABLE +#endif +#ifdef ESP8266 +// ESP32 - SX126x pin configuration +int PIN_LORA_RESET = -1; // LORA RESET +int PIN_LORA_NSS = 15; // LORA SPI CS +int PIN_LORA_SCLK = 14; // LORA SPI CLK +int PIN_LORA_MISO = 12; // LORA SPI MISO +int PIN_LORA_DIO_1 = 4; // LORA DIO_1 +int PIN_LORA_BUSY = 5; // LORA SPI BUSY +int PIN_LORA_MOSI = 13; // LORA SPI MOSI +int RADIO_TXEN = 16; // LORA ANTENNA TX ENABLE +int RADIO_RXEN = 2; // LORA ANTENNA RX ENABLE #endif #ifdef NRF52 // nRF52832 - SX126x pin configuration @@ -26,15 +38,13 @@ int PIN_LORA_MISO = 14; // LORA SPI MISO int PIN_LORA_DIO_1 = 11; // LORA DIO_1 int PIN_LORA_BUSY = 29; // LORA SPI BUSY int PIN_LORA_MOSI = 13; // LORA SPI MOSI -int RADIO_TXEN = 31; // LORA ANTENNA TX ENABLE -int RADIO_RXEN = 27; // LORA ANTENNA RX ENABLE +int RADIO_TXEN = 31; // LORA ANTENNA TX ENABLE +int RADIO_RXEN = 27; // LORA ANTENNA RX ENABLE // Replace PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI with your SPIClass SPI_LORA(NRF_SPI2, 14, 12, 13); #endif // Function declarations -void enableRX(void); -void enableTX(void); void OnTxDone(void); void OnRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr); void OnTxTimeout(void); @@ -50,21 +60,22 @@ extern BLEUart bleuart; #endif // Check if the board has an LED port defined -#ifndef LED_BUILTIN #ifdef ESP32 #define LED_BUILTIN 2 #endif +#ifdef ESP8266 +#define LED_BUILTIN 2 +#endif #ifdef NRF52 #define LED_BUILTIN 17 #endif -#endif // Define LoRa parameters #define RF_FREQUENCY 868000000 // Hz -#define TX_OUTPUT_POWER 22 // dBm -#define LORA_BANDWIDTH 0 // [0: 125 kHz, 1: 250 kHz, 2: 500 kHz, 3: Reserved] +#define TX_OUTPUT_POWER 22 // dBm +#define LORA_BANDWIDTH 0 // [0: 125 kHz, 1: 250 kHz, 2: 500 kHz, 3: Reserved] #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] -#define LORA_CODINGRATE 1 // [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] +#define LORA_CODINGRATE 1 // [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx #define LORA_SYMBOL_TIMEOUT 0 // Symbols #define LORA_FIX_LENGTH_PAYLOAD_ON false @@ -91,362 +102,393 @@ uint8_t pongCnt = 0; void setup() { - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - - // Define the HW configuration between MCU and SX126x - hwConfig.CHIP_TYPE = SX1262_CHIP; // Example uses an eByte E22 module with an SX1262 - hwConfig.PIN_LORA_RESET = PIN_LORA_RESET; // LORA RESET - hwConfig.PIN_LORA_NSS = PIN_LORA_NSS; // LORA SPI CS - hwConfig.PIN_LORA_SCLK = PIN_LORA_SCLK; // LORA SPI CLK - hwConfig.PIN_LORA_MISO = PIN_LORA_MISO; // LORA SPI MISO - hwConfig.PIN_LORA_DIO_1 = PIN_LORA_DIO_1; // LORA DIO_1 - hwConfig.PIN_LORA_BUSY = PIN_LORA_BUSY; // LORA SPI BUSY - hwConfig.PIN_LORA_MOSI = PIN_LORA_MOSI; // LORA SPI MOSI - hwConfig.RADIO_TXEN = RADIO_TXEN; // LORA ANTENNA TX ENABLE - hwConfig.RADIO_RXEN = RADIO_RXEN; // LORA ANTENNA RX ENABLE - hwConfig.USE_DIO2_ANT_SWITCH = false; // Example uses an eByte E22 module which uses RXEN and TXEN pins as antenna control - hwConfig.USE_DIO3_TCXO = true; // Example uses an eByte E22 module which uses DIO3 to control oscillator voltage - hwConfig.USE_DIO3_ANT_SWITCH = false; // Only Insight ISP4520 module uses DIO3 as antenna control - - // Initialize Serial for debug output - Serial.begin(115200); - - Serial.println("====================================="); - Serial.println("SX126x PingPong test"); - Serial.println("====================================="); + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + // Define the HW configuration between MCU and SX126x + hwConfig.CHIP_TYPE = SX1262_CHIP; // Example uses an eByte E22 module with an SX1262 + hwConfig.PIN_LORA_RESET = PIN_LORA_RESET; // LORA RESET + hwConfig.PIN_LORA_NSS = PIN_LORA_NSS; // LORA SPI CS + hwConfig.PIN_LORA_SCLK = PIN_LORA_SCLK; // LORA SPI CLK + hwConfig.PIN_LORA_MISO = PIN_LORA_MISO; // LORA SPI MISO + hwConfig.PIN_LORA_DIO_1 = PIN_LORA_DIO_1; // LORA DIO_1 + hwConfig.PIN_LORA_BUSY = PIN_LORA_BUSY; // LORA SPI BUSY + hwConfig.PIN_LORA_MOSI = PIN_LORA_MOSI; // LORA SPI MOSI + hwConfig.RADIO_TXEN = RADIO_TXEN; // LORA ANTENNA TX ENABLE + hwConfig.RADIO_RXEN = RADIO_RXEN; // LORA ANTENNA RX ENABLE + hwConfig.USE_DIO2_ANT_SWITCH = false; // Example uses an eByte E22 module which uses RXEN and TXEN pins as antenna control + hwConfig.USE_DIO3_TCXO = true; // Example uses an eByte E22 module which uses DIO3 to control oscillator voltage + hwConfig.USE_DIO3_ANT_SWITCH = false; // Only Insight ISP4520 module uses DIO3 as antenna control + + // Initialize Serial for debug output + Serial.begin(115200); + + Serial.println("====================================="); + Serial.println("SX126x PingPong test"); + Serial.println("====================================="); #ifdef NRF52 - pinMode(30, OUTPUT); - digitalWrite(30, HIGH); - // Start BLE if we compile for nRF52 - initBLE(); + Serial.println("MCU Nordic nRF52832"); + pinMode(30, OUTPUT); + digitalWrite(30, HIGH); + // Start BLE if we compile for nRF52 + initBLE(); +#endif +#ifdef ESP32 + Serial.println("MCU Espressif ESP32"); +#endif +#ifdef ESP8266 + Serial.println("MCU Espressif ESP8266"); #endif - // Initialize the LoRa chip - Serial.println("Starting lora_hardware_init"); - lora_hardware_init(hwConfig); - - // Initialize the Radio callbacks - RadioEvents.TxDone = OnTxDone; - RadioEvents.RxDone = OnRxDone; - RadioEvents.TxTimeout = OnTxTimeout; - RadioEvents.RxTimeout = OnRxTimeout; - RadioEvents.RxError = OnRxError; - RadioEvents.CadDone = OnCadDone; - - // Initialize the Radio - Radio.Init(&RadioEvents); - - // Set Radio channel - Radio.SetChannel(RF_FREQUENCY); - - // Set Radio TX configuration - Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, - LORA_SPREADING_FACTOR, LORA_CODINGRATE, - LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, - true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE); - - // Set Radio RX configuration - Radio.SetRxConfig(MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, - LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, - LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, - 0, true, 0, 0, LORA_IQ_INVERSION_ON, true); - - // Start LoRa - Serial.println("Starting Radio.Rx"); - Radio.Rx(RX_TIMEOUT_VALUE); - - timeToSend = millis(); + uint8_t deviceId[8]; + + BoardGetUniqueId(deviceId); + Serial.printf("BoardId: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n", + deviceId[7], + deviceId[6], + deviceId[5], + deviceId[4], + deviceId[3], + deviceId[2], + deviceId[1], + deviceId[0]); + + // Initialize the LoRa chip + Serial.println("Starting lora_hardware_init"); + lora_hardware_init(hwConfig); + + // Initialize the Radio callbacks + RadioEvents.TxDone = OnTxDone; + RadioEvents.RxDone = OnRxDone; + RadioEvents.TxTimeout = OnTxTimeout; + RadioEvents.RxTimeout = OnRxTimeout; + RadioEvents.RxError = OnRxError; + RadioEvents.CadDone = OnCadDone; + + // Initialize the Radio + Radio.Init(&RadioEvents); + + // Set Radio channel + Radio.SetChannel(RF_FREQUENCY); + + // Set Radio TX configuration + Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, + LORA_SPREADING_FACTOR, LORA_CODINGRATE, + LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, + true, 0, 0, LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE); + + // Set Radio RX configuration + Radio.SetRxConfig(MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, + LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, + LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, + 0, true, 0, 0, LORA_IQ_INVERSION_ON, true); + + // Start LoRa + Serial.println("Starting Radio.Rx"); + Radio.Rx(RX_TIMEOUT_VALUE); + + timeToSend = millis(); } void loop() { - // Handle Radio events - Radio.IrqProcess(); + // Handle Radio events + Radio.IrqProcess(); + + // We are on FreeRTOS, give other tasks a chance to run + delay(100); + yield(); } /**@brief Function to be executed on Radio Tx Done event */ void OnTxDone(void) { - Serial.println("OnTxDone"); + Serial.println("OnTxDone"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnTxDone\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnTxDone\n"); + } #endif - Radio.Rx(RX_TIMEOUT_VALUE); + Radio.Rx(RX_TIMEOUT_VALUE); } /**@brief Function to be executed on Radio Rx Done event */ void OnRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) { - Serial.println("OnRxDone"); + Serial.println("OnRxDone"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnRxDone\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnRxDone\n"); + } #endif - delay(10); - BufferSize = size; - memcpy(RcvBuffer, payload, BufferSize); + delay(10); + BufferSize = size; + memcpy(RcvBuffer, payload, BufferSize); + + Serial.printf("RssiValue=%d dBm, SnrValue=%d\n", rssi, snr); + + for (int idx = 0; idx < size; idx++) + { + Serial.printf("%02X ", RcvBuffer[idx]); + } + Serial.println(""); - Serial.printf("RssiValue=%d dBm, SnrValue=%d\n", rssi, snr); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.printf("RssiValue=%d dBm, SnrValue=%d\n", rssi, snr); - } + if (bleUARTisConnected) + { + bleuart.printf("RssiValue=%d dBm, SnrValue=%d\n", rssi, snr); + } #endif - digitalWrite(LED_BUILTIN, HIGH); - - if (isMaster == true) - { - if (BufferSize > 0) - { - if (strncmp((const char *)RcvBuffer, (const char *)PongMsg, 4) == 0) - { - Serial.println("Received a PONG in OnRxDone as Master"); + digitalWrite(LED_BUILTIN, HIGH); + + if (isMaster == true) + { + if (BufferSize > 0) + { + if (strncmp((const char *)RcvBuffer, (const char *)PongMsg, 4) == 0) + { + Serial.println("Received a PONG in OnRxDone as Master"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Received a PONG in OnRxDone as Master\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Received a PONG in OnRxDone as Master\n"); + } #endif - // Wait 500ms before sending the next package - delay(500); - - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending next Ping will be started when the channel is free - } - else if (strncmp((const char *)RcvBuffer, (const char *)PingMsg, 4) == 0) - { // A master already exists then become a slave - Serial.println("Received a PING in OnRxDone as Master"); + // Wait 500ms before sending the next package + delay(500); + + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending next Ping will be started when the channel is free + } + else if (strncmp((const char *)RcvBuffer, (const char *)PingMsg, 4) == 0) + { // A master already exists then become a slave + Serial.println("Received a PING in OnRxDone as Master"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Received a PING in OnRxDone as Master\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Received a PING in OnRxDone as Master\n"); + } #endif - isMaster = false; - Radio.Rx(RX_TIMEOUT_VALUE); - } - else // valid reception but neither a PING or a PONG message - { // Set device as master and start again - isMaster = true; - Radio.Rx(RX_TIMEOUT_VALUE); - } - } - } - else - { - if (BufferSize > 0) - { - if (strncmp((const char *)RcvBuffer, (const char *)PingMsg, 4) == 0) - { - Serial.println("Received a PING in OnRxDone as Slave"); + isMaster = false; + Radio.Rx(RX_TIMEOUT_VALUE); + } + else // valid reception but neither a PING or a PONG message + { // Set device as master and start again + isMaster = true; + Radio.Rx(RX_TIMEOUT_VALUE); + } + } + } + else + { + if (BufferSize > 0) + { + if (strncmp((const char *)RcvBuffer, (const char *)PingMsg, 4) == 0) + { + Serial.println("Received a PING in OnRxDone as Slave"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Received a PING in OnRxDone as Slave\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Received a PING in OnRxDone as Slave\n"); + } #endif - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending Pong will be started when the channel is free - } - else // valid reception but not a PING as expected - { // Set device as master and start again - Serial.println("Received something in OnRxDone as Slave"); + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending Pong will be started when the channel is free + } + else // valid reception but not a PING as expected + { // Set device as master and start again + Serial.println("Received something in OnRxDone as Slave"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Received something in OnRxDone as Slave\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Received something in OnRxDone as Slave\n"); + } #endif - isMaster = true; - Radio.Rx(RX_TIMEOUT_VALUE); - } - } - } + isMaster = true; + Radio.Rx(RX_TIMEOUT_VALUE); + } + } + } } /**@brief Function to be executed on Radio Tx Timeout event */ void OnTxTimeout(void) { - // Radio.Sleep(); - Serial.println("OnTxTimeout"); + // Radio.Sleep(); + Serial.println("OnTxTimeout"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnTxTimeout\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnTxTimeout\n"); + } #endif - digitalWrite(LED_BUILTIN, LOW); + digitalWrite(LED_BUILTIN, LOW); - Radio.Rx(RX_TIMEOUT_VALUE); + Radio.Rx(RX_TIMEOUT_VALUE); } /**@brief Function to be executed on Radio Rx Timeout event */ void OnRxTimeout(void) { - Serial.println("OnRxTimeout"); + Serial.println("OnRxTimeout"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnRxTimeout\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnRxTimeout\n"); + } #endif - digitalWrite(LED_BUILTIN, LOW); - - if (isMaster == true) - { - // Wait 500ms before sending the next package - delay(500); - - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending the ping will be started when the channel is free - } - else - { - // No Ping received within timeout, switch to Master - isMaster = true; - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending the ping will be started when the channel is free - // Radio.Rx(RX_TIMEOUT_VALUE); - } + + digitalWrite(LED_BUILTIN, LOW); + + if (isMaster == true) + { + // Wait 500ms before sending the next package + delay(500); + + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending the ping will be started when the channel is free + } + else + { + // No Ping received within timeout, switch to Master + isMaster = true; + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending the ping will be started when the channel is free + } } /**@brief Function to be executed on Radio Rx Error event */ void OnRxError(void) { - Serial.println("OnRxError"); + Serial.println("OnRxError"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("OnRxError\n"); - } + if (bleUARTisConnected) + { + bleuart.print("OnRxError\n"); + } #endif - digitalWrite(LED_BUILTIN, LOW); - - if (isMaster == true) - { - // Wait 500ms before sending the next package - delay(500); - - // Check if our channel is available for sending - Radio.Standby(); - SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); - SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, - IRQ_RADIO_NONE, IRQ_RADIO_NONE); - cadTime = millis(); - Radio.StartCad(); - // Sending the ping will be started when the channel is free - } - else - { - Radio.Rx(RX_TIMEOUT_VALUE); - } + digitalWrite(LED_BUILTIN, LOW); + + if (isMaster == true) + { + // Wait 500ms before sending the next package + delay(500); + + // Check if our channel is available for sending + Radio.Standby(); + SX126xSetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + SX126xSetDioIrqParams(IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, + IRQ_RADIO_NONE, IRQ_RADIO_NONE); + cadTime = millis(); + Radio.StartCad(); + // Sending the ping will be started when the channel is free + } + else + { + Radio.Rx(RX_TIMEOUT_VALUE); + } } /**@brief Function to be executed on Radio Rx Error event */ void OnCadDone(bool cadResult) { - time_t duration = millis() - cadTime; - if (cadResult) - { - Serial.printf("CAD returned channel busy after %ldms\n", duration); + time_t duration = millis() - cadTime; + if (cadResult) + { + Serial.printf("CAD returned channel busy after %ldms\n", duration); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.printf("CAD returned channel busy after %ldms\n", duration); - } + if (bleUARTisConnected) + { + bleuart.printf("CAD returned channel busy after %ldms\n", duration); + } #endif - Radio.Rx(RX_TIMEOUT_VALUE); - } - else - { - Serial.printf("CAD returned channel free after %ldms\n", duration); + Radio.Rx(RX_TIMEOUT_VALUE); + } + else + { + Serial.printf("CAD returned channel free after %ldms\n", duration); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.printf("CAD returned channel free after %ldms\n", duration); - } + if (bleUARTisConnected) + { + bleuart.printf("CAD returned channel free after %ldms\n", duration); + } #endif - if (isMaster) - { - Serial.println("Sending a PING in OnCadDone as Master"); + if (isMaster) + { + Serial.println("Sending a PING in OnCadDone as Master"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Sending a PING in OnCadDone as Master\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Sending a PING in OnCadDone as Master\n"); + } #endif - // Send the next PING frame - TxdBuffer[0] = 'P'; - TxdBuffer[1] = 'I'; - TxdBuffer[2] = 'N'; - TxdBuffer[3] = 'G'; - } - else - { - Serial.println("Sending a PONG in OnCadDone as Slave"); + // Send the next PING frame + TxdBuffer[0] = 'P'; + TxdBuffer[1] = 'I'; + TxdBuffer[2] = 'N'; + TxdBuffer[3] = 'G'; + } + else + { + Serial.println("Sending a PONG in OnCadDone as Slave"); #ifdef NRF52 - if (bleUARTisConnected) - { - bleuart.print("Sending a PONG in OnCadDone as Slave\n"); - } + if (bleUARTisConnected) + { + bleuart.print("Sending a PONG in OnCadDone as Slave\n"); + } #endif - // Send the reply to the PONG string - TxdBuffer[0] = 'P'; - TxdBuffer[1] = 'O'; - TxdBuffer[2] = 'N'; - TxdBuffer[3] = 'G'; - } - // We fill the buffer with numbers for the payload - for (int i = 4; i < BufferSize; i++) - { - TxdBuffer[i] = i - 4; - } - - Radio.Send(TxdBuffer, BufferSize); - } + // Send the reply to the PONG string + TxdBuffer[0] = 'P'; + TxdBuffer[1] = 'O'; + TxdBuffer[2] = 'N'; + TxdBuffer[3] = 'G'; + } + // We fill the buffer with numbers for the payload + for (int i = 4; i < BufferSize; i++) + { + TxdBuffer[i] = i - 4; + } + + Radio.Send(TxdBuffer, BufferSize); + } } diff --git a/keywords.txt b/keywords.txt index a7e7797..385c81b 100644 --- a/keywords.txt +++ b/keywords.txt @@ -77,9 +77,6 @@ SX126xGetDeviceErrors KEYWORD1 SX126xClearDeviceErrors KEYWORD1 SX126xClearIrqStatus KEYWORD1 -Delay KEYWORD1 -DelayMs KEYWORD1 - ####################################### # Methods and Functions (KEYWORD2) Radio ####################################### diff --git a/library.properties b/library.properties index bc6dd5b..96123e7 100644 --- a/library.properties +++ b/library.properties @@ -3,7 +3,7 @@ version=1.0.0 author=Bernd Giesecke maintainer=Bernd Giesecke sentence=Arduino library to use Semtech SX126x LoRa chips and modules to communicate -paragraph=This library is for LoRa communication with Semtech SX126x chips. It is based on Semtech`s SX126x libraries and adapted to the Arduino framework for ESP32. It will not work with other uC`s like AVR or Espressif 8266 (yet). +paragraph=This library is for LoRa communication with Semtech SX126x chips. It is based on Semtech`s SX126x libraries and adapted to the Arduino framework for ESP32, ESP8266 and Nordic nRF52832. It will not work with other uC`s like AVR. category=Communication -url=https://github.com/beegee-tokyo/SX126x-ESP32/ -architectures=esp32,nrf52 \ No newline at end of file +url=https://github.com/beegee-tokyo/SX126x-Arduino/ +architectures=esp32,nrf52,esp8266 \ No newline at end of file diff --git a/src/boards/mcu/board.cpp b/src/boards/mcu/board.cpp index ffea3e5..a05e0ec 100644 --- a/src/boards/mcu/board.cpp +++ b/src/boards/mcu/board.cpp @@ -37,7 +37,7 @@ Maintainer: Miguel Luis and Gregory Cristian extern "C" { -hw_config _hwConfig; + hw_config _hwConfig; /**@brief Unique Devices IDs register set (nRF52) */ @@ -46,18 +46,18 @@ hw_config _hwConfig; uint32_t lora_hardware_init(hw_config hwConfig) { - _hwConfig.CHIP_TYPE = hwConfig.CHIP_TYPE; // Chip type, SX1261 or SX1262 - _hwConfig.PIN_LORA_RESET = hwConfig.PIN_LORA_RESET; // LORA RESET - _hwConfig.PIN_LORA_NSS = hwConfig.PIN_LORA_NSS; // LORA SPI CS - _hwConfig.PIN_LORA_SCLK = hwConfig.PIN_LORA_SCLK; // LORA SPI CLK - _hwConfig.PIN_LORA_MISO = hwConfig.PIN_LORA_MISO; // LORA SPI MISO - _hwConfig.PIN_LORA_DIO_1 = hwConfig.PIN_LORA_DIO_1; // LORA DIO_1 - _hwConfig.PIN_LORA_BUSY = hwConfig.PIN_LORA_BUSY; // LORA SPI BUSY - _hwConfig.PIN_LORA_MOSI = hwConfig.PIN_LORA_MOSI; // LORA SPI MOSI - _hwConfig.RADIO_TXEN = hwConfig.RADIO_TXEN; // LORA ANTENNA TX ENABLE (e.g. eByte E22 module) - _hwConfig.RADIO_RXEN = hwConfig.RADIO_RXEN; // LORA ANTENNA RX ENABLE (e.g. eByte E22 module) - _hwConfig.USE_DIO2_ANT_SWITCH = hwConfig.USE_DIO2_ANT_SWITCH; // LORA DIO2 controls antenna - _hwConfig.USE_DIO3_TCXO = hwConfig.USE_DIO3_TCXO; // LORA DIO3 controls oscillator voltage (e.g. eByte E22 module) + _hwConfig.CHIP_TYPE = hwConfig.CHIP_TYPE; // Chip type, SX1261 or SX1262 + _hwConfig.PIN_LORA_RESET = hwConfig.PIN_LORA_RESET; // LORA RESET + _hwConfig.PIN_LORA_NSS = hwConfig.PIN_LORA_NSS; // LORA SPI CS + _hwConfig.PIN_LORA_SCLK = hwConfig.PIN_LORA_SCLK; // LORA SPI CLK + _hwConfig.PIN_LORA_MISO = hwConfig.PIN_LORA_MISO; // LORA SPI MISO + _hwConfig.PIN_LORA_DIO_1 = hwConfig.PIN_LORA_DIO_1; // LORA DIO_1 + _hwConfig.PIN_LORA_BUSY = hwConfig.PIN_LORA_BUSY; // LORA SPI BUSY + _hwConfig.PIN_LORA_MOSI = hwConfig.PIN_LORA_MOSI; // LORA SPI MOSI + _hwConfig.RADIO_TXEN = hwConfig.RADIO_TXEN; // LORA ANTENNA TX ENABLE (e.g. eByte E22 module) + _hwConfig.RADIO_RXEN = hwConfig.RADIO_RXEN; // LORA ANTENNA RX ENABLE (e.g. eByte E22 module) + _hwConfig.USE_DIO2_ANT_SWITCH = hwConfig.USE_DIO2_ANT_SWITCH; // LORA DIO2 controls antenna + _hwConfig.USE_DIO3_TCXO = hwConfig.USE_DIO3_TCXO; // LORA DIO3 controls oscillator voltage (e.g. eByte E22 module) _hwConfig.USE_DIO3_ANT_SWITCH = hwConfig.USE_DIO3_ANT_SWITCH; // LORA DIO3 controls antenna (e.g. Insight SIP ISP4520 module) TimerConfig(); diff --git a/src/boards/mcu/board.h b/src/boards/mcu/board.h index a354712..a1fc55a 100644 --- a/src/boards/mcu/board.h +++ b/src/boards/mcu/board.h @@ -45,8 +45,6 @@ Maintainer: Miguel Luis and Gregory Cristian #include #include -#include "system/delay.h" - #include "radio/radio.h" #include "radio/sx126x/sx126x.h" #include "boards/sx126x/sx126x-board.h" @@ -58,26 +56,27 @@ Maintainer: Miguel Luis and Gregory Cristian #define SX1268_CHIP 2 // Microcontroller - SX126x pin configuration -struct hw_config { - int CHIP_TYPE = SX1262_CHIP; // Module type, see defines above - int PIN_LORA_RESET; // LORA RESET - int PIN_LORA_NSS; // LORA SPI CS - int PIN_LORA_SCLK; // LORA SPI CLK - int PIN_LORA_MISO; // LORA SPI MISO - int PIN_LORA_DIO_1; // LORA DIO_1 - int PIN_LORA_BUSY; // LORA SPI BUSY - int PIN_LORA_MOSI; // LORA SPI MOSI - int RADIO_TXEN = -1; // LORA ANTENNA TX ENABLE (eByte E22 module only) - int RADIO_RXEN = -1; // LORA ANTENNA RX ENABLE (eByte E22 module only) +struct hw_config +{ + int CHIP_TYPE = SX1262_CHIP; // Module type, see defines above + int PIN_LORA_RESET; // LORA RESET + int PIN_LORA_NSS; // LORA SPI CS + int PIN_LORA_SCLK; // LORA SPI CLK + int PIN_LORA_MISO; // LORA SPI MISO + int PIN_LORA_DIO_1; // LORA DIO_1 + int PIN_LORA_BUSY; // LORA SPI BUSY + int PIN_LORA_MOSI; // LORA SPI MOSI + int RADIO_TXEN = -1; // LORA ANTENNA TX ENABLE (eByte E22 module only) + int RADIO_RXEN = -1; // LORA ANTENNA RX ENABLE (eByte E22 module only) bool USE_DIO2_ANT_SWITCH = false; // Whether DIO2 is used to control the antenna - bool USE_DIO3_TCXO = false; // Whether DIO3 is used to control the oscillator + bool USE_DIO3_TCXO = false; // Whether DIO3 is used to control the oscillator bool USE_DIO3_ANT_SWITCH = false; // Whether DIO2 is used to control the antenna }; extern "C" { -extern hw_config _hwConfig; + extern hw_config _hwConfig; /**@brief Initializes the target board peripherals. */ diff --git a/src/boards/mcu/esp32/spi_board.cpp b/src/boards/mcu/esp32/spi_board.cpp deleted file mode 100644 index e59f398..0000000 --- a/src/boards/mcu/esp32/spi_board.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#ifdef ESP32 -#include -#include "boards/mcu/board.h" - -SPIClass SPI_LORA; - -void initSPI(void) -{ - SPI_LORA.begin(_hwConfig.PIN_LORA_SCLK, _hwConfig.PIN_LORA_MISO, _hwConfig.PIN_LORA_MOSI, _hwConfig.PIN_LORA_NSS); -} -#endif \ No newline at end of file diff --git a/src/boards/mcu/esp32/board.cpp b/src/boards/mcu/espressif/board.cpp similarity index 69% rename from src/boards/mcu/esp32/board.cpp rename to src/boards/mcu/espressif/board.cpp index 39a2900..e7c0c19 100644 --- a/src/boards/mcu/esp32/board.cpp +++ b/src/boards/mcu/espressif/board.cpp @@ -33,7 +33,7 @@ Maintainer: Miguel Luis and Gregory Cristian * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ -#ifdef ESP32 +#if defined ESP32 || defined ESP8266 #include "boards/mcu/board.h" extern "C" { @@ -44,15 +44,29 @@ extern "C" void BoardGetUniqueId(uint8_t *id) { - //TO BE IMPLEMENTED - id[7] = 8; - id[6] = 7; - id[5] = 6; - id[4] = 5; - id[3] = 4; - id[2] = 3; - id[1] = 2; - id[0] = 1; +#ifdef ESP8266 + uint32_t uniqueId = ESP.getChipId(); + // Using ESP8266 chip ID (32 bytes only, so we use it twice + id[7] = (uint8_t)(uniqueId >> 24); + id[6] = (uint8_t)(uniqueId >> 16); + id[5] = (uint8_t)(uniqueId >> 8); + id[4] = (uint8_t)(uniqueId); + id[3] = (uint8_t)(uniqueId >> 24); + id[2] = (uint8_t)(uniqueId >> 16); + id[1] = (uint8_t)(uniqueId >> 8); + id[0] = (uint8_t)(uniqueId); +#else + uint64_t uniqueId = ESP.getEfuseMac(); + // Using ESP32 MAC (48 bytes only, so upper 2 bytes will be 0) + id[7] = (uint8_t)(uniqueId >> 56); + id[6] = (uint8_t)(uniqueId >> 48); + id[5] = (uint8_t)(uniqueId >> 40); + id[4] = (uint8_t)(uniqueId >> 32); + id[3] = (uint8_t)(uniqueId >> 24); + id[2] = (uint8_t)(uniqueId >> 16); + id[1] = (uint8_t)(uniqueId >> 8); + id[0] = (uint8_t)(uniqueId); +#endif } uint8_t BoardGetBatteryLevel(void) @@ -64,16 +78,21 @@ extern "C" return batteryLevel; } +#ifdef ESP32 portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; - +#endif void BoardDisableIrq(void) { +#ifdef ESP32 portENTER_CRITICAL(&mux); +#endif } void BoardEnableIrq(void) { +#ifdef ESP32 portEXIT_CRITICAL(&mux); +#endif } }; #endif \ No newline at end of file diff --git a/src/boards/mcu/espressif/spi_board.cpp b/src/boards/mcu/espressif/spi_board.cpp new file mode 100644 index 0000000..c54c2b1 --- /dev/null +++ b/src/boards/mcu/espressif/spi_board.cpp @@ -0,0 +1,15 @@ +#if defined ESP8266 || defined ESP32 +#include +#include "boards/mcu/board.h" + +SPIClass SPI_LORA; + +void initSPI(void) +{ +#ifdef ESP8266 + SPI_LORA.begin(); +#else + SPI_LORA.begin(_hwConfig.PIN_LORA_SCLK, _hwConfig.PIN_LORA_MISO, _hwConfig.PIN_LORA_MOSI, _hwConfig.PIN_LORA_NSS); +#endif +} +#endif \ No newline at end of file diff --git a/src/boards/mcu/esp32/spi_board.h b/src/boards/mcu/espressif/spi_board.h similarity index 100% rename from src/boards/mcu/esp32/spi_board.h rename to src/boards/mcu/espressif/spi_board.h diff --git a/src/boards/mcu/esp32/timer.cpp b/src/boards/mcu/espressif/timer.cpp similarity index 96% rename from src/boards/mcu/esp32/timer.cpp rename to src/boards/mcu/espressif/timer.cpp index 45583db..5666b5c 100644 --- a/src/boards/mcu/esp32/timer.cpp +++ b/src/boards/mcu/espressif/timer.cpp @@ -33,7 +33,7 @@ Maintainer: Miguel Luis, Gregory Cristian and Wael Guibene * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ -#ifdef ESP32 +#if defined ESP8266 || defined ESP32 #include "boards/mcu/timer.h" #include "boards/mcu/board.h" @@ -44,7 +44,6 @@ extern "C" uint32_t timerTimes[10]; bool timerInUse[10] = {false, false, false, false, false, false, false, false, false, false}; - // External functions void TimerConfig(void) @@ -61,7 +60,7 @@ extern "C" { timerInUse[idx] = true; obj->timerNum = idx; - obj->Callback = callback; + obj->Callback = callback; return; } } @@ -76,7 +75,8 @@ extern "C" void TimerStart(TimerEvent_t *obj) { int idx = obj->timerNum; - if (obj->oneShot){ + if (obj->oneShot) + { timerTickers[idx].once_ms(timerTimes[idx], obj->Callback); } else @@ -89,21 +89,20 @@ extern "C" { int idx = obj->timerNum; timerTickers[idx].detach(); - } void TimerReset(TimerEvent_t *obj) { int idx = obj->timerNum; timerTickers[idx].detach(); - if (obj->oneShot){ + if (obj->oneShot) + { timerTickers[idx].once_ms(timerTimes[idx], obj->Callback); } else { timerTickers[idx].attach_ms(timerTimes[idx], obj->Callback); } - } void TimerSetValue(TimerEvent_t *obj, uint32_t value) diff --git a/src/boards/mcu/nrf52832/spi_board.cpp b/src/boards/mcu/nrf52832/spi_board.cpp index 91d008d..062bb89 100644 --- a/src/boards/mcu/nrf52832/spi_board.cpp +++ b/src/boards/mcu/nrf52832/spi_board.cpp @@ -10,7 +10,7 @@ extern SPIClass SPI_LORA; void initSPI(void) { - // SPI_LORA.begin(NRF_SPI2, _hwConfig.PIN_LORA_MISO, _hwConfig.PIN_LORA_SCLK, _hwConfig.PIN_LORA_MOSI); - SPI_LORA.begin(); + // SPI_LORA.begin(NRF_SPI2, _hwConfig.PIN_LORA_MISO, _hwConfig.PIN_LORA_SCLK, _hwConfig.PIN_LORA_MOSI); + SPI_LORA.begin(); } #endif \ No newline at end of file diff --git a/src/boards/mcu/nrf52832/timer.cpp b/src/boards/mcu/nrf52832/timer.cpp index 61dc5df..69b4ff2 100644 --- a/src/boards/mcu/nrf52832/timer.cpp +++ b/src/boards/mcu/nrf52832/timer.cpp @@ -40,7 +40,7 @@ Maintainer: Miguel Luis, Gregory Cristian and Wael Guibene extern "C" { -#define TIMER_RTC2_PRESCALER 31 /**< Prescaler for the RTC Timer */ +#define TIMER_RTC2_PRESCALER 31 /**< Prescaler for the RTC Timer */ #define TIMER_RTC2_CLOCK_FREQ 32768 /**< Clock frequency of the RTC timer. */ /**@brief Convert ticks to timer milliseconds. (tick * 32000 / 32768) @@ -50,9 +50,9 @@ extern "C" * @return milliseconds. */ #define TICKS_TO_MS(TICKS) \ - ((uint32_t)ROUNDED_DIV( \ - (TICKS) * ((uint64_t)(1000 * (TIMER_RTC2_PRESCALER + 1))), \ - (uint64_t)TIMER_RTC2_CLOCK_FREQ)) + ((uint32_t)ROUNDED_DIV( \ + (TICKS) * ((uint64_t)(1000 * (TIMER_RTC2_PRESCALER + 1))), \ + (uint64_t)TIMER_RTC2_CLOCK_FREQ)) /**@brief Convert timer milliseconds to ticks. (tick * 32768 / 32000) * @@ -61,396 +61,396 @@ extern "C" * @return ticks. */ #define MS_TO_TICKS(MS) \ - ((uint32_t)ROUNDED_DIV( \ - (MS) * ((uint64_t)TIMER_RTC2_CLOCK_FREQ), \ - 1000 * (TIMER_RTC2_PRESCALER + 1))) + ((uint32_t)ROUNDED_DIV( \ + (MS) * ((uint64_t)TIMER_RTC2_CLOCK_FREQ), \ + 1000 * (TIMER_RTC2_PRESCALER + 1))) - TimerTime_t m_rtc_reference_time; /**< Reference time */ + TimerTime_t m_rtc_reference_time; /**< Reference time */ - /** Timers list head pointer + /** Timers list head pointer */ - static TimerEvent_t *TimerListHead = NULL; + static TimerEvent_t *TimerListHead = NULL; - /**@brief returns the wake up time in ticks + /**@brief returns the wake up time in ticks * @retval wake up time in ticks */ - static uint32_t RTC2_GetMinimumTimeout(void) - { - return 3; - } + static uint32_t RTC2_GetMinimumTimeout(void) + { + return 3; + } - /**@brief Get the RTC timer elapsed time since the reference time + /**@brief Get the RTC timer elapsed time since the reference time * * @retval RTC Elapsed time in ticks */ - static uint32_t RTC2_GetTimerElapsedTime(void) - { - TimerTime_t now_in_ticks = NRF_RTC2->COUNTER; - return (now_in_ticks - m_rtc_reference_time); - } + static uint32_t RTC2_GetTimerElapsedTime(void) + { + TimerTime_t now_in_ticks = NRF_RTC2->COUNTER; + return (now_in_ticks - m_rtc_reference_time); + } - /**@brief Get the RTC2 Counter value + /**@brief Get the RTC2 Counter value * * @retval RTC2 COUNTER */ - static uint32_t RTC2_GetCounterReg(void) - { - return NRF_RTC2->COUNTER; - } + static uint32_t RTC2_GetCounterReg(void) + { + return NRF_RTC2->COUNTER; + } - /**@brief Set value in the CC[0] register + /**@brief Set value in the CC[0] register * * @details The CC[0] is set at now (read in this funtion) + timeout, once the COUNTER * reaches this value, an interrupt is triggered * * @param timeout Duration of the Timer ticks */ - static void RTC2_SetCompareReg(uint32_t timeout) - { - TimerTime_t now = NRF_RTC2->COUNTER; - NRF_RTC2->CC[0] = now + timeout; - } + static void RTC2_SetCompareReg(uint32_t timeout) + { + TimerTime_t now = NRF_RTC2->COUNTER; + NRF_RTC2->CC[0] = now + timeout; + } - /**@brief Check if the input timer object exists + /**@brief Check if the input timer object exists * * @param [IN] obj Structure containing the timer object parameters * * @retval true is it exists, false otherwise */ - static bool TimerExists(TimerEvent_t *obj) - { - TimerEvent_t *cur = TimerListHead; - - while (cur != NULL) - { - if (cur == obj) - { - return true; - } - cur = cur->Next; - } - return false; - } - - /**@brief Sets a timeout of an timer obj + static bool TimerExists(TimerEvent_t *obj) + { + TimerEvent_t *cur = TimerListHead; + + while (cur != NULL) + { + if (cur == obj) + { + return true; + } + cur = cur->Next; + } + return false; + } + + /**@brief Sets a timeout of an timer obj * * @param [IN] obj Structure containing the timer object parameters */ - static void TimerSetTimeout(TimerEvent_t *obj) - { - int32_t minTicks = RTC2_GetMinimumTimeout(); - obj->IsRunning = true; - - //in case deadline too soon - if (obj->Timestamp < (RTC2_GetTimerElapsedTime() + minTicks)) - { - obj->Timestamp = RTC2_GetTimerElapsedTime() + minTicks; - } - RTC2_SetCompareReg(obj->Timestamp); - } - - /**@brief Adds or replace the head timer of the list. + static void TimerSetTimeout(TimerEvent_t *obj) + { + int32_t minTicks = RTC2_GetMinimumTimeout(); + obj->IsRunning = true; + + //in case deadline too soon + if (obj->Timestamp < (RTC2_GetTimerElapsedTime() + minTicks)) + { + obj->Timestamp = RTC2_GetTimerElapsedTime() + minTicks; + } + RTC2_SetCompareReg(obj->Timestamp); + } + + /**@brief Adds or replace the head timer of the list. * * @remark The list is automatically sorted. The list head always contains the next timer to expire. * * @param [IN] obj Timer object to be become the new head */ - static void TimerInsertNewHeadTimer(TimerEvent_t *obj) - { - TimerEvent_t *cur = TimerListHead; + static void TimerInsertNewHeadTimer(TimerEvent_t *obj) + { + TimerEvent_t *cur = TimerListHead; - if (cur != NULL) - { - cur->IsRunning = false; - } + if (cur != NULL) + { + cur->IsRunning = false; + } - obj->Next = cur; - TimerListHead = obj; - TimerSetTimeout(TimerListHead); - } + obj->Next = cur; + TimerListHead = obj; + TimerSetTimeout(TimerListHead); + } - /**@brief Adds a timer to the list. + /**@brief Adds a timer to the list. * * @remark The list is automatically sorted. The list head always contains the next timer to expire. * * @param [IN] obj Timer object to be added to the list */ - static void TimerInsertTimer(TimerEvent_t *obj) - { - TimerEvent_t *cur = TimerListHead; - TimerEvent_t *next = TimerListHead->Next; - - while (cur->Next != NULL) - { - if (obj->Timestamp > next->Timestamp) - { - cur = next; - next = next->Next; - } - else - { - cur->Next = obj; - obj->Next = next; - return; - } - } - cur->Next = obj; - obj->Next = NULL; - } - - /**@brief RTC2 IRQ + static void TimerInsertTimer(TimerEvent_t *obj) + { + TimerEvent_t *cur = TimerListHead; + TimerEvent_t *next = TimerListHead->Next; + + while (cur->Next != NULL) + { + if (obj->Timestamp > next->Timestamp) + { + cur = next; + next = next->Next; + } + else + { + cur->Next = obj; + obj->Next = next; + return; + } + } + cur->Next = obj; + obj->Next = NULL; + } + + /**@brief RTC2 IRQ * */ - void RTC2_IRQHandler(void) - { - // Clear all events (also unexpected ones) - NRF_RTC2->EVENTS_COMPARE[0] = 0; - NRF_RTC2->EVENTS_COMPARE[1] = 0; - NRF_RTC2->EVENTS_COMPARE[2] = 0; - NRF_RTC2->EVENTS_COMPARE[3] = 0; - NRF_RTC2->EVENTS_TICK = 0; - NRF_RTC2->EVENTS_OVRFLW = 0; - - TimerEvent_t *cur; - TimerEvent_t *next; - - uint32_t old = m_rtc_reference_time; - uint32_t now = RTC2_GetCounterReg(); - m_rtc_reference_time = now; - uint32_t delta = now - old; - - /* update timeStamp based upon new Time Reference*/ - if (TimerListHead != NULL) - { - for (cur = TimerListHead; cur->Next != NULL; cur = cur->Next) - { - next = cur->Next; - if (next->Timestamp > delta) - { - next->Timestamp -= delta; - } - else - { - next->Timestamp = 0; - } - } - } - - /* execute imediately the callback */ - if (TimerListHead != NULL) - { - cur = TimerListHead; - TimerListHead = TimerListHead->Next; - if (cur->Callback != NULL) - { - cur->Callback(); - } - } - - // remove all the expired object from the list - while ((TimerListHead != NULL) && (TimerListHead->Timestamp < RTC2_GetTimerElapsedTime())) - { - cur = TimerListHead; - TimerListHead = TimerListHead->Next; - if (cur->Callback != NULL) - { - cur->Callback(); - } - } - - /* start the next TimerListHead if it exists AND NOT running */ - if ((TimerListHead != NULL) && (TimerListHead->IsRunning == false)) - { - TimerSetTimeout(TimerListHead); - } - } - - // External functions - - void TimerConfig(void) - { - NRF_RTC2->PRESCALER = TIMER_RTC2_PRESCALER; - NVIC_SetPriority(RTC2_IRQn, 5); - - NRF_RTC2->EVTENSET = RTC_EVTEN_COMPARE0_Disabled; - NRF_RTC2->INTENSET = RTC_INTENSET_COMPARE0_Disabled; - - NVIC_ClearPendingIRQ(RTC2_IRQn); - NVIC_EnableIRQ(RTC2_IRQn); - - NRF_RTC2->TASKS_START = 1; - } - - void TimerInit(TimerEvent_t *obj, void (*callback)(void)) - { - obj->Timestamp = 0; - obj->ReloadValue = 0; - obj->IsRunning = false; - obj->Callback = callback; - obj->Next = NULL; - } - - void TimerStart(TimerEvent_t *obj) - { - uint32_t elapsedTime = 0; - - if ((obj == NULL) || (TimerExists(obj) == true)) - { - return; - } - - // CRITICAL_REGION_ENTER(); - - obj->Timestamp = obj->ReloadValue; - obj->IsRunning = false; - - // First obj in the list - if (TimerListHead == NULL) - { - // enable RTC2 CC[0] interrupts - NRF_RTC2->EVTENSET = RTC_EVTEN_COMPARE0_Msk; - NRF_RTC2->INTENSET = RTC_INTENSET_COMPARE0_Msk; - // Get reference time - m_rtc_reference_time = RTC2_GetCounterReg(); - - // insert a timeout at reference time + obj->Timestamp - TimerInsertNewHeadTimer(obj); - } - // Add obj to the list - else - { - elapsedTime = RTC2_GetTimerElapsedTime(); - obj->Timestamp += elapsedTime; - - if (obj->Timestamp < TimerListHead->Timestamp) - { - TimerInsertNewHeadTimer(obj); - } - else - { - TimerInsertTimer(obj); - } - } - - // CRITICAL_REGION_EXIT(); - } - - void TimerStop(TimerEvent_t *obj) - { - TimerEvent_t *prev = TimerListHead; - TimerEvent_t *cur = TimerListHead; - - // List is empty or the Obj to stop does not exist - if ((TimerListHead == NULL) || (obj == NULL)) - { - return; - } - - // CRITICAL_REGION_ENTER(); - - // Stop the Head - if (TimerListHead == obj) - { - // The head is already running - if (TimerListHead->IsRunning == true) - { - // If another obj is registered we switch to it - if (TimerListHead->Next != NULL) - { - TimerListHead->IsRunning = false; - TimerListHead = TimerListHead->Next; - TimerSetTimeout(TimerListHead); - } - // No other obj registered: we can disable interrupts - else - { - // Disable RTC2 CC[0] interrupt - NRF_RTC2->EVTENSET = RTC_EVTEN_COMPARE0_Disabled; - NRF_RTC2->INTENSET = RTC_INTENSET_COMPARE0_Disabled; - TimerListHead = NULL; - } - } - // Stop the head before it is started - else - { - if (TimerListHead->Next != NULL) - { - TimerListHead = TimerListHead->Next; - } - else - { - TimerListHead = NULL; - } - } - } - // Stop an object within the list - else - { - while (cur != NULL) - { - if (cur == obj) - { - if (cur->Next != NULL) - { - cur = cur->Next; - prev->Next = cur; - } - else - { - cur = NULL; - prev->Next = cur; - } - break; - } - else - { - prev = cur; - cur = cur->Next; - } - } - } - - // CRITICAL_REGION_EXIT(); - } - - void TimerReset(TimerEvent_t *obj) - { - TimerStop(obj); - TimerStart(obj); - } - - void TimerSetValue(TimerEvent_t *obj, uint32_t value) - { - uint32_t minValue = 0; - uint32_t ticks = MS_TO_TICKS(value); - - // APP_ERROR_CHECK_BOOL(obj!=NULL); - - TimerStop(obj); - - minValue = RTC2_GetMinimumTimeout(); - if (ticks < minValue) - { - ticks = minValue; - } - - obj->Timestamp = ticks; - obj->ReloadValue = ticks; - } - - TimerTime_t TimerGetCurrentTime(void) - { - uint32_t now = RTC2_GetCounterReg(); - return TICKS_TO_MS(now); - } - - TimerTime_t TimerGetElapsedTime(TimerTime_t past) - { - uint32_t nowInTicks = RTC2_GetCounterReg(); - uint32_t pastInTicks = MS_TO_TICKS(past); - TimerTime_t diff = TICKS_TO_MS((nowInTicks - pastInTicks) & 0x00FFFFFF); - - return diff; - } + void RTC2_IRQHandler(void) + { + // Clear all events (also unexpected ones) + NRF_RTC2->EVENTS_COMPARE[0] = 0; + NRF_RTC2->EVENTS_COMPARE[1] = 0; + NRF_RTC2->EVENTS_COMPARE[2] = 0; + NRF_RTC2->EVENTS_COMPARE[3] = 0; + NRF_RTC2->EVENTS_TICK = 0; + NRF_RTC2->EVENTS_OVRFLW = 0; + + TimerEvent_t *cur; + TimerEvent_t *next; + + uint32_t old = m_rtc_reference_time; + uint32_t now = RTC2_GetCounterReg(); + m_rtc_reference_time = now; + uint32_t delta = now - old; + + /* update timeStamp based upon new Time Reference*/ + if (TimerListHead != NULL) + { + for (cur = TimerListHead; cur->Next != NULL; cur = cur->Next) + { + next = cur->Next; + if (next->Timestamp > delta) + { + next->Timestamp -= delta; + } + else + { + next->Timestamp = 0; + } + } + } + + /* execute imediately the callback */ + if (TimerListHead != NULL) + { + cur = TimerListHead; + TimerListHead = TimerListHead->Next; + if (cur->Callback != NULL) + { + cur->Callback(); + } + } + + // remove all the expired object from the list + while ((TimerListHead != NULL) && (TimerListHead->Timestamp < RTC2_GetTimerElapsedTime())) + { + cur = TimerListHead; + TimerListHead = TimerListHead->Next; + if (cur->Callback != NULL) + { + cur->Callback(); + } + } + + /* start the next TimerListHead if it exists AND NOT running */ + if ((TimerListHead != NULL) && (TimerListHead->IsRunning == false)) + { + TimerSetTimeout(TimerListHead); + } + } + + // External functions + + void TimerConfig(void) + { + NRF_RTC2->PRESCALER = TIMER_RTC2_PRESCALER; + NVIC_SetPriority(RTC2_IRQn, 5); + + NRF_RTC2->EVTENSET = RTC_EVTEN_COMPARE0_Disabled; + NRF_RTC2->INTENSET = RTC_INTENSET_COMPARE0_Disabled; + + NVIC_ClearPendingIRQ(RTC2_IRQn); + NVIC_EnableIRQ(RTC2_IRQn); + + NRF_RTC2->TASKS_START = 1; + } + + void TimerInit(TimerEvent_t *obj, void (*callback)(void)) + { + obj->Timestamp = 0; + obj->ReloadValue = 0; + obj->IsRunning = false; + obj->Callback = callback; + obj->Next = NULL; + } + + void TimerStart(TimerEvent_t *obj) + { + uint32_t elapsedTime = 0; + + if ((obj == NULL) || (TimerExists(obj) == true)) + { + return; + } + + // CRITICAL_REGION_ENTER(); + + obj->Timestamp = obj->ReloadValue; + obj->IsRunning = false; + + // First obj in the list + if (TimerListHead == NULL) + { + // enable RTC2 CC[0] interrupts + NRF_RTC2->EVTENSET = RTC_EVTEN_COMPARE0_Msk; + NRF_RTC2->INTENSET = RTC_INTENSET_COMPARE0_Msk; + // Get reference time + m_rtc_reference_time = RTC2_GetCounterReg(); + + // insert a timeout at reference time + obj->Timestamp + TimerInsertNewHeadTimer(obj); + } + // Add obj to the list + else + { + elapsedTime = RTC2_GetTimerElapsedTime(); + obj->Timestamp += elapsedTime; + + if (obj->Timestamp < TimerListHead->Timestamp) + { + TimerInsertNewHeadTimer(obj); + } + else + { + TimerInsertTimer(obj); + } + } + + // CRITICAL_REGION_EXIT(); + } + + void TimerStop(TimerEvent_t *obj) + { + TimerEvent_t *prev = TimerListHead; + TimerEvent_t *cur = TimerListHead; + + // List is empty or the Obj to stop does not exist + if ((TimerListHead == NULL) || (obj == NULL)) + { + return; + } + + // CRITICAL_REGION_ENTER(); + + // Stop the Head + if (TimerListHead == obj) + { + // The head is already running + if (TimerListHead->IsRunning == true) + { + // If another obj is registered we switch to it + if (TimerListHead->Next != NULL) + { + TimerListHead->IsRunning = false; + TimerListHead = TimerListHead->Next; + TimerSetTimeout(TimerListHead); + } + // No other obj registered: we can disable interrupts + else + { + // Disable RTC2 CC[0] interrupt + NRF_RTC2->EVTENSET = RTC_EVTEN_COMPARE0_Disabled; + NRF_RTC2->INTENSET = RTC_INTENSET_COMPARE0_Disabled; + TimerListHead = NULL; + } + } + // Stop the head before it is started + else + { + if (TimerListHead->Next != NULL) + { + TimerListHead = TimerListHead->Next; + } + else + { + TimerListHead = NULL; + } + } + } + // Stop an object within the list + else + { + while (cur != NULL) + { + if (cur == obj) + { + if (cur->Next != NULL) + { + cur = cur->Next; + prev->Next = cur; + } + else + { + cur = NULL; + prev->Next = cur; + } + break; + } + else + { + prev = cur; + cur = cur->Next; + } + } + } + + // CRITICAL_REGION_EXIT(); + } + + void TimerReset(TimerEvent_t *obj) + { + TimerStop(obj); + TimerStart(obj); + } + + void TimerSetValue(TimerEvent_t *obj, uint32_t value) + { + uint32_t minValue = 0; + uint32_t ticks = MS_TO_TICKS(value); + + // APP_ERROR_CHECK_BOOL(obj!=NULL); + + TimerStop(obj); + + minValue = RTC2_GetMinimumTimeout(); + if (ticks < minValue) + { + ticks = minValue; + } + + obj->Timestamp = ticks; + obj->ReloadValue = ticks; + } + + TimerTime_t TimerGetCurrentTime(void) + { + uint32_t now = RTC2_GetCounterReg(); + return TICKS_TO_MS(now); + } + + TimerTime_t TimerGetElapsedTime(TimerTime_t past) + { + uint32_t nowInTicks = RTC2_GetCounterReg(); + uint32_t pastInTicks = MS_TO_TICKS(past); + TimerTime_t diff = TICKS_TO_MS((nowInTicks - pastInTicks) & 0x00FFFFFF); + + return diff; + } }; #endif \ No newline at end of file diff --git a/src/boards/mcu/spi_board.h b/src/boards/mcu/spi_board.h index 208dca7..cda5eac 100644 --- a/src/boards/mcu/spi_board.h +++ b/src/boards/mcu/spi_board.h @@ -1,7 +1,7 @@ #ifndef _SPI_BOARD_H #define _SPI_BOARD_H -#ifdef ESP32 -#include "boards/mcu/esp32/spi_board.h" +#if defined ESP8266 || defined ESP32 +#include "boards/mcu/espressif/spi_board.h" #endif #ifdef NRF52 #include "boards/mcu/nrf52832/spi_board.h" diff --git a/src/boards/mcu/timer.h b/src/boards/mcu/timer.h index 22ab5f6..28fc0ea 100644 --- a/src/boards/mcu/timer.h +++ b/src/boards/mcu/timer.h @@ -39,7 +39,7 @@ Maintainer: Miguel Luis and Gregory Cristian #include "stdint.h" #include "stdbool.h" -#ifdef ESP32 +#if defined(ESP32) || defined(ESP8266) #include #endif @@ -47,36 +47,36 @@ extern "C" { #define ROUNDED_DIV(A, B) (((A) + ((B) / 2)) / (B)) -typedef void (*callbackType)(void); + typedef void (*callbackType)(void); -/**@brief Timer object description + /**@brief Timer object description */ -typedef struct TimerEvent_s -{ - uint8_t timerNum; /**< Used with ESP32 MCU 1 for TX, 2 for RX*/ - bool oneShot = false; /**< True if it is a one shot timer */ - uint32_t Timestamp; /**< Current timer value */ - uint32_t ReloadValue; /**< Timer delay value */ - bool IsRunning; /**< Is the timer currently running */ - void (*Callback)(void); /**< Timer IRQ callback function */ - struct TimerEvent_s *Next; /**< Pointer to the next Timer object. */ -}TimerEvent_t; + typedef struct TimerEvent_s + { + uint8_t timerNum; /**< Used with ESP32 MCU 1 for TX, 2 for RX*/ + bool oneShot = false; /**< True if it is a one shot timer */ + uint32_t Timestamp; /**< Current timer value */ + uint32_t ReloadValue; /**< Timer delay value */ + bool IsRunning; /**< Is the timer currently running */ + void (*Callback)(void); /**< Timer IRQ callback function */ + struct TimerEvent_s *Next; /**< Pointer to the next Timer object. */ + } TimerEvent_t; /**@brief Timer time variable definition */ #ifndef TimerTime_t -typedef uint32_t TimerTime_t; + typedef uint32_t TimerTime_t; #endif -/**@brief Initializes the RTC2 timer + /**@brief Initializes the RTC2 timer * * @details Set prescaler to 31 in order to have Fs=1kHz * Enable CC interrupt * Start RTC2 */ -void TimerConfig (void); + void TimerConfig(void); -/**@brief Initializes the timer object + /**@brief Initializes the timer object * * @remark TimerSetValue function must be called before starting the timer. * this function initializes timestamp and reload value at 0. @@ -84,46 +84,46 @@ void TimerConfig (void); * @param [IN] obj Structure containing the timer object parameters * @param [IN] callback Function callback called at the end of the timeout */ -void TimerInit (TimerEvent_t *obj, void (*callback)(void)); + void TimerInit(TimerEvent_t *obj, void (*callback)(void)); -/**@brief Starts and adds the timer object to the list of timer events + /**@brief Starts and adds the timer object to the list of timer events * * @param [IN] obj Structure containing the timer object parameters */ -void TimerStart (TimerEvent_t *obj); + void TimerStart(TimerEvent_t *obj); -/**@brief Stops and removes the timer object from the list of timer events + /**@brief Stops and removes the timer object from the list of timer events * * @param [IN] obj Structure containing the timer object parameters */ -void TimerStop (TimerEvent_t *obj); + void TimerStop(TimerEvent_t *obj); -/**@brief Resets the timer object + /**@brief Resets the timer object * * @param [IN] obj Structure containing the timer object parameters */ -void TimerReset (TimerEvent_t *obj); + void TimerReset(TimerEvent_t *obj); -/**@brief Set timer new timeout value + /**@brief Set timer new timeout value * * @param [IN] obj Structure containing the timer object parameters * * @param [IN] value New timer timeout value in ms */ -void TimerSetValue (TimerEvent_t *obj, uint32_t value); + void TimerSetValue(TimerEvent_t *obj, uint32_t value); -/**@brief Return the Time elapsed since a fix moment in Time + /**@brief Return the Time elapsed since a fix moment in Time * * @param [IN] savedTime fix moment in Time * * @retval time returns elapsed time in ms */ -TimerTime_t TimerGetElapsedTime (TimerTime_t savedTime); + TimerTime_t TimerGetElapsedTime(TimerTime_t savedTime); -/**@brief Read the current time ellapsed since the start (or restart) of RTC2 + /**@brief Read the current time ellapsed since the start (or restart) of RTC2 * * @retval current time in ms */ -TimerTime_t TimerGetCurrentTime (void); + TimerTime_t TimerGetCurrentTime(void); }; -#endif // __TIMER_H__ +#endif // __TIMER_H__ diff --git a/src/boards/sx126x/sx126x-board.cpp b/src/boards/sx126x/sx126x-board.cpp index d2b11e2..ca11135 100644 --- a/src/boards/sx126x/sx126x-board.cpp +++ b/src/boards/sx126x/sx126x-board.cpp @@ -86,11 +86,11 @@ extern "C" void SX126xReset(void) { - DelayMs(10); + delay(10); digitalWrite(_hwConfig.PIN_LORA_RESET, LOW); - DelayMs(20); + delay(20); digitalWrite(_hwConfig.PIN_LORA_RESET, HIGH); - DelayMs(10); + delay(10); dio3IsOutput = false; } @@ -99,7 +99,7 @@ extern "C" int timeout = 1000; while (digitalRead(_hwConfig.PIN_LORA_BUSY) == HIGH) { - DelayMs(1); + delay(1); timeout -= 1; if (timeout < 0) { diff --git a/src/mac/Commissioning.h b/src/mac/Commissioning.h index 6fffefc..99f965f 100644 --- a/src/mac/Commissioning.h +++ b/src/mac/Commissioning.h @@ -42,35 +42,44 @@ extern "C" * When set to 1 the application uses the Over-the-Air activation procedure * When set to 0 the application uses the Personalization activation procedure */ -#define OVER_THE_AIR_ACTIVATION 0 +#define OVER_THE_AIR_ACTIVATION 0 /**@brief Indicates if the end-device is to be connected to a private or public network */ -#define LORAWAN_PUBLIC_NETWORK true +#define LORAWAN_PUBLIC_NETWORK true /**@brief Select if a hard coded device ID is used or an automatic generated one * When set to 1 DevEui is LORAWAN_DEVICE_EUI * When set to 0 DevEui is automatically generated by calling BoardGetUniqueId function */ -#define STATIC_DEVICE_EUI 0 +#define STATIC_DEVICE_EUI 0 /**@brief Mote device IEEE EUI (big endian) * * @remark see STATIC_DEVICE_EUI comments */ -#define LORAWAN_DEVICE_EUI {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +#define LORAWAN_DEVICE_EUI \ + { \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \ + } /**@brief Application IEEE EUI (big endian) */ -#define LORAWAN_APPLICATION_EUI {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +#define LORAWAN_APPLICATION_EUI \ + { \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \ + } /**@brief AES encryption/decryption cipher application key */ -#define LORAWAN_APPLICATION_KEY {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C} +#define LORAWAN_APPLICATION_KEY \ + { \ + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C \ + } /**@brief Current network ID */ -#define LORAWAN_NETWORK_ID (uint32_t)0 +#define LORAWAN_NETWORK_ID (uint32_t)0 /**@brief Select if a hard coded device address is used or an automatic generated one * When set to 1 DevAdd is LORAWAN_DEVICE_ADDRESS @@ -78,7 +87,7 @@ extern "C" * a pseudo random generator seeded with a value derived from * BoardUniqueId value */ -#define STATIC_DEVICE_ADDRESS 1 +#define STATIC_DEVICE_ADDRESS 1 /**@brief Device address on the network (big endian) * @@ -86,14 +95,20 @@ extern "C" * a pseudo random generator seeded with a value derived from * BoardUniqueId value if LORAWAN_DEVICE_ADDRESS is set to 0 */ -#define LORAWAN_DEVICE_ADDRESS (uint32_t)0x00000000 +#define LORAWAN_DEVICE_ADDRESS (uint32_t)0x00000000 /**@brief AES encryption/decryption cipher network session key */ -#define LORAWAN_NWKSKEY {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C} +#define LORAWAN_NWKSKEY \ + { \ + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C \ + } /**@brief AES encryption/decryption cipher application session key */ -#define LORAWAN_APPSKEY {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C} +#define LORAWAN_APPSKEY \ + { \ + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C \ + } }; #endif // __LORA_COMMISSIONING_H__ diff --git a/src/mac/LoRaMac-definitions.h b/src/mac/LoRaMac-definitions.h index 74a775e..67e624e 100644 --- a/src/mac/LoRaMac-definitions.h +++ b/src/mac/LoRaMac-definitions.h @@ -24,91 +24,91 @@ extern "C" * \param[IN] channelIndex Channel index 1 based * \retval channelMask */ -#define LC( channelIndex ) ( uint16_t )( 1 << ( channelIndex - 1 ) ) +#define LC(channelIndex) (uint16_t)(1 << (channelIndex - 1)) -#if defined( USE_BAND_433 ) +#if defined(USE_BAND_433) /*! * LoRaMac maximum number of channels */ -#define LORA_MAX_NB_CHANNELS 16 +#define LORA_MAX_NB_CHANNELS 16 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_TX_MIN_DATARATE DR_0 +#define LORAMAC_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_TX_MAX_DATARATE DR_7 +#define LORAMAC_TX_MAX_DATARATE DR_7 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_RX_MIN_DATARATE DR_0 +#define LORAMAC_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_RX_MAX_DATARATE DR_7 +#define LORAMAC_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node */ -#define LORAMAC_DEFAULT_DATARATE DR_0 +#define LORAMAC_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define LORAMAC_MIN_RX1_DR_OFFSET 0 +#define LORAMAC_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define LORAMAC_MAX_RX1_DR_OFFSET 5 +#define LORAMAC_MAX_RX1_DR_OFFSET 5 /*! * Minimal Tx output power that can be used by the node */ -#define LORAMAC_MIN_TX_POWER TX_POWER_M5_DBM +#define LORAMAC_MIN_TX_POWER TX_POWER_M5_DBM /*! * Maximal Tx output power that can be used by the node */ -#define LORAMAC_MAX_TX_POWER TX_POWER_10_DBM +#define LORAMAC_MAX_TX_POWER TX_POWER_10_DBM /*! * Default Tx output power used by the node */ -#define LORAMAC_DEFAULT_TX_POWER TX_POWER_10_DBM +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_10_DBM /*! * LoRaMac TxPower definition */ -#define TX_POWER_10_DBM 0 -#define TX_POWER_07_DBM 1 -#define TX_POWER_04_DBM 2 -#define TX_POWER_01_DBM 3 -#define TX_POWER_M2_DBM 4 -#define TX_POWER_M5_DBM 5 +#define TX_POWER_10_DBM 0 +#define TX_POWER_07_DBM 1 +#define TX_POWER_04_DBM 2 +#define TX_POWER_01_DBM 3 +#define TX_POWER_M2_DBM 4 +#define TX_POWER_M5_DBM 5 /*! * LoRaMac datarates definition */ -#define DR_0 0 // SF12 - BW125 -#define DR_1 1 // SF11 - BW125 -#define DR_2 2 // SF10 - BW125 -#define DR_3 3 // SF9 - BW125 -#define DR_4 4 // SF8 - BW125 -#define DR_5 5 // SF7 - BW125 -#define DR_6 6 // SF7 - BW250 -#define DR_7 7 // FSK +#define DR_0 0 // SF12 - BW125 +#define DR_1 1 // SF11 - BW125 +#define DR_2 2 // SF10 - BW125 +#define DR_3 3 // SF9 - BW125 +#define DR_4 4 // SF8 - BW125 +#define DR_5 5 // SF7 - BW125 +#define DR_6 6 // SF7 - BW250 +#define DR_7 7 // FSK /*! * Verification of default datarate */ -#if ( LORAMAC_DEFAULT_DATARATE > DR_5 ) +#if (LORAMAC_DEFAULT_DATARATE > DR_5) #error "A default DR higher than DR_5 may lead to connectivity loss." #endif @@ -116,206 +116,226 @@ extern "C" * Second reception window channel definition. */ // Channel = { Frequency [Hz], Datarate } -#define RX_WND_2_CHANNEL { 434665000, DR_0 } +#define RX_WND_2_CHANNEL \ + { \ + 434665000, DR_0 \ + } /*! * LoRaMac maximum number of bands */ -#define LORA_MAX_NB_BANDS 1 +#define LORA_MAX_NB_BANDS 1 // Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } -#define BAND0 { 100, TX_POWER_10_DBM, 0, 0 } // 1.0 % +#define BAND0 \ + { \ + 100, TX_POWER_10_DBM, 0, 0 \ + } // 1.0 % /*! * LoRaMac default channels */ // Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } -#define LC1 { 433175000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } -#define LC2 { 433375000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } -#define LC3 { 433575000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define LC1 \ + { \ + 433175000, {((DR_5 << 4) | DR_0)}, 0 \ + } +#define LC2 \ + { \ + 433375000, {((DR_5 << 4) | DR_0)}, 0 \ + } +#define LC3 \ + { \ + 433575000, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac channels which are allowed for the join procedure */ -#define JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) +#define JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) -#elif defined( USE_BAND_470 ) +#elif defined(USE_BAND_470) /*! * LoRaMac maximum number of channels */ -#define LORA_MAX_NB_CHANNELS 96 +#define LORA_MAX_NB_CHANNELS 96 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_TX_MIN_DATARATE DR_0 +#define LORAMAC_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_TX_MAX_DATARATE DR_5 +#define LORAMAC_TX_MAX_DATARATE DR_5 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_RX_MIN_DATARATE DR_0 +#define LORAMAC_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_RX_MAX_DATARATE DR_5 +#define LORAMAC_RX_MAX_DATARATE DR_5 /*! * Default datarate used by the node */ -#define LORAMAC_DEFAULT_DATARATE DR_0 +#define LORAMAC_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define LORAMAC_MIN_RX1_DR_OFFSET 0 +#define LORAMAC_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define LORAMAC_MAX_RX1_DR_OFFSET 3 +#define LORAMAC_MAX_RX1_DR_OFFSET 3 /*! * Minimal Tx output power that can be used by the node */ -#define LORAMAC_MIN_TX_POWER TX_POWER_2_DBM +#define LORAMAC_MIN_TX_POWER TX_POWER_2_DBM /*! * Maximal Tx output power that can be used by the node */ -#define LORAMAC_MAX_TX_POWER TX_POWER_17_DBM +#define LORAMAC_MAX_TX_POWER TX_POWER_17_DBM /*! * Default Tx output power used by the node */ -#define LORAMAC_DEFAULT_TX_POWER TX_POWER_14_DBM +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_14_DBM /*! * LoRaMac TxPower definition */ -#define TX_POWER_17_DBM 0 -#define TX_POWER_16_DBM 1 -#define TX_POWER_14_DBM 2 -#define TX_POWER_12_DBM 3 -#define TX_POWER_10_DBM 4 -#define TX_POWER_7_DBM 5 -#define TX_POWER_5_DBM 6 -#define TX_POWER_2_DBM 7 - +#define TX_POWER_17_DBM 0 +#define TX_POWER_16_DBM 1 +#define TX_POWER_14_DBM 2 +#define TX_POWER_12_DBM 3 +#define TX_POWER_10_DBM 4 +#define TX_POWER_7_DBM 5 +#define TX_POWER_5_DBM 6 +#define TX_POWER_2_DBM 7 /*! * LoRaMac datarates definition */ -#define DR_0 0 // SF12 - BW125 | -#define DR_1 1 // SF11 - BW125 | -#define DR_2 2 // SF10 - BW125 | -#define DR_3 3 // SF9 - BW125 | -#define DR_4 4 // SF8 - BW125 | -#define DR_5 5 // SF7 - BW125 | +#define DR_0 0 // SF12 - BW125 | +#define DR_1 1 // SF11 - BW125 | +#define DR_2 2 // SF10 - BW125 | +#define DR_3 3 // SF9 - BW125 | +#define DR_4 4 // SF8 - BW125 | +#define DR_5 5 // SF7 - BW125 | /*! * Second reception window channel definition. */ // Channel = { Frequency [Hz], Datarate } -#define RX_WND_2_CHANNEL { 505300000, DR_0 } +#define RX_WND_2_CHANNEL \ + { \ + 505300000, DR_0 \ + } /*! * LoRaMac maximum number of bands */ -#define LORA_MAX_NB_BANDS 1 +#define LORA_MAX_NB_BANDS 1 // Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } -#define BAND0 { 1, TX_POWER_17_DBM, 0, 0 } // 100.0 % +#define BAND0 \ + { \ + 1, TX_POWER_17_DBM, 0, 0 \ + } // 100.0 % -#elif defined( USE_BAND_780 ) +#elif defined(USE_BAND_780) /*! * LoRaMac maximum number of channels */ -#define LORA_MAX_NB_CHANNELS 16 +#define LORA_MAX_NB_CHANNELS 16 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_TX_MIN_DATARATE DR_0 +#define LORAMAC_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_TX_MAX_DATARATE DR_7 +#define LORAMAC_TX_MAX_DATARATE DR_7 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_RX_MIN_DATARATE DR_0 +#define LORAMAC_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_RX_MAX_DATARATE DR_7 +#define LORAMAC_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node */ -#define LORAMAC_DEFAULT_DATARATE DR_0 +#define LORAMAC_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define LORAMAC_MIN_RX1_DR_OFFSET 0 +#define LORAMAC_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define LORAMAC_MAX_RX1_DR_OFFSET 5 +#define LORAMAC_MAX_RX1_DR_OFFSET 5 /*! * Minimal Tx output power that can be used by the node */ -#define LORAMAC_MIN_TX_POWER TX_POWER_M5_DBM +#define LORAMAC_MIN_TX_POWER TX_POWER_M5_DBM /*! * Maximal Tx output power that can be used by the node */ -#define LORAMAC_MAX_TX_POWER TX_POWER_10_DBM +#define LORAMAC_MAX_TX_POWER TX_POWER_10_DBM /*! * Default Tx output power used by the node */ -#define LORAMAC_DEFAULT_TX_POWER TX_POWER_10_DBM +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_10_DBM /*! * LoRaMac TxPower definition */ -#define TX_POWER_10_DBM 0 -#define TX_POWER_07_DBM 1 -#define TX_POWER_04_DBM 2 -#define TX_POWER_01_DBM 3 -#define TX_POWER_M2_DBM 4 -#define TX_POWER_M5_DBM 5 +#define TX_POWER_10_DBM 0 +#define TX_POWER_07_DBM 1 +#define TX_POWER_04_DBM 2 +#define TX_POWER_01_DBM 3 +#define TX_POWER_M2_DBM 4 +#define TX_POWER_M5_DBM 5 /*! * LoRaMac datarates definition */ -#define DR_0 0 // SF12 - BW125 -#define DR_1 1 // SF11 - BW125 -#define DR_2 2 // SF10 - BW125 -#define DR_3 3 // SF9 - BW125 -#define DR_4 4 // SF8 - BW125 -#define DR_5 5 // SF7 - BW125 -#define DR_6 6 // SF7 - BW250 -#define DR_7 7 // FSK +#define DR_0 0 // SF12 - BW125 +#define DR_1 1 // SF11 - BW125 +#define DR_2 2 // SF10 - BW125 +#define DR_3 3 // SF9 - BW125 +#define DR_4 4 // SF8 - BW125 +#define DR_5 5 // SF7 - BW125 +#define DR_6 6 // SF7 - BW250 +#define DR_7 7 // FSK /*! * Verification of default datarate */ -#if ( LORAMAC_DEFAULT_DATARATE > DR_5 ) +#if (LORAMAC_DEFAULT_DATARATE > DR_5) #error "A default DR higher than DR_5 may lead to connectivity loss." #endif @@ -323,112 +343,127 @@ extern "C" * Second reception window channel definition. */ // Channel = { Frequency [Hz], Datarate } -#define RX_WND_2_CHANNEL { 786000000, DR_0 } +#define RX_WND_2_CHANNEL \ + { \ + 786000000, DR_0 \ + } /*! * LoRaMac maximum number of bands */ -#define LORA_MAX_NB_BANDS 1 +#define LORA_MAX_NB_BANDS 1 // Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } -#define BAND0 { 100, TX_POWER_10_DBM, 0, 0 } // 1.0 % +#define BAND0 \ + { \ + 100, TX_POWER_10_DBM, 0, 0 \ + } // 1.0 % /*! * LoRaMac default channels */ // Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } -#define LC1 { 779500000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } -#define LC2 { 779700000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } -#define LC3 { 779900000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define LC1 \ + { \ + 779500000, {((DR_5 << 4) | DR_0)}, 0 \ + } +#define LC2 \ + { \ + 779700000, {((DR_5 << 4) | DR_0)}, 0 \ + } +#define LC3 \ + { \ + 779900000, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac channels which are allowed for the join procedure */ -#define JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) +#define JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) -#elif defined( USE_BAND_868 ) +#elif defined(USE_BAND_868) /*! * LoRaMac maximum number of channels */ -#define LORA_MAX_NB_CHANNELS 16 +#define LORA_MAX_NB_CHANNELS 16 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_TX_MIN_DATARATE DR_0 +#define LORAMAC_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_TX_MAX_DATARATE DR_7 +#define LORAMAC_TX_MAX_DATARATE DR_7 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_RX_MIN_DATARATE DR_0 +#define LORAMAC_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_RX_MAX_DATARATE DR_7 +#define LORAMAC_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node */ -#define LORAMAC_DEFAULT_DATARATE DR_0 +#define LORAMAC_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define LORAMAC_MIN_RX1_DR_OFFSET 0 +#define LORAMAC_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define LORAMAC_MAX_RX1_DR_OFFSET 5 +#define LORAMAC_MAX_RX1_DR_OFFSET 5 /*! * Minimal Tx output power that can be used by the node */ -#define LORAMAC_MIN_TX_POWER TX_POWER_02_DBM +#define LORAMAC_MIN_TX_POWER TX_POWER_02_DBM /*! * Maximal Tx output power that can be used by the node */ -#define LORAMAC_MAX_TX_POWER TX_POWER_20_DBM +#define LORAMAC_MAX_TX_POWER TX_POWER_20_DBM /*! * Default Tx output power used by the node */ -#define LORAMAC_DEFAULT_TX_POWER TX_POWER_14_DBM +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_14_DBM /*! * LoRaMac TxPower definition */ -#define TX_POWER_20_DBM 0 -#define TX_POWER_14_DBM 1 -#define TX_POWER_11_DBM 2 -#define TX_POWER_08_DBM 3 -#define TX_POWER_05_DBM 4 -#define TX_POWER_02_DBM 5 +#define TX_POWER_20_DBM 0 +#define TX_POWER_14_DBM 1 +#define TX_POWER_11_DBM 2 +#define TX_POWER_08_DBM 3 +#define TX_POWER_05_DBM 4 +#define TX_POWER_02_DBM 5 /*! * LoRaMac datarates definition */ -#define DR_0 0 // SF12 - BW125 -#define DR_1 1 // SF11 - BW125 -#define DR_2 2 // SF10 - BW125 -#define DR_3 3 // SF9 - BW125 -#define DR_4 4 // SF8 - BW125 -#define DR_5 5 // SF7 - BW125 -#define DR_6 6 // SF7 - BW250 -#define DR_7 7 // FSK +#define DR_0 0 // SF12 - BW125 +#define DR_1 1 // SF11 - BW125 +#define DR_2 2 // SF10 - BW125 +#define DR_3 3 // SF9 - BW125 +#define DR_4 4 // SF8 - BW125 +#define DR_5 5 // SF7 - BW125 +#define DR_6 6 // SF7 - BW250 +#define DR_7 7 // FSK /*! * Verification of default datarate */ -#if ( LORAMAC_DEFAULT_DATARATE > DR_5 ) +#if (LORAMAC_DEFAULT_DATARATE > DR_5) #error "A default DR higher than DR_5 may lead to connectivity loss." #endif @@ -436,150 +471,183 @@ extern "C" * Second reception window channel definition. */ // Channel = { Frequency [Hz], Datarate } -#define RX_WND_2_CHANNEL { 869525000, DR_0 } +#define RX_WND_2_CHANNEL \ + { \ + 869525000, DR_0 \ + } /*! * LoRaMac maximum number of bands */ -#define LORA_MAX_NB_BANDS 5 +#define LORA_MAX_NB_BANDS 5 -/*! + /*! * LoRaMac EU868 default bands */ -typedef enum -{ - BAND_G1_0, - BAND_G1_1, - BAND_G1_2, - BAND_G1_3, - BAND_G1_4, -}BandId_t; + typedef enum + { + BAND_G1_0, + BAND_G1_1, + BAND_G1_2, + BAND_G1_3, + BAND_G1_4, + } BandId_t; // Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } -#define BAND0 { 100 , TX_POWER_14_DBM, 0, 0 } // 1.0 % -#define BAND1 { 100 , TX_POWER_14_DBM, 0, 0 } // 1.0 % -#define BAND2 { 1000, TX_POWER_14_DBM, 0, 0 } // 0.1 % -#define BAND3 { 10 , TX_POWER_14_DBM, 0, 0 } // 10.0 % -#define BAND4 { 100 , TX_POWER_14_DBM, 0, 0 } // 1.0 % +#define BAND0 \ + { \ + 100, TX_POWER_14_DBM, 0, 0 \ + } // 1.0 % +#define BAND1 \ + { \ + 100, TX_POWER_14_DBM, 0, 0 \ + } // 1.0 % +#define BAND2 \ + { \ + 1000, TX_POWER_14_DBM, 0, 0 \ + } // 0.1 % +#define BAND3 \ + { \ + 10, TX_POWER_14_DBM, 0, 0 \ + } // 10.0 % +#define BAND4 \ + { \ + 100, TX_POWER_14_DBM, 0, 0 \ + } // 1.0 % /*! * LoRaMac default channels */ // Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } -#define LC1 { 868100000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } -#define LC2 { 868300000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } -#define LC3 { 868500000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } +#define LC1 \ + { \ + 868100000, {((DR_5 << 4) | DR_0)}, 1 \ + } +#define LC2 \ + { \ + 868300000, {((DR_5 << 4) | DR_0)}, 1 \ + } +#define LC3 \ + { \ + 868500000, {((DR_5 << 4) | DR_0)}, 1 \ + } /*! * LoRaMac channels which are allowed for the join procedure */ -#define JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) +#define JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) -#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) +#elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) /*! * LoRaMac maximum number of channels */ -#define LORA_MAX_NB_CHANNELS 72 +#define LORA_MAX_NB_CHANNELS 72 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_TX_MIN_DATARATE DR_0 +#define LORAMAC_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_TX_MAX_DATARATE DR_4 +#define LORAMAC_TX_MAX_DATARATE DR_4 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_RX_MIN_DATARATE DR_8 +#define LORAMAC_RX_MIN_DATARATE DR_8 /*! * Maximal datarate that can be used by the node */ -#define LORAMAC_RX_MAX_DATARATE DR_13 +#define LORAMAC_RX_MAX_DATARATE DR_13 /*! * Default datarate used by the node */ -#define LORAMAC_DEFAULT_DATARATE DR_0 +#define LORAMAC_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define LORAMAC_MIN_RX1_DR_OFFSET 0 +#define LORAMAC_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define LORAMAC_MAX_RX1_DR_OFFSET 3 +#define LORAMAC_MAX_RX1_DR_OFFSET 3 /*! * Minimal Tx output power that can be used by the node */ -#define LORAMAC_MIN_TX_POWER TX_POWER_10_DBM +#define LORAMAC_MIN_TX_POWER TX_POWER_10_DBM /*! * Maximal Tx output power that can be used by the node */ -#define LORAMAC_MAX_TX_POWER TX_POWER_30_DBM +#define LORAMAC_MAX_TX_POWER TX_POWER_30_DBM /*! * Default Tx output power used by the node */ -#define LORAMAC_DEFAULT_TX_POWER TX_POWER_20_DBM +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_20_DBM /*! * LoRaMac TxPower definition */ -#define TX_POWER_30_DBM 0 -#define TX_POWER_28_DBM 1 -#define TX_POWER_26_DBM 2 -#define TX_POWER_24_DBM 3 -#define TX_POWER_22_DBM 4 -#define TX_POWER_20_DBM 5 -#define TX_POWER_18_DBM 6 -#define TX_POWER_16_DBM 7 -#define TX_POWER_14_DBM 8 -#define TX_POWER_12_DBM 9 -#define TX_POWER_10_DBM 10 +#define TX_POWER_30_DBM 0 +#define TX_POWER_28_DBM 1 +#define TX_POWER_26_DBM 2 +#define TX_POWER_24_DBM 3 +#define TX_POWER_22_DBM 4 +#define TX_POWER_20_DBM 5 +#define TX_POWER_18_DBM 6 +#define TX_POWER_16_DBM 7 +#define TX_POWER_14_DBM 8 +#define TX_POWER_12_DBM 9 +#define TX_POWER_10_DBM 10 /*! * LoRaMac datarates definition */ -#define DR_0 0 // SF10 - BW125 | -#define DR_1 1 // SF9 - BW125 | -#define DR_2 2 // SF8 - BW125 +-> Up link -#define DR_3 3 // SF7 - BW125 | -#define DR_4 4 // SF8 - BW500 | -#define DR_5 5 // RFU -#define DR_6 6 // RFU -#define DR_7 7 // RFU -#define DR_8 8 // SF12 - BW500 | -#define DR_9 9 // SF11 - BW500 | -#define DR_10 10 // SF10 - BW500 | -#define DR_11 11 // SF9 - BW500 | -#define DR_12 12 // SF8 - BW500 +-> Down link -#define DR_13 13 // SF7 - BW500 | -#define DR_14 14 // RFU | -#define DR_15 15 // RFU | +#define DR_0 0 // SF10 - BW125 | +#define DR_1 1 // SF9 - BW125 | +#define DR_2 2 // SF8 - BW125 +-> Up link +#define DR_3 3 // SF7 - BW125 | +#define DR_4 4 // SF8 - BW500 | +#define DR_5 5 // RFU +#define DR_6 6 // RFU +#define DR_7 7 // RFU +#define DR_8 8 // SF12 - BW500 | +#define DR_9 9 // SF11 - BW500 | +#define DR_10 10 // SF10 - BW500 | +#define DR_11 11 // SF9 - BW500 | +#define DR_12 12 // SF8 - BW500 +-> Down link +#define DR_13 13 // SF7 - BW500 | +#define DR_14 14 // RFU | +#define DR_15 15 // RFU | /*! * Second reception window channel definition. */ // Channel = { Frequency [Hz], Datarate } -#define RX_WND_2_CHANNEL { 923300000, DR_8 } +#define RX_WND_2_CHANNEL \ + { \ + 923300000, DR_8 \ + } /*! * LoRaMac maximum number of bands */ -#define LORA_MAX_NB_BANDS 1 +#define LORA_MAX_NB_BANDS 1 // Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } -#define BAND0 { 1, TX_POWER_20_DBM, 0, 0 } // 100.0 % +#define BAND0 \ + { \ + 1, TX_POWER_20_DBM, 0, 0 \ + } // 100.0 % /*! * LoRaMac default channels @@ -605,7 +673,7 @@ typedef enum * \endcode */ #else - #error "Please define a frequency band in the compiler options." +#error "Please define a frequency band in the compiler options." #endif }; #endif // __LORAMAC_BOARD_H__ diff --git a/src/mac/LoRaMac.h b/src/mac/LoRaMac.h index 26bc882..a3f4936 100644 --- a/src/mac/LoRaMac.h +++ b/src/mac/LoRaMac.h @@ -118,556 +118,556 @@ extern "C" */ #define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) - /*! + /*! * LoRaWAN devices classes definition * * LoRaWAN Specification V1.0.2, chapter 2.1 */ - typedef enum eDeviceClass - { - /*! + typedef enum eDeviceClass + { + /*! * LoRaWAN device class A * * LoRaWAN Specification V1.0.2, chapter 3 */ - CLASS_A, - /*! + CLASS_A, + /*! * LoRaWAN device class B * * LoRaWAN Specification V1.0.2, chapter 8 */ - CLASS_B, - /*! + CLASS_B, + /*! * LoRaWAN device class C * * LoRaWAN Specification V1.0.2, chapter 17 */ - CLASS_C, - } DeviceClass_t; + CLASS_C, + } DeviceClass_t; - /*! + /*! * LoRaMAC channels parameters definition */ - typedef union uDrRange { - /*! + typedef union uDrRange { + /*! * Byte-access to the bits */ - int8_t Value; - /*! + int8_t Value; + /*! * Structure to store the minimum and the maximum datarate */ - struct sFields - { - /*! + struct sFields + { + /*! * Minimum data rate * * LoRaWAN Regional Parameters V1.0.2rB * * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details. */ - int8_t Min : 4; - /*! + int8_t Min : 4; + /*! * Maximum data rate * * LoRaWAN Regional Parameters V1.0.2rB * * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details. */ - int8_t Max : 4; - } Fields; - } DrRange_t; + int8_t Max : 4; + } Fields; + } DrRange_t; - /*! + /*! * LoRaMAC band parameters definition */ - typedef struct sBand - { - /*! + typedef struct sBand + { + /*! * Duty cycle */ - uint16_t DCycle; - /*! + uint16_t DCycle; + /*! * Maximum Tx power */ - int8_t TxMaxPower; - /*! + int8_t TxMaxPower; + /*! * Time stamp of the last JoinReq Tx frame. */ - TimerTime_t LastJoinTxDoneTime; - /*! + TimerTime_t LastJoinTxDoneTime; + /*! * Time stamp of the last Tx frame */ - TimerTime_t LastTxDoneTime; - /*! + TimerTime_t LastTxDoneTime; + /*! * Holds the time where the device is off */ - TimerTime_t TimeOff; - } Band_t; + TimerTime_t TimeOff; + } Band_t; - /*! + /*! * LoRaMAC channel definition */ - typedef struct sChannelParams - { - /*! + typedef struct sChannelParams + { + /*! * Frequency in Hz */ - uint32_t Frequency; - /*! + uint32_t Frequency; + /*! * Alternative frequency for RX window 1 */ - uint32_t Rx1Frequency; - /*! + uint32_t Rx1Frequency; + /*! * Data rate definition */ - DrRange_t DrRange; - /*! + DrRange_t DrRange; + /*! * Band index */ - uint8_t Band; - } ChannelParams_t; + uint8_t Band; + } ChannelParams_t; - /*! + /*! * LoRaMAC receive window 2 channel parameters */ - typedef struct sRx2ChannelParams - { - /*! + typedef struct sRx2ChannelParams + { + /*! * Frequency in Hz */ - uint32_t Frequency; - /*! + uint32_t Frequency; + /*! * Data rate * * LoRaWAN Regional Parameters V1.0.2rB * * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details. */ - uint8_t Datarate; - } Rx2ChannelParams_t; + uint8_t Datarate; + } Rx2ChannelParams_t; - /*! + /*! * Global MAC layer parameters */ - typedef struct sLoRaMacParams - { - /*! + typedef struct sLoRaMacParams + { + /*! * Channels TX power */ - int8_t ChannelsTxPower; - /*! + int8_t ChannelsTxPower; + /*! * Channels data rate */ - int8_t ChannelsDatarate; - /*! + int8_t ChannelsDatarate; + /*! * System overall timing error in milliseconds. * [-SystemMaxRxError : +SystemMaxRxError] * Default: +/-10 ms */ - uint32_t SystemMaxRxError; - /*! + uint32_t SystemMaxRxError; + /*! * Minimum required number of symbols to detect an Rx frame * Default: 6 symbols */ - uint8_t MinRxSymbols; - /*! + uint8_t MinRxSymbols; + /*! * LoRaMac maximum time a reception window stays open */ - uint32_t MaxRxWindow; - /*! + uint32_t MaxRxWindow; + /*! * Receive delay 1 */ - uint32_t ReceiveDelay1; - /*! + uint32_t ReceiveDelay1; + /*! * Receive delay 2 */ - uint32_t ReceiveDelay2; - /*! + uint32_t ReceiveDelay2; + /*! * Join accept delay 1 */ - uint32_t JoinAcceptDelay1; - /*! + uint32_t JoinAcceptDelay1; + /*! * Join accept delay 1 */ - uint32_t JoinAcceptDelay2; - /*! + uint32_t JoinAcceptDelay2; + /*! * Number of uplink messages repetitions [1:15] (unconfirmed messages only) */ - uint8_t ChannelsNbRep; - /*! + uint8_t ChannelsNbRep; + /*! * Datarate offset between uplink and downlink on first window */ - uint8_t Rx1DrOffset; - /*! + uint8_t Rx1DrOffset; + /*! * LoRaMAC 2nd reception window settings */ - Rx2ChannelParams_t Rx2Channel; - /*! + Rx2ChannelParams_t Rx2Channel; + /*! * Uplink dwell time configuration. 0: No limit, 1: 400ms */ - uint8_t UplinkDwellTime; - /*! + uint8_t UplinkDwellTime; + /*! * Downlink dwell time configuration. 0: No limit, 1: 400ms */ - uint8_t DownlinkDwellTime; - /*! + uint8_t DownlinkDwellTime; + /*! * Maximum possible EIRP */ - float MaxEirp; - /*! + float MaxEirp; + /*! * Antenna gain of the node */ - float AntennaGain; - } LoRaMacParams_t; + float AntennaGain; + } LoRaMacParams_t; - /*! + /*! * LoRaMAC multicast channel parameter */ - typedef struct sMulticastParams - { - /*! + typedef struct sMulticastParams + { + /*! * Address */ - uint32_t Address; - /*! + uint32_t Address; + /*! * Network session key */ - uint8_t NwkSKey[16]; - /*! + uint8_t NwkSKey[16]; + /*! * Application session key */ - uint8_t AppSKey[16]; - /*! + uint8_t AppSKey[16]; + /*! * Downlink counter */ - uint32_t DownLinkCounter; - /*! + uint32_t DownLinkCounter; + /*! * Reference pointer to the next multicast channel parameters in the list */ - struct sMulticastParams *Next; - } MulticastParams_t; + struct sMulticastParams *Next; + } MulticastParams_t; - /*! + /*! * LoRaMAC frame types * * LoRaWAN Specification V1.0.2, chapter 4.2.1, table 1 */ - typedef enum eLoRaMacFrameType - { - /*! + typedef enum eLoRaMacFrameType + { + /*! * LoRaMAC join request frame */ - FRAME_TYPE_JOIN_REQ = 0x00, - /*! + FRAME_TYPE_JOIN_REQ = 0x00, + /*! * LoRaMAC join accept frame */ - FRAME_TYPE_JOIN_ACCEPT = 0x01, - /*! + FRAME_TYPE_JOIN_ACCEPT = 0x01, + /*! * LoRaMAC unconfirmed up-link frame */ - FRAME_TYPE_DATA_UNCONFIRMED_UP = 0x02, - /*! + FRAME_TYPE_DATA_UNCONFIRMED_UP = 0x02, + /*! * LoRaMAC unconfirmed down-link frame */ - FRAME_TYPE_DATA_UNCONFIRMED_DOWN = 0x03, - /*! + FRAME_TYPE_DATA_UNCONFIRMED_DOWN = 0x03, + /*! * LoRaMAC confirmed up-link frame */ - FRAME_TYPE_DATA_CONFIRMED_UP = 0x04, - /*! + FRAME_TYPE_DATA_CONFIRMED_UP = 0x04, + /*! * LoRaMAC confirmed down-link frame */ - FRAME_TYPE_DATA_CONFIRMED_DOWN = 0x05, - /*! + FRAME_TYPE_DATA_CONFIRMED_DOWN = 0x05, + /*! * LoRaMAC RFU frame */ - FRAME_TYPE_RFU = 0x06, - /*! + FRAME_TYPE_RFU = 0x06, + /*! * LoRaMAC proprietary frame */ - FRAME_TYPE_PROPRIETARY = 0x07, - } LoRaMacFrameType_t; + FRAME_TYPE_PROPRIETARY = 0x07, + } LoRaMacFrameType_t; - /*! + /*! * LoRaMAC mote MAC commands * * LoRaWAN Specification V1.0.2, chapter 5, table 4 */ - typedef enum eLoRaMacMoteCmd - { - /*! + typedef enum eLoRaMacMoteCmd + { + /*! * LinkCheckReq */ - MOTE_MAC_LINK_CHECK_REQ = 0x02, - /*! + MOTE_MAC_LINK_CHECK_REQ = 0x02, + /*! * LinkADRAns */ - MOTE_MAC_LINK_ADR_ANS = 0x03, - /*! + MOTE_MAC_LINK_ADR_ANS = 0x03, + /*! * DutyCycleAns */ - MOTE_MAC_DUTY_CYCLE_ANS = 0x04, - /*! + MOTE_MAC_DUTY_CYCLE_ANS = 0x04, + /*! * RXParamSetupAns */ - MOTE_MAC_RX_PARAM_SETUP_ANS = 0x05, - /*! + MOTE_MAC_RX_PARAM_SETUP_ANS = 0x05, + /*! * DevStatusAns */ - MOTE_MAC_DEV_STATUS_ANS = 0x06, - /*! + MOTE_MAC_DEV_STATUS_ANS = 0x06, + /*! * NewChannelAns */ - MOTE_MAC_NEW_CHANNEL_ANS = 0x07, - /*! + MOTE_MAC_NEW_CHANNEL_ANS = 0x07, + /*! * RXTimingSetupAns */ - MOTE_MAC_RX_TIMING_SETUP_ANS = 0x08, - /*! + MOTE_MAC_RX_TIMING_SETUP_ANS = 0x08, + /*! * TXParamSetupAns */ - MOTE_MAC_TX_PARAM_SETUP_ANS = 0x09, - /*! + MOTE_MAC_TX_PARAM_SETUP_ANS = 0x09, + /*! * DlChannelAns */ - MOTE_MAC_DL_CHANNEL_ANS = 0x0A - } LoRaMacMoteCmd_t; + MOTE_MAC_DL_CHANNEL_ANS = 0x0A + } LoRaMacMoteCmd_t; - /*! + /*! * LoRaMAC server MAC commands * * LoRaWAN Specification V1.0.2 chapter 5, table 4 */ - typedef enum eLoRaMacSrvCmd - { - /*! + typedef enum eLoRaMacSrvCmd + { + /*! * LinkCheckAns */ - SRV_MAC_LINK_CHECK_ANS = 0x02, - /*! + SRV_MAC_LINK_CHECK_ANS = 0x02, + /*! * LinkADRReq */ - SRV_MAC_LINK_ADR_REQ = 0x03, - /*! + SRV_MAC_LINK_ADR_REQ = 0x03, + /*! * DutyCycleReq */ - SRV_MAC_DUTY_CYCLE_REQ = 0x04, - /*! + SRV_MAC_DUTY_CYCLE_REQ = 0x04, + /*! * RXParamSetupReq */ - SRV_MAC_RX_PARAM_SETUP_REQ = 0x05, - /*! + SRV_MAC_RX_PARAM_SETUP_REQ = 0x05, + /*! * DevStatusReq */ - SRV_MAC_DEV_STATUS_REQ = 0x06, - /*! + SRV_MAC_DEV_STATUS_REQ = 0x06, + /*! * NewChannelReq */ - SRV_MAC_NEW_CHANNEL_REQ = 0x07, - /*! + SRV_MAC_NEW_CHANNEL_REQ = 0x07, + /*! * RXTimingSetupReq */ - SRV_MAC_RX_TIMING_SETUP_REQ = 0x08, - /*! + SRV_MAC_RX_TIMING_SETUP_REQ = 0x08, + /*! * NewChannelReq */ - SRV_MAC_TX_PARAM_SETUP_REQ = 0x09, - /*! + SRV_MAC_TX_PARAM_SETUP_REQ = 0x09, + /*! * DlChannelReq */ - SRV_MAC_DL_CHANNEL_REQ = 0x0A, - } LoRaMacSrvCmd_t; + SRV_MAC_DL_CHANNEL_REQ = 0x0A, + } LoRaMacSrvCmd_t; - /*! + /*! * LoRaMAC Battery level indicator */ - typedef enum eLoRaMacBatteryLevel - { - /*! + typedef enum eLoRaMacBatteryLevel + { + /*! * External power source */ - BAT_LEVEL_EXT_SRC = 0x00, - /*! + BAT_LEVEL_EXT_SRC = 0x00, + /*! * Battery level empty */ - BAT_LEVEL_EMPTY = 0x01, - /*! + BAT_LEVEL_EMPTY = 0x01, + /*! * Battery level full */ - BAT_LEVEL_FULL = 0xFE, - /*! + BAT_LEVEL_FULL = 0xFE, + /*! * Battery level - no measurement available */ - BAT_LEVEL_NO_MEASURE = 0xFF, - } LoRaMacBatteryLevel_t; + BAT_LEVEL_NO_MEASURE = 0xFF, + } LoRaMacBatteryLevel_t; - /*! + /*! * LoRaMAC header field definition (MHDR field) * * LoRaWAN Specification V1.0.2, chapter 4.2 */ - typedef union uLoRaMacHeader { - /*! + typedef union uLoRaMacHeader { + /*! * Byte-access to the bits */ - uint8_t Value; - /*! + uint8_t Value; + /*! * Structure containing single access to header bits */ - struct sHdrBits - { - /*! + struct sHdrBits + { + /*! * Major version */ - uint8_t Major : 2; - /*! + uint8_t Major : 2; + /*! * RFU */ - uint8_t RFU : 3; - /*! + uint8_t RFU : 3; + /*! * Message type */ - uint8_t MType : 3; - } Bits; - } LoRaMacHeader_t; + uint8_t MType : 3; + } Bits; + } LoRaMacHeader_t; - /*! + /*! * LoRaMAC frame control field definition (FCtrl) * * LoRaWAN Specification V1.0.2, chapter 4.3.1 */ - typedef union uLoRaMacFrameCtrl { - /*! + typedef union uLoRaMacFrameCtrl { + /*! * Byte-access to the bits */ - uint8_t Value; - /*! + uint8_t Value; + /*! * Structure containing single access to bits */ - struct sCtrlBits - { - /*! + struct sCtrlBits + { + /*! * Frame options length */ - uint8_t FOptsLen : 4; - /*! + uint8_t FOptsLen : 4; + /*! * Frame pending bit */ - uint8_t FPending : 1; - /*! + uint8_t FPending : 1; + /*! * Message acknowledge bit */ - uint8_t Ack : 1; - /*! + uint8_t Ack : 1; + /*! * ADR acknowledgment request bit */ - uint8_t AdrAckReq : 1; - /*! + uint8_t AdrAckReq : 1; + /*! * ADR control in frame header */ - uint8_t Adr : 1; - } Bits; - } LoRaMacFrameCtrl_t; + uint8_t Adr : 1; + } Bits; + } LoRaMacFrameCtrl_t; - /*! + /*! * Enumeration containing the status of the operation of a MAC service */ - typedef enum eLoRaMacEventInfoStatus - { - /*! + typedef enum eLoRaMacEventInfoStatus + { + /*! * Service performed successfully */ - LORAMAC_EVENT_INFO_STATUS_OK = 0, - /*! + LORAMAC_EVENT_INFO_STATUS_OK = 0, + /*! * An error occurred during the execution of the service */ - LORAMAC_EVENT_INFO_STATUS_ERROR, - /*! + LORAMAC_EVENT_INFO_STATUS_ERROR, + /*! * A Tx timeout occurred */ - LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT, - /*! + LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT, + /*! * An Rx timeout occurred on receive window 1 */ - LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT, - /*! + LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT, + /*! * An Rx timeout occurred on receive window 2 */ - LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT, - /*! + LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT, + /*! * An Rx error occurred on receive window 1 */ - LORAMAC_EVENT_INFO_STATUS_RX1_ERROR, - /*! + LORAMAC_EVENT_INFO_STATUS_RX1_ERROR, + /*! * An Rx error occurred on receive window 2 */ - LORAMAC_EVENT_INFO_STATUS_RX2_ERROR, - /*! + LORAMAC_EVENT_INFO_STATUS_RX2_ERROR, + /*! * An error occurred in the join procedure */ - LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL, - /*! + LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL, + /*! * A frame with an invalid downlink counter was received. The * downlink counter of the frame was equal to the local copy * of the downlink counter of the node. */ - LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED, - /*! + LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED, + /*! * The MAC could not retransmit a frame since the MAC decreased the datarate. The * payload size is not applicable for the datarate. */ - LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR, - /*! + LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR, + /*! * The node has lost MAX_FCNT_GAP or more frames. */ - LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS, - /*! + LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS, + /*! * An address error occurred */ - LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL, - /*! + LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL, + /*! * message integrity check failure */ - LORAMAC_EVENT_INFO_STATUS_MIC_FAIL, - } LoRaMacEventInfoStatus_t; + LORAMAC_EVENT_INFO_STATUS_MIC_FAIL, + } LoRaMacEventInfoStatus_t; - /*! + /*! * LoRaMac tx/rx operation state */ - typedef union eLoRaMacFlags_t { - /*! + typedef union eLoRaMacFlags_t { + /*! * Byte-access to the bits */ - uint8_t Value; - /*! + uint8_t Value; + /*! * Structure containing single access to bits */ - struct sMacFlagBits - { - /*! + struct sMacFlagBits + { + /*! * MCPS-Req pending */ - uint8_t McpsReq : 1; - /*! + uint8_t McpsReq : 1; + /*! * MCPS-Ind pending */ - uint8_t McpsInd : 1; - /*! + uint8_t McpsInd : 1; + /*! * MCPS-Ind pending. Skip indication to the application layer */ - uint8_t McpsIndSkip : 1; - /*! + uint8_t McpsIndSkip : 1; + /*! * MLME-Req pending */ - uint8_t MlmeReq : 1; - /*! + uint8_t MlmeReq : 1; + /*! * MAC cycle done */ - uint8_t MacDone : 1; - } Bits; - } LoRaMacFlags_t; + uint8_t MacDone : 1; + } Bits; + } LoRaMacFlags_t; - /*! + /*! * * \brief LoRaMAC data services * @@ -690,77 +690,77 @@ extern "C" * MCPS-Confirm | MacMcpsConfirm in \ref LoRaMacPrimitives_t * MCPS-Indication | MacMcpsIndication in \ref LoRaMacPrimitives_t */ - typedef enum eMcps - { - /*! + typedef enum eMcps + { + /*! * Unconfirmed LoRaMAC frame */ - MCPS_UNCONFIRMED, - /*! + MCPS_UNCONFIRMED, + /*! * Confirmed LoRaMAC frame */ - MCPS_CONFIRMED, - /*! + MCPS_CONFIRMED, + /*! * Multicast LoRaMAC frame */ - MCPS_MULTICAST, - /*! + MCPS_MULTICAST, + /*! * Proprietary frame */ - MCPS_PROPRIETARY, - } Mcps_t; + MCPS_PROPRIETARY, + } Mcps_t; - /*! + /*! * LoRaMAC MCPS-Request for an unconfirmed frame */ - typedef struct sMcpsReqUnconfirmed - { - /*! + typedef struct sMcpsReqUnconfirmed + { + /*! * Frame port field. Must be set if the payload is not empty. Use the * application specific frame port values: [1...223] * * LoRaWAN Specification V1.0.2, chapter 4.3.2 */ - uint8_t fPort; - /*! + uint8_t fPort; + /*! * Pointer to the buffer of the frame payload */ - void *fBuffer; - /*! + void *fBuffer; + /*! * Size of the frame payload */ - uint16_t fBufferSize; - /*! + uint16_t fBufferSize; + /*! * Uplink datarate, if ADR is off */ - int8_t Datarate; - } McpsReqUnconfirmed_t; + int8_t Datarate; + } McpsReqUnconfirmed_t; - /*! + /*! * LoRaMAC MCPS-Request for a confirmed frame */ - typedef struct sMcpsReqConfirmed - { - /*! + typedef struct sMcpsReqConfirmed + { + /*! * Frame port field. Must be set if the payload is not empty. Use the * application specific frame port values: [1...223] * * LoRaWAN Specification V1.0.2, chapter 4.3.2 */ - uint8_t fPort; - /*! + uint8_t fPort; + /*! * Pointer to the buffer of the frame payload */ - void *fBuffer; - /*! + void *fBuffer; + /*! * Size of the frame payload */ - uint16_t fBufferSize; - /*! + uint16_t fBufferSize; + /*! * Uplink datarate, if ADR is off */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * Number of trials to transmit the frame, if the LoRaMAC layer did not * receive an acknowledgment. The MAC performs a datarate adaptation, * according to the LoRaWAN Specification V1.0.2, chapter 18.4, according @@ -780,166 +780,166 @@ extern "C" * Note, that if NbTrials is set to 1 or 2, the MAC will not decrease * the datarate, in case the LoRaMAC layer did not receive an acknowledgment */ - uint8_t NbTrials; - } McpsReqConfirmed_t; + uint8_t NbTrials; + } McpsReqConfirmed_t; - /*! + /*! * LoRaMAC MCPS-Request for a proprietary frame */ - typedef struct sMcpsReqProprietary - { - /*! + typedef struct sMcpsReqProprietary + { + /*! * Pointer to the buffer of the frame payload */ - void *fBuffer; - /*! + void *fBuffer; + /*! * Size of the frame payload */ - uint16_t fBufferSize; - /*! + uint16_t fBufferSize; + /*! * Uplink datarate, if ADR is off */ - int8_t Datarate; - } McpsReqProprietary_t; + int8_t Datarate; + } McpsReqProprietary_t; - /*! + /*! * LoRaMAC MCPS-Request structure */ - typedef struct sMcpsReq - { - /*! + typedef struct sMcpsReq + { + /*! * MCPS-Request type */ - Mcps_t Type; + Mcps_t Type; - /*! + /*! * MCPS-Request parameters */ - union uMcpsParam { - /*! + union uMcpsParam { + /*! * MCPS-Request parameters for an unconfirmed frame */ - McpsReqUnconfirmed_t Unconfirmed; - /*! + McpsReqUnconfirmed_t Unconfirmed; + /*! * MCPS-Request parameters for a confirmed frame */ - McpsReqConfirmed_t Confirmed; - /*! + McpsReqConfirmed_t Confirmed; + /*! * MCPS-Request parameters for a proprietary frame */ - McpsReqProprietary_t Proprietary; - } Req; - } McpsReq_t; + McpsReqProprietary_t Proprietary; + } Req; + } McpsReq_t; - /*! + /*! * LoRaMAC MCPS-Confirm */ - typedef struct sMcpsConfirm - { - /*! + typedef struct sMcpsConfirm + { + /*! * Holds the previously performed MCPS-Request */ - Mcps_t McpsRequest; - /*! + Mcps_t McpsRequest; + /*! * Status of the operation */ - LoRaMacEventInfoStatus_t Status; - /*! + LoRaMacEventInfoStatus_t Status; + /*! * Uplink datarate */ - uint8_t Datarate; - /*! + uint8_t Datarate; + /*! * Transmission power */ - int8_t TxPower; - /*! + int8_t TxPower; + /*! * Set if an acknowledgement was received */ - bool AckReceived; - /*! + bool AckReceived; + /*! * Provides the number of retransmissions */ - uint8_t NbRetries; - /*! + uint8_t NbRetries; + /*! * The transmission time on air of the frame */ - TimerTime_t TxTimeOnAir; - /*! + TimerTime_t TxTimeOnAir; + /*! * The uplink counter value related to the frame */ - uint32_t UpLinkCounter; - /*! + uint32_t UpLinkCounter; + /*! * The uplink frequency related to the frame */ - uint32_t UpLinkFrequency; - } McpsConfirm_t; + uint32_t UpLinkFrequency; + } McpsConfirm_t; - /*! + /*! * LoRaMAC MCPS-Indication primitive */ - typedef struct sMcpsIndication - { - /*! + typedef struct sMcpsIndication + { + /*! * MCPS-Indication type */ - Mcps_t McpsIndication; - /*! + Mcps_t McpsIndication; + /*! * Status of the operation */ - LoRaMacEventInfoStatus_t Status; - /*! + LoRaMacEventInfoStatus_t Status; + /*! * Multicast */ - uint8_t Multicast; - /*! + uint8_t Multicast; + /*! * Application port */ - uint8_t Port; - /*! + uint8_t Port; + /*! * Downlink datarate */ - uint8_t RxDatarate; - /*! + uint8_t RxDatarate; + /*! * Frame pending status */ - uint8_t FramePending; - /*! + uint8_t FramePending; + /*! * Pointer to the received data stream */ - uint8_t *Buffer; - /*! + uint8_t *Buffer; + /*! * Size of the received data stream */ - uint8_t BufferSize; - /*! + uint8_t BufferSize; + /*! * Indicates, if data is available */ - bool RxData; - /*! + bool RxData; + /*! * Rssi of the received packet */ - int16_t Rssi; - /*! + int16_t Rssi; + /*! * Snr of the received packet */ - uint8_t Snr; - /*! + uint8_t Snr; + /*! * Receive window * * [0: Rx window 1, 1: Rx window 2] */ - uint8_t RxSlot; - /*! + uint8_t RxSlot; + /*! * Set if an acknowledgement was received */ - bool AckReceived; - /*! + bool AckReceived; + /*! * The downlink counter value for the received frame */ - uint32_t DownLinkCounter; - } McpsIndication_t; + uint32_t DownLinkCounter; + } McpsIndication_t; - /*! + /*! * \brief LoRaMAC management services * * \details The following table list the primitives which are supported by the @@ -959,140 +959,140 @@ extern "C" * MLME-Request | \ref LoRaMacMlmeRequest * MLME-Confirm | MacMlmeConfirm in \ref LoRaMacPrimitives_t */ - typedef enum eMlme - { - /*! + typedef enum eMlme + { + /*! * Initiates the Over-the-Air activation * * LoRaWAN Specification V1.0.2, chapter 6.2 */ - MLME_JOIN, - /*! + MLME_JOIN, + /*! * LinkCheckReq - Connectivity validation * * LoRaWAN Specification V1.0.2, chapter 5, table 4 */ - MLME_LINK_CHECK, - /*! + MLME_LINK_CHECK, + /*! * Sets Tx continuous wave mode * * LoRaWAN end-device certification */ - MLME_TXCW, - /*! + MLME_TXCW, + /*! * Sets Tx continuous wave mode (new LoRa-Alliance CC definition) * * LoRaWAN end-device certification */ - MLME_TXCW_1, - } Mlme_t; + MLME_TXCW_1, + } Mlme_t; - /*! + /*! * LoRaMAC MLME-Request for the join service */ - typedef struct sMlmeReqJoin - { - /*! + typedef struct sMlmeReqJoin + { + /*! * Globally unique end-device identifier * * LoRaWAN Specification V1.0.2, chapter 6.2.1 */ - uint8_t *DevEui; - /*! + uint8_t *DevEui; + /*! * Application identifier * * LoRaWAN Specification V1.0.2, chapter 6.1.2 */ - uint8_t *AppEui; - /*! + uint8_t *AppEui; + /*! * AES-128 application key * * LoRaWAN Specification V1.0.2, chapter 6.2.2 */ - uint8_t *AppKey; - /*! + uint8_t *AppKey; + /*! * Number of trials for the join request. */ - uint8_t NbTrials; - } MlmeReqJoin_t; + uint8_t NbTrials; + } MlmeReqJoin_t; - /*! + /*! * LoRaMAC MLME-Request for Tx continuous wave mode */ - typedef struct sMlmeReqTxCw - { - /*! + typedef struct sMlmeReqTxCw + { + /*! * Time in seconds while the radio is kept in continuous wave mode */ - uint16_t Timeout; - /*! + uint16_t Timeout; + /*! * RF frequency to set (Only used with new way) */ - uint32_t Frequency; - /*! + uint32_t Frequency; + /*! * RF output power to set (Only used with new way) */ - uint8_t Power; - } MlmeReqTxCw_t; + uint8_t Power; + } MlmeReqTxCw_t; - /*! + /*! * LoRaMAC MLME-Request structure */ - typedef struct sMlmeReq - { - /*! + typedef struct sMlmeReq + { + /*! * MLME-Request type */ - Mlme_t Type; + Mlme_t Type; - /*! + /*! * MLME-Request parameters */ - union uMlmeParam { - /*! + union uMlmeParam { + /*! * MLME-Request parameters for a join request */ - MlmeReqJoin_t Join; - /*! + MlmeReqJoin_t Join; + /*! * MLME-Request parameters for Tx continuous mode request */ - MlmeReqTxCw_t TxCw; - } Req; - } MlmeReq_t; + MlmeReqTxCw_t TxCw; + } Req; + } MlmeReq_t; - /*! + /*! * LoRaMAC MLME-Confirm primitive */ - typedef struct sMlmeConfirm - { - /*! + typedef struct sMlmeConfirm + { + /*! * Holds the previously performed MLME-Request */ - Mlme_t MlmeRequest; - /*! + Mlme_t MlmeRequest; + /*! * Status of the operation */ - LoRaMacEventInfoStatus_t Status; - /*! + LoRaMacEventInfoStatus_t Status; + /*! * The transmission time on air of the frame */ - TimerTime_t TxTimeOnAir; - /*! + TimerTime_t TxTimeOnAir; + /*! * Demodulation margin. Contains the link margin [dB] of the last * successfully received LinkCheckReq */ - uint8_t DemodMargin; - /*! + uint8_t DemodMargin; + /*! * Number of gateways which received the last LinkCheckReq */ - uint8_t NbGateways; - /*! + uint8_t NbGateways; + /*! * Provides the number of retransmissions */ - uint8_t NbRetries; - } MlmeConfirm_t; + uint8_t NbRetries; + } MlmeConfirm_t; - /*! + /*! * LoRa Mac Information Base (MIB) * * The following table lists the MIB parameters and the related attributes: @@ -1137,554 +1137,554 @@ extern "C" * MIB-Set | \ref LoRaMacMibSetRequestConfirm * MIB-Get | \ref LoRaMacMibGetRequestConfirm */ - typedef enum eMib - { - /*! + typedef enum eMib + { + /*! * LoRaWAN device class * * LoRaWAN Specification V1.0.2 */ - MIB_DEVICE_CLASS, - /*! + MIB_DEVICE_CLASS, + /*! * LoRaWAN Network joined attribute * * LoRaWAN Specification V1.0.2 */ - MIB_NETWORK_JOINED, - /*! + MIB_NETWORK_JOINED, + /*! * Adaptive data rate * * LoRaWAN Specification V1.0.2, chapter 4.3.1.1 * * [true: ADR enabled, false: ADR disabled] */ - MIB_ADR, - /*! + MIB_ADR, + /*! * Network identifier * * LoRaWAN Specification V1.0.2, chapter 6.1.1 */ - MIB_NET_ID, - /*! + MIB_NET_ID, + /*! * End-device address * * LoRaWAN Specification V1.0.2, chapter 6.1.1 */ - MIB_DEV_ADDR, - /*! + MIB_DEV_ADDR, + /*! * Network session key * * LoRaWAN Specification V1.0.2, chapter 6.1.3 */ - MIB_NWK_SKEY, - /*! + MIB_NWK_SKEY, + /*! * Application session key * * LoRaWAN Specification V1.0.2, chapter 6.1.4 */ - MIB_APP_SKEY, - /*! + MIB_APP_SKEY, + /*! * Set the network type to public or private * * LoRaWAN Regional Parameters V1.0.2rB * * [true: public network, false: private network] */ - MIB_PUBLIC_NETWORK, - /*! + MIB_PUBLIC_NETWORK, + /*! * Support the operation with repeaters * * LoRaWAN Regional Parameters V1.0.2rB * * [true: repeater support enabled, false: repeater support disabled] */ - MIB_REPEATER_SUPPORT, - /*! + MIB_REPEATER_SUPPORT, + /*! * Communication channels. A get request will return a * pointer which references the first entry of the channel list. The * list is of size LORA_MAX_NB_CHANNELS * * LoRaWAN Regional Parameters V1.0.2rB */ - MIB_CHANNELS, - /*! + MIB_CHANNELS, + /*! * Set receive window 2 channel * * LoRaWAN Specification V1.0.2, chapter 3.3.1 */ - MIB_RX2_CHANNEL, - /*! + MIB_RX2_CHANNEL, + /*! * Set receive window 2 channel * * LoRaWAN Specification V1.0.2, chapter 3.3.2 */ - MIB_RX2_DEFAULT_CHANNEL, - /*! + MIB_RX2_DEFAULT_CHANNEL, + /*! * LoRaWAN channels mask * * LoRaWAN Regional Parameters V1.0.2rB */ - MIB_CHANNELS_MASK, - /*! + MIB_CHANNELS_MASK, + /*! * LoRaWAN default channels mask * * LoRaWAN Regional Parameters V1.0.2rB */ - MIB_CHANNELS_DEFAULT_MASK, - /*! + MIB_CHANNELS_DEFAULT_MASK, + /*! * Set the number of repetitions on a channel * * LoRaWAN Specification V1.0.2, chapter 5.2 */ - MIB_CHANNELS_NB_REP, - /*! + MIB_CHANNELS_NB_REP, + /*! * Maximum receive window duration in [ms] * * LoRaWAN Specification V1.0.2, chapter 3.3.3 */ - MIB_MAX_RX_WINDOW_DURATION, - /*! + MIB_MAX_RX_WINDOW_DURATION, + /*! * Receive delay 1 in [ms] * * LoRaWAN Regional Parameters V1.0.2rB */ - MIB_RECEIVE_DELAY_1, - /*! + MIB_RECEIVE_DELAY_1, + /*! * Receive delay 2 in [ms] * * LoRaWAN Regional Parameters V1.0.2rB */ - MIB_RECEIVE_DELAY_2, - /*! + MIB_RECEIVE_DELAY_2, + /*! * Join accept delay 1 in [ms] * * LoRaWAN Regional Parameters V1.0.2rB */ - MIB_JOIN_ACCEPT_DELAY_1, - /*! + MIB_JOIN_ACCEPT_DELAY_1, + /*! * Join accept delay 2 in [ms] * * LoRaWAN Regional Parameters V1.0.2rB */ - MIB_JOIN_ACCEPT_DELAY_2, - /*! + MIB_JOIN_ACCEPT_DELAY_2, + /*! * Default Data rate of a channel * * LoRaWAN Regional Parameters V1.0.2rB * * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details. */ - MIB_CHANNELS_DEFAULT_DATARATE, - /*! + MIB_CHANNELS_DEFAULT_DATARATE, + /*! * Data rate of a channel * * LoRaWAN Regional Parameters V1.0.2rB * * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details. */ - MIB_CHANNELS_DATARATE, - /*! + MIB_CHANNELS_DATARATE, + /*! * Transmission power of a channel * * LoRaWAN Regional Parameters V1.0.2rB * * The allowed ranges are region specific. Please refer to \ref TX_POWER_0 to \ref TX_POWER_15 for details. */ - MIB_CHANNELS_TX_POWER, - /*! + MIB_CHANNELS_TX_POWER, + /*! * Transmission power of a channel * * LoRaWAN Regional Parameters V1.0.2rB * * The allowed ranges are region specific. Please refer to \ref TX_POWER_0 to \ref TX_POWER_15 for details. */ - MIB_CHANNELS_DEFAULT_TX_POWER, - /*! + MIB_CHANNELS_DEFAULT_TX_POWER, + /*! * LoRaWAN Up-link counter * * LoRaWAN Specification V1.0.2, chapter 4.3.1.5 */ - MIB_UPLINK_COUNTER, - /*! + MIB_UPLINK_COUNTER, + /*! * LoRaWAN Down-link counter * * LoRaWAN Specification V1.0.2, chapter 4.3.1.5 */ - MIB_DOWNLINK_COUNTER, - /*! + MIB_DOWNLINK_COUNTER, + /*! * Multicast channels. A get request will return a pointer to the first * entry of the multicast channel linked list. If the pointer is equal to * NULL, the list is empty. */ - MIB_MULTICAST_CHANNEL, - /*! + MIB_MULTICAST_CHANNEL, + /*! * System overall timing error in milliseconds. * [-SystemMaxRxError : +SystemMaxRxError] * Default: +/-10 ms */ - MIB_SYSTEM_MAX_RX_ERROR, - /*! + MIB_SYSTEM_MAX_RX_ERROR, + /*! * Minimum required number of symbols to detect an Rx frame * Default: 6 symbols */ - MIB_MIN_RX_SYMBOLS, - /*! + MIB_MIN_RX_SYMBOLS, + /*! * Antenna gain of the node. Default value is region specific. * The antenna gain is used to calculate the TX power of the node. * The formula is: * radioTxPower = ( int8_t )floor( maxEirp - antennaGain ) */ - MIB_ANTENNA_GAIN - } Mib_t; + MIB_ANTENNA_GAIN + } Mib_t; - /*! + /*! * LoRaMAC MIB parameters */ - typedef union uMibParam { - /*! + typedef union uMibParam { + /*! * LoRaWAN device class * * Related MIB type: \ref MIB_DEVICE_CLASS */ - DeviceClass_t Class; - /*! + DeviceClass_t Class; + /*! * LoRaWAN network joined attribute * * Related MIB type: \ref MIB_NETWORK_JOINED */ - bool IsNetworkJoined; - /*! + bool IsNetworkJoined; + /*! * Activation state of ADR * * Related MIB type: \ref MIB_ADR */ - bool AdrEnable; - /*! + bool AdrEnable; + /*! * Network identifier * * Related MIB type: \ref MIB_NET_ID */ - uint32_t NetID; - /*! + uint32_t NetID; + /*! * End-device address * * Related MIB type: \ref MIB_DEV_ADDR */ - uint32_t DevAddr; - /*! + uint32_t DevAddr; + /*! * Network session key * * Related MIB type: \ref MIB_NWK_SKEY */ - uint8_t *NwkSKey; - /*! + uint8_t *NwkSKey; + /*! * Application session key * * Related MIB type: \ref MIB_APP_SKEY */ - uint8_t *AppSKey; - /*! + uint8_t *AppSKey; + /*! * Enable or disable a public network * * Related MIB type: \ref MIB_PUBLIC_NETWORK */ - bool EnablePublicNetwork; - /*! + bool EnablePublicNetwork; + /*! * Enable or disable repeater support * * Related MIB type: \ref MIB_REPEATER_SUPPORT */ - bool EnableRepeaterSupport; - /*! + bool EnableRepeaterSupport; + /*! * LoRaWAN Channel * * Related MIB type: \ref MIB_CHANNELS */ - ChannelParams_t *ChannelList; - /*! + ChannelParams_t *ChannelList; + /*! * Channel for the receive window 2 * * Related MIB type: \ref MIB_RX2_CHANNEL */ - Rx2ChannelParams_t Rx2Channel; - /*! + Rx2ChannelParams_t Rx2Channel; + /*! * Channel for the receive window 2 * * Related MIB type: \ref MIB_RX2_DEFAULT_CHANNEL */ - Rx2ChannelParams_t Rx2DefaultChannel; - /*! + Rx2ChannelParams_t Rx2DefaultChannel; + /*! * Channel mask * * Related MIB type: \ref MIB_CHANNELS_MASK */ - uint16_t *ChannelsMask; - /*! + uint16_t *ChannelsMask; + /*! * Default channel mask * * Related MIB type: \ref MIB_CHANNELS_DEFAULT_MASK */ - uint16_t *ChannelsDefaultMask; - /*! + uint16_t *ChannelsDefaultMask; + /*! * Number of frame repetitions * * Related MIB type: \ref MIB_CHANNELS_NB_REP */ - uint8_t ChannelNbRep; - /*! + uint8_t ChannelNbRep; + /*! * Maximum receive window duration * * Related MIB type: \ref MIB_MAX_RX_WINDOW_DURATION */ - uint32_t MaxRxWindow; - /*! + uint32_t MaxRxWindow; + /*! * Receive delay 1 * * Related MIB type: \ref MIB_RECEIVE_DELAY_1 */ - uint32_t ReceiveDelay1; - /*! + uint32_t ReceiveDelay1; + /*! * Receive delay 2 * * Related MIB type: \ref MIB_RECEIVE_DELAY_2 */ - uint32_t ReceiveDelay2; - /*! + uint32_t ReceiveDelay2; + /*! * Join accept delay 1 * * Related MIB type: \ref MIB_JOIN_ACCEPT_DELAY_1 */ - uint32_t JoinAcceptDelay1; - /*! + uint32_t JoinAcceptDelay1; + /*! * Join accept delay 2 * * Related MIB type: \ref MIB_JOIN_ACCEPT_DELAY_2 */ - uint32_t JoinAcceptDelay2; - /*! + uint32_t JoinAcceptDelay2; + /*! * Channels data rate * * Related MIB type: \ref MIB_CHANNELS_DEFAULT_DATARATE */ - int8_t ChannelsDefaultDatarate; - /*! + int8_t ChannelsDefaultDatarate; + /*! * Channels data rate * * Related MIB type: \ref MIB_CHANNELS_DATARATE */ - int8_t ChannelsDatarate; - /*! + int8_t ChannelsDatarate; + /*! * Channels TX power * * Related MIB type: \ref MIB_CHANNELS_DEFAULT_TX_POWER */ - int8_t ChannelsDefaultTxPower; - /*! + int8_t ChannelsDefaultTxPower; + /*! * Channels TX power * * Related MIB type: \ref MIB_CHANNELS_TX_POWER */ - int8_t ChannelsTxPower; - /*! + int8_t ChannelsTxPower; + /*! * LoRaWAN Up-link counter * * Related MIB type: \ref MIB_UPLINK_COUNTER */ - uint32_t UpLinkCounter; - /*! + uint32_t UpLinkCounter; + /*! * LoRaWAN Down-link counter * * Related MIB type: \ref MIB_DOWNLINK_COUNTER */ - uint32_t DownLinkCounter; - /*! + uint32_t DownLinkCounter; + /*! * Multicast channel * * Related MIB type: \ref MIB_MULTICAST_CHANNEL */ - MulticastParams_t *MulticastList; - /*! + MulticastParams_t *MulticastList; + /*! * System overall timing error in milliseconds. * * Related MIB type: \ref MIB_SYSTEM_MAX_RX_ERROR */ - uint32_t SystemMaxRxError; - /*! + uint32_t SystemMaxRxError; + /*! * Minimum required number of symbols to detect an Rx frame * * Related MIB type: \ref MIB_MIN_RX_SYMBOLS */ - uint8_t MinRxSymbols; - /*! + uint8_t MinRxSymbols; + /*! * Antenna gain * * Related MIB type: \ref MIB_ANTENNA_GAIN */ - float AntennaGain; - } MibParam_t; + float AntennaGain; + } MibParam_t; - /*! + /*! * LoRaMAC MIB-RequestConfirm structure */ - typedef struct eMibRequestConfirm - { - /*! + typedef struct eMibRequestConfirm + { + /*! * MIB-Request type */ - Mib_t Type; + Mib_t Type; - /*! + /*! * MLME-RequestConfirm parameters */ - MibParam_t Param; - } MibRequestConfirm_t; + MibParam_t Param; + } MibRequestConfirm_t; - /*! + /*! * LoRaMAC tx information */ - typedef struct sLoRaMacTxInfo - { - /*! + typedef struct sLoRaMacTxInfo + { + /*! * Defines the size of the applicative payload which can be processed */ - uint8_t MaxPossiblePayload; - /*! + uint8_t MaxPossiblePayload; + /*! * The current payload size, dependent on the current datarate */ - uint8_t CurrentPayloadSize; - } LoRaMacTxInfo_t; + uint8_t CurrentPayloadSize; + } LoRaMacTxInfo_t; - /*! + /*! * LoRaMAC Status */ - typedef enum eLoRaMacStatus - { - /*! + typedef enum eLoRaMacStatus + { + /*! * Service started successfully */ - LORAMAC_STATUS_OK, - /*! + LORAMAC_STATUS_OK, + /*! * Service not started - LoRaMAC is busy */ - LORAMAC_STATUS_BUSY, - /*! + LORAMAC_STATUS_BUSY, + /*! * Service unknown */ - LORAMAC_STATUS_SERVICE_UNKNOWN, - /*! + LORAMAC_STATUS_SERVICE_UNKNOWN, + /*! * Service not started - invalid parameter */ - LORAMAC_STATUS_PARAMETER_INVALID, - /*! + LORAMAC_STATUS_PARAMETER_INVALID, + /*! * Service not started - invalid frequency */ - LORAMAC_STATUS_FREQUENCY_INVALID, - /*! + LORAMAC_STATUS_FREQUENCY_INVALID, + /*! * Service not started - invalid datarate */ - LORAMAC_STATUS_DATARATE_INVALID, - /*! + LORAMAC_STATUS_DATARATE_INVALID, + /*! * Service not started - invalid frequency and datarate */ - LORAMAC_STATUS_FREQ_AND_DR_INVALID, - /*! + LORAMAC_STATUS_FREQ_AND_DR_INVALID, + /*! * Service not started - the device is not in a LoRaWAN */ - LORAMAC_STATUS_NO_NETWORK_JOINED, - /*! + LORAMAC_STATUS_NO_NETWORK_JOINED, + /*! * Service not started - payload length error */ - LORAMAC_STATUS_LENGTH_ERROR, - /*! + LORAMAC_STATUS_LENGTH_ERROR, + /*! * Service not started - the device is switched off */ - LORAMAC_STATUS_DEVICE_OFF, - /*! + LORAMAC_STATUS_DEVICE_OFF, + /*! * Service not started - the specified region is not supported * or not activated with preprocessor definitions. */ - LORAMAC_STATUS_REGION_NOT_SUPPORTED - } LoRaMacStatus_t; + LORAMAC_STATUS_REGION_NOT_SUPPORTED + } LoRaMacStatus_t; - /*! + /*! * LoRaMAC region enumeration */ - typedef enum eLoRaMacRegion_t - { - /*! + typedef enum eLoRaMacRegion_t + { + /*! * AS band on 923MHz */ - LORAMAC_REGION_AS923, - /*! + LORAMAC_REGION_AS923, + /*! * Australian band on 915MHz */ - LORAMAC_REGION_AU915, - /*! + LORAMAC_REGION_AU915, + /*! * Chinese band on 470MHz */ - LORAMAC_REGION_CN470, - /*! + LORAMAC_REGION_CN470, + /*! * Chinese band on 779MHz */ - LORAMAC_REGION_CN779, - /*! + LORAMAC_REGION_CN779, + /*! * European band on 433MHz */ - LORAMAC_REGION_EU433, - /*! + LORAMAC_REGION_EU433, + /*! * European band on 868MHz */ - LORAMAC_REGION_EU868, - /*! + LORAMAC_REGION_EU868, + /*! * South korean band on 920MHz */ - LORAMAC_REGION_KR920, - /*! + LORAMAC_REGION_KR920, + /*! * India band on 865MHz */ - LORAMAC_REGION_IN865, - /*! + LORAMAC_REGION_IN865, + /*! * North american band on 915MHz */ - LORAMAC_REGION_US915, - /*! + LORAMAC_REGION_US915, + /*! * North american band on 915MHz with a maximum of 16 channels */ - LORAMAC_REGION_US915_HYBRID, - } LoRaMacRegion_t; + LORAMAC_REGION_US915_HYBRID, + } LoRaMacRegion_t; - /*! + /*! * LoRaMAC events structure * Used to notify upper layers of MAC events */ - typedef struct sLoRaMacPrimitives - { - /*! + typedef struct sLoRaMacPrimitives + { + /*! * \brief MCPS-Confirm primitive * * \param [OUT] MCPS-Confirm parameters */ - void (*MacMcpsConfirm)(McpsConfirm_t *McpsConfirm); - /*! + void (*MacMcpsConfirm)(McpsConfirm_t *McpsConfirm); + /*! * \brief MCPS-Indication primitive * * \param [OUT] MCPS-Indication parameters */ - void (*MacMcpsIndication)(McpsIndication_t *McpsIndication); - /*! + void (*MacMcpsIndication)(McpsIndication_t *McpsIndication); + /*! * \brief MLME-Confirm primitive * * \param [OUT] MLME-Confirm parameters */ - void (*MacMlmeConfirm)(MlmeConfirm_t *MlmeConfirm); - } LoRaMacPrimitives_t; + void (*MacMlmeConfirm)(MlmeConfirm_t *MlmeConfirm); + } LoRaMacPrimitives_t; - /*! + /*! * LoRaMAC callback structure */ - typedef struct sLoRaMacCallback - { - /*! + typedef struct sLoRaMacCallback + { + /*! * \brief Measures the battery level * * \retval Battery level [0: node is connected to an external @@ -1692,15 +1692,15 @@ extern "C" * and 254 is the maximum value, 255: the node was not able * to measure the battery level] */ - uint8_t (*GetBatteryLevel)(void); - } LoRaMacCallback_t; + uint8_t (*GetBatteryLevel)(void); + } LoRaMacCallback_t; - /*! + /*! * LoRaMAC Max EIRP (dBm) table */ - static const uint8_t LoRaMacMaxEirpTable[] = {8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36}; + static const uint8_t LoRaMacMaxEirpTable[] = {8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36}; - /*! + /*! * \brief LoRaMAC layer initialization * * \details In addition to the initialization of the LoRaMAC layer, this @@ -1722,9 +1722,9 @@ extern "C" * \ref LORAMAC_STATUS_PARAMETER_INVALID, * \ref LORAMAC_STATUS_REGION_NOT_SUPPORTED. */ - LoRaMacStatus_t LoRaMacInitialization(LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks, LoRaMacRegion_t region); + LoRaMacStatus_t LoRaMacInitialization(LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks, LoRaMacRegion_t region); - /*! + /*! * \brief Queries the LoRaMAC if it is possible to send the next frame with * a given payload size. The LoRaMAC takes scheduled MAC commands into * account and reports, when the frame can be send or not. @@ -1747,9 +1747,9 @@ extern "C" * In case the query is valid, and the LoRaMAC is able to send the frame, * the function returns \ref LORAMAC_STATUS_OK. */ - LoRaMacStatus_t LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t *txInfo); + LoRaMacStatus_t LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t *txInfo); - /*! + /*! * \brief LoRaMAC channel add service * * \details Adds a new channel to the channel list and activates the id in @@ -1765,9 +1765,9 @@ extern "C" * \ref LORAMAC_STATUS_BUSY, * \ref LORAMAC_STATUS_PARAMETER_INVALID. */ - LoRaMacStatus_t LoRaMacChannelAdd(uint8_t id, ChannelParams_t params); + LoRaMacStatus_t LoRaMacChannelAdd(uint8_t id, ChannelParams_t params); - /*! + /*! * \brief LoRaMAC channel remove service * * \details Deactivates the id in the channel mask. @@ -1779,9 +1779,9 @@ extern "C" * \ref LORAMAC_STATUS_BUSY, * \ref LORAMAC_STATUS_PARAMETER_INVALID. */ - LoRaMacStatus_t LoRaMacChannelRemove(uint8_t id); + LoRaMacStatus_t LoRaMacChannelRemove(uint8_t id); - /*! + /*! * \brief LoRaMAC multicast channel link service * * \details Links a multicast channel into the linked list. @@ -1793,9 +1793,9 @@ extern "C" * \ref LORAMAC_STATUS_BUSY, * \ref LORAMAC_STATUS_PARAMETER_INVALID. */ - LoRaMacStatus_t LoRaMacMulticastChannelLink(MulticastParams_t *channelParam); + LoRaMacStatus_t LoRaMacMulticastChannelLink(MulticastParams_t *channelParam); - /*! + /*! * \brief LoRaMAC multicast channel unlink service * * \details Unlinks a multicast channel from the linked list. @@ -1807,9 +1807,9 @@ extern "C" * \ref LORAMAC_STATUS_BUSY, * \ref LORAMAC_STATUS_PARAMETER_INVALID. */ - LoRaMacStatus_t LoRaMacMulticastChannelUnlink(MulticastParams_t *channelParam); + LoRaMacStatus_t LoRaMacMulticastChannelUnlink(MulticastParams_t *channelParam); - /*! + /*! * \brief LoRaMAC MIB-Get * * \details The mac information base service to get attributes of the LoRaMac @@ -1835,9 +1835,9 @@ extern "C" * \ref LORAMAC_STATUS_SERVICE_UNKNOWN, * \ref LORAMAC_STATUS_PARAMETER_INVALID. */ - LoRaMacStatus_t LoRaMacMibGetRequestConfirm(MibRequestConfirm_t *mibGet); + LoRaMacStatus_t LoRaMacMibGetRequestConfirm(MibRequestConfirm_t *mibGet); - /*! + /*! * \brief LoRaMAC MIB-Set * * \details The mac information base service to set attributes of the LoRaMac @@ -1866,9 +1866,9 @@ extern "C" * \ref LORAMAC_STATUS_SERVICE_UNKNOWN, * \ref LORAMAC_STATUS_PARAMETER_INVALID. */ - LoRaMacStatus_t LoRaMacMibSetRequestConfirm(MibRequestConfirm_t *mibSet); + LoRaMacStatus_t LoRaMacMibSetRequestConfirm(MibRequestConfirm_t *mibSet); - /*! + /*! * \brief LoRaMAC MLME-Request * * \details The Mac layer management entity handles management services. The @@ -1913,9 +1913,9 @@ extern "C" * \ref LORAMAC_STATUS_LENGTH_ERROR, * \ref LORAMAC_STATUS_DEVICE_OFF. */ - LoRaMacStatus_t LoRaMacMlmeRequest(MlmeReq_t *mlmeRequest); + LoRaMacStatus_t LoRaMacMlmeRequest(MlmeReq_t *mlmeRequest); - /*! + /*! * \brief LoRaMAC MCPS-Request * * \details The Mac Common Part Sublayer handles data services. The following @@ -1948,8 +1948,8 @@ extern "C" * \ref LORAMAC_STATUS_LENGTH_ERROR, * \ref LORAMAC_STATUS_DEVICE_OFF. */ - LoRaMacStatus_t LoRaMacMcpsRequest(McpsReq_t *mcpsRequest); + LoRaMacStatus_t LoRaMacMcpsRequest(McpsReq_t *mcpsRequest); - /*! \} defgroup LORAMAC */ + /*! \} defgroup LORAMAC */ }; #endif // __LORAMAC_H__ diff --git a/src/mac/LoRaMacCrypto.cpp b/src/mac/LoRaMacCrypto.cpp index 716829e..e303578 100644 --- a/src/mac/LoRaMacCrypto.cpp +++ b/src/mac/LoRaMacCrypto.cpp @@ -34,38 +34,38 @@ extern "C" */ #define LORAMAC_MIC_BLOCK_B0_SIZE 16 - /*! + /*! * MIC field computation initial data */ - static uint8_t MicBlockB0[] = {0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static uint8_t MicBlockB0[] = {0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - /*! + /*! * Contains the computed MIC field. * * \remark Only the 4 first bytes are used */ - static uint8_t Mic[16]; + static uint8_t Mic[16]; - /*! + /*! * Encryption aBlock and sBlock */ - static uint8_t aBlock[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - static uint8_t sBlock[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static uint8_t aBlock[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static uint8_t sBlock[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - /*! + /*! * AES computation context variable */ - static lora_aes_context AesContext; + static lora_aes_context AesContext; - /*! + /*! * CMAC computation context variable */ - static AES_CMAC_CTX AesCmacCtx[1]; + static AES_CMAC_CTX AesCmacCtx[1]; - /*! + /*! * \brief Computes the LoRaMAC frame MIC field * * \param [IN] buffer Data buffer @@ -76,128 +76,128 @@ extern "C" * \param [IN] sequenceCounter Frame sequence counter * \param [OUT] mic Computed MIC field */ - void LoRaMacComputeMic(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic) - { - MicBlockB0[5] = dir; - - MicBlockB0[6] = (address)&0xFF; - MicBlockB0[7] = (address >> 8) & 0xFF; - MicBlockB0[8] = (address >> 16) & 0xFF; - MicBlockB0[9] = (address >> 24) & 0xFF; - - MicBlockB0[10] = (sequenceCounter)&0xFF; - MicBlockB0[11] = (sequenceCounter >> 8) & 0xFF; - MicBlockB0[12] = (sequenceCounter >> 16) & 0xFF; - MicBlockB0[13] = (sequenceCounter >> 24) & 0xFF; - - MicBlockB0[15] = size & 0xFF; - - AES_CMAC_Init(AesCmacCtx); - - AES_CMAC_SetKey(AesCmacCtx, key); - - AES_CMAC_Update(AesCmacCtx, MicBlockB0, LORAMAC_MIC_BLOCK_B0_SIZE); - - AES_CMAC_Update(AesCmacCtx, buffer, size & 0xFF); - - AES_CMAC_Final(Mic, AesCmacCtx); - - *mic = (uint32_t)((uint32_t)Mic[3] << 24 | (uint32_t)Mic[2] << 16 | (uint32_t)Mic[1] << 8 | (uint32_t)Mic[0]); - } - - void LoRaMacPayloadEncrypt(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer) - { - uint16_t i; - uint8_t bufferIndex = 0; - uint16_t ctr = 1; - - memset1(AesContext.ksch, '\0', 240); - lora_aes_set_key(key, 16, &AesContext); - - aBlock[5] = dir; - - aBlock[6] = (address)&0xFF; - aBlock[7] = (address >> 8) & 0xFF; - aBlock[8] = (address >> 16) & 0xFF; - aBlock[9] = (address >> 24) & 0xFF; - - aBlock[10] = (sequenceCounter)&0xFF; - aBlock[11] = (sequenceCounter >> 8) & 0xFF; - aBlock[12] = (sequenceCounter >> 16) & 0xFF; - aBlock[13] = (sequenceCounter >> 24) & 0xFF; - - while (size >= 16) - { - aBlock[15] = ((ctr)&0xFF); - ctr++; - lora_aes_encrypt(aBlock, sBlock, &AesContext); - for (i = 0; i < 16; i++) - { - encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; - } - size -= 16; - bufferIndex += 16; - } - - if (size > 0) - { - aBlock[15] = ((ctr)&0xFF); - lora_aes_encrypt(aBlock, sBlock, &AesContext); - for (i = 0; i < size; i++) - { - encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; - } - } - } - - void LoRaMacPayloadDecrypt(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer) - { - LoRaMacPayloadEncrypt(buffer, size, key, address, dir, sequenceCounter, decBuffer); - } - - void LoRaMacJoinComputeMic(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic) - { - AES_CMAC_Init(AesCmacCtx); - - AES_CMAC_SetKey(AesCmacCtx, key); - - AES_CMAC_Update(AesCmacCtx, buffer, size & 0xFF); - - AES_CMAC_Final(Mic, AesCmacCtx); - - *mic = (uint32_t)((uint32_t)Mic[3] << 24 | (uint32_t)Mic[2] << 16 | (uint32_t)Mic[1] << 8 | (uint32_t)Mic[0]); - } - - void LoRaMacJoinDecrypt(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer) - { - memset1(AesContext.ksch, '\0', 240); - lora_aes_set_key(key, 16, &AesContext); - lora_aes_encrypt(buffer, decBuffer, &AesContext); - // Check if optional CFList is included - if (size >= 16) - { - lora_aes_encrypt(buffer + 16, decBuffer + 16, &AesContext); - } - } - - void LoRaMacJoinComputeSKeys(const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey) - { - uint8_t nonce[16]; - uint8_t *pDevNonce = (uint8_t *)&devNonce; - - memset1(AesContext.ksch, '\0', 240); - lora_aes_set_key(key, 16, &AesContext); - - memset1(nonce, 0, sizeof(nonce)); - nonce[0] = 0x01; - memcpy1(nonce + 1, appNonce, 6); - memcpy1(nonce + 7, pDevNonce, 2); - lora_aes_encrypt(nonce, nwkSKey, &AesContext); - - memset1(nonce, 0, sizeof(nonce)); - nonce[0] = 0x02; - memcpy1(nonce + 1, appNonce, 6); - memcpy1(nonce + 7, pDevNonce, 2); - lora_aes_encrypt(nonce, appSKey, &AesContext); - } + void LoRaMacComputeMic(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic) + { + MicBlockB0[5] = dir; + + MicBlockB0[6] = (address)&0xFF; + MicBlockB0[7] = (address >> 8) & 0xFF; + MicBlockB0[8] = (address >> 16) & 0xFF; + MicBlockB0[9] = (address >> 24) & 0xFF; + + MicBlockB0[10] = (sequenceCounter)&0xFF; + MicBlockB0[11] = (sequenceCounter >> 8) & 0xFF; + MicBlockB0[12] = (sequenceCounter >> 16) & 0xFF; + MicBlockB0[13] = (sequenceCounter >> 24) & 0xFF; + + MicBlockB0[15] = size & 0xFF; + + AES_CMAC_Init(AesCmacCtx); + + AES_CMAC_SetKey(AesCmacCtx, key); + + AES_CMAC_Update(AesCmacCtx, MicBlockB0, LORAMAC_MIC_BLOCK_B0_SIZE); + + AES_CMAC_Update(AesCmacCtx, buffer, size & 0xFF); + + AES_CMAC_Final(Mic, AesCmacCtx); + + *mic = (uint32_t)((uint32_t)Mic[3] << 24 | (uint32_t)Mic[2] << 16 | (uint32_t)Mic[1] << 8 | (uint32_t)Mic[0]); + } + + void LoRaMacPayloadEncrypt(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer) + { + uint16_t i; + uint8_t bufferIndex = 0; + uint16_t ctr = 1; + + memset1(AesContext.ksch, '\0', 240); + lora_aes_set_key(key, 16, &AesContext); + + aBlock[5] = dir; + + aBlock[6] = (address)&0xFF; + aBlock[7] = (address >> 8) & 0xFF; + aBlock[8] = (address >> 16) & 0xFF; + aBlock[9] = (address >> 24) & 0xFF; + + aBlock[10] = (sequenceCounter)&0xFF; + aBlock[11] = (sequenceCounter >> 8) & 0xFF; + aBlock[12] = (sequenceCounter >> 16) & 0xFF; + aBlock[13] = (sequenceCounter >> 24) & 0xFF; + + while (size >= 16) + { + aBlock[15] = ((ctr)&0xFF); + ctr++; + lora_aes_encrypt(aBlock, sBlock, &AesContext); + for (i = 0; i < 16; i++) + { + encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; + } + size -= 16; + bufferIndex += 16; + } + + if (size > 0) + { + aBlock[15] = ((ctr)&0xFF); + lora_aes_encrypt(aBlock, sBlock, &AesContext); + for (i = 0; i < size; i++) + { + encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; + } + } + } + + void LoRaMacPayloadDecrypt(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer) + { + LoRaMacPayloadEncrypt(buffer, size, key, address, dir, sequenceCounter, decBuffer); + } + + void LoRaMacJoinComputeMic(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic) + { + AES_CMAC_Init(AesCmacCtx); + + AES_CMAC_SetKey(AesCmacCtx, key); + + AES_CMAC_Update(AesCmacCtx, buffer, size & 0xFF); + + AES_CMAC_Final(Mic, AesCmacCtx); + + *mic = (uint32_t)((uint32_t)Mic[3] << 24 | (uint32_t)Mic[2] << 16 | (uint32_t)Mic[1] << 8 | (uint32_t)Mic[0]); + } + + void LoRaMacJoinDecrypt(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer) + { + memset1(AesContext.ksch, '\0', 240); + lora_aes_set_key(key, 16, &AesContext); + lora_aes_encrypt(buffer, decBuffer, &AesContext); + // Check if optional CFList is included + if (size >= 16) + { + lora_aes_encrypt(buffer + 16, decBuffer + 16, &AesContext); + } + } + + void LoRaMacJoinComputeSKeys(const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey) + { + uint8_t nonce[16]; + uint8_t *pDevNonce = (uint8_t *)&devNonce; + + memset1(AesContext.ksch, '\0', 240); + lora_aes_set_key(key, 16, &AesContext); + + memset1(nonce, 0, sizeof(nonce)); + nonce[0] = 0x01; + memcpy1(nonce + 1, appNonce, 6); + memcpy1(nonce + 7, pDevNonce, 2); + lora_aes_encrypt(nonce, nwkSKey, &AesContext); + + memset1(nonce, 0, sizeof(nonce)); + nonce[0] = 0x02; + memcpy1(nonce + 1, appNonce, 6); + memcpy1(nonce + 7, pDevNonce, 2); + lora_aes_encrypt(nonce, appSKey, &AesContext); + } }; \ No newline at end of file diff --git a/src/mac/LoRaMacCrypto.h b/src/mac/LoRaMacCrypto.h index 275ef53..d5e3995 100644 --- a/src/mac/LoRaMacCrypto.h +++ b/src/mac/LoRaMacCrypto.h @@ -39,7 +39,7 @@ extern "C" { -/*! + /*! * Computes the LoRaMAC frame MIC field * * \param [IN] buffer - Data buffer @@ -50,9 +50,9 @@ extern "C" * \param [IN] sequenceCounter - Frame sequence counter * \param [OUT] mic - Computed MIC field */ -void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic ); + void LoRaMacComputeMic(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic); -/*! + /*! * Computes the LoRaMAC payload encryption * * \param [IN] buffer - Data buffer @@ -63,9 +63,9 @@ void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key * \param [IN] sequenceCounter - Frame sequence counter * \param [OUT] encBuffer - Encrypted buffer */ -void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer ); + void LoRaMacPayloadEncrypt(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer); -/*! + /*! * Computes the LoRaMAC payload decryption * * \param [IN] buffer - Data buffer @@ -76,9 +76,9 @@ void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t * \param [IN] sequenceCounter - Frame sequence counter * \param [OUT] decBuffer - Decrypted buffer */ -void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer ); + void LoRaMacPayloadDecrypt(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer); -/*! + /*! * Computes the LoRaMAC Join Request frame MIC field * * \param [IN] buffer - Data buffer @@ -86,9 +86,9 @@ void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t * \param [IN] key - AES key to be used * \param [OUT] mic - Computed MIC field */ -void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic ); + void LoRaMacJoinComputeMic(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic); -/*! + /*! * Computes the LoRaMAC join frame decryption * * \param [IN] buffer - Data buffer @@ -96,9 +96,9 @@ void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t * \param [IN] key - AES key to be used * \param [OUT] decBuffer - Decrypted buffer */ -void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer ); + void LoRaMacJoinDecrypt(const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer); -/*! + /*! * Computes the LoRaMAC join frame decryption * * \param [IN] key - AES key to be used @@ -107,8 +107,8 @@ void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *ke * \param [OUT] nwkSKey - Network session key * \param [OUT] appSKey - Application session key */ -void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey ); + void LoRaMacJoinComputeSKeys(const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey); -/*! \} defgroup LORAMAC */ + /*! \} defgroup LORAMAC */ }; #endif // __LORAMAC_CRYPTO_H__ diff --git a/src/mac/LoRaMacHelper.cpp b/src/mac/LoRaMacHelper.cpp index ddce209..f08d6ba 100644 --- a/src/mac/LoRaMacHelper.cpp +++ b/src/mac/LoRaMacHelper.cpp @@ -20,7 +20,6 @@ *****************************************************************************/ #include "LoRaMacHelper.h" -#include "system/delay.h" #include "system/utilities.h" extern "C" diff --git a/src/mac/LoRaMacHelper.h b/src/mac/LoRaMacHelper.h index 5892ddc..b6bd36a 100644 --- a/src/mac/LoRaMacHelper.h +++ b/src/mac/LoRaMacHelper.h @@ -31,130 +31,130 @@ extern "C" { -#define LORAWAN_CONFIRMED_MSG_ON 0 /**< LoRaWAN confirmed messages */ -#define LORAWAN_CERTIF_PORT 224 /**< LoRaWAN certification port */ -#define LORAWAN_APP_PORT 2 /**< LoRaWAN application port, do not use 224. It is reserved for certification */ -#define LORAWAN_APP_DATA_MAX_SIZE 242 /**< LoRaWAN User application data buffer size*/ -#define LORAWAN_DEFAULT_DATARATE DR_0 /**< LoRaWAN Default datarate*/ +#define LORAWAN_CONFIRMED_MSG_ON 0 /**< LoRaWAN confirmed messages */ +#define LORAWAN_CERTIF_PORT 224 /**< LoRaWAN certification port */ +#define LORAWAN_APP_PORT 2 /**< LoRaWAN application port, do not use 224. It is reserved for certification */ +#define LORAWAN_APP_DATA_MAX_SIZE 242 /**< LoRaWAN User application data buffer size*/ +#define LORAWAN_DEFAULT_DATARATE DR_0 /**< LoRaWAN Default datarate*/ #define LORAWAN_DEFAULT_TX_POWER TX_POWER_0 /**< LoRaWAN Default tx power*/ - typedef struct lmh_param_s - { - bool adr_enable; /**< Activation state of adaptative Datarate */ - int8_t tx_data_rate; /**< Uplink datarate, if AdrEnable is off */ - bool enable_public_network; /**< Enable or disable a public network */ - uint8_t nb_trials; /**< Number of trials for the join request. */ - int8_t tx_power; /**< Uplink power */ - - } lmh_param_t; - - typedef enum - { - LMH_RESET = 0, - LMH_SET = !LMH_RESET - } lmh_join_status; - - typedef enum - { - LMH_ERROR = -1, - LMH_SUCCESS = 0 - } lmh_error_status; - - typedef enum - { - LMH_UNCONFIRMED_MSG = 0, - LMH_CONFIRMED_MSG = !LMH_UNCONFIRMED_MSG - } lmh_confirm; - - /**@brief Application Data structure - */ - typedef struct - { - uint8_t *buffer; /**< point to the LoRa App data buffer */ - uint8_t buffsize; /**< LoRa App data buffer size */ - uint8_t port; /**< Port on which the LoRa App is data is sent/ received */ - int16_t rssi; - uint8_t snr; - } lmh_app_data_t; - - /**@brief LoRaMac Helper Callbacks - */ - typedef struct lmh_callback_s - { - /**@brief Get the current battery level + typedef struct lmh_param_s + { + bool adr_enable; /**< Activation state of adaptative Datarate */ + int8_t tx_data_rate; /**< Uplink datarate, if AdrEnable is off */ + bool enable_public_network; /**< Enable or disable a public network */ + uint8_t nb_trials; /**< Number of trials for the join request. */ + int8_t tx_power; /**< Uplink power */ + + } lmh_param_t; + + typedef enum + { + LMH_RESET = 0, + LMH_SET = !LMH_RESET + } lmh_join_status; + + typedef enum + { + LMH_ERROR = -1, + LMH_SUCCESS = 0 + } lmh_error_status; + + typedef enum + { + LMH_UNCONFIRMED_MSG = 0, + LMH_CONFIRMED_MSG = !LMH_UNCONFIRMED_MSG + } lmh_confirm; + + /**@brief Application Data structure + */ + typedef struct + { + uint8_t *buffer; /**< point to the LoRa App data buffer */ + uint8_t buffsize; /**< LoRa App data buffer size */ + uint8_t port; /**< Port on which the LoRa App is data is sent/ received */ + int16_t rssi; + uint8_t snr; + } lmh_app_data_t; + + /**@brief LoRaMac Helper Callbacks + */ + typedef struct lmh_callback_s + { + /**@brief Get the current battery level * @retval value battery level ( 0: very low, 254: fully charged ) */ - uint8_t (*BoardGetBatteryLevel)(void); + uint8_t (*BoardGetBatteryLevel)(void); - /**@brief Gets the board 64 bits unique ID + /**@brief Gets the board 64 bits unique ID * @param[in] id Pointer to an array that will contain the Unique ID */ - void (*BoardGetUniqueId)(uint8_t *id); + void (*BoardGetUniqueId)(uint8_t *id); - /**@brief Returns a pseudo random seed generated using the MCU Unique ID + /**@brief Returns a pseudo random seed generated using the MCU Unique ID * @retval seed Generated pseudo random seed */ - uint32_t (*BoardGetRandomSeed)(void); + uint32_t (*BoardGetRandomSeed)(void); - /**@brief Process Rx Data received from Lora network + /**@brief Process Rx Data received from Lora network * @param[in] AppData Rx structure */ - void (*lmh_RxData)(lmh_app_data_t *appdata); + void (*lmh_RxData)(lmh_app_data_t *appdata); - /**@brief callback indicating EndNode has just joined + /**@brief callback indicating EndNode has just joined */ - void (*lmh_has_joined)(); + void (*lmh_has_joined)(); - /**@brief Confirms the class change + /**@brief Confirms the class change * @param[in] Class A, B, or C */ - void (*lmh_ConfirmClass)(DeviceClass_t Class); + void (*lmh_ConfirmClass)(DeviceClass_t Class); - } lmh_callback_t; + } lmh_callback_t; - /**@brief LoRaWAN compliance tests support data + /**@brief LoRaWAN compliance tests support data */ - typedef struct LoraMacHelper_ComplianceTest_s - { - bool running; - uint8_t state; - bool is_tx_confirmed; - uint8_t app_port; - uint8_t data_buffer_size; - uint8_t data_buffer[64]; - uint16_t downlink_counter; - bool link_check; - uint8_t demod_margin; - uint8_t nb_gateways; - } lmh_compliance_test_t; + typedef struct LoraMacHelper_ComplianceTest_s + { + bool running; + uint8_t state; + bool is_tx_confirmed; + uint8_t app_port; + uint8_t data_buffer_size; + uint8_t data_buffer[64]; + uint16_t downlink_counter; + bool link_check; + uint8_t demod_margin; + uint8_t nb_gateways; + } lmh_compliance_test_t; - /**@brief Lora Initialisation + /**@brief Lora Initialisation * * @param[in] callbacks Pointer to structure containing the callback functions * @param[in] LoRaParam Pointer to structure containing the parameters */ - lmh_error_status lmh_init(lmh_callback_t *callbacks, lmh_param_t lora_param); + lmh_error_status lmh_init(lmh_callback_t *callbacks, lmh_param_t lora_param); - /**@brief Send data + /**@brief Send data * * @param[in] app_data Pointer to data structure to be sent * @param[in] is_txconfirmed do we need confirmation? * * @retval error status */ - lmh_error_status lmh_send(lmh_app_data_t *app_data, lmh_confirm is_txconfirmed); + lmh_error_status lmh_send(lmh_app_data_t *app_data, lmh_confirm is_txconfirmed); - /**@brief Join a Lora Network in class A + /**@brief Join a Lora Network in class A */ - void lmh_join(void); + void lmh_join(void); - /**@brief Check whether the Device is joined to the network + /**@brief Check whether the Device is joined to the network * * @retval returns LORAMACHELPER_SET if joined */ - lmh_join_status lmh_join_status_get(void); + lmh_join_status lmh_join_status_get(void); - /**@brief change Lora Class + /**@brief change Lora Class * * @Note callback LORA_ConfirmClass informs upper layer that the change has occured * @Note Only switch from class A to class B/C OR from class B/C to class A is allowed @@ -164,25 +164,25 @@ extern "C" * * @retval LoraErrorStatus */ - lmh_error_status lmh_class_request(DeviceClass_t newClass); + lmh_error_status lmh_class_request(DeviceClass_t newClass); - /**@brief get the current Lora Class + /**@brief get the current Lora Class * * @param[in] DeviceClass_t NewClass */ - void lmh_class_get(DeviceClass_t *currentClass); + void lmh_class_get(DeviceClass_t *currentClass); - /**@brief Configure data rate + /**@brief Configure data rate * * @param[in] data_rate data rate * @param[in] enable_adr enable adaptative data rate */ - void lmh_datarate_set(uint8_t data_rate, uint8_t enable_adr); + void lmh_datarate_set(uint8_t data_rate, uint8_t enable_adr); - /**@brief Configure tx power + /**@brief Configure tx power * * @param[in] tx_power tx power */ - void lmh_tx_power_set(uint8_t tx_power); + void lmh_tx_power_set(uint8_t tx_power); }; #endif diff --git a/src/mac/LoRaMacTest.h b/src/mac/LoRaMacTest.h index 7eac4d3..429d4cd 100644 --- a/src/mac/LoRaMacTest.h +++ b/src/mac/LoRaMacTest.h @@ -38,7 +38,7 @@ extern "C" { -/*! + /*! * \brief Enabled or disables the reception windows * * \details This is a test function. It shall be used for testing purposes only. @@ -46,9 +46,9 @@ extern "C" * * \param [IN] enable - Enabled or disables the reception windows */ -void LoRaMacTestRxWindowsOn( bool enable ); + void LoRaMacTestRxWindowsOn(bool enable); -/*! + /*! * \brief Enables the MIC field test * * \details This is a test function. It shall be used for testing purposes only. @@ -56,9 +56,9 @@ void LoRaMacTestRxWindowsOn( bool enable ); * * \param [IN] txPacketCounter - Fixed Tx packet counter value */ -void LoRaMacTestSetMic( uint16_t txPacketCounter ); + void LoRaMacTestSetMic(uint16_t txPacketCounter); -/*! + /*! * \brief Enabled or disables the duty cycle * * \details This is a test function. It shall be used for testing purposes only. @@ -66,9 +66,9 @@ void LoRaMacTestSetMic( uint16_t txPacketCounter ); * * \param [IN] enable - Enabled or disables the duty cycle */ -void LoRaMacTestSetDutyCycleOn( bool enable ); + void LoRaMacTestSetDutyCycleOn(bool enable); -/*! + /*! * \brief Sets the channel index * * \details This is a test function. It shall be used for testing purposes only. @@ -76,8 +76,8 @@ void LoRaMacTestSetDutyCycleOn( bool enable ); * * \param [IN] channel - Channel index */ -void LoRaMacTestSetChannel( uint8_t channel ); + void LoRaMacTestSetChannel(uint8_t channel); -/*! \} defgroup LORAMACTEST */ + /*! \} defgroup LORAMACTEST */ }; #endif // __LORAMACTEST_H__ diff --git a/src/mac/region/Region.cpp b/src/mac/region/Region.cpp index c67f38f..3f8fe28 100644 --- a/src/mac/region/Region.cpp +++ b/src/mac/region/Region.cpp @@ -35,75 +35,75 @@ extern "C" #include "RegionAS923.h" #define AS923_CASE case LORAMAC_REGION_AS923: #define AS923_IS_ACTIVE() \ - AS923_CASE { return true; } + AS923_CASE { return true; } #define AS923_GET_PHY_PARAM() \ - AS923_CASE { return RegionAS923GetPhyParam(getPhy); } + AS923_CASE { return RegionAS923GetPhyParam(getPhy); } #define AS923_SET_BAND_TX_DONE() \ - AS923_CASE \ - { \ - RegionAS923SetBandTxDone(txDone); \ - break; \ - } + AS923_CASE \ + { \ + RegionAS923SetBandTxDone(txDone); \ + break; \ + } #define AS923_INIT_DEFAULTS() \ - AS923_CASE \ - { \ - RegionAS923InitDefaults(type); \ - break; \ - } + AS923_CASE \ + { \ + RegionAS923InitDefaults(type); \ + break; \ + } #define AS923_VERIFY() \ - AS923_CASE { return RegionAS923Verify(verify, phyAttribute); } + AS923_CASE { return RegionAS923Verify(verify, phyAttribute); } #define AS923_APPLY_CF_LIST() \ - AS923_CASE \ - { \ - RegionAS923ApplyCFList(applyCFList); \ - break; \ - } + AS923_CASE \ + { \ + RegionAS923ApplyCFList(applyCFList); \ + break; \ + } #define AS923_CHAN_MASK_SET() \ - AS923_CASE { return RegionAS923ChanMaskSet(chanMaskSet); } + AS923_CASE { return RegionAS923ChanMaskSet(chanMaskSet); } #define AS923_ADR_NEXT() \ - AS923_CASE { return RegionAS923AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + AS923_CASE { return RegionAS923AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define AS923_COMPUTE_RX_WINDOW_PARAMETERS() \ - AS923_CASE \ - { \ - RegionAS923ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + AS923_CASE \ + { \ + RegionAS923ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define AS923_RX_CONFIG() \ - AS923_CASE { return RegionAS923RxConfig(rxConfig, datarate); } + AS923_CASE { return RegionAS923RxConfig(rxConfig, datarate); } #define AS923_TX_CONFIG() \ - AS923_CASE { return RegionAS923TxConfig(txConfig, txPower, txTimeOnAir); } + AS923_CASE { return RegionAS923TxConfig(txConfig, txPower, txTimeOnAir); } #define AS923_LINK_ADR_REQ() \ - AS923_CASE { return RegionAS923LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + AS923_CASE { return RegionAS923LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define AS923_RX_PARAM_SETUP_REQ() \ - AS923_CASE { return RegionAS923RxParamSetupReq(rxParamSetupReq); } + AS923_CASE { return RegionAS923RxParamSetupReq(rxParamSetupReq); } #define AS923_NEW_CHANNEL_REQ() \ - AS923_CASE { return RegionAS923NewChannelReq(newChannelReq); } + AS923_CASE { return RegionAS923NewChannelReq(newChannelReq); } #define AS923_TX_PARAM_SETUP_REQ() \ - AS923_CASE { return RegionAS923TxParamSetupReq(txParamSetupReq); } + AS923_CASE { return RegionAS923TxParamSetupReq(txParamSetupReq); } #define AS923_DL_CHANNEL_REQ() \ - AS923_CASE { return RegionAS923DlChannelReq(dlChannelReq); } + AS923_CASE { return RegionAS923DlChannelReq(dlChannelReq); } #define AS923_ALTERNATE_DR() \ - AS923_CASE { return RegionAS923AlternateDr(alternateDr); } + AS923_CASE { return RegionAS923AlternateDr(alternateDr); } #define AS923_CALC_BACKOFF() \ - AS923_CASE \ - { \ - RegionAS923CalcBackOff(calcBackOff); \ - break; \ - } + AS923_CASE \ + { \ + RegionAS923CalcBackOff(calcBackOff); \ + break; \ + } #define AS923_NEXT_CHANNEL() \ - AS923_CASE { return RegionAS923NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + AS923_CASE { return RegionAS923NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define AS923_CHANNEL_ADD() \ - AS923_CASE { return RegionAS923ChannelAdd(channelAdd); } + AS923_CASE { return RegionAS923ChannelAdd(channelAdd); } #define AS923_CHANNEL_REMOVE() \ - AS923_CASE { return RegionAS923ChannelsRemove(channelRemove); } + AS923_CASE { return RegionAS923ChannelsRemove(channelRemove); } #define AS923_SET_CONTINUOUS_WAVE() \ - AS923_CASE \ - { \ - RegionAS923SetContinuousWave(continuousWave); \ - break; \ - } + AS923_CASE \ + { \ + RegionAS923SetContinuousWave(continuousWave); \ + break; \ + } #define AS923_APPLY_DR_OFFSET() \ - AS923_CASE { return RegionAS923ApplyDrOffset(downlinkDwellTime, dr, drOffset); } + AS923_CASE { return RegionAS923ApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define AS923_IS_ACTIVE() #define AS923_GET_PHY_PARAM() @@ -134,75 +134,75 @@ extern "C" #include "RegionAU915.h" #define AU915_CASE case LORAMAC_REGION_AU915: #define AU915_IS_ACTIVE() \ - AU915_CASE { return true; } + AU915_CASE { return true; } #define AU915_GET_PHY_PARAM() \ - AU915_CASE { return RegionAU915GetPhyParam(getPhy); } + AU915_CASE { return RegionAU915GetPhyParam(getPhy); } #define AU915_SET_BAND_TX_DONE() \ - AU915_CASE \ - { \ - RegionAU915SetBandTxDone(txDone); \ - break; \ - } + AU915_CASE \ + { \ + RegionAU915SetBandTxDone(txDone); \ + break; \ + } #define AU915_INIT_DEFAULTS() \ - AU915_CASE \ - { \ - RegionAU915InitDefaults(type); \ - break; \ - } + AU915_CASE \ + { \ + RegionAU915InitDefaults(type); \ + break; \ + } #define AU915_VERIFY() \ - AU915_CASE { return RegionAU915Verify(verify, phyAttribute); } + AU915_CASE { return RegionAU915Verify(verify, phyAttribute); } #define AU915_APPLY_CF_LIST() \ - AU915_CASE \ - { \ - RegionAU915ApplyCFList(applyCFList); \ - break; \ - } + AU915_CASE \ + { \ + RegionAU915ApplyCFList(applyCFList); \ + break; \ + } #define AU915_CHAN_MASK_SET() \ - AU915_CASE { return RegionAU915ChanMaskSet(chanMaskSet); } + AU915_CASE { return RegionAU915ChanMaskSet(chanMaskSet); } #define AU915_ADR_NEXT() \ - AU915_CASE { return RegionAU915AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + AU915_CASE { return RegionAU915AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define AU915_COMPUTE_RX_WINDOW_PARAMETERS() \ - AU915_CASE \ - { \ - RegionAU915ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + AU915_CASE \ + { \ + RegionAU915ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define AU915_RX_CONFIG() \ - AU915_CASE { return RegionAU915RxConfig(rxConfig, datarate); } + AU915_CASE { return RegionAU915RxConfig(rxConfig, datarate); } #define AU915_TX_CONFIG() \ - AU915_CASE { return RegionAU915TxConfig(txConfig, txPower, txTimeOnAir); } + AU915_CASE { return RegionAU915TxConfig(txConfig, txPower, txTimeOnAir); } #define AU915_LINK_ADR_REQ() \ - AU915_CASE { return RegionAU915LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + AU915_CASE { return RegionAU915LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define AU915_RX_PARAM_SETUP_REQ() \ - AU915_CASE { return RegionAU915RxParamSetupReq(rxParamSetupReq); } + AU915_CASE { return RegionAU915RxParamSetupReq(rxParamSetupReq); } #define AU915_NEW_CHANNEL_REQ() \ - AU915_CASE { return RegionAU915NewChannelReq(newChannelReq); } + AU915_CASE { return RegionAU915NewChannelReq(newChannelReq); } #define AU915_TX_PARAM_SETUP_REQ() \ - AU915_CASE { return RegionAU915TxParamSetupReq(txParamSetupReq); } + AU915_CASE { return RegionAU915TxParamSetupReq(txParamSetupReq); } #define AU915_DL_CHANNEL_REQ() \ - AU915_CASE { return RegionAU915DlChannelReq(dlChannelReq); } + AU915_CASE { return RegionAU915DlChannelReq(dlChannelReq); } #define AU915_ALTERNATE_DR() \ - AU915_CASE { return RegionAU915AlternateDr(alternateDr); } + AU915_CASE { return RegionAU915AlternateDr(alternateDr); } #define AU915_CALC_BACKOFF() \ - AU915_CASE \ - { \ - RegionAU915CalcBackOff(calcBackOff); \ - break; \ - } + AU915_CASE \ + { \ + RegionAU915CalcBackOff(calcBackOff); \ + break; \ + } #define AU915_NEXT_CHANNEL() \ - AU915_CASE { return RegionAU915NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + AU915_CASE { return RegionAU915NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define AU915_CHANNEL_ADD() \ - AU915_CASE { return RegionAU915ChannelAdd(channelAdd); } + AU915_CASE { return RegionAU915ChannelAdd(channelAdd); } #define AU915_CHANNEL_REMOVE() \ - AU915_CASE { return RegionAU915ChannelsRemove(channelRemove); } + AU915_CASE { return RegionAU915ChannelsRemove(channelRemove); } #define AU915_SET_CONTINUOUS_WAVE() \ - AU915_CASE \ - { \ - RegionAU915SetContinuousWave(continuousWave); \ - break; \ - } + AU915_CASE \ + { \ + RegionAU915SetContinuousWave(continuousWave); \ + break; \ + } #define AU915_APPLY_DR_OFFSET() \ - AU915_CASE { return RegionAU915ApplyDrOffset(downlinkDwellTime, dr, drOffset); } + AU915_CASE { return RegionAU915ApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define AU915_IS_ACTIVE() #define AU915_GET_PHY_PARAM() @@ -233,75 +233,75 @@ extern "C" #include "RegionCN470.h" #define CN470_CASE case LORAMAC_REGION_CN470: #define CN470_IS_ACTIVE() \ - CN470_CASE { return true; } + CN470_CASE { return true; } #define CN470_GET_PHY_PARAM() \ - CN470_CASE { return RegionCN470GetPhyParam(getPhy); } + CN470_CASE { return RegionCN470GetPhyParam(getPhy); } #define CN470_SET_BAND_TX_DONE() \ - CN470_CASE \ - { \ - RegionCN470SetBandTxDone(txDone); \ - break; \ - } + CN470_CASE \ + { \ + RegionCN470SetBandTxDone(txDone); \ + break; \ + } #define CN470_INIT_DEFAULTS() \ - CN470_CASE \ - { \ - RegionCN470InitDefaults(type); \ - break; \ - } + CN470_CASE \ + { \ + RegionCN470InitDefaults(type); \ + break; \ + } #define CN470_VERIFY() \ - CN470_CASE { return RegionCN470Verify(verify, phyAttribute); } + CN470_CASE { return RegionCN470Verify(verify, phyAttribute); } #define CN470_APPLY_CF_LIST() \ - CN470_CASE \ - { \ - RegionCN470ApplyCFList(applyCFList); \ - break; \ - } + CN470_CASE \ + { \ + RegionCN470ApplyCFList(applyCFList); \ + break; \ + } #define CN470_CHAN_MASK_SET() \ - CN470_CASE { return RegionCN470ChanMaskSet(chanMaskSet); } + CN470_CASE { return RegionCN470ChanMaskSet(chanMaskSet); } #define CN470_ADR_NEXT() \ - CN470_CASE { return RegionCN470AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + CN470_CASE { return RegionCN470AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define CN470_COMPUTE_RX_WINDOW_PARAMETERS() \ - CN470_CASE \ - { \ - RegionCN470ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + CN470_CASE \ + { \ + RegionCN470ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define CN470_RX_CONFIG() \ - CN470_CASE { return RegionCN470RxConfig(rxConfig, datarate); } + CN470_CASE { return RegionCN470RxConfig(rxConfig, datarate); } #define CN470_TX_CONFIG() \ - CN470_CASE { return RegionCN470TxConfig(txConfig, txPower, txTimeOnAir); } + CN470_CASE { return RegionCN470TxConfig(txConfig, txPower, txTimeOnAir); } #define CN470_LINK_ADR_REQ() \ - CN470_CASE { return RegionCN470LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + CN470_CASE { return RegionCN470LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define CN470_RX_PARAM_SETUP_REQ() \ - CN470_CASE { return RegionCN470RxParamSetupReq(rxParamSetupReq); } + CN470_CASE { return RegionCN470RxParamSetupReq(rxParamSetupReq); } #define CN470_NEW_CHANNEL_REQ() \ - CN470_CASE { return RegionCN470NewChannelReq(newChannelReq); } + CN470_CASE { return RegionCN470NewChannelReq(newChannelReq); } #define CN470_TX_PARAM_SETUP_REQ() \ - CN470_CASE { return RegionCN470TxParamSetupReq(txParamSetupReq); } + CN470_CASE { return RegionCN470TxParamSetupReq(txParamSetupReq); } #define CN470_DL_CHANNEL_REQ() \ - CN470_CASE { return RegionCN470DlChannelReq(dlChannelReq); } + CN470_CASE { return RegionCN470DlChannelReq(dlChannelReq); } #define CN470_ALTERNATE_DR() \ - CN470_CASE { return RegionCN470AlternateDr(alternateDr); } + CN470_CASE { return RegionCN470AlternateDr(alternateDr); } #define CN470_CALC_BACKOFF() \ - CN470_CASE \ - { \ - RegionCN470CalcBackOff(calcBackOff); \ - break; \ - } + CN470_CASE \ + { \ + RegionCN470CalcBackOff(calcBackOff); \ + break; \ + } #define CN470_NEXT_CHANNEL() \ - CN470_CASE { return RegionCN470NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + CN470_CASE { return RegionCN470NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define CN470_CHANNEL_ADD() \ - CN470_CASE { return RegionCN470ChannelAdd(channelAdd); } + CN470_CASE { return RegionCN470ChannelAdd(channelAdd); } #define CN470_CHANNEL_REMOVE() \ - CN470_CASE { return RegionCN470ChannelsRemove(channelRemove); } + CN470_CASE { return RegionCN470ChannelsRemove(channelRemove); } #define CN470_SET_CONTINUOUS_WAVE() \ - CN470_CASE \ - { \ - RegionCN470SetContinuousWave(continuousWave); \ - break; \ - } + CN470_CASE \ + { \ + RegionCN470SetContinuousWave(continuousWave); \ + break; \ + } #define CN470_APPLY_DR_OFFSET() \ - CN470_CASE { return RegionCN470ApplyDrOffset(downlinkDwellTime, dr, drOffset); } + CN470_CASE { return RegionCN470ApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define CN470_IS_ACTIVE() #define CN470_GET_PHY_PARAM() @@ -332,75 +332,75 @@ extern "C" #include "RegionCN779.h" #define CN779_CASE case LORAMAC_REGION_CN779: #define CN779_IS_ACTIVE() \ - CN779_CASE { return true; } + CN779_CASE { return true; } #define CN779_GET_PHY_PARAM() \ - CN779_CASE { return RegionCN779GetPhyParam(getPhy); } + CN779_CASE { return RegionCN779GetPhyParam(getPhy); } #define CN779_SET_BAND_TX_DONE() \ - CN779_CASE \ - { \ - RegionCN779SetBandTxDone(txDone); \ - break; \ - } + CN779_CASE \ + { \ + RegionCN779SetBandTxDone(txDone); \ + break; \ + } #define CN779_INIT_DEFAULTS() \ - CN779_CASE \ - { \ - RegionCN779InitDefaults(type); \ - break; \ - } + CN779_CASE \ + { \ + RegionCN779InitDefaults(type); \ + break; \ + } #define CN779_VERIFY() \ - CN779_CASE { return RegionCN779Verify(verify, phyAttribute); } + CN779_CASE { return RegionCN779Verify(verify, phyAttribute); } #define CN779_APPLY_CF_LIST() \ - CN779_CASE \ - { \ - RegionCN779ApplyCFList(applyCFList); \ - break; \ - } + CN779_CASE \ + { \ + RegionCN779ApplyCFList(applyCFList); \ + break; \ + } #define CN779_CHAN_MASK_SET() \ - CN779_CASE { return RegionCN779ChanMaskSet(chanMaskSet); } + CN779_CASE { return RegionCN779ChanMaskSet(chanMaskSet); } #define CN779_ADR_NEXT() \ - CN779_CASE { return RegionCN779AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + CN779_CASE { return RegionCN779AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define CN779_COMPUTE_RX_WINDOW_PARAMETERS() \ - CN779_CASE \ - { \ - RegionCN779ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + CN779_CASE \ + { \ + RegionCN779ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define CN779_RX_CONFIG() \ - CN779_CASE { return RegionCN779RxConfig(rxConfig, datarate); } + CN779_CASE { return RegionCN779RxConfig(rxConfig, datarate); } #define CN779_TX_CONFIG() \ - CN779_CASE { return RegionCN779TxConfig(txConfig, txPower, txTimeOnAir); } + CN779_CASE { return RegionCN779TxConfig(txConfig, txPower, txTimeOnAir); } #define CN779_LINK_ADR_REQ() \ - CN779_CASE { return RegionCN779LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + CN779_CASE { return RegionCN779LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define CN779_RX_PARAM_SETUP_REQ() \ - CN779_CASE { return RegionCN779RxParamSetupReq(rxParamSetupReq); } + CN779_CASE { return RegionCN779RxParamSetupReq(rxParamSetupReq); } #define CN779_NEW_CHANNEL_REQ() \ - CN779_CASE { return RegionCN779NewChannelReq(newChannelReq); } + CN779_CASE { return RegionCN779NewChannelReq(newChannelReq); } #define CN779_TX_PARAM_SETUP_REQ() \ - CN779_CASE { return RegionCN779TxParamSetupReq(txParamSetupReq); } + CN779_CASE { return RegionCN779TxParamSetupReq(txParamSetupReq); } #define CN779_DL_CHANNEL_REQ() \ - CN779_CASE { return RegionCN779DlChannelReq(dlChannelReq); } + CN779_CASE { return RegionCN779DlChannelReq(dlChannelReq); } #define CN779_ALTERNATE_DR() \ - CN779_CASE { return RegionCN779AlternateDr(alternateDr); } + CN779_CASE { return RegionCN779AlternateDr(alternateDr); } #define CN779_CALC_BACKOFF() \ - CN779_CASE \ - { \ - RegionCN779CalcBackOff(calcBackOff); \ - break; \ - } + CN779_CASE \ + { \ + RegionCN779CalcBackOff(calcBackOff); \ + break; \ + } #define CN779_NEXT_CHANNEL() \ - CN779_CASE { return RegionCN779NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + CN779_CASE { return RegionCN779NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define CN779_CHANNEL_ADD() \ - CN779_CASE { return RegionCN779ChannelAdd(channelAdd); } + CN779_CASE { return RegionCN779ChannelAdd(channelAdd); } #define CN779_CHANNEL_REMOVE() \ - CN779_CASE { return RegionCN779ChannelsRemove(channelRemove); } + CN779_CASE { return RegionCN779ChannelsRemove(channelRemove); } #define CN779_SET_CONTINUOUS_WAVE() \ - CN779_CASE \ - { \ - RegionCN779SetContinuousWave(continuousWave); \ - break; \ - } + CN779_CASE \ + { \ + RegionCN779SetContinuousWave(continuousWave); \ + break; \ + } #define CN779_APPLY_DR_OFFSET() \ - CN779_CASE { return RegionCN779ApplyDrOffset(downlinkDwellTime, dr, drOffset); } + CN779_CASE { return RegionCN779ApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define CN779_IS_ACTIVE() #define CN779_GET_PHY_PARAM() @@ -431,75 +431,75 @@ extern "C" #include "RegionEU433.h" #define EU433_CASE case LORAMAC_REGION_EU433: #define EU433_IS_ACTIVE() \ - EU433_CASE { return true; } + EU433_CASE { return true; } #define EU433_GET_PHY_PARAM() \ - EU433_CASE { return RegionEU433GetPhyParam(getPhy); } + EU433_CASE { return RegionEU433GetPhyParam(getPhy); } #define EU433_SET_BAND_TX_DONE() \ - EU433_CASE \ - { \ - RegionEU433SetBandTxDone(txDone); \ - break; \ - } + EU433_CASE \ + { \ + RegionEU433SetBandTxDone(txDone); \ + break; \ + } #define EU433_INIT_DEFAULTS() \ - EU433_CASE \ - { \ - RegionEU433InitDefaults(type); \ - break; \ - } + EU433_CASE \ + { \ + RegionEU433InitDefaults(type); \ + break; \ + } #define EU433_VERIFY() \ - EU433_CASE { return RegionEU433Verify(verify, phyAttribute); } + EU433_CASE { return RegionEU433Verify(verify, phyAttribute); } #define EU433_APPLY_CF_LIST() \ - EU433_CASE \ - { \ - RegionEU433ApplyCFList(applyCFList); \ - break; \ - } + EU433_CASE \ + { \ + RegionEU433ApplyCFList(applyCFList); \ + break; \ + } #define EU433_CHAN_MASK_SET() \ - EU433_CASE { return RegionEU433ChanMaskSet(chanMaskSet); } + EU433_CASE { return RegionEU433ChanMaskSet(chanMaskSet); } #define EU433_ADR_NEXT() \ - EU433_CASE { return RegionEU433AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + EU433_CASE { return RegionEU433AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define EU433_COMPUTE_RX_WINDOW_PARAMETERS() \ - EU433_CASE \ - { \ - RegionEU433ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + EU433_CASE \ + { \ + RegionEU433ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define EU433_RX_CONFIG() \ - EU433_CASE { return RegionEU433RxConfig(rxConfig, datarate); } + EU433_CASE { return RegionEU433RxConfig(rxConfig, datarate); } #define EU433_TX_CONFIG() \ - EU433_CASE { return RegionEU433TxConfig(txConfig, txPower, txTimeOnAir); } + EU433_CASE { return RegionEU433TxConfig(txConfig, txPower, txTimeOnAir); } #define EU433_LINK_ADR_REQ() \ - EU433_CASE { return RegionEU433LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + EU433_CASE { return RegionEU433LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define EU433_RX_PARAM_SETUP_REQ() \ - EU433_CASE { return RegionEU433RxParamSetupReq(rxParamSetupReq); } + EU433_CASE { return RegionEU433RxParamSetupReq(rxParamSetupReq); } #define EU433_NEW_CHANNEL_REQ() \ - EU433_CASE { return RegionEU433NewChannelReq(newChannelReq); } + EU433_CASE { return RegionEU433NewChannelReq(newChannelReq); } #define EU433_TX_PARAM_SETUP_REQ() \ - EU433_CASE { return RegionEU433TxParamSetupReq(txParamSetupReq); } + EU433_CASE { return RegionEU433TxParamSetupReq(txParamSetupReq); } #define EU433_DL_CHANNEL_REQ() \ - EU433_CASE { return RegionEU433DlChannelReq(dlChannelReq); } + EU433_CASE { return RegionEU433DlChannelReq(dlChannelReq); } #define EU433_ALTERNATE_DR() \ - EU433_CASE { return RegionEU433AlternateDr(alternateDr); } + EU433_CASE { return RegionEU433AlternateDr(alternateDr); } #define EU433_CALC_BACKOFF() \ - EU433_CASE \ - { \ - RegionEU433CalcBackOff(calcBackOff); \ - break; \ - } + EU433_CASE \ + { \ + RegionEU433CalcBackOff(calcBackOff); \ + break; \ + } #define EU433_NEXT_CHANNEL() \ - EU433_CASE { return RegionEU433NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + EU433_CASE { return RegionEU433NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define EU433_CHANNEL_ADD() \ - EU433_CASE { return RegionEU433ChannelAdd(channelAdd); } + EU433_CASE { return RegionEU433ChannelAdd(channelAdd); } #define EU433_CHANNEL_REMOVE() \ - EU433_CASE { return RegionEU433ChannelsRemove(channelRemove); } + EU433_CASE { return RegionEU433ChannelsRemove(channelRemove); } #define EU433_SET_CONTINUOUS_WAVE() \ - EU433_CASE \ - { \ - RegionEU433SetContinuousWave(continuousWave); \ - break; \ - } + EU433_CASE \ + { \ + RegionEU433SetContinuousWave(continuousWave); \ + break; \ + } #define EU433_APPLY_DR_OFFSET() \ - EU433_CASE { return RegionEU433ApplyDrOffset(downlinkDwellTime, dr, drOffset); } + EU433_CASE { return RegionEU433ApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define EU433_IS_ACTIVE() #define EU433_GET_PHY_PARAM() @@ -530,75 +530,75 @@ extern "C" #include "RegionEU868.h" #define EU868_CASE case LORAMAC_REGION_EU868: #define EU868_IS_ACTIVE() \ - EU868_CASE { return true; } + EU868_CASE { return true; } #define EU868_GET_PHY_PARAM() \ - EU868_CASE { return RegionEU868GetPhyParam(getPhy); } + EU868_CASE { return RegionEU868GetPhyParam(getPhy); } #define EU868_SET_BAND_TX_DONE() \ - EU868_CASE \ - { \ - RegionEU868SetBandTxDone(txDone); \ - break; \ - } + EU868_CASE \ + { \ + RegionEU868SetBandTxDone(txDone); \ + break; \ + } #define EU868_INIT_DEFAULTS() \ - EU868_CASE \ - { \ - RegionEU868InitDefaults(type); \ - break; \ - } + EU868_CASE \ + { \ + RegionEU868InitDefaults(type); \ + break; \ + } #define EU868_VERIFY() \ - EU868_CASE { return RegionEU868Verify(verify, phyAttribute); } + EU868_CASE { return RegionEU868Verify(verify, phyAttribute); } #define EU868_APPLY_CF_LIST() \ - EU868_CASE \ - { \ - RegionEU868ApplyCFList(applyCFList); \ - break; \ - } + EU868_CASE \ + { \ + RegionEU868ApplyCFList(applyCFList); \ + break; \ + } #define EU868_CHAN_MASK_SET() \ - EU868_CASE { return RegionEU868ChanMaskSet(chanMaskSet); } + EU868_CASE { return RegionEU868ChanMaskSet(chanMaskSet); } #define EU868_ADR_NEXT() \ - EU868_CASE { return RegionEU868AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + EU868_CASE { return RegionEU868AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define EU868_COMPUTE_RX_WINDOW_PARAMETERS() \ - EU868_CASE \ - { \ - RegionEU868ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + EU868_CASE \ + { \ + RegionEU868ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define EU868_RX_CONFIG() \ - EU868_CASE { return RegionEU868RxConfig(rxConfig, datarate); } + EU868_CASE { return RegionEU868RxConfig(rxConfig, datarate); } #define EU868_TX_CONFIG() \ - EU868_CASE { return RegionEU868TxConfig(txConfig, txPower, txTimeOnAir); } + EU868_CASE { return RegionEU868TxConfig(txConfig, txPower, txTimeOnAir); } #define EU868_LINK_ADR_REQ() \ - EU868_CASE { return RegionEU868LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + EU868_CASE { return RegionEU868LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define EU868_RX_PARAM_SETUP_REQ() \ - EU868_CASE { return RegionEU868RxParamSetupReq(rxParamSetupReq); } + EU868_CASE { return RegionEU868RxParamSetupReq(rxParamSetupReq); } #define EU868_NEW_CHANNEL_REQ() \ - EU868_CASE { return RegionEU868NewChannelReq(newChannelReq); } + EU868_CASE { return RegionEU868NewChannelReq(newChannelReq); } #define EU868_TX_PARAM_SETUP_REQ() \ - EU868_CASE { return RegionEU868TxParamSetupReq(txParamSetupReq); } + EU868_CASE { return RegionEU868TxParamSetupReq(txParamSetupReq); } #define EU868_DL_CHANNEL_REQ() \ - EU868_CASE { return RegionEU868DlChannelReq(dlChannelReq); } + EU868_CASE { return RegionEU868DlChannelReq(dlChannelReq); } #define EU868_ALTERNATE_DR() \ - EU868_CASE { return RegionEU868AlternateDr(alternateDr); } + EU868_CASE { return RegionEU868AlternateDr(alternateDr); } #define EU868_CALC_BACKOFF() \ - EU868_CASE \ - { \ - RegionEU868CalcBackOff(calcBackOff); \ - break; \ - } + EU868_CASE \ + { \ + RegionEU868CalcBackOff(calcBackOff); \ + break; \ + } #define EU868_NEXT_CHANNEL() \ - EU868_CASE { return RegionEU868NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + EU868_CASE { return RegionEU868NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define EU868_CHANNEL_ADD() \ - EU868_CASE { return RegionEU868ChannelAdd(channelAdd); } + EU868_CASE { return RegionEU868ChannelAdd(channelAdd); } #define EU868_CHANNEL_REMOVE() \ - EU868_CASE { return RegionEU868ChannelsRemove(channelRemove); } + EU868_CASE { return RegionEU868ChannelsRemove(channelRemove); } #define EU868_SET_CONTINUOUS_WAVE() \ - EU868_CASE \ - { \ - RegionEU868SetContinuousWave(continuousWave); \ - break; \ - } + EU868_CASE \ + { \ + RegionEU868SetContinuousWave(continuousWave); \ + break; \ + } #define EU868_APPLY_DR_OFFSET() \ - EU868_CASE { return RegionEU868ApplyDrOffset(downlinkDwellTime, dr, drOffset); } + EU868_CASE { return RegionEU868ApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define EU868_IS_ACTIVE() #define EU868_GET_PHY_PARAM() @@ -629,75 +629,75 @@ extern "C" #include "RegionKR920.h" #define KR920_CASE case LORAMAC_REGION_KR920: #define KR920_IS_ACTIVE() \ - KR920_CASE { return true; } + KR920_CASE { return true; } #define KR920_GET_PHY_PARAM() \ - KR920_CASE { return RegionKR920GetPhyParam(getPhy); } + KR920_CASE { return RegionKR920GetPhyParam(getPhy); } #define KR920_SET_BAND_TX_DONE() \ - KR920_CASE \ - { \ - RegionKR920SetBandTxDone(txDone); \ - break; \ - } + KR920_CASE \ + { \ + RegionKR920SetBandTxDone(txDone); \ + break; \ + } #define KR920_INIT_DEFAULTS() \ - KR920_CASE \ - { \ - RegionKR920InitDefaults(type); \ - break; \ - } + KR920_CASE \ + { \ + RegionKR920InitDefaults(type); \ + break; \ + } #define KR920_VERIFY() \ - KR920_CASE { return RegionKR920Verify(verify, phyAttribute); } + KR920_CASE { return RegionKR920Verify(verify, phyAttribute); } #define KR920_APPLY_CF_LIST() \ - KR920_CASE \ - { \ - RegionKR920ApplyCFList(applyCFList); \ - break; \ - } + KR920_CASE \ + { \ + RegionKR920ApplyCFList(applyCFList); \ + break; \ + } #define KR920_CHAN_MASK_SET() \ - KR920_CASE { return RegionKR920ChanMaskSet(chanMaskSet); } + KR920_CASE { return RegionKR920ChanMaskSet(chanMaskSet); } #define KR920_ADR_NEXT() \ - KR920_CASE { return RegionKR920AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + KR920_CASE { return RegionKR920AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define KR920_COMPUTE_RX_WINDOW_PARAMETERS() \ - KR920_CASE \ - { \ - RegionKR920ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + KR920_CASE \ + { \ + RegionKR920ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define KR920_RX_CONFIG() \ - KR920_CASE { return RegionKR920RxConfig(rxConfig, datarate); } + KR920_CASE { return RegionKR920RxConfig(rxConfig, datarate); } #define KR920_TX_CONFIG() \ - KR920_CASE { return RegionKR920TxConfig(txConfig, txPower, txTimeOnAir); } + KR920_CASE { return RegionKR920TxConfig(txConfig, txPower, txTimeOnAir); } #define KR920_LINK_ADR_REQ() \ - KR920_CASE { return RegionKR920LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + KR920_CASE { return RegionKR920LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define KR920_RX_PARAM_SETUP_REQ() \ - KR920_CASE { return RegionKR920RxParamSetupReq(rxParamSetupReq); } + KR920_CASE { return RegionKR920RxParamSetupReq(rxParamSetupReq); } #define KR920_NEW_CHANNEL_REQ() \ - KR920_CASE { return RegionKR920NewChannelReq(newChannelReq); } + KR920_CASE { return RegionKR920NewChannelReq(newChannelReq); } #define KR920_TX_PARAM_SETUP_REQ() \ - KR920_CASE { return RegionKR920TxParamSetupReq(txParamSetupReq); } + KR920_CASE { return RegionKR920TxParamSetupReq(txParamSetupReq); } #define KR920_DL_CHANNEL_REQ() \ - KR920_CASE { return RegionKR920DlChannelReq(dlChannelReq); } + KR920_CASE { return RegionKR920DlChannelReq(dlChannelReq); } #define KR920_ALTERNATE_DR() \ - KR920_CASE { return RegionKR920AlternateDr(alternateDr); } + KR920_CASE { return RegionKR920AlternateDr(alternateDr); } #define KR920_CALC_BACKOFF() \ - KR920_CASE \ - { \ - RegionKR920CalcBackOff(calcBackOff); \ - break; \ - } + KR920_CASE \ + { \ + RegionKR920CalcBackOff(calcBackOff); \ + break; \ + } #define KR920_NEXT_CHANNEL() \ - KR920_CASE { return RegionKR920NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + KR920_CASE { return RegionKR920NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define KR920_CHANNEL_ADD() \ - KR920_CASE { return RegionKR920ChannelAdd(channelAdd); } + KR920_CASE { return RegionKR920ChannelAdd(channelAdd); } #define KR920_CHANNEL_REMOVE() \ - KR920_CASE { return RegionKR920ChannelsRemove(channelRemove); } + KR920_CASE { return RegionKR920ChannelsRemove(channelRemove); } #define KR920_SET_CONTINUOUS_WAVE() \ - KR920_CASE \ - { \ - RegionKR920SetContinuousWave(continuousWave); \ - break; \ - } + KR920_CASE \ + { \ + RegionKR920SetContinuousWave(continuousWave); \ + break; \ + } #define KR920_APPLY_DR_OFFSET() \ - KR920_CASE { return RegionKR920ApplyDrOffset(downlinkDwellTime, dr, drOffset); } + KR920_CASE { return RegionKR920ApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define KR920_IS_ACTIVE() #define KR920_GET_PHY_PARAM() @@ -728,75 +728,75 @@ extern "C" #include "RegionIN865.h" #define IN865_CASE case LORAMAC_REGION_IN865: #define IN865_IS_ACTIVE() \ - IN865_CASE { return true; } + IN865_CASE { return true; } #define IN865_GET_PHY_PARAM() \ - IN865_CASE { return RegionIN865GetPhyParam(getPhy); } + IN865_CASE { return RegionIN865GetPhyParam(getPhy); } #define IN865_SET_BAND_TX_DONE() \ - IN865_CASE \ - { \ - RegionIN865SetBandTxDone(txDone); \ - break; \ - } + IN865_CASE \ + { \ + RegionIN865SetBandTxDone(txDone); \ + break; \ + } #define IN865_INIT_DEFAULTS() \ - IN865_CASE \ - { \ - RegionIN865InitDefaults(type); \ - break; \ - } + IN865_CASE \ + { \ + RegionIN865InitDefaults(type); \ + break; \ + } #define IN865_VERIFY() \ - IN865_CASE { return RegionIN865Verify(verify, phyAttribute); } + IN865_CASE { return RegionIN865Verify(verify, phyAttribute); } #define IN865_APPLY_CF_LIST() \ - IN865_CASE \ - { \ - RegionIN865ApplyCFList(applyCFList); \ - break; \ - } + IN865_CASE \ + { \ + RegionIN865ApplyCFList(applyCFList); \ + break; \ + } #define IN865_CHAN_MASK_SET() \ - IN865_CASE { return RegionIN865ChanMaskSet(chanMaskSet); } + IN865_CASE { return RegionIN865ChanMaskSet(chanMaskSet); } #define IN865_ADR_NEXT() \ - IN865_CASE { return RegionIN865AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + IN865_CASE { return RegionIN865AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define IN865_COMPUTE_RX_WINDOW_PARAMETERS() \ - IN865_CASE \ - { \ - RegionIN865ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + IN865_CASE \ + { \ + RegionIN865ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define IN865_RX_CONFIG() \ - IN865_CASE { return RegionIN865RxConfig(rxConfig, datarate); } + IN865_CASE { return RegionIN865RxConfig(rxConfig, datarate); } #define IN865_TX_CONFIG() \ - IN865_CASE { return RegionIN865TxConfig(txConfig, txPower, txTimeOnAir); } + IN865_CASE { return RegionIN865TxConfig(txConfig, txPower, txTimeOnAir); } #define IN865_LINK_ADR_REQ() \ - IN865_CASE { return RegionIN865LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + IN865_CASE { return RegionIN865LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define IN865_RX_PARAM_SETUP_REQ() \ - IN865_CASE { return RegionIN865RxParamSetupReq(rxParamSetupReq); } + IN865_CASE { return RegionIN865RxParamSetupReq(rxParamSetupReq); } #define IN865_NEW_CHANNEL_REQ() \ - IN865_CASE { return RegionIN865NewChannelReq(newChannelReq); } + IN865_CASE { return RegionIN865NewChannelReq(newChannelReq); } #define IN865_TX_PARAM_SETUP_REQ() \ - IN865_CASE { return RegionIN865TxParamSetupReq(txParamSetupReq); } + IN865_CASE { return RegionIN865TxParamSetupReq(txParamSetupReq); } #define IN865_DL_CHANNEL_REQ() \ - IN865_CASE { return RegionIN865DlChannelReq(dlChannelReq); } + IN865_CASE { return RegionIN865DlChannelReq(dlChannelReq); } #define IN865_ALTERNATE_DR() \ - IN865_CASE { return RegionIN865AlternateDr(alternateDr); } + IN865_CASE { return RegionIN865AlternateDr(alternateDr); } #define IN865_CALC_BACKOFF() \ - IN865_CASE \ - { \ - RegionIN865CalcBackOff(calcBackOff); \ - break; \ - } + IN865_CASE \ + { \ + RegionIN865CalcBackOff(calcBackOff); \ + break; \ + } #define IN865_NEXT_CHANNEL() \ - IN865_CASE { return RegionIN865NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + IN865_CASE { return RegionIN865NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define IN865_CHANNEL_ADD() \ - IN865_CASE { return RegionIN865ChannelAdd(channelAdd); } + IN865_CASE { return RegionIN865ChannelAdd(channelAdd); } #define IN865_CHANNEL_REMOVE() \ - IN865_CASE { return RegionIN865ChannelsRemove(channelRemove); } + IN865_CASE { return RegionIN865ChannelsRemove(channelRemove); } #define IN865_SET_CONTINUOUS_WAVE() \ - IN865_CASE \ - { \ - RegionIN865SetContinuousWave(continuousWave); \ - break; \ - } + IN865_CASE \ + { \ + RegionIN865SetContinuousWave(continuousWave); \ + break; \ + } #define IN865_APPLY_DR_OFFSET() \ - IN865_CASE { return RegionIN865ApplyDrOffset(downlinkDwellTime, dr, drOffset); } + IN865_CASE { return RegionIN865ApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define IN865_IS_ACTIVE() #define IN865_GET_PHY_PARAM() @@ -827,75 +827,75 @@ extern "C" #include "RegionUS915.h" #define US915_CASE case LORAMAC_REGION_US915: #define US915_IS_ACTIVE() \ - US915_CASE { return true; } + US915_CASE { return true; } #define US915_GET_PHY_PARAM() \ - US915_CASE { return RegionUS915GetPhyParam(getPhy); } + US915_CASE { return RegionUS915GetPhyParam(getPhy); } #define US915_SET_BAND_TX_DONE() \ - US915_CASE \ - { \ - RegionUS915SetBandTxDone(txDone); \ - break; \ - } + US915_CASE \ + { \ + RegionUS915SetBandTxDone(txDone); \ + break; \ + } #define US915_INIT_DEFAULTS() \ - US915_CASE \ - { \ - RegionUS915InitDefaults(type); \ - break; \ - } + US915_CASE \ + { \ + RegionUS915InitDefaults(type); \ + break; \ + } #define US915_VERIFY() \ - US915_CASE { return RegionUS915Verify(verify, phyAttribute); } + US915_CASE { return RegionUS915Verify(verify, phyAttribute); } #define US915_APPLY_CF_LIST() \ - US915_CASE \ - { \ - RegionUS915ApplyCFList(applyCFList); \ - break; \ - } + US915_CASE \ + { \ + RegionUS915ApplyCFList(applyCFList); \ + break; \ + } #define US915_CHAN_MASK_SET() \ - US915_CASE { return RegionUS915ChanMaskSet(chanMaskSet); } + US915_CASE { return RegionUS915ChanMaskSet(chanMaskSet); } #define US915_ADR_NEXT() \ - US915_CASE { return RegionUS915AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + US915_CASE { return RegionUS915AdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define US915_COMPUTE_RX_WINDOW_PARAMETERS() \ - US915_CASE \ - { \ - RegionUS915ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + US915_CASE \ + { \ + RegionUS915ComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define US915_RX_CONFIG() \ - US915_CASE { return RegionUS915RxConfig(rxConfig, datarate); } + US915_CASE { return RegionUS915RxConfig(rxConfig, datarate); } #define US915_TX_CONFIG() \ - US915_CASE { return RegionUS915TxConfig(txConfig, txPower, txTimeOnAir); } + US915_CASE { return RegionUS915TxConfig(txConfig, txPower, txTimeOnAir); } #define US915_LINK_ADR_REQ() \ - US915_CASE { return RegionUS915LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + US915_CASE { return RegionUS915LinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define US915_RX_PARAM_SETUP_REQ() \ - US915_CASE { return RegionUS915RxParamSetupReq(rxParamSetupReq); } + US915_CASE { return RegionUS915RxParamSetupReq(rxParamSetupReq); } #define US915_NEW_CHANNEL_REQ() \ - US915_CASE { return RegionUS915NewChannelReq(newChannelReq); } + US915_CASE { return RegionUS915NewChannelReq(newChannelReq); } #define US915_TX_PARAM_SETUP_REQ() \ - US915_CASE { return RegionUS915TxParamSetupReq(txParamSetupReq); } + US915_CASE { return RegionUS915TxParamSetupReq(txParamSetupReq); } #define US915_DL_CHANNEL_REQ() \ - US915_CASE { return RegionUS915DlChannelReq(dlChannelReq); } + US915_CASE { return RegionUS915DlChannelReq(dlChannelReq); } #define US915_ALTERNATE_DR() \ - US915_CASE { return RegionUS915AlternateDr(alternateDr); } + US915_CASE { return RegionUS915AlternateDr(alternateDr); } #define US915_CALC_BACKOFF() \ - US915_CASE \ - { \ - RegionUS915CalcBackOff(calcBackOff); \ - break; \ - } + US915_CASE \ + { \ + RegionUS915CalcBackOff(calcBackOff); \ + break; \ + } #define US915_NEXT_CHANNEL() \ - US915_CASE { return RegionUS915NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + US915_CASE { return RegionUS915NextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define US915_CHANNEL_ADD() \ - US915_CASE { return RegionUS915ChannelAdd(channelAdd); } + US915_CASE { return RegionUS915ChannelAdd(channelAdd); } #define US915_CHANNEL_REMOVE() \ - US915_CASE { return RegionUS915ChannelsRemove(channelRemove); } + US915_CASE { return RegionUS915ChannelsRemove(channelRemove); } #define US915_SET_CONTINUOUS_WAVE() \ - US915_CASE \ - { \ - RegionUS915SetContinuousWave(continuousWave); \ - break; \ - } + US915_CASE \ + { \ + RegionUS915SetContinuousWave(continuousWave); \ + break; \ + } #define US915_APPLY_DR_OFFSET() \ - US915_CASE { return RegionUS915ApplyDrOffset(downlinkDwellTime, dr, drOffset); } + US915_CASE { return RegionUS915ApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define US915_IS_ACTIVE() #define US915_GET_PHY_PARAM() @@ -926,75 +926,75 @@ extern "C" #include "RegionUS915-Hybrid.h" #define US915_HYBRID_CASE case LORAMAC_REGION_US915_HYBRID: #define US915_HYBRID_IS_ACTIVE() \ - US915_HYBRID_CASE { return true; } + US915_HYBRID_CASE { return true; } #define US915_HYBRID_GET_PHY_PARAM() \ - US915_HYBRID_CASE { return RegionUS915HybridGetPhyParam(getPhy); } + US915_HYBRID_CASE { return RegionUS915HybridGetPhyParam(getPhy); } #define US915_HYBRID_SET_BAND_TX_DONE() \ - US915_HYBRID_CASE \ - { \ - RegionUS915HybridSetBandTxDone(txDone); \ - break; \ - } + US915_HYBRID_CASE \ + { \ + RegionUS915HybridSetBandTxDone(txDone); \ + break; \ + } #define US915_HYBRID_INIT_DEFAULTS() \ - US915_HYBRID_CASE \ - { \ - RegionUS915HybridInitDefaults(type); \ - break; \ - } + US915_HYBRID_CASE \ + { \ + RegionUS915HybridInitDefaults(type); \ + break; \ + } #define US915_HYBRID_VERIFY() \ - US915_HYBRID_CASE { return RegionUS915HybridVerify(verify, phyAttribute); } + US915_HYBRID_CASE { return RegionUS915HybridVerify(verify, phyAttribute); } #define US915_HYBRID_APPLY_CF_LIST() \ - US915_HYBRID_CASE \ - { \ - RegionUS915HybridApplyCFList(applyCFList); \ - break; \ - } + US915_HYBRID_CASE \ + { \ + RegionUS915HybridApplyCFList(applyCFList); \ + break; \ + } #define US915_HYBRID_CHAN_MASK_SET() \ - US915_HYBRID_CASE { return RegionUS915HybridChanMaskSet(chanMaskSet); } + US915_HYBRID_CASE { return RegionUS915HybridChanMaskSet(chanMaskSet); } #define US915_HYBRID_ADR_NEXT() \ - US915_HYBRID_CASE { return RegionUS915HybridAdrNext(adrNext, drOut, txPowOut, adrAckCounter); } + US915_HYBRID_CASE { return RegionUS915HybridAdrNext(adrNext, drOut, txPowOut, adrAckCounter); } #define US915_HYBRID_COMPUTE_RX_WINDOW_PARAMETERS() \ - US915_HYBRID_CASE \ - { \ - RegionUS915HybridComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ - break; \ - } + US915_HYBRID_CASE \ + { \ + RegionUS915HybridComputeRxWindowParameters(datarate, minRxSymbols, rxError, rxConfigParams); \ + break; \ + } #define US915_HYBRID_RX_CONFIG() \ - US915_HYBRID_CASE { return RegionUS915HybridRxConfig(rxConfig, datarate); } + US915_HYBRID_CASE { return RegionUS915HybridRxConfig(rxConfig, datarate); } #define US915_HYBRID_TX_CONFIG() \ - US915_HYBRID_CASE { return RegionUS915HybridTxConfig(txConfig, txPower, txTimeOnAir); } + US915_HYBRID_CASE { return RegionUS915HybridTxConfig(txConfig, txPower, txTimeOnAir); } #define US915_HYBRID_LINK_ADR_REQ() \ - US915_HYBRID_CASE { return RegionUS915HybridLinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } + US915_HYBRID_CASE { return RegionUS915HybridLinkAdrReq(linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed); } #define US915_HYBRID_RX_PARAM_SETUP_REQ() \ - US915_HYBRID_CASE { return RegionUS915HybridRxParamSetupReq(rxParamSetupReq); } + US915_HYBRID_CASE { return RegionUS915HybridRxParamSetupReq(rxParamSetupReq); } #define US915_HYBRID_NEW_CHANNEL_REQ() \ - US915_HYBRID_CASE { return RegionUS915HybridNewChannelReq(newChannelReq); } + US915_HYBRID_CASE { return RegionUS915HybridNewChannelReq(newChannelReq); } #define US915_HYBRID_TX_PARAM_SETUP_REQ() \ - US915_HYBRID_CASE { return RegionUS915HybridTxParamSetupReq(txParamSetupReq); } + US915_HYBRID_CASE { return RegionUS915HybridTxParamSetupReq(txParamSetupReq); } #define US915_HYBRID_DL_CHANNEL_REQ() \ - US915_HYBRID_CASE { return RegionUS915HybridDlChannelReq(dlChannelReq); } + US915_HYBRID_CASE { return RegionUS915HybridDlChannelReq(dlChannelReq); } #define US915_HYBRID_ALTERNATE_DR() \ - US915_HYBRID_CASE { return RegionUS915HybridAlternateDr(alternateDr); } + US915_HYBRID_CASE { return RegionUS915HybridAlternateDr(alternateDr); } #define US915_HYBRID_CALC_BACKOFF() \ - US915_HYBRID_CASE \ - { \ - RegionUS915HybridCalcBackOff(calcBackOff); \ - break; \ - } + US915_HYBRID_CASE \ + { \ + RegionUS915HybridCalcBackOff(calcBackOff); \ + break; \ + } #define US915_HYBRID_NEXT_CHANNEL() \ - US915_HYBRID_CASE { return RegionUS915HybridNextChannel(nextChanParams, channel, time, aggregatedTimeOff); } + US915_HYBRID_CASE { return RegionUS915HybridNextChannel(nextChanParams, channel, time, aggregatedTimeOff); } #define US915_HYBRID_CHANNEL_ADD() \ - US915_HYBRID_CASE { return RegionUS915HybridChannelAdd(channelAdd); } + US915_HYBRID_CASE { return RegionUS915HybridChannelAdd(channelAdd); } #define US915_HYBRID_CHANNEL_REMOVE() \ - US915_HYBRID_CASE { return RegionUS915HybridChannelsRemove(channelRemove); } + US915_HYBRID_CASE { return RegionUS915HybridChannelsRemove(channelRemove); } #define US915_HYBRID_SET_CONTINUOUS_WAVE() \ - US915_HYBRID_CASE \ - { \ - RegionUS915HybridSetContinuousWave(continuousWave); \ - break; \ - } + US915_HYBRID_CASE \ + { \ + RegionUS915HybridSetContinuousWave(continuousWave); \ + break; \ + } #define US915_HYBRID_APPLY_DR_OFFSET() \ - US915_HYBRID_CASE { return RegionUS915HybridApplyDrOffset(downlinkDwellTime, dr, drOffset); } + US915_HYBRID_CASE { return RegionUS915HybridApplyDrOffset(downlinkDwellTime, dr, drOffset); } #else #define US915_HYBRID_IS_ACTIVE() #define US915_HYBRID_GET_PHY_PARAM() @@ -1021,487 +1021,487 @@ extern "C" #define US915_HYBRID_APPLY_DR_OFFSET() #endif - bool RegionIsActive(LoRaMacRegion_t region) - { - switch (region) - { - AS923_IS_ACTIVE(); - AU915_IS_ACTIVE(); - CN470_IS_ACTIVE(); - CN779_IS_ACTIVE(); - EU433_IS_ACTIVE(); - EU868_IS_ACTIVE(); - KR920_IS_ACTIVE(); - IN865_IS_ACTIVE(); - US915_IS_ACTIVE(); - US915_HYBRID_IS_ACTIVE(); - default: - { - return false; - } - } - } + bool RegionIsActive(LoRaMacRegion_t region) + { + switch (region) + { + AS923_IS_ACTIVE(); + AU915_IS_ACTIVE(); + CN470_IS_ACTIVE(); + CN779_IS_ACTIVE(); + EU433_IS_ACTIVE(); + EU868_IS_ACTIVE(); + KR920_IS_ACTIVE(); + IN865_IS_ACTIVE(); + US915_IS_ACTIVE(); + US915_HYBRID_IS_ACTIVE(); + default: + { + return false; + } + } + } - PhyParam_t RegionGetPhyParam(LoRaMacRegion_t region, GetPhyParams_t *getPhy) - { - PhyParam_t phyParam = {0}; - switch (region) - { - AS923_GET_PHY_PARAM(); - AU915_GET_PHY_PARAM(); - CN470_GET_PHY_PARAM(); - CN779_GET_PHY_PARAM(); - EU433_GET_PHY_PARAM(); - EU868_GET_PHY_PARAM(); - KR920_GET_PHY_PARAM(); - IN865_GET_PHY_PARAM(); - US915_GET_PHY_PARAM(); - US915_HYBRID_GET_PHY_PARAM(); - default: - { - return phyParam; - } - } - } + PhyParam_t RegionGetPhyParam(LoRaMacRegion_t region, GetPhyParams_t *getPhy) + { + PhyParam_t phyParam = {0}; + switch (region) + { + AS923_GET_PHY_PARAM(); + AU915_GET_PHY_PARAM(); + CN470_GET_PHY_PARAM(); + CN779_GET_PHY_PARAM(); + EU433_GET_PHY_PARAM(); + EU868_GET_PHY_PARAM(); + KR920_GET_PHY_PARAM(); + IN865_GET_PHY_PARAM(); + US915_GET_PHY_PARAM(); + US915_HYBRID_GET_PHY_PARAM(); + default: + { + return phyParam; + } + } + } - void RegionSetBandTxDone(LoRaMacRegion_t region, SetBandTxDoneParams_t *txDone) - { - switch (region) - { - AS923_SET_BAND_TX_DONE(); - AU915_SET_BAND_TX_DONE(); - CN470_SET_BAND_TX_DONE(); - CN779_SET_BAND_TX_DONE(); - EU433_SET_BAND_TX_DONE(); - EU868_SET_BAND_TX_DONE(); - KR920_SET_BAND_TX_DONE(); - IN865_SET_BAND_TX_DONE(); - US915_SET_BAND_TX_DONE(); - US915_HYBRID_SET_BAND_TX_DONE(); - default: - { - return; - } - } - } + void RegionSetBandTxDone(LoRaMacRegion_t region, SetBandTxDoneParams_t *txDone) + { + switch (region) + { + AS923_SET_BAND_TX_DONE(); + AU915_SET_BAND_TX_DONE(); + CN470_SET_BAND_TX_DONE(); + CN779_SET_BAND_TX_DONE(); + EU433_SET_BAND_TX_DONE(); + EU868_SET_BAND_TX_DONE(); + KR920_SET_BAND_TX_DONE(); + IN865_SET_BAND_TX_DONE(); + US915_SET_BAND_TX_DONE(); + US915_HYBRID_SET_BAND_TX_DONE(); + default: + { + return; + } + } + } - void RegionInitDefaults(LoRaMacRegion_t region, InitType_t type) - { - switch (region) - { - AS923_INIT_DEFAULTS(); - AU915_INIT_DEFAULTS(); - CN470_INIT_DEFAULTS(); - CN779_INIT_DEFAULTS(); - EU433_INIT_DEFAULTS(); - EU868_INIT_DEFAULTS(); - KR920_INIT_DEFAULTS(); - IN865_INIT_DEFAULTS(); - US915_INIT_DEFAULTS(); - US915_HYBRID_INIT_DEFAULTS(); - default: - { - break; - } - } - } + void RegionInitDefaults(LoRaMacRegion_t region, InitType_t type) + { + switch (region) + { + AS923_INIT_DEFAULTS(); + AU915_INIT_DEFAULTS(); + CN470_INIT_DEFAULTS(); + CN779_INIT_DEFAULTS(); + EU433_INIT_DEFAULTS(); + EU868_INIT_DEFAULTS(); + KR920_INIT_DEFAULTS(); + IN865_INIT_DEFAULTS(); + US915_INIT_DEFAULTS(); + US915_HYBRID_INIT_DEFAULTS(); + default: + { + break; + } + } + } - bool RegionVerify(LoRaMacRegion_t region, VerifyParams_t *verify, PhyAttribute_t phyAttribute) - { - switch (region) - { - AS923_VERIFY(); - AU915_VERIFY(); - CN470_VERIFY(); - CN779_VERIFY(); - EU433_VERIFY(); - EU868_VERIFY(); - KR920_VERIFY(); - IN865_VERIFY(); - US915_VERIFY(); - US915_HYBRID_VERIFY(); - default: - { - return false; - } - } - } + bool RegionVerify(LoRaMacRegion_t region, VerifyParams_t *verify, PhyAttribute_t phyAttribute) + { + switch (region) + { + AS923_VERIFY(); + AU915_VERIFY(); + CN470_VERIFY(); + CN779_VERIFY(); + EU433_VERIFY(); + EU868_VERIFY(); + KR920_VERIFY(); + IN865_VERIFY(); + US915_VERIFY(); + US915_HYBRID_VERIFY(); + default: + { + return false; + } + } + } - void RegionApplyCFList(LoRaMacRegion_t region, ApplyCFListParams_t *applyCFList) - { - switch (region) - { - AS923_APPLY_CF_LIST(); - AU915_APPLY_CF_LIST(); - CN470_APPLY_CF_LIST(); - CN779_APPLY_CF_LIST(); - EU433_APPLY_CF_LIST(); - EU868_APPLY_CF_LIST(); - KR920_APPLY_CF_LIST(); - IN865_APPLY_CF_LIST(); - US915_APPLY_CF_LIST(); - US915_HYBRID_APPLY_CF_LIST(); - default: - { - break; - } - } - } + void RegionApplyCFList(LoRaMacRegion_t region, ApplyCFListParams_t *applyCFList) + { + switch (region) + { + AS923_APPLY_CF_LIST(); + AU915_APPLY_CF_LIST(); + CN470_APPLY_CF_LIST(); + CN779_APPLY_CF_LIST(); + EU433_APPLY_CF_LIST(); + EU868_APPLY_CF_LIST(); + KR920_APPLY_CF_LIST(); + IN865_APPLY_CF_LIST(); + US915_APPLY_CF_LIST(); + US915_HYBRID_APPLY_CF_LIST(); + default: + { + break; + } + } + } - bool RegionChanMaskSet(LoRaMacRegion_t region, ChanMaskSetParams_t *chanMaskSet) - { - switch (region) - { - AS923_CHAN_MASK_SET(); - AU915_CHAN_MASK_SET(); - CN470_CHAN_MASK_SET(); - CN779_CHAN_MASK_SET(); - EU433_CHAN_MASK_SET(); - EU868_CHAN_MASK_SET(); - KR920_CHAN_MASK_SET(); - IN865_CHAN_MASK_SET(); - US915_CHAN_MASK_SET(); - US915_HYBRID_CHAN_MASK_SET(); - default: - { - return false; - } - } - } + bool RegionChanMaskSet(LoRaMacRegion_t region, ChanMaskSetParams_t *chanMaskSet) + { + switch (region) + { + AS923_CHAN_MASK_SET(); + AU915_CHAN_MASK_SET(); + CN470_CHAN_MASK_SET(); + CN779_CHAN_MASK_SET(); + EU433_CHAN_MASK_SET(); + EU868_CHAN_MASK_SET(); + KR920_CHAN_MASK_SET(); + IN865_CHAN_MASK_SET(); + US915_CHAN_MASK_SET(); + US915_HYBRID_CHAN_MASK_SET(); + default: + { + return false; + } + } + } - bool RegionAdrNext(LoRaMacRegion_t region, AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) - { - switch (region) - { - AS923_ADR_NEXT(); - AU915_ADR_NEXT(); - CN470_ADR_NEXT(); - CN779_ADR_NEXT(); - EU433_ADR_NEXT(); - EU868_ADR_NEXT(); - KR920_ADR_NEXT(); - IN865_ADR_NEXT(); - US915_ADR_NEXT(); - US915_HYBRID_ADR_NEXT(); - default: - { - return false; - } - } - } + bool RegionAdrNext(LoRaMacRegion_t region, AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) + { + switch (region) + { + AS923_ADR_NEXT(); + AU915_ADR_NEXT(); + CN470_ADR_NEXT(); + CN779_ADR_NEXT(); + EU433_ADR_NEXT(); + EU868_ADR_NEXT(); + KR920_ADR_NEXT(); + IN865_ADR_NEXT(); + US915_ADR_NEXT(); + US915_HYBRID_ADR_NEXT(); + default: + { + return false; + } + } + } - void RegionComputeRxWindowParameters(LoRaMacRegion_t region, int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) - { - switch (region) - { - AS923_COMPUTE_RX_WINDOW_PARAMETERS(); - AU915_COMPUTE_RX_WINDOW_PARAMETERS(); - CN470_COMPUTE_RX_WINDOW_PARAMETERS(); - CN779_COMPUTE_RX_WINDOW_PARAMETERS(); - EU433_COMPUTE_RX_WINDOW_PARAMETERS(); - EU868_COMPUTE_RX_WINDOW_PARAMETERS(); - KR920_COMPUTE_RX_WINDOW_PARAMETERS(); - IN865_COMPUTE_RX_WINDOW_PARAMETERS(); - US915_COMPUTE_RX_WINDOW_PARAMETERS(); - US915_HYBRID_COMPUTE_RX_WINDOW_PARAMETERS(); - default: - { - break; - } - } - } + void RegionComputeRxWindowParameters(LoRaMacRegion_t region, int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) + { + switch (region) + { + AS923_COMPUTE_RX_WINDOW_PARAMETERS(); + AU915_COMPUTE_RX_WINDOW_PARAMETERS(); + CN470_COMPUTE_RX_WINDOW_PARAMETERS(); + CN779_COMPUTE_RX_WINDOW_PARAMETERS(); + EU433_COMPUTE_RX_WINDOW_PARAMETERS(); + EU868_COMPUTE_RX_WINDOW_PARAMETERS(); + KR920_COMPUTE_RX_WINDOW_PARAMETERS(); + IN865_COMPUTE_RX_WINDOW_PARAMETERS(); + US915_COMPUTE_RX_WINDOW_PARAMETERS(); + US915_HYBRID_COMPUTE_RX_WINDOW_PARAMETERS(); + default: + { + break; + } + } + } - bool RegionRxConfig(LoRaMacRegion_t region, RxConfigParams_t *rxConfig, int8_t *datarate) - { - switch (region) - { - AS923_RX_CONFIG(); - AU915_RX_CONFIG(); - CN470_RX_CONFIG(); - CN779_RX_CONFIG(); - EU433_RX_CONFIG(); - EU868_RX_CONFIG(); - KR920_RX_CONFIG(); - IN865_RX_CONFIG(); - US915_RX_CONFIG(); - US915_HYBRID_RX_CONFIG(); - default: - { - return false; - } - } - } + bool RegionRxConfig(LoRaMacRegion_t region, RxConfigParams_t *rxConfig, int8_t *datarate) + { + switch (region) + { + AS923_RX_CONFIG(); + AU915_RX_CONFIG(); + CN470_RX_CONFIG(); + CN779_RX_CONFIG(); + EU433_RX_CONFIG(); + EU868_RX_CONFIG(); + KR920_RX_CONFIG(); + IN865_RX_CONFIG(); + US915_RX_CONFIG(); + US915_HYBRID_RX_CONFIG(); + default: + { + return false; + } + } + } - bool RegionTxConfig(LoRaMacRegion_t region, TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) - { - switch (region) - { - AS923_TX_CONFIG(); - AU915_TX_CONFIG(); - CN470_TX_CONFIG(); - CN779_TX_CONFIG(); - EU433_TX_CONFIG(); - EU868_TX_CONFIG(); - KR920_TX_CONFIG(); - IN865_TX_CONFIG(); - US915_TX_CONFIG(); - US915_HYBRID_TX_CONFIG(); - default: - { - return false; - } - } - } + bool RegionTxConfig(LoRaMacRegion_t region, TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) + { + switch (region) + { + AS923_TX_CONFIG(); + AU915_TX_CONFIG(); + CN470_TX_CONFIG(); + CN779_TX_CONFIG(); + EU433_TX_CONFIG(); + EU868_TX_CONFIG(); + KR920_TX_CONFIG(); + IN865_TX_CONFIG(); + US915_TX_CONFIG(); + US915_HYBRID_TX_CONFIG(); + default: + { + return false; + } + } + } - uint8_t RegionLinkAdrReq(LoRaMacRegion_t region, LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) - { - switch (region) - { - AS923_LINK_ADR_REQ(); - AU915_LINK_ADR_REQ(); - CN470_LINK_ADR_REQ(); - CN779_LINK_ADR_REQ(); - EU433_LINK_ADR_REQ(); - EU868_LINK_ADR_REQ(); - KR920_LINK_ADR_REQ(); - IN865_LINK_ADR_REQ(); - US915_LINK_ADR_REQ(); - US915_HYBRID_LINK_ADR_REQ(); - default: - { - return 0; - } - } - } + uint8_t RegionLinkAdrReq(LoRaMacRegion_t region, LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) + { + switch (region) + { + AS923_LINK_ADR_REQ(); + AU915_LINK_ADR_REQ(); + CN470_LINK_ADR_REQ(); + CN779_LINK_ADR_REQ(); + EU433_LINK_ADR_REQ(); + EU868_LINK_ADR_REQ(); + KR920_LINK_ADR_REQ(); + IN865_LINK_ADR_REQ(); + US915_LINK_ADR_REQ(); + US915_HYBRID_LINK_ADR_REQ(); + default: + { + return 0; + } + } + } - uint8_t RegionRxParamSetupReq(LoRaMacRegion_t region, RxParamSetupReqParams_t *rxParamSetupReq) - { - switch (region) - { - AS923_RX_PARAM_SETUP_REQ(); - AU915_RX_PARAM_SETUP_REQ(); - CN470_RX_PARAM_SETUP_REQ(); - CN779_RX_PARAM_SETUP_REQ(); - EU433_RX_PARAM_SETUP_REQ(); - EU868_RX_PARAM_SETUP_REQ(); - KR920_RX_PARAM_SETUP_REQ(); - IN865_RX_PARAM_SETUP_REQ(); - US915_RX_PARAM_SETUP_REQ(); - US915_HYBRID_RX_PARAM_SETUP_REQ(); - default: - { - return 0; - } - } - } + uint8_t RegionRxParamSetupReq(LoRaMacRegion_t region, RxParamSetupReqParams_t *rxParamSetupReq) + { + switch (region) + { + AS923_RX_PARAM_SETUP_REQ(); + AU915_RX_PARAM_SETUP_REQ(); + CN470_RX_PARAM_SETUP_REQ(); + CN779_RX_PARAM_SETUP_REQ(); + EU433_RX_PARAM_SETUP_REQ(); + EU868_RX_PARAM_SETUP_REQ(); + KR920_RX_PARAM_SETUP_REQ(); + IN865_RX_PARAM_SETUP_REQ(); + US915_RX_PARAM_SETUP_REQ(); + US915_HYBRID_RX_PARAM_SETUP_REQ(); + default: + { + return 0; + } + } + } - uint8_t RegionNewChannelReq(LoRaMacRegion_t region, NewChannelReqParams_t *newChannelReq) - { - switch (region) - { - AS923_NEW_CHANNEL_REQ(); - AU915_NEW_CHANNEL_REQ(); - CN470_NEW_CHANNEL_REQ(); - CN779_NEW_CHANNEL_REQ(); - EU433_NEW_CHANNEL_REQ(); - EU868_NEW_CHANNEL_REQ(); - KR920_NEW_CHANNEL_REQ(); - IN865_NEW_CHANNEL_REQ(); - US915_NEW_CHANNEL_REQ(); - US915_HYBRID_NEW_CHANNEL_REQ(); - default: - { - return 0; - } - } - } + uint8_t RegionNewChannelReq(LoRaMacRegion_t region, NewChannelReqParams_t *newChannelReq) + { + switch (region) + { + AS923_NEW_CHANNEL_REQ(); + AU915_NEW_CHANNEL_REQ(); + CN470_NEW_CHANNEL_REQ(); + CN779_NEW_CHANNEL_REQ(); + EU433_NEW_CHANNEL_REQ(); + EU868_NEW_CHANNEL_REQ(); + KR920_NEW_CHANNEL_REQ(); + IN865_NEW_CHANNEL_REQ(); + US915_NEW_CHANNEL_REQ(); + US915_HYBRID_NEW_CHANNEL_REQ(); + default: + { + return 0; + } + } + } - int8_t RegionTxParamSetupReq(LoRaMacRegion_t region, TxParamSetupReqParams_t *txParamSetupReq) - { - switch (region) - { - AS923_TX_PARAM_SETUP_REQ(); - AU915_TX_PARAM_SETUP_REQ(); - CN470_TX_PARAM_SETUP_REQ(); - CN779_TX_PARAM_SETUP_REQ(); - EU433_TX_PARAM_SETUP_REQ(); - EU868_TX_PARAM_SETUP_REQ(); - KR920_TX_PARAM_SETUP_REQ(); - IN865_TX_PARAM_SETUP_REQ(); - US915_TX_PARAM_SETUP_REQ(); - US915_HYBRID_TX_PARAM_SETUP_REQ(); - default: - { - return 0; - } - } - } + int8_t RegionTxParamSetupReq(LoRaMacRegion_t region, TxParamSetupReqParams_t *txParamSetupReq) + { + switch (region) + { + AS923_TX_PARAM_SETUP_REQ(); + AU915_TX_PARAM_SETUP_REQ(); + CN470_TX_PARAM_SETUP_REQ(); + CN779_TX_PARAM_SETUP_REQ(); + EU433_TX_PARAM_SETUP_REQ(); + EU868_TX_PARAM_SETUP_REQ(); + KR920_TX_PARAM_SETUP_REQ(); + IN865_TX_PARAM_SETUP_REQ(); + US915_TX_PARAM_SETUP_REQ(); + US915_HYBRID_TX_PARAM_SETUP_REQ(); + default: + { + return 0; + } + } + } - uint8_t RegionDlChannelReq(LoRaMacRegion_t region, DlChannelReqParams_t *dlChannelReq) - { - switch (region) - { - AS923_DL_CHANNEL_REQ(); - AU915_DL_CHANNEL_REQ(); - CN470_DL_CHANNEL_REQ(); - CN779_DL_CHANNEL_REQ(); - EU433_DL_CHANNEL_REQ(); - EU868_DL_CHANNEL_REQ(); - KR920_DL_CHANNEL_REQ(); - IN865_DL_CHANNEL_REQ(); - US915_DL_CHANNEL_REQ(); - US915_HYBRID_DL_CHANNEL_REQ(); - default: - { - return 0; - } - } - } + uint8_t RegionDlChannelReq(LoRaMacRegion_t region, DlChannelReqParams_t *dlChannelReq) + { + switch (region) + { + AS923_DL_CHANNEL_REQ(); + AU915_DL_CHANNEL_REQ(); + CN470_DL_CHANNEL_REQ(); + CN779_DL_CHANNEL_REQ(); + EU433_DL_CHANNEL_REQ(); + EU868_DL_CHANNEL_REQ(); + KR920_DL_CHANNEL_REQ(); + IN865_DL_CHANNEL_REQ(); + US915_DL_CHANNEL_REQ(); + US915_HYBRID_DL_CHANNEL_REQ(); + default: + { + return 0; + } + } + } - int8_t RegionAlternateDr(LoRaMacRegion_t region, AlternateDrParams_t *alternateDr) - { - switch (region) - { - AS923_ALTERNATE_DR(); - AU915_ALTERNATE_DR(); - CN470_ALTERNATE_DR(); - CN779_ALTERNATE_DR(); - EU433_ALTERNATE_DR(); - EU868_ALTERNATE_DR(); - KR920_ALTERNATE_DR(); - IN865_ALTERNATE_DR(); - US915_ALTERNATE_DR(); - US915_HYBRID_ALTERNATE_DR(); - default: - { - return 0; - } - } - } + int8_t RegionAlternateDr(LoRaMacRegion_t region, AlternateDrParams_t *alternateDr) + { + switch (region) + { + AS923_ALTERNATE_DR(); + AU915_ALTERNATE_DR(); + CN470_ALTERNATE_DR(); + CN779_ALTERNATE_DR(); + EU433_ALTERNATE_DR(); + EU868_ALTERNATE_DR(); + KR920_ALTERNATE_DR(); + IN865_ALTERNATE_DR(); + US915_ALTERNATE_DR(); + US915_HYBRID_ALTERNATE_DR(); + default: + { + return 0; + } + } + } - void RegionCalcBackOff(LoRaMacRegion_t region, CalcBackOffParams_t *calcBackOff) - { - switch (region) - { - AS923_CALC_BACKOFF(); - AU915_CALC_BACKOFF(); - CN470_CALC_BACKOFF(); - CN779_CALC_BACKOFF(); - EU433_CALC_BACKOFF(); - EU868_CALC_BACKOFF(); - KR920_CALC_BACKOFF(); - IN865_CALC_BACKOFF(); - US915_CALC_BACKOFF(); - US915_HYBRID_CALC_BACKOFF(); - default: - { - break; - } - } - } + void RegionCalcBackOff(LoRaMacRegion_t region, CalcBackOffParams_t *calcBackOff) + { + switch (region) + { + AS923_CALC_BACKOFF(); + AU915_CALC_BACKOFF(); + CN470_CALC_BACKOFF(); + CN779_CALC_BACKOFF(); + EU433_CALC_BACKOFF(); + EU868_CALC_BACKOFF(); + KR920_CALC_BACKOFF(); + IN865_CALC_BACKOFF(); + US915_CALC_BACKOFF(); + US915_HYBRID_CALC_BACKOFF(); + default: + { + break; + } + } + } - bool RegionNextChannel(LoRaMacRegion_t region, NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) - { - switch (region) - { - AS923_NEXT_CHANNEL(); - AU915_NEXT_CHANNEL(); - CN470_NEXT_CHANNEL(); - CN779_NEXT_CHANNEL(); - EU433_NEXT_CHANNEL(); - EU868_NEXT_CHANNEL(); - KR920_NEXT_CHANNEL(); - IN865_NEXT_CHANNEL(); - US915_NEXT_CHANNEL(); - US915_HYBRID_NEXT_CHANNEL(); - default: - { - return false; - } - } - } + bool RegionNextChannel(LoRaMacRegion_t region, NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) + { + switch (region) + { + AS923_NEXT_CHANNEL(); + AU915_NEXT_CHANNEL(); + CN470_NEXT_CHANNEL(); + CN779_NEXT_CHANNEL(); + EU433_NEXT_CHANNEL(); + EU868_NEXT_CHANNEL(); + KR920_NEXT_CHANNEL(); + IN865_NEXT_CHANNEL(); + US915_NEXT_CHANNEL(); + US915_HYBRID_NEXT_CHANNEL(); + default: + { + return false; + } + } + } - LoRaMacStatus_t RegionChannelAdd(LoRaMacRegion_t region, ChannelAddParams_t *channelAdd) - { - switch (region) - { - AS923_CHANNEL_ADD(); - AU915_CHANNEL_ADD(); - CN470_CHANNEL_ADD(); - CN779_CHANNEL_ADD(); - EU433_CHANNEL_ADD(); - EU868_CHANNEL_ADD(); - KR920_CHANNEL_ADD(); - IN865_CHANNEL_ADD(); - US915_CHANNEL_ADD(); - US915_HYBRID_CHANNEL_ADD(); - default: - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - } - } + LoRaMacStatus_t RegionChannelAdd(LoRaMacRegion_t region, ChannelAddParams_t *channelAdd) + { + switch (region) + { + AS923_CHANNEL_ADD(); + AU915_CHANNEL_ADD(); + CN470_CHANNEL_ADD(); + CN779_CHANNEL_ADD(); + EU433_CHANNEL_ADD(); + EU868_CHANNEL_ADD(); + KR920_CHANNEL_ADD(); + IN865_CHANNEL_ADD(); + US915_CHANNEL_ADD(); + US915_HYBRID_CHANNEL_ADD(); + default: + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + } + } - bool RegionChannelsRemove(LoRaMacRegion_t region, ChannelRemoveParams_t *channelRemove) - { - switch (region) - { - AS923_CHANNEL_REMOVE(); - AU915_CHANNEL_REMOVE(); - CN470_CHANNEL_REMOVE(); - CN779_CHANNEL_REMOVE(); - EU433_CHANNEL_REMOVE(); - EU868_CHANNEL_REMOVE(); - KR920_CHANNEL_REMOVE(); - IN865_CHANNEL_REMOVE(); - US915_CHANNEL_REMOVE(); - US915_HYBRID_CHANNEL_REMOVE(); - default: - { - return false; - } - } - } + bool RegionChannelsRemove(LoRaMacRegion_t region, ChannelRemoveParams_t *channelRemove) + { + switch (region) + { + AS923_CHANNEL_REMOVE(); + AU915_CHANNEL_REMOVE(); + CN470_CHANNEL_REMOVE(); + CN779_CHANNEL_REMOVE(); + EU433_CHANNEL_REMOVE(); + EU868_CHANNEL_REMOVE(); + KR920_CHANNEL_REMOVE(); + IN865_CHANNEL_REMOVE(); + US915_CHANNEL_REMOVE(); + US915_HYBRID_CHANNEL_REMOVE(); + default: + { + return false; + } + } + } - void RegionSetContinuousWave(LoRaMacRegion_t region, ContinuousWaveParams_t *continuousWave) - { - switch (region) - { - AS923_SET_CONTINUOUS_WAVE(); - AU915_SET_CONTINUOUS_WAVE(); - CN470_SET_CONTINUOUS_WAVE(); - CN779_SET_CONTINUOUS_WAVE(); - EU433_SET_CONTINUOUS_WAVE(); - EU868_SET_CONTINUOUS_WAVE(); - KR920_SET_CONTINUOUS_WAVE(); - IN865_SET_CONTINUOUS_WAVE(); - US915_SET_CONTINUOUS_WAVE(); - US915_HYBRID_SET_CONTINUOUS_WAVE(); - default: - { - break; - } - } - } + void RegionSetContinuousWave(LoRaMacRegion_t region, ContinuousWaveParams_t *continuousWave) + { + switch (region) + { + AS923_SET_CONTINUOUS_WAVE(); + AU915_SET_CONTINUOUS_WAVE(); + CN470_SET_CONTINUOUS_WAVE(); + CN779_SET_CONTINUOUS_WAVE(); + EU433_SET_CONTINUOUS_WAVE(); + EU868_SET_CONTINUOUS_WAVE(); + KR920_SET_CONTINUOUS_WAVE(); + IN865_SET_CONTINUOUS_WAVE(); + US915_SET_CONTINUOUS_WAVE(); + US915_HYBRID_SET_CONTINUOUS_WAVE(); + default: + { + break; + } + } + } - uint8_t RegionApplyDrOffset(LoRaMacRegion_t region, uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) - { - switch (region) - { - AS923_APPLY_DR_OFFSET(); - AU915_APPLY_DR_OFFSET(); - CN470_APPLY_DR_OFFSET(); - CN779_APPLY_DR_OFFSET(); - EU433_APPLY_DR_OFFSET(); - EU868_APPLY_DR_OFFSET(); - KR920_APPLY_DR_OFFSET(); - IN865_APPLY_DR_OFFSET(); - US915_APPLY_DR_OFFSET(); - US915_HYBRID_APPLY_DR_OFFSET(); - default: - { - return dr; - } - } - } + uint8_t RegionApplyDrOffset(LoRaMacRegion_t region, uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) + { + switch (region) + { + AS923_APPLY_DR_OFFSET(); + AU915_APPLY_DR_OFFSET(); + CN470_APPLY_DR_OFFSET(); + CN779_APPLY_DR_OFFSET(); + EU433_APPLY_DR_OFFSET(); + EU868_APPLY_DR_OFFSET(); + KR920_APPLY_DR_OFFSET(); + IN865_APPLY_DR_OFFSET(); + US915_APPLY_DR_OFFSET(); + US915_HYBRID_APPLY_DR_OFFSET(); + default: + { + return dr; + } + } + } }; \ No newline at end of file diff --git a/src/mac/region/Region.h b/src/mac/region/Region.h index 351284a..7467098 100644 --- a/src/mac/region/Region.h +++ b/src/mac/region/Region.h @@ -517,657 +517,657 @@ extern "C" */ #define TX_POWER_15 15 - /*! + /*! * Enumeration of phy attributes. */ - typedef enum ePhyAttribute - { - /*! + typedef enum ePhyAttribute + { + /*! * Minimum RX datarate. */ - PHY_MIN_RX_DR, - /*! + PHY_MIN_RX_DR, + /*! * Minimum TX datarate. */ - PHY_MIN_TX_DR, - /*! + PHY_MIN_TX_DR, + /*! * Maximum RX datarate. */ - PHY_MAX_RX_DR, - /*! + PHY_MAX_RX_DR, + /*! * Maximum TX datarate. */ - PHY_MAX_TX_DR, - /*! + PHY_MAX_TX_DR, + /*! * TX datarate. */ - PHY_TX_DR, - /*! + PHY_TX_DR, + /*! * Default TX datarate. */ - PHY_DEF_TX_DR, - /*! + PHY_DEF_TX_DR, + /*! * RX datarate. */ - PHY_RX_DR, - /*! + PHY_RX_DR, + /*! * TX power. */ - PHY_TX_POWER, - /*! + PHY_TX_POWER, + /*! * Default TX power. */ - PHY_DEF_TX_POWER, - /*! + PHY_DEF_TX_POWER, + /*! * Maximum payload possible. */ - PHY_MAX_PAYLOAD, - /*! + PHY_MAX_PAYLOAD, + /*! * Maximum payload possible when repeater support is enabled. */ - PHY_MAX_PAYLOAD_REPEATER, - /*! + PHY_MAX_PAYLOAD_REPEATER, + /*! * Duty cycle. */ - PHY_DUTY_CYCLE, - /*! + PHY_DUTY_CYCLE, + /*! * Maximum receive window duration. */ - PHY_MAX_RX_WINDOW, - /*! + PHY_MAX_RX_WINDOW, + /*! * Receive delay for window 1. */ - PHY_RECEIVE_DELAY1, - /*! + PHY_RECEIVE_DELAY1, + /*! * Receive delay for window 2. */ - PHY_RECEIVE_DELAY2, - /*! + PHY_RECEIVE_DELAY2, + /*! * Join accept delay for window 1. */ - PHY_JOIN_ACCEPT_DELAY1, - /*! + PHY_JOIN_ACCEPT_DELAY1, + /*! * Join accept delay for window 2. */ - PHY_JOIN_ACCEPT_DELAY2, - /*! + PHY_JOIN_ACCEPT_DELAY2, + /*! * Maximum frame counter gap. */ - PHY_MAX_FCNT_GAP, - /*! + PHY_MAX_FCNT_GAP, + /*! * Acknowledgement time out. */ - PHY_ACK_TIMEOUT, - /*! + PHY_ACK_TIMEOUT, + /*! * Default datarate offset for window 1. */ - PHY_DEF_DR1_OFFSET, - /*! + PHY_DEF_DR1_OFFSET, + /*! * Default receive window 2 frequency. */ - PHY_DEF_RX2_FREQUENCY, - /*! + PHY_DEF_RX2_FREQUENCY, + /*! * Default receive window 2 datarate. */ - PHY_DEF_RX2_DR, - /*! + PHY_DEF_RX2_DR, + /*! * Channels mask. */ - PHY_CHANNELS_MASK, - /*! + PHY_CHANNELS_MASK, + /*! * Channels default mask. */ - PHY_CHANNELS_DEFAULT_MASK, - /*! + PHY_CHANNELS_DEFAULT_MASK, + /*! * Maximum number of supported channels */ - PHY_MAX_NB_CHANNELS, - /*! + PHY_MAX_NB_CHANNELS, + /*! * Channels. */ - PHY_CHANNELS, - /*! + PHY_CHANNELS, + /*! * Default value of the uplink dwell time. */ - PHY_DEF_UPLINK_DWELL_TIME, - /*! + PHY_DEF_UPLINK_DWELL_TIME, + /*! * Default value of the downlink dwell time. */ - PHY_DEF_DOWNLINK_DWELL_TIME, - /*! + PHY_DEF_DOWNLINK_DWELL_TIME, + /*! * Default value of the MaxEIRP. */ - PHY_DEF_MAX_EIRP, - /*! + PHY_DEF_MAX_EIRP, + /*! * Default value of the antenna gain. */ - PHY_DEF_ANTENNA_GAIN, - /*! + PHY_DEF_ANTENNA_GAIN, + /*! * Value for the number of join trials. */ - PHY_NB_JOIN_TRIALS, - /*! + PHY_NB_JOIN_TRIALS, + /*! * Default value for the number of join trials. */ - PHY_DEF_NB_JOIN_TRIALS, - /*! + PHY_DEF_NB_JOIN_TRIALS, + /*! * Next lower datarate. */ - PHY_NEXT_LOWER_TX_DR - } PhyAttribute_t; + PHY_NEXT_LOWER_TX_DR + } PhyAttribute_t; - /*! + /*! * Enumeration of initialization types. */ - typedef enum eInitType - { - /*! + typedef enum eInitType + { + /*! * Initializes the region specific data to defaults, according to the * LoRaWAN specification. */ - INIT_TYPE_INIT, - /*! + INIT_TYPE_INIT, + /*! * Restores default channels defined by the LoRaWAN specification only. */ - INIT_TYPE_RESTORE, - /*! + INIT_TYPE_RESTORE, + /*! * Initializes the region specific data to the defaults which were set by * the application. */ - INIT_TYPE_APP_DEFAULTS - } InitType_t; + INIT_TYPE_APP_DEFAULTS + } InitType_t; - typedef enum eChannelsMask - { - /*! + typedef enum eChannelsMask + { + /*! * The channels mask. */ - CHANNELS_MASK, - /*! + CHANNELS_MASK, + /*! * The channels default mask. */ - CHANNELS_DEFAULT_MASK - } ChannelsMask_t; + CHANNELS_DEFAULT_MASK + } ChannelsMask_t; - /*! + /*! * Union for the structure uGetPhyParams */ - typedef union uPhyParam { - /*! + typedef union uPhyParam { + /*! * A parameter value. */ - uint32_t Value; - /*! + uint32_t Value; + /*! * A floating point value. */ - float fValue; - /*! + float fValue; + /*! * Pointer to the channels mask. */ - uint16_t *ChannelsMask; - /*! + uint16_t *ChannelsMask; + /*! * Pointer to the channels. */ - ChannelParams_t *Channels; - } PhyParam_t; + ChannelParams_t *Channels; + } PhyParam_t; - /*! + /*! * Parameter structure for the function RegionGetPhyParam. */ - typedef struct sGetPhyParams - { - /*! + typedef struct sGetPhyParams + { + /*! * Setup the parameter to get. */ - PhyAttribute_t Attribute; - /*! + PhyAttribute_t Attribute; + /*! * Datarate. * The parameter is needed for the following queries: * PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER, PHY_NEXT_LOWER_TX_DR. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * Uplink dwell time. * The parameter is needed for the following queries: * PHY_MIN_TX_DR, PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER, PHY_NEXT_LOWER_TX_DR. */ - uint8_t UplinkDwellTime; - /*! + uint8_t UplinkDwellTime; + /*! * Downlink dwell time. * The parameter is needed for the following queries: * PHY_MIN_RX_DR, PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER. */ - uint8_t DownlinkDwellTime; - } GetPhyParams_t; + uint8_t DownlinkDwellTime; + } GetPhyParams_t; - /*! + /*! * Parameter structure for the function RegionSetBandTxDone. */ - typedef struct sSetBandTxDoneParams - { - /*! + typedef struct sSetBandTxDoneParams + { + /*! * Channel to update. */ - uint8_t Channel; - /*! + uint8_t Channel; + /*! * Joined Set to true, if the node has joined the network */ - bool Joined; - /*! + bool Joined; + /*! * Last TX done time. */ - TimerTime_t LastTxDoneTime; - } SetBandTxDoneParams_t; + TimerTime_t LastTxDoneTime; + } SetBandTxDoneParams_t; - /*! + /*! * Parameter structure for the function RegionVerify. */ - typedef union uVerifyParams { - /*! + typedef union uVerifyParams { + /*! * TX power to verify. */ - int8_t TxPower; - /*! + int8_t TxPower; + /*! * Set to true, if the duty cycle is enabled, otherwise false. */ - bool DutyCycle; - /*! + bool DutyCycle; + /*! * The number of join trials. */ - uint8_t NbJoinTrials; - /*! + uint8_t NbJoinTrials; + /*! * Datarate to verify. */ - struct sDatarateParams - { - /*! + struct sDatarateParams + { + /*! * Datarate to verify. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * The downlink dwell time. */ - uint8_t DownlinkDwellTime; - /*! + uint8_t DownlinkDwellTime; + /*! * The up link dwell time. */ - uint8_t UplinkDwellTime; - } DatarateParams; - } VerifyParams_t; + uint8_t UplinkDwellTime; + } DatarateParams; + } VerifyParams_t; - /*! + /*! * Parameter structure for the function RegionApplyCFList. */ - typedef struct sApplyCFListParams - { - /*! + typedef struct sApplyCFListParams + { + /*! * Payload which contains the CF list. */ - uint8_t *Payload; - /*! + uint8_t *Payload; + /*! * Size of the payload. */ - uint8_t Size; - } ApplyCFListParams_t; + uint8_t Size; + } ApplyCFListParams_t; - /*! + /*! * Parameter structure for the function RegionChanMaskSet. */ - typedef struct sChanMaskSetParams - { - /*! + typedef struct sChanMaskSetParams + { + /*! * Pointer to the channels mask which should be set. */ - uint16_t *ChannelsMaskIn; - /*! + uint16_t *ChannelsMaskIn; + /*! * Pointer to the channels mask which should be set. */ - ChannelsMask_t ChannelsMaskType; - } ChanMaskSetParams_t; + ChannelsMask_t ChannelsMaskType; + } ChanMaskSetParams_t; - /*! + /*! * Parameter structure for the function RegionAdrNext. */ - typedef struct sAdrNextParams - { - /*! + typedef struct sAdrNextParams + { + /*! * Set to true, if the function should update the channels mask. */ - bool UpdateChanMask; - /*! + bool UpdateChanMask; + /*! * Set to true, if ADR is enabled. */ - bool AdrEnabled; - /*! + bool AdrEnabled; + /*! * ADR ack counter. */ - uint32_t AdrAckCounter; - /*! + uint32_t AdrAckCounter; + /*! * Datarate used currently. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * TX power used currently. */ - int8_t TxPower; - /*! + int8_t TxPower; + /*! * UplinkDwellTime */ - uint8_t UplinkDwellTime; - } AdrNextParams_t; + uint8_t UplinkDwellTime; + } AdrNextParams_t; - /*! + /*! * Parameter structure for the function RegionRxConfig. */ - typedef struct sRxConfigParams - { - /*! + typedef struct sRxConfigParams + { + /*! * The RX channel. */ - uint8_t Channel; - /*! + uint8_t Channel; + /*! * RX datarate. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * RX bandwidth. */ - uint8_t Bandwidth; - /*! + uint8_t Bandwidth; + /*! * RX datarate offset. */ - int8_t DrOffset; - /*! + int8_t DrOffset; + /*! * RX frequency. */ - uint32_t Frequency; - /*! + uint32_t Frequency; + /*! * RX window timeout */ - uint32_t WindowTimeout; - /*! + uint32_t WindowTimeout; + /*! * RX window offset */ - int32_t WindowOffset; - /*! + int32_t WindowOffset; + /*! * Downlink dwell time. */ - uint8_t DownlinkDwellTime; - /*! + uint8_t DownlinkDwellTime; + /*! * Set to true, if a repeater is supported. */ - bool RepeaterSupport; - /*! + bool RepeaterSupport; + /*! * Set to true, if RX should be continuous. */ - bool RxContinuous; - /*! + bool RxContinuous; + /*! * Sets the RX window. 0: RX window 1, 1: RX window 2. */ - bool Window; - } RxConfigParams_t; + bool Window; + } RxConfigParams_t; - /*! + /*! * Parameter structure for the function RegionTxConfig. */ - typedef struct sTxConfigParams - { - /*! + typedef struct sTxConfigParams + { + /*! * The TX channel. */ - uint8_t Channel; - /*! + uint8_t Channel; + /*! * The TX datarate. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * The TX power. */ - int8_t TxPower; - /*! + int8_t TxPower; + /*! * The Max EIRP, if applicable. */ - float MaxEirp; - /*! + float MaxEirp; + /*! * The antenna gain, if applicable. */ - float AntennaGain; - /*! + float AntennaGain; + /*! * Frame length to setup. */ - uint16_t PktLen; - } TxConfigParams_t; + uint16_t PktLen; + } TxConfigParams_t; - /*! + /*! * Parameter structure for the function RegionLinkAdrReq. */ - typedef struct sLinkAdrReqParams - { - /*! + typedef struct sLinkAdrReqParams + { + /*! * Pointer to the payload which contains the MAC commands. */ - uint8_t *Payload; - /*! + uint8_t *Payload; + /*! * Size of the payload. */ - uint8_t PayloadSize; - /*! + uint8_t PayloadSize; + /*! * Uplink dwell time. */ - uint8_t UplinkDwellTime; - /*! + uint8_t UplinkDwellTime; + /*! * Set to true, if ADR is enabled. */ - bool AdrEnabled; - /*! + bool AdrEnabled; + /*! * The current datarate. */ - int8_t CurrentDatarate; - /*! + int8_t CurrentDatarate; + /*! * The current TX power. */ - int8_t CurrentTxPower; - /*! + int8_t CurrentTxPower; + /*! * The current number of repetitions. */ - uint8_t CurrentNbRep; - } LinkAdrReqParams_t; + uint8_t CurrentNbRep; + } LinkAdrReqParams_t; - /*! + /*! * Parameter structure for the function RegionRxParamSetupReq. */ - typedef struct sRxParamSetupReqParams - { - /*! + typedef struct sRxParamSetupReqParams + { + /*! * The datarate to setup. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * Datarate offset. */ - int8_t DrOffset; - /*! + int8_t DrOffset; + /*! * The frequency to setup. */ - uint32_t Frequency; - } RxParamSetupReqParams_t; + uint32_t Frequency; + } RxParamSetupReqParams_t; - /*! + /*! * Parameter structure for the function RegionNewChannelReq. */ - typedef struct sNewChannelReqParams - { - /*! + typedef struct sNewChannelReqParams + { + /*! * Pointer to the new channels. */ - ChannelParams_t *NewChannel; - /*! + ChannelParams_t *NewChannel; + /*! * Channel id. */ - int8_t ChannelId; - } NewChannelReqParams_t; + int8_t ChannelId; + } NewChannelReqParams_t; - /*! + /*! * Parameter structure for the function RegionTxParamSetupReq. */ - typedef struct sTxParamSetupReqParams - { - /*! + typedef struct sTxParamSetupReqParams + { + /*! * Uplink dwell time. */ - uint8_t UplinkDwellTime; - /*! + uint8_t UplinkDwellTime; + /*! * Downlink dwell time. */ - uint8_t DownlinkDwellTime; - /*! + uint8_t DownlinkDwellTime; + /*! * Max EIRP. */ - uint8_t MaxEirp; - } TxParamSetupReqParams_t; + uint8_t MaxEirp; + } TxParamSetupReqParams_t; - /*! + /*! * Parameter structure for the function RegionDlChannelReq. */ - typedef struct sDlChannelReqParams - { - /*! + typedef struct sDlChannelReqParams + { + /*! * Channel Id to add the frequency. */ - uint8_t ChannelId; - /*! + uint8_t ChannelId; + /*! * Alternative frequency for the Rx1 window. */ - uint32_t Rx1Frequency; - } DlChannelReqParams_t; + uint32_t Rx1Frequency; + } DlChannelReqParams_t; - /*! + /*! * Parameter structure for the function RegionAlternateDr. */ - typedef struct sAlternateDrParams - { - /*! + typedef struct sAlternateDrParams + { + /*! * Number of trials. */ - uint16_t NbTrials; - } AlternateDrParams_t; + uint16_t NbTrials; + } AlternateDrParams_t; - /*! + /*! * Parameter structure for the function RegionCalcBackOff. */ - typedef struct sCalcBackOffParams - { - /*! + typedef struct sCalcBackOffParams + { + /*! * Set to true, if the node has already joined a network, otherwise false. */ - bool Joined; - /*! + bool Joined; + /*! * Joined Set to true, if the last uplink was a join request */ - bool LastTxIsJoinRequest; - /*! + bool LastTxIsJoinRequest; + /*! * Set to true, if the duty cycle is enabled, otherwise false. */ - bool DutyCycleEnabled; - /*! + bool DutyCycleEnabled; + /*! * Current channel index. */ - uint8_t Channel; - /*! + uint8_t Channel; + /*! * Elapsed time since the start of the node. */ - TimerTime_t ElapsedTime; - /*! + TimerTime_t ElapsedTime; + /*! * Time-on-air of the last transmission. */ - TimerTime_t TxTimeOnAir; - } CalcBackOffParams_t; + TimerTime_t TxTimeOnAir; + } CalcBackOffParams_t; - /*! + /*! * Parameter structure for the function RegionNextChannel. */ - typedef struct sNextChanParams - { - /*! + typedef struct sNextChanParams + { + /*! * Aggregated time-off time. */ - TimerTime_t AggrTimeOff; - /*! + TimerTime_t AggrTimeOff; + /*! * Time of the last aggregated TX. */ - TimerTime_t LastAggrTx; - /*! + TimerTime_t LastAggrTx; + /*! * Current datarate. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * Set to true, if the node has already joined a network, otherwise false. */ - bool Joined; - /*! + bool Joined; + /*! * Set to true, if the duty cycle is enabled, otherwise false. */ - bool DutyCycleEnabled; - } NextChanParams_t; + bool DutyCycleEnabled; + } NextChanParams_t; - /*! + /*! * Parameter structure for the function RegionChannelsAdd. */ - typedef struct sChannelAddParams - { - /*! + typedef struct sChannelAddParams + { + /*! * Pointer to the new channel to add. */ - ChannelParams_t *NewChannel; - /*! + ChannelParams_t *NewChannel; + /*! * Channel id to add. */ - uint8_t ChannelId; - } ChannelAddParams_t; + uint8_t ChannelId; + } ChannelAddParams_t; - /*! + /*! * Parameter structure for the function RegionChannelsRemove. */ - typedef struct sChannelRemoveParams - { - /*! + typedef struct sChannelRemoveParams + { + /*! * Channel id to remove. */ - uint8_t ChannelId; - } ChannelRemoveParams_t; + uint8_t ChannelId; + } ChannelRemoveParams_t; - /*! + /*! * Parameter structure for the function RegionContinuousWave. */ - typedef struct sContinuousWaveParams - { - /*! + typedef struct sContinuousWaveParams + { + /*! * Current channel index. */ - uint8_t Channel; - /*! + uint8_t Channel; + /*! * Datarate. Used to limit the TX power. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * The TX power to setup. */ - int8_t TxPower; - /*! + int8_t TxPower; + /*! * Max EIRP, if applicable. */ - float MaxEirp; - /*! + float MaxEirp; + /*! * The antenna gain, if applicable. */ - float AntennaGain; - /*! + float AntennaGain; + /*! * Specifies the time the radio will stay in CW mode. */ - uint16_t Timeout; - } ContinuousWaveParams_t; + uint16_t Timeout; + } ContinuousWaveParams_t; - /*! + /*! * \brief The function verifies if a region is active or not. If a region * is not active, it cannot be used. * @@ -1175,9 +1175,9 @@ extern "C" * * \retval Return true, if the region is supported. */ - bool RegionIsActive(LoRaMacRegion_t region); + bool RegionIsActive(LoRaMacRegion_t region); - /*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] region LoRaWAN region. @@ -1186,27 +1186,27 @@ extern "C" * * \retval Returns a structure containing the PHY parameter. */ - PhyParam_t RegionGetPhyParam(LoRaMacRegion_t region, GetPhyParams_t *getPhy); + PhyParam_t RegionGetPhyParam(LoRaMacRegion_t region, GetPhyParams_t *getPhy); - /*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] region LoRaWAN region. * * \param [IN] txDone Pointer to the function parameters. */ - void RegionSetBandTxDone(LoRaMacRegion_t region, SetBandTxDoneParams_t *txDone); + void RegionSetBandTxDone(LoRaMacRegion_t region, SetBandTxDoneParams_t *txDone); - /*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] region LoRaWAN region. * * \param [IN] type Sets the initialization type. */ - void RegionInitDefaults(LoRaMacRegion_t region, InitType_t type); + void RegionInitDefaults(LoRaMacRegion_t region, InitType_t type); - /*! + /*! * \brief Verifies a parameter. * * \param [IN] region LoRaWAN region. @@ -1217,9 +1217,9 @@ extern "C" * * \retval Returns true, if the parameter is valid. */ - bool RegionVerify(LoRaMacRegion_t region, VerifyParams_t *verify, PhyAttribute_t phyAttribute); + bool RegionVerify(LoRaMacRegion_t region, VerifyParams_t *verify, PhyAttribute_t phyAttribute); - /*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * @@ -1227,9 +1227,9 @@ extern "C" * * \param [IN] applyCFList Pointer to the function parameters. */ - void RegionApplyCFList(LoRaMacRegion_t region, ApplyCFListParams_t *applyCFList); + void RegionApplyCFList(LoRaMacRegion_t region, ApplyCFListParams_t *applyCFList); - /*! + /*! * \brief Sets a channels mask. * * \param [IN] region LoRaWAN region. @@ -1238,9 +1238,9 @@ extern "C" * * \retval Returns true, if the channels mask could be set. */ - bool RegionChanMaskSet(LoRaMacRegion_t region, ChanMaskSetParams_t *chanMaskSet); + bool RegionChanMaskSet(LoRaMacRegion_t region, ChanMaskSetParams_t *chanMaskSet); - /*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] region LoRaWAN region. @@ -1255,9 +1255,9 @@ extern "C" * * \retval Returns true, if an ADR request should be performed. */ - bool RegionAdrNext(LoRaMacRegion_t region, AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); + bool RegionAdrNext(LoRaMacRegion_t region, AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); - /*! + /*! * \brief Configuration of the RX windows. * * \param [IN] region LoRaWAN region. @@ -1268,9 +1268,9 @@ extern "C" * * \retval Returns true, if the configuration was applied successfully. */ - bool RegionRxConfig(LoRaMacRegion_t region, RxConfigParams_t *rxConfig, int8_t *datarate); + bool RegionRxConfig(LoRaMacRegion_t region, RxConfigParams_t *rxConfig, int8_t *datarate); - /* + /* * Rx window precise timing * * For more details please consult the following document, chapter 3.1.2. @@ -1308,7 +1308,7 @@ extern "C" * * Minimal value of RxWindowTimeout must be 5 symbols which implies that the system always tolerates at least an error of 1.5 * tSymbol */ - /*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] region LoRaWAN region. @@ -1323,9 +1323,9 @@ extern "C" * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ - void RegionComputeRxWindowParameters(LoRaMacRegion_t region, int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); + void RegionComputeRxWindowParameters(LoRaMacRegion_t region, int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); - /*! + /*! * \brief TX configuration. * * \param [IN] region LoRaWAN region. @@ -1338,9 +1338,9 @@ extern "C" * * \retval Returns true, if the configuration was applied successfully. */ - bool RegionTxConfig(LoRaMacRegion_t region, TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); + bool RegionTxConfig(LoRaMacRegion_t region, TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); - /*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] region LoRaWAN region. @@ -1357,9 +1357,9 @@ extern "C" * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ - uint8_t RegionLinkAdrReq(LoRaMacRegion_t region, LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); + uint8_t RegionLinkAdrReq(LoRaMacRegion_t region, LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); - /*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] region LoRaWAN region. @@ -1368,9 +1368,9 @@ extern "C" * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ - uint8_t RegionRxParamSetupReq(LoRaMacRegion_t region, RxParamSetupReqParams_t *rxParamSetupReq); + uint8_t RegionRxParamSetupReq(LoRaMacRegion_t region, RxParamSetupReqParams_t *rxParamSetupReq); - /*! + /*! * \brief The function processes a New Channel Request. * * \param [IN] region LoRaWAN region. @@ -1379,9 +1379,9 @@ extern "C" * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ - uint8_t RegionNewChannelReq(LoRaMacRegion_t region, NewChannelReqParams_t *newChannelReq); + uint8_t RegionNewChannelReq(LoRaMacRegion_t region, NewChannelReqParams_t *newChannelReq); - /*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] region LoRaWAN region. @@ -1392,9 +1392,9 @@ extern "C" * Returns -1, if the functionality is not implemented. In this case, the end node * shall ignore the command. */ - int8_t RegionTxParamSetupReq(LoRaMacRegion_t region, TxParamSetupReqParams_t *txParamSetupReq); + int8_t RegionTxParamSetupReq(LoRaMacRegion_t region, TxParamSetupReqParams_t *txParamSetupReq); - /*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] region LoRaWAN region. @@ -1403,9 +1403,9 @@ extern "C" * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ - uint8_t RegionDlChannelReq(LoRaMacRegion_t region, DlChannelReqParams_t *dlChannelReq); + uint8_t RegionDlChannelReq(LoRaMacRegion_t region, DlChannelReqParams_t *dlChannelReq); - /*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] region LoRaWAN region. @@ -1414,18 +1414,18 @@ extern "C" * * \retval Datarate to apply. */ - int8_t RegionAlternateDr(LoRaMacRegion_t region, AlternateDrParams_t *alternateDr); + int8_t RegionAlternateDr(LoRaMacRegion_t region, AlternateDrParams_t *alternateDr); - /*! + /*! * \brief Calculates the back-off time. * * \param [IN] region LoRaWAN region. * * \param [IN] calcBackOff Pointer to the function parameters. */ - void RegionCalcBackOff(LoRaMacRegion_t region, CalcBackOffParams_t *calcBackOff); + void RegionCalcBackOff(LoRaMacRegion_t region, CalcBackOffParams_t *calcBackOff); - /*! + /*! * \brief Searches and set the next random available channel * * \param [IN] region LoRaWAN region. @@ -1439,9 +1439,9 @@ extern "C" * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]. */ - bool RegionNextChannel(LoRaMacRegion_t region, NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); + bool RegionNextChannel(LoRaMacRegion_t region, NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); - /*! + /*! * \brief Adds a channel. * * \param [IN] region LoRaWAN region. @@ -1450,9 +1450,9 @@ extern "C" * * \retval Status of the operation. */ - LoRaMacStatus_t RegionChannelAdd(LoRaMacRegion_t region, ChannelAddParams_t *channelAdd); + LoRaMacStatus_t RegionChannelAdd(LoRaMacRegion_t region, ChannelAddParams_t *channelAdd); - /*! + /*! * \brief Removes a channel. * * \param [IN] region LoRaWAN region. @@ -1461,18 +1461,18 @@ extern "C" * * \retval Returns true, if the channel was removed successfully. */ - bool RegionChannelsRemove(LoRaMacRegion_t region, ChannelRemoveParams_t *channelRemove); + bool RegionChannelsRemove(LoRaMacRegion_t region, ChannelRemoveParams_t *channelRemove); - /*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] region LoRaWAN region. * * \param [IN] continuousWave Pointer to the function parameters. */ - void RegionSetContinuousWave(LoRaMacRegion_t region, ContinuousWaveParams_t *continuousWave); + void RegionSetContinuousWave(LoRaMacRegion_t region, ContinuousWaveParams_t *continuousWave); - /*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -1483,8 +1483,8 @@ extern "C" * * \retval newDr Computed datarate. */ - uint8_t RegionApplyDrOffset(LoRaMacRegion_t region, uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); + uint8_t RegionApplyDrOffset(LoRaMacRegion_t region, uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); - /*! \} defgroup REGION */ + /*! \} defgroup REGION */ }; #endif // __REGION_H__ diff --git a/src/mac/region/RegionAS923.cpp b/src/mac/region/RegionAS923.cpp index f14240a..cd0e242 100644 --- a/src/mac/region/RegionAS923.cpp +++ b/src/mac/region/RegionAS923.cpp @@ -37,1069 +37,1069 @@ extern "C" // Definitions #define CHANNELS_MASK_SIZE 1 - // Global attributes - /*! + // Global attributes + /*! * LoRaMAC channels */ - static ChannelParams_t Channels[AS923_MAX_NB_CHANNELS]; + static ChannelParams_t Channels[AS923_MAX_NB_CHANNELS]; - /*! + /*! * LoRaMac bands */ - static Band_t Bands[AS923_MAX_NB_BANDS] = - { - AS923_BAND0}; + static Band_t Bands[AS923_MAX_NB_BANDS] = + { + AS923_BAND0}; - /*! + /*! * LoRaMac channels mask */ - static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; + static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; - /*! + /*! * LoRaMac channels default mask */ - static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; - - // Static functions - static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) - { - uint8_t nextLowerDr = 0; - - if (dr == minDr) - { - nextLowerDr = minDr; - } - else - { - nextLowerDr = dr - 1; - } - return nextLowerDr; - } - - static uint32_t GetBandwidth(uint32_t drIndex) - { - switch (BandwidthsAS923[drIndex]) - { - default: - case 125000: - return 0; - case 250000: - return 1; - case 500000: - return 2; - } - } - - static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) - { - int8_t txPowerResult = txPower; - - // Limit tx power to the band max - txPowerResult = MAX(txPower, maxBandTxPower); - - return txPowerResult; - } - - static bool VerifyTxFreq(uint32_t freq) - { - // Check radio driver support - if (Radio.CheckRfFrequency(freq) == false) - { - return false; - } - - if ((freq < 915000000) || (freq > 928000000)) - { - return false; - } - return true; - } - - static uint8_t CountNbOfEnabledChannels(bool joined, uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTransmission = 0; - - for (uint8_t i = 0, k = 0; i < AS923_MAX_NB_CHANNELS; i += 16, k++) - { - for (uint8_t j = 0; j < 16; j++) - { - if ((channelsMask[k] & (1 << j)) != 0) - { - if (channels[i + j].Frequency == 0) - { // Check if the channel is enabled - continue; - } - if (joined == false) - { - if ((AS923_JOIN_CHANNELS & (1 << j)) == 0) - { - continue; - } - } - if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, - channels[i + j].DrRange.Fields.Max) == false) - { // Check if the current channel selection supports the given datarate - continue; - } - if (bands[channels[i + j].Band].TimeOff > 0) - { // Check if the band is available for transmission - delayTransmission++; - continue; - } - enabledChannels[nbEnabledChannels++] = i + j; - } - } - } - - *delayTx = delayTransmission; - return nbEnabledChannels; - } - - PhyParam_t RegionAS923GetPhyParam(GetPhyParams_t *getPhy) - { - PhyParam_t phyParam = {0}; - - switch (getPhy->Attribute) - { - case PHY_MIN_RX_DR: - { - if (getPhy->DownlinkDwellTime == 0) - { - phyParam.Value = AS923_RX_MIN_DATARATE; - } - else - { - phyParam.Value = AS923_DWELL_LIMIT_DATARATE; - } - break; - } - case PHY_MIN_TX_DR: - { - if (getPhy->UplinkDwellTime == 0) - { - phyParam.Value = AS923_TX_MIN_DATARATE; - } - else - { - phyParam.Value = AS923_DWELL_LIMIT_DATARATE; - } - break; - } - case PHY_DEF_TX_DR: - { - phyParam.Value = AS923_DEFAULT_DATARATE; - break; - } - case PHY_NEXT_LOWER_TX_DR: - { - if (getPhy->UplinkDwellTime == 0) - { - phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, AS923_TX_MIN_DATARATE); - } - else - { - phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, AS923_DWELL_LIMIT_DATARATE); - } - break; - } - case PHY_DEF_TX_POWER: - { - phyParam.Value = AS923_DEFAULT_TX_POWER; - break; - } - case PHY_MAX_PAYLOAD: - { - if (getPhy->UplinkDwellTime == 0) - { - phyParam.Value = MaxPayloadOfDatarateDwell0AS923[getPhy->Datarate]; - } - else - { - phyParam.Value = MaxPayloadOfDatarateDwell1UpAS923[getPhy->Datarate]; - } - break; - } - case PHY_MAX_PAYLOAD_REPEATER: - { - if (getPhy->UplinkDwellTime == 0) - { - phyParam.Value = MaxPayloadOfDatarateRepeaterDwell0AS923[getPhy->Datarate]; - } - else - { - phyParam.Value = MaxPayloadOfDatarateDwell1UpAS923[getPhy->Datarate]; - } - break; - } - case PHY_DUTY_CYCLE: - { - phyParam.Value = AS923_DUTY_CYCLE_ENABLED; - break; - } - case PHY_MAX_RX_WINDOW: - { - phyParam.Value = AS923_MAX_RX_WINDOW; - break; - } - case PHY_RECEIVE_DELAY1: - { - phyParam.Value = AS923_RECEIVE_DELAY1; - break; - } - case PHY_RECEIVE_DELAY2: - { - phyParam.Value = AS923_RECEIVE_DELAY2; - break; - } - case PHY_JOIN_ACCEPT_DELAY1: - { - phyParam.Value = AS923_JOIN_ACCEPT_DELAY1; - break; - } - case PHY_JOIN_ACCEPT_DELAY2: - { - phyParam.Value = AS923_JOIN_ACCEPT_DELAY2; - break; - } - case PHY_MAX_FCNT_GAP: - { - phyParam.Value = AS923_MAX_FCNT_GAP; - break; - } - case PHY_ACK_TIMEOUT: - { - phyParam.Value = (AS923_ACKTIMEOUT + randr(-AS923_ACK_TIMEOUT_RND, AS923_ACK_TIMEOUT_RND)); - break; - } - case PHY_DEF_DR1_OFFSET: - { - phyParam.Value = AS923_DEFAULT_RX1_DR_OFFSET; - break; - } - case PHY_DEF_RX2_FREQUENCY: - { - phyParam.Value = AS923_RX_WND_2_FREQ; - break; - } - case PHY_DEF_RX2_DR: - { - phyParam.Value = AS923_RX_WND_2_DR; - break; - } - case PHY_CHANNELS_MASK: - { - phyParam.ChannelsMask = ChannelsMask; - break; - } - case PHY_CHANNELS_DEFAULT_MASK: - { - phyParam.ChannelsMask = ChannelsDefaultMask; - break; - } - case PHY_MAX_NB_CHANNELS: - { - phyParam.Value = AS923_MAX_NB_CHANNELS; - break; - } - case PHY_CHANNELS: - { - phyParam.Channels = Channels; - break; - } - case PHY_DEF_UPLINK_DWELL_TIME: - { - phyParam.Value = AS923_DEFAULT_UPLINK_DWELL_TIME; - break; - } - case PHY_DEF_DOWNLINK_DWELL_TIME: - { - phyParam.Value = AS923_DEFAULT_DOWNLINK_DWELL_TIME; - break; - } - case PHY_DEF_MAX_EIRP: - { - phyParam.fValue = AS923_DEFAULT_MAX_EIRP; - break; - } - case PHY_DEF_ANTENNA_GAIN: - { - phyParam.fValue = AS923_DEFAULT_ANTENNA_GAIN; - break; - } - case PHY_NB_JOIN_TRIALS: - case PHY_DEF_NB_JOIN_TRIALS: - { - phyParam.Value = 1; - break; - } - default: - { - break; - } - } - - return phyParam; - } - - void RegionAS923SetBandTxDone(SetBandTxDoneParams_t *txDone) - { - RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); - } - - void RegionAS923InitDefaults(InitType_t type) - { - switch (type) - { - case INIT_TYPE_INIT: - { - // Channels - Channels[0] = (ChannelParams_t)AS923_LC1; - Channels[1] = (ChannelParams_t)AS923_LC2; - - // Initialize the channels default mask - ChannelsDefaultMask[0] = LC(1) + LC(2); - // Update the channels mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); - break; - } - case INIT_TYPE_RESTORE: - { - // Restore channels default mask - ChannelsMask[0] |= ChannelsDefaultMask[0]; - break; - } - case INIT_TYPE_APP_DEFAULTS: - { - // Update the channels mask defaults - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); - break; - } - default: - { - break; - } - } - } - - bool RegionAS923Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) - { - switch (phyAttribute) - { - case PHY_TX_DR: - { - if (verify->DatarateParams.UplinkDwellTime == 0) - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, AS923_TX_MIN_DATARATE, AS923_TX_MAX_DATARATE); - } - else - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, AS923_DWELL_LIMIT_DATARATE, AS923_TX_MAX_DATARATE); - } - } - case PHY_DEF_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); - } - case PHY_RX_DR: - { - if (verify->DatarateParams.DownlinkDwellTime == 0) - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, AS923_RX_MIN_DATARATE, AS923_RX_MAX_DATARATE); - } - else - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, AS923_DWELL_LIMIT_DATARATE, AS923_RX_MAX_DATARATE); - } - } - case PHY_DEF_TX_POWER: - case PHY_TX_POWER: - { - // Remark: switched min and max! - return RegionCommonValueInRange(verify->TxPower, AS923_MAX_TX_POWER, AS923_MIN_TX_POWER); - } - case PHY_DUTY_CYCLE: - { - return AS923_DUTY_CYCLE_ENABLED; - } - case PHY_NB_JOIN_TRIALS: - { - return true; - } - default: - return false; - } - } - - void RegionAS923ApplyCFList(ApplyCFListParams_t *applyCFList) - { - ChannelParams_t newChannel; - ChannelAddParams_t channelAdd; - ChannelRemoveParams_t channelRemove; - - // Setup default datarate range - newChannel.DrRange.Value = (DR_5 << 4) | DR_0; - - // Size of the optional CF list - if (applyCFList->Size != 16) - { - return; - } - - // Last byte is RFU, don't take it into account - for (uint8_t i = 0, chanIdx = AS923_NUMB_DEFAULT_CHANNELS; chanIdx < AS923_MAX_NB_CHANNELS; i += 3, chanIdx++) - { - if (chanIdx < (AS923_NUMB_CHANNELS_CF_LIST + AS923_NUMB_DEFAULT_CHANNELS)) - { - // Channel frequency - newChannel.Frequency = (uint32_t)applyCFList->Payload[i]; - newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 1] << 8); - newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 2] << 16); - newChannel.Frequency *= 100; - - // Initialize alternative frequency to 0 - newChannel.Rx1Frequency = 0; - } - else - { - newChannel.Frequency = 0; - newChannel.DrRange.Value = 0; - newChannel.Rx1Frequency = 0; - } - - if (newChannel.Frequency != 0) - { - channelAdd.NewChannel = &newChannel; - channelAdd.ChannelId = chanIdx; - - // Try to add all channels - RegionAS923ChannelAdd(&channelAdd); - } - else - { - channelRemove.ChannelId = chanIdx; - - RegionAS923ChannelsRemove(&channelRemove); - } - } - } - - bool RegionAS923ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) - { - switch (chanMaskSet->ChannelsMaskType) - { - case CHANNELS_MASK: - { - RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 1); - break; - } - case CHANNELS_DEFAULT_MASK: - { - RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1); - break; - } - default: - return false; - } - return true; - } - - bool RegionAS923AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) - { - bool adrAckReq = false; - int8_t datarate = adrNext->Datarate; - int8_t minTxDatarate = 0; - int8_t txPower = adrNext->TxPower; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - - // Get the minimum possible datarate - getPhy.Attribute = PHY_MIN_TX_DR; - getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; - phyParam = RegionAS923GetPhyParam(&getPhy); - minTxDatarate = phyParam.Value; - - // Report back the adr ack counter - *adrAckCounter = adrNext->AdrAckCounter; - - // Apply the minimum possible datarate. - datarate = MAX(datarate, minTxDatarate); - - if (adrNext->AdrEnabled == true) - { - if (datarate == minTxDatarate) - { - *adrAckCounter = 0; - adrAckReq = false; - } - else - { - if (adrNext->AdrAckCounter >= AS923_ADR_ACK_LIMIT) - { - adrAckReq = true; - txPower = AS923_MAX_TX_POWER; - } - else - { - adrAckReq = false; - } - if (adrNext->AdrAckCounter >= (AS923_ADR_ACK_LIMIT + AS923_ADR_ACK_DELAY)) - { - if ((adrNext->AdrAckCounter % AS923_ADR_ACK_DELAY) == 1) - { - // Decrease the datarate - getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; - getPhy.Datarate = datarate; - getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; - phyParam = RegionAS923GetPhyParam(&getPhy); - datarate = phyParam.Value; - - if (datarate == minTxDatarate) - { - // We must set adrAckReq to false as soon as we reach the lowest datarate - adrAckReq = false; - if (adrNext->UpdateChanMask == true) - { - // Re-enable default channels - ChannelsMask[0] |= LC(1) + LC(2); - } - } - } - } - } - } - - *drOut = datarate; - *txPowOut = txPower; - return adrAckReq; - } - - void RegionAS923ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) - { - double tSymbol = 0.0; - - // Get the datarate, perform a boundary check - rxConfigParams->Datarate = MIN(datarate, AS923_RX_MAX_DATARATE); - rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); - - if (rxConfigParams->Datarate == DR_7) - { // FSK - tSymbol = RegionCommonComputeSymbolTimeFsk(DataratesAS923[rxConfigParams->Datarate]); - } - else - { // LoRa - tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesAS923[rxConfigParams->Datarate], BandwidthsAS923[rxConfigParams->Datarate]); - } - - RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); - } - - bool RegionAS923RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) - { - RadioModems_t modem; - int8_t dr = rxConfig->Datarate; - uint8_t maxPayload = 0; - int8_t phyDr = 0; - uint32_t frequency = rxConfig->Frequency; - - if (Radio.GetStatus() != RF_IDLE) - { - return false; - } - - if (rxConfig->Window == 0) - { - // Apply window 1 frequency - frequency = Channels[rxConfig->Channel].Frequency; - // Apply the alternative RX 1 window frequency, if it is available - if (Channels[rxConfig->Channel].Rx1Frequency != 0) - { - frequency = Channels[rxConfig->Channel].Rx1Frequency; - } - } - - // Read the physical datarate from the datarates table - phyDr = DataratesAS923[dr]; - - Radio.SetChannel(frequency); - - // Radio configuration - if (dr == DR_7) - { - modem = MODEM_FSK; - Radio.SetRxConfig(modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous); - } - else - { - modem = MODEM_LORA; - Radio.SetRxConfig(modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); - } - - // Check for repeater support - if (rxConfig->RepeaterSupport == true) - { - maxPayload = MaxPayloadOfDatarateRepeaterDwell0AS923[dr]; - } - else - { - maxPayload = MaxPayloadOfDatarateDwell0AS923[dr]; - } - - Radio.SetMaxPayloadLength(modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - *datarate = (uint8_t)dr; - return true; - } - - bool RegionAS923TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) - { - RadioModems_t modem; - int8_t phyDr = DataratesAS923[txConfig->Datarate]; - int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); - uint32_t bandwidth = GetBandwidth(txConfig->Datarate); - int8_t phyTxPower = 0; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); - - // Setup the radio frequency - Radio.SetChannel(Channels[txConfig->Channel].Frequency); - - if (txConfig->Datarate == DR_7) - { // High Speed FSK channel - modem = MODEM_FSK; - Radio.SetTxConfig(modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000); - } - else - { - modem = MODEM_LORA; - Radio.SetTxConfig(modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); - } - - // Setup maximum payload lenght of the radio driver - Radio.SetMaxPayloadLength(modem, txConfig->PktLen); - // Get the time-on-air of the next tx frame - *txTimeOnAir = Radio.TimeOnAir(modem, txConfig->PktLen); - - *txPower = txPowerLimited; - return true; - } - - uint8_t RegionAS923LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) - { - uint8_t status = 0x07; - RegionCommonLinkAdrParams_t linkAdrParams; - uint8_t nextIndex = 0; - uint8_t bytesProcessed = 0; - uint16_t chMask = 0; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; - - while (bytesProcessed < linkAdrReq->PayloadSize) - { - // Get ADR request parameters - nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); - - if (nextIndex == 0) - break; // break loop, since no more request has been found - - // Update bytes processed - bytesProcessed += nextIndex; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - // Setup temporary channels mask - chMask = linkAdrParams.ChMask; - - // Verify channels mask - if ((linkAdrParams.ChMaskCtrl == 0) && (chMask == 0)) - { - status &= 0xFE; // Channel mask KO - } - else if (((linkAdrParams.ChMaskCtrl >= 1) && (linkAdrParams.ChMaskCtrl <= 5)) || - (linkAdrParams.ChMaskCtrl >= 7)) - { - // RFU - status &= 0xFE; // Channel mask KO - } - else - { - for (uint8_t i = 0; i < AS923_MAX_NB_CHANNELS; i++) - { - if (linkAdrParams.ChMaskCtrl == 6) - { - if (Channels[i].Frequency != 0) - { - chMask |= 1 << i; - } - } - else - { - if (((chMask & (1 << i)) != 0) && - (Channels[i].Frequency == 0)) - { // Trying to enable an undefined channel - status &= 0xFE; // Channel mask KO - } - } - } - } - } - - // Get the minimum possible datarate - getPhy.Attribute = PHY_MIN_TX_DR; - getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; - phyParam = RegionAS923GetPhyParam(&getPhy); - - linkAdrVerifyParams.Status = status; - linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; - linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; - linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; - linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; - linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; - linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; - linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; - linkAdrVerifyParams.NbChannels = AS923_MAX_NB_CHANNELS; - linkAdrVerifyParams.ChannelsMask = &chMask; - linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; - linkAdrVerifyParams.MaxDatarate = AS923_TX_MAX_DATARATE; - linkAdrVerifyParams.Channels = Channels; - linkAdrVerifyParams.MinTxPower = AS923_MIN_TX_POWER; - linkAdrVerifyParams.MaxTxPower = AS923_MAX_TX_POWER; - - // Verify the parameters and update, if necessary - status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); - - // Update channelsMask if everything is correct - if (status == 0x07) - { - // Set the channels mask to a default value - memset(ChannelsMask, 0, sizeof(ChannelsMask)); - // Update the channels mask - ChannelsMask[0] = chMask; - } - - // Update status variables - *drOut = linkAdrParams.Datarate; - *txPowOut = linkAdrParams.TxPower; - *nbRepOut = linkAdrParams.NbRep; - *nbBytesParsed = bytesProcessed; - - return status; - } - - uint8_t RegionAS923RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) - { - uint8_t status = 0x07; - - // Verify radio frequency - if (Radio.CheckRfFrequency(rxParamSetupReq->Frequency) == false) - { - status &= 0xFE; // Channel frequency KO - } - - // Verify datarate - if (RegionCommonValueInRange(rxParamSetupReq->Datarate, AS923_RX_MIN_DATARATE, AS923_RX_MAX_DATARATE) == false) - { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, AS923_MIN_RX1_DR_OFFSET, AS923_MAX_RX1_DR_OFFSET) == false) - { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; - } - - uint8_t RegionAS923NewChannelReq(NewChannelReqParams_t *newChannelReq) - { - uint8_t status = 0x03; - ChannelAddParams_t channelAdd; - ChannelRemoveParams_t channelRemove; - - if (newChannelReq->NewChannel->Frequency == 0) - { - channelRemove.ChannelId = newChannelReq->ChannelId; - - // Remove - if (RegionAS923ChannelsRemove(&channelRemove) == false) - { - status &= 0xFC; - } - } - else - { - channelAdd.NewChannel = newChannelReq->NewChannel; - channelAdd.ChannelId = newChannelReq->ChannelId; - - switch (RegionAS923ChannelAdd(&channelAdd)) - { - case LORAMAC_STATUS_OK: - { - break; - } - case LORAMAC_STATUS_FREQUENCY_INVALID: - { - status &= 0xFE; - break; - } - case LORAMAC_STATUS_DATARATE_INVALID: - { - status &= 0xFD; - break; - } - case LORAMAC_STATUS_FREQ_AND_DR_INVALID: - { - status &= 0xFC; - break; - } - default: - { - status &= 0xFC; - break; - } - } - } - - return status; - } - - int8_t RegionAS923TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) - { - // Accept the request - return 0; - } - - uint8_t RegionAS923DlChannelReq(DlChannelReqParams_t *dlChannelReq) - { - uint8_t status = 0x03; - - // Verify if the frequency is supported - if (VerifyTxFreq(dlChannelReq->Rx1Frequency) == false) - { - status &= 0xFE; - } - - // Verify if an uplink frequency exists - if (Channels[dlChannelReq->ChannelId].Frequency == 0) - { - status &= 0xFD; - } - - // Apply Rx1 frequency, if the status is OK - if (status == 0x03) - { - Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency; - } - - return status; - } - - int8_t RegionAS923AlternateDr(AlternateDrParams_t *alternateDr) - { - // Only AS923_DWELL_LIMIT_DATARATE is supported - return AS923_DWELL_LIMIT_DATARATE; - } - - void RegionAS923CalcBackOff(CalcBackOffParams_t *calcBackOff) - { - RegionCommonCalcBackOffParams_t calcBackOffParams; - - calcBackOffParams.Channels = Channels; - calcBackOffParams.Bands = Bands; - calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; - calcBackOffParams.Joined = calcBackOff->Joined; - calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; - calcBackOffParams.Channel = calcBackOff->Channel; - calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; - calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; - - RegionCommonCalcBackOff(&calcBackOffParams); - } - - bool RegionAS923NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) - { - uint8_t channelNext = 0; - uint8_t nbEnabledChannels = 0; - uint8_t delayTx = 0; - uint8_t enabledChannels[AS923_MAX_NB_CHANNELS] = {0}; - TimerTime_t nextTxDelay = 0; - - if (RegionCommonCountChannels(ChannelsMask, 0, 1) == 0) - { // Reactivate default channels - ChannelsMask[0] |= LC(1) + LC(2); - } - - if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) - { - // Reset Aggregated time off - *aggregatedTimeOff = 0; - - // Update bands Time OFF - nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, AS923_MAX_NB_BANDS); - - // Search how many channels are enabled - nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Joined, nextChanParams->Datarate, - ChannelsMask, Channels, - Bands, enabledChannels, &delayTx); - } - else - { - delayTx++; - nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); - } - - if (nbEnabledChannels > 0) - { - for (uint8_t i = 0, j = randr(0, nbEnabledChannels - 1); i < AS923_MAX_NB_CHANNELS; i++) - { - channelNext = enabledChannels[j]; - j = (j + 1) % nbEnabledChannels; - - // Perform carrier sense for AS923_CARRIER_SENSE_TIME - // If the channel is free, we can stop the LBT mechanism - if (Radio.IsChannelFree(MODEM_LORA, Channels[channelNext].Frequency, AS923_RSSI_FREE_TH, AS923_CARRIER_SENSE_TIME) == true) - { - // Free channel found - *channel = channelNext; - *time = 0; - return true; - } - } - return false; - } - else - { - if (delayTx > 0) - { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = nextTxDelay; - return true; - } - // Datarate not supported by any channel, restore defaults - ChannelsMask[0] |= LC(1) + LC(2); - *time = 0; - return false; - } - } - - LoRaMacStatus_t RegionAS923ChannelAdd(ChannelAddParams_t *channelAdd) - { - uint8_t band = 0; - bool drInvalid = false; - bool freqInvalid = false; - uint8_t id = channelAdd->ChannelId; - - if (id >= AS923_MAX_NB_CHANNELS) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - // Validate the datarate range - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Min, AS923_TX_MIN_DATARATE, AS923_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, AS923_TX_MIN_DATARATE, AS923_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - if (channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max) - { - drInvalid = true; - } - - // Default channels don't accept all values - if (id < AS923_NUMB_DEFAULT_CHANNELS) - { - // Validate the datarate range for min: must be DR_0 - if (channelAdd->NewChannel->DrRange.Fields.Min > DR_0) - { - drInvalid = true; - } - // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, DR_5, AS923_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - // We are not allowed to change the frequency - if (channelAdd->NewChannel->Frequency != Channels[id].Frequency) - { - freqInvalid = true; - } - } - - // Check frequency - if (freqInvalid == false) - { - if (VerifyTxFreq(channelAdd->NewChannel->Frequency) == false) - { - freqInvalid = true; - } - } - - // Check status - if ((drInvalid == true) && (freqInvalid == true)) - { - return LORAMAC_STATUS_FREQ_AND_DR_INVALID; - } - if (drInvalid == true) - { - return LORAMAC_STATUS_DATARATE_INVALID; - } - if (freqInvalid == true) - { - return LORAMAC_STATUS_FREQUENCY_INVALID; - } - - memcpy(&(Channels[id]), channelAdd->NewChannel, sizeof(Channels[id])); - Channels[id].Band = band; - ChannelsMask[0] |= (1 << id); - return LORAMAC_STATUS_OK; - } - - bool RegionAS923ChannelsRemove(ChannelRemoveParams_t *channelRemove) - { - uint8_t id = channelRemove->ChannelId; - - if (id < AS923_NUMB_DEFAULT_CHANNELS) - { - return false; - } - - // Remove the channel from the list of channels - Channels[id] = (ChannelParams_t){0, 0, {0}, 0}; - - return RegionCommonChanDisable(ChannelsMask, id, AS923_MAX_NB_CHANNELS); - } - - void RegionAS923SetContinuousWave(ContinuousWaveParams_t *continuousWave) - { - int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); - int8_t phyTxPower = 0; - uint32_t frequency = Channels[continuousWave->Channel].Frequency; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); - - Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); - } - - uint8_t RegionAS923ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) - { - // Initialize minDr for a downlink dwell time configuration of 0 - int8_t minDr = DR_0; - - // Update the minDR for a downlink dwell time configuration of 1 - if (downlinkDwellTime == 1) - { - minDr = AS923_DWELL_LIMIT_DATARATE; - } - - // Apply offset formula - return MIN(DR_5, MAX(minDr, dr - EffectiveRx1DrOffsetAS923[drOffset])); - } + static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; + + // Static functions + static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) + { + uint8_t nextLowerDr = 0; + + if (dr == minDr) + { + nextLowerDr = minDr; + } + else + { + nextLowerDr = dr - 1; + } + return nextLowerDr; + } + + static uint32_t GetBandwidth(uint32_t drIndex) + { + switch (BandwidthsAS923[drIndex]) + { + default: + case 125000: + return 0; + case 250000: + return 1; + case 500000: + return 2; + } + } + + static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) + { + int8_t txPowerResult = txPower; + + // Limit tx power to the band max + txPowerResult = MAX(txPower, maxBandTxPower); + + return txPowerResult; + } + + static bool VerifyTxFreq(uint32_t freq) + { + // Check radio driver support + if (Radio.CheckRfFrequency(freq) == false) + { + return false; + } + + if ((freq < 915000000) || (freq > 928000000)) + { + return false; + } + return true; + } + + static uint8_t CountNbOfEnabledChannels(bool joined, uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTransmission = 0; + + for (uint8_t i = 0, k = 0; i < AS923_MAX_NB_CHANNELS; i += 16, k++) + { + for (uint8_t j = 0; j < 16; j++) + { + if ((channelsMask[k] & (1 << j)) != 0) + { + if (channels[i + j].Frequency == 0) + { // Check if the channel is enabled + continue; + } + if (joined == false) + { + if ((AS923_JOIN_CHANNELS & (1 << j)) == 0) + { + continue; + } + } + if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, + channels[i + j].DrRange.Fields.Max) == false) + { // Check if the current channel selection supports the given datarate + continue; + } + if (bands[channels[i + j].Band].TimeOff > 0) + { // Check if the band is available for transmission + delayTransmission++; + continue; + } + enabledChannels[nbEnabledChannels++] = i + j; + } + } + } + + *delayTx = delayTransmission; + return nbEnabledChannels; + } + + PhyParam_t RegionAS923GetPhyParam(GetPhyParams_t *getPhy) + { + PhyParam_t phyParam = {0}; + + switch (getPhy->Attribute) + { + case PHY_MIN_RX_DR: + { + if (getPhy->DownlinkDwellTime == 0) + { + phyParam.Value = AS923_RX_MIN_DATARATE; + } + else + { + phyParam.Value = AS923_DWELL_LIMIT_DATARATE; + } + break; + } + case PHY_MIN_TX_DR: + { + if (getPhy->UplinkDwellTime == 0) + { + phyParam.Value = AS923_TX_MIN_DATARATE; + } + else + { + phyParam.Value = AS923_DWELL_LIMIT_DATARATE; + } + break; + } + case PHY_DEF_TX_DR: + { + phyParam.Value = AS923_DEFAULT_DATARATE; + break; + } + case PHY_NEXT_LOWER_TX_DR: + { + if (getPhy->UplinkDwellTime == 0) + { + phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, AS923_TX_MIN_DATARATE); + } + else + { + phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, AS923_DWELL_LIMIT_DATARATE); + } + break; + } + case PHY_DEF_TX_POWER: + { + phyParam.Value = AS923_DEFAULT_TX_POWER; + break; + } + case PHY_MAX_PAYLOAD: + { + if (getPhy->UplinkDwellTime == 0) + { + phyParam.Value = MaxPayloadOfDatarateDwell0AS923[getPhy->Datarate]; + } + else + { + phyParam.Value = MaxPayloadOfDatarateDwell1UpAS923[getPhy->Datarate]; + } + break; + } + case PHY_MAX_PAYLOAD_REPEATER: + { + if (getPhy->UplinkDwellTime == 0) + { + phyParam.Value = MaxPayloadOfDatarateRepeaterDwell0AS923[getPhy->Datarate]; + } + else + { + phyParam.Value = MaxPayloadOfDatarateDwell1UpAS923[getPhy->Datarate]; + } + break; + } + case PHY_DUTY_CYCLE: + { + phyParam.Value = AS923_DUTY_CYCLE_ENABLED; + break; + } + case PHY_MAX_RX_WINDOW: + { + phyParam.Value = AS923_MAX_RX_WINDOW; + break; + } + case PHY_RECEIVE_DELAY1: + { + phyParam.Value = AS923_RECEIVE_DELAY1; + break; + } + case PHY_RECEIVE_DELAY2: + { + phyParam.Value = AS923_RECEIVE_DELAY2; + break; + } + case PHY_JOIN_ACCEPT_DELAY1: + { + phyParam.Value = AS923_JOIN_ACCEPT_DELAY1; + break; + } + case PHY_JOIN_ACCEPT_DELAY2: + { + phyParam.Value = AS923_JOIN_ACCEPT_DELAY2; + break; + } + case PHY_MAX_FCNT_GAP: + { + phyParam.Value = AS923_MAX_FCNT_GAP; + break; + } + case PHY_ACK_TIMEOUT: + { + phyParam.Value = (AS923_ACKTIMEOUT + randr(-AS923_ACK_TIMEOUT_RND, AS923_ACK_TIMEOUT_RND)); + break; + } + case PHY_DEF_DR1_OFFSET: + { + phyParam.Value = AS923_DEFAULT_RX1_DR_OFFSET; + break; + } + case PHY_DEF_RX2_FREQUENCY: + { + phyParam.Value = AS923_RX_WND_2_FREQ; + break; + } + case PHY_DEF_RX2_DR: + { + phyParam.Value = AS923_RX_WND_2_DR; + break; + } + case PHY_CHANNELS_MASK: + { + phyParam.ChannelsMask = ChannelsMask; + break; + } + case PHY_CHANNELS_DEFAULT_MASK: + { + phyParam.ChannelsMask = ChannelsDefaultMask; + break; + } + case PHY_MAX_NB_CHANNELS: + { + phyParam.Value = AS923_MAX_NB_CHANNELS; + break; + } + case PHY_CHANNELS: + { + phyParam.Channels = Channels; + break; + } + case PHY_DEF_UPLINK_DWELL_TIME: + { + phyParam.Value = AS923_DEFAULT_UPLINK_DWELL_TIME; + break; + } + case PHY_DEF_DOWNLINK_DWELL_TIME: + { + phyParam.Value = AS923_DEFAULT_DOWNLINK_DWELL_TIME; + break; + } + case PHY_DEF_MAX_EIRP: + { + phyParam.fValue = AS923_DEFAULT_MAX_EIRP; + break; + } + case PHY_DEF_ANTENNA_GAIN: + { + phyParam.fValue = AS923_DEFAULT_ANTENNA_GAIN; + break; + } + case PHY_NB_JOIN_TRIALS: + case PHY_DEF_NB_JOIN_TRIALS: + { + phyParam.Value = 1; + break; + } + default: + { + break; + } + } + + return phyParam; + } + + void RegionAS923SetBandTxDone(SetBandTxDoneParams_t *txDone) + { + RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); + } + + void RegionAS923InitDefaults(InitType_t type) + { + switch (type) + { + case INIT_TYPE_INIT: + { + // Channels + Channels[0] = (ChannelParams_t)AS923_LC1; + Channels[1] = (ChannelParams_t)AS923_LC2; + + // Initialize the channels default mask + ChannelsDefaultMask[0] = LC(1) + LC(2); + // Update the channels mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); + break; + } + case INIT_TYPE_RESTORE: + { + // Restore channels default mask + ChannelsMask[0] |= ChannelsDefaultMask[0]; + break; + } + case INIT_TYPE_APP_DEFAULTS: + { + // Update the channels mask defaults + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); + break; + } + default: + { + break; + } + } + } + + bool RegionAS923Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) + { + switch (phyAttribute) + { + case PHY_TX_DR: + { + if (verify->DatarateParams.UplinkDwellTime == 0) + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, AS923_TX_MIN_DATARATE, AS923_TX_MAX_DATARATE); + } + else + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, AS923_DWELL_LIMIT_DATARATE, AS923_TX_MAX_DATARATE); + } + } + case PHY_DEF_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); + } + case PHY_RX_DR: + { + if (verify->DatarateParams.DownlinkDwellTime == 0) + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, AS923_RX_MIN_DATARATE, AS923_RX_MAX_DATARATE); + } + else + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, AS923_DWELL_LIMIT_DATARATE, AS923_RX_MAX_DATARATE); + } + } + case PHY_DEF_TX_POWER: + case PHY_TX_POWER: + { + // Remark: switched min and max! + return RegionCommonValueInRange(verify->TxPower, AS923_MAX_TX_POWER, AS923_MIN_TX_POWER); + } + case PHY_DUTY_CYCLE: + { + return AS923_DUTY_CYCLE_ENABLED; + } + case PHY_NB_JOIN_TRIALS: + { + return true; + } + default: + return false; + } + } + + void RegionAS923ApplyCFList(ApplyCFListParams_t *applyCFList) + { + ChannelParams_t newChannel; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + // Setup default datarate range + newChannel.DrRange.Value = (DR_5 << 4) | DR_0; + + // Size of the optional CF list + if (applyCFList->Size != 16) + { + return; + } + + // Last byte is RFU, don't take it into account + for (uint8_t i = 0, chanIdx = AS923_NUMB_DEFAULT_CHANNELS; chanIdx < AS923_MAX_NB_CHANNELS; i += 3, chanIdx++) + { + if (chanIdx < (AS923_NUMB_CHANNELS_CF_LIST + AS923_NUMB_DEFAULT_CHANNELS)) + { + // Channel frequency + newChannel.Frequency = (uint32_t)applyCFList->Payload[i]; + newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 1] << 8); + newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 2] << 16); + newChannel.Frequency *= 100; + + // Initialize alternative frequency to 0 + newChannel.Rx1Frequency = 0; + } + else + { + newChannel.Frequency = 0; + newChannel.DrRange.Value = 0; + newChannel.Rx1Frequency = 0; + } + + if (newChannel.Frequency != 0) + { + channelAdd.NewChannel = &newChannel; + channelAdd.ChannelId = chanIdx; + + // Try to add all channels + RegionAS923ChannelAdd(&channelAdd); + } + else + { + channelRemove.ChannelId = chanIdx; + + RegionAS923ChannelsRemove(&channelRemove); + } + } + } + + bool RegionAS923ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) + { + switch (chanMaskSet->ChannelsMaskType) + { + case CHANNELS_MASK: + { + RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 1); + break; + } + case CHANNELS_DEFAULT_MASK: + { + RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1); + break; + } + default: + return false; + } + return true; + } + + bool RegionAS923AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) + { + bool adrAckReq = false; + int8_t datarate = adrNext->Datarate; + int8_t minTxDatarate = 0; + int8_t txPower = adrNext->TxPower; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + + // Get the minimum possible datarate + getPhy.Attribute = PHY_MIN_TX_DR; + getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; + phyParam = RegionAS923GetPhyParam(&getPhy); + minTxDatarate = phyParam.Value; + + // Report back the adr ack counter + *adrAckCounter = adrNext->AdrAckCounter; + + // Apply the minimum possible datarate. + datarate = MAX(datarate, minTxDatarate); + + if (adrNext->AdrEnabled == true) + { + if (datarate == minTxDatarate) + { + *adrAckCounter = 0; + adrAckReq = false; + } + else + { + if (adrNext->AdrAckCounter >= AS923_ADR_ACK_LIMIT) + { + adrAckReq = true; + txPower = AS923_MAX_TX_POWER; + } + else + { + adrAckReq = false; + } + if (adrNext->AdrAckCounter >= (AS923_ADR_ACK_LIMIT + AS923_ADR_ACK_DELAY)) + { + if ((adrNext->AdrAckCounter % AS923_ADR_ACK_DELAY) == 1) + { + // Decrease the datarate + getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; + getPhy.Datarate = datarate; + getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; + phyParam = RegionAS923GetPhyParam(&getPhy); + datarate = phyParam.Value; + + if (datarate == minTxDatarate) + { + // We must set adrAckReq to false as soon as we reach the lowest datarate + adrAckReq = false; + if (adrNext->UpdateChanMask == true) + { + // Re-enable default channels + ChannelsMask[0] |= LC(1) + LC(2); + } + } + } + } + } + } + + *drOut = datarate; + *txPowOut = txPower; + return adrAckReq; + } + + void RegionAS923ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) + { + double tSymbol = 0.0; + + // Get the datarate, perform a boundary check + rxConfigParams->Datarate = MIN(datarate, AS923_RX_MAX_DATARATE); + rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); + + if (rxConfigParams->Datarate == DR_7) + { // FSK + tSymbol = RegionCommonComputeSymbolTimeFsk(DataratesAS923[rxConfigParams->Datarate]); + } + else + { // LoRa + tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesAS923[rxConfigParams->Datarate], BandwidthsAS923[rxConfigParams->Datarate]); + } + + RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); + } + + bool RegionAS923RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) + { + RadioModems_t modem; + int8_t dr = rxConfig->Datarate; + uint8_t maxPayload = 0; + int8_t phyDr = 0; + uint32_t frequency = rxConfig->Frequency; + + if (Radio.GetStatus() != RF_IDLE) + { + return false; + } + + if (rxConfig->Window == 0) + { + // Apply window 1 frequency + frequency = Channels[rxConfig->Channel].Frequency; + // Apply the alternative RX 1 window frequency, if it is available + if (Channels[rxConfig->Channel].Rx1Frequency != 0) + { + frequency = Channels[rxConfig->Channel].Rx1Frequency; + } + } + + // Read the physical datarate from the datarates table + phyDr = DataratesAS923[dr]; + + Radio.SetChannel(frequency); + + // Radio configuration + if (dr == DR_7) + { + modem = MODEM_FSK; + Radio.SetRxConfig(modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous); + } + else + { + modem = MODEM_LORA; + Radio.SetRxConfig(modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); + } + + // Check for repeater support + if (rxConfig->RepeaterSupport == true) + { + maxPayload = MaxPayloadOfDatarateRepeaterDwell0AS923[dr]; + } + else + { + maxPayload = MaxPayloadOfDatarateDwell0AS923[dr]; + } + + Radio.SetMaxPayloadLength(modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + *datarate = (uint8_t)dr; + return true; + } + + bool RegionAS923TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) + { + RadioModems_t modem; + int8_t phyDr = DataratesAS923[txConfig->Datarate]; + int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); + uint32_t bandwidth = GetBandwidth(txConfig->Datarate); + int8_t phyTxPower = 0; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); + + // Setup the radio frequency + Radio.SetChannel(Channels[txConfig->Channel].Frequency); + + if (txConfig->Datarate == DR_7) + { // High Speed FSK channel + modem = MODEM_FSK; + Radio.SetTxConfig(modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000); + } + else + { + modem = MODEM_LORA; + Radio.SetTxConfig(modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); + } + + // Setup maximum payload lenght of the radio driver + Radio.SetMaxPayloadLength(modem, txConfig->PktLen); + // Get the time-on-air of the next tx frame + *txTimeOnAir = Radio.TimeOnAir(modem, txConfig->PktLen); + + *txPower = txPowerLimited; + return true; + } + + uint8_t RegionAS923LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) + { + uint8_t status = 0x07; + RegionCommonLinkAdrParams_t linkAdrParams; + uint8_t nextIndex = 0; + uint8_t bytesProcessed = 0; + uint16_t chMask = 0; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; + + while (bytesProcessed < linkAdrReq->PayloadSize) + { + // Get ADR request parameters + nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); + + if (nextIndex == 0) + break; // break loop, since no more request has been found + + // Update bytes processed + bytesProcessed += nextIndex; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + // Setup temporary channels mask + chMask = linkAdrParams.ChMask; + + // Verify channels mask + if ((linkAdrParams.ChMaskCtrl == 0) && (chMask == 0)) + { + status &= 0xFE; // Channel mask KO + } + else if (((linkAdrParams.ChMaskCtrl >= 1) && (linkAdrParams.ChMaskCtrl <= 5)) || + (linkAdrParams.ChMaskCtrl >= 7)) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + for (uint8_t i = 0; i < AS923_MAX_NB_CHANNELS; i++) + { + if (linkAdrParams.ChMaskCtrl == 6) + { + if (Channels[i].Frequency != 0) + { + chMask |= 1 << i; + } + } + else + { + if (((chMask & (1 << i)) != 0) && + (Channels[i].Frequency == 0)) + { // Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + } + } + } + + // Get the minimum possible datarate + getPhy.Attribute = PHY_MIN_TX_DR; + getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; + phyParam = RegionAS923GetPhyParam(&getPhy); + + linkAdrVerifyParams.Status = status; + linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; + linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; + linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; + linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; + linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; + linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; + linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; + linkAdrVerifyParams.NbChannels = AS923_MAX_NB_CHANNELS; + linkAdrVerifyParams.ChannelsMask = &chMask; + linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; + linkAdrVerifyParams.MaxDatarate = AS923_TX_MAX_DATARATE; + linkAdrVerifyParams.Channels = Channels; + linkAdrVerifyParams.MinTxPower = AS923_MIN_TX_POWER; + linkAdrVerifyParams.MaxTxPower = AS923_MAX_TX_POWER; + + // Verify the parameters and update, if necessary + status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); + + // Update channelsMask if everything is correct + if (status == 0x07) + { + // Set the channels mask to a default value + memset(ChannelsMask, 0, sizeof(ChannelsMask)); + // Update the channels mask + ChannelsMask[0] = chMask; + } + + // Update status variables + *drOut = linkAdrParams.Datarate; + *txPowOut = linkAdrParams.TxPower; + *nbRepOut = linkAdrParams.NbRep; + *nbBytesParsed = bytesProcessed; + + return status; + } + + uint8_t RegionAS923RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) + { + uint8_t status = 0x07; + + // Verify radio frequency + if (Radio.CheckRfFrequency(rxParamSetupReq->Frequency) == false) + { + status &= 0xFE; // Channel frequency KO + } + + // Verify datarate + if (RegionCommonValueInRange(rxParamSetupReq->Datarate, AS923_RX_MIN_DATARATE, AS923_RX_MAX_DATARATE) == false) + { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, AS923_MIN_RX1_DR_OFFSET, AS923_MAX_RX1_DR_OFFSET) == false) + { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; + } + + uint8_t RegionAS923NewChannelReq(NewChannelReqParams_t *newChannelReq) + { + uint8_t status = 0x03; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + if (newChannelReq->NewChannel->Frequency == 0) + { + channelRemove.ChannelId = newChannelReq->ChannelId; + + // Remove + if (RegionAS923ChannelsRemove(&channelRemove) == false) + { + status &= 0xFC; + } + } + else + { + channelAdd.NewChannel = newChannelReq->NewChannel; + channelAdd.ChannelId = newChannelReq->ChannelId; + + switch (RegionAS923ChannelAdd(&channelAdd)) + { + case LORAMAC_STATUS_OK: + { + break; + } + case LORAMAC_STATUS_FREQUENCY_INVALID: + { + status &= 0xFE; + break; + } + case LORAMAC_STATUS_DATARATE_INVALID: + { + status &= 0xFD; + break; + } + case LORAMAC_STATUS_FREQ_AND_DR_INVALID: + { + status &= 0xFC; + break; + } + default: + { + status &= 0xFC; + break; + } + } + } + + return status; + } + + int8_t RegionAS923TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) + { + // Accept the request + return 0; + } + + uint8_t RegionAS923DlChannelReq(DlChannelReqParams_t *dlChannelReq) + { + uint8_t status = 0x03; + + // Verify if the frequency is supported + if (VerifyTxFreq(dlChannelReq->Rx1Frequency) == false) + { + status &= 0xFE; + } + + // Verify if an uplink frequency exists + if (Channels[dlChannelReq->ChannelId].Frequency == 0) + { + status &= 0xFD; + } + + // Apply Rx1 frequency, if the status is OK + if (status == 0x03) + { + Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency; + } + + return status; + } + + int8_t RegionAS923AlternateDr(AlternateDrParams_t *alternateDr) + { + // Only AS923_DWELL_LIMIT_DATARATE is supported + return AS923_DWELL_LIMIT_DATARATE; + } + + void RegionAS923CalcBackOff(CalcBackOffParams_t *calcBackOff) + { + RegionCommonCalcBackOffParams_t calcBackOffParams; + + calcBackOffParams.Channels = Channels; + calcBackOffParams.Bands = Bands; + calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; + calcBackOffParams.Joined = calcBackOff->Joined; + calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; + calcBackOffParams.Channel = calcBackOff->Channel; + calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; + calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; + + RegionCommonCalcBackOff(&calcBackOffParams); + } + + bool RegionAS923NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) + { + uint8_t channelNext = 0; + uint8_t nbEnabledChannels = 0; + uint8_t delayTx = 0; + uint8_t enabledChannels[AS923_MAX_NB_CHANNELS] = {0}; + TimerTime_t nextTxDelay = 0; + + if (RegionCommonCountChannels(ChannelsMask, 0, 1) == 0) + { // Reactivate default channels + ChannelsMask[0] |= LC(1) + LC(2); + } + + if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) + { + // Reset Aggregated time off + *aggregatedTimeOff = 0; + + // Update bands Time OFF + nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, AS923_MAX_NB_BANDS); + + // Search how many channels are enabled + nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Joined, nextChanParams->Datarate, + ChannelsMask, Channels, + Bands, enabledChannels, &delayTx); + } + else + { + delayTx++; + nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); + } + + if (nbEnabledChannels > 0) + { + for (uint8_t i = 0, j = randr(0, nbEnabledChannels - 1); i < AS923_MAX_NB_CHANNELS; i++) + { + channelNext = enabledChannels[j]; + j = (j + 1) % nbEnabledChannels; + + // Perform carrier sense for AS923_CARRIER_SENSE_TIME + // If the channel is free, we can stop the LBT mechanism + if (Radio.IsChannelFree(MODEM_LORA, Channels[channelNext].Frequency, AS923_RSSI_FREE_TH, AS923_CARRIER_SENSE_TIME) == true) + { + // Free channel found + *channel = channelNext; + *time = 0; + return true; + } + } + return false; + } + else + { + if (delayTx > 0) + { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return true; + } + // Datarate not supported by any channel, restore defaults + ChannelsMask[0] |= LC(1) + LC(2); + *time = 0; + return false; + } + } + + LoRaMacStatus_t RegionAS923ChannelAdd(ChannelAddParams_t *channelAdd) + { + uint8_t band = 0; + bool drInvalid = false; + bool freqInvalid = false; + uint8_t id = channelAdd->ChannelId; + + if (id >= AS923_MAX_NB_CHANNELS) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + // Validate the datarate range + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Min, AS923_TX_MIN_DATARATE, AS923_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, AS923_TX_MIN_DATARATE, AS923_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + if (channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max) + { + drInvalid = true; + } + + // Default channels don't accept all values + if (id < AS923_NUMB_DEFAULT_CHANNELS) + { + // Validate the datarate range for min: must be DR_0 + if (channelAdd->NewChannel->DrRange.Fields.Min > DR_0) + { + drInvalid = true; + } + // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, DR_5, AS923_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + // We are not allowed to change the frequency + if (channelAdd->NewChannel->Frequency != Channels[id].Frequency) + { + freqInvalid = true; + } + } + + // Check frequency + if (freqInvalid == false) + { + if (VerifyTxFreq(channelAdd->NewChannel->Frequency) == false) + { + freqInvalid = true; + } + } + + // Check status + if ((drInvalid == true) && (freqInvalid == true)) + { + return LORAMAC_STATUS_FREQ_AND_DR_INVALID; + } + if (drInvalid == true) + { + return LORAMAC_STATUS_DATARATE_INVALID; + } + if (freqInvalid == true) + { + return LORAMAC_STATUS_FREQUENCY_INVALID; + } + + memcpy(&(Channels[id]), channelAdd->NewChannel, sizeof(Channels[id])); + Channels[id].Band = band; + ChannelsMask[0] |= (1 << id); + return LORAMAC_STATUS_OK; + } + + bool RegionAS923ChannelsRemove(ChannelRemoveParams_t *channelRemove) + { + uint8_t id = channelRemove->ChannelId; + + if (id < AS923_NUMB_DEFAULT_CHANNELS) + { + return false; + } + + // Remove the channel from the list of channels + Channels[id] = (ChannelParams_t){0, 0, {0}, 0}; + + return RegionCommonChanDisable(ChannelsMask, id, AS923_MAX_NB_CHANNELS); + } + + void RegionAS923SetContinuousWave(ContinuousWaveParams_t *continuousWave) + { + int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); + int8_t phyTxPower = 0; + uint32_t frequency = Channels[continuousWave->Channel].Frequency; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); + + Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); + } + + uint8_t RegionAS923ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) + { + // Initialize minDr for a downlink dwell time configuration of 0 + int8_t minDr = DR_0; + + // Update the minDR for a downlink dwell time configuration of 1 + if (downlinkDwellTime == 1) + { + minDr = AS923_DWELL_LIMIT_DATARATE; + } + + // Apply offset formula + return MIN(DR_5, MAX(minDr, dr - EffectiveRx1DrOffsetAS923[drOffset])); + } }; \ No newline at end of file diff --git a/src/mac/region/RegionAS923.h b/src/mac/region/RegionAS923.h index 4c1ce5c..1c9f243 100644 --- a/src/mac/region/RegionAS923.h +++ b/src/mac/region/RegionAS923.h @@ -41,270 +41,279 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define AS923_MAX_NB_CHANNELS 16 +#define AS923_MAX_NB_CHANNELS 16 /*! * Number of default channels */ -#define AS923_NUMB_DEFAULT_CHANNELS 2 +#define AS923_NUMB_DEFAULT_CHANNELS 2 /*! * Number of channels to apply for the CF list */ -#define AS923_NUMB_CHANNELS_CF_LIST 5 +#define AS923_NUMB_CHANNELS_CF_LIST 5 /*! * Minimal datarate that can be used by the node */ -#define AS923_TX_MIN_DATARATE DR_0 +#define AS923_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define AS923_TX_MAX_DATARATE DR_7 +#define AS923_TX_MAX_DATARATE DR_7 /*! * Minimal datarate that can be used by the node */ -#define AS923_RX_MIN_DATARATE DR_0 +#define AS923_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define AS923_RX_MAX_DATARATE DR_7 +#define AS923_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node */ -#define AS923_DEFAULT_DATARATE DR_2 +#define AS923_DEFAULT_DATARATE DR_2 /*! * The minimum datarate which is used when the * dwell time is limited. */ -#define AS923_DWELL_LIMIT_DATARATE DR_2 +#define AS923_DWELL_LIMIT_DATARATE DR_2 /*! * Minimal Rx1 receive datarate offset */ -#define AS923_MIN_RX1_DR_OFFSET 0 +#define AS923_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define AS923_MAX_RX1_DR_OFFSET 7 +#define AS923_MAX_RX1_DR_OFFSET 7 /*! * Default Rx1 receive datarate offset */ -#define AS923_DEFAULT_RX1_DR_OFFSET 0 +#define AS923_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define AS923_MIN_TX_POWER TX_POWER_7 +#define AS923_MIN_TX_POWER TX_POWER_7 /*! * Maximal Tx output power that can be used by the node */ -#define AS923_MAX_TX_POWER TX_POWER_0 +#define AS923_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define AS923_DEFAULT_TX_POWER TX_POWER_0 +#define AS923_DEFAULT_TX_POWER TX_POWER_0 /*! * Default uplink dwell time configuration */ -#define AS923_DEFAULT_UPLINK_DWELL_TIME 1 +#define AS923_DEFAULT_UPLINK_DWELL_TIME 1 /*! * Default downlink dwell time configuration */ -#define AS923_DEFAULT_DOWNLINK_DWELL_TIME 1 +#define AS923_DEFAULT_DOWNLINK_DWELL_TIME 1 /*! * Default Max EIRP */ -#define AS923_DEFAULT_MAX_EIRP 16.0f +#define AS923_DEFAULT_MAX_EIRP 16.0f /*! * Default antenna gain */ -#define AS923_DEFAULT_ANTENNA_GAIN 2.15f +#define AS923_DEFAULT_ANTENNA_GAIN 2.15f /*! * ADR Ack limit */ -#define AS923_ADR_ACK_LIMIT 64 +#define AS923_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define AS923_ADR_ACK_DELAY 32 +#define AS923_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define AS923_DUTY_CYCLE_ENABLED 0 +#define AS923_DUTY_CYCLE_ENABLED 0 /*! * Maximum RX window duration */ -#define AS923_MAX_RX_WINDOW 3000 +#define AS923_MAX_RX_WINDOW 3000 /*! * Receive delay 1 */ -#define AS923_RECEIVE_DELAY1 1000 +#define AS923_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define AS923_RECEIVE_DELAY2 2000 +#define AS923_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define AS923_JOIN_ACCEPT_DELAY1 5000 +#define AS923_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define AS923_JOIN_ACCEPT_DELAY2 6000 +#define AS923_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define AS923_MAX_FCNT_GAP 16384 +#define AS923_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define AS923_ACKTIMEOUT 2000 +#define AS923_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define AS923_ACK_TIMEOUT_RND 1000 +#define AS923_ACK_TIMEOUT_RND 1000 -#if ( AS923_DEFAULT_DATARATE > DR_5 ) +#if (AS923_DEFAULT_DATARATE > DR_5) #error "A default DR higher than DR_5 may lead to connectivity loss." #endif /*! * Second reception window channel frequency definition. */ -#define AS923_RX_WND_2_FREQ 923200000 +#define AS923_RX_WND_2_FREQ 923200000 /*! * Second reception window channel datarate definition. */ -#define AS923_RX_WND_2_DR DR_2 +#define AS923_RX_WND_2_DR DR_2 /*! * Maximum number of bands */ -#define AS923_MAX_NB_BANDS 1 +#define AS923_MAX_NB_BANDS 1 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define AS923_BAND0 { 100, AS923_MAX_TX_POWER, 0, 0 } // 1.0 % +#define AS923_BAND0 \ + { \ + 100, AS923_MAX_TX_POWER, 0, 0 \ + } // 1.0 % /*! * LoRaMac default channel 1 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define AS923_LC1 { 923200000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define AS923_LC1 \ + { \ + 923200000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac default channel 2 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define AS923_LC2 { 923400000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define AS923_LC2 \ + { \ + 923400000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac channels which are allowed for the join procedure */ -#define AS923_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) ) +#define AS923_JOIN_CHANNELS (uint16_t)(LC(1) | LC(2)) /*! * RSSI threshold for a free channel [dBm] */ -#define AS923_RSSI_FREE_TH -85 +#define AS923_RSSI_FREE_TH -85 /*! * Specifies the time the node performs a carrier sense */ -#define AS923_CARRIER_SENSE_TIME 6 +#define AS923_CARRIER_SENSE_TIME 6 -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesAS923[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; + static const uint8_t DataratesAS923[] = {12, 11, 10, 9, 8, 7, 7, 50}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsAS923[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 }; + static const uint32_t BandwidthsAS923[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; -/*! + /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. * The table is valid for the dwell time configuration of 0 for uplinks and downlinks. */ -static const uint8_t MaxPayloadOfDatarateDwell0AS923[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; + static const uint8_t MaxPayloadOfDatarateDwell0AS923[] = {51, 51, 51, 115, 242, 242, 242, 242}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. * The table is valid for the dwell time configuration of 0 for uplinks and downlinks. The table provides * repeater support. */ -static const uint8_t MaxPayloadOfDatarateRepeaterDwell0AS923[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; + static const uint8_t MaxPayloadOfDatarateRepeaterDwell0AS923[] = {51, 51, 51, 115, 222, 222, 222, 222}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with and without repeater. * The table proides repeater support. The table is only valid for uplinks. */ -static const uint8_t MaxPayloadOfDatarateDwell1UpAS923[] = { 0, 0, 11, 53, 125, 242, 242, 242 }; + static const uint8_t MaxPayloadOfDatarateDwell1UpAS923[] = {0, 0, 11, 53, 125, 242, 242, 242}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with and without repeater. * The table proides repeater support. The table is only valid for downlinks. */ -static const uint8_t MaxPayloadOfDatarateDwell1DownAS923[] = { 0, 0, 11, 53, 126, 242, 242, 242 }; + static const uint8_t MaxPayloadOfDatarateDwell1DownAS923[] = {0, 0, 11, 53, 126, 242, 242, 242}; -/*! + /*! * Effective datarate offsets for receive window 1. */ -static const int8_t EffectiveRx1DrOffsetAS923[] = { 0, 1, 2, 3, 4, 5, -1, -2 }; + static const int8_t EffectiveRx1DrOffsetAS923[] = {0, 1, 2, 3, 4, 5, -1, -2}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionAS923GetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionAS923GetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionAS923SetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionAS923SetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionAS923InitDefaults( InitType_t type ); + void RegionAS923InitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -313,26 +322,26 @@ void RegionAS923InitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionAS923Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionAS923Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionAS923ApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionAS923ApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionAS923ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionAS923ChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -345,9 +354,9 @@ bool RegionAS923ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionAS923AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionAS923AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -360,9 +369,9 @@ bool RegionAS923AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowO * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionAS923ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionAS923ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -371,9 +380,9 @@ void RegionAS923ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionAS923RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionAS923RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -384,36 +393,36 @@ bool RegionAS923RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionAS923TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionAS923TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionAS923LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionAS923LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionAS923RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionAS923RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionAS923NewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionAS923NewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -422,34 +431,34 @@ uint8_t RegionAS923NewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionAS923TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionAS923TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionAS923DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionAS923DlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionAS923AlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionAS923AlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionAS923CalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionAS923CalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -461,34 +470,34 @@ void RegionAS923CalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionAS923NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionAS923NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionAS923ChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionAS923ChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionAS923ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionAS923ChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionAS923SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionAS923SetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -499,8 +508,8 @@ void RegionAS923SetContinuousWave( ContinuousWaveParams_t* continuousWave ); * * \retval newDr Computed datarate. */ -uint8_t RegionAS923ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionAS923ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONAS923 */ + /*! \} defgroup REGIONAS923 */ }; #endif // __REGION_AS923_H__ diff --git a/src/mac/region/RegionAU915.cpp b/src/mac/region/RegionAU915.cpp index 5d8c60f..fbde513 100644 --- a/src/mac/region/RegionAU915.cpp +++ b/src/mac/region/RegionAU915.cpp @@ -37,833 +37,833 @@ extern "C" // Definitions #define CHANNELS_MASK_SIZE 6 - // Global attributes - /*! + // Global attributes + /*! * LoRaMAC channels */ - static ChannelParams_t Channels[AU915_MAX_NB_CHANNELS]; + static ChannelParams_t Channels[AU915_MAX_NB_CHANNELS]; - /*! + /*! * LoRaMac bands */ - static Band_t Bands[AU915_MAX_NB_BANDS] = - { - AU915_BAND0}; + static Band_t Bands[AU915_MAX_NB_BANDS] = + { + AU915_BAND0}; - /*! + /*! * LoRaMac channels mask */ - static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; + static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; - /*! + /*! * LoRaMac channels remaining */ - static uint16_t ChannelsMaskRemaining[CHANNELS_MASK_SIZE]; + static uint16_t ChannelsMaskRemaining[CHANNELS_MASK_SIZE]; - /*! + /*! * LoRaMac channels default mask */ - static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; - - // Static functions - static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) - { - uint8_t nextLowerDr = 0; - - if (dr == minDr) - { - nextLowerDr = minDr; - } - else - { - nextLowerDr = dr - 1; - } - return nextLowerDr; - } - - static uint32_t GetBandwidth(uint32_t drIndex) - { - switch (BandwidthsAU915[drIndex]) - { - default: - case 125000: - return 0; - case 250000: - return 1; - case 500000: - return 2; - } - } - - static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) - { - int8_t txPowerResult = txPower; - - // Limit tx power to the band max - txPowerResult = MAX(txPower, maxBandTxPower); - - return txPowerResult; - } - - static uint8_t CountNbOfEnabledChannels(uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTransmission = 0; - - for (uint8_t i = 0, k = 0; i < AU915_MAX_NB_CHANNELS; i += 16, k++) - { - for (uint8_t j = 0; j < 16; j++) - { - if ((channelsMask[k] & (1 << j)) != 0) - { - if (channels[i + j].Frequency == 0) - { // Check if the channel is enabled - continue; - } - if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, - channels[i + j].DrRange.Fields.Max) == false) - { // Check if the current channel selection supports the given datarate - continue; - } - if (bands[channels[i + j].Band].TimeOff > 0) - { // Check if the band is available for transmission - delayTransmission++; - continue; - } - enabledChannels[nbEnabledChannels++] = i + j; - } - } - } - - *delayTx = delayTransmission; - return nbEnabledChannels; - } - - PhyParam_t RegionAU915GetPhyParam(GetPhyParams_t *getPhy) - { - PhyParam_t phyParam = {0}; - - switch (getPhy->Attribute) - { - case PHY_MIN_RX_DR: - { - phyParam.Value = AU915_RX_MIN_DATARATE; - break; - } - case PHY_MIN_TX_DR: - { - phyParam.Value = AU915_TX_MIN_DATARATE; - break; - } - case PHY_DEF_TX_DR: - { - phyParam.Value = AU915_DEFAULT_DATARATE; - break; - } - case PHY_NEXT_LOWER_TX_DR: - { - phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, AU915_TX_MIN_DATARATE); - break; - } - case PHY_DEF_TX_POWER: - { - phyParam.Value = AU915_DEFAULT_TX_POWER; - break; - } - case PHY_MAX_PAYLOAD: - { - phyParam.Value = MaxPayloadOfDatarateAU915[getPhy->Datarate]; - break; - } - case PHY_MAX_PAYLOAD_REPEATER: - { - phyParam.Value = MaxPayloadOfDatarateRepeaterAU915[getPhy->Datarate]; - break; - } - case PHY_DUTY_CYCLE: - { - phyParam.Value = AU915_DUTY_CYCLE_ENABLED; - break; - } - case PHY_MAX_RX_WINDOW: - { - phyParam.Value = AU915_MAX_RX_WINDOW; - break; - } - case PHY_RECEIVE_DELAY1: - { - phyParam.Value = AU915_RECEIVE_DELAY1; - break; - } - case PHY_RECEIVE_DELAY2: - { - phyParam.Value = AU915_RECEIVE_DELAY2; - break; - } - case PHY_JOIN_ACCEPT_DELAY1: - { - phyParam.Value = AU915_JOIN_ACCEPT_DELAY1; - break; - } - case PHY_JOIN_ACCEPT_DELAY2: - { - phyParam.Value = AU915_JOIN_ACCEPT_DELAY2; - break; - } - case PHY_MAX_FCNT_GAP: - { - phyParam.Value = AU915_MAX_FCNT_GAP; - break; - } - case PHY_ACK_TIMEOUT: - { - phyParam.Value = (AU915_ACKTIMEOUT + randr(-AU915_ACK_TIMEOUT_RND, AU915_ACK_TIMEOUT_RND)); - break; - } - case PHY_DEF_DR1_OFFSET: - { - phyParam.Value = AU915_DEFAULT_RX1_DR_OFFSET; - break; - } - case PHY_DEF_RX2_FREQUENCY: - { - phyParam.Value = AU915_RX_WND_2_FREQ; - break; - } - case PHY_DEF_RX2_DR: - { - phyParam.Value = AU915_RX_WND_2_DR; - break; - } - case PHY_CHANNELS_MASK: - { - phyParam.ChannelsMask = ChannelsMask; - break; - } - case PHY_CHANNELS_DEFAULT_MASK: - { - phyParam.ChannelsMask = ChannelsDefaultMask; - break; - } - case PHY_MAX_NB_CHANNELS: - { - phyParam.Value = AU915_MAX_NB_CHANNELS; - break; - } - case PHY_CHANNELS: - { - phyParam.Channels = Channels; - break; - } - case PHY_DEF_UPLINK_DWELL_TIME: - case PHY_DEF_DOWNLINK_DWELL_TIME: - { - phyParam.Value = 0; - break; - } - case PHY_DEF_MAX_EIRP: - { - phyParam.fValue = AU915_DEFAULT_MAX_EIRP; - break; - } - case PHY_DEF_ANTENNA_GAIN: - { - phyParam.fValue = AU915_DEFAULT_ANTENNA_GAIN; - break; - } - case PHY_NB_JOIN_TRIALS: - case PHY_DEF_NB_JOIN_TRIALS: - { - phyParam.Value = 2; - break; - } - default: - { - break; - } - } - - return phyParam; - } - - void RegionAU915SetBandTxDone(SetBandTxDoneParams_t *txDone) - { - RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); - } - - void RegionAU915InitDefaults(InitType_t type) - { - switch (type) - { - case INIT_TYPE_INIT: - { - // Channels - // 125 kHz channels - for (uint8_t i = 0; i < AU915_MAX_NB_CHANNELS - 8; i++) - { - Channels[i].Frequency = 915200000 + i * 200000; - Channels[i].DrRange.Value = (DR_5 << 4) | DR_0; - Channels[i].Band = 0; - } - // 500 kHz channels - for (uint8_t i = AU915_MAX_NB_CHANNELS - 8; i < AU915_MAX_NB_CHANNELS; i++) - { - Channels[i].Frequency = 915900000 + (i - (AU915_MAX_NB_CHANNELS - 8)) * 1600000; - Channels[i].DrRange.Value = (DR_6 << 4) | DR_6; - Channels[i].Band = 0; - } - - // Initialize channels default mask - ChannelsDefaultMask[0] = 0xFFFF; - ChannelsDefaultMask[1] = 0xFFFF; - ChannelsDefaultMask[2] = 0xFFFF; - ChannelsDefaultMask[3] = 0xFFFF; - ChannelsDefaultMask[4] = 0x00FF; - ChannelsDefaultMask[5] = 0x0000; - - // Copy channels default mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); - - // Copy into channels mask remaining - RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 6); - break; - } - case INIT_TYPE_RESTORE: - { - // Copy channels default mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); - - for (uint8_t i = 0; i < 6; i++) - { // Copy-And the channels mask - ChannelsMaskRemaining[i] &= ChannelsMask[i]; - } - break; - } - case INIT_TYPE_APP_DEFAULTS: - { - // Copy channels default mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); - - // Copy into channels mask remaining - RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 6); - break; - } - default: - { - break; - } - } - } - - bool RegionAU915Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) - { - switch (phyAttribute) - { - case PHY_TX_DR: - case PHY_DEF_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, AU915_TX_MIN_DATARATE, AU915_TX_MAX_DATARATE); - } - case PHY_RX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE); - } - case PHY_DEF_TX_POWER: - case PHY_TX_POWER: - { - // Remark: switched min and max! - return RegionCommonValueInRange(verify->TxPower, AU915_MAX_TX_POWER, AU915_MIN_TX_POWER); - } - case PHY_DUTY_CYCLE: - { - return AU915_DUTY_CYCLE_ENABLED; - } - case PHY_NB_JOIN_TRIALS: - { - if (verify->NbJoinTrials < 2) - { - return false; - } - break; - } - default: - return false; - } - return true; - } - - void RegionAU915ApplyCFList(ApplyCFListParams_t *applyCFList) - { - return; - } - - bool RegionAU915ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) - { - uint8_t nbChannels = RegionCommonCountChannels(chanMaskSet->ChannelsMaskIn, 0, 4); - - // Check the number of active channels - // According to ACMA regulation, we require at least 20 125KHz channels, if - // the node shall utilize 125KHz channels. - if ((nbChannels < 20) && - (nbChannels > 0)) - { - return false; - } - - switch (chanMaskSet->ChannelsMaskType) - { - case CHANNELS_MASK: - { - RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 6); - - for (uint8_t i = 0; i < 6; i++) - { // Copy-And the channels mask - ChannelsMaskRemaining[i] &= ChannelsMask[i]; - } - break; - } - case CHANNELS_DEFAULT_MASK: - { - RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6); - break; - } - default: - return false; - } - return true; - } - - bool RegionAU915AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) - { - bool adrAckReq = false; - int8_t datarate = adrNext->Datarate; - int8_t txPower = adrNext->TxPower; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - - // Report back the adr ack counter - *adrAckCounter = adrNext->AdrAckCounter; - - if (adrNext->AdrEnabled == true) - { - if (datarate == AU915_TX_MIN_DATARATE) - { - *adrAckCounter = 0; - adrAckReq = false; - } - else - { - if (adrNext->AdrAckCounter >= AU915_ADR_ACK_LIMIT) - { - adrAckReq = true; - txPower = AU915_MAX_TX_POWER; - } - else - { - adrAckReq = false; - } - if (adrNext->AdrAckCounter >= (AU915_ADR_ACK_LIMIT + AU915_ADR_ACK_DELAY)) - { - if ((adrNext->AdrAckCounter % AU915_ADR_ACK_DELAY) == 1) - { - // Decrease the datarate - getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; - getPhy.Datarate = datarate; - getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; - phyParam = RegionAU915GetPhyParam(&getPhy); - datarate = phyParam.Value; - - if (datarate == AU915_TX_MIN_DATARATE) - { - // We must set adrAckReq to false as soon as we reach the lowest datarate - adrAckReq = false; - if (adrNext->UpdateChanMask == true) - { - // Re-enable default channels - ChannelsMask[0] = 0xFFFF; - ChannelsMask[1] = 0xFFFF; - ChannelsMask[2] = 0xFFFF; - ChannelsMask[3] = 0xFFFF; - ChannelsMask[4] = 0x00FF; - ChannelsMask[5] = 0x0000; - } - } - } - } - } - } - - *drOut = datarate; - *txPowOut = txPower; - return adrAckReq; - } - - void RegionAU915ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) - { - double tSymbol = 0.0; - - // Get the datarate, perform a boundary check - rxConfigParams->Datarate = MIN(datarate, AU915_RX_MAX_DATARATE); - rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); - - tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesAU915[rxConfigParams->Datarate], BandwidthsAU915[rxConfigParams->Datarate]); - - RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); - } - - bool RegionAU915RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) - { - int8_t dr = rxConfig->Datarate; - uint8_t maxPayload = 0; - int8_t phyDr = 0; - uint32_t frequency = rxConfig->Frequency; - - if (Radio.GetStatus() != RF_IDLE) - { - return false; - } - - if (rxConfig->Window == 0) - { - // Apply window 1 frequency - frequency = AU915_FIRST_RX1_CHANNEL + (rxConfig->Channel % 8) * AU915_STEPWIDTH_RX1_CHANNEL; - } - - // Read the physical datarate from the datarates table - phyDr = DataratesAU915[dr]; - - Radio.SetChannel(frequency); - - // Radio configuration - Radio.SetRxConfig(MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); - - if (rxConfig->RepeaterSupport == true) - { - maxPayload = MaxPayloadOfDatarateRepeaterAU915[dr]; - } - else - { - maxPayload = MaxPayloadOfDatarateAU915[dr]; - } - Radio.SetMaxPayloadLength(MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - *datarate = (uint8_t)dr; - return true; - } - - bool RegionAU915TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) - { - int8_t phyDr = DataratesAU915[txConfig->Datarate]; - int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); - uint32_t bandwidth = GetBandwidth(txConfig->Datarate); - int8_t phyTxPower = 0; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); - - // Setup the radio frequency - Radio.SetChannel(Channels[txConfig->Channel].Frequency); - - Radio.SetTxConfig(MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); - - // Setup maximum payload lenght of the radio driver - Radio.SetMaxPayloadLength(MODEM_LORA, txConfig->PktLen); - - *txTimeOnAir = Radio.TimeOnAir(MODEM_LORA, txConfig->PktLen); - *txPower = txPowerLimited; - - return true; - } - - uint8_t RegionAU915LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) - { - uint8_t status = 0x07; - RegionCommonLinkAdrParams_t linkAdrParams; - uint8_t nextIndex = 0; - uint8_t bytesProcessed = 0; - uint16_t channelsMask[6] = {0, 0, 0, 0, 0, 0}; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; - - // Initialize local copy of channels mask - RegionCommonChanMaskCopy(channelsMask, ChannelsMask, 6); - - while (bytesProcessed < linkAdrReq->PayloadSize) - { - nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); - - if (nextIndex == 0) - break; // break loop, since no more request has been found - - // Update bytes processed - bytesProcessed += nextIndex; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - if (linkAdrParams.ChMaskCtrl == 6) - { - // Enable all 125 kHz channels - channelsMask[0] = 0xFFFF; - channelsMask[1] = 0xFFFF; - channelsMask[2] = 0xFFFF; - channelsMask[3] = 0xFFFF; - // Apply chMask to channels 64 to 71 - channelsMask[4] = linkAdrParams.ChMask; - } - else if (linkAdrParams.ChMaskCtrl == 7) - { - // Disable all 125 kHz channels - channelsMask[0] = 0x0000; - channelsMask[1] = 0x0000; - channelsMask[2] = 0x0000; - channelsMask[3] = 0x0000; - // Apply chMask to channels 64 to 71 - channelsMask[4] = linkAdrParams.ChMask; - } - else if (linkAdrParams.ChMaskCtrl == 5) - { - // RFU - status &= 0xFE; // Channel mask KO - } - else - { - channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask; - } - } - - // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels - if ((linkAdrParams.Datarate < DR_6) && (RegionCommonCountChannels(channelsMask, 0, 4) < 2)) - { - status &= 0xFE; // Channel mask KO - } - - // Get the minimum possible datarate - getPhy.Attribute = PHY_MIN_TX_DR; - getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; - phyParam = RegionAU915GetPhyParam(&getPhy); - - linkAdrVerifyParams.Status = status; - linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; - linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; - linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; - linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; - linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; - linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; - linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; - linkAdrVerifyParams.NbChannels = AU915_MAX_NB_CHANNELS; - linkAdrVerifyParams.ChannelsMask = channelsMask; - linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; - linkAdrVerifyParams.MaxDatarate = AU915_TX_MAX_DATARATE; - linkAdrVerifyParams.Channels = Channels; - linkAdrVerifyParams.MinTxPower = AU915_MIN_TX_POWER; - linkAdrVerifyParams.MaxTxPower = AU915_MAX_TX_POWER; - - // Verify the parameters and update, if necessary - status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); - - // Update channelsMask if everything is correct - if (status == 0x07) - { - // Copy Mask - RegionCommonChanMaskCopy(ChannelsMask, channelsMask, 6); - - ChannelsMaskRemaining[0] &= ChannelsMask[0]; - ChannelsMaskRemaining[1] &= ChannelsMask[1]; - ChannelsMaskRemaining[2] &= ChannelsMask[2]; - ChannelsMaskRemaining[3] &= ChannelsMask[3]; - ChannelsMaskRemaining[4] = ChannelsMask[4]; - ChannelsMaskRemaining[5] = ChannelsMask[5]; - } - - // Update status variables - *drOut = linkAdrParams.Datarate; - *txPowOut = linkAdrParams.TxPower; - *nbRepOut = linkAdrParams.NbRep; - *nbBytesParsed = bytesProcessed; - - return status; - } - - uint8_t RegionAU915RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) - { - uint8_t status = 0x07; - uint32_t freq = rxParamSetupReq->Frequency; - - // Verify radio frequency - if ((Radio.CheckRfFrequency(freq) == false) || - (freq < AU915_FIRST_RX1_CHANNEL) || - (freq > AU915_LAST_RX1_CHANNEL) || - (((freq - (uint32_t)AU915_FIRST_RX1_CHANNEL) % (uint32_t)AU915_STEPWIDTH_RX1_CHANNEL) != 0)) - { - status &= 0xFE; // Channel frequency KO - } - - // Verify datarate - if (RegionCommonValueInRange(rxParamSetupReq->Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE) == false) - { - status &= 0xFD; // Datarate KO - } - if ((rxParamSetupReq->Datarate == DR_7) || - (rxParamSetupReq->Datarate > DR_13)) - { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, AU915_MIN_RX1_DR_OFFSET, AU915_MAX_RX1_DR_OFFSET) == false) - { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; - } - - uint8_t RegionAU915NewChannelReq(NewChannelReqParams_t *newChannelReq) - { - // Datarate and frequency KO - return 0; - } - - int8_t RegionAU915TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) - { - return -1; - } - - uint8_t RegionAU915DlChannelReq(DlChannelReqParams_t *dlChannelReq) - { - return 0; - } - - int8_t RegionAU915AlternateDr(AlternateDrParams_t *alternateDr) - { - int8_t datarate = 0; - - // Re-enable 500 kHz default channels - ChannelsMask[4] = 0x00FF; - - if ((alternateDr->NbTrials & 0x01) == 0x01) - { - datarate = DR_6; - } - else - { - datarate = DR_0; - } - return datarate; - } - - void RegionAU915CalcBackOff(CalcBackOffParams_t *calcBackOff) - { - RegionCommonCalcBackOffParams_t calcBackOffParams; - - calcBackOffParams.Channels = Channels; - calcBackOffParams.Bands = Bands; - calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; - calcBackOffParams.Joined = calcBackOff->Joined; - calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; - calcBackOffParams.Channel = calcBackOff->Channel; - calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; - calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; - - RegionCommonCalcBackOff(&calcBackOffParams); - } - - bool RegionAU915NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTx = 0; - uint8_t enabledChannels[AU915_MAX_NB_CHANNELS] = {0}; - TimerTime_t nextTxDelay = 0; - - // Count 125kHz channels - if (RegionCommonCountChannels(ChannelsMaskRemaining, 0, 4) == 0) - { // Reactivate default channels - RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 4); - } - // Check other channels - if (nextChanParams->Datarate >= DR_6) - { - if ((ChannelsMaskRemaining[4] & 0x00FF) == 0) - { - ChannelsMaskRemaining[4] = ChannelsMask[4]; - } - } - - if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) - { - // Reset Aggregated time off - *aggregatedTimeOff = 0; - - // Update bands Time OFF - nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, AU915_MAX_NB_BANDS); - - // Search how many channels are enabled - nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Datarate, - ChannelsMaskRemaining, Channels, - Bands, enabledChannels, &delayTx); - } - else - { - delayTx++; - nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); - } - - if (nbEnabledChannels > 0) - { - // We found a valid channel - *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; - // Disable the channel in the mask - RegionCommonChanDisable(ChannelsMaskRemaining, *channel, AU915_MAX_NB_CHANNELS - 8); - - *time = 0; - return true; - } - else - { - if (delayTx > 0) - { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = nextTxDelay; - return true; - } - // Datarate not supported by any channel - *time = 0; - return false; - } - } - - LoRaMacStatus_t RegionAU915ChannelAdd(ChannelAddParams_t *channelAdd) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - bool RegionAU915ChannelsRemove(ChannelRemoveParams_t *channelRemove) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - void RegionAU915SetContinuousWave(ContinuousWaveParams_t *continuousWave) - { - int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); - int8_t phyTxPower = 0; - uint32_t frequency = Channels[continuousWave->Channel].Frequency; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); - - Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); - } - - uint8_t RegionAU915ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) - { - int8_t datarate = DatarateOffsetsAU915[dr][drOffset]; - - if (datarate < 0) - { - datarate = DR_0; - } - return datarate; - } + static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; + + // Static functions + static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) + { + uint8_t nextLowerDr = 0; + + if (dr == minDr) + { + nextLowerDr = minDr; + } + else + { + nextLowerDr = dr - 1; + } + return nextLowerDr; + } + + static uint32_t GetBandwidth(uint32_t drIndex) + { + switch (BandwidthsAU915[drIndex]) + { + default: + case 125000: + return 0; + case 250000: + return 1; + case 500000: + return 2; + } + } + + static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) + { + int8_t txPowerResult = txPower; + + // Limit tx power to the band max + txPowerResult = MAX(txPower, maxBandTxPower); + + return txPowerResult; + } + + static uint8_t CountNbOfEnabledChannels(uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTransmission = 0; + + for (uint8_t i = 0, k = 0; i < AU915_MAX_NB_CHANNELS; i += 16, k++) + { + for (uint8_t j = 0; j < 16; j++) + { + if ((channelsMask[k] & (1 << j)) != 0) + { + if (channels[i + j].Frequency == 0) + { // Check if the channel is enabled + continue; + } + if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, + channels[i + j].DrRange.Fields.Max) == false) + { // Check if the current channel selection supports the given datarate + continue; + } + if (bands[channels[i + j].Band].TimeOff > 0) + { // Check if the band is available for transmission + delayTransmission++; + continue; + } + enabledChannels[nbEnabledChannels++] = i + j; + } + } + } + + *delayTx = delayTransmission; + return nbEnabledChannels; + } + + PhyParam_t RegionAU915GetPhyParam(GetPhyParams_t *getPhy) + { + PhyParam_t phyParam = {0}; + + switch (getPhy->Attribute) + { + case PHY_MIN_RX_DR: + { + phyParam.Value = AU915_RX_MIN_DATARATE; + break; + } + case PHY_MIN_TX_DR: + { + phyParam.Value = AU915_TX_MIN_DATARATE; + break; + } + case PHY_DEF_TX_DR: + { + phyParam.Value = AU915_DEFAULT_DATARATE; + break; + } + case PHY_NEXT_LOWER_TX_DR: + { + phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, AU915_TX_MIN_DATARATE); + break; + } + case PHY_DEF_TX_POWER: + { + phyParam.Value = AU915_DEFAULT_TX_POWER; + break; + } + case PHY_MAX_PAYLOAD: + { + phyParam.Value = MaxPayloadOfDatarateAU915[getPhy->Datarate]; + break; + } + case PHY_MAX_PAYLOAD_REPEATER: + { + phyParam.Value = MaxPayloadOfDatarateRepeaterAU915[getPhy->Datarate]; + break; + } + case PHY_DUTY_CYCLE: + { + phyParam.Value = AU915_DUTY_CYCLE_ENABLED; + break; + } + case PHY_MAX_RX_WINDOW: + { + phyParam.Value = AU915_MAX_RX_WINDOW; + break; + } + case PHY_RECEIVE_DELAY1: + { + phyParam.Value = AU915_RECEIVE_DELAY1; + break; + } + case PHY_RECEIVE_DELAY2: + { + phyParam.Value = AU915_RECEIVE_DELAY2; + break; + } + case PHY_JOIN_ACCEPT_DELAY1: + { + phyParam.Value = AU915_JOIN_ACCEPT_DELAY1; + break; + } + case PHY_JOIN_ACCEPT_DELAY2: + { + phyParam.Value = AU915_JOIN_ACCEPT_DELAY2; + break; + } + case PHY_MAX_FCNT_GAP: + { + phyParam.Value = AU915_MAX_FCNT_GAP; + break; + } + case PHY_ACK_TIMEOUT: + { + phyParam.Value = (AU915_ACKTIMEOUT + randr(-AU915_ACK_TIMEOUT_RND, AU915_ACK_TIMEOUT_RND)); + break; + } + case PHY_DEF_DR1_OFFSET: + { + phyParam.Value = AU915_DEFAULT_RX1_DR_OFFSET; + break; + } + case PHY_DEF_RX2_FREQUENCY: + { + phyParam.Value = AU915_RX_WND_2_FREQ; + break; + } + case PHY_DEF_RX2_DR: + { + phyParam.Value = AU915_RX_WND_2_DR; + break; + } + case PHY_CHANNELS_MASK: + { + phyParam.ChannelsMask = ChannelsMask; + break; + } + case PHY_CHANNELS_DEFAULT_MASK: + { + phyParam.ChannelsMask = ChannelsDefaultMask; + break; + } + case PHY_MAX_NB_CHANNELS: + { + phyParam.Value = AU915_MAX_NB_CHANNELS; + break; + } + case PHY_CHANNELS: + { + phyParam.Channels = Channels; + break; + } + case PHY_DEF_UPLINK_DWELL_TIME: + case PHY_DEF_DOWNLINK_DWELL_TIME: + { + phyParam.Value = 0; + break; + } + case PHY_DEF_MAX_EIRP: + { + phyParam.fValue = AU915_DEFAULT_MAX_EIRP; + break; + } + case PHY_DEF_ANTENNA_GAIN: + { + phyParam.fValue = AU915_DEFAULT_ANTENNA_GAIN; + break; + } + case PHY_NB_JOIN_TRIALS: + case PHY_DEF_NB_JOIN_TRIALS: + { + phyParam.Value = 2; + break; + } + default: + { + break; + } + } + + return phyParam; + } + + void RegionAU915SetBandTxDone(SetBandTxDoneParams_t *txDone) + { + RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); + } + + void RegionAU915InitDefaults(InitType_t type) + { + switch (type) + { + case INIT_TYPE_INIT: + { + // Channels + // 125 kHz channels + for (uint8_t i = 0; i < AU915_MAX_NB_CHANNELS - 8; i++) + { + Channels[i].Frequency = 915200000 + i * 200000; + Channels[i].DrRange.Value = (DR_5 << 4) | DR_0; + Channels[i].Band = 0; + } + // 500 kHz channels + for (uint8_t i = AU915_MAX_NB_CHANNELS - 8; i < AU915_MAX_NB_CHANNELS; i++) + { + Channels[i].Frequency = 915900000 + (i - (AU915_MAX_NB_CHANNELS - 8)) * 1600000; + Channels[i].DrRange.Value = (DR_6 << 4) | DR_6; + Channels[i].Band = 0; + } + + // Initialize channels default mask + ChannelsDefaultMask[0] = 0xFFFF; + ChannelsDefaultMask[1] = 0xFFFF; + ChannelsDefaultMask[2] = 0xFFFF; + ChannelsDefaultMask[3] = 0xFFFF; + ChannelsDefaultMask[4] = 0x00FF; + ChannelsDefaultMask[5] = 0x0000; + + // Copy channels default mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); + + // Copy into channels mask remaining + RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 6); + break; + } + case INIT_TYPE_RESTORE: + { + // Copy channels default mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); + + for (uint8_t i = 0; i < 6; i++) + { // Copy-And the channels mask + ChannelsMaskRemaining[i] &= ChannelsMask[i]; + } + break; + } + case INIT_TYPE_APP_DEFAULTS: + { + // Copy channels default mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); + + // Copy into channels mask remaining + RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 6); + break; + } + default: + { + break; + } + } + } + + bool RegionAU915Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) + { + switch (phyAttribute) + { + case PHY_TX_DR: + case PHY_DEF_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, AU915_TX_MIN_DATARATE, AU915_TX_MAX_DATARATE); + } + case PHY_RX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE); + } + case PHY_DEF_TX_POWER: + case PHY_TX_POWER: + { + // Remark: switched min and max! + return RegionCommonValueInRange(verify->TxPower, AU915_MAX_TX_POWER, AU915_MIN_TX_POWER); + } + case PHY_DUTY_CYCLE: + { + return AU915_DUTY_CYCLE_ENABLED; + } + case PHY_NB_JOIN_TRIALS: + { + if (verify->NbJoinTrials < 2) + { + return false; + } + break; + } + default: + return false; + } + return true; + } + + void RegionAU915ApplyCFList(ApplyCFListParams_t *applyCFList) + { + return; + } + + bool RegionAU915ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) + { + uint8_t nbChannels = RegionCommonCountChannels(chanMaskSet->ChannelsMaskIn, 0, 4); + + // Check the number of active channels + // According to ACMA regulation, we require at least 20 125KHz channels, if + // the node shall utilize 125KHz channels. + if ((nbChannels < 20) && + (nbChannels > 0)) + { + return false; + } + + switch (chanMaskSet->ChannelsMaskType) + { + case CHANNELS_MASK: + { + RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 6); + + for (uint8_t i = 0; i < 6; i++) + { // Copy-And the channels mask + ChannelsMaskRemaining[i] &= ChannelsMask[i]; + } + break; + } + case CHANNELS_DEFAULT_MASK: + { + RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6); + break; + } + default: + return false; + } + return true; + } + + bool RegionAU915AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) + { + bool adrAckReq = false; + int8_t datarate = adrNext->Datarate; + int8_t txPower = adrNext->TxPower; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + + // Report back the adr ack counter + *adrAckCounter = adrNext->AdrAckCounter; + + if (adrNext->AdrEnabled == true) + { + if (datarate == AU915_TX_MIN_DATARATE) + { + *adrAckCounter = 0; + adrAckReq = false; + } + else + { + if (adrNext->AdrAckCounter >= AU915_ADR_ACK_LIMIT) + { + adrAckReq = true; + txPower = AU915_MAX_TX_POWER; + } + else + { + adrAckReq = false; + } + if (adrNext->AdrAckCounter >= (AU915_ADR_ACK_LIMIT + AU915_ADR_ACK_DELAY)) + { + if ((adrNext->AdrAckCounter % AU915_ADR_ACK_DELAY) == 1) + { + // Decrease the datarate + getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; + getPhy.Datarate = datarate; + getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; + phyParam = RegionAU915GetPhyParam(&getPhy); + datarate = phyParam.Value; + + if (datarate == AU915_TX_MIN_DATARATE) + { + // We must set adrAckReq to false as soon as we reach the lowest datarate + adrAckReq = false; + if (adrNext->UpdateChanMask == true) + { + // Re-enable default channels + ChannelsMask[0] = 0xFFFF; + ChannelsMask[1] = 0xFFFF; + ChannelsMask[2] = 0xFFFF; + ChannelsMask[3] = 0xFFFF; + ChannelsMask[4] = 0x00FF; + ChannelsMask[5] = 0x0000; + } + } + } + } + } + } + + *drOut = datarate; + *txPowOut = txPower; + return adrAckReq; + } + + void RegionAU915ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) + { + double tSymbol = 0.0; + + // Get the datarate, perform a boundary check + rxConfigParams->Datarate = MIN(datarate, AU915_RX_MAX_DATARATE); + rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); + + tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesAU915[rxConfigParams->Datarate], BandwidthsAU915[rxConfigParams->Datarate]); + + RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); + } + + bool RegionAU915RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) + { + int8_t dr = rxConfig->Datarate; + uint8_t maxPayload = 0; + int8_t phyDr = 0; + uint32_t frequency = rxConfig->Frequency; + + if (Radio.GetStatus() != RF_IDLE) + { + return false; + } + + if (rxConfig->Window == 0) + { + // Apply window 1 frequency + frequency = AU915_FIRST_RX1_CHANNEL + (rxConfig->Channel % 8) * AU915_STEPWIDTH_RX1_CHANNEL; + } + + // Read the physical datarate from the datarates table + phyDr = DataratesAU915[dr]; + + Radio.SetChannel(frequency); + + // Radio configuration + Radio.SetRxConfig(MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); + + if (rxConfig->RepeaterSupport == true) + { + maxPayload = MaxPayloadOfDatarateRepeaterAU915[dr]; + } + else + { + maxPayload = MaxPayloadOfDatarateAU915[dr]; + } + Radio.SetMaxPayloadLength(MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + *datarate = (uint8_t)dr; + return true; + } + + bool RegionAU915TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) + { + int8_t phyDr = DataratesAU915[txConfig->Datarate]; + int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); + uint32_t bandwidth = GetBandwidth(txConfig->Datarate); + int8_t phyTxPower = 0; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); + + // Setup the radio frequency + Radio.SetChannel(Channels[txConfig->Channel].Frequency); + + Radio.SetTxConfig(MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); + + // Setup maximum payload lenght of the radio driver + Radio.SetMaxPayloadLength(MODEM_LORA, txConfig->PktLen); + + *txTimeOnAir = Radio.TimeOnAir(MODEM_LORA, txConfig->PktLen); + *txPower = txPowerLimited; + + return true; + } + + uint8_t RegionAU915LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) + { + uint8_t status = 0x07; + RegionCommonLinkAdrParams_t linkAdrParams; + uint8_t nextIndex = 0; + uint8_t bytesProcessed = 0; + uint16_t channelsMask[6] = {0, 0, 0, 0, 0, 0}; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; + + // Initialize local copy of channels mask + RegionCommonChanMaskCopy(channelsMask, ChannelsMask, 6); + + while (bytesProcessed < linkAdrReq->PayloadSize) + { + nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); + + if (nextIndex == 0) + break; // break loop, since no more request has been found + + // Update bytes processed + bytesProcessed += nextIndex; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + if (linkAdrParams.ChMaskCtrl == 6) + { + // Enable all 125 kHz channels + channelsMask[0] = 0xFFFF; + channelsMask[1] = 0xFFFF; + channelsMask[2] = 0xFFFF; + channelsMask[3] = 0xFFFF; + // Apply chMask to channels 64 to 71 + channelsMask[4] = linkAdrParams.ChMask; + } + else if (linkAdrParams.ChMaskCtrl == 7) + { + // Disable all 125 kHz channels + channelsMask[0] = 0x0000; + channelsMask[1] = 0x0000; + channelsMask[2] = 0x0000; + channelsMask[3] = 0x0000; + // Apply chMask to channels 64 to 71 + channelsMask[4] = linkAdrParams.ChMask; + } + else if (linkAdrParams.ChMaskCtrl == 5) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask; + } + } + + // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels + if ((linkAdrParams.Datarate < DR_6) && (RegionCommonCountChannels(channelsMask, 0, 4) < 2)) + { + status &= 0xFE; // Channel mask KO + } + + // Get the minimum possible datarate + getPhy.Attribute = PHY_MIN_TX_DR; + getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; + phyParam = RegionAU915GetPhyParam(&getPhy); + + linkAdrVerifyParams.Status = status; + linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; + linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; + linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; + linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; + linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; + linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; + linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; + linkAdrVerifyParams.NbChannels = AU915_MAX_NB_CHANNELS; + linkAdrVerifyParams.ChannelsMask = channelsMask; + linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; + linkAdrVerifyParams.MaxDatarate = AU915_TX_MAX_DATARATE; + linkAdrVerifyParams.Channels = Channels; + linkAdrVerifyParams.MinTxPower = AU915_MIN_TX_POWER; + linkAdrVerifyParams.MaxTxPower = AU915_MAX_TX_POWER; + + // Verify the parameters and update, if necessary + status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); + + // Update channelsMask if everything is correct + if (status == 0x07) + { + // Copy Mask + RegionCommonChanMaskCopy(ChannelsMask, channelsMask, 6); + + ChannelsMaskRemaining[0] &= ChannelsMask[0]; + ChannelsMaskRemaining[1] &= ChannelsMask[1]; + ChannelsMaskRemaining[2] &= ChannelsMask[2]; + ChannelsMaskRemaining[3] &= ChannelsMask[3]; + ChannelsMaskRemaining[4] = ChannelsMask[4]; + ChannelsMaskRemaining[5] = ChannelsMask[5]; + } + + // Update status variables + *drOut = linkAdrParams.Datarate; + *txPowOut = linkAdrParams.TxPower; + *nbRepOut = linkAdrParams.NbRep; + *nbBytesParsed = bytesProcessed; + + return status; + } + + uint8_t RegionAU915RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) + { + uint8_t status = 0x07; + uint32_t freq = rxParamSetupReq->Frequency; + + // Verify radio frequency + if ((Radio.CheckRfFrequency(freq) == false) || + (freq < AU915_FIRST_RX1_CHANNEL) || + (freq > AU915_LAST_RX1_CHANNEL) || + (((freq - (uint32_t)AU915_FIRST_RX1_CHANNEL) % (uint32_t)AU915_STEPWIDTH_RX1_CHANNEL) != 0)) + { + status &= 0xFE; // Channel frequency KO + } + + // Verify datarate + if (RegionCommonValueInRange(rxParamSetupReq->Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE) == false) + { + status &= 0xFD; // Datarate KO + } + if ((rxParamSetupReq->Datarate == DR_7) || + (rxParamSetupReq->Datarate > DR_13)) + { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, AU915_MIN_RX1_DR_OFFSET, AU915_MAX_RX1_DR_OFFSET) == false) + { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; + } + + uint8_t RegionAU915NewChannelReq(NewChannelReqParams_t *newChannelReq) + { + // Datarate and frequency KO + return 0; + } + + int8_t RegionAU915TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) + { + return -1; + } + + uint8_t RegionAU915DlChannelReq(DlChannelReqParams_t *dlChannelReq) + { + return 0; + } + + int8_t RegionAU915AlternateDr(AlternateDrParams_t *alternateDr) + { + int8_t datarate = 0; + + // Re-enable 500 kHz default channels + ChannelsMask[4] = 0x00FF; + + if ((alternateDr->NbTrials & 0x01) == 0x01) + { + datarate = DR_6; + } + else + { + datarate = DR_0; + } + return datarate; + } + + void RegionAU915CalcBackOff(CalcBackOffParams_t *calcBackOff) + { + RegionCommonCalcBackOffParams_t calcBackOffParams; + + calcBackOffParams.Channels = Channels; + calcBackOffParams.Bands = Bands; + calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; + calcBackOffParams.Joined = calcBackOff->Joined; + calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; + calcBackOffParams.Channel = calcBackOff->Channel; + calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; + calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; + + RegionCommonCalcBackOff(&calcBackOffParams); + } + + bool RegionAU915NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTx = 0; + uint8_t enabledChannels[AU915_MAX_NB_CHANNELS] = {0}; + TimerTime_t nextTxDelay = 0; + + // Count 125kHz channels + if (RegionCommonCountChannels(ChannelsMaskRemaining, 0, 4) == 0) + { // Reactivate default channels + RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 4); + } + // Check other channels + if (nextChanParams->Datarate >= DR_6) + { + if ((ChannelsMaskRemaining[4] & 0x00FF) == 0) + { + ChannelsMaskRemaining[4] = ChannelsMask[4]; + } + } + + if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) + { + // Reset Aggregated time off + *aggregatedTimeOff = 0; + + // Update bands Time OFF + nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, AU915_MAX_NB_BANDS); + + // Search how many channels are enabled + nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Datarate, + ChannelsMaskRemaining, Channels, + Bands, enabledChannels, &delayTx); + } + else + { + delayTx++; + nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); + } + + if (nbEnabledChannels > 0) + { + // We found a valid channel + *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; + // Disable the channel in the mask + RegionCommonChanDisable(ChannelsMaskRemaining, *channel, AU915_MAX_NB_CHANNELS - 8); + + *time = 0; + return true; + } + else + { + if (delayTx > 0) + { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return true; + } + // Datarate not supported by any channel + *time = 0; + return false; + } + } + + LoRaMacStatus_t RegionAU915ChannelAdd(ChannelAddParams_t *channelAdd) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + bool RegionAU915ChannelsRemove(ChannelRemoveParams_t *channelRemove) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + void RegionAU915SetContinuousWave(ContinuousWaveParams_t *continuousWave) + { + int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); + int8_t phyTxPower = 0; + uint32_t frequency = Channels[continuousWave->Channel].Frequency; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); + + Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); + } + + uint8_t RegionAU915ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) + { + int8_t datarate = DatarateOffsetsAU915[dr][drOffset]; + + if (datarate < 0) + { + datarate = DR_0; + } + return datarate; + } }; \ No newline at end of file diff --git a/src/mac/region/RegionAU915.h b/src/mac/region/RegionAU915.h index 12a2649..32d2ee9 100644 --- a/src/mac/region/RegionAU915.h +++ b/src/mac/region/RegionAU915.h @@ -41,222 +41,225 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define AU915_MAX_NB_CHANNELS 72 +#define AU915_MAX_NB_CHANNELS 72 /*! * Minimal datarate that can be used by the node */ -#define AU915_TX_MIN_DATARATE DR_0 +#define AU915_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define AU915_TX_MAX_DATARATE DR_6 +#define AU915_TX_MAX_DATARATE DR_6 /*! * Minimal datarate that can be used by the node */ -#define AU915_RX_MIN_DATARATE DR_8 +#define AU915_RX_MIN_DATARATE DR_8 /*! * Maximal datarate that can be used by the node */ -#define AU915_RX_MAX_DATARATE DR_13 +#define AU915_RX_MAX_DATARATE DR_13 /*! * Default datarate used by the node */ -#define AU915_DEFAULT_DATARATE DR_0 +#define AU915_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define AU915_MIN_RX1_DR_OFFSET 0 +#define AU915_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define AU915_MAX_RX1_DR_OFFSET 6 +#define AU915_MAX_RX1_DR_OFFSET 6 /*! * Default Rx1 receive datarate offset */ -#define AU915_DEFAULT_RX1_DR_OFFSET 0 +#define AU915_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define AU915_MIN_TX_POWER TX_POWER_10 +#define AU915_MIN_TX_POWER TX_POWER_10 /*! * Maximal Tx output power that can be used by the node */ -#define AU915_MAX_TX_POWER TX_POWER_0 +#define AU915_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define AU915_DEFAULT_TX_POWER TX_POWER_0 +#define AU915_DEFAULT_TX_POWER TX_POWER_0 /*! * Default Max EIRP */ -#define AU915_DEFAULT_MAX_EIRP 30.0f +#define AU915_DEFAULT_MAX_EIRP 30.0f /*! * Default antenna gain */ -#define AU915_DEFAULT_ANTENNA_GAIN 2.15f +#define AU915_DEFAULT_ANTENNA_GAIN 2.15f /*! * ADR Ack limit */ -#define AU915_ADR_ACK_LIMIT 64 +#define AU915_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define AU915_ADR_ACK_DELAY 32 +#define AU915_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define AU915_DUTY_CYCLE_ENABLED 0 +#define AU915_DUTY_CYCLE_ENABLED 0 /*! * Maximum RX window duration */ -#define AU915_MAX_RX_WINDOW 3000 +#define AU915_MAX_RX_WINDOW 3000 /*! * Receive delay 1 */ -#define AU915_RECEIVE_DELAY1 1000 +#define AU915_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define AU915_RECEIVE_DELAY2 2000 +#define AU915_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define AU915_JOIN_ACCEPT_DELAY1 5000 +#define AU915_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define AU915_JOIN_ACCEPT_DELAY2 6000 +#define AU915_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define AU915_MAX_FCNT_GAP 16384 +#define AU915_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define AU915_ACKTIMEOUT 2000 +#define AU915_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define AU915_ACK_TIMEOUT_RND 1000 +#define AU915_ACK_TIMEOUT_RND 1000 /*! * Second reception window channel frequency definition. */ -#define AU915_RX_WND_2_FREQ 923300000 +#define AU915_RX_WND_2_FREQ 923300000 /*! * Second reception window channel datarate definition. */ -#define AU915_RX_WND_2_DR DR_8 +#define AU915_RX_WND_2_DR DR_8 /*! * LoRaMac maximum number of bands */ -#define AU915_MAX_NB_BANDS 1 +#define AU915_MAX_NB_BANDS 1 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define AU915_BAND0 { 1, AU915_MAX_TX_POWER, 0, 0 } // 100.0 % +#define AU915_BAND0 \ + { \ + 1, AU915_MAX_TX_POWER, 0, 0 \ + } // 100.0 % /*! * Defines the first channel for RX window 1 for US band */ -#define AU915_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 ) +#define AU915_FIRST_RX1_CHANNEL ((uint32_t)923300000) /*! * Defines the last channel for RX window 1 for US band */ -#define AU915_LAST_RX1_CHANNEL ( (uint32_t) 927500000 ) +#define AU915_LAST_RX1_CHANNEL ((uint32_t)927500000) /*! * Defines the step width of the channels for RX window 1 */ -#define AU915_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 ) +#define AU915_STEPWIDTH_RX1_CHANNEL ((uint32_t)600000) -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesAU915[] = { 12, 11, 10, 9, 8, 7, 8, 0, 12, 11, 10, 9, 8, 7, 0, 0 }; + static const uint8_t DataratesAU915[] = {12, 11, 10, 9, 8, 7, 8, 0, 12, 11, 10, 9, 8, 7, 0, 0}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsAU915[] = { 125000, 125000, 125000, 125000, 125000, 125000, 500000, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 }; + static const uint32_t BandwidthsAU915[] = {125000, 125000, 125000, 125000, 125000, 125000, 500000, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0}; -/*! + /*! * Up/Down link data rates offset definition */ -static const int8_t DatarateOffsetsAU915[7][6] = -{ - { DR_8 , DR_8 , DR_8 , DR_8 , DR_8 , DR_8 }, // DR_0 - { DR_9 , DR_8 , DR_8 , DR_8 , DR_8 , DR_8 }, // DR_1 - { DR_10, DR_9 , DR_8 , DR_8 , DR_8 , DR_8 }, // DR_2 - { DR_11, DR_10, DR_9 , DR_8 , DR_8 , DR_8 }, // DR_3 - { DR_12, DR_11, DR_10, DR_9 , DR_8 , DR_8 }, // DR_4 - { DR_13, DR_12, DR_11, DR_10, DR_9 , DR_8 }, // DR_5 - { DR_13, DR_13, DR_12, DR_11, DR_10, DR_9 }, // DR_6 -}; - -/*! + static const int8_t DatarateOffsetsAU915[7][6] = + { + {DR_8, DR_8, DR_8, DR_8, DR_8, DR_8}, // DR_0 + {DR_9, DR_8, DR_8, DR_8, DR_8, DR_8}, // DR_1 + {DR_10, DR_9, DR_8, DR_8, DR_8, DR_8}, // DR_2 + {DR_11, DR_10, DR_9, DR_8, DR_8, DR_8}, // DR_3 + {DR_12, DR_11, DR_10, DR_9, DR_8, DR_8}, // DR_4 + {DR_13, DR_12, DR_11, DR_10, DR_9, DR_8}, // DR_5 + {DR_13, DR_13, DR_12, DR_11, DR_10, DR_9}, // DR_6 + }; + + /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateAU915[] = { 51, 51, 51, 115, 242, 242, 242, 0, 53, 129, 242, 242, 242, 242, 0, 0 }; + static const uint8_t MaxPayloadOfDatarateAU915[] = {51, 51, 51, 115, 242, 242, 242, 0, 53, 129, 242, 242, 242, 242, 0, 0}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateRepeaterAU915[] = { 51, 51, 51, 115, 222, 222, 222, 0, 33, 109, 222, 222, 222, 222, 0, 0 }; + static const uint8_t MaxPayloadOfDatarateRepeaterAU915[] = {51, 51, 51, 115, 222, 222, 222, 0, 33, 109, 222, 222, 222, 222, 0, 0}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionAU915GetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionAU915SetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionAU915SetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionAU915InitDefaults( InitType_t type ); + void RegionAU915InitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -265,26 +268,26 @@ void RegionAU915InitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionAU915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionAU915Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionAU915ApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionAU915ApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionAU915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionAU915ChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -297,9 +300,9 @@ bool RegionAU915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionAU915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionAU915AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -312,9 +315,9 @@ bool RegionAU915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowO * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionAU915ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -323,9 +326,9 @@ void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionAU915RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -336,36 +339,36 @@ bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionAU915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionAU915TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionAU915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionAU915LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionAU915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionAU915RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionAU915NewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionAU915NewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -374,34 +377,34 @@ uint8_t RegionAU915NewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionAU915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionAU915TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionAU915DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionAU915DlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionAU915AlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionAU915AlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionAU915CalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionAU915CalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -413,34 +416,34 @@ void RegionAU915CalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionAU915NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionAU915ChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionAU915ChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionAU915ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionAU915ChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionAU915SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionAU915SetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -451,8 +454,8 @@ void RegionAU915SetContinuousWave( ContinuousWaveParams_t* continuousWave ); * * \retval newDr Computed datarate. */ -uint8_t RegionAU915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionAU915ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONAU915 */ + /*! \} defgroup REGIONAU915 */ }; #endif // __REGION_AU915_H__ diff --git a/src/mac/region/RegionCN470.cpp b/src/mac/region/RegionCN470.cpp index 6e8268f..15470ea 100644 --- a/src/mac/region/RegionCN470.cpp +++ b/src/mac/region/RegionCN470.cpp @@ -37,780 +37,780 @@ extern "C" // Definitions #define CHANNELS_MASK_SIZE 6 - // Global attributes - /*! + // Global attributes + /*! * LoRaMAC channels */ - static ChannelParams_t Channels[CN470_MAX_NB_CHANNELS]; + static ChannelParams_t Channels[CN470_MAX_NB_CHANNELS]; - /*! + /*! * LoRaMac bands */ - static Band_t Bands[CN470_MAX_NB_BANDS] = - { - CN470_BAND0}; + static Band_t Bands[CN470_MAX_NB_BANDS] = + { + CN470_BAND0}; - /*! + /*! * LoRaMac channels mask */ - static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; + static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; - /*! + /*! * LoRaMac channels default mask */ - static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; - - // Static functions - static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) - { - uint8_t nextLowerDr = 0; - - if (dr == minDr) - { - nextLowerDr = minDr; - } - else - { - nextLowerDr = dr - 1; - } - return nextLowerDr; - } - - static uint32_t GetBandwidth(uint32_t drIndex) - { - switch (BandwidthsCN470[drIndex]) - { - default: - case 125000: - return 0; - case 250000: - return 1; - case 500000: - return 2; - } - } - - static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) - { - int8_t txPowerResult = txPower; - - // Limit tx power to the band max - txPowerResult = MAX(txPower, maxBandTxPower); - - return txPowerResult; - } - - static uint8_t CountNbOfEnabledChannels(uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTransmission = 0; - - for (uint8_t i = 0, k = 0; i < CN470_MAX_NB_CHANNELS; i += 16, k++) - { - for (uint8_t j = 0; j < 16; j++) - { - if ((channelsMask[k] & (1 << j)) != 0) - { - if (channels[i + j].Frequency == 0) - { // Check if the channel is enabled - continue; - } - if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, - channels[i + j].DrRange.Fields.Max) == false) - { // Check if the current channel selection supports the given datarate - continue; - } - if (bands[channels[i + j].Band].TimeOff > 0) - { // Check if the band is available for transmission - delayTransmission++; - continue; - } - enabledChannels[nbEnabledChannels++] = i + j; - } - } - } - - *delayTx = delayTransmission; - return nbEnabledChannels; - } - - PhyParam_t RegionCN470GetPhyParam(GetPhyParams_t *getPhy) - { - PhyParam_t phyParam = {0}; - - switch (getPhy->Attribute) - { - case PHY_MIN_RX_DR: - { - phyParam.Value = CN470_RX_MIN_DATARATE; - break; - } - case PHY_MIN_TX_DR: - { - phyParam.Value = CN470_TX_MIN_DATARATE; - break; - } - case PHY_DEF_TX_DR: - { - phyParam.Value = CN470_DEFAULT_DATARATE; - break; - } - case PHY_NEXT_LOWER_TX_DR: - { - phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, CN470_TX_MIN_DATARATE); - break; - } - case PHY_DEF_TX_POWER: - { - phyParam.Value = CN470_DEFAULT_TX_POWER; - break; - } - case PHY_MAX_PAYLOAD: - { - phyParam.Value = MaxPayloadOfDatarateCN470[getPhy->Datarate]; - break; - } - case PHY_MAX_PAYLOAD_REPEATER: - { - phyParam.Value = MaxPayloadOfDatarateRepeaterCN470[getPhy->Datarate]; - break; - } - case PHY_DUTY_CYCLE: - { - phyParam.Value = CN470_DUTY_CYCLE_ENABLED; - break; - } - case PHY_MAX_RX_WINDOW: - { - phyParam.Value = CN470_MAX_RX_WINDOW; - break; - } - case PHY_RECEIVE_DELAY1: - { - phyParam.Value = CN470_RECEIVE_DELAY1; - break; - } - case PHY_RECEIVE_DELAY2: - { - phyParam.Value = CN470_RECEIVE_DELAY2; - break; - } - case PHY_JOIN_ACCEPT_DELAY1: - { - phyParam.Value = CN470_JOIN_ACCEPT_DELAY1; - break; - } - case PHY_JOIN_ACCEPT_DELAY2: - { - phyParam.Value = CN470_JOIN_ACCEPT_DELAY2; - break; - } - case PHY_MAX_FCNT_GAP: - { - phyParam.Value = CN470_MAX_FCNT_GAP; - break; - } - case PHY_ACK_TIMEOUT: - { - phyParam.Value = (CN470_ACKTIMEOUT + randr(-CN470_ACK_TIMEOUT_RND, CN470_ACK_TIMEOUT_RND)); - break; - } - case PHY_DEF_DR1_OFFSET: - { - phyParam.Value = CN470_DEFAULT_RX1_DR_OFFSET; - break; - } - case PHY_DEF_RX2_FREQUENCY: - { - phyParam.Value = CN470_RX_WND_2_FREQ; - break; - } - case PHY_DEF_RX2_DR: - { - phyParam.Value = CN470_RX_WND_2_DR; - break; - } - case PHY_CHANNELS_MASK: - { - phyParam.ChannelsMask = ChannelsMask; - break; - } - case PHY_CHANNELS_DEFAULT_MASK: - { - phyParam.ChannelsMask = ChannelsDefaultMask; - break; - } - case PHY_MAX_NB_CHANNELS: - { - phyParam.Value = CN470_MAX_NB_CHANNELS; - break; - } - case PHY_CHANNELS: - { - phyParam.Channels = Channels; - break; - } - case PHY_DEF_UPLINK_DWELL_TIME: - case PHY_DEF_DOWNLINK_DWELL_TIME: - { - phyParam.Value = 0; - break; - } - case PHY_DEF_MAX_EIRP: - { - phyParam.fValue = CN470_DEFAULT_MAX_EIRP; - break; - } - case PHY_DEF_ANTENNA_GAIN: - { - phyParam.fValue = CN470_DEFAULT_ANTENNA_GAIN; - break; - } - case PHY_NB_JOIN_TRIALS: - case PHY_DEF_NB_JOIN_TRIALS: - { - phyParam.Value = 48; - break; - } - default: - { - break; - } - } - - return phyParam; - } - - void RegionCN470SetBandTxDone(SetBandTxDoneParams_t *txDone) - { - RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); - } - - void RegionCN470InitDefaults(InitType_t type) - { - switch (type) - { - case INIT_TYPE_INIT: - { - // Channels - // 125 kHz channels - for (uint8_t i = 0; i < CN470_MAX_NB_CHANNELS; i++) - { - Channels[i].Frequency = 470300000 + i * 200000; - Channels[i].DrRange.Value = (DR_5 << 4) | DR_0; - Channels[i].Band = 0; - } - - // Initialize the channels default mask - ChannelsDefaultMask[0] = 0xFFFF; - ChannelsDefaultMask[1] = 0xFFFF; - ChannelsDefaultMask[2] = 0xFFFF; - ChannelsDefaultMask[3] = 0xFFFF; - ChannelsDefaultMask[4] = 0xFFFF; - ChannelsDefaultMask[5] = 0xFFFF; - - // Update the channels mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); - break; - } - case INIT_TYPE_RESTORE: - { - // Restore channels default mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); - break; - } - case INIT_TYPE_APP_DEFAULTS: - { - // Update the channels mask defaults - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); - break; - } - default: - { - break; - } - } - } - - bool RegionCN470Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) - { - switch (phyAttribute) - { - case PHY_TX_DR: - case PHY_DEF_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, CN470_TX_MIN_DATARATE, CN470_TX_MAX_DATARATE); - } - case PHY_RX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE); - } - case PHY_DEF_TX_POWER: - case PHY_TX_POWER: - { - // Remark: switched min and max! - return RegionCommonValueInRange(verify->TxPower, CN470_MAX_TX_POWER, CN470_MIN_TX_POWER); - } - case PHY_DUTY_CYCLE: - { - return CN470_DUTY_CYCLE_ENABLED; - } - case PHY_NB_JOIN_TRIALS: - { - if (verify->NbJoinTrials < 48) - { - return false; - } - break; - } - default: - return false; - } - return true; - } - - void RegionCN470ApplyCFList(ApplyCFListParams_t *applyCFList) - { - return; - } - - bool RegionCN470ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) - { - switch (chanMaskSet->ChannelsMaskType) - { - case CHANNELS_MASK: - { - RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 6); - break; - } - case CHANNELS_DEFAULT_MASK: - { - RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6); - break; - } - default: - return false; - } - return true; - } - - bool RegionCN470AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) - { - bool adrAckReq = false; - int8_t datarate = adrNext->Datarate; - int8_t txPower = adrNext->TxPower; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - - // Report back the adr ack counter - *adrAckCounter = adrNext->AdrAckCounter; - - if (adrNext->AdrEnabled == true) - { - if (datarate == CN470_TX_MIN_DATARATE) - { - *adrAckCounter = 0; - adrAckReq = false; - } - else - { - if (adrNext->AdrAckCounter >= CN470_ADR_ACK_LIMIT) - { - adrAckReq = true; - txPower = CN470_MAX_TX_POWER; - } - else - { - adrAckReq = false; - } - if (adrNext->AdrAckCounter >= (CN470_ADR_ACK_LIMIT + CN470_ADR_ACK_DELAY)) - { - if ((adrNext->AdrAckCounter % CN470_ADR_ACK_DELAY) == 1) - { - // Decrease the datarate - getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; - getPhy.Datarate = datarate; - getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; - phyParam = RegionCN470GetPhyParam(&getPhy); - datarate = phyParam.Value; - - if (datarate == CN470_TX_MIN_DATARATE) - { - // We must set adrAckReq to false as soon as we reach the lowest datarate - adrAckReq = false; - if (adrNext->UpdateChanMask == true) - { - // Re-enable default channels - ChannelsMask[0] = 0xFFFF; - ChannelsMask[1] = 0xFFFF; - ChannelsMask[2] = 0xFFFF; - ChannelsMask[3] = 0xFFFF; - ChannelsMask[4] = 0xFFFF; - ChannelsMask[5] = 0xFFFF; - } - } - } - } - } - } - - *drOut = datarate; - *txPowOut = txPower; - return adrAckReq; - } - - void RegionCN470ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) - { - double tSymbol = 0.0; - - // Get the datarate, perform a boundary check - rxConfigParams->Datarate = MIN(datarate, CN470_RX_MAX_DATARATE); - rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); - - tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesCN470[rxConfigParams->Datarate], BandwidthsCN470[rxConfigParams->Datarate]); - - RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); - } - - bool RegionCN470RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) - { - int8_t dr = rxConfig->Datarate; - uint8_t maxPayload = 0; - int8_t phyDr = 0; - uint32_t frequency = rxConfig->Frequency; - - if (Radio.GetStatus() != RF_IDLE) - { - return false; - } - - if (rxConfig->Window == 0) - { - // Apply window 1 frequency - frequency = CN470_FIRST_RX1_CHANNEL + (rxConfig->Channel % 48) * CN470_STEPWIDTH_RX1_CHANNEL; - } - - // Read the physical datarate from the datarates table - phyDr = DataratesCN470[dr]; - - Radio.SetChannel(frequency); - - // Radio configuration - Radio.SetRxConfig(MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); - - if (rxConfig->RepeaterSupport == true) - { - maxPayload = MaxPayloadOfDatarateRepeaterCN470[dr]; - } - else - { - maxPayload = MaxPayloadOfDatarateCN470[dr]; - } - Radio.SetMaxPayloadLength(MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - *datarate = (uint8_t)dr; - return true; - } - - bool RegionCN470TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) - { - int8_t phyDr = DataratesCN470[txConfig->Datarate]; - int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); - int8_t phyTxPower = 0; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); - - // Setup the radio frequency - Radio.SetChannel(Channels[txConfig->Channel].Frequency); - - Radio.SetTxConfig(MODEM_LORA, phyTxPower, 0, 0, phyDr, 1, 8, false, true, 0, 0, false, 3000); - // Setup maximum payload lenght of the radio driver - Radio.SetMaxPayloadLength(MODEM_LORA, txConfig->PktLen); - // Get the time-on-air of the next tx frame - *txTimeOnAir = Radio.TimeOnAir(MODEM_LORA, txConfig->PktLen); - *txPower = txPowerLimited; - - return true; - } - - uint8_t RegionCN470LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) - { - uint8_t status = 0x07; - RegionCommonLinkAdrParams_t linkAdrParams; - uint8_t nextIndex = 0; - uint8_t bytesProcessed = 0; - uint16_t channelsMask[6] = {0, 0, 0, 0, 0, 0}; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; - - // Initialize local copy of channels mask - RegionCommonChanMaskCopy(channelsMask, ChannelsMask, 6); - - while (bytesProcessed < linkAdrReq->PayloadSize) - { - // Get ADR request parameters - nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); - - if (nextIndex == 0) - break; // break loop, since no more request has been found - - // Update bytes processed - bytesProcessed += nextIndex; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - if (linkAdrParams.ChMaskCtrl == 6) - { - // Enable all 125 kHz channels - channelsMask[0] = 0xFFFF; - channelsMask[1] = 0xFFFF; - channelsMask[2] = 0xFFFF; - channelsMask[3] = 0xFFFF; - channelsMask[4] = 0xFFFF; - channelsMask[5] = 0xFFFF; - } - else if (linkAdrParams.ChMaskCtrl == 7) - { - status &= 0xFE; // Channel mask KO - } - else - { - for (uint8_t i = 0; i < 16; i++) - { - if (((linkAdrParams.ChMask & (1 << i)) != 0) && - (Channels[linkAdrParams.ChMaskCtrl * 16 + i].Frequency == 0)) - { // Trying to enable an undefined channel - status &= 0xFE; // Channel mask KO - } - } - channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask; - } - } - - // Get the minimum possible datarate - getPhy.Attribute = PHY_MIN_TX_DR; - getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; - phyParam = RegionCN470GetPhyParam(&getPhy); - - linkAdrVerifyParams.Status = status; - linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; - linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; - linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; - linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; - linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; - linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; - linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; - linkAdrVerifyParams.NbChannels = CN470_MAX_NB_CHANNELS; - linkAdrVerifyParams.ChannelsMask = channelsMask; - linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; - linkAdrVerifyParams.MaxDatarate = CN470_TX_MAX_DATARATE; - linkAdrVerifyParams.Channels = Channels; - linkAdrVerifyParams.MinTxPower = CN470_MIN_TX_POWER; - linkAdrVerifyParams.MaxTxPower = CN470_MAX_TX_POWER; - - // Verify the parameters and update, if necessary - status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); - - // Update channelsMask if everything is correct - if (status == 0x07) - { - // Copy Mask - RegionCommonChanMaskCopy(ChannelsMask, channelsMask, 6); - } - - // Update status variables - *drOut = linkAdrParams.Datarate; - *txPowOut = linkAdrParams.TxPower; - *nbRepOut = linkAdrParams.NbRep; - *nbBytesParsed = bytesProcessed; - - return status; - } - - uint8_t RegionCN470RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) - { - uint8_t status = 0x07; - uint32_t freq = rxParamSetupReq->Frequency; - - // Verify radio frequency - if ((Radio.CheckRfFrequency(freq) == false) || - (freq < CN470_FIRST_RX1_CHANNEL) || - (freq > CN470_LAST_RX1_CHANNEL) || - (((freq - (uint32_t)CN470_FIRST_RX1_CHANNEL) % (uint32_t)CN470_STEPWIDTH_RX1_CHANNEL) != 0)) - { - status &= 0xFE; // Channel frequency KO - } - - // Verify datarate - if (RegionCommonValueInRange(rxParamSetupReq->Datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE) == false) - { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, CN470_MIN_RX1_DR_OFFSET, CN470_MAX_RX1_DR_OFFSET) == false) - { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; - } - - uint8_t RegionCN470NewChannelReq(NewChannelReqParams_t *newChannelReq) - { - // Datarate and frequency KO - return 0; - } - - int8_t RegionCN470TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) - { - return -1; - } - - uint8_t RegionCN470DlChannelReq(DlChannelReqParams_t *dlChannelReq) - { - return 0; - } - - int8_t RegionCN470AlternateDr(AlternateDrParams_t *alternateDr) - { - int8_t datarate = 0; - - if ((alternateDr->NbTrials % 48) == 0) - { - datarate = DR_0; - } - else if ((alternateDr->NbTrials % 32) == 0) - { - datarate = DR_1; - } - else if ((alternateDr->NbTrials % 24) == 0) - { - datarate = DR_2; - } - else if ((alternateDr->NbTrials % 16) == 0) - { - datarate = DR_3; - } - else if ((alternateDr->NbTrials % 8) == 0) - { - datarate = DR_4; - } - else - { - datarate = DR_5; - } - return datarate; - } - - void RegionCN470CalcBackOff(CalcBackOffParams_t *calcBackOff) - { - RegionCommonCalcBackOffParams_t calcBackOffParams; - - calcBackOffParams.Channels = Channels; - calcBackOffParams.Bands = Bands; - calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; - calcBackOffParams.Joined = calcBackOff->Joined; - calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; - calcBackOffParams.Channel = calcBackOff->Channel; - calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; - calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; - - RegionCommonCalcBackOff(&calcBackOffParams); - } - - bool RegionCN470NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTx = 0; - uint8_t enabledChannels[CN470_MAX_NB_CHANNELS] = {0}; - TimerTime_t nextTxDelay = 0; - - // Count 125kHz channels - if (RegionCommonCountChannels(ChannelsMask, 0, 6) == 0) - { // Reactivate default channels - ChannelsMask[0] = 0xFFFF; - ChannelsMask[1] = 0xFFFF; - ChannelsMask[2] = 0xFFFF; - ChannelsMask[3] = 0xFFFF; - ChannelsMask[4] = 0xFFFF; - ChannelsMask[5] = 0xFFFF; - } - - if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) - { - // Reset Aggregated time off - *aggregatedTimeOff = 0; - - // Update bands Time OFF - nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, CN470_MAX_NB_BANDS); - - // Search how many channels are enabled - nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Datarate, - ChannelsMask, Channels, - Bands, enabledChannels, &delayTx); - } - else - { - delayTx++; - nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); - } - - if (nbEnabledChannels > 0) - { - // We found a valid channel - *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; - - *time = 0; - return true; - } - else - { - if (delayTx > 0) - { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = nextTxDelay; - return true; - } - // Datarate not supported by any channel - *time = 0; - return false; - } - } - - LoRaMacStatus_t RegionCN470ChannelAdd(ChannelAddParams_t *channelAdd) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - bool RegionCN470ChannelsRemove(ChannelRemoveParams_t *channelRemove) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - void RegionCN470SetContinuousWave(ContinuousWaveParams_t *continuousWave) - { - int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); - int8_t phyTxPower = 0; - uint32_t frequency = Channels[continuousWave->Channel].Frequency; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); - - Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); - } - - uint8_t RegionCN470ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) - { - int8_t datarate = dr - drOffset; - - if (datarate < 0) - { - datarate = DR_0; - } - return datarate; - } + static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; + + // Static functions + static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) + { + uint8_t nextLowerDr = 0; + + if (dr == minDr) + { + nextLowerDr = minDr; + } + else + { + nextLowerDr = dr - 1; + } + return nextLowerDr; + } + + static uint32_t GetBandwidth(uint32_t drIndex) + { + switch (BandwidthsCN470[drIndex]) + { + default: + case 125000: + return 0; + case 250000: + return 1; + case 500000: + return 2; + } + } + + static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) + { + int8_t txPowerResult = txPower; + + // Limit tx power to the band max + txPowerResult = MAX(txPower, maxBandTxPower); + + return txPowerResult; + } + + static uint8_t CountNbOfEnabledChannels(uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTransmission = 0; + + for (uint8_t i = 0, k = 0; i < CN470_MAX_NB_CHANNELS; i += 16, k++) + { + for (uint8_t j = 0; j < 16; j++) + { + if ((channelsMask[k] & (1 << j)) != 0) + { + if (channels[i + j].Frequency == 0) + { // Check if the channel is enabled + continue; + } + if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, + channels[i + j].DrRange.Fields.Max) == false) + { // Check if the current channel selection supports the given datarate + continue; + } + if (bands[channels[i + j].Band].TimeOff > 0) + { // Check if the band is available for transmission + delayTransmission++; + continue; + } + enabledChannels[nbEnabledChannels++] = i + j; + } + } + } + + *delayTx = delayTransmission; + return nbEnabledChannels; + } + + PhyParam_t RegionCN470GetPhyParam(GetPhyParams_t *getPhy) + { + PhyParam_t phyParam = {0}; + + switch (getPhy->Attribute) + { + case PHY_MIN_RX_DR: + { + phyParam.Value = CN470_RX_MIN_DATARATE; + break; + } + case PHY_MIN_TX_DR: + { + phyParam.Value = CN470_TX_MIN_DATARATE; + break; + } + case PHY_DEF_TX_DR: + { + phyParam.Value = CN470_DEFAULT_DATARATE; + break; + } + case PHY_NEXT_LOWER_TX_DR: + { + phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, CN470_TX_MIN_DATARATE); + break; + } + case PHY_DEF_TX_POWER: + { + phyParam.Value = CN470_DEFAULT_TX_POWER; + break; + } + case PHY_MAX_PAYLOAD: + { + phyParam.Value = MaxPayloadOfDatarateCN470[getPhy->Datarate]; + break; + } + case PHY_MAX_PAYLOAD_REPEATER: + { + phyParam.Value = MaxPayloadOfDatarateRepeaterCN470[getPhy->Datarate]; + break; + } + case PHY_DUTY_CYCLE: + { + phyParam.Value = CN470_DUTY_CYCLE_ENABLED; + break; + } + case PHY_MAX_RX_WINDOW: + { + phyParam.Value = CN470_MAX_RX_WINDOW; + break; + } + case PHY_RECEIVE_DELAY1: + { + phyParam.Value = CN470_RECEIVE_DELAY1; + break; + } + case PHY_RECEIVE_DELAY2: + { + phyParam.Value = CN470_RECEIVE_DELAY2; + break; + } + case PHY_JOIN_ACCEPT_DELAY1: + { + phyParam.Value = CN470_JOIN_ACCEPT_DELAY1; + break; + } + case PHY_JOIN_ACCEPT_DELAY2: + { + phyParam.Value = CN470_JOIN_ACCEPT_DELAY2; + break; + } + case PHY_MAX_FCNT_GAP: + { + phyParam.Value = CN470_MAX_FCNT_GAP; + break; + } + case PHY_ACK_TIMEOUT: + { + phyParam.Value = (CN470_ACKTIMEOUT + randr(-CN470_ACK_TIMEOUT_RND, CN470_ACK_TIMEOUT_RND)); + break; + } + case PHY_DEF_DR1_OFFSET: + { + phyParam.Value = CN470_DEFAULT_RX1_DR_OFFSET; + break; + } + case PHY_DEF_RX2_FREQUENCY: + { + phyParam.Value = CN470_RX_WND_2_FREQ; + break; + } + case PHY_DEF_RX2_DR: + { + phyParam.Value = CN470_RX_WND_2_DR; + break; + } + case PHY_CHANNELS_MASK: + { + phyParam.ChannelsMask = ChannelsMask; + break; + } + case PHY_CHANNELS_DEFAULT_MASK: + { + phyParam.ChannelsMask = ChannelsDefaultMask; + break; + } + case PHY_MAX_NB_CHANNELS: + { + phyParam.Value = CN470_MAX_NB_CHANNELS; + break; + } + case PHY_CHANNELS: + { + phyParam.Channels = Channels; + break; + } + case PHY_DEF_UPLINK_DWELL_TIME: + case PHY_DEF_DOWNLINK_DWELL_TIME: + { + phyParam.Value = 0; + break; + } + case PHY_DEF_MAX_EIRP: + { + phyParam.fValue = CN470_DEFAULT_MAX_EIRP; + break; + } + case PHY_DEF_ANTENNA_GAIN: + { + phyParam.fValue = CN470_DEFAULT_ANTENNA_GAIN; + break; + } + case PHY_NB_JOIN_TRIALS: + case PHY_DEF_NB_JOIN_TRIALS: + { + phyParam.Value = 48; + break; + } + default: + { + break; + } + } + + return phyParam; + } + + void RegionCN470SetBandTxDone(SetBandTxDoneParams_t *txDone) + { + RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); + } + + void RegionCN470InitDefaults(InitType_t type) + { + switch (type) + { + case INIT_TYPE_INIT: + { + // Channels + // 125 kHz channels + for (uint8_t i = 0; i < CN470_MAX_NB_CHANNELS; i++) + { + Channels[i].Frequency = 470300000 + i * 200000; + Channels[i].DrRange.Value = (DR_5 << 4) | DR_0; + Channels[i].Band = 0; + } + + // Initialize the channels default mask + ChannelsDefaultMask[0] = 0xFFFF; + ChannelsDefaultMask[1] = 0xFFFF; + ChannelsDefaultMask[2] = 0xFFFF; + ChannelsDefaultMask[3] = 0xFFFF; + ChannelsDefaultMask[4] = 0xFFFF; + ChannelsDefaultMask[5] = 0xFFFF; + + // Update the channels mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); + break; + } + case INIT_TYPE_RESTORE: + { + // Restore channels default mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); + break; + } + case INIT_TYPE_APP_DEFAULTS: + { + // Update the channels mask defaults + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); + break; + } + default: + { + break; + } + } + } + + bool RegionCN470Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) + { + switch (phyAttribute) + { + case PHY_TX_DR: + case PHY_DEF_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, CN470_TX_MIN_DATARATE, CN470_TX_MAX_DATARATE); + } + case PHY_RX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE); + } + case PHY_DEF_TX_POWER: + case PHY_TX_POWER: + { + // Remark: switched min and max! + return RegionCommonValueInRange(verify->TxPower, CN470_MAX_TX_POWER, CN470_MIN_TX_POWER); + } + case PHY_DUTY_CYCLE: + { + return CN470_DUTY_CYCLE_ENABLED; + } + case PHY_NB_JOIN_TRIALS: + { + if (verify->NbJoinTrials < 48) + { + return false; + } + break; + } + default: + return false; + } + return true; + } + + void RegionCN470ApplyCFList(ApplyCFListParams_t *applyCFList) + { + return; + } + + bool RegionCN470ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) + { + switch (chanMaskSet->ChannelsMaskType) + { + case CHANNELS_MASK: + { + RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 6); + break; + } + case CHANNELS_DEFAULT_MASK: + { + RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6); + break; + } + default: + return false; + } + return true; + } + + bool RegionCN470AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) + { + bool adrAckReq = false; + int8_t datarate = adrNext->Datarate; + int8_t txPower = adrNext->TxPower; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + + // Report back the adr ack counter + *adrAckCounter = adrNext->AdrAckCounter; + + if (adrNext->AdrEnabled == true) + { + if (datarate == CN470_TX_MIN_DATARATE) + { + *adrAckCounter = 0; + adrAckReq = false; + } + else + { + if (adrNext->AdrAckCounter >= CN470_ADR_ACK_LIMIT) + { + adrAckReq = true; + txPower = CN470_MAX_TX_POWER; + } + else + { + adrAckReq = false; + } + if (adrNext->AdrAckCounter >= (CN470_ADR_ACK_LIMIT + CN470_ADR_ACK_DELAY)) + { + if ((adrNext->AdrAckCounter % CN470_ADR_ACK_DELAY) == 1) + { + // Decrease the datarate + getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; + getPhy.Datarate = datarate; + getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; + phyParam = RegionCN470GetPhyParam(&getPhy); + datarate = phyParam.Value; + + if (datarate == CN470_TX_MIN_DATARATE) + { + // We must set adrAckReq to false as soon as we reach the lowest datarate + adrAckReq = false; + if (adrNext->UpdateChanMask == true) + { + // Re-enable default channels + ChannelsMask[0] = 0xFFFF; + ChannelsMask[1] = 0xFFFF; + ChannelsMask[2] = 0xFFFF; + ChannelsMask[3] = 0xFFFF; + ChannelsMask[4] = 0xFFFF; + ChannelsMask[5] = 0xFFFF; + } + } + } + } + } + } + + *drOut = datarate; + *txPowOut = txPower; + return adrAckReq; + } + + void RegionCN470ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) + { + double tSymbol = 0.0; + + // Get the datarate, perform a boundary check + rxConfigParams->Datarate = MIN(datarate, CN470_RX_MAX_DATARATE); + rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); + + tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesCN470[rxConfigParams->Datarate], BandwidthsCN470[rxConfigParams->Datarate]); + + RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); + } + + bool RegionCN470RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) + { + int8_t dr = rxConfig->Datarate; + uint8_t maxPayload = 0; + int8_t phyDr = 0; + uint32_t frequency = rxConfig->Frequency; + + if (Radio.GetStatus() != RF_IDLE) + { + return false; + } + + if (rxConfig->Window == 0) + { + // Apply window 1 frequency + frequency = CN470_FIRST_RX1_CHANNEL + (rxConfig->Channel % 48) * CN470_STEPWIDTH_RX1_CHANNEL; + } + + // Read the physical datarate from the datarates table + phyDr = DataratesCN470[dr]; + + Radio.SetChannel(frequency); + + // Radio configuration + Radio.SetRxConfig(MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); + + if (rxConfig->RepeaterSupport == true) + { + maxPayload = MaxPayloadOfDatarateRepeaterCN470[dr]; + } + else + { + maxPayload = MaxPayloadOfDatarateCN470[dr]; + } + Radio.SetMaxPayloadLength(MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + *datarate = (uint8_t)dr; + return true; + } + + bool RegionCN470TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) + { + int8_t phyDr = DataratesCN470[txConfig->Datarate]; + int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); + int8_t phyTxPower = 0; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); + + // Setup the radio frequency + Radio.SetChannel(Channels[txConfig->Channel].Frequency); + + Radio.SetTxConfig(MODEM_LORA, phyTxPower, 0, 0, phyDr, 1, 8, false, true, 0, 0, false, 3000); + // Setup maximum payload lenght of the radio driver + Radio.SetMaxPayloadLength(MODEM_LORA, txConfig->PktLen); + // Get the time-on-air of the next tx frame + *txTimeOnAir = Radio.TimeOnAir(MODEM_LORA, txConfig->PktLen); + *txPower = txPowerLimited; + + return true; + } + + uint8_t RegionCN470LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) + { + uint8_t status = 0x07; + RegionCommonLinkAdrParams_t linkAdrParams; + uint8_t nextIndex = 0; + uint8_t bytesProcessed = 0; + uint16_t channelsMask[6] = {0, 0, 0, 0, 0, 0}; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; + + // Initialize local copy of channels mask + RegionCommonChanMaskCopy(channelsMask, ChannelsMask, 6); + + while (bytesProcessed < linkAdrReq->PayloadSize) + { + // Get ADR request parameters + nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); + + if (nextIndex == 0) + break; // break loop, since no more request has been found + + // Update bytes processed + bytesProcessed += nextIndex; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + if (linkAdrParams.ChMaskCtrl == 6) + { + // Enable all 125 kHz channels + channelsMask[0] = 0xFFFF; + channelsMask[1] = 0xFFFF; + channelsMask[2] = 0xFFFF; + channelsMask[3] = 0xFFFF; + channelsMask[4] = 0xFFFF; + channelsMask[5] = 0xFFFF; + } + else if (linkAdrParams.ChMaskCtrl == 7) + { + status &= 0xFE; // Channel mask KO + } + else + { + for (uint8_t i = 0; i < 16; i++) + { + if (((linkAdrParams.ChMask & (1 << i)) != 0) && + (Channels[linkAdrParams.ChMaskCtrl * 16 + i].Frequency == 0)) + { // Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask; + } + } + + // Get the minimum possible datarate + getPhy.Attribute = PHY_MIN_TX_DR; + getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; + phyParam = RegionCN470GetPhyParam(&getPhy); + + linkAdrVerifyParams.Status = status; + linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; + linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; + linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; + linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; + linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; + linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; + linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; + linkAdrVerifyParams.NbChannels = CN470_MAX_NB_CHANNELS; + linkAdrVerifyParams.ChannelsMask = channelsMask; + linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; + linkAdrVerifyParams.MaxDatarate = CN470_TX_MAX_DATARATE; + linkAdrVerifyParams.Channels = Channels; + linkAdrVerifyParams.MinTxPower = CN470_MIN_TX_POWER; + linkAdrVerifyParams.MaxTxPower = CN470_MAX_TX_POWER; + + // Verify the parameters and update, if necessary + status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); + + // Update channelsMask if everything is correct + if (status == 0x07) + { + // Copy Mask + RegionCommonChanMaskCopy(ChannelsMask, channelsMask, 6); + } + + // Update status variables + *drOut = linkAdrParams.Datarate; + *txPowOut = linkAdrParams.TxPower; + *nbRepOut = linkAdrParams.NbRep; + *nbBytesParsed = bytesProcessed; + + return status; + } + + uint8_t RegionCN470RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) + { + uint8_t status = 0x07; + uint32_t freq = rxParamSetupReq->Frequency; + + // Verify radio frequency + if ((Radio.CheckRfFrequency(freq) == false) || + (freq < CN470_FIRST_RX1_CHANNEL) || + (freq > CN470_LAST_RX1_CHANNEL) || + (((freq - (uint32_t)CN470_FIRST_RX1_CHANNEL) % (uint32_t)CN470_STEPWIDTH_RX1_CHANNEL) != 0)) + { + status &= 0xFE; // Channel frequency KO + } + + // Verify datarate + if (RegionCommonValueInRange(rxParamSetupReq->Datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE) == false) + { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, CN470_MIN_RX1_DR_OFFSET, CN470_MAX_RX1_DR_OFFSET) == false) + { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; + } + + uint8_t RegionCN470NewChannelReq(NewChannelReqParams_t *newChannelReq) + { + // Datarate and frequency KO + return 0; + } + + int8_t RegionCN470TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) + { + return -1; + } + + uint8_t RegionCN470DlChannelReq(DlChannelReqParams_t *dlChannelReq) + { + return 0; + } + + int8_t RegionCN470AlternateDr(AlternateDrParams_t *alternateDr) + { + int8_t datarate = 0; + + if ((alternateDr->NbTrials % 48) == 0) + { + datarate = DR_0; + } + else if ((alternateDr->NbTrials % 32) == 0) + { + datarate = DR_1; + } + else if ((alternateDr->NbTrials % 24) == 0) + { + datarate = DR_2; + } + else if ((alternateDr->NbTrials % 16) == 0) + { + datarate = DR_3; + } + else if ((alternateDr->NbTrials % 8) == 0) + { + datarate = DR_4; + } + else + { + datarate = DR_5; + } + return datarate; + } + + void RegionCN470CalcBackOff(CalcBackOffParams_t *calcBackOff) + { + RegionCommonCalcBackOffParams_t calcBackOffParams; + + calcBackOffParams.Channels = Channels; + calcBackOffParams.Bands = Bands; + calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; + calcBackOffParams.Joined = calcBackOff->Joined; + calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; + calcBackOffParams.Channel = calcBackOff->Channel; + calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; + calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; + + RegionCommonCalcBackOff(&calcBackOffParams); + } + + bool RegionCN470NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTx = 0; + uint8_t enabledChannels[CN470_MAX_NB_CHANNELS] = {0}; + TimerTime_t nextTxDelay = 0; + + // Count 125kHz channels + if (RegionCommonCountChannels(ChannelsMask, 0, 6) == 0) + { // Reactivate default channels + ChannelsMask[0] = 0xFFFF; + ChannelsMask[1] = 0xFFFF; + ChannelsMask[2] = 0xFFFF; + ChannelsMask[3] = 0xFFFF; + ChannelsMask[4] = 0xFFFF; + ChannelsMask[5] = 0xFFFF; + } + + if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) + { + // Reset Aggregated time off + *aggregatedTimeOff = 0; + + // Update bands Time OFF + nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, CN470_MAX_NB_BANDS); + + // Search how many channels are enabled + nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Datarate, + ChannelsMask, Channels, + Bands, enabledChannels, &delayTx); + } + else + { + delayTx++; + nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); + } + + if (nbEnabledChannels > 0) + { + // We found a valid channel + *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; + + *time = 0; + return true; + } + else + { + if (delayTx > 0) + { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return true; + } + // Datarate not supported by any channel + *time = 0; + return false; + } + } + + LoRaMacStatus_t RegionCN470ChannelAdd(ChannelAddParams_t *channelAdd) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + bool RegionCN470ChannelsRemove(ChannelRemoveParams_t *channelRemove) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + void RegionCN470SetContinuousWave(ContinuousWaveParams_t *continuousWave) + { + int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); + int8_t phyTxPower = 0; + uint32_t frequency = Channels[continuousWave->Channel].Frequency; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); + + Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); + } + + uint8_t RegionCN470ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) + { + int8_t datarate = dr - drOffset; + + if (datarate < 0) + { + datarate = DR_0; + } + return datarate; + } }; \ No newline at end of file diff --git a/src/mac/region/RegionCN470.h b/src/mac/region/RegionCN470.h index e86e0f0..54c5d6b 100644 --- a/src/mac/region/RegionCN470.h +++ b/src/mac/region/RegionCN470.h @@ -41,208 +41,211 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define CN470_MAX_NB_CHANNELS 96 +#define CN470_MAX_NB_CHANNELS 96 /*! * Minimal datarate that can be used by the node */ -#define CN470_TX_MIN_DATARATE DR_0 +#define CN470_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define CN470_TX_MAX_DATARATE DR_5 +#define CN470_TX_MAX_DATARATE DR_5 /*! * Minimal datarate that can be used by the node */ -#define CN470_RX_MIN_DATARATE DR_0 +#define CN470_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define CN470_RX_MAX_DATARATE DR_5 +#define CN470_RX_MAX_DATARATE DR_5 /*! * Default datarate used by the node */ -#define CN470_DEFAULT_DATARATE DR_0 +#define CN470_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define CN470_MIN_RX1_DR_OFFSET 0 +#define CN470_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define CN470_MAX_RX1_DR_OFFSET 3 +#define CN470_MAX_RX1_DR_OFFSET 3 /*! * Default Rx1 receive datarate offset */ -#define CN470_DEFAULT_RX1_DR_OFFSET 0 +#define CN470_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define CN470_MIN_TX_POWER TX_POWER_7 +#define CN470_MIN_TX_POWER TX_POWER_7 /*! * Maximal Tx output power that can be used by the node */ -#define CN470_MAX_TX_POWER TX_POWER_0 +#define CN470_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define CN470_DEFAULT_TX_POWER TX_POWER_0 +#define CN470_DEFAULT_TX_POWER TX_POWER_0 /*! * Default Max EIRP */ -#define CN470_DEFAULT_MAX_EIRP 19.15f +#define CN470_DEFAULT_MAX_EIRP 19.15f /*! * Default antenna gain */ -#define CN470_DEFAULT_ANTENNA_GAIN 2.15f +#define CN470_DEFAULT_ANTENNA_GAIN 2.15f /*! * ADR Ack limit */ -#define CN470_ADR_ACK_LIMIT 64 +#define CN470_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define CN470_ADR_ACK_DELAY 32 +#define CN470_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define CN470_DUTY_CYCLE_ENABLED 0 +#define CN470_DUTY_CYCLE_ENABLED 0 /*! * Maximum RX window duration */ -#define CN470_MAX_RX_WINDOW 3000 +#define CN470_MAX_RX_WINDOW 3000 /*! * Receive delay 1 */ -#define CN470_RECEIVE_DELAY1 1000 +#define CN470_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define CN470_RECEIVE_DELAY2 2000 +#define CN470_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define CN470_JOIN_ACCEPT_DELAY1 5000 +#define CN470_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define CN470_JOIN_ACCEPT_DELAY2 6000 +#define CN470_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define CN470_MAX_FCNT_GAP 16384 +#define CN470_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define CN470_ACKTIMEOUT 2000 +#define CN470_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define CN470_ACK_TIMEOUT_RND 1000 +#define CN470_ACK_TIMEOUT_RND 1000 /*! * Second reception window channel frequency definition. */ -#define CN470_RX_WND_2_FREQ 505300000 +#define CN470_RX_WND_2_FREQ 505300000 /*! * Second reception window channel datarate definition. */ -#define CN470_RX_WND_2_DR DR_0 +#define CN470_RX_WND_2_DR DR_0 /*! * LoRaMac maximum number of bands */ -#define CN470_MAX_NB_BANDS 1 +#define CN470_MAX_NB_BANDS 1 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define CN470_BAND0 { 1, CN470_MAX_TX_POWER, 0, 0 } // 100.0 % +#define CN470_BAND0 \ + { \ + 1, CN470_MAX_TX_POWER, 0, 0 \ + } // 100.0 % /*! * Defines the first channel for RX window 1 for CN470 band */ -#define CN470_FIRST_RX1_CHANNEL ( (uint32_t) 500300000 ) +#define CN470_FIRST_RX1_CHANNEL ((uint32_t)500300000) /*! * Defines the last channel for RX window 1 for CN470 band */ -#define CN470_LAST_RX1_CHANNEL ( (uint32_t) 509700000 ) +#define CN470_LAST_RX1_CHANNEL ((uint32_t)509700000) /*! * Defines the step width of the channels for RX window 1 */ -#define CN470_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 200000 ) +#define CN470_STEPWIDTH_RX1_CHANNEL ((uint32_t)200000) -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesCN470[] = { 12, 11, 10, 9, 8, 7 }; + static const uint8_t DataratesCN470[] = {12, 11, 10, 9, 8, 7}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsCN470[] = { 125000, 125000, 125000, 125000, 125000, 125000 }; + static const uint32_t BandwidthsCN470[] = {125000, 125000, 125000, 125000, 125000, 125000}; -/*! + /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateCN470[] = { 51, 51, 51, 115, 222, 222 }; + static const uint8_t MaxPayloadOfDatarateCN470[] = {51, 51, 51, 115, 222, 222}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateRepeaterCN470[] = { 51, 51, 51, 115, 222, 222 }; + static const uint8_t MaxPayloadOfDatarateRepeaterCN470[] = {51, 51, 51, 115, 222, 222}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionCN470GetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionCN470SetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionCN470SetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionCN470InitDefaults( InitType_t type ); + void RegionCN470InitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -251,26 +254,26 @@ void RegionCN470InitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionCN470Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionCN470Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionCN470ApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionCN470ApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionCN470ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionCN470ChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -283,9 +286,9 @@ bool RegionCN470ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionCN470AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionCN470AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -298,9 +301,9 @@ bool RegionCN470AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowO * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionCN470ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionCN470ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -309,9 +312,9 @@ void RegionCN470ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionCN470RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionCN470RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -322,36 +325,36 @@ bool RegionCN470RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionCN470TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionCN470TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionCN470LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionCN470LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionCN470RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionCN470RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionCN470NewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionCN470NewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -360,34 +363,34 @@ uint8_t RegionCN470NewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionCN470TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionCN470TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionCN470DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionCN470DlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionCN470AlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionCN470AlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionCN470CalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionCN470CalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -399,34 +402,34 @@ void RegionCN470CalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionCN470NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionCN470NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionCN470ChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionCN470ChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionCN470ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionCN470ChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionCN470SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionCN470SetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -437,8 +440,8 @@ void RegionCN470SetContinuousWave( ContinuousWaveParams_t* continuousWave ); * * \retval newDr Computed datarate. */ -uint8_t RegionCN470ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionCN470ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONCN470 */ + /*! \} defgroup REGIONCN470 */ }; #endif // __REGION_CN470_H__ diff --git a/src/mac/region/RegionCN779.cpp b/src/mac/region/RegionCN779.cpp index 504872f..c687bde 100644 --- a/src/mac/region/RegionCN779.cpp +++ b/src/mac/region/RegionCN779.cpp @@ -37,1018 +37,1018 @@ extern "C" // Definitions #define CHANNELS_MASK_SIZE 1 - // Global attributes - /*! + // Global attributes + /*! * LoRaMAC channels */ - static ChannelParams_t Channels[CN779_MAX_NB_CHANNELS]; + static ChannelParams_t Channels[CN779_MAX_NB_CHANNELS]; - /*! + /*! * LoRaMac bands */ - static Band_t Bands[CN779_MAX_NB_BANDS] = - { - CN779_BAND0}; + static Band_t Bands[CN779_MAX_NB_BANDS] = + { + CN779_BAND0}; - /*! + /*! * LoRaMac channels mask */ - static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; + static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; - /*! + /*! * LoRaMac channels default mask */ - static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; - - // Static functions - static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) - { - uint8_t nextLowerDr = 0; - - if (dr == minDr) - { - nextLowerDr = minDr; - } - else - { - nextLowerDr = dr - 1; - } - return nextLowerDr; - } - - static uint32_t GetBandwidth(uint32_t drIndex) - { - switch (BandwidthsCN779[drIndex]) - { - default: - case 125000: - return 0; - case 250000: - return 1; - case 500000: - return 2; - } - } - - static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) - { - int8_t txPowerResult = txPower; - - // Limit tx power to the band max - txPowerResult = MAX(txPower, maxBandTxPower); - - return txPowerResult; - } - - static bool VerifyTxFreq(uint32_t freq) - { - // Check radio driver support - if (Radio.CheckRfFrequency(freq) == false) - { - return false; - } - - if ((freq < 779500000) || (freq > 786500000)) - { - return false; - } - return true; - } - - static uint8_t CountNbOfEnabledChannels(bool joined, uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTransmission = 0; - - for (uint8_t i = 0, k = 0; i < CN779_MAX_NB_CHANNELS; i += 16, k++) - { - for (uint8_t j = 0; j < 16; j++) - { - if ((channelsMask[k] & (1 << j)) != 0) - { - if (channels[i + j].Frequency == 0) - { // Check if the channel is enabled - continue; - } - if (joined == false) - { - if ((CN779_JOIN_CHANNELS & (1 << j)) == 0) - { - continue; - } - } - if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, - channels[i + j].DrRange.Fields.Max) == false) - { // Check if the current channel selection supports the given datarate - continue; - } - if (bands[channels[i + j].Band].TimeOff > 0) - { // Check if the band is available for transmission - delayTransmission++; - continue; - } - enabledChannels[nbEnabledChannels++] = i + j; - } - } - } - - *delayTx = delayTransmission; - return nbEnabledChannels; - } - - PhyParam_t RegionCN779GetPhyParam(GetPhyParams_t *getPhy) - { - PhyParam_t phyParam = {0}; - - switch (getPhy->Attribute) - { - case PHY_MIN_RX_DR: - { - phyParam.Value = CN779_RX_MIN_DATARATE; - break; - } - case PHY_MIN_TX_DR: - { - phyParam.Value = CN779_TX_MIN_DATARATE; - break; - } - case PHY_DEF_TX_DR: - { - phyParam.Value = CN779_DEFAULT_DATARATE; - break; - } - case PHY_NEXT_LOWER_TX_DR: - { - phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, CN779_TX_MIN_DATARATE); - break; - } - case PHY_DEF_TX_POWER: - { - phyParam.Value = CN779_DEFAULT_TX_POWER; - break; - } - case PHY_MAX_PAYLOAD: - { - phyParam.Value = MaxPayloadOfDatarateCN779[getPhy->Datarate]; - break; - } - case PHY_MAX_PAYLOAD_REPEATER: - { - phyParam.Value = MaxPayloadOfDatarateRepeaterCN779[getPhy->Datarate]; - break; - } - case PHY_DUTY_CYCLE: - { - phyParam.Value = CN779_DUTY_CYCLE_ENABLED; - break; - } - case PHY_MAX_RX_WINDOW: - { - phyParam.Value = CN779_MAX_RX_WINDOW; - break; - } - case PHY_RECEIVE_DELAY1: - { - phyParam.Value = CN779_RECEIVE_DELAY1; - break; - } - case PHY_RECEIVE_DELAY2: - { - phyParam.Value = CN779_RECEIVE_DELAY2; - break; - } - case PHY_JOIN_ACCEPT_DELAY1: - { - phyParam.Value = CN779_JOIN_ACCEPT_DELAY1; - break; - } - case PHY_JOIN_ACCEPT_DELAY2: - { - phyParam.Value = CN779_JOIN_ACCEPT_DELAY2; - break; - } - case PHY_MAX_FCNT_GAP: - { - phyParam.Value = CN779_MAX_FCNT_GAP; - break; - } - case PHY_ACK_TIMEOUT: - { - phyParam.Value = (CN779_ACKTIMEOUT + randr(-CN779_ACK_TIMEOUT_RND, CN779_ACK_TIMEOUT_RND)); - break; - } - case PHY_DEF_DR1_OFFSET: - { - phyParam.Value = CN779_DEFAULT_RX1_DR_OFFSET; - break; - } - case PHY_DEF_RX2_FREQUENCY: - { - phyParam.Value = CN779_RX_WND_2_FREQ; - break; - } - case PHY_DEF_RX2_DR: - { - phyParam.Value = CN779_RX_WND_2_DR; - break; - } - case PHY_CHANNELS_MASK: - { - phyParam.ChannelsMask = ChannelsMask; - break; - } - case PHY_CHANNELS_DEFAULT_MASK: - { - phyParam.ChannelsMask = ChannelsDefaultMask; - break; - } - case PHY_MAX_NB_CHANNELS: - { - phyParam.Value = CN779_MAX_NB_CHANNELS; - break; - } - case PHY_CHANNELS: - { - phyParam.Channels = Channels; - break; - } - case PHY_DEF_UPLINK_DWELL_TIME: - case PHY_DEF_DOWNLINK_DWELL_TIME: - { - phyParam.Value = 0; - break; - } - case PHY_DEF_MAX_EIRP: - { - phyParam.fValue = CN779_DEFAULT_MAX_EIRP; - break; - } - case PHY_DEF_ANTENNA_GAIN: - { - phyParam.fValue = CN779_DEFAULT_ANTENNA_GAIN; - break; - } - case PHY_NB_JOIN_TRIALS: - case PHY_DEF_NB_JOIN_TRIALS: - { - phyParam.Value = 48; - break; - } - default: - { - break; - } - } - - return phyParam; - } - - void RegionCN779SetBandTxDone(SetBandTxDoneParams_t *txDone) - { - RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); - } - - void RegionCN779InitDefaults(InitType_t type) - { - switch (type) - { - case INIT_TYPE_INIT: - { - // Channels - Channels[0] = (ChannelParams_t)CN779_LC1; - Channels[1] = (ChannelParams_t)CN779_LC2; - Channels[2] = (ChannelParams_t)CN779_LC3; - - // Initialize the channels default mask - ChannelsDefaultMask[0] = LC(1) + LC(2) + LC(3); - // Update the channels mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); - break; - } - case INIT_TYPE_RESTORE: - { - // Restore channels default mask - ChannelsMask[0] |= ChannelsDefaultMask[0]; - break; - } - case INIT_TYPE_APP_DEFAULTS: - { - // Update the channels mask defaults - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); - break; - } - default: - { - break; - } - } - } - - bool RegionCN779Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) - { - switch (phyAttribute) - { - case PHY_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE); - } - case PHY_DEF_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); - } - case PHY_RX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, CN779_RX_MIN_DATARATE, CN779_RX_MAX_DATARATE); - } - case PHY_DEF_TX_POWER: - case PHY_TX_POWER: - { - // Remark: switched min and max! - return RegionCommonValueInRange(verify->TxPower, CN779_MAX_TX_POWER, CN779_MIN_TX_POWER); - } - case PHY_DUTY_CYCLE: - { - return CN779_DUTY_CYCLE_ENABLED; - } - case PHY_NB_JOIN_TRIALS: - { - if (verify->NbJoinTrials < 48) - { - return false; - } - break; - } - default: - return false; - } - return true; - } - - void RegionCN779ApplyCFList(ApplyCFListParams_t *applyCFList) - { - ChannelParams_t newChannel; - ChannelAddParams_t channelAdd; - ChannelRemoveParams_t channelRemove; - - // Setup default datarate range - newChannel.DrRange.Value = (DR_5 << 4) | DR_0; - - // Size of the optional CF list - if (applyCFList->Size != 16) - { - return; - } - - // Last byte is RFU, don't take it into account - for (uint8_t i = 0, chanIdx = CN779_NUMB_DEFAULT_CHANNELS; chanIdx < CN779_MAX_NB_CHANNELS; i += 3, chanIdx++) - { - if (chanIdx < (CN779_NUMB_CHANNELS_CF_LIST + CN779_NUMB_DEFAULT_CHANNELS)) - { - // Channel frequency - newChannel.Frequency = (uint32_t)applyCFList->Payload[i]; - newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 1] << 8); - newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 2] << 16); - newChannel.Frequency *= 100; - - // Initialize alternative frequency to 0 - newChannel.Rx1Frequency = 0; - } - else - { - newChannel.Frequency = 0; - newChannel.DrRange.Value = 0; - newChannel.Rx1Frequency = 0; - } - - if (newChannel.Frequency != 0) - { - channelAdd.NewChannel = &newChannel; - channelAdd.ChannelId = chanIdx; - - // Try to add all channels - RegionCN779ChannelAdd(&channelAdd); - } - else - { - channelRemove.ChannelId = chanIdx; - - RegionCN779ChannelsRemove(&channelRemove); - } - } - } - - bool RegionCN779ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) - { - switch (chanMaskSet->ChannelsMaskType) - { - case CHANNELS_MASK: - { - RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 1); - break; - } - case CHANNELS_DEFAULT_MASK: - { - RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1); - break; - } - default: - return false; - } - return true; - } - - bool RegionCN779AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) - { - bool adrAckReq = false; - int8_t datarate = adrNext->Datarate; - int8_t txPower = adrNext->TxPower; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - - // Report back the adr ack counter - *adrAckCounter = adrNext->AdrAckCounter; - - if (adrNext->AdrEnabled == true) - { - if (datarate == CN779_TX_MIN_DATARATE) - { - *adrAckCounter = 0; - adrAckReq = false; - } - else - { - if (adrNext->AdrAckCounter >= CN779_ADR_ACK_LIMIT) - { - adrAckReq = true; - txPower = CN779_MAX_TX_POWER; - } - else - { - adrAckReq = false; - } - if (adrNext->AdrAckCounter >= (CN779_ADR_ACK_LIMIT + CN779_ADR_ACK_DELAY)) - { - if ((adrNext->AdrAckCounter % CN779_ADR_ACK_DELAY) == 1) - { - // Decrease the datarate - getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; - getPhy.Datarate = datarate; - getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; - phyParam = RegionCN779GetPhyParam(&getPhy); - datarate = phyParam.Value; - - if (datarate == CN779_TX_MIN_DATARATE) - { - // We must set adrAckReq to false as soon as we reach the lowest datarate - adrAckReq = false; - if (adrNext->UpdateChanMask == true) - { - // Re-enable default channels - ChannelsMask[0] |= LC(1) + LC(2) + LC(3); - } - } - } - } - } - } - - *drOut = datarate; - *txPowOut = txPower; - return adrAckReq; - } - - void RegionCN779ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) - { - double tSymbol = 0.0; - - // Get the datarate, perform a boundary check - rxConfigParams->Datarate = MIN(datarate, CN779_RX_MAX_DATARATE); - rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); - - if (rxConfigParams->Datarate == DR_7) - { // FSK - tSymbol = RegionCommonComputeSymbolTimeFsk(DataratesCN779[rxConfigParams->Datarate]); - } - else - { // LoRa - tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesCN779[rxConfigParams->Datarate], BandwidthsCN779[rxConfigParams->Datarate]); - } - - RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); - } - - bool RegionCN779RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) - { - RadioModems_t modem; - int8_t dr = rxConfig->Datarate; - uint8_t maxPayload = 0; - int8_t phyDr = 0; - uint32_t frequency = rxConfig->Frequency; - - if (Radio.GetStatus() != RF_IDLE) - { - return false; - } - - if (rxConfig->Window == 0) - { - // Apply window 1 frequency - frequency = Channels[rxConfig->Channel].Frequency; - // Apply the alternative RX 1 window frequency, if it is available - if (Channels[rxConfig->Channel].Rx1Frequency != 0) - { - frequency = Channels[rxConfig->Channel].Rx1Frequency; - } - } - - // Read the physical datarate from the datarates table - phyDr = DataratesCN779[dr]; - - Radio.SetChannel(frequency); - - // Radio configuration - if (dr == DR_7) - { - modem = MODEM_FSK; - Radio.SetRxConfig(modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous); - } - else - { - modem = MODEM_LORA; - Radio.SetRxConfig(modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); - } - - if (rxConfig->RepeaterSupport == true) - { - maxPayload = MaxPayloadOfDatarateRepeaterCN779[dr]; - } - else - { - maxPayload = MaxPayloadOfDatarateCN779[dr]; - } - Radio.SetMaxPayloadLength(modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - *datarate = (uint8_t)dr; - return true; - } - - bool RegionCN779TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) - { - RadioModems_t modem; - int8_t phyDr = DataratesCN779[txConfig->Datarate]; - int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); - uint32_t bandwidth = GetBandwidth(txConfig->Datarate); - int8_t phyTxPower = 0; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); - - // Setup the radio frequency - Radio.SetChannel(Channels[txConfig->Channel].Frequency); - - if (txConfig->Datarate == DR_7) - { // High Speed FSK channel - modem = MODEM_FSK; - Radio.SetTxConfig(modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000); - } - else - { - modem = MODEM_LORA; - Radio.SetTxConfig(modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); - } - - // Setup maximum payload lenght of the radio driver - Radio.SetMaxPayloadLength(modem, txConfig->PktLen); - // Get the time-on-air of the next tx frame - *txTimeOnAir = Radio.TimeOnAir(modem, txConfig->PktLen); - - *txPower = txPowerLimited; - return true; - } - - uint8_t RegionCN779LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) - { - uint8_t status = 0x07; - RegionCommonLinkAdrParams_t linkAdrParams; - uint8_t nextIndex = 0; - uint8_t bytesProcessed = 0; - uint16_t chMask = 0; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; - - while (bytesProcessed < linkAdrReq->PayloadSize) - { - // Get ADR request parameters - nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); - - if (nextIndex == 0) - break; // break loop, since no more request has been found - - // Update bytes processed - bytesProcessed += nextIndex; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - // Setup temporary channels mask - chMask = linkAdrParams.ChMask; - - // Verify channels mask - if ((linkAdrParams.ChMaskCtrl == 0) && (chMask == 0)) - { - status &= 0xFE; // Channel mask KO - } - else if (((linkAdrParams.ChMaskCtrl >= 1) && (linkAdrParams.ChMaskCtrl <= 5)) || - (linkAdrParams.ChMaskCtrl >= 7)) - { - // RFU - status &= 0xFE; // Channel mask KO - } - else - { - for (uint8_t i = 0; i < CN779_MAX_NB_CHANNELS; i++) - { - if (linkAdrParams.ChMaskCtrl == 6) - { - if (Channels[i].Frequency != 0) - { - chMask |= 1 << i; - } - } - else - { - if (((chMask & (1 << i)) != 0) && - (Channels[i].Frequency == 0)) - { // Trying to enable an undefined channel - status &= 0xFE; // Channel mask KO - } - } - } - } - } - - // Get the minimum possible datarate - getPhy.Attribute = PHY_MIN_TX_DR; - getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; - phyParam = RegionCN779GetPhyParam(&getPhy); - - linkAdrVerifyParams.Status = status; - linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; - linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; - linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; - linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; - linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; - linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; - linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; - linkAdrVerifyParams.NbChannels = CN779_MAX_NB_CHANNELS; - linkAdrVerifyParams.ChannelsMask = &chMask; - linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; - linkAdrVerifyParams.MaxDatarate = CN779_TX_MAX_DATARATE; - linkAdrVerifyParams.Channels = Channels; - linkAdrVerifyParams.MinTxPower = CN779_MIN_TX_POWER; - linkAdrVerifyParams.MaxTxPower = CN779_MAX_TX_POWER; - - // Verify the parameters and update, if necessary - status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); - - // Update channelsMask if everything is correct - if (status == 0x07) - { - // Set the channels mask to a default value - memset(ChannelsMask, 0, sizeof(ChannelsMask)); - // Update the channels mask - ChannelsMask[0] = chMask; - } - - // Update status variables - *drOut = linkAdrParams.Datarate; - *txPowOut = linkAdrParams.TxPower; - *nbRepOut = linkAdrParams.NbRep; - *nbBytesParsed = bytesProcessed; - - return status; - } - - uint8_t RegionCN779RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) - { - uint8_t status = 0x07; - - // Verify radio frequency - if (Radio.CheckRfFrequency(rxParamSetupReq->Frequency) == false) - { - status &= 0xFE; // Channel frequency KO - } - - // Verify datarate - if (RegionCommonValueInRange(rxParamSetupReq->Datarate, CN779_RX_MIN_DATARATE, CN779_RX_MAX_DATARATE) == false) - { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, CN779_MIN_RX1_DR_OFFSET, CN779_MAX_RX1_DR_OFFSET) == false) - { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; - } - - uint8_t RegionCN779NewChannelReq(NewChannelReqParams_t *newChannelReq) - { - uint8_t status = 0x03; - ChannelAddParams_t channelAdd; - ChannelRemoveParams_t channelRemove; - - if (newChannelReq->NewChannel->Frequency == 0) - { - channelRemove.ChannelId = newChannelReq->ChannelId; - - // Remove - if (RegionCN779ChannelsRemove(&channelRemove) == false) - { - status &= 0xFC; - } - } - else - { - channelAdd.NewChannel = newChannelReq->NewChannel; - channelAdd.ChannelId = newChannelReq->ChannelId; - - switch (RegionCN779ChannelAdd(&channelAdd)) - { - case LORAMAC_STATUS_OK: - { - break; - } - case LORAMAC_STATUS_FREQUENCY_INVALID: - { - status &= 0xFE; - break; - } - case LORAMAC_STATUS_DATARATE_INVALID: - { - status &= 0xFD; - break; - } - case LORAMAC_STATUS_FREQ_AND_DR_INVALID: - { - status &= 0xFC; - break; - } - default: - { - status &= 0xFC; - break; - } - } - } - - return status; - } - - int8_t RegionCN779TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) - { - return -1; - } - - uint8_t RegionCN779DlChannelReq(DlChannelReqParams_t *dlChannelReq) - { - uint8_t status = 0x03; - - // Verify if the frequency is supported - if (VerifyTxFreq(dlChannelReq->Rx1Frequency) == false) - { - status &= 0xFE; - } - - // Verify if an uplink frequency exists - if (Channels[dlChannelReq->ChannelId].Frequency == 0) - { - status &= 0xFD; - } - - // Apply Rx1 frequency, if the status is OK - if (status == 0x03) - { - Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency; - } - - return status; - } - - int8_t RegionCN779AlternateDr(AlternateDrParams_t *alternateDr) - { - int8_t datarate = 0; - - if ((alternateDr->NbTrials % 48) == 0) - { - datarate = DR_0; - } - else if ((alternateDr->NbTrials % 32) == 0) - { - datarate = DR_1; - } - else if ((alternateDr->NbTrials % 24) == 0) - { - datarate = DR_2; - } - else if ((alternateDr->NbTrials % 16) == 0) - { - datarate = DR_3; - } - else if ((alternateDr->NbTrials % 8) == 0) - { - datarate = DR_4; - } - else - { - datarate = DR_5; - } - return datarate; - } - - void RegionCN779CalcBackOff(CalcBackOffParams_t *calcBackOff) - { - RegionCommonCalcBackOffParams_t calcBackOffParams; - - calcBackOffParams.Channels = Channels; - calcBackOffParams.Bands = Bands; - calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; - calcBackOffParams.Joined = calcBackOff->Joined; - calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; - calcBackOffParams.Channel = calcBackOff->Channel; - calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; - calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; - - RegionCommonCalcBackOff(&calcBackOffParams); - } - - bool RegionCN779NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTx = 0; - uint8_t enabledChannels[CN779_MAX_NB_CHANNELS] = {0}; - TimerTime_t nextTxDelay = 0; - - if (RegionCommonCountChannels(ChannelsMask, 0, 1) == 0) - { // Reactivate default channels - ChannelsMask[0] |= LC(1) + LC(2) + LC(3); - } - - if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) - { - // Reset Aggregated time off - *aggregatedTimeOff = 0; - - // Update bands Time OFF - nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, CN779_MAX_NB_BANDS); - - // Search how many channels are enabled - nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Joined, nextChanParams->Datarate, - ChannelsMask, Channels, - Bands, enabledChannels, &delayTx); - } - else - { - delayTx++; - nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); - } - - if (nbEnabledChannels > 0) - { - // We found a valid channel - *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; - - *time = 0; - return true; - } - else - { - if (delayTx > 0) - { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = nextTxDelay; - return true; - } - // Datarate not supported by any channel, restore defaults - ChannelsMask[0] |= LC(1) + LC(2) + LC(3); - *time = 0; - return false; - } - } - - LoRaMacStatus_t RegionCN779ChannelAdd(ChannelAddParams_t *channelAdd) - { - uint8_t band = 0; - bool drInvalid = false; - bool freqInvalid = false; - uint8_t id = channelAdd->ChannelId; - - if (id >= CN779_MAX_NB_CHANNELS) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - // Validate the datarate range - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Min, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - if (channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max) - { - drInvalid = true; - } - - // Default channels don't accept all values - if (id < CN779_NUMB_DEFAULT_CHANNELS) - { - // Validate the datarate range for min: must be DR_0 - if (channelAdd->NewChannel->DrRange.Fields.Min > DR_0) - { - drInvalid = true; - } - // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, DR_5, CN779_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - // We are not allowed to change the frequency - if (channelAdd->NewChannel->Frequency != Channels[id].Frequency) - { - freqInvalid = true; - } - } - - // Check frequency - if (freqInvalid == false) - { - if (VerifyTxFreq(channelAdd->NewChannel->Frequency) == false) - { - freqInvalid = true; - } - } - - // Check status - if ((drInvalid == true) && (freqInvalid == true)) - { - return LORAMAC_STATUS_FREQ_AND_DR_INVALID; - } - if (drInvalid == true) - { - return LORAMAC_STATUS_DATARATE_INVALID; - } - if (freqInvalid == true) - { - return LORAMAC_STATUS_FREQUENCY_INVALID; - } - - memcpy(&(Channels[id]), channelAdd->NewChannel, sizeof(Channels[id])); - Channels[id].Band = band; - ChannelsMask[0] |= (1 << id); - return LORAMAC_STATUS_OK; - } - - bool RegionCN779ChannelsRemove(ChannelRemoveParams_t *channelRemove) - { - uint8_t id = channelRemove->ChannelId; - - if (id < CN779_NUMB_DEFAULT_CHANNELS) - { - return false; - } - - // Remove the channel from the list of channels - Channels[id] = (ChannelParams_t){0, 0, {0}, 0}; - - return RegionCommonChanDisable(ChannelsMask, id, CN779_MAX_NB_CHANNELS); - } - - void RegionCN779SetContinuousWave(ContinuousWaveParams_t *continuousWave) - { - int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); - int8_t phyTxPower = 0; - uint32_t frequency = Channels[continuousWave->Channel].Frequency; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); - - Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); - } - - uint8_t RegionCN779ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) - { - int8_t datarate = dr - drOffset; - - if (datarate < 0) - { - datarate = DR_0; - } - return datarate; - } + static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; + + // Static functions + static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) + { + uint8_t nextLowerDr = 0; + + if (dr == minDr) + { + nextLowerDr = minDr; + } + else + { + nextLowerDr = dr - 1; + } + return nextLowerDr; + } + + static uint32_t GetBandwidth(uint32_t drIndex) + { + switch (BandwidthsCN779[drIndex]) + { + default: + case 125000: + return 0; + case 250000: + return 1; + case 500000: + return 2; + } + } + + static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) + { + int8_t txPowerResult = txPower; + + // Limit tx power to the band max + txPowerResult = MAX(txPower, maxBandTxPower); + + return txPowerResult; + } + + static bool VerifyTxFreq(uint32_t freq) + { + // Check radio driver support + if (Radio.CheckRfFrequency(freq) == false) + { + return false; + } + + if ((freq < 779500000) || (freq > 786500000)) + { + return false; + } + return true; + } + + static uint8_t CountNbOfEnabledChannels(bool joined, uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTransmission = 0; + + for (uint8_t i = 0, k = 0; i < CN779_MAX_NB_CHANNELS; i += 16, k++) + { + for (uint8_t j = 0; j < 16; j++) + { + if ((channelsMask[k] & (1 << j)) != 0) + { + if (channels[i + j].Frequency == 0) + { // Check if the channel is enabled + continue; + } + if (joined == false) + { + if ((CN779_JOIN_CHANNELS & (1 << j)) == 0) + { + continue; + } + } + if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, + channels[i + j].DrRange.Fields.Max) == false) + { // Check if the current channel selection supports the given datarate + continue; + } + if (bands[channels[i + j].Band].TimeOff > 0) + { // Check if the band is available for transmission + delayTransmission++; + continue; + } + enabledChannels[nbEnabledChannels++] = i + j; + } + } + } + + *delayTx = delayTransmission; + return nbEnabledChannels; + } + + PhyParam_t RegionCN779GetPhyParam(GetPhyParams_t *getPhy) + { + PhyParam_t phyParam = {0}; + + switch (getPhy->Attribute) + { + case PHY_MIN_RX_DR: + { + phyParam.Value = CN779_RX_MIN_DATARATE; + break; + } + case PHY_MIN_TX_DR: + { + phyParam.Value = CN779_TX_MIN_DATARATE; + break; + } + case PHY_DEF_TX_DR: + { + phyParam.Value = CN779_DEFAULT_DATARATE; + break; + } + case PHY_NEXT_LOWER_TX_DR: + { + phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, CN779_TX_MIN_DATARATE); + break; + } + case PHY_DEF_TX_POWER: + { + phyParam.Value = CN779_DEFAULT_TX_POWER; + break; + } + case PHY_MAX_PAYLOAD: + { + phyParam.Value = MaxPayloadOfDatarateCN779[getPhy->Datarate]; + break; + } + case PHY_MAX_PAYLOAD_REPEATER: + { + phyParam.Value = MaxPayloadOfDatarateRepeaterCN779[getPhy->Datarate]; + break; + } + case PHY_DUTY_CYCLE: + { + phyParam.Value = CN779_DUTY_CYCLE_ENABLED; + break; + } + case PHY_MAX_RX_WINDOW: + { + phyParam.Value = CN779_MAX_RX_WINDOW; + break; + } + case PHY_RECEIVE_DELAY1: + { + phyParam.Value = CN779_RECEIVE_DELAY1; + break; + } + case PHY_RECEIVE_DELAY2: + { + phyParam.Value = CN779_RECEIVE_DELAY2; + break; + } + case PHY_JOIN_ACCEPT_DELAY1: + { + phyParam.Value = CN779_JOIN_ACCEPT_DELAY1; + break; + } + case PHY_JOIN_ACCEPT_DELAY2: + { + phyParam.Value = CN779_JOIN_ACCEPT_DELAY2; + break; + } + case PHY_MAX_FCNT_GAP: + { + phyParam.Value = CN779_MAX_FCNT_GAP; + break; + } + case PHY_ACK_TIMEOUT: + { + phyParam.Value = (CN779_ACKTIMEOUT + randr(-CN779_ACK_TIMEOUT_RND, CN779_ACK_TIMEOUT_RND)); + break; + } + case PHY_DEF_DR1_OFFSET: + { + phyParam.Value = CN779_DEFAULT_RX1_DR_OFFSET; + break; + } + case PHY_DEF_RX2_FREQUENCY: + { + phyParam.Value = CN779_RX_WND_2_FREQ; + break; + } + case PHY_DEF_RX2_DR: + { + phyParam.Value = CN779_RX_WND_2_DR; + break; + } + case PHY_CHANNELS_MASK: + { + phyParam.ChannelsMask = ChannelsMask; + break; + } + case PHY_CHANNELS_DEFAULT_MASK: + { + phyParam.ChannelsMask = ChannelsDefaultMask; + break; + } + case PHY_MAX_NB_CHANNELS: + { + phyParam.Value = CN779_MAX_NB_CHANNELS; + break; + } + case PHY_CHANNELS: + { + phyParam.Channels = Channels; + break; + } + case PHY_DEF_UPLINK_DWELL_TIME: + case PHY_DEF_DOWNLINK_DWELL_TIME: + { + phyParam.Value = 0; + break; + } + case PHY_DEF_MAX_EIRP: + { + phyParam.fValue = CN779_DEFAULT_MAX_EIRP; + break; + } + case PHY_DEF_ANTENNA_GAIN: + { + phyParam.fValue = CN779_DEFAULT_ANTENNA_GAIN; + break; + } + case PHY_NB_JOIN_TRIALS: + case PHY_DEF_NB_JOIN_TRIALS: + { + phyParam.Value = 48; + break; + } + default: + { + break; + } + } + + return phyParam; + } + + void RegionCN779SetBandTxDone(SetBandTxDoneParams_t *txDone) + { + RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); + } + + void RegionCN779InitDefaults(InitType_t type) + { + switch (type) + { + case INIT_TYPE_INIT: + { + // Channels + Channels[0] = (ChannelParams_t)CN779_LC1; + Channels[1] = (ChannelParams_t)CN779_LC2; + Channels[2] = (ChannelParams_t)CN779_LC3; + + // Initialize the channels default mask + ChannelsDefaultMask[0] = LC(1) + LC(2) + LC(3); + // Update the channels mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); + break; + } + case INIT_TYPE_RESTORE: + { + // Restore channels default mask + ChannelsMask[0] |= ChannelsDefaultMask[0]; + break; + } + case INIT_TYPE_APP_DEFAULTS: + { + // Update the channels mask defaults + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); + break; + } + default: + { + break; + } + } + } + + bool RegionCN779Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) + { + switch (phyAttribute) + { + case PHY_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE); + } + case PHY_DEF_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); + } + case PHY_RX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, CN779_RX_MIN_DATARATE, CN779_RX_MAX_DATARATE); + } + case PHY_DEF_TX_POWER: + case PHY_TX_POWER: + { + // Remark: switched min and max! + return RegionCommonValueInRange(verify->TxPower, CN779_MAX_TX_POWER, CN779_MIN_TX_POWER); + } + case PHY_DUTY_CYCLE: + { + return CN779_DUTY_CYCLE_ENABLED; + } + case PHY_NB_JOIN_TRIALS: + { + if (verify->NbJoinTrials < 48) + { + return false; + } + break; + } + default: + return false; + } + return true; + } + + void RegionCN779ApplyCFList(ApplyCFListParams_t *applyCFList) + { + ChannelParams_t newChannel; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + // Setup default datarate range + newChannel.DrRange.Value = (DR_5 << 4) | DR_0; + + // Size of the optional CF list + if (applyCFList->Size != 16) + { + return; + } + + // Last byte is RFU, don't take it into account + for (uint8_t i = 0, chanIdx = CN779_NUMB_DEFAULT_CHANNELS; chanIdx < CN779_MAX_NB_CHANNELS; i += 3, chanIdx++) + { + if (chanIdx < (CN779_NUMB_CHANNELS_CF_LIST + CN779_NUMB_DEFAULT_CHANNELS)) + { + // Channel frequency + newChannel.Frequency = (uint32_t)applyCFList->Payload[i]; + newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 1] << 8); + newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 2] << 16); + newChannel.Frequency *= 100; + + // Initialize alternative frequency to 0 + newChannel.Rx1Frequency = 0; + } + else + { + newChannel.Frequency = 0; + newChannel.DrRange.Value = 0; + newChannel.Rx1Frequency = 0; + } + + if (newChannel.Frequency != 0) + { + channelAdd.NewChannel = &newChannel; + channelAdd.ChannelId = chanIdx; + + // Try to add all channels + RegionCN779ChannelAdd(&channelAdd); + } + else + { + channelRemove.ChannelId = chanIdx; + + RegionCN779ChannelsRemove(&channelRemove); + } + } + } + + bool RegionCN779ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) + { + switch (chanMaskSet->ChannelsMaskType) + { + case CHANNELS_MASK: + { + RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 1); + break; + } + case CHANNELS_DEFAULT_MASK: + { + RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1); + break; + } + default: + return false; + } + return true; + } + + bool RegionCN779AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) + { + bool adrAckReq = false; + int8_t datarate = adrNext->Datarate; + int8_t txPower = adrNext->TxPower; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + + // Report back the adr ack counter + *adrAckCounter = adrNext->AdrAckCounter; + + if (adrNext->AdrEnabled == true) + { + if (datarate == CN779_TX_MIN_DATARATE) + { + *adrAckCounter = 0; + adrAckReq = false; + } + else + { + if (adrNext->AdrAckCounter >= CN779_ADR_ACK_LIMIT) + { + adrAckReq = true; + txPower = CN779_MAX_TX_POWER; + } + else + { + adrAckReq = false; + } + if (adrNext->AdrAckCounter >= (CN779_ADR_ACK_LIMIT + CN779_ADR_ACK_DELAY)) + { + if ((adrNext->AdrAckCounter % CN779_ADR_ACK_DELAY) == 1) + { + // Decrease the datarate + getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; + getPhy.Datarate = datarate; + getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; + phyParam = RegionCN779GetPhyParam(&getPhy); + datarate = phyParam.Value; + + if (datarate == CN779_TX_MIN_DATARATE) + { + // We must set adrAckReq to false as soon as we reach the lowest datarate + adrAckReq = false; + if (adrNext->UpdateChanMask == true) + { + // Re-enable default channels + ChannelsMask[0] |= LC(1) + LC(2) + LC(3); + } + } + } + } + } + } + + *drOut = datarate; + *txPowOut = txPower; + return adrAckReq; + } + + void RegionCN779ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) + { + double tSymbol = 0.0; + + // Get the datarate, perform a boundary check + rxConfigParams->Datarate = MIN(datarate, CN779_RX_MAX_DATARATE); + rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); + + if (rxConfigParams->Datarate == DR_7) + { // FSK + tSymbol = RegionCommonComputeSymbolTimeFsk(DataratesCN779[rxConfigParams->Datarate]); + } + else + { // LoRa + tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesCN779[rxConfigParams->Datarate], BandwidthsCN779[rxConfigParams->Datarate]); + } + + RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); + } + + bool RegionCN779RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) + { + RadioModems_t modem; + int8_t dr = rxConfig->Datarate; + uint8_t maxPayload = 0; + int8_t phyDr = 0; + uint32_t frequency = rxConfig->Frequency; + + if (Radio.GetStatus() != RF_IDLE) + { + return false; + } + + if (rxConfig->Window == 0) + { + // Apply window 1 frequency + frequency = Channels[rxConfig->Channel].Frequency; + // Apply the alternative RX 1 window frequency, if it is available + if (Channels[rxConfig->Channel].Rx1Frequency != 0) + { + frequency = Channels[rxConfig->Channel].Rx1Frequency; + } + } + + // Read the physical datarate from the datarates table + phyDr = DataratesCN779[dr]; + + Radio.SetChannel(frequency); + + // Radio configuration + if (dr == DR_7) + { + modem = MODEM_FSK; + Radio.SetRxConfig(modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous); + } + else + { + modem = MODEM_LORA; + Radio.SetRxConfig(modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); + } + + if (rxConfig->RepeaterSupport == true) + { + maxPayload = MaxPayloadOfDatarateRepeaterCN779[dr]; + } + else + { + maxPayload = MaxPayloadOfDatarateCN779[dr]; + } + Radio.SetMaxPayloadLength(modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + *datarate = (uint8_t)dr; + return true; + } + + bool RegionCN779TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) + { + RadioModems_t modem; + int8_t phyDr = DataratesCN779[txConfig->Datarate]; + int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); + uint32_t bandwidth = GetBandwidth(txConfig->Datarate); + int8_t phyTxPower = 0; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); + + // Setup the radio frequency + Radio.SetChannel(Channels[txConfig->Channel].Frequency); + + if (txConfig->Datarate == DR_7) + { // High Speed FSK channel + modem = MODEM_FSK; + Radio.SetTxConfig(modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000); + } + else + { + modem = MODEM_LORA; + Radio.SetTxConfig(modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); + } + + // Setup maximum payload lenght of the radio driver + Radio.SetMaxPayloadLength(modem, txConfig->PktLen); + // Get the time-on-air of the next tx frame + *txTimeOnAir = Radio.TimeOnAir(modem, txConfig->PktLen); + + *txPower = txPowerLimited; + return true; + } + + uint8_t RegionCN779LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) + { + uint8_t status = 0x07; + RegionCommonLinkAdrParams_t linkAdrParams; + uint8_t nextIndex = 0; + uint8_t bytesProcessed = 0; + uint16_t chMask = 0; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; + + while (bytesProcessed < linkAdrReq->PayloadSize) + { + // Get ADR request parameters + nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); + + if (nextIndex == 0) + break; // break loop, since no more request has been found + + // Update bytes processed + bytesProcessed += nextIndex; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + // Setup temporary channels mask + chMask = linkAdrParams.ChMask; + + // Verify channels mask + if ((linkAdrParams.ChMaskCtrl == 0) && (chMask == 0)) + { + status &= 0xFE; // Channel mask KO + } + else if (((linkAdrParams.ChMaskCtrl >= 1) && (linkAdrParams.ChMaskCtrl <= 5)) || + (linkAdrParams.ChMaskCtrl >= 7)) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + for (uint8_t i = 0; i < CN779_MAX_NB_CHANNELS; i++) + { + if (linkAdrParams.ChMaskCtrl == 6) + { + if (Channels[i].Frequency != 0) + { + chMask |= 1 << i; + } + } + else + { + if (((chMask & (1 << i)) != 0) && + (Channels[i].Frequency == 0)) + { // Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + } + } + } + + // Get the minimum possible datarate + getPhy.Attribute = PHY_MIN_TX_DR; + getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; + phyParam = RegionCN779GetPhyParam(&getPhy); + + linkAdrVerifyParams.Status = status; + linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; + linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; + linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; + linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; + linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; + linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; + linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; + linkAdrVerifyParams.NbChannels = CN779_MAX_NB_CHANNELS; + linkAdrVerifyParams.ChannelsMask = &chMask; + linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; + linkAdrVerifyParams.MaxDatarate = CN779_TX_MAX_DATARATE; + linkAdrVerifyParams.Channels = Channels; + linkAdrVerifyParams.MinTxPower = CN779_MIN_TX_POWER; + linkAdrVerifyParams.MaxTxPower = CN779_MAX_TX_POWER; + + // Verify the parameters and update, if necessary + status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); + + // Update channelsMask if everything is correct + if (status == 0x07) + { + // Set the channels mask to a default value + memset(ChannelsMask, 0, sizeof(ChannelsMask)); + // Update the channels mask + ChannelsMask[0] = chMask; + } + + // Update status variables + *drOut = linkAdrParams.Datarate; + *txPowOut = linkAdrParams.TxPower; + *nbRepOut = linkAdrParams.NbRep; + *nbBytesParsed = bytesProcessed; + + return status; + } + + uint8_t RegionCN779RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) + { + uint8_t status = 0x07; + + // Verify radio frequency + if (Radio.CheckRfFrequency(rxParamSetupReq->Frequency) == false) + { + status &= 0xFE; // Channel frequency KO + } + + // Verify datarate + if (RegionCommonValueInRange(rxParamSetupReq->Datarate, CN779_RX_MIN_DATARATE, CN779_RX_MAX_DATARATE) == false) + { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, CN779_MIN_RX1_DR_OFFSET, CN779_MAX_RX1_DR_OFFSET) == false) + { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; + } + + uint8_t RegionCN779NewChannelReq(NewChannelReqParams_t *newChannelReq) + { + uint8_t status = 0x03; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + if (newChannelReq->NewChannel->Frequency == 0) + { + channelRemove.ChannelId = newChannelReq->ChannelId; + + // Remove + if (RegionCN779ChannelsRemove(&channelRemove) == false) + { + status &= 0xFC; + } + } + else + { + channelAdd.NewChannel = newChannelReq->NewChannel; + channelAdd.ChannelId = newChannelReq->ChannelId; + + switch (RegionCN779ChannelAdd(&channelAdd)) + { + case LORAMAC_STATUS_OK: + { + break; + } + case LORAMAC_STATUS_FREQUENCY_INVALID: + { + status &= 0xFE; + break; + } + case LORAMAC_STATUS_DATARATE_INVALID: + { + status &= 0xFD; + break; + } + case LORAMAC_STATUS_FREQ_AND_DR_INVALID: + { + status &= 0xFC; + break; + } + default: + { + status &= 0xFC; + break; + } + } + } + + return status; + } + + int8_t RegionCN779TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) + { + return -1; + } + + uint8_t RegionCN779DlChannelReq(DlChannelReqParams_t *dlChannelReq) + { + uint8_t status = 0x03; + + // Verify if the frequency is supported + if (VerifyTxFreq(dlChannelReq->Rx1Frequency) == false) + { + status &= 0xFE; + } + + // Verify if an uplink frequency exists + if (Channels[dlChannelReq->ChannelId].Frequency == 0) + { + status &= 0xFD; + } + + // Apply Rx1 frequency, if the status is OK + if (status == 0x03) + { + Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency; + } + + return status; + } + + int8_t RegionCN779AlternateDr(AlternateDrParams_t *alternateDr) + { + int8_t datarate = 0; + + if ((alternateDr->NbTrials % 48) == 0) + { + datarate = DR_0; + } + else if ((alternateDr->NbTrials % 32) == 0) + { + datarate = DR_1; + } + else if ((alternateDr->NbTrials % 24) == 0) + { + datarate = DR_2; + } + else if ((alternateDr->NbTrials % 16) == 0) + { + datarate = DR_3; + } + else if ((alternateDr->NbTrials % 8) == 0) + { + datarate = DR_4; + } + else + { + datarate = DR_5; + } + return datarate; + } + + void RegionCN779CalcBackOff(CalcBackOffParams_t *calcBackOff) + { + RegionCommonCalcBackOffParams_t calcBackOffParams; + + calcBackOffParams.Channels = Channels; + calcBackOffParams.Bands = Bands; + calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; + calcBackOffParams.Joined = calcBackOff->Joined; + calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; + calcBackOffParams.Channel = calcBackOff->Channel; + calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; + calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; + + RegionCommonCalcBackOff(&calcBackOffParams); + } + + bool RegionCN779NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTx = 0; + uint8_t enabledChannels[CN779_MAX_NB_CHANNELS] = {0}; + TimerTime_t nextTxDelay = 0; + + if (RegionCommonCountChannels(ChannelsMask, 0, 1) == 0) + { // Reactivate default channels + ChannelsMask[0] |= LC(1) + LC(2) + LC(3); + } + + if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) + { + // Reset Aggregated time off + *aggregatedTimeOff = 0; + + // Update bands Time OFF + nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, CN779_MAX_NB_BANDS); + + // Search how many channels are enabled + nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Joined, nextChanParams->Datarate, + ChannelsMask, Channels, + Bands, enabledChannels, &delayTx); + } + else + { + delayTx++; + nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); + } + + if (nbEnabledChannels > 0) + { + // We found a valid channel + *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; + + *time = 0; + return true; + } + else + { + if (delayTx > 0) + { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return true; + } + // Datarate not supported by any channel, restore defaults + ChannelsMask[0] |= LC(1) + LC(2) + LC(3); + *time = 0; + return false; + } + } + + LoRaMacStatus_t RegionCN779ChannelAdd(ChannelAddParams_t *channelAdd) + { + uint8_t band = 0; + bool drInvalid = false; + bool freqInvalid = false; + uint8_t id = channelAdd->ChannelId; + + if (id >= CN779_MAX_NB_CHANNELS) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + // Validate the datarate range + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Min, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + if (channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max) + { + drInvalid = true; + } + + // Default channels don't accept all values + if (id < CN779_NUMB_DEFAULT_CHANNELS) + { + // Validate the datarate range for min: must be DR_0 + if (channelAdd->NewChannel->DrRange.Fields.Min > DR_0) + { + drInvalid = true; + } + // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, DR_5, CN779_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + // We are not allowed to change the frequency + if (channelAdd->NewChannel->Frequency != Channels[id].Frequency) + { + freqInvalid = true; + } + } + + // Check frequency + if (freqInvalid == false) + { + if (VerifyTxFreq(channelAdd->NewChannel->Frequency) == false) + { + freqInvalid = true; + } + } + + // Check status + if ((drInvalid == true) && (freqInvalid == true)) + { + return LORAMAC_STATUS_FREQ_AND_DR_INVALID; + } + if (drInvalid == true) + { + return LORAMAC_STATUS_DATARATE_INVALID; + } + if (freqInvalid == true) + { + return LORAMAC_STATUS_FREQUENCY_INVALID; + } + + memcpy(&(Channels[id]), channelAdd->NewChannel, sizeof(Channels[id])); + Channels[id].Band = band; + ChannelsMask[0] |= (1 << id); + return LORAMAC_STATUS_OK; + } + + bool RegionCN779ChannelsRemove(ChannelRemoveParams_t *channelRemove) + { + uint8_t id = channelRemove->ChannelId; + + if (id < CN779_NUMB_DEFAULT_CHANNELS) + { + return false; + } + + // Remove the channel from the list of channels + Channels[id] = (ChannelParams_t){0, 0, {0}, 0}; + + return RegionCommonChanDisable(ChannelsMask, id, CN779_MAX_NB_CHANNELS); + } + + void RegionCN779SetContinuousWave(ContinuousWaveParams_t *continuousWave) + { + int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); + int8_t phyTxPower = 0; + uint32_t frequency = Channels[continuousWave->Channel].Frequency; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); + + Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); + } + + uint8_t RegionCN779ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) + { + int8_t datarate = dr - drOffset; + + if (datarate < 0) + { + datarate = DR_0; + } + return datarate; + } }; \ No newline at end of file diff --git a/src/mac/region/RegionCN779.h b/src/mac/region/RegionCN779.h index dfcf1fe..147507a 100644 --- a/src/mac/region/RegionCN779.h +++ b/src/mac/region/RegionCN779.h @@ -41,232 +41,244 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define CN779_MAX_NB_CHANNELS 16 +#define CN779_MAX_NB_CHANNELS 16 /*! * Number of default channels */ -#define CN779_NUMB_DEFAULT_CHANNELS 3 +#define CN779_NUMB_DEFAULT_CHANNELS 3 /*! * Number of channels to apply for the CF list */ -#define CN779_NUMB_CHANNELS_CF_LIST 5 +#define CN779_NUMB_CHANNELS_CF_LIST 5 /*! * Minimal datarate that can be used by the node */ -#define CN779_TX_MIN_DATARATE DR_0 +#define CN779_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define CN779_TX_MAX_DATARATE DR_7 +#define CN779_TX_MAX_DATARATE DR_7 /*! * Minimal datarate that can be used by the node */ -#define CN779_RX_MIN_DATARATE DR_0 +#define CN779_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define CN779_RX_MAX_DATARATE DR_7 +#define CN779_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node */ -#define CN779_DEFAULT_DATARATE DR_0 +#define CN779_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define CN779_MIN_RX1_DR_OFFSET 0 +#define CN779_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define CN779_MAX_RX1_DR_OFFSET 5 +#define CN779_MAX_RX1_DR_OFFSET 5 /*! * Default Rx1 receive datarate offset */ -#define CN779_DEFAULT_RX1_DR_OFFSET 0 +#define CN779_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define CN779_MIN_TX_POWER TX_POWER_5 +#define CN779_MIN_TX_POWER TX_POWER_5 /*! * Maximal Tx output power that can be used by the node */ -#define CN779_MAX_TX_POWER TX_POWER_0 +#define CN779_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define CN779_DEFAULT_TX_POWER TX_POWER_0 +#define CN779_DEFAULT_TX_POWER TX_POWER_0 /*! * Default Max EIRP */ -#define CN779_DEFAULT_MAX_EIRP 12.15f +#define CN779_DEFAULT_MAX_EIRP 12.15f /*! * Default antenna gain */ -#define CN779_DEFAULT_ANTENNA_GAIN 2.15f +#define CN779_DEFAULT_ANTENNA_GAIN 2.15f /*! * ADR Ack limit */ -#define CN779_ADR_ACK_LIMIT 64 +#define CN779_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define CN779_ADR_ACK_DELAY 32 +#define CN779_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define CN779_DUTY_CYCLE_ENABLED 1 +#define CN779_DUTY_CYCLE_ENABLED 1 /*! * Maximum RX window duration */ -#define CN779_MAX_RX_WINDOW 3000 +#define CN779_MAX_RX_WINDOW 3000 /*! * Receive delay 1 */ -#define CN779_RECEIVE_DELAY1 1000 +#define CN779_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define CN779_RECEIVE_DELAY2 2000 +#define CN779_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define CN779_JOIN_ACCEPT_DELAY1 5000 +#define CN779_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define CN779_JOIN_ACCEPT_DELAY2 6000 +#define CN779_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define CN779_MAX_FCNT_GAP 16384 +#define CN779_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define CN779_ACKTIMEOUT 2000 +#define CN779_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define CN779_ACK_TIMEOUT_RND 1000 +#define CN779_ACK_TIMEOUT_RND 1000 /*! * Verification of default datarate */ -#if ( CN779_DEFAULT_DATARATE > DR_5 ) +#if (CN779_DEFAULT_DATARATE > DR_5) #error "A default DR higher than DR_5 may lead to connectivity loss." #endif /*! * Second reception window channel frequency definition. */ -#define CN779_RX_WND_2_FREQ 786000000 +#define CN779_RX_WND_2_FREQ 786000000 /*! * Second reception window channel datarate definition. */ -#define CN779_RX_WND_2_DR DR_0 +#define CN779_RX_WND_2_DR DR_0 /*! * LoRaMac maximum number of bands */ -#define CN779_MAX_NB_BANDS 1 +#define CN779_MAX_NB_BANDS 1 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define CN779_BAND0 { 100, CN779_MAX_TX_POWER, 0, 0 } // 1.0 % +#define CN779_BAND0 \ + { \ + 100, CN779_MAX_TX_POWER, 0, 0 \ + } // 1.0 % /*! * LoRaMac default channel 1 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define CN779_LC1 { 779500000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define CN779_LC1 \ + { \ + 779500000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac default channel 2 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define CN779_LC2 { 779700000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define CN779_LC2 \ + { \ + 779700000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac default channel 3 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define CN779_LC3 { 779900000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define CN779_LC3 \ + { \ + 779900000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac channels which are allowed for the join procedure */ -#define CN779_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) +#define CN779_JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesCN779[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; + static const uint8_t DataratesCN779[] = {12, 11, 10, 9, 8, 7, 7, 50}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsCN779[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 }; + static const uint32_t BandwidthsCN779[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; -/*! + /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateCN779[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; + static const uint8_t MaxPayloadOfDatarateCN779[] = {51, 51, 51, 115, 242, 242, 242, 242}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateRepeaterCN779[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; + static const uint8_t MaxPayloadOfDatarateRepeaterCN779[] = {51, 51, 51, 115, 222, 222, 222, 222}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionCN779GetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionCN779GetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionCN779SetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionCN779SetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionCN779InitDefaults( InitType_t type ); + void RegionCN779InitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -275,26 +287,26 @@ void RegionCN779InitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionCN779Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionCN779Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionCN779ApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionCN779ApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionCN779ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionCN779ChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -307,9 +319,9 @@ bool RegionCN779ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionCN779AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionCN779AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -322,9 +334,9 @@ bool RegionCN779AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowO * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionCN779ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionCN779ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -333,9 +345,9 @@ void RegionCN779ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionCN779RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionCN779RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -346,36 +358,36 @@ bool RegionCN779RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionCN779TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionCN779TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionCN779LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionCN779LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionCN779RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionCN779RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionCN779NewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionCN779NewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -384,34 +396,34 @@ uint8_t RegionCN779NewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionCN779TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionCN779TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionCN779DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionCN779DlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionCN779AlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionCN779AlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionCN779CalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionCN779CalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -423,34 +435,34 @@ void RegionCN779CalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionCN779NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionCN779NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionCN779ChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionCN779ChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionCN779ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionCN779ChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionCN779SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionCN779SetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -461,8 +473,8 @@ void RegionCN779SetContinuousWave( ContinuousWaveParams_t* continuousWave ); * * \retval newDr Computed datarate. */ -uint8_t RegionCN779ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionCN779ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONCN779 */ + /*! \} defgroup REGIONCN779 */ }; #endif // __REGION_CN779_H__ diff --git a/src/mac/region/RegionCommon.cpp b/src/mac/region/RegionCommon.cpp index 7c27e1b..4a582b0 100644 --- a/src/mac/region/RegionCommon.cpp +++ b/src/mac/region/RegionCommon.cpp @@ -35,326 +35,326 @@ extern "C" #define BACKOFF_DC_10_HOURS 1000 #define BACKOFF_DC_24_HOURS 10000 - static uint8_t CountChannels(uint16_t mask, uint8_t nbBits) - { - uint8_t nbActiveBits = 0; - - for (uint8_t j = 0; j < nbBits; j++) - { - if ((mask & (1 << j)) == (1 << j)) - { - nbActiveBits++; - } - } - return nbActiveBits; - } - - uint16_t RegionCommonGetJoinDc(TimerTime_t elapsedTime) - { - uint16_t dutyCycle = 0; - - if (elapsedTime < 3600000) - { - dutyCycle = BACKOFF_DC_1_HOUR; - } - else if (elapsedTime < (3600000 + 36000000)) - { - dutyCycle = BACKOFF_DC_10_HOURS; - } - else - { - dutyCycle = BACKOFF_DC_24_HOURS; - } - return dutyCycle; - } - - bool RegionCommonChanVerifyDr(uint8_t nbChannels, uint16_t *channelsMask, int8_t dr, int8_t minDr, int8_t maxDr, ChannelParams_t *channels) - { - if (RegionCommonValueInRange(dr, minDr, maxDr) == 0) - { - return false; - } - - for (uint8_t i = 0, k = 0; i < nbChannels; i += 16, k++) - { - for (uint8_t j = 0; j < 16; j++) - { - if (((channelsMask[k] & (1 << j)) != 0)) - { // Check datarate validity for enabled channels - if (RegionCommonValueInRange(dr, (channels[i + j].DrRange.Fields.Min & 0x0F), - (channels[i + j].DrRange.Fields.Max & 0x0F)) == 1) - { - // At least 1 channel has been found we can return OK. - return true; - } - } - } - } - return false; - } - - uint8_t RegionCommonValueInRange(int8_t value, int8_t min, int8_t max) - { - if ((value >= min) && (value <= max)) - { - return 1; - } - return 0; - } - - bool RegionCommonChanDisable(uint16_t *channelsMask, uint8_t id, uint8_t maxChannels) - { - uint8_t index = id / 16; - - if ((index > (maxChannels / 16)) || (id >= maxChannels)) - { - return false; - } - - // Deactivate channel - channelsMask[index] &= ~(1 << (id % 16)); - - return true; - } - - uint8_t RegionCommonCountChannels(uint16_t *channelsMask, uint8_t startIdx, uint8_t stopIdx) - { - uint8_t nbChannels = 0; - - if (channelsMask == NULL) - { - return 0; - } - - for (uint8_t i = startIdx; i < stopIdx; i++) - { - nbChannels += CountChannels(channelsMask[i], 16); - } - - return nbChannels; - } - - void RegionCommonChanMaskCopy(uint16_t *channelsMaskDest, uint16_t *channelsMaskSrc, uint8_t len) - { - if ((channelsMaskDest != NULL) && (channelsMaskSrc != NULL)) - { - for (uint8_t i = 0; i < len; i++) - { - channelsMaskDest[i] = channelsMaskSrc[i]; - } - } - } - - void RegionCommonSetBandTxDone(bool joined, Band_t *band, TimerTime_t lastTxDone) - { - if (joined == true) - { - band->LastTxDoneTime = lastTxDone; - } - else - { - band->LastTxDoneTime = lastTxDone; - band->LastJoinTxDoneTime = lastTxDone; - } - } - - TimerTime_t RegionCommonUpdateBandTimeOff(bool joined, bool dutyCycle, Band_t *bands, uint8_t nbBands) - { - TimerTime_t nextTxDelay = (TimerTime_t)(-1); - - // Update bands Time OFF - for (uint8_t i = 0; i < nbBands; i++) - { - if (joined == false) - { - uint32_t txDoneTime = MAX(TimerGetElapsedTime(bands[i].LastJoinTxDoneTime), - (dutyCycle == true) ? TimerGetElapsedTime(bands[i].LastTxDoneTime) : 0); - - if (bands[i].TimeOff <= txDoneTime) - { - bands[i].TimeOff = 0; - } - if (bands[i].TimeOff != 0) - { - nextTxDelay = MIN(bands[i].TimeOff - txDoneTime, nextTxDelay); - } - } - else - { - if (dutyCycle == true) - { - if (bands[i].TimeOff <= TimerGetElapsedTime(bands[i].LastTxDoneTime)) - { - bands[i].TimeOff = 0; - } - if (bands[i].TimeOff != 0) - { - nextTxDelay = MIN(bands[i].TimeOff - TimerGetElapsedTime(bands[i].LastTxDoneTime), - nextTxDelay); - } - } - else - { - nextTxDelay = 0; - bands[i].TimeOff = 0; - } - } - } - return nextTxDelay; - } - - uint8_t RegionCommonParseLinkAdrReq(uint8_t *payload, RegionCommonLinkAdrParams_t *linkAdrParams) - { - uint8_t retIndex = 0; - - if (payload[0] == SRV_MAC_LINK_ADR_REQ) - { - // Parse datarate and tx power - linkAdrParams->Datarate = payload[1]; - linkAdrParams->TxPower = linkAdrParams->Datarate & 0x0F; - linkAdrParams->Datarate = (linkAdrParams->Datarate >> 4) & 0x0F; - // Parse ChMask - linkAdrParams->ChMask = (uint16_t)payload[2]; - linkAdrParams->ChMask |= (uint16_t)payload[3] << 8; - // Parse ChMaskCtrl and nbRep - linkAdrParams->NbRep = payload[4]; - linkAdrParams->ChMaskCtrl = (linkAdrParams->NbRep >> 4) & 0x07; - linkAdrParams->NbRep &= 0x0F; - - // LinkAdrReq has 4 bytes length + 1 byte CMD - retIndex = 5; - } - return retIndex; - } - - uint8_t RegionCommonLinkAdrReqVerifyParams(RegionCommonLinkAdrReqVerifyParams_t *verifyParams, int8_t *dr, int8_t *txPow, uint8_t *nbRep) - { - uint8_t status = verifyParams->Status; - int8_t datarate = verifyParams->Datarate; - int8_t txPower = verifyParams->TxPower; - int8_t nbRepetitions = verifyParams->NbRep; - - // Handle the case when ADR is off. - if (verifyParams->AdrEnabled == false) - { - // When ADR is off, we are allowed to change the channels mask and the NbRep, - // if the datarate and the TX power of the LinkAdrReq are set to 0x0F. - if ((verifyParams->Datarate != 0x0F) || (verifyParams->TxPower != 0x0F)) - { - status = 0; - nbRepetitions = verifyParams->CurrentNbRep; - } - // Get the current datarate and tx power - datarate = verifyParams->CurrentDatarate; - txPower = verifyParams->CurrentTxPower; - } - - if (status != 0) - { - // Verify datarate. The variable phyParam. Value contains the minimum allowed datarate. - if (RegionCommonChanVerifyDr(verifyParams->NbChannels, verifyParams->ChannelsMask, datarate, - verifyParams->MinDatarate, verifyParams->MaxDatarate, verifyParams->Channels) == false) - { - status &= 0xFD; // Datarate KO - } - - // Verify tx power - if (RegionCommonValueInRange(txPower, verifyParams->MaxTxPower, verifyParams->MinTxPower) == 0) - { - // Verify if the maximum TX power is exceeded - if (verifyParams->MaxTxPower > txPower) - { // Apply maximum TX power. Accept TX power. - txPower = verifyParams->MaxTxPower; - } - else - { - status &= 0xFB; // TxPower KO - } - } - } - - // If the status is ok, verify the NbRep - if (status == 0x07) - { - if (nbRepetitions == 0) - { // Keep the current one - nbRepetitions = verifyParams->CurrentNbRep; - } - } - - // Apply changes - *dr = datarate; - *txPow = txPower; - *nbRep = nbRepetitions; - - return status; - } - - double RegionCommonComputeSymbolTimeLoRa(uint8_t phyDr, uint32_t bandwidth) - { - return ((double)(1 << phyDr) / (double)bandwidth) * 1000; - } - - double RegionCommonComputeSymbolTimeFsk(uint8_t phyDr) - { - return (8.0 / (double)phyDr); // 1 symbol equals 1 byte - } - - void RegionCommonComputeRxWindowParameters(double tSymbol, uint8_t minRxSymbols, uint32_t rxError, uint32_t wakeUpTime, uint32_t *windowTimeout, int32_t *windowOffset) - { - *windowTimeout = MAX((uint32_t)ceil(((2 * minRxSymbols - 8) * tSymbol + 2 * rxError) / tSymbol), minRxSymbols); // Computed number of symbols - *windowOffset = (int32_t)ceil((4.0 * tSymbol) - ((*windowTimeout * tSymbol) / 2.0) - wakeUpTime); - } - - int8_t RegionCommonComputeTxPower(int8_t txPowerIndex, float maxEirp, float antennaGain) - { - int8_t phyTxPower = 0; - - phyTxPower = (int8_t)floor((maxEirp - (txPowerIndex * 2U)) - antennaGain); - - return phyTxPower; - } - - void RegionCommonCalcBackOff(RegionCommonCalcBackOffParams_t *calcBackOffParams) - { - uint8_t bandIdx = calcBackOffParams->Channels[calcBackOffParams->Channel].Band; - uint16_t dutyCycle = calcBackOffParams->Bands[bandIdx].DCycle; - uint16_t joinDutyCycle = 0; - - // Reset time-off to initial value. - calcBackOffParams->Bands[bandIdx].TimeOff = 0; - - if (calcBackOffParams->Joined == false) - { - // Get the join duty cycle - joinDutyCycle = RegionCommonGetJoinDc(calcBackOffParams->ElapsedTime); - // Apply the most restricting duty cycle - dutyCycle = MAX(dutyCycle, joinDutyCycle); - // Reset the timeoff if the last frame was not a join request and when the duty cycle is not enabled - if ((calcBackOffParams->DutyCycleEnabled == false) && (calcBackOffParams->LastTxIsJoinRequest == false)) - { - // This is the case when the duty cycle is off and the last uplink frame was not a join. - // This could happen in case of a rejoin, e.g. in compliance test mode. - // In this special case we have to set the time off to 0, since the join duty cycle shall only - // be applied after the first join request. - calcBackOffParams->Bands[bandIdx].TimeOff = 0; - } - else - { - // Apply band time-off. - calcBackOffParams->Bands[bandIdx].TimeOff = calcBackOffParams->TxTimeOnAir * dutyCycle - calcBackOffParams->TxTimeOnAir; - } - } - else - { - if (calcBackOffParams->DutyCycleEnabled == true) - { - calcBackOffParams->Bands[bandIdx].TimeOff = calcBackOffParams->TxTimeOnAir * dutyCycle - calcBackOffParams->TxTimeOnAir; - } - else - { - calcBackOffParams->Bands[bandIdx].TimeOff = 0; - } - } - } + static uint8_t CountChannels(uint16_t mask, uint8_t nbBits) + { + uint8_t nbActiveBits = 0; + + for (uint8_t j = 0; j < nbBits; j++) + { + if ((mask & (1 << j)) == (1 << j)) + { + nbActiveBits++; + } + } + return nbActiveBits; + } + + uint16_t RegionCommonGetJoinDc(TimerTime_t elapsedTime) + { + uint16_t dutyCycle = 0; + + if (elapsedTime < 3600000) + { + dutyCycle = BACKOFF_DC_1_HOUR; + } + else if (elapsedTime < (3600000 + 36000000)) + { + dutyCycle = BACKOFF_DC_10_HOURS; + } + else + { + dutyCycle = BACKOFF_DC_24_HOURS; + } + return dutyCycle; + } + + bool RegionCommonChanVerifyDr(uint8_t nbChannels, uint16_t *channelsMask, int8_t dr, int8_t minDr, int8_t maxDr, ChannelParams_t *channels) + { + if (RegionCommonValueInRange(dr, minDr, maxDr) == 0) + { + return false; + } + + for (uint8_t i = 0, k = 0; i < nbChannels; i += 16, k++) + { + for (uint8_t j = 0; j < 16; j++) + { + if (((channelsMask[k] & (1 << j)) != 0)) + { // Check datarate validity for enabled channels + if (RegionCommonValueInRange(dr, (channels[i + j].DrRange.Fields.Min & 0x0F), + (channels[i + j].DrRange.Fields.Max & 0x0F)) == 1) + { + // At least 1 channel has been found we can return OK. + return true; + } + } + } + } + return false; + } + + uint8_t RegionCommonValueInRange(int8_t value, int8_t min, int8_t max) + { + if ((value >= min) && (value <= max)) + { + return 1; + } + return 0; + } + + bool RegionCommonChanDisable(uint16_t *channelsMask, uint8_t id, uint8_t maxChannels) + { + uint8_t index = id / 16; + + if ((index > (maxChannels / 16)) || (id >= maxChannels)) + { + return false; + } + + // Deactivate channel + channelsMask[index] &= ~(1 << (id % 16)); + + return true; + } + + uint8_t RegionCommonCountChannels(uint16_t *channelsMask, uint8_t startIdx, uint8_t stopIdx) + { + uint8_t nbChannels = 0; + + if (channelsMask == NULL) + { + return 0; + } + + for (uint8_t i = startIdx; i < stopIdx; i++) + { + nbChannels += CountChannels(channelsMask[i], 16); + } + + return nbChannels; + } + + void RegionCommonChanMaskCopy(uint16_t *channelsMaskDest, uint16_t *channelsMaskSrc, uint8_t len) + { + if ((channelsMaskDest != NULL) && (channelsMaskSrc != NULL)) + { + for (uint8_t i = 0; i < len; i++) + { + channelsMaskDest[i] = channelsMaskSrc[i]; + } + } + } + + void RegionCommonSetBandTxDone(bool joined, Band_t *band, TimerTime_t lastTxDone) + { + if (joined == true) + { + band->LastTxDoneTime = lastTxDone; + } + else + { + band->LastTxDoneTime = lastTxDone; + band->LastJoinTxDoneTime = lastTxDone; + } + } + + TimerTime_t RegionCommonUpdateBandTimeOff(bool joined, bool dutyCycle, Band_t *bands, uint8_t nbBands) + { + TimerTime_t nextTxDelay = (TimerTime_t)(-1); + + // Update bands Time OFF + for (uint8_t i = 0; i < nbBands; i++) + { + if (joined == false) + { + uint32_t txDoneTime = MAX(TimerGetElapsedTime(bands[i].LastJoinTxDoneTime), + (dutyCycle == true) ? TimerGetElapsedTime(bands[i].LastTxDoneTime) : 0); + + if (bands[i].TimeOff <= txDoneTime) + { + bands[i].TimeOff = 0; + } + if (bands[i].TimeOff != 0) + { + nextTxDelay = MIN(bands[i].TimeOff - txDoneTime, nextTxDelay); + } + } + else + { + if (dutyCycle == true) + { + if (bands[i].TimeOff <= TimerGetElapsedTime(bands[i].LastTxDoneTime)) + { + bands[i].TimeOff = 0; + } + if (bands[i].TimeOff != 0) + { + nextTxDelay = MIN(bands[i].TimeOff - TimerGetElapsedTime(bands[i].LastTxDoneTime), + nextTxDelay); + } + } + else + { + nextTxDelay = 0; + bands[i].TimeOff = 0; + } + } + } + return nextTxDelay; + } + + uint8_t RegionCommonParseLinkAdrReq(uint8_t *payload, RegionCommonLinkAdrParams_t *linkAdrParams) + { + uint8_t retIndex = 0; + + if (payload[0] == SRV_MAC_LINK_ADR_REQ) + { + // Parse datarate and tx power + linkAdrParams->Datarate = payload[1]; + linkAdrParams->TxPower = linkAdrParams->Datarate & 0x0F; + linkAdrParams->Datarate = (linkAdrParams->Datarate >> 4) & 0x0F; + // Parse ChMask + linkAdrParams->ChMask = (uint16_t)payload[2]; + linkAdrParams->ChMask |= (uint16_t)payload[3] << 8; + // Parse ChMaskCtrl and nbRep + linkAdrParams->NbRep = payload[4]; + linkAdrParams->ChMaskCtrl = (linkAdrParams->NbRep >> 4) & 0x07; + linkAdrParams->NbRep &= 0x0F; + + // LinkAdrReq has 4 bytes length + 1 byte CMD + retIndex = 5; + } + return retIndex; + } + + uint8_t RegionCommonLinkAdrReqVerifyParams(RegionCommonLinkAdrReqVerifyParams_t *verifyParams, int8_t *dr, int8_t *txPow, uint8_t *nbRep) + { + uint8_t status = verifyParams->Status; + int8_t datarate = verifyParams->Datarate; + int8_t txPower = verifyParams->TxPower; + int8_t nbRepetitions = verifyParams->NbRep; + + // Handle the case when ADR is off. + if (verifyParams->AdrEnabled == false) + { + // When ADR is off, we are allowed to change the channels mask and the NbRep, + // if the datarate and the TX power of the LinkAdrReq are set to 0x0F. + if ((verifyParams->Datarate != 0x0F) || (verifyParams->TxPower != 0x0F)) + { + status = 0; + nbRepetitions = verifyParams->CurrentNbRep; + } + // Get the current datarate and tx power + datarate = verifyParams->CurrentDatarate; + txPower = verifyParams->CurrentTxPower; + } + + if (status != 0) + { + // Verify datarate. The variable phyParam. Value contains the minimum allowed datarate. + if (RegionCommonChanVerifyDr(verifyParams->NbChannels, verifyParams->ChannelsMask, datarate, + verifyParams->MinDatarate, verifyParams->MaxDatarate, verifyParams->Channels) == false) + { + status &= 0xFD; // Datarate KO + } + + // Verify tx power + if (RegionCommonValueInRange(txPower, verifyParams->MaxTxPower, verifyParams->MinTxPower) == 0) + { + // Verify if the maximum TX power is exceeded + if (verifyParams->MaxTxPower > txPower) + { // Apply maximum TX power. Accept TX power. + txPower = verifyParams->MaxTxPower; + } + else + { + status &= 0xFB; // TxPower KO + } + } + } + + // If the status is ok, verify the NbRep + if (status == 0x07) + { + if (nbRepetitions == 0) + { // Keep the current one + nbRepetitions = verifyParams->CurrentNbRep; + } + } + + // Apply changes + *dr = datarate; + *txPow = txPower; + *nbRep = nbRepetitions; + + return status; + } + + double RegionCommonComputeSymbolTimeLoRa(uint8_t phyDr, uint32_t bandwidth) + { + return ((double)(1 << phyDr) / (double)bandwidth) * 1000; + } + + double RegionCommonComputeSymbolTimeFsk(uint8_t phyDr) + { + return (8.0 / (double)phyDr); // 1 symbol equals 1 byte + } + + void RegionCommonComputeRxWindowParameters(double tSymbol, uint8_t minRxSymbols, uint32_t rxError, uint32_t wakeUpTime, uint32_t *windowTimeout, int32_t *windowOffset) + { + *windowTimeout = MAX((uint32_t)ceil(((2 * minRxSymbols - 8) * tSymbol + 2 * rxError) / tSymbol), minRxSymbols); // Computed number of symbols + *windowOffset = (int32_t)ceil((4.0 * tSymbol) - ((*windowTimeout * tSymbol) / 2.0) - wakeUpTime); + } + + int8_t RegionCommonComputeTxPower(int8_t txPowerIndex, float maxEirp, float antennaGain) + { + int8_t phyTxPower = 0; + + phyTxPower = (int8_t)floor((maxEirp - (txPowerIndex * 2U)) - antennaGain); + + return phyTxPower; + } + + void RegionCommonCalcBackOff(RegionCommonCalcBackOffParams_t *calcBackOffParams) + { + uint8_t bandIdx = calcBackOffParams->Channels[calcBackOffParams->Channel].Band; + uint16_t dutyCycle = calcBackOffParams->Bands[bandIdx].DCycle; + uint16_t joinDutyCycle = 0; + + // Reset time-off to initial value. + calcBackOffParams->Bands[bandIdx].TimeOff = 0; + + if (calcBackOffParams->Joined == false) + { + // Get the join duty cycle + joinDutyCycle = RegionCommonGetJoinDc(calcBackOffParams->ElapsedTime); + // Apply the most restricting duty cycle + dutyCycle = MAX(dutyCycle, joinDutyCycle); + // Reset the timeoff if the last frame was not a join request and when the duty cycle is not enabled + if ((calcBackOffParams->DutyCycleEnabled == false) && (calcBackOffParams->LastTxIsJoinRequest == false)) + { + // This is the case when the duty cycle is off and the last uplink frame was not a join. + // This could happen in case of a rejoin, e.g. in compliance test mode. + // In this special case we have to set the time off to 0, since the join duty cycle shall only + // be applied after the first join request. + calcBackOffParams->Bands[bandIdx].TimeOff = 0; + } + else + { + // Apply band time-off. + calcBackOffParams->Bands[bandIdx].TimeOff = calcBackOffParams->TxTimeOnAir * dutyCycle - calcBackOffParams->TxTimeOnAir; + } + } + else + { + if (calcBackOffParams->DutyCycleEnabled == true) + { + calcBackOffParams->Bands[bandIdx].TimeOff = calcBackOffParams->TxTimeOnAir * dutyCycle - calcBackOffParams->TxTimeOnAir; + } + else + { + calcBackOffParams->Bands[bandIdx].TimeOff = 0; + } + } + } }; \ No newline at end of file diff --git a/src/mac/region/RegionCommon.h b/src/mac/region/RegionCommon.h index 4e5d4b3..6e542e1 100644 --- a/src/mac/region/RegionCommon.h +++ b/src/mac/region/RegionCommon.h @@ -38,131 +38,131 @@ extern "C" { -typedef struct sRegionCommonLinkAdrParams -{ - /*! + typedef struct sRegionCommonLinkAdrParams + { + /*! * Number of repetitions. */ - uint8_t NbRep; - /*! + uint8_t NbRep; + /*! * Datarate. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * Tx power. */ - int8_t TxPower; - /*! + int8_t TxPower; + /*! * Channels mask control field. */ - uint8_t ChMaskCtrl; - /*! + uint8_t ChMaskCtrl; + /*! * Channels mask field. */ - uint16_t ChMask; -}RegionCommonLinkAdrParams_t; + uint16_t ChMask; + } RegionCommonLinkAdrParams_t; -typedef struct sRegionCommonLinkAdrReqVerifyParams -{ - /*! + typedef struct sRegionCommonLinkAdrReqVerifyParams + { + /*! * The current status of the AdrLinkRequest. */ - uint8_t Status; - /*! + uint8_t Status; + /*! * Set to true, if ADR is enabled. */ - bool AdrEnabled; - /*! + bool AdrEnabled; + /*! * The datarate the AdrLinkRequest wants to set. */ - int8_t Datarate; - /*! + int8_t Datarate; + /*! * The TX power the AdrLinkRequest wants to set. */ - int8_t TxPower; - /*! + int8_t TxPower; + /*! * The number of repetitions the AdrLinkRequest wants to set. */ - uint8_t NbRep; - /*! + uint8_t NbRep; + /*! * The current datarate the node is using. */ - int8_t CurrentDatarate; - /*! + int8_t CurrentDatarate; + /*! * The current TX power the node is using. */ - int8_t CurrentTxPower; - /*! + int8_t CurrentTxPower; + /*! * The current number of repetitions the node is using. */ - int8_t CurrentNbRep; - /*! + int8_t CurrentNbRep; + /*! * The number of channels. */ - uint8_t NbChannels; - /*! + uint8_t NbChannels; + /*! * Pointer to the first element of the channels mask. */ - uint16_t* ChannelsMask; - /*! + uint16_t *ChannelsMask; + /*! * The minimum possible datarate. */ - int8_t MinDatarate; - /*! + int8_t MinDatarate; + /*! * The maximum possible datarate. */ - int8_t MaxDatarate; - /*! + int8_t MaxDatarate; + /*! * Pointer to the channels. */ - ChannelParams_t* Channels; - /*! + ChannelParams_t *Channels; + /*! * The minimum possible TX power. */ - int8_t MinTxPower; - /*! + int8_t MinTxPower; + /*! * The maximum possible TX power. */ - int8_t MaxTxPower; -}RegionCommonLinkAdrReqVerifyParams_t; + int8_t MaxTxPower; + } RegionCommonLinkAdrReqVerifyParams_t; -typedef struct sRegionCommonCalcBackOffParams -{ - /*! + typedef struct sRegionCommonCalcBackOffParams + { + /*! * A pointer to region specific channels. */ - ChannelParams_t* Channels; - /*! + ChannelParams_t *Channels; + /*! * A pointer to region specific bands. */ - Band_t* Bands; - /*! + Band_t *Bands; + /*! * Set to true, if the last uplink was a join request. */ - bool LastTxIsJoinRequest; - /*! + bool LastTxIsJoinRequest; + /*! * Set to true, if the node is joined. */ - bool Joined; - /*! + bool Joined; + /*! * Set to true, if the duty cycle is enabled. */ - bool DutyCycleEnabled; - /*! + bool DutyCycleEnabled; + /*! * The current channel. */ - uint8_t Channel; - /*! + uint8_t Channel; + /*! * The elapsed time since initialization. */ - TimerTime_t ElapsedTime; - /*! + TimerTime_t ElapsedTime; + /*! * The time on air of the last Tx frame. */ - TimerTime_t TxTimeOnAir; -}RegionCommonCalcBackOffParams_t; + TimerTime_t TxTimeOnAir; + } RegionCommonCalcBackOffParams_t; -/*! + /*! * \brief Calculates the join duty cycle. * This is a generic function and valid for all regions. * @@ -170,9 +170,9 @@ typedef struct sRegionCommonCalcBackOffParams * * \retval Duty cycle restriction. */ -uint16_t RegionCommonGetJoinDc( TimerTime_t elapsedTime ); + uint16_t RegionCommonGetJoinDc(TimerTime_t elapsedTime); -/*! + /*! * \brief Verifies, if a value is in a given range. * This is a generic function and valid for all regions. * @@ -184,9 +184,9 @@ uint16_t RegionCommonGetJoinDc( TimerTime_t elapsedTime ); * * \retval Returns 1 if the value is in range, otherwise 0. */ -uint8_t RegionCommonValueInRange( int8_t value, int8_t min, int8_t max ); + uint8_t RegionCommonValueInRange(int8_t value, int8_t min, int8_t max); -/*! + /*! * \brief Verifies, if a datarate is available on an active channel. * This is a generic function and valid for all regions. * @@ -204,10 +204,10 @@ uint8_t RegionCommonValueInRange( int8_t value, int8_t min, int8_t max ); * * \retval Returns true if the datarate is supported, false if not. */ -bool RegionCommonChanVerifyDr( uint8_t nbChannels, uint16_t* channelsMask, int8_t dr, - int8_t minDr, int8_t maxDr, ChannelParams_t* channels ); + bool RegionCommonChanVerifyDr(uint8_t nbChannels, uint16_t *channelsMask, int8_t dr, + int8_t minDr, int8_t maxDr, ChannelParams_t *channels); -/*! + /*! * \brief Disables a channel in a given channels mask. * This is a generic function and valid for all regions. * @@ -219,9 +219,9 @@ bool RegionCommonChanVerifyDr( uint8_t nbChannels, uint16_t* channelsMask, int8_ * * \retval Returns true if the channel could be disabled, false if not. */ -bool RegionCommonChanDisable( uint16_t* channelsMask, uint8_t id, uint8_t maxChannels ); + bool RegionCommonChanDisable(uint16_t *channelsMask, uint8_t id, uint8_t maxChannels); -/*! + /*! * \brief Counts the number of active channels in a given channels mask. * This is a generic function and valid for all regions. * @@ -233,9 +233,9 @@ bool RegionCommonChanDisable( uint16_t* channelsMask, uint8_t id, uint8_t maxCha * * \retval Returns the number of active channels. */ -uint8_t RegionCommonCountChannels( uint16_t* channelsMask, uint8_t startIdx, uint8_t stopIdx ); + uint8_t RegionCommonCountChannels(uint16_t *channelsMask, uint8_t startIdx, uint8_t stopIdx); -/*! + /*! * \brief Copy a channels mask. * This is a generic function and valid for all regions. * @@ -245,9 +245,9 @@ uint8_t RegionCommonCountChannels( uint16_t* channelsMask, uint8_t startIdx, uin * * \param [IN] len The index length to copy. */ -void RegionCommonChanMaskCopy( uint16_t* channelsMaskDest, uint16_t* channelsMaskSrc, uint8_t len ); + void RegionCommonChanMaskCopy(uint16_t *channelsMaskDest, uint16_t *channelsMaskSrc, uint8_t len); -/*! + /*! * \brief Sets the last tx done property. * This is a generic function and valid for all regions. * @@ -257,9 +257,9 @@ void RegionCommonChanMaskCopy( uint16_t* channelsMaskDest, uint16_t* channelsMas * * \param [IN] lastTxDone The time of the last TX done. */ -void RegionCommonSetBandTxDone( bool joined, Band_t* band, TimerTime_t lastTxDone ); + void RegionCommonSetBandTxDone(bool joined, Band_t *band, TimerTime_t lastTxDone); -/*! + /*! * \brief Updates the time-offs of the bands. * This is a generic function and valid for all regions. * @@ -273,9 +273,9 @@ void RegionCommonSetBandTxDone( bool joined, Band_t* band, TimerTime_t lastTxDon * * \retval Returns the time which must be waited to perform the next uplink. */ -TimerTime_t RegionCommonUpdateBandTimeOff( bool joined, bool dutyCycle, Band_t* bands, uint8_t nbBands ); + TimerTime_t RegionCommonUpdateBandTimeOff(bool joined, bool dutyCycle, Band_t *bands, uint8_t nbBands); -/*! + /*! * \brief Parses the parameter of an LinkAdrRequest. * This is a generic function and valid for all regions. * @@ -287,9 +287,9 @@ TimerTime_t RegionCommonUpdateBandTimeOff( bool joined, bool dutyCycle, Band_t* * \retval Returns the length of the ADR request, if a request was found. Otherwise, the * function returns 0. */ -uint8_t RegionCommonParseLinkAdrReq( uint8_t* payload, RegionCommonLinkAdrParams_t* parseLinkAdr ); + uint8_t RegionCommonParseLinkAdrReq(uint8_t *payload, RegionCommonLinkAdrParams_t *parseLinkAdr); -/*! + /*! * \brief Verifies and updates the datarate, the TX power and the number of repetitions * of a LinkAdrRequest. This depends on the configuration of ADR also. * @@ -303,9 +303,9 @@ uint8_t RegionCommonParseLinkAdrReq( uint8_t* payload, RegionCommonLinkAdrParams * * \retval Returns the status according to the LinkAdrRequest definition. */ -uint8_t RegionCommonLinkAdrReqVerifyParams( RegionCommonLinkAdrReqVerifyParams_t* verifyParams, int8_t* dr, int8_t* txPow, uint8_t* nbRep ); + uint8_t RegionCommonLinkAdrReqVerifyParams(RegionCommonLinkAdrReqVerifyParams_t *verifyParams, int8_t *dr, int8_t *txPow, uint8_t *nbRep); -/*! + /*! * \brief Computes the symbol time for LoRa modulation. * * \param [IN] phyDr Physical datarate to use. @@ -314,9 +314,9 @@ uint8_t RegionCommonLinkAdrReqVerifyParams( RegionCommonLinkAdrReqVerifyParams_t * * \retval Returns the symbol time. */ -double RegionCommonComputeSymbolTimeLoRa( uint8_t phyDr, uint32_t bandwidth ); + double RegionCommonComputeSymbolTimeLoRa(uint8_t phyDr, uint32_t bandwidth); -/*! + /*! * \brief Computes the symbol time for FSK modulation. * * \param [IN] phyDr Physical datarate to use. @@ -325,9 +325,9 @@ double RegionCommonComputeSymbolTimeLoRa( uint8_t phyDr, uint32_t bandwidth ); * * \retval Returns the symbol time. */ -double RegionCommonComputeSymbolTimeFsk( uint8_t phyDr ); + double RegionCommonComputeSymbolTimeFsk(uint8_t phyDr); -/*! + /*! * \brief Computes the RX window timeout and the RX window offset. * * \param [IN] tSymbol Symbol timeout. @@ -343,9 +343,9 @@ double RegionCommonComputeSymbolTimeFsk( uint8_t phyDr ); * * \param [OUT] windowOffset RX window time offset to be applied to the RX delay. */ -void RegionCommonComputeRxWindowParameters( double tSymbol, uint8_t minRxSymbols, uint32_t rxError, uint32_t wakeUpTime, uint32_t* windowTimeout, int32_t* windowOffset ); + void RegionCommonComputeRxWindowParameters(double tSymbol, uint8_t minRxSymbols, uint32_t rxError, uint32_t wakeUpTime, uint32_t *windowTimeout, int32_t *windowOffset); -/*! + /*! * \brief Computes the txPower, based on the max EIRP and the antenna gain. * * \param [IN] txPower TX power index. @@ -356,15 +356,15 @@ void RegionCommonComputeRxWindowParameters( double tSymbol, uint8_t minRxSymbols * * \retval Returns the physical TX power. */ -int8_t RegionCommonComputeTxPower( int8_t txPowerIndex, float maxEirp, float antennaGain ); + int8_t RegionCommonComputeTxPower(int8_t txPowerIndex, float maxEirp, float antennaGain); -/*! + /*! * \brief Calculates the duty cycle for the current band. * * \param [IN] calcBackOffParams A pointer to the input parameters. */ -void RegionCommonCalcBackOff( RegionCommonCalcBackOffParams_t* calcBackOffParams ); + void RegionCommonCalcBackOff(RegionCommonCalcBackOffParams_t *calcBackOffParams); -/*! \} defgroup REGIONCOMMON */ + /*! \} defgroup REGIONCOMMON */ }; #endif // __REGIONCOMMON_H__ diff --git a/src/mac/region/RegionEU433.h b/src/mac/region/RegionEU433.h index 38ad24d..0ddd4d3 100644 --- a/src/mac/region/RegionEU433.h +++ b/src/mac/region/RegionEU433.h @@ -41,233 +41,245 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define EU433_MAX_NB_CHANNELS 16 +#define EU433_MAX_NB_CHANNELS 16 /*! * Number of default channels */ -#define EU433_NUMB_DEFAULT_CHANNELS 3 +#define EU433_NUMB_DEFAULT_CHANNELS 3 /*! * Number of channels to apply for the CF list */ -#define EU433_NUMB_CHANNELS_CF_LIST 5 +#define EU433_NUMB_CHANNELS_CF_LIST 5 /*! * Minimal datarate that can be used by the node */ -#define EU433_TX_MIN_DATARATE DR_0 +#define EU433_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define EU433_TX_MAX_DATARATE DR_7 +#define EU433_TX_MAX_DATARATE DR_7 /*! * Minimal datarate that can be used by the node */ -#define EU433_RX_MIN_DATARATE DR_0 +#define EU433_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define EU433_RX_MAX_DATARATE DR_7 +#define EU433_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node */ -#define EU433_DEFAULT_DATARATE DR_0 +#define EU433_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define EU433_MIN_RX1_DR_OFFSET 0 +#define EU433_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define EU433_MAX_RX1_DR_OFFSET 5 +#define EU433_MAX_RX1_DR_OFFSET 5 /*! * Default Rx1 receive datarate offset */ -#define EU433_DEFAULT_RX1_DR_OFFSET 0 +#define EU433_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define EU433_MIN_TX_POWER TX_POWER_5 +#define EU433_MIN_TX_POWER TX_POWER_5 /*! * Maximal Tx output power that can be used by the node */ -#define EU433_MAX_TX_POWER TX_POWER_0 +#define EU433_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define EU433_DEFAULT_TX_POWER TX_POWER_0 +#define EU433_DEFAULT_TX_POWER TX_POWER_0 /*! * Default Max EIRP */ -#define EU433_DEFAULT_MAX_EIRP 12.15f +#define EU433_DEFAULT_MAX_EIRP 12.15f /*! * Default antenna gain */ -#define EU433_DEFAULT_ANTENNA_GAIN 2.15f +#define EU433_DEFAULT_ANTENNA_GAIN 2.15f /*! * ADR Ack limit */ -#define EU433_ADR_ACK_LIMIT 64 +#define EU433_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define EU433_ADR_ACK_DELAY 32 +#define EU433_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define EU433_DUTY_CYCLE_ENABLED 1 +#define EU433_DUTY_CYCLE_ENABLED 1 /*! * Maximum RX window duration */ -#define EU433_MAX_RX_WINDOW 3000 +#define EU433_MAX_RX_WINDOW 3000 /*! * Receive delay 1 */ -#define EU433_RECEIVE_DELAY1 1000 +#define EU433_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define EU433_RECEIVE_DELAY2 2000 +#define EU433_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define EU433_JOIN_ACCEPT_DELAY1 5000 +#define EU433_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define EU433_JOIN_ACCEPT_DELAY2 6000 +#define EU433_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define EU433_MAX_FCNT_GAP 16384 +#define EU433_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define EU433_ACKTIMEOUT 2000 +#define EU433_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define EU433_ACK_TIMEOUT_RND 1000 +#define EU433_ACK_TIMEOUT_RND 1000 /*! * Verification of default datarate */ -#if ( EU433_DEFAULT_DATARATE > DR_5 ) +#if (EU433_DEFAULT_DATARATE > DR_5) #error "A default DR higher than DR_5 may lead to connectivity loss." #endif /*! * Second reception window channel frequency definition. */ -#define EU433_RX_WND_2_FREQ 434665000 +#define EU433_RX_WND_2_FREQ 434665000 /*! * Second reception window channel datarate definition. */ -#define EU433_RX_WND_2_DR DR_0 +#define EU433_RX_WND_2_DR DR_0 /*! * LoRaMac maximum number of bands */ -#define EU433_MAX_NB_BANDS 1 +#define EU433_MAX_NB_BANDS 1 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define EU433_BAND0 { 100, EU433_MAX_TX_POWER, 0, 0 } // 1.0 % +#define EU433_BAND0 \ + { \ + 100, EU433_MAX_TX_POWER, 0, 0 \ + } // 1.0 % /*! * LoRaMac default channel 1 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define EU433_LC1 { 433175000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define EU433_LC1 \ + { \ + 433175000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac default channel 2 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define EU433_LC2 { 433375000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define EU433_LC2 \ + { \ + 433375000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac default channel 3 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define EU433_LC3 { 433575000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define EU433_LC3 \ + { \ + 433575000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac channels which are allowed for the join procedure */ -#define EU433_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) +#define EU433_JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesEU433[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; + static const uint8_t DataratesEU433[] = {12, 11, 10, 9, 8, 7, 7, 50}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsEU433[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 }; + static const uint32_t BandwidthsEU433[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; -/*! + /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateEU433[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; + static const uint8_t MaxPayloadOfDatarateEU433[] = {51, 51, 51, 115, 242, 242, 242, 242}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateRepeaterEU433[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; + static const uint8_t MaxPayloadOfDatarateRepeaterEU433[] = {51, 51, 51, 115, 222, 222, 222, 222}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionEU433GetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionEU433GetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionEU433SetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionEU433SetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionEU433InitDefaults( InitType_t type ); + void RegionEU433InitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -276,26 +288,26 @@ void RegionEU433InitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionEU433Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionEU433Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionEU433ApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionEU433ApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionEU433ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionEU433ChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -308,9 +320,9 @@ bool RegionEU433ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionEU433AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionEU433AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -323,9 +335,9 @@ bool RegionEU433AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowO * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionEU433ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionEU433ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -334,9 +346,9 @@ void RegionEU433ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionEU433RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionEU433RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -347,36 +359,36 @@ bool RegionEU433RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionEU433TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionEU433TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionEU433LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionEU433LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionEU433RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionEU433RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionEU433NewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionEU433NewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -385,34 +397,34 @@ uint8_t RegionEU433NewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionEU433TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionEU433TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionEU433DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionEU433DlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionEU433AlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionEU433AlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionEU433CalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionEU433CalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -424,34 +436,34 @@ void RegionEU433CalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionEU433NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionEU433NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionEU433ChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionEU433ChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionEU433ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionEU433ChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionEU433SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionEU433SetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -462,8 +474,8 @@ void RegionEU433SetContinuousWave( ContinuousWaveParams_t* continuousWave ); * * \retval newDr Computed datarate. */ -uint8_t RegionEU433ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionEU433ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONEU433 */ + /*! \} defgroup REGIONEU433 */ }; #endif // __REGION_EU433_H__ diff --git a/src/mac/region/RegionEU868.cpp b/src/mac/region/RegionEU868.cpp index 4346c53..598ded1 100644 --- a/src/mac/region/RegionEU868.cpp +++ b/src/mac/region/RegionEU868.cpp @@ -37,1050 +37,1050 @@ extern "C" // Definitions #define CHANNELS_MASK_SIZE 1 - // Global attributes - /*! + // Global attributes + /*! * LoRaMAC channels */ - static ChannelParams_t Channels[EU868_MAX_NB_CHANNELS]; + static ChannelParams_t Channels[EU868_MAX_NB_CHANNELS]; - /*! + /*! * LoRaMac bands */ - static Band_t Bands[EU868_MAX_NB_BANDS] = - { - EU868_BAND0, - EU868_BAND1, - EU868_BAND2, - EU868_BAND3, - EU868_BAND4, - }; - - /*! + static Band_t Bands[EU868_MAX_NB_BANDS] = + { + EU868_BAND0, + EU868_BAND1, + EU868_BAND2, + EU868_BAND3, + EU868_BAND4, + }; + + /*! * LoRaMac channels mask */ - static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; + static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; - /*! + /*! * LoRaMac channels default mask */ - static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; - - // Static functions - static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) - { - uint8_t nextLowerDr = 0; - - if (dr == minDr) - { - nextLowerDr = minDr; - } - else - { - nextLowerDr = dr - 1; - } - return nextLowerDr; - } - - static uint32_t GetBandwidth(uint32_t drIndex) - { - switch (BandwidthsEU868[drIndex]) - { - default: - case 125000: - return 0; - case 250000: - return 1; - case 500000: - return 2; - } - } - - static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) - { - int8_t txPowerResult = txPower; - - // Limit tx power to the band max - txPowerResult = MAX(txPower, maxBandTxPower); - - return txPowerResult; - } - - static bool VerifyTxFreq(uint32_t freq, uint8_t *band) - { - // Check radio driver support - if (Radio.CheckRfFrequency(freq) == false) - { - return false; - } - - // Check frequency bands - if ((freq >= 863000000) && (freq < 865000000)) - { - *band = 2; - } - else if ((freq >= 865000000) && (freq <= 868000000)) - { - *band = 0; - } - else if ((freq > 868000000) && (freq <= 868600000)) - { - *band = 1; - } - else if ((freq >= 868700000) && (freq <= 869200000)) - { - *band = 2; - } - else if ((freq >= 869400000) && (freq <= 869650000)) - { - *band = 3; - } - else if ((freq >= 869700000) && (freq <= 870000000)) - { - *band = 4; - } - else - { - return false; - } - return true; - } - - static uint8_t CountNbOfEnabledChannels(bool joined, uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTransmission = 0; - - for (uint8_t i = 0, k = 0; i < EU868_MAX_NB_CHANNELS; i += 16, k++) - { - for (uint8_t j = 0; j < 16; j++) - { - if ((channelsMask[k] & (1 << j)) != 0) - { - if (channels[i + j].Frequency == 0) - { // Check if the channel is enabled - continue; - } - if (joined == false) - { - if ((EU868_JOIN_CHANNELS & (1 << j)) == 0) - { - continue; - } - } - if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, - channels[i + j].DrRange.Fields.Max) == false) - { // Check if the current channel selection supports the given datarate - continue; - } - if (bands[channels[i + j].Band].TimeOff > 0) - { // Check if the band is available for transmission - delayTransmission++; - continue; - } - enabledChannels[nbEnabledChannels++] = i + j; - } - } - } - - *delayTx = delayTransmission; - return nbEnabledChannels; - } - - PhyParam_t RegionEU868GetPhyParam(GetPhyParams_t *getPhy) - { - PhyParam_t phyParam = {0}; - - switch (getPhy->Attribute) - { - case PHY_MIN_RX_DR: - { - phyParam.Value = EU868_RX_MIN_DATARATE; - break; - } - case PHY_MIN_TX_DR: - { - phyParam.Value = EU868_TX_MIN_DATARATE; - break; - } - case PHY_DEF_TX_DR: - { - phyParam.Value = EU868_DEFAULT_DATARATE; - break; - } - case PHY_NEXT_LOWER_TX_DR: - { - phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, EU868_TX_MIN_DATARATE); - break; - } - case PHY_DEF_TX_POWER: - { - phyParam.Value = EU868_DEFAULT_TX_POWER; - break; - } - case PHY_MAX_PAYLOAD: - { - phyParam.Value = MaxPayloadOfDatarateEU868[getPhy->Datarate]; - break; - } - case PHY_MAX_PAYLOAD_REPEATER: - { - phyParam.Value = MaxPayloadOfDatarateRepeaterEU868[getPhy->Datarate]; - break; - } - case PHY_DUTY_CYCLE: - { - phyParam.Value = EU868_DUTY_CYCLE_ENABLED; - break; - } - case PHY_MAX_RX_WINDOW: - { - phyParam.Value = EU868_MAX_RX_WINDOW; - break; - } - case PHY_RECEIVE_DELAY1: - { - phyParam.Value = EU868_RECEIVE_DELAY1; - break; - } - case PHY_RECEIVE_DELAY2: - { - phyParam.Value = EU868_RECEIVE_DELAY2; - break; - } - case PHY_JOIN_ACCEPT_DELAY1: - { - phyParam.Value = EU868_JOIN_ACCEPT_DELAY1; - break; - } - case PHY_JOIN_ACCEPT_DELAY2: - { - phyParam.Value = EU868_JOIN_ACCEPT_DELAY2; - break; - } - case PHY_MAX_FCNT_GAP: - { - phyParam.Value = EU868_MAX_FCNT_GAP; - break; - } - case PHY_ACK_TIMEOUT: - { - phyParam.Value = (EU868_ACKTIMEOUT + randr(-EU868_ACK_TIMEOUT_RND, EU868_ACK_TIMEOUT_RND)); - break; - } - case PHY_DEF_DR1_OFFSET: - { - phyParam.Value = EU868_DEFAULT_RX1_DR_OFFSET; - break; - } - case PHY_DEF_RX2_FREQUENCY: - { - phyParam.Value = EU868_RX_WND_2_FREQ; - break; - } - case PHY_DEF_RX2_DR: - { - phyParam.Value = EU868_RX_WND_2_DR; - break; - } - case PHY_CHANNELS_MASK: - { - phyParam.ChannelsMask = ChannelsMask; - break; - } - case PHY_CHANNELS_DEFAULT_MASK: - { - phyParam.ChannelsMask = ChannelsDefaultMask; - break; - } - case PHY_MAX_NB_CHANNELS: - { - phyParam.Value = EU868_MAX_NB_CHANNELS; - break; - } - case PHY_CHANNELS: - { - phyParam.Channels = Channels; - break; - } - case PHY_DEF_UPLINK_DWELL_TIME: - case PHY_DEF_DOWNLINK_DWELL_TIME: - { - phyParam.Value = 0; - break; - } - case PHY_DEF_MAX_EIRP: - { - phyParam.fValue = EU868_DEFAULT_MAX_EIRP; - break; - } - case PHY_DEF_ANTENNA_GAIN: - { - phyParam.fValue = EU868_DEFAULT_ANTENNA_GAIN; - break; - } - case PHY_NB_JOIN_TRIALS: - case PHY_DEF_NB_JOIN_TRIALS: - { - phyParam.Value = 48; - break; - } - default: - { - break; - } - } - - return phyParam; - } - - void RegionEU868SetBandTxDone(SetBandTxDoneParams_t *txDone) - { - RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); - } - - void RegionEU868InitDefaults(InitType_t type) - { - switch (type) - { - case INIT_TYPE_INIT: - { - // Channels - Channels[0] = (ChannelParams_t)EU868_LC1; - Channels[1] = (ChannelParams_t)EU868_LC2; - Channels[2] = (ChannelParams_t)EU868_LC3; - - // Initialize the channels default mask - ChannelsDefaultMask[0] = LC(1) + LC(2) + LC(3); - // Update the channels mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); - break; - } - case INIT_TYPE_RESTORE: - { - // Restore channels default mask - ChannelsMask[0] |= ChannelsDefaultMask[0]; - break; - } - case INIT_TYPE_APP_DEFAULTS: - { - // Update the channels mask defaults - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); - break; - } - default: - { - break; - } - } - } - - bool RegionEU868Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) - { - switch (phyAttribute) - { - case PHY_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, EU868_TX_MIN_DATARATE, EU868_TX_MAX_DATARATE); - } - case PHY_DEF_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); - } - case PHY_RX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, EU868_RX_MIN_DATARATE, EU868_RX_MAX_DATARATE); - } - case PHY_DEF_TX_POWER: - case PHY_TX_POWER: - { - // Remark: switched min and max! - return RegionCommonValueInRange(verify->TxPower, EU868_MAX_TX_POWER, EU868_MIN_TX_POWER); - } - case PHY_DUTY_CYCLE: - { - return EU868_DUTY_CYCLE_ENABLED; - } - case PHY_NB_JOIN_TRIALS: - { - if (verify->NbJoinTrials < 48) - { - return false; - } - break; - } - default: - return false; - } - return true; - } - - void RegionEU868ApplyCFList(ApplyCFListParams_t *applyCFList) - { - ChannelParams_t newChannel; - ChannelAddParams_t channelAdd; - ChannelRemoveParams_t channelRemove; - - // Setup default datarate range - newChannel.DrRange.Value = (DR_5 << 4) | DR_0; - - // Size of the optional CF list - if (applyCFList->Size != 16) - { - return; - } - - // Last byte is RFU, don't take it into account - for (uint8_t i = 0, chanIdx = EU868_NUMB_DEFAULT_CHANNELS; chanIdx < EU868_MAX_NB_CHANNELS; i += 3, chanIdx++) - { - if (chanIdx < (EU868_NUMB_CHANNELS_CF_LIST + EU868_NUMB_DEFAULT_CHANNELS)) - { - // Channel frequency - newChannel.Frequency = (uint32_t)applyCFList->Payload[i]; - newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 1] << 8); - newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 2] << 16); - newChannel.Frequency *= 100; - - // Initialize alternative frequency to 0 - newChannel.Rx1Frequency = 0; - } - else - { - newChannel.Frequency = 0; - newChannel.DrRange.Value = 0; - newChannel.Rx1Frequency = 0; - } - - if (newChannel.Frequency != 0) - { - channelAdd.NewChannel = &newChannel; - channelAdd.ChannelId = chanIdx; - - // Try to add all channels - RegionEU868ChannelAdd(&channelAdd); - } - else - { - channelRemove.ChannelId = chanIdx; - - RegionEU868ChannelsRemove(&channelRemove); - } - } - } - - bool RegionEU868ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) - { - switch (chanMaskSet->ChannelsMaskType) - { - case CHANNELS_MASK: - { - RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 1); - break; - } - case CHANNELS_DEFAULT_MASK: - { - RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1); - break; - } - default: - return false; - } - return true; - } - - bool RegionEU868AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) - { - bool adrAckReq = false; - int8_t datarate = adrNext->Datarate; - int8_t txPower = adrNext->TxPower; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - - // Report back the adr ack counter - *adrAckCounter = adrNext->AdrAckCounter; - - if (adrNext->AdrEnabled == true) - { - if (datarate == EU868_TX_MIN_DATARATE) - { - *adrAckCounter = 0; - adrAckReq = false; - } - else - { - if (adrNext->AdrAckCounter >= EU868_ADR_ACK_LIMIT) - { - adrAckReq = true; - txPower = EU868_MAX_TX_POWER; - } - else - { - adrAckReq = false; - } - if (adrNext->AdrAckCounter >= (EU868_ADR_ACK_LIMIT + EU868_ADR_ACK_DELAY)) - { - if ((adrNext->AdrAckCounter % EU868_ADR_ACK_DELAY) == 1) - { - // Decrease the datarate - getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; - getPhy.Datarate = datarate; - getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; - phyParam = RegionEU868GetPhyParam(&getPhy); - datarate = phyParam.Value; - - if (datarate == EU868_TX_MIN_DATARATE) - { - // We must set adrAckReq to false as soon as we reach the lowest datarate - adrAckReq = false; - if (adrNext->UpdateChanMask == true) - { - // Re-enable default channels - ChannelsMask[0] |= LC(1) + LC(2) + LC(3); - } - } - } - } - } - } - - *drOut = datarate; - *txPowOut = txPower; - return adrAckReq; - } - - void RegionEU868ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) - { - double tSymbol = 0.0; - - // Get the datarate, perform a boundary check - rxConfigParams->Datarate = MIN(datarate, EU868_RX_MAX_DATARATE); - rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); - - if (rxConfigParams->Datarate == DR_7) - { // FSK - tSymbol = RegionCommonComputeSymbolTimeFsk(DataratesEU868[rxConfigParams->Datarate]); - } - else - { // LoRa - tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesEU868[rxConfigParams->Datarate], BandwidthsEU868[rxConfigParams->Datarate]); - } - - RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); - } - - bool RegionEU868RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) - { - RadioModems_t modem; - int8_t dr = rxConfig->Datarate; - uint8_t maxPayload = 0; - int8_t phyDr = 0; - uint32_t frequency = rxConfig->Frequency; - - if (Radio.GetStatus() != RF_IDLE) - { - return false; - } - - if (rxConfig->Window == 0) - { - // Apply window 1 frequency - frequency = Channels[rxConfig->Channel].Frequency; - // Apply the alternative RX 1 window frequency, if it is available - if (Channels[rxConfig->Channel].Rx1Frequency != 0) - { - frequency = Channels[rxConfig->Channel].Rx1Frequency; - } - } - - // Read the physical datarate from the datarates table - phyDr = DataratesEU868[dr]; - - Radio.SetChannel(frequency); - - // Radio configuration - if (dr == DR_7) - { - modem = MODEM_FSK; - Radio.SetRxConfig(modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous); - } - else - { - modem = MODEM_LORA; - Radio.SetRxConfig(modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); - } - - if (rxConfig->RepeaterSupport == true) - { - maxPayload = MaxPayloadOfDatarateRepeaterEU868[dr]; - } - else - { - maxPayload = MaxPayloadOfDatarateEU868[dr]; - } - - Radio.SetMaxPayloadLength(modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - *datarate = (uint8_t)dr; - return true; - } - - bool RegionEU868TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) - { - RadioModems_t modem; - int8_t phyDr = DataratesEU868[txConfig->Datarate]; - int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); - uint32_t bandwidth = GetBandwidth(txConfig->Datarate); - int8_t phyTxPower = 0; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); - - // Setup the radio frequency - Radio.SetChannel(Channels[txConfig->Channel].Frequency); - - if (txConfig->Datarate == DR_7) - { // High Speed FSK channel - modem = MODEM_FSK; - Radio.SetTxConfig(modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000); - } - else - { - modem = MODEM_LORA; - Radio.SetTxConfig(modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); - } - - // Setup maximum payload lenght of the radio driver - Radio.SetMaxPayloadLength(modem, txConfig->PktLen); - // Get the time-on-air of the next tx frame - *txTimeOnAir = Radio.TimeOnAir(modem, txConfig->PktLen); - - *txPower = txPowerLimited; - return true; - } - - uint8_t RegionEU868LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) - { - uint8_t status = 0x07; - RegionCommonLinkAdrParams_t linkAdrParams; - uint8_t nextIndex = 0; - uint8_t bytesProcessed = 0; - uint16_t chMask = 0; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; - - while (bytesProcessed < linkAdrReq->PayloadSize) - { - // Get ADR request parameters - nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); - - if (nextIndex == 0) - break; // break loop, since no more request has been found - - // Update bytes processed - bytesProcessed += nextIndex; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - // Setup temporary channels mask - chMask = linkAdrParams.ChMask; - - // Verify channels mask - if ((linkAdrParams.ChMaskCtrl == 0) && (chMask == 0)) - { - status &= 0xFE; // Channel mask KO - } - else if (((linkAdrParams.ChMaskCtrl >= 1) && (linkAdrParams.ChMaskCtrl <= 5)) || - (linkAdrParams.ChMaskCtrl >= 7)) - { - // RFU - status &= 0xFE; // Channel mask KO - } - else - { - for (uint8_t i = 0; i < EU868_MAX_NB_CHANNELS; i++) - { - if (linkAdrParams.ChMaskCtrl == 6) - { - if (Channels[i].Frequency != 0) - { - chMask |= 1 << i; - } - } - else - { - if (((chMask & (1 << i)) != 0) && - (Channels[i].Frequency == 0)) - { // Trying to enable an undefined channel - status &= 0xFE; // Channel mask KO - } - } - } - } - } - - // Get the minimum possible datarate - getPhy.Attribute = PHY_MIN_TX_DR; - getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; - phyParam = RegionEU868GetPhyParam(&getPhy); - - linkAdrVerifyParams.Status = status; - linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; - linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; - linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; - linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; - linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; - linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; - linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; - linkAdrVerifyParams.NbChannels = EU868_MAX_NB_CHANNELS; - linkAdrVerifyParams.ChannelsMask = &chMask; - linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; - linkAdrVerifyParams.MaxDatarate = EU868_TX_MAX_DATARATE; - linkAdrVerifyParams.Channels = Channels; - linkAdrVerifyParams.MinTxPower = EU868_MIN_TX_POWER; - linkAdrVerifyParams.MaxTxPower = EU868_MAX_TX_POWER; - - // Verify the parameters and update, if necessary - status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); - - // Update channelsMask if everything is correct - if (status == 0x07) - { - // Set the channels mask to a default value - memset(ChannelsMask, 0, sizeof(ChannelsMask)); - // Update the channels mask - ChannelsMask[0] = chMask; - } - - // Update status variables - *drOut = linkAdrParams.Datarate; - *txPowOut = linkAdrParams.TxPower; - *nbRepOut = linkAdrParams.NbRep; - *nbBytesParsed = bytesProcessed; - - return status; - } - - uint8_t RegionEU868RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) - { - uint8_t status = 0x07; - - // Verify radio frequency - if (Radio.CheckRfFrequency(rxParamSetupReq->Frequency) == false) - { - status &= 0xFE; // Channel frequency KO - } - - // Verify datarate - if (RegionCommonValueInRange(rxParamSetupReq->Datarate, EU868_RX_MIN_DATARATE, EU868_RX_MAX_DATARATE) == false) - { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, EU868_MIN_RX1_DR_OFFSET, EU868_MAX_RX1_DR_OFFSET) == false) - { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; - } - - uint8_t RegionEU868NewChannelReq(NewChannelReqParams_t *newChannelReq) - { - uint8_t status = 0x03; - ChannelAddParams_t channelAdd; - ChannelRemoveParams_t channelRemove; - - if (newChannelReq->NewChannel->Frequency == 0) - { - channelRemove.ChannelId = newChannelReq->ChannelId; - - // Remove - if (RegionEU868ChannelsRemove(&channelRemove) == false) - { - status &= 0xFC; - } - } - else - { - channelAdd.NewChannel = newChannelReq->NewChannel; - channelAdd.ChannelId = newChannelReq->ChannelId; - - switch (RegionEU868ChannelAdd(&channelAdd)) - { - case LORAMAC_STATUS_OK: - { - break; - } - case LORAMAC_STATUS_FREQUENCY_INVALID: - { - status &= 0xFE; - break; - } - case LORAMAC_STATUS_DATARATE_INVALID: - { - status &= 0xFD; - break; - } - case LORAMAC_STATUS_FREQ_AND_DR_INVALID: - { - status &= 0xFC; - break; - } - default: - { - status &= 0xFC; - break; - } - } - } - - return status; - } - - int8_t RegionEU868TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) - { - return -1; - } - - uint8_t RegionEU868DlChannelReq(DlChannelReqParams_t *dlChannelReq) - { - uint8_t status = 0x03; - uint8_t band = 0; - - // Verify if the frequency is supported - if (VerifyTxFreq(dlChannelReq->Rx1Frequency, &band) == false) - { - status &= 0xFE; - } - - // Verify if an uplink frequency exists - if (Channels[dlChannelReq->ChannelId].Frequency == 0) - { - status &= 0xFD; - } - - // Apply Rx1 frequency, if the status is OK - if (status == 0x03) - { - Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency; - } - - return status; - } - - int8_t RegionEU868AlternateDr(AlternateDrParams_t *alternateDr) - { - int8_t datarate = 0; - - if ((alternateDr->NbTrials % 48) == 0) - { - datarate = DR_0; - } - else if ((alternateDr->NbTrials % 32) == 0) - { - datarate = DR_1; - } - else if ((alternateDr->NbTrials % 24) == 0) - { - datarate = DR_2; - } - else if ((alternateDr->NbTrials % 16) == 0) - { - datarate = DR_3; - } - else if ((alternateDr->NbTrials % 8) == 0) - { - datarate = DR_4; - } - else - { - datarate = DR_5; - } - return datarate; - } - - void RegionEU868CalcBackOff(CalcBackOffParams_t *calcBackOff) - { - RegionCommonCalcBackOffParams_t calcBackOffParams; - - calcBackOffParams.Channels = Channels; - calcBackOffParams.Bands = Bands; - calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; - calcBackOffParams.Joined = calcBackOff->Joined; - calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; - calcBackOffParams.Channel = calcBackOff->Channel; - calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; - calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; - - RegionCommonCalcBackOff(&calcBackOffParams); - } - - bool RegionEU868NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTx = 0; - uint8_t enabledChannels[EU868_MAX_NB_CHANNELS] = {0}; - TimerTime_t nextTxDelay = 0; - - if (RegionCommonCountChannels(ChannelsMask, 0, 1) == 0) - { // Reactivate default channels - ChannelsMask[0] |= LC(1) + LC(2) + LC(3); - } - - if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) - { - // Reset Aggregated time off - *aggregatedTimeOff = 0; - - // Update bands Time OFF - nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, EU868_MAX_NB_BANDS); - - // Search how many channels are enabled - nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Joined, nextChanParams->Datarate, - ChannelsMask, Channels, - Bands, enabledChannels, &delayTx); - } - else - { - delayTx++; - nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); - } - - if (nbEnabledChannels > 0) - { - // We found a valid channel - *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; - - *time = 0; - return true; - } - else - { - if (delayTx > 0) - { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = nextTxDelay; - return true; - } - // Datarate not supported by any channel, restore defaults - ChannelsMask[0] |= LC(1) + LC(2) + LC(3); - *time = 0; - return false; - } - } - - LoRaMacStatus_t RegionEU868ChannelAdd(ChannelAddParams_t *channelAdd) - { - uint8_t band = 0; - bool drInvalid = false; - bool freqInvalid = false; - uint8_t id = channelAdd->ChannelId; - - if (id >= EU868_MAX_NB_CHANNELS) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - // Validate the datarate range - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Min, EU868_TX_MIN_DATARATE, EU868_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, EU868_TX_MIN_DATARATE, EU868_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - if (channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max) - { - drInvalid = true; - } - - // Default channels don't accept all values - if (id < EU868_NUMB_DEFAULT_CHANNELS) - { - // Validate the datarate range for min: must be DR_0 - if (channelAdd->NewChannel->DrRange.Fields.Min > DR_0) - { - drInvalid = true; - } - // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, DR_5, EU868_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - // We are not allowed to change the frequency - if (channelAdd->NewChannel->Frequency != Channels[id].Frequency) - { - freqInvalid = true; - } - } - - // Check frequency - if (freqInvalid == false) - { - if (VerifyTxFreq(channelAdd->NewChannel->Frequency, &band) == false) - { - freqInvalid = true; - } - } - - // Check status - if ((drInvalid == true) && (freqInvalid == true)) - { - return LORAMAC_STATUS_FREQ_AND_DR_INVALID; - } - if (drInvalid == true) - { - return LORAMAC_STATUS_DATARATE_INVALID; - } - if (freqInvalid == true) - { - return LORAMAC_STATUS_FREQUENCY_INVALID; - } - - memcpy(&(Channels[id]), channelAdd->NewChannel, sizeof(Channels[id])); - Channels[id].Band = band; - ChannelsMask[0] |= (1 << id); - return LORAMAC_STATUS_OK; - } - - bool RegionEU868ChannelsRemove(ChannelRemoveParams_t *channelRemove) - { - uint8_t id = channelRemove->ChannelId; - - if (id < EU868_NUMB_DEFAULT_CHANNELS) - { - return false; - } - - // Remove the channel from the list of channels - Channels[id] = (ChannelParams_t){0, 0, {0}, 0}; - - return RegionCommonChanDisable(ChannelsMask, id, EU868_MAX_NB_CHANNELS); - } - - void RegionEU868SetContinuousWave(ContinuousWaveParams_t *continuousWave) - { - int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); - int8_t phyTxPower = 0; - uint32_t frequency = Channels[continuousWave->Channel].Frequency; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); - - Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); - } - - uint8_t RegionEU868ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) - { - int8_t datarate = dr - drOffset; - - if (datarate < 0) - { - datarate = DR_0; - } - return datarate; - } + static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; + + // Static functions + static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) + { + uint8_t nextLowerDr = 0; + + if (dr == minDr) + { + nextLowerDr = minDr; + } + else + { + nextLowerDr = dr - 1; + } + return nextLowerDr; + } + + static uint32_t GetBandwidth(uint32_t drIndex) + { + switch (BandwidthsEU868[drIndex]) + { + default: + case 125000: + return 0; + case 250000: + return 1; + case 500000: + return 2; + } + } + + static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) + { + int8_t txPowerResult = txPower; + + // Limit tx power to the band max + txPowerResult = MAX(txPower, maxBandTxPower); + + return txPowerResult; + } + + static bool VerifyTxFreq(uint32_t freq, uint8_t *band) + { + // Check radio driver support + if (Radio.CheckRfFrequency(freq) == false) + { + return false; + } + + // Check frequency bands + if ((freq >= 863000000) && (freq < 865000000)) + { + *band = 2; + } + else if ((freq >= 865000000) && (freq <= 868000000)) + { + *band = 0; + } + else if ((freq > 868000000) && (freq <= 868600000)) + { + *band = 1; + } + else if ((freq >= 868700000) && (freq <= 869200000)) + { + *band = 2; + } + else if ((freq >= 869400000) && (freq <= 869650000)) + { + *band = 3; + } + else if ((freq >= 869700000) && (freq <= 870000000)) + { + *band = 4; + } + else + { + return false; + } + return true; + } + + static uint8_t CountNbOfEnabledChannels(bool joined, uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTransmission = 0; + + for (uint8_t i = 0, k = 0; i < EU868_MAX_NB_CHANNELS; i += 16, k++) + { + for (uint8_t j = 0; j < 16; j++) + { + if ((channelsMask[k] & (1 << j)) != 0) + { + if (channels[i + j].Frequency == 0) + { // Check if the channel is enabled + continue; + } + if (joined == false) + { + if ((EU868_JOIN_CHANNELS & (1 << j)) == 0) + { + continue; + } + } + if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, + channels[i + j].DrRange.Fields.Max) == false) + { // Check if the current channel selection supports the given datarate + continue; + } + if (bands[channels[i + j].Band].TimeOff > 0) + { // Check if the band is available for transmission + delayTransmission++; + continue; + } + enabledChannels[nbEnabledChannels++] = i + j; + } + } + } + + *delayTx = delayTransmission; + return nbEnabledChannels; + } + + PhyParam_t RegionEU868GetPhyParam(GetPhyParams_t *getPhy) + { + PhyParam_t phyParam = {0}; + + switch (getPhy->Attribute) + { + case PHY_MIN_RX_DR: + { + phyParam.Value = EU868_RX_MIN_DATARATE; + break; + } + case PHY_MIN_TX_DR: + { + phyParam.Value = EU868_TX_MIN_DATARATE; + break; + } + case PHY_DEF_TX_DR: + { + phyParam.Value = EU868_DEFAULT_DATARATE; + break; + } + case PHY_NEXT_LOWER_TX_DR: + { + phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, EU868_TX_MIN_DATARATE); + break; + } + case PHY_DEF_TX_POWER: + { + phyParam.Value = EU868_DEFAULT_TX_POWER; + break; + } + case PHY_MAX_PAYLOAD: + { + phyParam.Value = MaxPayloadOfDatarateEU868[getPhy->Datarate]; + break; + } + case PHY_MAX_PAYLOAD_REPEATER: + { + phyParam.Value = MaxPayloadOfDatarateRepeaterEU868[getPhy->Datarate]; + break; + } + case PHY_DUTY_CYCLE: + { + phyParam.Value = EU868_DUTY_CYCLE_ENABLED; + break; + } + case PHY_MAX_RX_WINDOW: + { + phyParam.Value = EU868_MAX_RX_WINDOW; + break; + } + case PHY_RECEIVE_DELAY1: + { + phyParam.Value = EU868_RECEIVE_DELAY1; + break; + } + case PHY_RECEIVE_DELAY2: + { + phyParam.Value = EU868_RECEIVE_DELAY2; + break; + } + case PHY_JOIN_ACCEPT_DELAY1: + { + phyParam.Value = EU868_JOIN_ACCEPT_DELAY1; + break; + } + case PHY_JOIN_ACCEPT_DELAY2: + { + phyParam.Value = EU868_JOIN_ACCEPT_DELAY2; + break; + } + case PHY_MAX_FCNT_GAP: + { + phyParam.Value = EU868_MAX_FCNT_GAP; + break; + } + case PHY_ACK_TIMEOUT: + { + phyParam.Value = (EU868_ACKTIMEOUT + randr(-EU868_ACK_TIMEOUT_RND, EU868_ACK_TIMEOUT_RND)); + break; + } + case PHY_DEF_DR1_OFFSET: + { + phyParam.Value = EU868_DEFAULT_RX1_DR_OFFSET; + break; + } + case PHY_DEF_RX2_FREQUENCY: + { + phyParam.Value = EU868_RX_WND_2_FREQ; + break; + } + case PHY_DEF_RX2_DR: + { + phyParam.Value = EU868_RX_WND_2_DR; + break; + } + case PHY_CHANNELS_MASK: + { + phyParam.ChannelsMask = ChannelsMask; + break; + } + case PHY_CHANNELS_DEFAULT_MASK: + { + phyParam.ChannelsMask = ChannelsDefaultMask; + break; + } + case PHY_MAX_NB_CHANNELS: + { + phyParam.Value = EU868_MAX_NB_CHANNELS; + break; + } + case PHY_CHANNELS: + { + phyParam.Channels = Channels; + break; + } + case PHY_DEF_UPLINK_DWELL_TIME: + case PHY_DEF_DOWNLINK_DWELL_TIME: + { + phyParam.Value = 0; + break; + } + case PHY_DEF_MAX_EIRP: + { + phyParam.fValue = EU868_DEFAULT_MAX_EIRP; + break; + } + case PHY_DEF_ANTENNA_GAIN: + { + phyParam.fValue = EU868_DEFAULT_ANTENNA_GAIN; + break; + } + case PHY_NB_JOIN_TRIALS: + case PHY_DEF_NB_JOIN_TRIALS: + { + phyParam.Value = 48; + break; + } + default: + { + break; + } + } + + return phyParam; + } + + void RegionEU868SetBandTxDone(SetBandTxDoneParams_t *txDone) + { + RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); + } + + void RegionEU868InitDefaults(InitType_t type) + { + switch (type) + { + case INIT_TYPE_INIT: + { + // Channels + Channels[0] = (ChannelParams_t)EU868_LC1; + Channels[1] = (ChannelParams_t)EU868_LC2; + Channels[2] = (ChannelParams_t)EU868_LC3; + + // Initialize the channels default mask + ChannelsDefaultMask[0] = LC(1) + LC(2) + LC(3); + // Update the channels mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); + break; + } + case INIT_TYPE_RESTORE: + { + // Restore channels default mask + ChannelsMask[0] |= ChannelsDefaultMask[0]; + break; + } + case INIT_TYPE_APP_DEFAULTS: + { + // Update the channels mask defaults + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); + break; + } + default: + { + break; + } + } + } + + bool RegionEU868Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) + { + switch (phyAttribute) + { + case PHY_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, EU868_TX_MIN_DATARATE, EU868_TX_MAX_DATARATE); + } + case PHY_DEF_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); + } + case PHY_RX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, EU868_RX_MIN_DATARATE, EU868_RX_MAX_DATARATE); + } + case PHY_DEF_TX_POWER: + case PHY_TX_POWER: + { + // Remark: switched min and max! + return RegionCommonValueInRange(verify->TxPower, EU868_MAX_TX_POWER, EU868_MIN_TX_POWER); + } + case PHY_DUTY_CYCLE: + { + return EU868_DUTY_CYCLE_ENABLED; + } + case PHY_NB_JOIN_TRIALS: + { + if (verify->NbJoinTrials < 48) + { + return false; + } + break; + } + default: + return false; + } + return true; + } + + void RegionEU868ApplyCFList(ApplyCFListParams_t *applyCFList) + { + ChannelParams_t newChannel; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + // Setup default datarate range + newChannel.DrRange.Value = (DR_5 << 4) | DR_0; + + // Size of the optional CF list + if (applyCFList->Size != 16) + { + return; + } + + // Last byte is RFU, don't take it into account + for (uint8_t i = 0, chanIdx = EU868_NUMB_DEFAULT_CHANNELS; chanIdx < EU868_MAX_NB_CHANNELS; i += 3, chanIdx++) + { + if (chanIdx < (EU868_NUMB_CHANNELS_CF_LIST + EU868_NUMB_DEFAULT_CHANNELS)) + { + // Channel frequency + newChannel.Frequency = (uint32_t)applyCFList->Payload[i]; + newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 1] << 8); + newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 2] << 16); + newChannel.Frequency *= 100; + + // Initialize alternative frequency to 0 + newChannel.Rx1Frequency = 0; + } + else + { + newChannel.Frequency = 0; + newChannel.DrRange.Value = 0; + newChannel.Rx1Frequency = 0; + } + + if (newChannel.Frequency != 0) + { + channelAdd.NewChannel = &newChannel; + channelAdd.ChannelId = chanIdx; + + // Try to add all channels + RegionEU868ChannelAdd(&channelAdd); + } + else + { + channelRemove.ChannelId = chanIdx; + + RegionEU868ChannelsRemove(&channelRemove); + } + } + } + + bool RegionEU868ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) + { + switch (chanMaskSet->ChannelsMaskType) + { + case CHANNELS_MASK: + { + RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 1); + break; + } + case CHANNELS_DEFAULT_MASK: + { + RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1); + break; + } + default: + return false; + } + return true; + } + + bool RegionEU868AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) + { + bool adrAckReq = false; + int8_t datarate = adrNext->Datarate; + int8_t txPower = adrNext->TxPower; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + + // Report back the adr ack counter + *adrAckCounter = adrNext->AdrAckCounter; + + if (adrNext->AdrEnabled == true) + { + if (datarate == EU868_TX_MIN_DATARATE) + { + *adrAckCounter = 0; + adrAckReq = false; + } + else + { + if (adrNext->AdrAckCounter >= EU868_ADR_ACK_LIMIT) + { + adrAckReq = true; + txPower = EU868_MAX_TX_POWER; + } + else + { + adrAckReq = false; + } + if (adrNext->AdrAckCounter >= (EU868_ADR_ACK_LIMIT + EU868_ADR_ACK_DELAY)) + { + if ((adrNext->AdrAckCounter % EU868_ADR_ACK_DELAY) == 1) + { + // Decrease the datarate + getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; + getPhy.Datarate = datarate; + getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; + phyParam = RegionEU868GetPhyParam(&getPhy); + datarate = phyParam.Value; + + if (datarate == EU868_TX_MIN_DATARATE) + { + // We must set adrAckReq to false as soon as we reach the lowest datarate + adrAckReq = false; + if (adrNext->UpdateChanMask == true) + { + // Re-enable default channels + ChannelsMask[0] |= LC(1) + LC(2) + LC(3); + } + } + } + } + } + } + + *drOut = datarate; + *txPowOut = txPower; + return adrAckReq; + } + + void RegionEU868ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) + { + double tSymbol = 0.0; + + // Get the datarate, perform a boundary check + rxConfigParams->Datarate = MIN(datarate, EU868_RX_MAX_DATARATE); + rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); + + if (rxConfigParams->Datarate == DR_7) + { // FSK + tSymbol = RegionCommonComputeSymbolTimeFsk(DataratesEU868[rxConfigParams->Datarate]); + } + else + { // LoRa + tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesEU868[rxConfigParams->Datarate], BandwidthsEU868[rxConfigParams->Datarate]); + } + + RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); + } + + bool RegionEU868RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) + { + RadioModems_t modem; + int8_t dr = rxConfig->Datarate; + uint8_t maxPayload = 0; + int8_t phyDr = 0; + uint32_t frequency = rxConfig->Frequency; + + if (Radio.GetStatus() != RF_IDLE) + { + return false; + } + + if (rxConfig->Window == 0) + { + // Apply window 1 frequency + frequency = Channels[rxConfig->Channel].Frequency; + // Apply the alternative RX 1 window frequency, if it is available + if (Channels[rxConfig->Channel].Rx1Frequency != 0) + { + frequency = Channels[rxConfig->Channel].Rx1Frequency; + } + } + + // Read the physical datarate from the datarates table + phyDr = DataratesEU868[dr]; + + Radio.SetChannel(frequency); + + // Radio configuration + if (dr == DR_7) + { + modem = MODEM_FSK; + Radio.SetRxConfig(modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous); + } + else + { + modem = MODEM_LORA; + Radio.SetRxConfig(modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); + } + + if (rxConfig->RepeaterSupport == true) + { + maxPayload = MaxPayloadOfDatarateRepeaterEU868[dr]; + } + else + { + maxPayload = MaxPayloadOfDatarateEU868[dr]; + } + + Radio.SetMaxPayloadLength(modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + *datarate = (uint8_t)dr; + return true; + } + + bool RegionEU868TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) + { + RadioModems_t modem; + int8_t phyDr = DataratesEU868[txConfig->Datarate]; + int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); + uint32_t bandwidth = GetBandwidth(txConfig->Datarate); + int8_t phyTxPower = 0; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); + + // Setup the radio frequency + Radio.SetChannel(Channels[txConfig->Channel].Frequency); + + if (txConfig->Datarate == DR_7) + { // High Speed FSK channel + modem = MODEM_FSK; + Radio.SetTxConfig(modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000); + } + else + { + modem = MODEM_LORA; + Radio.SetTxConfig(modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); + } + + // Setup maximum payload lenght of the radio driver + Radio.SetMaxPayloadLength(modem, txConfig->PktLen); + // Get the time-on-air of the next tx frame + *txTimeOnAir = Radio.TimeOnAir(modem, txConfig->PktLen); + + *txPower = txPowerLimited; + return true; + } + + uint8_t RegionEU868LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) + { + uint8_t status = 0x07; + RegionCommonLinkAdrParams_t linkAdrParams; + uint8_t nextIndex = 0; + uint8_t bytesProcessed = 0; + uint16_t chMask = 0; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; + + while (bytesProcessed < linkAdrReq->PayloadSize) + { + // Get ADR request parameters + nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); + + if (nextIndex == 0) + break; // break loop, since no more request has been found + + // Update bytes processed + bytesProcessed += nextIndex; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + // Setup temporary channels mask + chMask = linkAdrParams.ChMask; + + // Verify channels mask + if ((linkAdrParams.ChMaskCtrl == 0) && (chMask == 0)) + { + status &= 0xFE; // Channel mask KO + } + else if (((linkAdrParams.ChMaskCtrl >= 1) && (linkAdrParams.ChMaskCtrl <= 5)) || + (linkAdrParams.ChMaskCtrl >= 7)) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + for (uint8_t i = 0; i < EU868_MAX_NB_CHANNELS; i++) + { + if (linkAdrParams.ChMaskCtrl == 6) + { + if (Channels[i].Frequency != 0) + { + chMask |= 1 << i; + } + } + else + { + if (((chMask & (1 << i)) != 0) && + (Channels[i].Frequency == 0)) + { // Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + } + } + } + + // Get the minimum possible datarate + getPhy.Attribute = PHY_MIN_TX_DR; + getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; + phyParam = RegionEU868GetPhyParam(&getPhy); + + linkAdrVerifyParams.Status = status; + linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; + linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; + linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; + linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; + linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; + linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; + linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; + linkAdrVerifyParams.NbChannels = EU868_MAX_NB_CHANNELS; + linkAdrVerifyParams.ChannelsMask = &chMask; + linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; + linkAdrVerifyParams.MaxDatarate = EU868_TX_MAX_DATARATE; + linkAdrVerifyParams.Channels = Channels; + linkAdrVerifyParams.MinTxPower = EU868_MIN_TX_POWER; + linkAdrVerifyParams.MaxTxPower = EU868_MAX_TX_POWER; + + // Verify the parameters and update, if necessary + status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); + + // Update channelsMask if everything is correct + if (status == 0x07) + { + // Set the channels mask to a default value + memset(ChannelsMask, 0, sizeof(ChannelsMask)); + // Update the channels mask + ChannelsMask[0] = chMask; + } + + // Update status variables + *drOut = linkAdrParams.Datarate; + *txPowOut = linkAdrParams.TxPower; + *nbRepOut = linkAdrParams.NbRep; + *nbBytesParsed = bytesProcessed; + + return status; + } + + uint8_t RegionEU868RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) + { + uint8_t status = 0x07; + + // Verify radio frequency + if (Radio.CheckRfFrequency(rxParamSetupReq->Frequency) == false) + { + status &= 0xFE; // Channel frequency KO + } + + // Verify datarate + if (RegionCommonValueInRange(rxParamSetupReq->Datarate, EU868_RX_MIN_DATARATE, EU868_RX_MAX_DATARATE) == false) + { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, EU868_MIN_RX1_DR_OFFSET, EU868_MAX_RX1_DR_OFFSET) == false) + { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; + } + + uint8_t RegionEU868NewChannelReq(NewChannelReqParams_t *newChannelReq) + { + uint8_t status = 0x03; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + if (newChannelReq->NewChannel->Frequency == 0) + { + channelRemove.ChannelId = newChannelReq->ChannelId; + + // Remove + if (RegionEU868ChannelsRemove(&channelRemove) == false) + { + status &= 0xFC; + } + } + else + { + channelAdd.NewChannel = newChannelReq->NewChannel; + channelAdd.ChannelId = newChannelReq->ChannelId; + + switch (RegionEU868ChannelAdd(&channelAdd)) + { + case LORAMAC_STATUS_OK: + { + break; + } + case LORAMAC_STATUS_FREQUENCY_INVALID: + { + status &= 0xFE; + break; + } + case LORAMAC_STATUS_DATARATE_INVALID: + { + status &= 0xFD; + break; + } + case LORAMAC_STATUS_FREQ_AND_DR_INVALID: + { + status &= 0xFC; + break; + } + default: + { + status &= 0xFC; + break; + } + } + } + + return status; + } + + int8_t RegionEU868TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) + { + return -1; + } + + uint8_t RegionEU868DlChannelReq(DlChannelReqParams_t *dlChannelReq) + { + uint8_t status = 0x03; + uint8_t band = 0; + + // Verify if the frequency is supported + if (VerifyTxFreq(dlChannelReq->Rx1Frequency, &band) == false) + { + status &= 0xFE; + } + + // Verify if an uplink frequency exists + if (Channels[dlChannelReq->ChannelId].Frequency == 0) + { + status &= 0xFD; + } + + // Apply Rx1 frequency, if the status is OK + if (status == 0x03) + { + Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency; + } + + return status; + } + + int8_t RegionEU868AlternateDr(AlternateDrParams_t *alternateDr) + { + int8_t datarate = 0; + + if ((alternateDr->NbTrials % 48) == 0) + { + datarate = DR_0; + } + else if ((alternateDr->NbTrials % 32) == 0) + { + datarate = DR_1; + } + else if ((alternateDr->NbTrials % 24) == 0) + { + datarate = DR_2; + } + else if ((alternateDr->NbTrials % 16) == 0) + { + datarate = DR_3; + } + else if ((alternateDr->NbTrials % 8) == 0) + { + datarate = DR_4; + } + else + { + datarate = DR_5; + } + return datarate; + } + + void RegionEU868CalcBackOff(CalcBackOffParams_t *calcBackOff) + { + RegionCommonCalcBackOffParams_t calcBackOffParams; + + calcBackOffParams.Channels = Channels; + calcBackOffParams.Bands = Bands; + calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; + calcBackOffParams.Joined = calcBackOff->Joined; + calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; + calcBackOffParams.Channel = calcBackOff->Channel; + calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; + calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; + + RegionCommonCalcBackOff(&calcBackOffParams); + } + + bool RegionEU868NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTx = 0; + uint8_t enabledChannels[EU868_MAX_NB_CHANNELS] = {0}; + TimerTime_t nextTxDelay = 0; + + if (RegionCommonCountChannels(ChannelsMask, 0, 1) == 0) + { // Reactivate default channels + ChannelsMask[0] |= LC(1) + LC(2) + LC(3); + } + + if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) + { + // Reset Aggregated time off + *aggregatedTimeOff = 0; + + // Update bands Time OFF + nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, EU868_MAX_NB_BANDS); + + // Search how many channels are enabled + nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Joined, nextChanParams->Datarate, + ChannelsMask, Channels, + Bands, enabledChannels, &delayTx); + } + else + { + delayTx++; + nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); + } + + if (nbEnabledChannels > 0) + { + // We found a valid channel + *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; + + *time = 0; + return true; + } + else + { + if (delayTx > 0) + { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return true; + } + // Datarate not supported by any channel, restore defaults + ChannelsMask[0] |= LC(1) + LC(2) + LC(3); + *time = 0; + return false; + } + } + + LoRaMacStatus_t RegionEU868ChannelAdd(ChannelAddParams_t *channelAdd) + { + uint8_t band = 0; + bool drInvalid = false; + bool freqInvalid = false; + uint8_t id = channelAdd->ChannelId; + + if (id >= EU868_MAX_NB_CHANNELS) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + // Validate the datarate range + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Min, EU868_TX_MIN_DATARATE, EU868_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, EU868_TX_MIN_DATARATE, EU868_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + if (channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max) + { + drInvalid = true; + } + + // Default channels don't accept all values + if (id < EU868_NUMB_DEFAULT_CHANNELS) + { + // Validate the datarate range for min: must be DR_0 + if (channelAdd->NewChannel->DrRange.Fields.Min > DR_0) + { + drInvalid = true; + } + // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, DR_5, EU868_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + // We are not allowed to change the frequency + if (channelAdd->NewChannel->Frequency != Channels[id].Frequency) + { + freqInvalid = true; + } + } + + // Check frequency + if (freqInvalid == false) + { + if (VerifyTxFreq(channelAdd->NewChannel->Frequency, &band) == false) + { + freqInvalid = true; + } + } + + // Check status + if ((drInvalid == true) && (freqInvalid == true)) + { + return LORAMAC_STATUS_FREQ_AND_DR_INVALID; + } + if (drInvalid == true) + { + return LORAMAC_STATUS_DATARATE_INVALID; + } + if (freqInvalid == true) + { + return LORAMAC_STATUS_FREQUENCY_INVALID; + } + + memcpy(&(Channels[id]), channelAdd->NewChannel, sizeof(Channels[id])); + Channels[id].Band = band; + ChannelsMask[0] |= (1 << id); + return LORAMAC_STATUS_OK; + } + + bool RegionEU868ChannelsRemove(ChannelRemoveParams_t *channelRemove) + { + uint8_t id = channelRemove->ChannelId; + + if (id < EU868_NUMB_DEFAULT_CHANNELS) + { + return false; + } + + // Remove the channel from the list of channels + Channels[id] = (ChannelParams_t){0, 0, {0}, 0}; + + return RegionCommonChanDisable(ChannelsMask, id, EU868_MAX_NB_CHANNELS); + } + + void RegionEU868SetContinuousWave(ContinuousWaveParams_t *continuousWave) + { + int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); + int8_t phyTxPower = 0; + uint32_t frequency = Channels[continuousWave->Channel].Frequency; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); + + Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); + } + + uint8_t RegionEU868ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) + { + int8_t datarate = dr - drOffset; + + if (datarate < 0) + { + datarate = DR_0; + } + return datarate; + } }; \ No newline at end of file diff --git a/src/mac/region/RegionEU868.h b/src/mac/region/RegionEU868.h index 82b08c0..050068a 100644 --- a/src/mac/region/RegionEU868.h +++ b/src/mac/region/RegionEU868.h @@ -41,254 +41,278 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define EU868_MAX_NB_CHANNELS 16 +#define EU868_MAX_NB_CHANNELS 16 /*! * Number of default channels */ -#define EU868_NUMB_DEFAULT_CHANNELS 3 +#define EU868_NUMB_DEFAULT_CHANNELS 3 /*! * Number of channels to apply for the CF list */ -#define EU868_NUMB_CHANNELS_CF_LIST 5 +#define EU868_NUMB_CHANNELS_CF_LIST 5 /*! * Minimal datarate that can be used by the node */ -#define EU868_TX_MIN_DATARATE DR_0 +#define EU868_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define EU868_TX_MAX_DATARATE DR_7 +#define EU868_TX_MAX_DATARATE DR_7 /*! * Minimal datarate that can be used by the node */ -#define EU868_RX_MIN_DATARATE DR_0 +#define EU868_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define EU868_RX_MAX_DATARATE DR_7 +#define EU868_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node */ -#define EU868_DEFAULT_DATARATE DR_0 +#define EU868_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define EU868_MIN_RX1_DR_OFFSET 0 +#define EU868_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define EU868_MAX_RX1_DR_OFFSET 5 +#define EU868_MAX_RX1_DR_OFFSET 5 /*! * Default Rx1 receive datarate offset */ -#define EU868_DEFAULT_RX1_DR_OFFSET 0 +#define EU868_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define EU868_MIN_TX_POWER TX_POWER_7 +#define EU868_MIN_TX_POWER TX_POWER_7 /*! * Maximal Tx output power that can be used by the node */ -#define EU868_MAX_TX_POWER TX_POWER_0 +#define EU868_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define EU868_DEFAULT_TX_POWER TX_POWER_0 +#define EU868_DEFAULT_TX_POWER TX_POWER_0 /*! * Default Max EIRP */ -#define EU868_DEFAULT_MAX_EIRP 16.0f +#define EU868_DEFAULT_MAX_EIRP 16.0f /*! * Default antenna gain */ -#define EU868_DEFAULT_ANTENNA_GAIN 2.15f +#define EU868_DEFAULT_ANTENNA_GAIN 2.15f /*! * ADR Ack limit */ -#define EU868_ADR_ACK_LIMIT 64 +#define EU868_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define EU868_ADR_ACK_DELAY 32 +#define EU868_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define EU868_DUTY_CYCLE_ENABLED 1 +#define EU868_DUTY_CYCLE_ENABLED 1 /*! * Maximum RX window duration */ -#define EU868_MAX_RX_WINDOW 3000 +#define EU868_MAX_RX_WINDOW 3000 /*! * Receive delay 1 */ -#define EU868_RECEIVE_DELAY1 1000 +#define EU868_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define EU868_RECEIVE_DELAY2 2000 +#define EU868_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define EU868_JOIN_ACCEPT_DELAY1 5000 +#define EU868_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define EU868_JOIN_ACCEPT_DELAY2 6000 +#define EU868_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define EU868_MAX_FCNT_GAP 16384 +#define EU868_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define EU868_ACKTIMEOUT 2000 +#define EU868_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define EU868_ACK_TIMEOUT_RND 1000 +#define EU868_ACK_TIMEOUT_RND 1000 -#if ( EU868_DEFAULT_DATARATE > DR_5 ) +#if (EU868_DEFAULT_DATARATE > DR_5) #error "A default DR higher than DR_5 may lead to connectivity loss." #endif /*! * Second reception window channel frequency definition. */ -#define EU868_RX_WND_2_FREQ 869525000 +#define EU868_RX_WND_2_FREQ 869525000 /*! * Second reception window channel datarate definition. */ -#define EU868_RX_WND_2_DR DR_0 +#define EU868_RX_WND_2_DR DR_0 /*! * Maximum number of bands */ -#define EU868_MAX_NB_BANDS 5 +#define EU868_MAX_NB_BANDS 5 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define EU868_BAND0 { 100 , EU868_MAX_TX_POWER, 0, 0 } // 1.0 % +#define EU868_BAND0 \ + { \ + 100, EU868_MAX_TX_POWER, 0, 0 \ + } // 1.0 % /*! * Band 1 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define EU868_BAND1 { 100 , EU868_MAX_TX_POWER, 0, 0 } // 1.0 % +#define EU868_BAND1 \ + { \ + 100, EU868_MAX_TX_POWER, 0, 0 \ + } // 1.0 % /*! * Band 2 definition * Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define EU868_BAND2 { 1000, EU868_MAX_TX_POWER, 0, 0 } // 0.1 % +#define EU868_BAND2 \ + { \ + 1000, EU868_MAX_TX_POWER, 0, 0 \ + } // 0.1 % /*! * Band 2 definition * Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define EU868_BAND3 { 10 , EU868_MAX_TX_POWER, 0, 0 } // 10.0 % +#define EU868_BAND3 \ + { \ + 10, EU868_MAX_TX_POWER, 0, 0 \ + } // 10.0 % /*! * Band 2 definition * Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define EU868_BAND4 { 100 , EU868_MAX_TX_POWER, 0, 0 } // 1.0 % +#define EU868_BAND4 \ + { \ + 100, EU868_MAX_TX_POWER, 0, 0 \ + } // 1.0 % /*! * LoRaMac default channel 1 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define EU868_LC1 { 868100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } +#define EU868_LC1 \ + { \ + 868100000, 0, {((DR_5 << 4) | DR_0)}, 1 \ + } /*! * LoRaMac default channel 2 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define EU868_LC2 { 868300000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } +#define EU868_LC2 \ + { \ + 868300000, 0, {((DR_5 << 4) | DR_0)}, 1 \ + } /*! * LoRaMac default channel 3 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define EU868_LC3 { 868500000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } +#define EU868_LC3 \ + { \ + 868500000, 0, {((DR_5 << 4) | DR_0)}, 1 \ + } /*! * LoRaMac channels which are allowed for the join procedure */ -#define EU868_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) +#define EU868_JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesEU868[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; + static const uint8_t DataratesEU868[] = {12, 11, 10, 9, 8, 7, 7, 50}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsEU868[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 }; + static const uint32_t BandwidthsEU868[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; -/*! + /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateEU868[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; + static const uint8_t MaxPayloadOfDatarateEU868[] = {51, 51, 51, 115, 242, 242, 242, 242}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateRepeaterEU868[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; + static const uint8_t MaxPayloadOfDatarateRepeaterEU868[] = {51, 51, 51, 115, 222, 222, 222, 222}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionEU868GetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionEU868GetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionEU868SetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionEU868SetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionEU868InitDefaults( InitType_t type ); + void RegionEU868InitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -297,26 +321,26 @@ void RegionEU868InitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionEU868Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionEU868Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionEU868ApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionEU868ApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionEU868ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionEU868ChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -329,9 +353,9 @@ bool RegionEU868ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionEU868AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionEU868AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -344,9 +368,9 @@ bool RegionEU868AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowO * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionEU868ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionEU868ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -355,9 +379,9 @@ void RegionEU868ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionEU868RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionEU868RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -368,36 +392,36 @@ bool RegionEU868RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionEU868TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionEU868TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionEU868LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionEU868LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionEU868RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionEU868RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionEU868NewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionEU868NewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -406,34 +430,34 @@ uint8_t RegionEU868NewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionEU868TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionEU868TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionEU868DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionEU868DlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionEU868AlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionEU868AlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionEU868CalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionEU868CalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -445,34 +469,34 @@ void RegionEU868CalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionEU868NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionEU868NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionEU868ChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionEU868ChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionEU868ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionEU868ChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionEU868SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionEU868SetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -483,8 +507,8 @@ void RegionEU868SetContinuousWave( ContinuousWaveParams_t* continuousWave ); * * \retval newDr Computed datarate. */ -uint8_t RegionEU868ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionEU868ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONEU868 */ + /*! \} defgroup REGIONEU868 */ }; #endif // __REGION_EU868_H__ diff --git a/src/mac/region/RegionIN865.cpp b/src/mac/region/RegionIN865.cpp index f6899e4..630dd97 100644 --- a/src/mac/region/RegionIN865.cpp +++ b/src/mac/region/RegionIN865.cpp @@ -37,1018 +37,1018 @@ extern "C" // Definitions #define CHANNELS_MASK_SIZE 1 - // Global attributes - /*! + // Global attributes + /*! * LoRaMAC channels */ - static ChannelParams_t Channels[IN865_MAX_NB_CHANNELS]; + static ChannelParams_t Channels[IN865_MAX_NB_CHANNELS]; - /*! + /*! * LoRaMac bands */ - static Band_t Bands[IN865_MAX_NB_BANDS] = - { - IN865_BAND0}; + static Band_t Bands[IN865_MAX_NB_BANDS] = + { + IN865_BAND0}; - /*! + /*! * LoRaMac channels mask */ - static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; + static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; - /*! + /*! * LoRaMac channels default mask */ - static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; - - // Static functions - static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) - { - uint8_t nextLowerDr = 0; - - if (dr == minDr) - { - nextLowerDr = minDr; - } - else if (dr == DR_7) - { - nextLowerDr = DR_5; - } - else - { - nextLowerDr = dr - 1; - } - return nextLowerDr; - } - - static uint32_t GetBandwidth(uint32_t drIndex) - { - switch (BandwidthsIN865[drIndex]) - { - default: - case 125000: - return 0; - case 250000: - return 1; - case 500000: - return 2; - } - } - - static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) - { - int8_t txPowerResult = txPower; - - // Limit tx power to the band max - txPowerResult = MAX(txPower, maxBandTxPower); - - return txPowerResult; - } - - static bool VerifyTxFreq(uint32_t freq, uint8_t *band) - { - // Check radio driver support - if (Radio.CheckRfFrequency(freq) == false) - { - return false; - } - - if ((freq < 865000000) || (freq > 867000000)) - { - return false; - } - return true; - } - - static uint8_t CountNbOfEnabledChannels(bool joined, uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTransmission = 0; - - for (uint8_t i = 0, k = 0; i < IN865_MAX_NB_CHANNELS; i += 16, k++) - { - for (uint8_t j = 0; j < 16; j++) - { - if ((channelsMask[k] & (1 << j)) != 0) - { - if (channels[i + j].Frequency == 0) - { // Check if the channel is enabled - continue; - } - if (joined == false) - { - if ((IN865_JOIN_CHANNELS & (1 << j)) == 0) - { - continue; - } - } - if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, - channels[i + j].DrRange.Fields.Max) == false) - { // Check if the current channel selection supports the given datarate - continue; - } - if (bands[channels[i + j].Band].TimeOff > 0) - { // Check if the band is available for transmission - delayTransmission++; - continue; - } - enabledChannels[nbEnabledChannels++] = i + j; - } - } - } - - *delayTx = delayTransmission; - return nbEnabledChannels; - } - - PhyParam_t RegionIN865GetPhyParam(GetPhyParams_t *getPhy) - { - PhyParam_t phyParam = {0}; - - switch (getPhy->Attribute) - { - case PHY_MIN_RX_DR: - { - phyParam.Value = IN865_RX_MIN_DATARATE; - break; - } - case PHY_MIN_TX_DR: - { - phyParam.Value = IN865_TX_MIN_DATARATE; - break; - } - case PHY_DEF_TX_DR: - { - phyParam.Value = IN865_DEFAULT_DATARATE; - break; - } - case PHY_NEXT_LOWER_TX_DR: - { - phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, IN865_TX_MIN_DATARATE); - break; - } - case PHY_DEF_TX_POWER: - { - phyParam.Value = IN865_DEFAULT_TX_POWER; - break; - } - case PHY_MAX_PAYLOAD: - { - phyParam.Value = MaxPayloadOfDatarateIN865[getPhy->Datarate]; - break; - } - case PHY_MAX_PAYLOAD_REPEATER: - { - phyParam.Value = MaxPayloadOfDatarateRepeaterIN865[getPhy->Datarate]; - break; - } - case PHY_DUTY_CYCLE: - { - phyParam.Value = IN865_DUTY_CYCLE_ENABLED; - break; - } - case PHY_MAX_RX_WINDOW: - { - phyParam.Value = IN865_MAX_RX_WINDOW; - break; - } - case PHY_RECEIVE_DELAY1: - { - phyParam.Value = IN865_RECEIVE_DELAY1; - break; - } - case PHY_RECEIVE_DELAY2: - { - phyParam.Value = IN865_RECEIVE_DELAY2; - break; - } - case PHY_JOIN_ACCEPT_DELAY1: - { - phyParam.Value = IN865_JOIN_ACCEPT_DELAY1; - break; - } - case PHY_JOIN_ACCEPT_DELAY2: - { - phyParam.Value = IN865_JOIN_ACCEPT_DELAY2; - break; - } - case PHY_MAX_FCNT_GAP: - { - phyParam.Value = IN865_MAX_FCNT_GAP; - break; - } - case PHY_ACK_TIMEOUT: - { - phyParam.Value = (IN865_ACKTIMEOUT + randr(-IN865_ACK_TIMEOUT_RND, IN865_ACK_TIMEOUT_RND)); - break; - } - case PHY_DEF_DR1_OFFSET: - { - phyParam.Value = IN865_DEFAULT_RX1_DR_OFFSET; - break; - } - case PHY_DEF_RX2_FREQUENCY: - { - phyParam.Value = IN865_RX_WND_2_FREQ; - break; - } - case PHY_DEF_RX2_DR: - { - phyParam.Value = IN865_RX_WND_2_DR; - break; - } - case PHY_CHANNELS_MASK: - { - phyParam.ChannelsMask = ChannelsMask; - break; - } - case PHY_CHANNELS_DEFAULT_MASK: - { - phyParam.ChannelsMask = ChannelsDefaultMask; - break; - } - case PHY_MAX_NB_CHANNELS: - { - phyParam.Value = IN865_MAX_NB_CHANNELS; - break; - } - case PHY_CHANNELS: - { - phyParam.Channels = Channels; - break; - } - case PHY_DEF_UPLINK_DWELL_TIME: - case PHY_DEF_DOWNLINK_DWELL_TIME: - { - phyParam.Value = 0; - break; - } - case PHY_DEF_MAX_EIRP: - { - phyParam.fValue = IN865_DEFAULT_MAX_EIRP; - break; - } - case PHY_DEF_ANTENNA_GAIN: - { - phyParam.fValue = IN865_DEFAULT_ANTENNA_GAIN; - break; - } - case PHY_NB_JOIN_TRIALS: - case PHY_DEF_NB_JOIN_TRIALS: - { - phyParam.Value = 48; - break; - } - default: - { - break; - } - } - - return phyParam; - } - - void RegionIN865SetBandTxDone(SetBandTxDoneParams_t *txDone) - { - RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); - } - - void RegionIN865InitDefaults(InitType_t type) - { - switch (type) - { - case INIT_TYPE_INIT: - { - // Channels - Channels[0] = (ChannelParams_t)IN865_LC1; - Channels[1] = (ChannelParams_t)IN865_LC2; - Channels[2] = (ChannelParams_t)IN865_LC3; - - // Initialize the channels default mask - ChannelsDefaultMask[0] = LC(1) + LC(2) + LC(3); - // Update the channels mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); - break; - } - case INIT_TYPE_RESTORE: - { - // Restore channels default mask - ChannelsMask[0] |= ChannelsDefaultMask[0]; - break; - } - case INIT_TYPE_APP_DEFAULTS: - { - // Update the channels mask defaults - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); - break; - } - default: - { - break; - } - } - } - - bool RegionIN865Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) - { - switch (phyAttribute) - { - case PHY_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, IN865_TX_MIN_DATARATE, IN865_TX_MAX_DATARATE); - } - case PHY_DEF_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); - } - case PHY_RX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, IN865_RX_MIN_DATARATE, IN865_RX_MAX_DATARATE); - } - case PHY_DEF_TX_POWER: - case PHY_TX_POWER: - { - // Remark: switched min and max! - return RegionCommonValueInRange(verify->TxPower, IN865_MAX_TX_POWER, IN865_MIN_TX_POWER); - } - case PHY_DUTY_CYCLE: - { - return IN865_DUTY_CYCLE_ENABLED; - } - case PHY_NB_JOIN_TRIALS: - { - if (verify->NbJoinTrials < 48) - { - return false; - } - break; - } - default: - return false; - } - return true; - } - - void RegionIN865ApplyCFList(ApplyCFListParams_t *applyCFList) - { - ChannelParams_t newChannel; - ChannelAddParams_t channelAdd; - ChannelRemoveParams_t channelRemove; - - // Setup default datarate range - newChannel.DrRange.Value = (DR_5 << 4) | DR_0; - - // Size of the optional CF list - if (applyCFList->Size != 16) - { - return; - } - - // Last byte is RFU, don't take it into account - for (uint8_t i = 0, chanIdx = IN865_NUMB_DEFAULT_CHANNELS; chanIdx < IN865_MAX_NB_CHANNELS; i += 3, chanIdx++) - { - if (chanIdx < (IN865_NUMB_CHANNELS_CF_LIST + IN865_NUMB_DEFAULT_CHANNELS)) - { - // Channel frequency - newChannel.Frequency = (uint32_t)applyCFList->Payload[i]; - newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 1] << 8); - newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 2] << 16); - newChannel.Frequency *= 100; - - // Initialize alternative frequency to 0 - newChannel.Rx1Frequency = 0; - } - else - { - newChannel.Frequency = 0; - newChannel.DrRange.Value = 0; - newChannel.Rx1Frequency = 0; - } - - if (newChannel.Frequency != 0) - { - channelAdd.NewChannel = &newChannel; - channelAdd.ChannelId = chanIdx; - - // Try to add all channels - RegionIN865ChannelAdd(&channelAdd); - } - else - { - channelRemove.ChannelId = chanIdx; - - RegionIN865ChannelsRemove(&channelRemove); - } - } - } - - bool RegionIN865ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) - { - switch (chanMaskSet->ChannelsMaskType) - { - case CHANNELS_MASK: - { - RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 1); - break; - } - case CHANNELS_DEFAULT_MASK: - { - RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1); - break; - } - default: - return false; - } - return true; - } - - bool RegionIN865AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) - { - bool adrAckReq = false; - int8_t datarate = adrNext->Datarate; - int8_t txPower = adrNext->TxPower; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - - // Report back the adr ack counter - *adrAckCounter = adrNext->AdrAckCounter; - - if (adrNext->AdrEnabled == true) - { - if (datarate == IN865_TX_MIN_DATARATE) - { - *adrAckCounter = 0; - adrAckReq = false; - } - else - { - if (adrNext->AdrAckCounter >= IN865_ADR_ACK_LIMIT) - { - adrAckReq = true; - txPower = IN865_MAX_TX_POWER; - } - else - { - adrAckReq = false; - } - if (adrNext->AdrAckCounter >= (IN865_ADR_ACK_LIMIT + IN865_ADR_ACK_DELAY)) - { - if ((adrNext->AdrAckCounter % IN865_ADR_ACK_DELAY) == 1) - { - // Decrease the datarate - getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; - getPhy.Datarate = datarate; - getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; - phyParam = RegionIN865GetPhyParam(&getPhy); - datarate = phyParam.Value; - - if (datarate == IN865_TX_MIN_DATARATE) - { - // We must set adrAckReq to false as soon as we reach the lowest datarate - adrAckReq = false; - if (adrNext->UpdateChanMask == true) - { - // Re-enable default channels - ChannelsMask[0] |= LC(1) + LC(2) + LC(3); - } - } - } - } - } - } - - *drOut = datarate; - *txPowOut = txPower; - return adrAckReq; - } - - void RegionIN865ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) - { - double tSymbol = 0.0; - - // Get the datarate, perform a boundary check - rxConfigParams->Datarate = MIN(datarate, IN865_RX_MAX_DATARATE); - rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); - - if (rxConfigParams->Datarate == DR_7) - { // FSK - tSymbol = RegionCommonComputeSymbolTimeFsk(DataratesIN865[rxConfigParams->Datarate]); - } - else - { // LoRa - tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesIN865[rxConfigParams->Datarate], BandwidthsIN865[rxConfigParams->Datarate]); - } - - RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); - } - - bool RegionIN865RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) - { - RadioModems_t modem; - int8_t dr = rxConfig->Datarate; - uint8_t maxPayload = 0; - int8_t phyDr = 0; - uint32_t frequency = rxConfig->Frequency; - - if (Radio.GetStatus() != RF_IDLE) - { - return false; - } - - if (rxConfig->Window == 0) - { - // Apply window 1 frequency - frequency = Channels[rxConfig->Channel].Frequency; - // Apply the alternative RX 1 window frequency, if it is available - if (Channels[rxConfig->Channel].Rx1Frequency != 0) - { - frequency = Channels[rxConfig->Channel].Rx1Frequency; - } - } - - // Read the physical datarate from the datarates table - phyDr = DataratesIN865[dr]; - - Radio.SetChannel(frequency); - - // Radio configuration - if (dr == DR_7) - { - modem = MODEM_FSK; - Radio.SetRxConfig(modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous); - } - else - { - modem = MODEM_LORA; - Radio.SetRxConfig(modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); - } - - if (rxConfig->RepeaterSupport == true) - { - maxPayload = MaxPayloadOfDatarateRepeaterIN865[dr]; - } - else - { - maxPayload = MaxPayloadOfDatarateIN865[dr]; - } - Radio.SetMaxPayloadLength(modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - *datarate = (uint8_t)dr; - return true; - } - - bool RegionIN865TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) - { - RadioModems_t modem; - int8_t phyDr = DataratesIN865[txConfig->Datarate]; - int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); - uint32_t bandwidth = GetBandwidth(txConfig->Datarate); - int8_t phyTxPower = 0; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); - - // Setup the radio frequency - Radio.SetChannel(Channels[txConfig->Channel].Frequency); - - if (txConfig->Datarate == DR_7) - { // High Speed FSK channel - modem = MODEM_FSK; - Radio.SetTxConfig(modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000); - } - else - { - modem = MODEM_LORA; - Radio.SetTxConfig(modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); - } - - // Setup maximum payload lenght of the radio driver - Radio.SetMaxPayloadLength(modem, txConfig->PktLen); - // Get the time-on-air of the next tx frame - *txTimeOnAir = Radio.TimeOnAir(modem, txConfig->PktLen); - - *txPower = txPowerLimited; - return true; - } - - uint8_t RegionIN865LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) - { - uint8_t status = 0x07; - RegionCommonLinkAdrParams_t linkAdrParams; - uint8_t nextIndex = 0; - uint8_t bytesProcessed = 0; - uint16_t chMask = 0; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; - - while (bytesProcessed < linkAdrReq->PayloadSize) - { - // Get ADR request parameters - nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); - - if (nextIndex == 0) - break; // break loop, since no more request has been found - - // Update bytes processed - bytesProcessed += nextIndex; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - // Setup temporary channels mask - chMask = linkAdrParams.ChMask; - - // Verify channels mask - if ((linkAdrParams.ChMaskCtrl == 0) && (chMask == 0)) - { - status &= 0xFE; // Channel mask KO - } - else if (((linkAdrParams.ChMaskCtrl >= 1) && (linkAdrParams.ChMaskCtrl <= 5)) || - (linkAdrParams.ChMaskCtrl >= 7)) - { - // RFU - status &= 0xFE; // Channel mask KO - } - else - { - for (uint8_t i = 0; i < IN865_MAX_NB_CHANNELS; i++) - { - if (linkAdrParams.ChMaskCtrl == 6) - { - if (Channels[i].Frequency != 0) - { - chMask |= 1 << i; - } - } - else - { - if (((chMask & (1 << i)) != 0) && - (Channels[i].Frequency == 0)) - { // Trying to enable an undefined channel - status &= 0xFE; // Channel mask KO - } - } - } - } - } - - // Get the minimum possible datarate - getPhy.Attribute = PHY_MIN_TX_DR; - getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; - phyParam = RegionIN865GetPhyParam(&getPhy); - - linkAdrVerifyParams.Status = status; - linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; - linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; - linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; - linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; - linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; - linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; - linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; - linkAdrVerifyParams.NbChannels = IN865_MAX_NB_CHANNELS; - linkAdrVerifyParams.ChannelsMask = &chMask; - linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; - linkAdrVerifyParams.MaxDatarate = IN865_TX_MAX_DATARATE; - linkAdrVerifyParams.Channels = Channels; - linkAdrVerifyParams.MinTxPower = IN865_MIN_TX_POWER; - linkAdrVerifyParams.MaxTxPower = IN865_MAX_TX_POWER; - - // Verify the parameters and update, if necessary - status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); - - // Update channelsMask if everything is correct - if (status == 0x07) - { - // Set the channels mask to a default value - memset(ChannelsMask, 0, sizeof(ChannelsMask)); - // Update the channels mask - ChannelsMask[0] = chMask; - } - - // Update status variables - *drOut = linkAdrParams.Datarate; - *txPowOut = linkAdrParams.TxPower; - *nbRepOut = linkAdrParams.NbRep; - *nbBytesParsed = bytesProcessed; - - return status; - } - - uint8_t RegionIN865RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) - { - uint8_t status = 0x07; - - // Verify radio frequency - if (Radio.CheckRfFrequency(rxParamSetupReq->Frequency) == false) - { - status &= 0xFE; // Channel frequency KO - } - - // Verify datarate - if (RegionCommonValueInRange(rxParamSetupReq->Datarate, IN865_RX_MIN_DATARATE, IN865_RX_MAX_DATARATE) == false) - { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, IN865_MIN_RX1_DR_OFFSET, IN865_MAX_RX1_DR_OFFSET) == false) - { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; - } - - uint8_t RegionIN865NewChannelReq(NewChannelReqParams_t *newChannelReq) - { - uint8_t status = 0x03; - ChannelAddParams_t channelAdd; - ChannelRemoveParams_t channelRemove; - - if (newChannelReq->NewChannel->Frequency == 0) - { - channelRemove.ChannelId = newChannelReq->ChannelId; - - // Remove - if (RegionIN865ChannelsRemove(&channelRemove) == false) - { - status &= 0xFC; - } - } - else - { - channelAdd.NewChannel = newChannelReq->NewChannel; - channelAdd.ChannelId = newChannelReq->ChannelId; - - switch (RegionIN865ChannelAdd(&channelAdd)) - { - case LORAMAC_STATUS_OK: - { - break; - } - case LORAMAC_STATUS_FREQUENCY_INVALID: - { - status &= 0xFE; - break; - } - case LORAMAC_STATUS_DATARATE_INVALID: - { - status &= 0xFD; - break; - } - case LORAMAC_STATUS_FREQ_AND_DR_INVALID: - { - status &= 0xFC; - break; - } - default: - { - status &= 0xFC; - break; - } - } - } - - return status; - } - - int8_t RegionIN865TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) - { - return -1; - } - - uint8_t RegionIN865DlChannelReq(DlChannelReqParams_t *dlChannelReq) - { - uint8_t status = 0x03; - uint8_t band = 0; - - // Verify if the frequency is supported - if (VerifyTxFreq(dlChannelReq->Rx1Frequency, &band) == false) - { - status &= 0xFE; - } - - // Verify if an uplink frequency exists - if (Channels[dlChannelReq->ChannelId].Frequency == 0) - { - status &= 0xFD; - } - - // Apply Rx1 frequency, if the status is OK - if (status == 0x03) - { - Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency; - } - - return status; - } - - int8_t RegionIN865AlternateDr(AlternateDrParams_t *alternateDr) - { - int8_t datarate = 0; - - if ((alternateDr->NbTrials % 48) == 0) - { - datarate = DR_0; - } - else if ((alternateDr->NbTrials % 32) == 0) - { - datarate = DR_1; - } - else if ((alternateDr->NbTrials % 24) == 0) - { - datarate = DR_2; - } - else if ((alternateDr->NbTrials % 16) == 0) - { - datarate = DR_3; - } - else if ((alternateDr->NbTrials % 8) == 0) - { - datarate = DR_4; - } - else - { - datarate = DR_5; - } - return datarate; - } - - void RegionIN865CalcBackOff(CalcBackOffParams_t *calcBackOff) - { - RegionCommonCalcBackOffParams_t calcBackOffParams; - - calcBackOffParams.Channels = Channels; - calcBackOffParams.Bands = Bands; - calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; - calcBackOffParams.Joined = calcBackOff->Joined; - calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; - calcBackOffParams.Channel = calcBackOff->Channel; - calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; - calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; - - RegionCommonCalcBackOff(&calcBackOffParams); - } - - bool RegionIN865NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTx = 0; - uint8_t enabledChannels[IN865_MAX_NB_CHANNELS] = {0}; - TimerTime_t nextTxDelay = 0; - - if (RegionCommonCountChannels(ChannelsMask, 0, 1) == 0) - { // Reactivate default channels - ChannelsMask[0] |= LC(1) + LC(2) + LC(3); - } - - if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) - { - // Reset Aggregated time off - *aggregatedTimeOff = 0; - - // Update bands Time OFF - nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, IN865_MAX_NB_BANDS); - - // Search how many channels are enabled - nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Joined, nextChanParams->Datarate, - ChannelsMask, Channels, - Bands, enabledChannels, &delayTx); - } - else - { - delayTx++; - nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); - } - - if (nbEnabledChannels > 0) - { - // We found a valid channel - *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; - - *time = 0; - return true; - } - else - { - if (delayTx > 0) - { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = nextTxDelay; - return true; - } - // Datarate not supported by any channel, restore defaults - ChannelsMask[0] |= LC(1) + LC(2) + LC(3); - *time = 0; - return false; - } - } - - LoRaMacStatus_t RegionIN865ChannelAdd(ChannelAddParams_t *channelAdd) - { - uint8_t band = 0; - bool drInvalid = false; - bool freqInvalid = false; - uint8_t id = channelAdd->ChannelId; - - if (id >= IN865_MAX_NB_CHANNELS) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - // Validate the datarate range - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Min, IN865_TX_MIN_DATARATE, IN865_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, IN865_TX_MIN_DATARATE, IN865_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - if (channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max) - { - drInvalid = true; - } - - // Default channels don't accept all values - if (id < IN865_NUMB_DEFAULT_CHANNELS) - { - // Validate the datarate range for min: must be DR_0 - if (channelAdd->NewChannel->DrRange.Fields.Min > DR_0) - { - drInvalid = true; - } - // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE - if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, DR_5, IN865_TX_MAX_DATARATE) == false) - { - drInvalid = true; - } - // We are not allowed to change the frequency - if (channelAdd->NewChannel->Frequency != Channels[id].Frequency) - { - freqInvalid = true; - } - } - - // Check frequency - if (freqInvalid == false) - { - if (VerifyTxFreq(channelAdd->NewChannel->Frequency, &band) == false) - { - freqInvalid = true; - } - } - - // Check status - if ((drInvalid == true) && (freqInvalid == true)) - { - return LORAMAC_STATUS_FREQ_AND_DR_INVALID; - } - if (drInvalid == true) - { - return LORAMAC_STATUS_DATARATE_INVALID; - } - if (freqInvalid == true) - { - return LORAMAC_STATUS_FREQUENCY_INVALID; - } - - memcpy(&(Channels[id]), channelAdd->NewChannel, sizeof(Channels[id])); - Channels[id].Band = band; - ChannelsMask[0] |= (1 << id); - return LORAMAC_STATUS_OK; - } - - bool RegionIN865ChannelsRemove(ChannelRemoveParams_t *channelRemove) - { - uint8_t id = channelRemove->ChannelId; - - if (id < IN865_NUMB_DEFAULT_CHANNELS) - { - return false; - } - - // Remove the channel from the list of channels - Channels[id] = (ChannelParams_t){0, 0, {0}, 0}; - - return RegionCommonChanDisable(ChannelsMask, id, IN865_MAX_NB_CHANNELS); - } - - void RegionIN865SetContinuousWave(ContinuousWaveParams_t *continuousWave) - { - int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); - int8_t phyTxPower = 0; - uint32_t frequency = Channels[continuousWave->Channel].Frequency; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); - - Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); - } - - uint8_t RegionIN865ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) - { - // Apply offset formula - return MIN(DR_5, MAX(DR_0, dr - EffectiveRx1DrOffsetIN865[drOffset])); - } + static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; + + // Static functions + static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) + { + uint8_t nextLowerDr = 0; + + if (dr == minDr) + { + nextLowerDr = minDr; + } + else if (dr == DR_7) + { + nextLowerDr = DR_5; + } + else + { + nextLowerDr = dr - 1; + } + return nextLowerDr; + } + + static uint32_t GetBandwidth(uint32_t drIndex) + { + switch (BandwidthsIN865[drIndex]) + { + default: + case 125000: + return 0; + case 250000: + return 1; + case 500000: + return 2; + } + } + + static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) + { + int8_t txPowerResult = txPower; + + // Limit tx power to the band max + txPowerResult = MAX(txPower, maxBandTxPower); + + return txPowerResult; + } + + static bool VerifyTxFreq(uint32_t freq, uint8_t *band) + { + // Check radio driver support + if (Radio.CheckRfFrequency(freq) == false) + { + return false; + } + + if ((freq < 865000000) || (freq > 867000000)) + { + return false; + } + return true; + } + + static uint8_t CountNbOfEnabledChannels(bool joined, uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTransmission = 0; + + for (uint8_t i = 0, k = 0; i < IN865_MAX_NB_CHANNELS; i += 16, k++) + { + for (uint8_t j = 0; j < 16; j++) + { + if ((channelsMask[k] & (1 << j)) != 0) + { + if (channels[i + j].Frequency == 0) + { // Check if the channel is enabled + continue; + } + if (joined == false) + { + if ((IN865_JOIN_CHANNELS & (1 << j)) == 0) + { + continue; + } + } + if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, + channels[i + j].DrRange.Fields.Max) == false) + { // Check if the current channel selection supports the given datarate + continue; + } + if (bands[channels[i + j].Band].TimeOff > 0) + { // Check if the band is available for transmission + delayTransmission++; + continue; + } + enabledChannels[nbEnabledChannels++] = i + j; + } + } + } + + *delayTx = delayTransmission; + return nbEnabledChannels; + } + + PhyParam_t RegionIN865GetPhyParam(GetPhyParams_t *getPhy) + { + PhyParam_t phyParam = {0}; + + switch (getPhy->Attribute) + { + case PHY_MIN_RX_DR: + { + phyParam.Value = IN865_RX_MIN_DATARATE; + break; + } + case PHY_MIN_TX_DR: + { + phyParam.Value = IN865_TX_MIN_DATARATE; + break; + } + case PHY_DEF_TX_DR: + { + phyParam.Value = IN865_DEFAULT_DATARATE; + break; + } + case PHY_NEXT_LOWER_TX_DR: + { + phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, IN865_TX_MIN_DATARATE); + break; + } + case PHY_DEF_TX_POWER: + { + phyParam.Value = IN865_DEFAULT_TX_POWER; + break; + } + case PHY_MAX_PAYLOAD: + { + phyParam.Value = MaxPayloadOfDatarateIN865[getPhy->Datarate]; + break; + } + case PHY_MAX_PAYLOAD_REPEATER: + { + phyParam.Value = MaxPayloadOfDatarateRepeaterIN865[getPhy->Datarate]; + break; + } + case PHY_DUTY_CYCLE: + { + phyParam.Value = IN865_DUTY_CYCLE_ENABLED; + break; + } + case PHY_MAX_RX_WINDOW: + { + phyParam.Value = IN865_MAX_RX_WINDOW; + break; + } + case PHY_RECEIVE_DELAY1: + { + phyParam.Value = IN865_RECEIVE_DELAY1; + break; + } + case PHY_RECEIVE_DELAY2: + { + phyParam.Value = IN865_RECEIVE_DELAY2; + break; + } + case PHY_JOIN_ACCEPT_DELAY1: + { + phyParam.Value = IN865_JOIN_ACCEPT_DELAY1; + break; + } + case PHY_JOIN_ACCEPT_DELAY2: + { + phyParam.Value = IN865_JOIN_ACCEPT_DELAY2; + break; + } + case PHY_MAX_FCNT_GAP: + { + phyParam.Value = IN865_MAX_FCNT_GAP; + break; + } + case PHY_ACK_TIMEOUT: + { + phyParam.Value = (IN865_ACKTIMEOUT + randr(-IN865_ACK_TIMEOUT_RND, IN865_ACK_TIMEOUT_RND)); + break; + } + case PHY_DEF_DR1_OFFSET: + { + phyParam.Value = IN865_DEFAULT_RX1_DR_OFFSET; + break; + } + case PHY_DEF_RX2_FREQUENCY: + { + phyParam.Value = IN865_RX_WND_2_FREQ; + break; + } + case PHY_DEF_RX2_DR: + { + phyParam.Value = IN865_RX_WND_2_DR; + break; + } + case PHY_CHANNELS_MASK: + { + phyParam.ChannelsMask = ChannelsMask; + break; + } + case PHY_CHANNELS_DEFAULT_MASK: + { + phyParam.ChannelsMask = ChannelsDefaultMask; + break; + } + case PHY_MAX_NB_CHANNELS: + { + phyParam.Value = IN865_MAX_NB_CHANNELS; + break; + } + case PHY_CHANNELS: + { + phyParam.Channels = Channels; + break; + } + case PHY_DEF_UPLINK_DWELL_TIME: + case PHY_DEF_DOWNLINK_DWELL_TIME: + { + phyParam.Value = 0; + break; + } + case PHY_DEF_MAX_EIRP: + { + phyParam.fValue = IN865_DEFAULT_MAX_EIRP; + break; + } + case PHY_DEF_ANTENNA_GAIN: + { + phyParam.fValue = IN865_DEFAULT_ANTENNA_GAIN; + break; + } + case PHY_NB_JOIN_TRIALS: + case PHY_DEF_NB_JOIN_TRIALS: + { + phyParam.Value = 48; + break; + } + default: + { + break; + } + } + + return phyParam; + } + + void RegionIN865SetBandTxDone(SetBandTxDoneParams_t *txDone) + { + RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); + } + + void RegionIN865InitDefaults(InitType_t type) + { + switch (type) + { + case INIT_TYPE_INIT: + { + // Channels + Channels[0] = (ChannelParams_t)IN865_LC1; + Channels[1] = (ChannelParams_t)IN865_LC2; + Channels[2] = (ChannelParams_t)IN865_LC3; + + // Initialize the channels default mask + ChannelsDefaultMask[0] = LC(1) + LC(2) + LC(3); + // Update the channels mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); + break; + } + case INIT_TYPE_RESTORE: + { + // Restore channels default mask + ChannelsMask[0] |= ChannelsDefaultMask[0]; + break; + } + case INIT_TYPE_APP_DEFAULTS: + { + // Update the channels mask defaults + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 1); + break; + } + default: + { + break; + } + } + } + + bool RegionIN865Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) + { + switch (phyAttribute) + { + case PHY_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, IN865_TX_MIN_DATARATE, IN865_TX_MAX_DATARATE); + } + case PHY_DEF_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); + } + case PHY_RX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, IN865_RX_MIN_DATARATE, IN865_RX_MAX_DATARATE); + } + case PHY_DEF_TX_POWER: + case PHY_TX_POWER: + { + // Remark: switched min and max! + return RegionCommonValueInRange(verify->TxPower, IN865_MAX_TX_POWER, IN865_MIN_TX_POWER); + } + case PHY_DUTY_CYCLE: + { + return IN865_DUTY_CYCLE_ENABLED; + } + case PHY_NB_JOIN_TRIALS: + { + if (verify->NbJoinTrials < 48) + { + return false; + } + break; + } + default: + return false; + } + return true; + } + + void RegionIN865ApplyCFList(ApplyCFListParams_t *applyCFList) + { + ChannelParams_t newChannel; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + // Setup default datarate range + newChannel.DrRange.Value = (DR_5 << 4) | DR_0; + + // Size of the optional CF list + if (applyCFList->Size != 16) + { + return; + } + + // Last byte is RFU, don't take it into account + for (uint8_t i = 0, chanIdx = IN865_NUMB_DEFAULT_CHANNELS; chanIdx < IN865_MAX_NB_CHANNELS; i += 3, chanIdx++) + { + if (chanIdx < (IN865_NUMB_CHANNELS_CF_LIST + IN865_NUMB_DEFAULT_CHANNELS)) + { + // Channel frequency + newChannel.Frequency = (uint32_t)applyCFList->Payload[i]; + newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 1] << 8); + newChannel.Frequency |= ((uint32_t)applyCFList->Payload[i + 2] << 16); + newChannel.Frequency *= 100; + + // Initialize alternative frequency to 0 + newChannel.Rx1Frequency = 0; + } + else + { + newChannel.Frequency = 0; + newChannel.DrRange.Value = 0; + newChannel.Rx1Frequency = 0; + } + + if (newChannel.Frequency != 0) + { + channelAdd.NewChannel = &newChannel; + channelAdd.ChannelId = chanIdx; + + // Try to add all channels + RegionIN865ChannelAdd(&channelAdd); + } + else + { + channelRemove.ChannelId = chanIdx; + + RegionIN865ChannelsRemove(&channelRemove); + } + } + } + + bool RegionIN865ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) + { + switch (chanMaskSet->ChannelsMaskType) + { + case CHANNELS_MASK: + { + RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 1); + break; + } + case CHANNELS_DEFAULT_MASK: + { + RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1); + break; + } + default: + return false; + } + return true; + } + + bool RegionIN865AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) + { + bool adrAckReq = false; + int8_t datarate = adrNext->Datarate; + int8_t txPower = adrNext->TxPower; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + + // Report back the adr ack counter + *adrAckCounter = adrNext->AdrAckCounter; + + if (adrNext->AdrEnabled == true) + { + if (datarate == IN865_TX_MIN_DATARATE) + { + *adrAckCounter = 0; + adrAckReq = false; + } + else + { + if (adrNext->AdrAckCounter >= IN865_ADR_ACK_LIMIT) + { + adrAckReq = true; + txPower = IN865_MAX_TX_POWER; + } + else + { + adrAckReq = false; + } + if (adrNext->AdrAckCounter >= (IN865_ADR_ACK_LIMIT + IN865_ADR_ACK_DELAY)) + { + if ((adrNext->AdrAckCounter % IN865_ADR_ACK_DELAY) == 1) + { + // Decrease the datarate + getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; + getPhy.Datarate = datarate; + getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; + phyParam = RegionIN865GetPhyParam(&getPhy); + datarate = phyParam.Value; + + if (datarate == IN865_TX_MIN_DATARATE) + { + // We must set adrAckReq to false as soon as we reach the lowest datarate + adrAckReq = false; + if (adrNext->UpdateChanMask == true) + { + // Re-enable default channels + ChannelsMask[0] |= LC(1) + LC(2) + LC(3); + } + } + } + } + } + } + + *drOut = datarate; + *txPowOut = txPower; + return adrAckReq; + } + + void RegionIN865ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) + { + double tSymbol = 0.0; + + // Get the datarate, perform a boundary check + rxConfigParams->Datarate = MIN(datarate, IN865_RX_MAX_DATARATE); + rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); + + if (rxConfigParams->Datarate == DR_7) + { // FSK + tSymbol = RegionCommonComputeSymbolTimeFsk(DataratesIN865[rxConfigParams->Datarate]); + } + else + { // LoRa + tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesIN865[rxConfigParams->Datarate], BandwidthsIN865[rxConfigParams->Datarate]); + } + + RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); + } + + bool RegionIN865RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) + { + RadioModems_t modem; + int8_t dr = rxConfig->Datarate; + uint8_t maxPayload = 0; + int8_t phyDr = 0; + uint32_t frequency = rxConfig->Frequency; + + if (Radio.GetStatus() != RF_IDLE) + { + return false; + } + + if (rxConfig->Window == 0) + { + // Apply window 1 frequency + frequency = Channels[rxConfig->Channel].Frequency; + // Apply the alternative RX 1 window frequency, if it is available + if (Channels[rxConfig->Channel].Rx1Frequency != 0) + { + frequency = Channels[rxConfig->Channel].Rx1Frequency; + } + } + + // Read the physical datarate from the datarates table + phyDr = DataratesIN865[dr]; + + Radio.SetChannel(frequency); + + // Radio configuration + if (dr == DR_7) + { + modem = MODEM_FSK; + Radio.SetRxConfig(modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous); + } + else + { + modem = MODEM_LORA; + Radio.SetRxConfig(modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); + } + + if (rxConfig->RepeaterSupport == true) + { + maxPayload = MaxPayloadOfDatarateRepeaterIN865[dr]; + } + else + { + maxPayload = MaxPayloadOfDatarateIN865[dr]; + } + Radio.SetMaxPayloadLength(modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + *datarate = (uint8_t)dr; + return true; + } + + bool RegionIN865TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) + { + RadioModems_t modem; + int8_t phyDr = DataratesIN865[txConfig->Datarate]; + int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); + uint32_t bandwidth = GetBandwidth(txConfig->Datarate); + int8_t phyTxPower = 0; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain); + + // Setup the radio frequency + Radio.SetChannel(Channels[txConfig->Channel].Frequency); + + if (txConfig->Datarate == DR_7) + { // High Speed FSK channel + modem = MODEM_FSK; + Radio.SetTxConfig(modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000); + } + else + { + modem = MODEM_LORA; + Radio.SetTxConfig(modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); + } + + // Setup maximum payload lenght of the radio driver + Radio.SetMaxPayloadLength(modem, txConfig->PktLen); + // Get the time-on-air of the next tx frame + *txTimeOnAir = Radio.TimeOnAir(modem, txConfig->PktLen); + + *txPower = txPowerLimited; + return true; + } + + uint8_t RegionIN865LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) + { + uint8_t status = 0x07; + RegionCommonLinkAdrParams_t linkAdrParams; + uint8_t nextIndex = 0; + uint8_t bytesProcessed = 0; + uint16_t chMask = 0; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; + + while (bytesProcessed < linkAdrReq->PayloadSize) + { + // Get ADR request parameters + nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); + + if (nextIndex == 0) + break; // break loop, since no more request has been found + + // Update bytes processed + bytesProcessed += nextIndex; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + // Setup temporary channels mask + chMask = linkAdrParams.ChMask; + + // Verify channels mask + if ((linkAdrParams.ChMaskCtrl == 0) && (chMask == 0)) + { + status &= 0xFE; // Channel mask KO + } + else if (((linkAdrParams.ChMaskCtrl >= 1) && (linkAdrParams.ChMaskCtrl <= 5)) || + (linkAdrParams.ChMaskCtrl >= 7)) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + for (uint8_t i = 0; i < IN865_MAX_NB_CHANNELS; i++) + { + if (linkAdrParams.ChMaskCtrl == 6) + { + if (Channels[i].Frequency != 0) + { + chMask |= 1 << i; + } + } + else + { + if (((chMask & (1 << i)) != 0) && + (Channels[i].Frequency == 0)) + { // Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + } + } + } + + // Get the minimum possible datarate + getPhy.Attribute = PHY_MIN_TX_DR; + getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; + phyParam = RegionIN865GetPhyParam(&getPhy); + + linkAdrVerifyParams.Status = status; + linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; + linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; + linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; + linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; + linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; + linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; + linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; + linkAdrVerifyParams.NbChannels = IN865_MAX_NB_CHANNELS; + linkAdrVerifyParams.ChannelsMask = &chMask; + linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; + linkAdrVerifyParams.MaxDatarate = IN865_TX_MAX_DATARATE; + linkAdrVerifyParams.Channels = Channels; + linkAdrVerifyParams.MinTxPower = IN865_MIN_TX_POWER; + linkAdrVerifyParams.MaxTxPower = IN865_MAX_TX_POWER; + + // Verify the parameters and update, if necessary + status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); + + // Update channelsMask if everything is correct + if (status == 0x07) + { + // Set the channels mask to a default value + memset(ChannelsMask, 0, sizeof(ChannelsMask)); + // Update the channels mask + ChannelsMask[0] = chMask; + } + + // Update status variables + *drOut = linkAdrParams.Datarate; + *txPowOut = linkAdrParams.TxPower; + *nbRepOut = linkAdrParams.NbRep; + *nbBytesParsed = bytesProcessed; + + return status; + } + + uint8_t RegionIN865RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) + { + uint8_t status = 0x07; + + // Verify radio frequency + if (Radio.CheckRfFrequency(rxParamSetupReq->Frequency) == false) + { + status &= 0xFE; // Channel frequency KO + } + + // Verify datarate + if (RegionCommonValueInRange(rxParamSetupReq->Datarate, IN865_RX_MIN_DATARATE, IN865_RX_MAX_DATARATE) == false) + { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, IN865_MIN_RX1_DR_OFFSET, IN865_MAX_RX1_DR_OFFSET) == false) + { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; + } + + uint8_t RegionIN865NewChannelReq(NewChannelReqParams_t *newChannelReq) + { + uint8_t status = 0x03; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + if (newChannelReq->NewChannel->Frequency == 0) + { + channelRemove.ChannelId = newChannelReq->ChannelId; + + // Remove + if (RegionIN865ChannelsRemove(&channelRemove) == false) + { + status &= 0xFC; + } + } + else + { + channelAdd.NewChannel = newChannelReq->NewChannel; + channelAdd.ChannelId = newChannelReq->ChannelId; + + switch (RegionIN865ChannelAdd(&channelAdd)) + { + case LORAMAC_STATUS_OK: + { + break; + } + case LORAMAC_STATUS_FREQUENCY_INVALID: + { + status &= 0xFE; + break; + } + case LORAMAC_STATUS_DATARATE_INVALID: + { + status &= 0xFD; + break; + } + case LORAMAC_STATUS_FREQ_AND_DR_INVALID: + { + status &= 0xFC; + break; + } + default: + { + status &= 0xFC; + break; + } + } + } + + return status; + } + + int8_t RegionIN865TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) + { + return -1; + } + + uint8_t RegionIN865DlChannelReq(DlChannelReqParams_t *dlChannelReq) + { + uint8_t status = 0x03; + uint8_t band = 0; + + // Verify if the frequency is supported + if (VerifyTxFreq(dlChannelReq->Rx1Frequency, &band) == false) + { + status &= 0xFE; + } + + // Verify if an uplink frequency exists + if (Channels[dlChannelReq->ChannelId].Frequency == 0) + { + status &= 0xFD; + } + + // Apply Rx1 frequency, if the status is OK + if (status == 0x03) + { + Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency; + } + + return status; + } + + int8_t RegionIN865AlternateDr(AlternateDrParams_t *alternateDr) + { + int8_t datarate = 0; + + if ((alternateDr->NbTrials % 48) == 0) + { + datarate = DR_0; + } + else if ((alternateDr->NbTrials % 32) == 0) + { + datarate = DR_1; + } + else if ((alternateDr->NbTrials % 24) == 0) + { + datarate = DR_2; + } + else if ((alternateDr->NbTrials % 16) == 0) + { + datarate = DR_3; + } + else if ((alternateDr->NbTrials % 8) == 0) + { + datarate = DR_4; + } + else + { + datarate = DR_5; + } + return datarate; + } + + void RegionIN865CalcBackOff(CalcBackOffParams_t *calcBackOff) + { + RegionCommonCalcBackOffParams_t calcBackOffParams; + + calcBackOffParams.Channels = Channels; + calcBackOffParams.Bands = Bands; + calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; + calcBackOffParams.Joined = calcBackOff->Joined; + calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; + calcBackOffParams.Channel = calcBackOff->Channel; + calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; + calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; + + RegionCommonCalcBackOff(&calcBackOffParams); + } + + bool RegionIN865NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTx = 0; + uint8_t enabledChannels[IN865_MAX_NB_CHANNELS] = {0}; + TimerTime_t nextTxDelay = 0; + + if (RegionCommonCountChannels(ChannelsMask, 0, 1) == 0) + { // Reactivate default channels + ChannelsMask[0] |= LC(1) + LC(2) + LC(3); + } + + if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) + { + // Reset Aggregated time off + *aggregatedTimeOff = 0; + + // Update bands Time OFF + nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, IN865_MAX_NB_BANDS); + + // Search how many channels are enabled + nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Joined, nextChanParams->Datarate, + ChannelsMask, Channels, + Bands, enabledChannels, &delayTx); + } + else + { + delayTx++; + nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); + } + + if (nbEnabledChannels > 0) + { + // We found a valid channel + *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; + + *time = 0; + return true; + } + else + { + if (delayTx > 0) + { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return true; + } + // Datarate not supported by any channel, restore defaults + ChannelsMask[0] |= LC(1) + LC(2) + LC(3); + *time = 0; + return false; + } + } + + LoRaMacStatus_t RegionIN865ChannelAdd(ChannelAddParams_t *channelAdd) + { + uint8_t band = 0; + bool drInvalid = false; + bool freqInvalid = false; + uint8_t id = channelAdd->ChannelId; + + if (id >= IN865_MAX_NB_CHANNELS) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + // Validate the datarate range + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Min, IN865_TX_MIN_DATARATE, IN865_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, IN865_TX_MIN_DATARATE, IN865_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + if (channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max) + { + drInvalid = true; + } + + // Default channels don't accept all values + if (id < IN865_NUMB_DEFAULT_CHANNELS) + { + // Validate the datarate range for min: must be DR_0 + if (channelAdd->NewChannel->DrRange.Fields.Min > DR_0) + { + drInvalid = true; + } + // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE + if (RegionCommonValueInRange(channelAdd->NewChannel->DrRange.Fields.Max, DR_5, IN865_TX_MAX_DATARATE) == false) + { + drInvalid = true; + } + // We are not allowed to change the frequency + if (channelAdd->NewChannel->Frequency != Channels[id].Frequency) + { + freqInvalid = true; + } + } + + // Check frequency + if (freqInvalid == false) + { + if (VerifyTxFreq(channelAdd->NewChannel->Frequency, &band) == false) + { + freqInvalid = true; + } + } + + // Check status + if ((drInvalid == true) && (freqInvalid == true)) + { + return LORAMAC_STATUS_FREQ_AND_DR_INVALID; + } + if (drInvalid == true) + { + return LORAMAC_STATUS_DATARATE_INVALID; + } + if (freqInvalid == true) + { + return LORAMAC_STATUS_FREQUENCY_INVALID; + } + + memcpy(&(Channels[id]), channelAdd->NewChannel, sizeof(Channels[id])); + Channels[id].Band = band; + ChannelsMask[0] |= (1 << id); + return LORAMAC_STATUS_OK; + } + + bool RegionIN865ChannelsRemove(ChannelRemoveParams_t *channelRemove) + { + uint8_t id = channelRemove->ChannelId; + + if (id < IN865_NUMB_DEFAULT_CHANNELS) + { + return false; + } + + // Remove the channel from the list of channels + Channels[id] = (ChannelParams_t){0, 0, {0}, 0}; + + return RegionCommonChanDisable(ChannelsMask, id, IN865_MAX_NB_CHANNELS); + } + + void RegionIN865SetContinuousWave(ContinuousWaveParams_t *continuousWave) + { + int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); + int8_t phyTxPower = 0; + uint32_t frequency = Channels[continuousWave->Channel].Frequency; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain); + + Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); + } + + uint8_t RegionIN865ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) + { + // Apply offset formula + return MIN(DR_5, MAX(DR_0, dr - EffectiveRx1DrOffsetIN865[drOffset])); + } }; \ No newline at end of file diff --git a/src/mac/region/RegionIN865.h b/src/mac/region/RegionIN865.h index 81cb689..974ede2 100644 --- a/src/mac/region/RegionIN865.h +++ b/src/mac/region/RegionIN865.h @@ -41,235 +41,247 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define IN865_MAX_NB_CHANNELS 16 +#define IN865_MAX_NB_CHANNELS 16 /*! * Number of default channels */ -#define IN865_NUMB_DEFAULT_CHANNELS 3 +#define IN865_NUMB_DEFAULT_CHANNELS 3 /*! * Number of channels to apply for the CF list */ -#define IN865_NUMB_CHANNELS_CF_LIST 5 +#define IN865_NUMB_CHANNELS_CF_LIST 5 /*! * Minimal datarate that can be used by the node */ -#define IN865_TX_MIN_DATARATE DR_0 +#define IN865_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define IN865_TX_MAX_DATARATE DR_7 +#define IN865_TX_MAX_DATARATE DR_7 /*! * Minimal datarate that can be used by the node */ -#define IN865_RX_MIN_DATARATE DR_0 +#define IN865_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define IN865_RX_MAX_DATARATE DR_7 +#define IN865_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node */ -#define IN865_DEFAULT_DATARATE DR_0 +#define IN865_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define IN865_MIN_RX1_DR_OFFSET 0 +#define IN865_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define IN865_MAX_RX1_DR_OFFSET 7 +#define IN865_MAX_RX1_DR_OFFSET 7 /*! * Default Rx1 receive datarate offset */ -#define IN865_DEFAULT_RX1_DR_OFFSET 0 +#define IN865_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define IN865_MIN_TX_POWER TX_POWER_10 +#define IN865_MIN_TX_POWER TX_POWER_10 /*! * Maximal Tx output power that can be used by the node */ -#define IN865_MAX_TX_POWER TX_POWER_0 +#define IN865_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define IN865_DEFAULT_TX_POWER TX_POWER_0 +#define IN865_DEFAULT_TX_POWER TX_POWER_0 /*! * Default Max EIRP */ -#define IN865_DEFAULT_MAX_EIRP 30.0f +#define IN865_DEFAULT_MAX_EIRP 30.0f /*! * Default antenna gain */ -#define IN865_DEFAULT_ANTENNA_GAIN 2.15f +#define IN865_DEFAULT_ANTENNA_GAIN 2.15f /*! * ADR Ack limit */ -#define IN865_ADR_ACK_LIMIT 64 +#define IN865_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define IN865_ADR_ACK_DELAY 32 +#define IN865_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define IN865_DUTY_CYCLE_ENABLED 1 +#define IN865_DUTY_CYCLE_ENABLED 1 /*! * Maximum RX window duration */ -#define IN865_MAX_RX_WINDOW 3000 +#define IN865_MAX_RX_WINDOW 3000 /*! * Receive delay 1 */ -#define IN865_RECEIVE_DELAY1 1000 +#define IN865_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define IN865_RECEIVE_DELAY2 2000 +#define IN865_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define IN865_JOIN_ACCEPT_DELAY1 5000 +#define IN865_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define IN865_JOIN_ACCEPT_DELAY2 6000 +#define IN865_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define IN865_MAX_FCNT_GAP 16384 +#define IN865_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define IN865_ACKTIMEOUT 2000 +#define IN865_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define IN865_ACK_TIMEOUT_RND 1000 +#define IN865_ACK_TIMEOUT_RND 1000 -#if ( IN865_DEFAULT_DATARATE > DR_5 ) +#if (IN865_DEFAULT_DATARATE > DR_5) #error "A default DR higher than DR_5 may lead to connectivity loss." #endif /*! * Second reception window channel frequency definition. */ -#define IN865_RX_WND_2_FREQ 866550000 +#define IN865_RX_WND_2_FREQ 866550000 /*! * Second reception window channel datarate definition. */ -#define IN865_RX_WND_2_DR DR_2 +#define IN865_RX_WND_2_DR DR_2 /*! * Maximum number of bands */ -#define IN865_MAX_NB_BANDS 1 +#define IN865_MAX_NB_BANDS 1 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define IN865_BAND0 { 1 , IN865_MAX_TX_POWER, 0, 0 } // 100.0 % +#define IN865_BAND0 \ + { \ + 1, IN865_MAX_TX_POWER, 0, 0 \ + } // 100.0 % /*! * LoRaMac default channel 1 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define IN865_LC1 { 865062500, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define IN865_LC1 \ + { \ + 865062500, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac default channel 2 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define IN865_LC2 { 865402500, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define IN865_LC2 \ + { \ + 865402500, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac default channel 3 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define IN865_LC3 { 865985000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define IN865_LC3 \ + { \ + 865985000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac channels which are allowed for the join procedure */ -#define IN865_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) +#define IN865_JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesIN865[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; + static const uint8_t DataratesIN865[] = {12, 11, 10, 9, 8, 7, 7, 50}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsIN865[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 }; + static const uint32_t BandwidthsIN865[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; -/*! + /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateIN865[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; + static const uint8_t MaxPayloadOfDatarateIN865[] = {51, 51, 51, 115, 242, 242, 242, 242}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateRepeaterIN865[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; + static const uint8_t MaxPayloadOfDatarateRepeaterIN865[] = {51, 51, 51, 115, 222, 222, 222, 222}; -/*! + /*! * Effective datarate offsets for receive window 1. */ -static const int8_t EffectiveRx1DrOffsetIN865[] = { 0, 1, 2, 3, 4, 5, -1, -2 }; + static const int8_t EffectiveRx1DrOffsetIN865[] = {0, 1, 2, 3, 4, 5, -1, -2}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionIN865GetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionIN865GetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionIN865SetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionIN865SetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionIN865InitDefaults( InitType_t type ); + void RegionIN865InitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -278,26 +290,26 @@ void RegionIN865InitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionIN865Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionIN865Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionIN865ApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionIN865ApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionIN865ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionIN865ChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -310,9 +322,9 @@ bool RegionIN865ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionIN865AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionIN865AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -325,9 +337,9 @@ bool RegionIN865AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowO * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionIN865ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionIN865ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -336,9 +348,9 @@ void RegionIN865ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionIN865RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionIN865RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -349,36 +361,36 @@ bool RegionIN865RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionIN865TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionIN865TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionIN865LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionIN865LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionIN865RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionIN865RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionIN865NewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionIN865NewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -387,34 +399,34 @@ uint8_t RegionIN865NewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionIN865TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionIN865TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionIN865DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionIN865DlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionIN865AlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionIN865AlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionIN865CalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionIN865CalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -426,34 +438,34 @@ void RegionIN865CalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionIN865NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionIN865NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionIN865ChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionIN865ChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionIN865ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionIN865ChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionIN865SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionIN865SetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -464,8 +476,8 @@ void RegionIN865SetContinuousWave( ContinuousWaveParams_t* continuousWave ); * * \retval newDr Computed datarate. */ -uint8_t RegionIN865ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionIN865ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONIN865 */ + /*! \} defgroup REGIONIN865 */ }; #endif // __REGION_IN865_H__ diff --git a/src/mac/region/RegionKR920.h b/src/mac/region/RegionKR920.h index 9cee0e2..498c80b 100644 --- a/src/mac/region/RegionKR920.h +++ b/src/mac/region/RegionKR920.h @@ -41,245 +41,257 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define KR920_MAX_NB_CHANNELS 16 +#define KR920_MAX_NB_CHANNELS 16 /*! * Number of default channels */ -#define KR920_NUMB_DEFAULT_CHANNELS 3 +#define KR920_NUMB_DEFAULT_CHANNELS 3 /*! * Number of channels to apply for the CF list */ -#define KR920_NUMB_CHANNELS_CF_LIST 5 +#define KR920_NUMB_CHANNELS_CF_LIST 5 /*! * Minimal datarate that can be used by the node */ -#define KR920_TX_MIN_DATARATE DR_0 +#define KR920_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define KR920_TX_MAX_DATARATE DR_5 +#define KR920_TX_MAX_DATARATE DR_5 /*! * Minimal datarate that can be used by the node */ -#define KR920_RX_MIN_DATARATE DR_0 +#define KR920_RX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define KR920_RX_MAX_DATARATE DR_5 +#define KR920_RX_MAX_DATARATE DR_5 /*! * Default datarate used by the node */ -#define KR920_DEFAULT_DATARATE DR_0 +#define KR920_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define KR920_MIN_RX1_DR_OFFSET 0 +#define KR920_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define KR920_MAX_RX1_DR_OFFSET 5 +#define KR920_MAX_RX1_DR_OFFSET 5 /*! * Default Rx1 receive datarate offset */ -#define KR920_DEFAULT_RX1_DR_OFFSET 0 +#define KR920_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define KR920_MIN_TX_POWER TX_POWER_7 +#define KR920_MIN_TX_POWER TX_POWER_7 /*! * Maximal Tx output power that can be used by the node */ -#define KR920_MAX_TX_POWER TX_POWER_0 +#define KR920_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define KR920_DEFAULT_TX_POWER TX_POWER_0 +#define KR920_DEFAULT_TX_POWER TX_POWER_0 /*! * Default Max EIRP for frequency 920.9 MHz - 921.9 MHz */ -#define KR920_DEFAULT_MAX_EIRP_LOW 10.0f +#define KR920_DEFAULT_MAX_EIRP_LOW 10.0f /*! * Default Max EIRP for frequency 922.1 MHz - 923.3 MHz */ -#define KR920_DEFAULT_MAX_EIRP_HIGH 14.0f +#define KR920_DEFAULT_MAX_EIRP_HIGH 14.0f /*! * Default antenna gain */ -#define KR920_DEFAULT_ANTENNA_GAIN 2.15f +#define KR920_DEFAULT_ANTENNA_GAIN 2.15f /*! * ADR Ack limit */ -#define KR920_ADR_ACK_LIMIT 64 +#define KR920_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define KR920_ADR_ACK_DELAY 32 +#define KR920_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define KR920_DUTY_CYCLE_ENABLED 0 +#define KR920_DUTY_CYCLE_ENABLED 0 /*! * Maximum RX window duration */ -#define KR920_MAX_RX_WINDOW 4000 +#define KR920_MAX_RX_WINDOW 4000 /*! * Receive delay 1 */ -#define KR920_RECEIVE_DELAY1 1000 +#define KR920_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define KR920_RECEIVE_DELAY2 2000 +#define KR920_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define KR920_JOIN_ACCEPT_DELAY1 5000 +#define KR920_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define KR920_JOIN_ACCEPT_DELAY2 6000 +#define KR920_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define KR920_MAX_FCNT_GAP 16384 +#define KR920_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define KR920_ACKTIMEOUT 2000 +#define KR920_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define KR920_ACK_TIMEOUT_RND 1000 +#define KR920_ACK_TIMEOUT_RND 1000 -#if ( KR920_DEFAULT_DATARATE > DR_5 ) +#if (KR920_DEFAULT_DATARATE > DR_5) #error "A default DR higher than DR_5 may lead to connectivity loss." #endif /*! * Second reception window channel frequency definition. */ -#define KR920_RX_WND_2_FREQ 921900000 +#define KR920_RX_WND_2_FREQ 921900000 /*! * Second reception window channel datarate definition. */ -#define KR920_RX_WND_2_DR DR_0 +#define KR920_RX_WND_2_DR DR_0 /*! * Maximum number of bands */ -#define KR920_MAX_NB_BANDS 1 +#define KR920_MAX_NB_BANDS 1 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define KR920_BAND0 { 1 , KR920_MAX_TX_POWER, 0, 0 } // 100.0 % +#define KR920_BAND0 \ + { \ + 1, KR920_MAX_TX_POWER, 0, 0 \ + } // 100.0 % /*! * LoRaMac default channel 1 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define KR920_LC1 { 922100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define KR920_LC1 \ + { \ + 922100000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac default channel 2 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define KR920_LC2 { 922300000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define KR920_LC2 \ + { \ + 922300000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac default channel 3 * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } */ -#define KR920_LC3 { 922500000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define KR920_LC3 \ + { \ + 922500000, 0, {((DR_5 << 4) | DR_0)}, 0 \ + } /*! * LoRaMac channels which are allowed for the join procedure */ -#define KR920_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) +#define KR920_JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) /*! * RSSI threshold for a free channel [dBm] */ -#define KR920_RSSI_FREE_TH -65 +#define KR920_RSSI_FREE_TH -65 /*! * Specifies the time the node performs a carrier sense */ -#define KR920_CARRIER_SENSE_TIME 6 +#define KR920_CARRIER_SENSE_TIME 6 -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesKR920[] = { 12, 11, 10, 9, 8, 7 }; + static const uint8_t DataratesKR920[] = {12, 11, 10, 9, 8, 7}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsKR920[] = { 125000, 125000, 125000, 125000, 125000, 125000 }; + static const uint32_t BandwidthsKR920[] = {125000, 125000, 125000, 125000, 125000, 125000}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with and without a repeater. */ -static const uint8_t MaxPayloadOfDatarateKR920[] = { 51, 51, 51, 115, 242, 242 }; + static const uint8_t MaxPayloadOfDatarateKR920[] = {51, 51, 51, 115, 242, 242}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateRepeaterKR920[] = { 51, 51, 51, 115, 222, 222 }; + static const uint8_t MaxPayloadOfDatarateRepeaterKR920[] = {51, 51, 51, 115, 222, 222}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionKR920GetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionKR920GetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionKR920SetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionKR920SetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionKR920InitDefaults( InitType_t type ); + void RegionKR920InitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -288,26 +300,26 @@ void RegionKR920InitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionKR920Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionKR920Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionKR920ApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionKR920ApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionKR920ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionKR920ChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -320,9 +332,9 @@ bool RegionKR920ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionKR920AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionKR920AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -335,9 +347,9 @@ bool RegionKR920AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowO * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionKR920ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionKR920ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -346,9 +358,9 @@ void RegionKR920ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionKR920RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionKR920RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -359,36 +371,36 @@ bool RegionKR920RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionKR920TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionKR920TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionKR920LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionKR920LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionKR920RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionKR920RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionKR920NewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionKR920NewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -397,34 +409,34 @@ uint8_t RegionKR920NewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionKR920TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionKR920TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionKR920DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionKR920DlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionKR920AlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionKR920AlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionKR920CalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionKR920CalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -436,34 +448,34 @@ void RegionKR920CalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionKR920NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionKR920NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionKR920ChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionKR920ChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionKR920ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionKR920ChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionKR920SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionKR920SetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -474,8 +486,8 @@ void RegionKR920SetContinuousWave( ContinuousWaveParams_t* continuousWave ); * * \retval newDr Computed datarate. */ -uint8_t RegionKR920ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionKR920ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONKR920 */ + /*! \} defgroup REGIONKR920 */ }; #endif // __REGION_KR920_H__ diff --git a/src/mac/region/RegionUS915-Hybrid.h b/src/mac/region/RegionUS915-Hybrid.h index a9d5e3a..a0a4768 100644 --- a/src/mac/region/RegionUS915-Hybrid.h +++ b/src/mac/region/RegionUS915-Hybrid.h @@ -41,215 +41,218 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define US915_HYBRID_MAX_NB_CHANNELS 72 +#define US915_HYBRID_MAX_NB_CHANNELS 72 /*! * Minimal datarate that can be used by the node */ -#define US915_HYBRID_TX_MIN_DATARATE DR_0 +#define US915_HYBRID_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define US915_HYBRID_TX_MAX_DATARATE DR_4 +#define US915_HYBRID_TX_MAX_DATARATE DR_4 /*! * Minimal datarate that can be used by the node */ -#define US915_HYBRID_RX_MIN_DATARATE DR_8 +#define US915_HYBRID_RX_MIN_DATARATE DR_8 /*! * Maximal datarate that can be used by the node */ -#define US915_HYBRID_RX_MAX_DATARATE DR_13 +#define US915_HYBRID_RX_MAX_DATARATE DR_13 /*! * Default datarate used by the node */ -#define US915_HYBRID_DEFAULT_DATARATE DR_0 +#define US915_HYBRID_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define US915_HYBRID_MIN_RX1_DR_OFFSET 0 +#define US915_HYBRID_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define US915_HYBRID_MAX_RX1_DR_OFFSET 3 +#define US915_HYBRID_MAX_RX1_DR_OFFSET 3 /*! * Default Rx1 receive datarate offset */ -#define US915_HYBRID_DEFAULT_RX1_DR_OFFSET 0 +#define US915_HYBRID_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define US915_HYBRID_MIN_TX_POWER TX_POWER_10 +#define US915_HYBRID_MIN_TX_POWER TX_POWER_10 /*! * Maximal Tx output power that can be used by the node */ -#define US915_HYBRID_MAX_TX_POWER TX_POWER_0 +#define US915_HYBRID_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define US915_HYBRID_DEFAULT_TX_POWER TX_POWER_0 +#define US915_HYBRID_DEFAULT_TX_POWER TX_POWER_0 /*! * Default Max ERP */ -#define US915_HYBRID_DEFAULT_MAX_ERP 30.0f +#define US915_HYBRID_DEFAULT_MAX_ERP 30.0f /*! * ADR Ack limit */ -#define US915_HYBRID_ADR_ACK_LIMIT 64 +#define US915_HYBRID_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define US915_HYBRID_ADR_ACK_DELAY 32 +#define US915_HYBRID_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define US915_HYBRID_DUTY_CYCLE_ENABLED 0 +#define US915_HYBRID_DUTY_CYCLE_ENABLED 0 /*! * Maximum RX window duration */ -#define US915_HYBRID_MAX_RX_WINDOW 3000 +#define US915_HYBRID_MAX_RX_WINDOW 3000 /*! * Receive delay 1 */ -#define US915_HYBRID_RECEIVE_DELAY1 1000 +#define US915_HYBRID_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define US915_HYBRID_RECEIVE_DELAY2 2000 +#define US915_HYBRID_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define US915_HYBRID_JOIN_ACCEPT_DELAY1 5000 +#define US915_HYBRID_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define US915_HYBRID_JOIN_ACCEPT_DELAY2 6000 +#define US915_HYBRID_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define US915_HYBRID_MAX_FCNT_GAP 16384 +#define US915_HYBRID_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define US915_HYBRID_ACKTIMEOUT 2000 +#define US915_HYBRID_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define US915_HYBRID_ACK_TIMEOUT_RND 1000 +#define US915_HYBRID_ACK_TIMEOUT_RND 1000 /*! * Second reception window channel frequency definition. */ -#define US915_HYBRID_RX_WND_2_FREQ 923300000 +#define US915_HYBRID_RX_WND_2_FREQ 923300000 /*! * Second reception window channel datarate definition. */ -#define US915_HYBRID_RX_WND_2_DR DR_8 +#define US915_HYBRID_RX_WND_2_DR DR_8 /*! * LoRaMac maximum number of bands */ -#define US915_HYBRID_MAX_NB_BANDS 1 +#define US915_HYBRID_MAX_NB_BANDS 1 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define US915_HYBRID_BAND0 { 1, US915_HYBRID_MAX_TX_POWER, 0, 0 } // 100.0 % +#define US915_HYBRID_BAND0 \ + { \ + 1, US915_HYBRID_MAX_TX_POWER, 0, 0 \ + } // 100.0 % /*! * Defines the first channel for RX window 1 for US band */ -#define US915_HYBRID_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 ) +#define US915_HYBRID_FIRST_RX1_CHANNEL ((uint32_t)923300000) /*! * Defines the last channel for RX window 1 for US band */ -#define US915_HYBRID_LAST_RX1_CHANNEL ( (uint32_t) 927500000 ) +#define US915_HYBRID_LAST_RX1_CHANNEL ((uint32_t)927500000) /*! * Defines the step width of the channels for RX window 1 */ -#define US915_HYBRID_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 ) +#define US915_HYBRID_STEPWIDTH_RX1_CHANNEL ((uint32_t)600000) -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesUS915_HYBRID[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 }; + static const uint8_t DataratesUS915_HYBRID[] = {10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsUS915_HYBRID[] = { 125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 }; + static const uint32_t BandwidthsUS915_HYBRID[] = {125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0}; -/*! + /*! * Up/Down link data rates offset definition */ -static const int8_t DatarateOffsetsUS915_HYBRID[5][4] = -{ - { DR_10, DR_9 , DR_8 , DR_8 }, // DR_0 - { DR_11, DR_10, DR_9 , DR_8 }, // DR_1 - { DR_12, DR_11, DR_10, DR_9 }, // DR_2 - { DR_13, DR_12, DR_11, DR_10 }, // DR_3 - { DR_13, DR_13, DR_12, DR_11 }, // DR_4 -}; + static const int8_t DatarateOffsetsUS915_HYBRID[5][4] = + { + {DR_10, DR_9, DR_8, DR_8}, // DR_0 + {DR_11, DR_10, DR_9, DR_8}, // DR_1 + {DR_12, DR_11, DR_10, DR_9}, // DR_2 + {DR_13, DR_12, DR_11, DR_10}, // DR_3 + {DR_13, DR_13, DR_12, DR_11}, // DR_4 + }; -/*! + /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateUS915_HYBRID[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 }; + static const uint8_t MaxPayloadOfDatarateUS915_HYBRID[] = {11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateRepeaterUS915_HYBRID[] = { 11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0 }; + static const uint8_t MaxPayloadOfDatarateRepeaterUS915_HYBRID[] = {11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionUS915HybridGetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionUS915HybridGetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionUS915HybridSetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionUS915HybridSetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionUS915HybridInitDefaults( InitType_t type ); + void RegionUS915HybridInitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -258,26 +261,26 @@ void RegionUS915HybridInitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionUS915HybridVerify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionUS915HybridVerify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionUS915HybridApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionUS915HybridApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionUS915HybridChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionUS915HybridChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -290,9 +293,9 @@ bool RegionUS915HybridChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionUS915HybridAdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionUS915HybridAdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -305,9 +308,9 @@ bool RegionUS915HybridAdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionUS915HybridComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionUS915HybridComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -316,9 +319,9 @@ void RegionUS915HybridComputeRxWindowParameters( int8_t datarate, uint8_t minRxS * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionUS915HybridRxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionUS915HybridRxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -329,36 +332,36 @@ bool RegionUS915HybridRxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionUS915HybridTxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionUS915HybridTxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionUS915HybridLinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionUS915HybridLinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionUS915HybridRxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionUS915HybridRxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionUS915HybridNewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionUS915HybridNewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -367,34 +370,34 @@ uint8_t RegionUS915HybridNewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionUS915HybridTxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionUS915HybridTxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionUS915HybridDlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionUS915HybridDlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionUS915HybridAlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionUS915HybridAlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionUS915HybridCalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionUS915HybridCalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -406,34 +409,34 @@ void RegionUS915HybridCalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionUS915HybridNextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionUS915HybridNextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionUS915HybridChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionUS915HybridChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionUS915HybridChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionUS915HybridChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionUS915HybridSetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionUS915HybridSetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -444,8 +447,8 @@ void RegionUS915HybridSetContinuousWave( ContinuousWaveParams_t* continuousWave * * \retval newDr Computed datarate. */ -uint8_t RegionUS915HybridApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionUS915HybridApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONUS915HYB */ + /*! \} defgroup REGIONUS915HYB */ }; #endif // __REGION_US915_HYBRID_H__ diff --git a/src/mac/region/RegionUS915.cpp b/src/mac/region/RegionUS915.cpp index 73d1607..d1cc1c0 100644 --- a/src/mac/region/RegionUS915.cpp +++ b/src/mac/region/RegionUS915.cpp @@ -37,840 +37,840 @@ extern "C" // Definitions #define CHANNELS_MASK_SIZE 6 - // Global attributes - /*! + // Global attributes + /*! * LoRaMAC channels */ - static ChannelParams_t Channels[US915_MAX_NB_CHANNELS]; + static ChannelParams_t Channels[US915_MAX_NB_CHANNELS]; - /*! + /*! * LoRaMac bands */ - static Band_t Bands[US915_MAX_NB_BANDS] = - { - US915_BAND0}; + static Band_t Bands[US915_MAX_NB_BANDS] = + { + US915_BAND0}; - /*! + /*! * LoRaMac channels mask */ - static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; + static uint16_t ChannelsMask[CHANNELS_MASK_SIZE]; - /*! + /*! * LoRaMac channels remaining */ - static uint16_t ChannelsMaskRemaining[CHANNELS_MASK_SIZE]; + static uint16_t ChannelsMaskRemaining[CHANNELS_MASK_SIZE]; - /*! + /*! * LoRaMac channels default mask */ - static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; - - // Static functions - static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) - { - uint8_t nextLowerDr = 0; - - if (dr == minDr) - { - nextLowerDr = minDr; - } - else - { - nextLowerDr = dr - 1; - } - return nextLowerDr; - } - - static uint32_t GetBandwidth(uint32_t drIndex) - { - switch (BandwidthsUS915[drIndex]) - { - default: - case 125000: - return 0; - case 250000: - return 1; - case 500000: - return 2; - } - } - - static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) - { - int8_t txPowerResult = txPower; - - // Limit tx power to the band max - txPowerResult = MAX(txPower, maxBandTxPower); - - if (datarate == DR_4) - { // Limit tx power to max 26dBm - txPowerResult = MAX(txPower, TX_POWER_2); - } - else - { - if (RegionCommonCountChannels(channelsMask, 0, 4) < 50) - { // Limit tx power to max 21dBm - txPowerResult = MAX(txPower, TX_POWER_5); - } - } - return txPowerResult; - } - - static uint8_t CountNbOfEnabledChannels(uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTransmission = 0; - - for (uint8_t i = 0, k = 0; i < US915_MAX_NB_CHANNELS; i += 16, k++) - { - for (uint8_t j = 0; j < 16; j++) - { - if ((channelsMask[k] & (1 << j)) != 0) - { - if (channels[i + j].Frequency == 0) - { // Check if the channel is enabled - continue; - } - if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, - channels[i + j].DrRange.Fields.Max) == false) - { // Check if the current channel selection supports the given datarate - continue; - } - if (bands[channels[i + j].Band].TimeOff > 0) - { // Check if the band is available for transmission - delayTransmission++; - continue; - } - enabledChannels[nbEnabledChannels++] = i + j; - } - } - } - - *delayTx = delayTransmission; - return nbEnabledChannels; - } - - PhyParam_t RegionUS915GetPhyParam(GetPhyParams_t *getPhy) - { - PhyParam_t phyParam = {0}; - - switch (getPhy->Attribute) - { - case PHY_MIN_RX_DR: - { - phyParam.Value = US915_RX_MIN_DATARATE; - break; - } - case PHY_MIN_TX_DR: - { - phyParam.Value = US915_TX_MIN_DATARATE; - break; - } - case PHY_DEF_TX_DR: - { - phyParam.Value = US915_DEFAULT_DATARATE; - break; - } - case PHY_NEXT_LOWER_TX_DR: - { - phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, US915_TX_MIN_DATARATE); - break; - } - case PHY_DEF_TX_POWER: - { - phyParam.Value = US915_DEFAULT_TX_POWER; - break; - } - case PHY_MAX_PAYLOAD: - { - phyParam.Value = MaxPayloadOfDatarateUS915[getPhy->Datarate]; - break; - } - case PHY_MAX_PAYLOAD_REPEATER: - { - phyParam.Value = MaxPayloadOfDatarateRepeaterUS915[getPhy->Datarate]; - break; - } - case PHY_DUTY_CYCLE: - { - phyParam.Value = US915_DUTY_CYCLE_ENABLED; - break; - } - case PHY_MAX_RX_WINDOW: - { - phyParam.Value = US915_MAX_RX_WINDOW; - break; - } - case PHY_RECEIVE_DELAY1: - { - phyParam.Value = US915_RECEIVE_DELAY1; - break; - } - case PHY_RECEIVE_DELAY2: - { - phyParam.Value = US915_RECEIVE_DELAY2; - break; - } - case PHY_JOIN_ACCEPT_DELAY1: - { - phyParam.Value = US915_JOIN_ACCEPT_DELAY1; - break; - } - case PHY_JOIN_ACCEPT_DELAY2: - { - phyParam.Value = US915_JOIN_ACCEPT_DELAY2; - break; - } - case PHY_MAX_FCNT_GAP: - { - phyParam.Value = US915_MAX_FCNT_GAP; - break; - } - case PHY_ACK_TIMEOUT: - { - phyParam.Value = (US915_ACKTIMEOUT + randr(-US915_ACK_TIMEOUT_RND, US915_ACK_TIMEOUT_RND)); - break; - } - case PHY_DEF_DR1_OFFSET: - { - phyParam.Value = US915_DEFAULT_RX1_DR_OFFSET; - break; - } - case PHY_DEF_RX2_FREQUENCY: - { - phyParam.Value = US915_RX_WND_2_FREQ; - break; - } - case PHY_DEF_RX2_DR: - { - phyParam.Value = US915_RX_WND_2_DR; - break; - } - case PHY_CHANNELS_MASK: - { - phyParam.ChannelsMask = ChannelsMask; - break; - } - case PHY_CHANNELS_DEFAULT_MASK: - { - phyParam.ChannelsMask = ChannelsDefaultMask; - break; - } - case PHY_MAX_NB_CHANNELS: - { - phyParam.Value = US915_MAX_NB_CHANNELS; - break; - } - case PHY_CHANNELS: - { - phyParam.Channels = Channels; - break; - } - case PHY_DEF_UPLINK_DWELL_TIME: - case PHY_DEF_DOWNLINK_DWELL_TIME: - { - phyParam.Value = 0; - break; - } - case PHY_DEF_MAX_EIRP: - case PHY_DEF_ANTENNA_GAIN: - { - phyParam.fValue = 0; - break; - } - case PHY_NB_JOIN_TRIALS: - case PHY_DEF_NB_JOIN_TRIALS: - { - phyParam.Value = 2; - break; - } - default: - { - break; - } - } - - return phyParam; - } - - void RegionUS915SetBandTxDone(SetBandTxDoneParams_t *txDone) - { - RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); - } - - void RegionUS915InitDefaults(InitType_t type) - { - switch (type) - { - case INIT_TYPE_INIT: - { - // Channels - // 125 kHz channels - for (uint8_t i = 0; i < US915_MAX_NB_CHANNELS - 8; i++) - { - Channels[i].Frequency = 902300000 + i * 200000; - Channels[i].DrRange.Value = (DR_3 << 4) | DR_0; - Channels[i].Band = 0; - } - // 500 kHz channels - for (uint8_t i = US915_MAX_NB_CHANNELS - 8; i < US915_MAX_NB_CHANNELS; i++) - { - Channels[i].Frequency = 903000000 + (i - (US915_MAX_NB_CHANNELS - 8)) * 1600000; - Channels[i].DrRange.Value = (DR_4 << 4) | DR_4; - Channels[i].Band = 0; - } - - // ChannelsMask - ChannelsDefaultMask[0] = 0xFFFF; - ChannelsDefaultMask[1] = 0xFFFF; - ChannelsDefaultMask[2] = 0xFFFF; - ChannelsDefaultMask[3] = 0xFFFF; - ChannelsDefaultMask[4] = 0x00FF; - ChannelsDefaultMask[5] = 0x0000; - - // Copy channels default mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); - - // Copy into channels mask remaining - RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 6); - break; - } - case INIT_TYPE_RESTORE: - { - // Copy channels default mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); - - for (uint8_t i = 0; i < 6; i++) - { // Copy-And the channels mask - ChannelsMaskRemaining[i] &= ChannelsMask[i]; - } - break; - } - case INIT_TYPE_APP_DEFAULTS: - { - // Copy channels default mask - RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); - - // Copy into channels mask remaining - RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 6); - break; - } - default: - { - break; - } - } - } - - bool RegionUS915Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) - { - switch (phyAttribute) - { - case PHY_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, US915_TX_MIN_DATARATE, US915_TX_MAX_DATARATE); - } - case PHY_DEF_TX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); - } - case PHY_RX_DR: - { - return RegionCommonValueInRange(verify->DatarateParams.Datarate, US915_RX_MIN_DATARATE, US915_RX_MAX_DATARATE); - } - case PHY_DEF_TX_POWER: - case PHY_TX_POWER: - { - // Remark: switched min and max! - return RegionCommonValueInRange(verify->TxPower, US915_MAX_TX_POWER, US915_MIN_TX_POWER); - } - case PHY_DUTY_CYCLE: - { - return US915_DUTY_CYCLE_ENABLED; - } - case PHY_NB_JOIN_TRIALS: - { - if (verify->NbJoinTrials < 2) - { - return false; - } - break; - } - default: - return false; - } - return true; - } - - void RegionUS915ApplyCFList(ApplyCFListParams_t *applyCFList) - { - return; - } - - bool RegionUS915ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) - { - uint8_t nbChannels = RegionCommonCountChannels(chanMaskSet->ChannelsMaskIn, 0, 4); - - // Check the number of active channels - if ((nbChannels < 2) && - (nbChannels > 0)) - { - return false; - } - - switch (chanMaskSet->ChannelsMaskType) - { - case CHANNELS_MASK: - { - RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 6); - - for (uint8_t i = 0; i < 6; i++) - { // Copy-And the channels mask - ChannelsMaskRemaining[i] &= ChannelsMask[i]; - } - break; - } - case CHANNELS_DEFAULT_MASK: - { - RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6); - break; - } - default: - return false; - } - return true; - } - - bool RegionUS915AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) - { - bool adrAckReq = false; - int8_t datarate = adrNext->Datarate; - int8_t txPower = adrNext->TxPower; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - - // Report back the adr ack counter - *adrAckCounter = adrNext->AdrAckCounter; - - if (adrNext->AdrEnabled == true) - { - if (datarate == US915_TX_MIN_DATARATE) - { - *adrAckCounter = 0; - adrAckReq = false; - } - else - { - if (adrNext->AdrAckCounter >= US915_ADR_ACK_LIMIT) - { - adrAckReq = true; - txPower = US915_MAX_TX_POWER; - } - else - { - adrAckReq = false; - } - if (adrNext->AdrAckCounter >= (US915_ADR_ACK_LIMIT + US915_ADR_ACK_DELAY)) - { - if ((adrNext->AdrAckCounter % US915_ADR_ACK_DELAY) == 1) - { - // Decrease the datarate - getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; - getPhy.Datarate = datarate; - getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; - phyParam = RegionUS915GetPhyParam(&getPhy); - datarate = phyParam.Value; - - if (datarate == US915_TX_MIN_DATARATE) - { - // We must set adrAckReq to false as soon as we reach the lowest datarate - adrAckReq = false; - if (adrNext->UpdateChanMask == true) - { - // Re-enable default channels - ChannelsMask[0] = 0xFFFF; - ChannelsMask[1] = 0xFFFF; - ChannelsMask[2] = 0xFFFF; - ChannelsMask[3] = 0xFFFF; - ChannelsMask[4] = 0x00FF; - ChannelsMask[5] = 0x0000; - } - } - } - } - } - } - - *drOut = datarate; - *txPowOut = txPower; - return adrAckReq; - } - - void RegionUS915ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) - { - double tSymbol = 0.0; - - // Get the datarate, perform a boundary check - rxConfigParams->Datarate = MIN(datarate, US915_RX_MAX_DATARATE); - rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); - - tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesUS915[rxConfigParams->Datarate], BandwidthsUS915[rxConfigParams->Datarate]); - - RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); - } - - bool RegionUS915RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) - { - int8_t dr = rxConfig->Datarate; - uint8_t maxPayload = 0; - int8_t phyDr = 0; - uint32_t frequency = rxConfig->Frequency; - - if (Radio.GetStatus() != RF_IDLE) - { - return false; - } - - if (rxConfig->Window == 0) - { - // Apply window 1 frequency - frequency = US915_FIRST_RX1_CHANNEL + (rxConfig->Channel % 8) * US915_STEPWIDTH_RX1_CHANNEL; - } - - // Read the physical datarate from the datarates table - phyDr = DataratesUS915[dr]; - - Radio.SetChannel(frequency); - - // Radio configuration - Radio.SetRxConfig(MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); - - if (rxConfig->RepeaterSupport == true) - { - maxPayload = MaxPayloadOfDatarateRepeaterUS915[dr]; - } - else - { - maxPayload = MaxPayloadOfDatarateUS915[dr]; - } - Radio.SetMaxPayloadLength(MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - *datarate = (uint8_t)dr; - return true; - } - - bool RegionUS915TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) - { - int8_t phyDr = DataratesUS915[txConfig->Datarate]; - int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); - uint32_t bandwidth = GetBandwidth(txConfig->Datarate); - int8_t phyTxPower = 0; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, US915_DEFAULT_MAX_ERP, 0); - - // Setup the radio frequency - Radio.SetChannel(Channels[txConfig->Channel].Frequency); - Radio.SetTxConfig(MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); - - // Setup maximum payload lenght of the radio driver - Radio.SetMaxPayloadLength(MODEM_LORA, txConfig->PktLen); - // Get the time-on-air of the next tx frame - *txTimeOnAir = Radio.TimeOnAir(MODEM_LORA, txConfig->PktLen); - *txPower = txPowerLimited; - - return true; - } - - uint8_t RegionUS915LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) - { - uint8_t status = 0x07; - RegionCommonLinkAdrParams_t linkAdrParams; - uint8_t nextIndex = 0; - uint8_t bytesProcessed = 0; - uint16_t channelsMask[6] = {0, 0, 0, 0, 0, 0}; - GetPhyParams_t getPhy; - PhyParam_t phyParam; - RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; - - // Initialize local copy of channels mask - RegionCommonChanMaskCopy(channelsMask, ChannelsMask, 6); - - while (bytesProcessed < linkAdrReq->PayloadSize) - { - nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); - - if (nextIndex == 0) - break; // break loop, since no more request has been found - - // Update bytes processed - bytesProcessed += nextIndex; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - if (linkAdrParams.ChMaskCtrl == 6) - { - // Enable all 125 kHz channels - channelsMask[0] = 0xFFFF; - channelsMask[1] = 0xFFFF; - channelsMask[2] = 0xFFFF; - channelsMask[3] = 0xFFFF; - // Apply chMask to channels 64 to 71 - channelsMask[4] = linkAdrParams.ChMask; - } - else if (linkAdrParams.ChMaskCtrl == 7) - { - // Disable all 125 kHz channels - channelsMask[0] = 0x0000; - channelsMask[1] = 0x0000; - channelsMask[2] = 0x0000; - channelsMask[3] = 0x0000; - // Apply chMask to channels 64 to 71 - channelsMask[4] = linkAdrParams.ChMask; - } - else if (linkAdrParams.ChMaskCtrl == 5) - { - // RFU - status &= 0xFE; // Channel mask KO - } - else - { - channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask; - } - } - - // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels - if ((linkAdrParams.Datarate < DR_4) && (RegionCommonCountChannels(channelsMask, 0, 4) < 2)) - { - status &= 0xFE; // Channel mask KO - } - - // Get the minimum possible datarate - getPhy.Attribute = PHY_MIN_TX_DR; - getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; - phyParam = RegionUS915GetPhyParam(&getPhy); - - linkAdrVerifyParams.Status = status; - linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; - linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; - linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; - linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; - linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; - linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; - linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; - linkAdrVerifyParams.NbChannels = US915_MAX_NB_CHANNELS; - linkAdrVerifyParams.ChannelsMask = channelsMask; - linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; - linkAdrVerifyParams.MaxDatarate = US915_TX_MAX_DATARATE; - linkAdrVerifyParams.Channels = Channels; - linkAdrVerifyParams.MinTxPower = US915_MIN_TX_POWER; - linkAdrVerifyParams.MaxTxPower = US915_MAX_TX_POWER; - - // Verify the parameters and update, if necessary - status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); - - // Update channelsMask if everything is correct - if (status == 0x07) - { - // Copy Mask - RegionCommonChanMaskCopy(ChannelsMask, channelsMask, 6); - - ChannelsMaskRemaining[0] &= ChannelsMask[0]; - ChannelsMaskRemaining[1] &= ChannelsMask[1]; - ChannelsMaskRemaining[2] &= ChannelsMask[2]; - ChannelsMaskRemaining[3] &= ChannelsMask[3]; - ChannelsMaskRemaining[4] = ChannelsMask[4]; - ChannelsMaskRemaining[5] = ChannelsMask[5]; - } - - // Update status variables - *drOut = linkAdrParams.Datarate; - *txPowOut = linkAdrParams.TxPower; - *nbRepOut = linkAdrParams.NbRep; - *nbBytesParsed = bytesProcessed; - - return status; - } - - uint8_t RegionUS915RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) - { - uint8_t status = 0x07; - uint32_t freq = rxParamSetupReq->Frequency; - - // Verify radio frequency - if ((Radio.CheckRfFrequency(freq) == false) || - (freq < US915_FIRST_RX1_CHANNEL) || - (freq > US915_LAST_RX1_CHANNEL) || - (((freq - (uint32_t)US915_FIRST_RX1_CHANNEL) % (uint32_t)US915_STEPWIDTH_RX1_CHANNEL) != 0)) - { - status &= 0xFE; // Channel frequency KO - } - - // Verify datarate - if (RegionCommonValueInRange(rxParamSetupReq->Datarate, US915_RX_MIN_DATARATE, US915_RX_MAX_DATARATE) == false) - { - status &= 0xFD; // Datarate KO - } - if ((RegionCommonValueInRange(rxParamSetupReq->Datarate, DR_5, DR_7) == true) || - (rxParamSetupReq->Datarate > DR_13)) - { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, US915_MIN_RX1_DR_OFFSET, US915_MAX_RX1_DR_OFFSET) == false) - { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; - } - - uint8_t RegionUS915NewChannelReq(NewChannelReqParams_t *newChannelReq) - { - // Datarate and frequency KO - return 0; - } - - int8_t RegionUS915TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) - { - return -1; - } - - uint8_t RegionUS915DlChannelReq(DlChannelReqParams_t *dlChannelReq) - { - return 0; - } - - int8_t RegionUS915AlternateDr(AlternateDrParams_t *alternateDr) - { - int8_t datarate = 0; - - // Re-enable 500 kHz default channels - ChannelsMask[4] = 0x00FF; - - if ((alternateDr->NbTrials & 0x01) == 0x01) - { - datarate = DR_4; - } - else - { - datarate = DR_0; - } - return datarate; - } - - void RegionUS915CalcBackOff(CalcBackOffParams_t *calcBackOff) - { - RegionCommonCalcBackOffParams_t calcBackOffParams; - - calcBackOffParams.Channels = Channels; - calcBackOffParams.Bands = Bands; - calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; - calcBackOffParams.Joined = calcBackOff->Joined; - calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; - calcBackOffParams.Channel = calcBackOff->Channel; - calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; - calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; - - RegionCommonCalcBackOff(&calcBackOffParams); - } - - bool RegionUS915NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) - { - uint8_t nbEnabledChannels = 0; - uint8_t delayTx = 0; - uint8_t enabledChannels[US915_MAX_NB_CHANNELS] = {0}; - TimerTime_t nextTxDelay = 0; - - // Count 125kHz channels - if (RegionCommonCountChannels(ChannelsMaskRemaining, 0, 4) == 0) - { // Reactivate default channels - RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 4); - } - // Check other channels - if (nextChanParams->Datarate >= DR_4) - { - if ((ChannelsMaskRemaining[4] & 0x00FF) == 0) - { - ChannelsMaskRemaining[4] = ChannelsMask[4]; - } - } - - if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) - { - // Reset Aggregated time off - *aggregatedTimeOff = 0; - - // Update bands Time OFF - nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, US915_MAX_NB_BANDS); - - // Search how many channels are enabled - nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Datarate, - ChannelsMaskRemaining, Channels, - Bands, enabledChannels, &delayTx); - } - else - { - delayTx++; - nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); - } - - if (nbEnabledChannels > 0) - { - // We found a valid channel - *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; - // Disable the channel in the mask - RegionCommonChanDisable(ChannelsMaskRemaining, *channel, US915_MAX_NB_CHANNELS - 8); - - *time = 0; - return true; - } - else - { - if (delayTx > 0) - { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = nextTxDelay; - return true; - } - // Datarate not supported by any channel - *time = 0; - return false; - } - } - - LoRaMacStatus_t RegionUS915ChannelAdd(ChannelAddParams_t *channelAdd) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - bool RegionUS915ChannelsRemove(ChannelRemoveParams_t *channelRemove) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - void RegionUS915SetContinuousWave(ContinuousWaveParams_t *continuousWave) - { - int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); - int8_t phyTxPower = 0; - uint32_t frequency = Channels[continuousWave->Channel].Frequency; - - // Calculate physical TX power - phyTxPower = RegionCommonComputeTxPower(txPowerLimited, US915_DEFAULT_MAX_ERP, 0); - - Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); - } - - uint8_t RegionUS915ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) - { - int8_t datarate = DatarateOffsetsUS915[dr][drOffset]; - - if (datarate < 0) - { - datarate = DR_0; - } - return datarate; - } + static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE]; + + // Static functions + static int8_t GetNextLowerTxDr(int8_t dr, int8_t minDr) + { + uint8_t nextLowerDr = 0; + + if (dr == minDr) + { + nextLowerDr = minDr; + } + else + { + nextLowerDr = dr - 1; + } + return nextLowerDr; + } + + static uint32_t GetBandwidth(uint32_t drIndex) + { + switch (BandwidthsUS915[drIndex]) + { + default: + case 125000: + return 0; + case 250000: + return 1; + case 500000: + return 2; + } + } + + static int8_t LimitTxPower(int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t *channelsMask) + { + int8_t txPowerResult = txPower; + + // Limit tx power to the band max + txPowerResult = MAX(txPower, maxBandTxPower); + + if (datarate == DR_4) + { // Limit tx power to max 26dBm + txPowerResult = MAX(txPower, TX_POWER_2); + } + else + { + if (RegionCommonCountChannels(channelsMask, 0, 4) < 50) + { // Limit tx power to max 21dBm + txPowerResult = MAX(txPower, TX_POWER_5); + } + } + return txPowerResult; + } + + static uint8_t CountNbOfEnabledChannels(uint8_t datarate, uint16_t *channelsMask, ChannelParams_t *channels, Band_t *bands, uint8_t *enabledChannels, uint8_t *delayTx) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTransmission = 0; + + for (uint8_t i = 0, k = 0; i < US915_MAX_NB_CHANNELS; i += 16, k++) + { + for (uint8_t j = 0; j < 16; j++) + { + if ((channelsMask[k] & (1 << j)) != 0) + { + if (channels[i + j].Frequency == 0) + { // Check if the channel is enabled + continue; + } + if (RegionCommonValueInRange(datarate, channels[i + j].DrRange.Fields.Min, + channels[i + j].DrRange.Fields.Max) == false) + { // Check if the current channel selection supports the given datarate + continue; + } + if (bands[channels[i + j].Band].TimeOff > 0) + { // Check if the band is available for transmission + delayTransmission++; + continue; + } + enabledChannels[nbEnabledChannels++] = i + j; + } + } + } + + *delayTx = delayTransmission; + return nbEnabledChannels; + } + + PhyParam_t RegionUS915GetPhyParam(GetPhyParams_t *getPhy) + { + PhyParam_t phyParam = {0}; + + switch (getPhy->Attribute) + { + case PHY_MIN_RX_DR: + { + phyParam.Value = US915_RX_MIN_DATARATE; + break; + } + case PHY_MIN_TX_DR: + { + phyParam.Value = US915_TX_MIN_DATARATE; + break; + } + case PHY_DEF_TX_DR: + { + phyParam.Value = US915_DEFAULT_DATARATE; + break; + } + case PHY_NEXT_LOWER_TX_DR: + { + phyParam.Value = GetNextLowerTxDr(getPhy->Datarate, US915_TX_MIN_DATARATE); + break; + } + case PHY_DEF_TX_POWER: + { + phyParam.Value = US915_DEFAULT_TX_POWER; + break; + } + case PHY_MAX_PAYLOAD: + { + phyParam.Value = MaxPayloadOfDatarateUS915[getPhy->Datarate]; + break; + } + case PHY_MAX_PAYLOAD_REPEATER: + { + phyParam.Value = MaxPayloadOfDatarateRepeaterUS915[getPhy->Datarate]; + break; + } + case PHY_DUTY_CYCLE: + { + phyParam.Value = US915_DUTY_CYCLE_ENABLED; + break; + } + case PHY_MAX_RX_WINDOW: + { + phyParam.Value = US915_MAX_RX_WINDOW; + break; + } + case PHY_RECEIVE_DELAY1: + { + phyParam.Value = US915_RECEIVE_DELAY1; + break; + } + case PHY_RECEIVE_DELAY2: + { + phyParam.Value = US915_RECEIVE_DELAY2; + break; + } + case PHY_JOIN_ACCEPT_DELAY1: + { + phyParam.Value = US915_JOIN_ACCEPT_DELAY1; + break; + } + case PHY_JOIN_ACCEPT_DELAY2: + { + phyParam.Value = US915_JOIN_ACCEPT_DELAY2; + break; + } + case PHY_MAX_FCNT_GAP: + { + phyParam.Value = US915_MAX_FCNT_GAP; + break; + } + case PHY_ACK_TIMEOUT: + { + phyParam.Value = (US915_ACKTIMEOUT + randr(-US915_ACK_TIMEOUT_RND, US915_ACK_TIMEOUT_RND)); + break; + } + case PHY_DEF_DR1_OFFSET: + { + phyParam.Value = US915_DEFAULT_RX1_DR_OFFSET; + break; + } + case PHY_DEF_RX2_FREQUENCY: + { + phyParam.Value = US915_RX_WND_2_FREQ; + break; + } + case PHY_DEF_RX2_DR: + { + phyParam.Value = US915_RX_WND_2_DR; + break; + } + case PHY_CHANNELS_MASK: + { + phyParam.ChannelsMask = ChannelsMask; + break; + } + case PHY_CHANNELS_DEFAULT_MASK: + { + phyParam.ChannelsMask = ChannelsDefaultMask; + break; + } + case PHY_MAX_NB_CHANNELS: + { + phyParam.Value = US915_MAX_NB_CHANNELS; + break; + } + case PHY_CHANNELS: + { + phyParam.Channels = Channels; + break; + } + case PHY_DEF_UPLINK_DWELL_TIME: + case PHY_DEF_DOWNLINK_DWELL_TIME: + { + phyParam.Value = 0; + break; + } + case PHY_DEF_MAX_EIRP: + case PHY_DEF_ANTENNA_GAIN: + { + phyParam.fValue = 0; + break; + } + case PHY_NB_JOIN_TRIALS: + case PHY_DEF_NB_JOIN_TRIALS: + { + phyParam.Value = 2; + break; + } + default: + { + break; + } + } + + return phyParam; + } + + void RegionUS915SetBandTxDone(SetBandTxDoneParams_t *txDone) + { + RegionCommonSetBandTxDone(txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime); + } + + void RegionUS915InitDefaults(InitType_t type) + { + switch (type) + { + case INIT_TYPE_INIT: + { + // Channels + // 125 kHz channels + for (uint8_t i = 0; i < US915_MAX_NB_CHANNELS - 8; i++) + { + Channels[i].Frequency = 902300000 + i * 200000; + Channels[i].DrRange.Value = (DR_3 << 4) | DR_0; + Channels[i].Band = 0; + } + // 500 kHz channels + for (uint8_t i = US915_MAX_NB_CHANNELS - 8; i < US915_MAX_NB_CHANNELS; i++) + { + Channels[i].Frequency = 903000000 + (i - (US915_MAX_NB_CHANNELS - 8)) * 1600000; + Channels[i].DrRange.Value = (DR_4 << 4) | DR_4; + Channels[i].Band = 0; + } + + // ChannelsMask + ChannelsDefaultMask[0] = 0xFFFF; + ChannelsDefaultMask[1] = 0xFFFF; + ChannelsDefaultMask[2] = 0xFFFF; + ChannelsDefaultMask[3] = 0xFFFF; + ChannelsDefaultMask[4] = 0x00FF; + ChannelsDefaultMask[5] = 0x0000; + + // Copy channels default mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); + + // Copy into channels mask remaining + RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 6); + break; + } + case INIT_TYPE_RESTORE: + { + // Copy channels default mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); + + for (uint8_t i = 0; i < 6; i++) + { // Copy-And the channels mask + ChannelsMaskRemaining[i] &= ChannelsMask[i]; + } + break; + } + case INIT_TYPE_APP_DEFAULTS: + { + // Copy channels default mask + RegionCommonChanMaskCopy(ChannelsMask, ChannelsDefaultMask, 6); + + // Copy into channels mask remaining + RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 6); + break; + } + default: + { + break; + } + } + } + + bool RegionUS915Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute) + { + switch (phyAttribute) + { + case PHY_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, US915_TX_MIN_DATARATE, US915_TX_MAX_DATARATE); + } + case PHY_DEF_TX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, DR_0, DR_5); + } + case PHY_RX_DR: + { + return RegionCommonValueInRange(verify->DatarateParams.Datarate, US915_RX_MIN_DATARATE, US915_RX_MAX_DATARATE); + } + case PHY_DEF_TX_POWER: + case PHY_TX_POWER: + { + // Remark: switched min and max! + return RegionCommonValueInRange(verify->TxPower, US915_MAX_TX_POWER, US915_MIN_TX_POWER); + } + case PHY_DUTY_CYCLE: + { + return US915_DUTY_CYCLE_ENABLED; + } + case PHY_NB_JOIN_TRIALS: + { + if (verify->NbJoinTrials < 2) + { + return false; + } + break; + } + default: + return false; + } + return true; + } + + void RegionUS915ApplyCFList(ApplyCFListParams_t *applyCFList) + { + return; + } + + bool RegionUS915ChanMaskSet(ChanMaskSetParams_t *chanMaskSet) + { + uint8_t nbChannels = RegionCommonCountChannels(chanMaskSet->ChannelsMaskIn, 0, 4); + + // Check the number of active channels + if ((nbChannels < 2) && + (nbChannels > 0)) + { + return false; + } + + switch (chanMaskSet->ChannelsMaskType) + { + case CHANNELS_MASK: + { + RegionCommonChanMaskCopy(ChannelsMask, chanMaskSet->ChannelsMaskIn, 6); + + for (uint8_t i = 0; i < 6; i++) + { // Copy-And the channels mask + ChannelsMaskRemaining[i] &= ChannelsMask[i]; + } + break; + } + case CHANNELS_DEFAULT_MASK: + { + RegionCommonChanMaskCopy(ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6); + break; + } + default: + return false; + } + return true; + } + + bool RegionUS915AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter) + { + bool adrAckReq = false; + int8_t datarate = adrNext->Datarate; + int8_t txPower = adrNext->TxPower; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + + // Report back the adr ack counter + *adrAckCounter = adrNext->AdrAckCounter; + + if (adrNext->AdrEnabled == true) + { + if (datarate == US915_TX_MIN_DATARATE) + { + *adrAckCounter = 0; + adrAckReq = false; + } + else + { + if (adrNext->AdrAckCounter >= US915_ADR_ACK_LIMIT) + { + adrAckReq = true; + txPower = US915_MAX_TX_POWER; + } + else + { + adrAckReq = false; + } + if (adrNext->AdrAckCounter >= (US915_ADR_ACK_LIMIT + US915_ADR_ACK_DELAY)) + { + if ((adrNext->AdrAckCounter % US915_ADR_ACK_DELAY) == 1) + { + // Decrease the datarate + getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; + getPhy.Datarate = datarate; + getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; + phyParam = RegionUS915GetPhyParam(&getPhy); + datarate = phyParam.Value; + + if (datarate == US915_TX_MIN_DATARATE) + { + // We must set adrAckReq to false as soon as we reach the lowest datarate + adrAckReq = false; + if (adrNext->UpdateChanMask == true) + { + // Re-enable default channels + ChannelsMask[0] = 0xFFFF; + ChannelsMask[1] = 0xFFFF; + ChannelsMask[2] = 0xFFFF; + ChannelsMask[3] = 0xFFFF; + ChannelsMask[4] = 0x00FF; + ChannelsMask[5] = 0x0000; + } + } + } + } + } + } + + *drOut = datarate; + *txPowOut = txPower; + return adrAckReq; + } + + void RegionUS915ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams) + { + double tSymbol = 0.0; + + // Get the datarate, perform a boundary check + rxConfigParams->Datarate = MIN(datarate, US915_RX_MAX_DATARATE); + rxConfigParams->Bandwidth = GetBandwidth(rxConfigParams->Datarate); + + tSymbol = RegionCommonComputeSymbolTimeLoRa(DataratesUS915[rxConfigParams->Datarate], BandwidthsUS915[rxConfigParams->Datarate]); + + RegionCommonComputeRxWindowParameters(tSymbol, minRxSymbols, rxError, RADIO_WAKEUP_TIME, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset); + } + + bool RegionUS915RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate) + { + int8_t dr = rxConfig->Datarate; + uint8_t maxPayload = 0; + int8_t phyDr = 0; + uint32_t frequency = rxConfig->Frequency; + + if (Radio.GetStatus() != RF_IDLE) + { + return false; + } + + if (rxConfig->Window == 0) + { + // Apply window 1 frequency + frequency = US915_FIRST_RX1_CHANNEL + (rxConfig->Channel % 8) * US915_STEPWIDTH_RX1_CHANNEL; + } + + // Read the physical datarate from the datarates table + phyDr = DataratesUS915[dr]; + + Radio.SetChannel(frequency); + + // Radio configuration + Radio.SetRxConfig(MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous); + + if (rxConfig->RepeaterSupport == true) + { + maxPayload = MaxPayloadOfDatarateRepeaterUS915[dr]; + } + else + { + maxPayload = MaxPayloadOfDatarateUS915[dr]; + } + Radio.SetMaxPayloadLength(MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + *datarate = (uint8_t)dr; + return true; + } + + bool RegionUS915TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir) + { + int8_t phyDr = DataratesUS915[txConfig->Datarate]; + int8_t txPowerLimited = LimitTxPower(txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask); + uint32_t bandwidth = GetBandwidth(txConfig->Datarate); + int8_t phyTxPower = 0; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, US915_DEFAULT_MAX_ERP, 0); + + // Setup the radio frequency + Radio.SetChannel(Channels[txConfig->Channel].Frequency); + Radio.SetTxConfig(MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000); + + // Setup maximum payload lenght of the radio driver + Radio.SetMaxPayloadLength(MODEM_LORA, txConfig->PktLen); + // Get the time-on-air of the next tx frame + *txTimeOnAir = Radio.TimeOnAir(MODEM_LORA, txConfig->PktLen); + *txPower = txPowerLimited; + + return true; + } + + uint8_t RegionUS915LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed) + { + uint8_t status = 0x07; + RegionCommonLinkAdrParams_t linkAdrParams; + uint8_t nextIndex = 0; + uint8_t bytesProcessed = 0; + uint16_t channelsMask[6] = {0, 0, 0, 0, 0, 0}; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; + + // Initialize local copy of channels mask + RegionCommonChanMaskCopy(channelsMask, ChannelsMask, 6); + + while (bytesProcessed < linkAdrReq->PayloadSize) + { + nextIndex = RegionCommonParseLinkAdrReq(&(linkAdrReq->Payload[bytesProcessed]), &linkAdrParams); + + if (nextIndex == 0) + break; // break loop, since no more request has been found + + // Update bytes processed + bytesProcessed += nextIndex; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + if (linkAdrParams.ChMaskCtrl == 6) + { + // Enable all 125 kHz channels + channelsMask[0] = 0xFFFF; + channelsMask[1] = 0xFFFF; + channelsMask[2] = 0xFFFF; + channelsMask[3] = 0xFFFF; + // Apply chMask to channels 64 to 71 + channelsMask[4] = linkAdrParams.ChMask; + } + else if (linkAdrParams.ChMaskCtrl == 7) + { + // Disable all 125 kHz channels + channelsMask[0] = 0x0000; + channelsMask[1] = 0x0000; + channelsMask[2] = 0x0000; + channelsMask[3] = 0x0000; + // Apply chMask to channels 64 to 71 + channelsMask[4] = linkAdrParams.ChMask; + } + else if (linkAdrParams.ChMaskCtrl == 5) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask; + } + } + + // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels + if ((linkAdrParams.Datarate < DR_4) && (RegionCommonCountChannels(channelsMask, 0, 4) < 2)) + { + status &= 0xFE; // Channel mask KO + } + + // Get the minimum possible datarate + getPhy.Attribute = PHY_MIN_TX_DR; + getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; + phyParam = RegionUS915GetPhyParam(&getPhy); + + linkAdrVerifyParams.Status = status; + linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; + linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; + linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; + linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; + linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; + linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; + linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; + linkAdrVerifyParams.NbChannels = US915_MAX_NB_CHANNELS; + linkAdrVerifyParams.ChannelsMask = channelsMask; + linkAdrVerifyParams.MinDatarate = (int8_t)phyParam.Value; + linkAdrVerifyParams.MaxDatarate = US915_TX_MAX_DATARATE; + linkAdrVerifyParams.Channels = Channels; + linkAdrVerifyParams.MinTxPower = US915_MIN_TX_POWER; + linkAdrVerifyParams.MaxTxPower = US915_MAX_TX_POWER; + + // Verify the parameters and update, if necessary + status = RegionCommonLinkAdrReqVerifyParams(&linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep); + + // Update channelsMask if everything is correct + if (status == 0x07) + { + // Copy Mask + RegionCommonChanMaskCopy(ChannelsMask, channelsMask, 6); + + ChannelsMaskRemaining[0] &= ChannelsMask[0]; + ChannelsMaskRemaining[1] &= ChannelsMask[1]; + ChannelsMaskRemaining[2] &= ChannelsMask[2]; + ChannelsMaskRemaining[3] &= ChannelsMask[3]; + ChannelsMaskRemaining[4] = ChannelsMask[4]; + ChannelsMaskRemaining[5] = ChannelsMask[5]; + } + + // Update status variables + *drOut = linkAdrParams.Datarate; + *txPowOut = linkAdrParams.TxPower; + *nbRepOut = linkAdrParams.NbRep; + *nbBytesParsed = bytesProcessed; + + return status; + } + + uint8_t RegionUS915RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq) + { + uint8_t status = 0x07; + uint32_t freq = rxParamSetupReq->Frequency; + + // Verify radio frequency + if ((Radio.CheckRfFrequency(freq) == false) || + (freq < US915_FIRST_RX1_CHANNEL) || + (freq > US915_LAST_RX1_CHANNEL) || + (((freq - (uint32_t)US915_FIRST_RX1_CHANNEL) % (uint32_t)US915_STEPWIDTH_RX1_CHANNEL) != 0)) + { + status &= 0xFE; // Channel frequency KO + } + + // Verify datarate + if (RegionCommonValueInRange(rxParamSetupReq->Datarate, US915_RX_MIN_DATARATE, US915_RX_MAX_DATARATE) == false) + { + status &= 0xFD; // Datarate KO + } + if ((RegionCommonValueInRange(rxParamSetupReq->Datarate, DR_5, DR_7) == true) || + (rxParamSetupReq->Datarate > DR_13)) + { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (RegionCommonValueInRange(rxParamSetupReq->DrOffset, US915_MIN_RX1_DR_OFFSET, US915_MAX_RX1_DR_OFFSET) == false) + { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; + } + + uint8_t RegionUS915NewChannelReq(NewChannelReqParams_t *newChannelReq) + { + // Datarate and frequency KO + return 0; + } + + int8_t RegionUS915TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq) + { + return -1; + } + + uint8_t RegionUS915DlChannelReq(DlChannelReqParams_t *dlChannelReq) + { + return 0; + } + + int8_t RegionUS915AlternateDr(AlternateDrParams_t *alternateDr) + { + int8_t datarate = 0; + + // Re-enable 500 kHz default channels + ChannelsMask[4] = 0x00FF; + + if ((alternateDr->NbTrials & 0x01) == 0x01) + { + datarate = DR_4; + } + else + { + datarate = DR_0; + } + return datarate; + } + + void RegionUS915CalcBackOff(CalcBackOffParams_t *calcBackOff) + { + RegionCommonCalcBackOffParams_t calcBackOffParams; + + calcBackOffParams.Channels = Channels; + calcBackOffParams.Bands = Bands; + calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest; + calcBackOffParams.Joined = calcBackOff->Joined; + calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled; + calcBackOffParams.Channel = calcBackOff->Channel; + calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime; + calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir; + + RegionCommonCalcBackOff(&calcBackOffParams); + } + + bool RegionUS915NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff) + { + uint8_t nbEnabledChannels = 0; + uint8_t delayTx = 0; + uint8_t enabledChannels[US915_MAX_NB_CHANNELS] = {0}; + TimerTime_t nextTxDelay = 0; + + // Count 125kHz channels + if (RegionCommonCountChannels(ChannelsMaskRemaining, 0, 4) == 0) + { // Reactivate default channels + RegionCommonChanMaskCopy(ChannelsMaskRemaining, ChannelsMask, 4); + } + // Check other channels + if (nextChanParams->Datarate >= DR_4) + { + if ((ChannelsMaskRemaining[4] & 0x00FF) == 0) + { + ChannelsMaskRemaining[4] = ChannelsMask[4]; + } + } + + if (nextChanParams->AggrTimeOff <= TimerGetElapsedTime(nextChanParams->LastAggrTx)) + { + // Reset Aggregated time off + *aggregatedTimeOff = 0; + + // Update bands Time OFF + nextTxDelay = RegionCommonUpdateBandTimeOff(nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, US915_MAX_NB_BANDS); + + // Search how many channels are enabled + nbEnabledChannels = CountNbOfEnabledChannels(nextChanParams->Datarate, + ChannelsMaskRemaining, Channels, + Bands, enabledChannels, &delayTx); + } + else + { + delayTx++; + nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime(nextChanParams->LastAggrTx); + } + + if (nbEnabledChannels > 0) + { + // We found a valid channel + *channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; + // Disable the channel in the mask + RegionCommonChanDisable(ChannelsMaskRemaining, *channel, US915_MAX_NB_CHANNELS - 8); + + *time = 0; + return true; + } + else + { + if (delayTx > 0) + { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return true; + } + // Datarate not supported by any channel + *time = 0; + return false; + } + } + + LoRaMacStatus_t RegionUS915ChannelAdd(ChannelAddParams_t *channelAdd) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + bool RegionUS915ChannelsRemove(ChannelRemoveParams_t *channelRemove) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + void RegionUS915SetContinuousWave(ContinuousWaveParams_t *continuousWave) + { + int8_t txPowerLimited = LimitTxPower(continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask); + int8_t phyTxPower = 0; + uint32_t frequency = Channels[continuousWave->Channel].Frequency; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower(txPowerLimited, US915_DEFAULT_MAX_ERP, 0); + + Radio.SetTxContinuousWave(frequency, phyTxPower, continuousWave->Timeout); + } + + uint8_t RegionUS915ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset) + { + int8_t datarate = DatarateOffsetsUS915[dr][drOffset]; + + if (datarate < 0) + { + datarate = DR_0; + } + return datarate; + } }; \ No newline at end of file diff --git a/src/mac/region/RegionUS915.h b/src/mac/region/RegionUS915.h index e08c351..0b49ddd 100644 --- a/src/mac/region/RegionUS915.h +++ b/src/mac/region/RegionUS915.h @@ -41,215 +41,218 @@ extern "C" /*! * LoRaMac maximum number of channels */ -#define US915_MAX_NB_CHANNELS 72 +#define US915_MAX_NB_CHANNELS 72 /*! * Minimal datarate that can be used by the node */ -#define US915_TX_MIN_DATARATE DR_0 +#define US915_TX_MIN_DATARATE DR_0 /*! * Maximal datarate that can be used by the node */ -#define US915_TX_MAX_DATARATE DR_4 +#define US915_TX_MAX_DATARATE DR_4 /*! * Minimal datarate that can be used by the node */ -#define US915_RX_MIN_DATARATE DR_8 +#define US915_RX_MIN_DATARATE DR_8 /*! * Maximal datarate that can be used by the node */ -#define US915_RX_MAX_DATARATE DR_13 +#define US915_RX_MAX_DATARATE DR_13 /*! * Default datarate used by the node */ -#define US915_DEFAULT_DATARATE DR_0 +#define US915_DEFAULT_DATARATE DR_0 /*! * Minimal Rx1 receive datarate offset */ -#define US915_MIN_RX1_DR_OFFSET 0 +#define US915_MIN_RX1_DR_OFFSET 0 /*! * Maximal Rx1 receive datarate offset */ -#define US915_MAX_RX1_DR_OFFSET 3 +#define US915_MAX_RX1_DR_OFFSET 3 /*! * Default Rx1 receive datarate offset */ -#define US915_DEFAULT_RX1_DR_OFFSET 0 +#define US915_DEFAULT_RX1_DR_OFFSET 0 /*! * Minimal Tx output power that can be used by the node */ -#define US915_MIN_TX_POWER TX_POWER_10 +#define US915_MIN_TX_POWER TX_POWER_10 /*! * Maximal Tx output power that can be used by the node */ -#define US915_MAX_TX_POWER TX_POWER_0 +#define US915_MAX_TX_POWER TX_POWER_0 /*! * Default Tx output power used by the node */ -#define US915_DEFAULT_TX_POWER TX_POWER_0 +#define US915_DEFAULT_TX_POWER TX_POWER_0 /*! * Default Max ERP */ -#define US915_DEFAULT_MAX_ERP 30.0f +#define US915_DEFAULT_MAX_ERP 30.0f /*! * ADR Ack limit */ -#define US915_ADR_ACK_LIMIT 64 +#define US915_ADR_ACK_LIMIT 64 /*! * ADR Ack delay */ -#define US915_ADR_ACK_DELAY 32 +#define US915_ADR_ACK_DELAY 32 /*! * Enabled or disabled the duty cycle */ -#define US915_DUTY_CYCLE_ENABLED 0 +#define US915_DUTY_CYCLE_ENABLED 0 /*! * Maximum RX window duration */ -#define US915_MAX_RX_WINDOW 3000 +#define US915_MAX_RX_WINDOW 3000 /*! * Receive delay 1 */ -#define US915_RECEIVE_DELAY1 1000 +#define US915_RECEIVE_DELAY1 1000 /*! * Receive delay 2 */ -#define US915_RECEIVE_DELAY2 2000 +#define US915_RECEIVE_DELAY2 2000 /*! * Join accept delay 1 */ -#define US915_JOIN_ACCEPT_DELAY1 5000 +#define US915_JOIN_ACCEPT_DELAY1 5000 /*! * Join accept delay 2 */ -#define US915_JOIN_ACCEPT_DELAY2 6000 +#define US915_JOIN_ACCEPT_DELAY2 6000 /*! * Maximum frame counter gap */ -#define US915_MAX_FCNT_GAP 16384 +#define US915_MAX_FCNT_GAP 16384 /*! * Ack timeout */ -#define US915_ACKTIMEOUT 2000 +#define US915_ACKTIMEOUT 2000 /*! * Random ack timeout limits */ -#define US915_ACK_TIMEOUT_RND 1000 +#define US915_ACK_TIMEOUT_RND 1000 /*! * Second reception window channel frequency definition. */ -#define US915_RX_WND_2_FREQ 923300000 +#define US915_RX_WND_2_FREQ 923300000 /*! * Second reception window channel datarate definition. */ -#define US915_RX_WND_2_DR DR_8 +#define US915_RX_WND_2_DR DR_8 /*! * LoRaMac maximum number of bands */ -#define US915_MAX_NB_BANDS 1 +#define US915_MAX_NB_BANDS 1 /*! * Band 0 definition * { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } */ -#define US915_BAND0 { 1, US915_MAX_TX_POWER, 0, 0 } // 100.0 % +#define US915_BAND0 \ + { \ + 1, US915_MAX_TX_POWER, 0, 0 \ + } // 100.0 % /*! * Defines the first channel for RX window 1 for US band */ -#define US915_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 ) +#define US915_FIRST_RX1_CHANNEL ((uint32_t)923300000) /*! * Defines the last channel for RX window 1 for US band */ -#define US915_LAST_RX1_CHANNEL ( (uint32_t) 927500000 ) +#define US915_LAST_RX1_CHANNEL ((uint32_t)927500000) /*! * Defines the step width of the channels for RX window 1 */ -#define US915_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 ) +#define US915_STEPWIDTH_RX1_CHANNEL ((uint32_t)600000) -/*! + /*! * Data rates table definition */ -static const uint8_t DataratesUS915[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 }; + static const uint8_t DataratesUS915[] = {10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0}; -/*! + /*! * Bandwidths table definition in Hz */ -static const uint32_t BandwidthsUS915[] = { 125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 }; + static const uint32_t BandwidthsUS915[] = {125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0}; -/*! + /*! * Up/Down link data rates offset definition */ -static const int8_t DatarateOffsetsUS915[5][4] = -{ - { DR_10, DR_9 , DR_8 , DR_8 }, // DR_0 - { DR_11, DR_10, DR_9 , DR_8 }, // DR_1 - { DR_12, DR_11, DR_10, DR_9 }, // DR_2 - { DR_13, DR_12, DR_11, DR_10 }, // DR_3 - { DR_13, DR_13, DR_12, DR_11 }, // DR_4 -}; + static const int8_t DatarateOffsetsUS915[5][4] = + { + {DR_10, DR_9, DR_8, DR_8}, // DR_0 + {DR_11, DR_10, DR_9, DR_8}, // DR_1 + {DR_12, DR_11, DR_10, DR_9}, // DR_2 + {DR_13, DR_12, DR_11, DR_10}, // DR_3 + {DR_13, DR_13, DR_12, DR_11}, // DR_4 + }; -/*! + /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateUS915[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 }; + static const uint8_t MaxPayloadOfDatarateUS915[] = {11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0}; -/*! + /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ -static const uint8_t MaxPayloadOfDatarateRepeaterUS915[] = { 11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0 }; + static const uint8_t MaxPayloadOfDatarateRepeaterUS915[] = {11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0}; -/*! + /*! * \brief The function gets a value of a specific phy attribute. * * \param [IN] getPhy Pointer to the function parameters. * * \retval Returns a structure containing the PHY parameter. */ -PhyParam_t RegionUS915GetPhyParam( GetPhyParams_t* getPhy ); + PhyParam_t RegionUS915GetPhyParam(GetPhyParams_t *getPhy); -/*! + /*! * \brief Updates the last TX done parameters of the current channel. * * \param [IN] txDone Pointer to the function parameters. */ -void RegionUS915SetBandTxDone( SetBandTxDoneParams_t* txDone ); + void RegionUS915SetBandTxDone(SetBandTxDoneParams_t *txDone); -/*! + /*! * \brief Initializes the channels masks and the channels. * * \param [IN] type Sets the initialization type. */ -void RegionUS915InitDefaults( InitType_t type ); + void RegionUS915InitDefaults(InitType_t type); -/*! + /*! * \brief Verifies a parameter. * * \param [IN] verify Pointer to the function parameters. @@ -258,26 +261,26 @@ void RegionUS915InitDefaults( InitType_t type ); * * \retval Returns true, if the parameter is valid. */ -bool RegionUS915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + bool RegionUS915Verify(VerifyParams_t *verify, PhyAttribute_t phyAttribute); -/*! + /*! * \brief The function parses the input buffer and sets up the channels of the * CF list. * * \param [IN] applyCFList Pointer to the function parameters. */ -void RegionUS915ApplyCFList( ApplyCFListParams_t* applyCFList ); + void RegionUS915ApplyCFList(ApplyCFListParams_t *applyCFList); -/*! + /*! * \brief Sets a channels mask. * * \param [IN] chanMaskSet Pointer to the function parameters. * * \retval Returns true, if the channels mask could be set. */ -bool RegionUS915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + bool RegionUS915ChanMaskSet(ChanMaskSetParams_t *chanMaskSet); -/*! + /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. @@ -290,9 +293,9 @@ bool RegionUS915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); * * \retval Returns true, if an ADR request should be performed. */ -bool RegionUS915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ); + bool RegionUS915AdrNext(AdrNextParams_t *adrNext, int8_t *drOut, int8_t *txPowOut, uint32_t *adrAckCounter); -/*! + /*! * Computes the Rx window timeout and offset. * * \param [IN] datarate Rx window datarate index to be used @@ -305,9 +308,9 @@ bool RegionUS915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowO * * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. */ -void RegionUS915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + void RegionUS915ComputeRxWindowParameters(int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams); -/*! + /*! * \brief Configuration of the RX windows. * * \param [IN] rxConfig Pointer to the function parameters. @@ -316,9 +319,9 @@ void RegionUS915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionUS915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + bool RegionUS915RxConfig(RxConfigParams_t *rxConfig, int8_t *datarate); -/*! + /*! * \brief TX configuration. * * \param [IN] txConfig Pointer to the function parameters. @@ -329,36 +332,36 @@ bool RegionUS915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); * * \retval Returns true, if the configuration was applied successfully. */ -bool RegionUS915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + bool RegionUS915TxConfig(TxConfigParams_t *txConfig, int8_t *txPower, TimerTime_t *txTimeOnAir); -/*! + /*! * \brief The function processes a Link ADR Request. * * \param [IN] linkAdrReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionUS915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + uint8_t RegionUS915LinkAdrReq(LinkAdrReqParams_t *linkAdrReq, int8_t *drOut, int8_t *txPowOut, uint8_t *nbRepOut, uint8_t *nbBytesParsed); -/*! + /*! * \brief The function processes a RX Parameter Setup Request. * * \param [IN] rxParamSetupReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionUS915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + uint8_t RegionUS915RxParamSetupReq(RxParamSetupReqParams_t *rxParamSetupReq); -/*! + /*! * \brief The function processes a Channel Request. * * \param [IN] newChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionUS915NewChannelReq( NewChannelReqParams_t* newChannelReq ); + uint8_t RegionUS915NewChannelReq(NewChannelReqParams_t *newChannelReq); -/*! + /*! * \brief The function processes a TX ParamSetup Request. * * \param [IN] txParamSetupReq Pointer to the function parameters. @@ -367,34 +370,34 @@ uint8_t RegionUS915NewChannelReq( NewChannelReqParams_t* newChannelReq ); * Returns -1, if the functionality is not implemented. In this case, the end node * shall not process the command. */ -int8_t RegionUS915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + int8_t RegionUS915TxParamSetupReq(TxParamSetupReqParams_t *txParamSetupReq); -/*! + /*! * \brief The function processes a DlChannel Request. * * \param [IN] dlChannelReq Pointer to the function parameters. * * \retval Returns the status of the operation, according to the LoRaMAC specification. */ -uint8_t RegionUS915DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + uint8_t RegionUS915DlChannelReq(DlChannelReqParams_t *dlChannelReq); -/*! + /*! * \brief Alternates the datarate of the channel for the join request. * * \param [IN] alternateDr Pointer to the function parameters. * * \retval Datarate to apply. */ -int8_t RegionUS915AlternateDr( AlternateDrParams_t* alternateDr ); + int8_t RegionUS915AlternateDr(AlternateDrParams_t *alternateDr); -/*! + /*! * \brief Calculates the back-off time. * * \param [IN] calcBackOff Pointer to the function parameters. */ -void RegionUS915CalcBackOff( CalcBackOffParams_t* calcBackOff ); + void RegionUS915CalcBackOff(CalcBackOffParams_t *calcBackOff); -/*! + /*! * \brief Searches and set the next random available channel * * \param [OUT] channel Next channel to use for TX. @@ -406,34 +409,34 @@ void RegionUS915CalcBackOff( CalcBackOffParams_t* calcBackOff ); * * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] */ -bool RegionUS915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + bool RegionUS915NextChannel(NextChanParams_t *nextChanParams, uint8_t *channel, TimerTime_t *time, TimerTime_t *aggregatedTimeOff); -/*! + /*! * \brief Adds a channel. * * \param [IN] channelAdd Pointer to the function parameters. * * \retval Status of the operation. */ -LoRaMacStatus_t RegionUS915ChannelAdd( ChannelAddParams_t* channelAdd ); + LoRaMacStatus_t RegionUS915ChannelAdd(ChannelAddParams_t *channelAdd); -/*! + /*! * \brief Removes a channel. * * \param [IN] channelRemove Pointer to the function parameters. * * \retval Returns true, if the channel was removed successfully. */ -bool RegionUS915ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + bool RegionUS915ChannelsRemove(ChannelRemoveParams_t *channelRemove); -/*! + /*! * \brief Sets the radio into continuous wave mode. * * \param [IN] continuousWave Pointer to the function parameters. */ -void RegionUS915SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + void RegionUS915SetContinuousWave(ContinuousWaveParams_t *continuousWave); -/*! + /*! * \brief Computes new datarate according to the given offset * * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms @@ -444,8 +447,8 @@ void RegionUS915SetContinuousWave( ContinuousWaveParams_t* continuousWave ); * * \retval newDr Computed datarate. */ -uint8_t RegionUS915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + uint8_t RegionUS915ApplyDrOffset(uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset); -/*! \} defgroup REGIONUS915 */ + /*! \} defgroup REGIONUS915 */ }; #endif // __REGION_US915_H__ diff --git a/src/radio/sx126x/radio.cpp b/src/radio/sx126x/radio.cpp index 88af7dd..97b9b76 100644 --- a/src/radio/sx126x/radio.cpp +++ b/src/radio/sx126x/radio.cpp @@ -420,6 +420,11 @@ extern "C" bool IrqFired = false; + bool TimerRxTimeout = false; + bool TimerTxTimeout = false; + + RadioModems_t _modem; + /* * SX126x DIO IRQ callback functions prototype */ @@ -540,6 +545,7 @@ extern "C" // When switching to GFSK mode the LoRa SyncWord register value is reset // Thus, we also reset the RadioPublicNetwork variable RadioPublicNetwork.Current = false; + _modem = modem; break; case MODEM_LORA: SX126xSetPacketType(PACKET_TYPE_LORA); @@ -549,6 +555,7 @@ extern "C" RadioPublicNetwork.Current = RadioPublicNetwork.Previous; RadioSetPublicNetwork(RadioPublicNetwork.Current); } + _modem = modem; break; } } @@ -570,7 +577,7 @@ extern "C" RadioRx(0); - DelayMs(1); + delay(1); carrierSenseTime = TimerGetCurrentTime(); @@ -605,7 +612,7 @@ extern "C" for (i = 0; i < 32; i++) { - DelayMs(1); + delay(1); // Unfiltered RSSI value reading. Only takes the LSB value rnd |= ((uint32_t)SX126xGetRssiInst() & 0x01) << i; } @@ -912,7 +919,7 @@ extern "C" params.Fields.WarmStart = 1; SX126xSetSleep(params); - DelayMs(2); + delay(2); } void RadioStandby(void) @@ -928,19 +935,26 @@ extern "C" IRQ_RADIO_NONE, IRQ_RADIO_NONE); - if (timeout != 0) - { - TimerSetValue(&RxTimeoutTimer, timeout); - TimerStart(&RxTimeoutTimer); - } - if (RxContinuous == true) { + // Even Continous mode is selected, put a timeout here + if (timeout != 0) + { + TimerSetValue(&RxTimeoutTimer, timeout); + TimerStart(&RxTimeoutTimer); + } SX126xSetRx(0xFFFFFF); // Rx Continuous } else { - SX126xSetRx(RxTimeout << 6); + if (_modem == MODEM_FSK) + { + SX126xSetRx(RxTimeout << 6); + } + else + { + SX126xSetRx(timeout << 6); + } } } @@ -951,19 +965,26 @@ extern "C" IRQ_RADIO_NONE, IRQ_RADIO_NONE); - if (timeout != 0) - { - TimerSetValue(&RxTimeoutTimer, timeout); - TimerStart(&RxTimeoutTimer); - } - if (RxContinuous == true) { + // Even Continous mode is selected, put a timeout here + if (timeout != 0) + { + TimerSetValue(&RxTimeoutTimer, timeout); + TimerStart(&RxTimeoutTimer); + } SX126xSetRxBoosted(0xFFFFFF); // Rx Continuous } else { - SX126xSetRxBoosted(RxTimeout << 6); + if (_modem == MODEM_FSK) + { + SX126xSetRxBoosted(RxTimeout << 6); + } + else + { + SX126xSetRxBoosted(timeout << 6); + } } } @@ -1079,21 +1100,31 @@ extern "C" void RadioOnTxTimeoutIrq(void) { - if ((RadioEvents != NULL) && (RadioEvents->TxTimeout != NULL)) - { - RadioEvents->TxTimeout(); - } + // if ((RadioEvents != NULL) && (RadioEvents->TxTimeout != NULL)) + // { + // RadioEvents->TxTimeout(); + // } + BoardDisableIrq(); + TimerTxTimeout = true; + BoardEnableIrq(); } void RadioOnRxTimeoutIrq(void) { - if ((RadioEvents != NULL) && (RadioEvents->RxTimeout != NULL)) - { - RadioEvents->RxTimeout(); - } + // if ((RadioEvents != NULL) && (RadioEvents->RxTimeout != NULL)) + // { + // RadioEvents->RxTimeout(); + // } + BoardDisableIrq(); + TimerRxTimeout = true; + BoardEnableIrq(); } +#ifdef ESP8266 + void ICACHE_RAM_ATTR RadioOnDioIrq(void) +#else void RadioOnDioIrq(void) +#endif { BoardDisableIrq(); IrqFired = true; @@ -1193,5 +1224,23 @@ extern "C" } } } + if (TimerRxTimeout) + { + TimerRxTimeout = false; + TimerStop(&RxTimeoutTimer); + if ((RadioEvents != NULL) && (RadioEvents->RxTimeout != NULL)) + { + RadioEvents->RxTimeout(); + } + } + if (TimerTxTimeout) + { + TimerTxTimeout = false; + TimerStop(&TxTimeoutTimer); + if ((RadioEvents != NULL) && (RadioEvents->TxTimeout != NULL)) + { + RadioEvents->TxTimeout(); + } + } } }; \ No newline at end of file diff --git a/src/radio/sx126x/sx126x.cpp b/src/radio/sx126x/sx126x.cpp index a531087..d59a42f 100644 --- a/src/radio/sx126x/sx126x.cpp +++ b/src/radio/sx126x/sx126x.cpp @@ -213,7 +213,7 @@ extern "C" // Set radio in continuous reception SX126xSetRx(0); - DelayMs(1); + delay(1); SX126xReadRegisters(RANDOM_NUMBER_GENERATORBASEADDR, buf, 4); diff --git a/src/system/crypto/aes.cpp b/src/system/crypto/aes.cpp index b9d59c9..bc62de1 100644 --- a/src/system/crypto/aes.cpp +++ b/src/system/crypto/aes.cpp @@ -33,905 +33,952 @@ /* define if you have a fast memcpy function on your system */ #if 0 -# define HAVE_MEMCPY -# include -# if defined( _MSC_VER ) -# include -# pragma intrinsic( memcpy ) -# endif +#define HAVE_MEMCPY +#include +#if defined(_MSC_VER) +#include +#pragma intrinsic(memcpy) +#endif #endif #include #include -extern "C" { +extern "C" +{ /* define if you have fast 32-bit types on your system */ -#if ( __CORTEX_M != 0 ) // if Cortex is different from M0/M0+ -# define HAVE_UINT_32T +#if (__CORTEX_M != 0) // if Cortex is different from M0/M0+ +#define HAVE_UINT_32T #endif /* define if you don't want any tables */ #if 1 -# define USE_TABLES +#define USE_TABLES #endif /* On Intel Core 2 duo VERSION_1 is faster */ /* alternative versions (test for performance on your system) */ #if 1 -# define VERSION_1 +#define VERSION_1 #endif #include "aes.h" -// #if defined( HAVE_UINT_32T ) -// typedef unsigned long uint32_t; -// #endif - -/* functions for finite field multiplication in the AES Galois field */ - -#define WPOLY 0x011b -#define BPOLY 0x1b -#define DPOLY 0x008d - -#define f1(x) (x) -#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY)) -#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY)) -#define f8(x) ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) \ - ^ (((x >> 5) & 4) * WPOLY)) -#define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0)) - -#define f3(x) (f2(x) ^ x) -#define f9(x) (f8(x) ^ x) -#define fb(x) (f8(x) ^ f2(x) ^ x) -#define fd(x) (f8(x) ^ f4(x) ^ x) -#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) - -#if defined( USE_TABLES ) - -#define sb_data(w) { /* S Box data values */ \ - w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ - w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ - w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ - w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ - w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ - w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ - w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ - w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ - w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ - w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ - w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ - w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ - w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ - w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ - w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ - w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ - w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ - w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ - w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ - w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ - w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ - w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ - w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ - w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ - w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ - w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ - w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ - w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ - w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ - w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ - w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ - w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } - -#define isb_data(w) { /* inverse S Box data values */ \ - w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ - w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ - w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ - w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ - w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ - w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ - w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ - w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ - w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ - w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ - w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ - w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ - w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ - w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ - w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ - w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ - w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ - w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ - w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ - w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ - w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ - w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ - w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ - w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ - w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ - w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ - w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ - w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ - w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ - w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ - w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ - w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } - -#define mm_data(w) { /* basic data for forming finite field tables */ \ - w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ - w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ - w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ - w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ - w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ - w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ - w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ - w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ - w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ - w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ - w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ - w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ - w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ - w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ - w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ - w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ - w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ - w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ - w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ - w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ - w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ - w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ - w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ - w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ - w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ - w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ - w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ - w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ - w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ - w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ - w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ - w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } - -static const uint8_t sbox[256] = sb_data(f1); - -#if defined( AES_DEC_PREKEYED ) -static const uint8_t isbox[256] = isb_data(f1); -#endif - -static const uint8_t gfm2_sbox[256] = sb_data(f2); -static const uint8_t gfm3_sbox[256] = sb_data(f3); - -#if defined( AES_DEC_PREKEYED ) -static const uint8_t gfmul_9[256] = mm_data(f9); -static const uint8_t gfmul_b[256] = mm_data(fb); -static const uint8_t gfmul_d[256] = mm_data(fd); -static const uint8_t gfmul_e[256] = mm_data(fe); -#endif - -#define s_box(x) sbox[(x)] -#if defined( AES_DEC_PREKEYED ) -#define is_box(x) isbox[(x)] -#endif -#define gfm2_sb(x) gfm2_sbox[(x)] -#define gfm3_sb(x) gfm3_sbox[(x)] -#if defined( AES_DEC_PREKEYED ) -#define gfm_9(x) gfmul_9[(x)] -#define gfm_b(x) gfmul_b[(x)] -#define gfm_d(x) gfmul_d[(x)] -#define gfm_e(x) gfmul_e[(x)] + // #if defined( HAVE_UINT_32T ) + // typedef unsigned long uint32_t; + // #endif + + /* functions for finite field multiplication in the AES Galois field */ + +#define WPOLY 0x011b +#define BPOLY 0x1b +#define DPOLY 0x008d + +#define f1(x) (x) +#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY)) +#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY)) +#define f8(x) ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) ^ (((x >> 5) & 4) * WPOLY)) +#define d2(x) (((x) >> 1) ^ ((x)&1 ? DPOLY : 0)) + +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#if defined(USE_TABLES) + +#define sb_data(w) \ + { /* S Box data values */ \ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5), \ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76), \ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0), \ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0), \ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc), \ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), \ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), \ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75), \ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0), \ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84), \ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b), \ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf), \ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), \ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), \ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5), \ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2), \ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17), \ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73), \ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88), \ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), \ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), \ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79), \ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9), \ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08), \ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6), \ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a), \ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), \ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), \ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94), \ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf), \ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68), \ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) \ + } + +#define isb_data(w) \ + { /* inverse S Box data values */ \ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38), \ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb), \ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87), \ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb), \ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d), \ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e), \ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2), \ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25), \ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16), \ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92), \ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda), \ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84), \ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a), \ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06), \ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02), \ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b), \ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea), \ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73), \ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85), \ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), \ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), \ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b), \ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20), \ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4), \ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31), \ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f), \ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), \ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), \ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0), \ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61), \ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26), \ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) \ + } + +#define mm_data(w) \ + { /* basic data for forming finite field tables */ \ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07), \ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f), \ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17), \ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f), \ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27), \ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f), \ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37), \ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f), \ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47), \ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f), \ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57), \ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f), \ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67), \ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f), \ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77), \ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f), \ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87), \ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f), \ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97), \ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f), \ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7), \ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf), \ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7), \ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf), \ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7), \ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf), \ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7), \ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf), \ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7), \ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef), \ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7), \ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) \ + } + + static const uint8_t sbox[256] = sb_data(f1); + +#if defined(AES_DEC_PREKEYED) + static const uint8_t isbox[256] = isb_data(f1); +#endif + + static const uint8_t gfm2_sbox[256] = sb_data(f2); + static const uint8_t gfm3_sbox[256] = sb_data(f3); + +#if defined(AES_DEC_PREKEYED) + static const uint8_t gfmul_9[256] = mm_data(f9); + static const uint8_t gfmul_b[256] = mm_data(fb); + static const uint8_t gfmul_d[256] = mm_data(fd); + static const uint8_t gfmul_e[256] = mm_data(fe); +#endif + +#define s_box(x) sbox[(x)] +#if defined(AES_DEC_PREKEYED) +#define is_box(x) isbox[(x)] +#endif +#define gfm2_sb(x) gfm2_sbox[(x)] +#define gfm3_sb(x) gfm3_sbox[(x)] +#if defined(AES_DEC_PREKEYED) +#define gfm_9(x) gfmul_9[(x)] +#define gfm_b(x) gfmul_b[(x)] +#define gfm_d(x) gfmul_d[(x)] +#define gfm_e(x) gfmul_e[(x)] #endif #else -/* this is the high bit of x right shifted by 1 */ -/* position. Since the starting polynomial has */ -/* 9 bits (0x11b), this right shift keeps the */ -/* values of all top bits within a byte */ - -static uint8_t hibit(const uint8_t x) -{ uint8_t r = (uint8_t)((x >> 1) | (x >> 2)); - - r |= (r >> 2); - r |= (r >> 4); - return (r + 1) >> 1; -} - -/* return the inverse of the finite field element x */ - -static uint8_t gf_inv(const uint8_t x) -{ uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; - - if(x < 2) - return x; - - for( ; ; ) - { - if(n1) - while(n2 >= n1) /* divide polynomial p2 by p1 */ - { - n2 /= n1; /* shift smaller polynomial left */ - p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ - v2 ^= (v1 * n2); /* shift accumulated value and */ - n2 = hibit(p2); /* add into result */ - } - else - return v1; - - if(n2) /* repeat with values swapped */ - while(n1 >= n2) - { - n1 /= n2; - p1 ^= p2 * n1; - v1 ^= v2 * n1; - n1 = hibit(p1); - } - else - return v2; - } -} - -/* The forward and inverse affine transformations used in the S-box */ -uint8_t fwd_affine(const uint8_t x) -{ -#if defined( HAVE_UINT_32T ) - uint32_t w = x; - w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); - return 0x63 ^ ((w ^ (w >> 8)) & 0xff); + /* this is the high bit of x right shifted by 1 */ + /* position. Since the starting polynomial has */ + /* 9 bits (0x11b), this right shift keeps the */ + /* values of all top bits within a byte */ + + static uint8_t hibit(const uint8_t x) + { + uint8_t r = (uint8_t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; + } + + /* return the inverse of the finite field element x */ + + static uint8_t gf_inv(const uint8_t x) + { + uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if (x < 2) + return x; + + for (;;) + { + if (n1) + while (n2 >= n1) /* divide polynomial p2 by p1 */ + { + n2 /= n1; /* shift smaller polynomial left */ + p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ + v2 ^= (v1 * n2); /* shift accumulated value and */ + n2 = hibit(p2); /* add into result */ + } + else + return v1; + + if (n2) /* repeat with values swapped */ + while (n1 >= n2) + { + n1 /= n2; + p1 ^= p2 * n1; + v1 ^= v2 * n1; + n1 = hibit(p1); + } + else + return v2; + } + } + + /* The forward and inverse affine transformations used in the S-box */ + uint8_t fwd_affine(const uint8_t x) + { +#if defined(HAVE_UINT_32T) + uint32_t w = x; + w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); + return 0x63 ^ ((w ^ (w >> 8)) & 0xff); #else - return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) - ^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4); + return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) ^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4); #endif -} + } -uint8_t inv_affine(const uint8_t x) -{ -#if defined( HAVE_UINT_32T ) - uint32_t w = x; - w = (w << 1) ^ (w << 3) ^ (w << 6); - return 0x05 ^ ((w ^ (w >> 8)) & 0xff); + uint8_t inv_affine(const uint8_t x) + { +#if defined(HAVE_UINT_32T) + uint32_t w = x; + w = (w << 1) ^ (w << 3) ^ (w << 6); + return 0x05 ^ ((w ^ (w >> 8)) & 0xff); #else - return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) - ^ (x >> 7) ^ (x >> 5) ^ (x >> 2); + return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) ^ (x >> 7) ^ (x >> 5) ^ (x >> 2); #endif -} + } -#define s_box(x) fwd_affine(gf_inv(x)) -#define is_box(x) gf_inv(inv_affine(x)) +#define s_box(x) fwd_affine(gf_inv(x)) +#define is_box(x) gf_inv(inv_affine(x)) #define gfm2_sb(x) f2(s_box(x)) #define gfm3_sb(x) f3(s_box(x)) -#define gfm_9(x) f9(x) -#define gfm_b(x) fb(x) -#define gfm_d(x) fd(x) -#define gfm_e(x) fe(x) +#define gfm_9(x) f9(x) +#define gfm_b(x) fb(x) +#define gfm_d(x) fd(x) +#define gfm_e(x) fe(x) #endif -#if defined( HAVE_MEMCPY ) -# define block_copy_nn(d, s, l) memcpy(d, s, l) -# define block_copy(d, s) memcpy(d, s, N_BLOCK) +#if defined(HAVE_MEMCPY) +#define block_copy_nn(d, s, l) memcpy(d, s, l) +#define block_copy(d, s) memcpy(d, s, N_BLOCK) #else -# define block_copy_nn(d, s, l) copy_block_nn(d, s, l) -# define block_copy(d, s) copy_block(d, s) +#define block_copy_nn(d, s, l) copy_block_nn(d, s, l) +#define block_copy(d, s) copy_block(d, s) #endif -static void copy_block( void *d, const void *s ) -{ -#if defined( HAVE_UINT_32T ) - ((uint32_t*)d)[ 0] = ((uint32_t*)s)[ 0]; - ((uint32_t*)d)[ 1] = ((uint32_t*)s)[ 1]; - ((uint32_t*)d)[ 2] = ((uint32_t*)s)[ 2]; - ((uint32_t*)d)[ 3] = ((uint32_t*)s)[ 3]; + static void copy_block(void *d, const void *s) + { +#if defined(HAVE_UINT_32T) + ((uint32_t *)d)[0] = ((uint32_t *)s)[0]; + ((uint32_t *)d)[1] = ((uint32_t *)s)[1]; + ((uint32_t *)d)[2] = ((uint32_t *)s)[2]; + ((uint32_t *)d)[3] = ((uint32_t *)s)[3]; #else - ((uint8_t*)d)[ 0] = ((uint8_t*)s)[ 0]; - ((uint8_t*)d)[ 1] = ((uint8_t*)s)[ 1]; - ((uint8_t*)d)[ 2] = ((uint8_t*)s)[ 2]; - ((uint8_t*)d)[ 3] = ((uint8_t*)s)[ 3]; - ((uint8_t*)d)[ 4] = ((uint8_t*)s)[ 4]; - ((uint8_t*)d)[ 5] = ((uint8_t*)s)[ 5]; - ((uint8_t*)d)[ 6] = ((uint8_t*)s)[ 6]; - ((uint8_t*)d)[ 7] = ((uint8_t*)s)[ 7]; - ((uint8_t*)d)[ 8] = ((uint8_t*)s)[ 8]; - ((uint8_t*)d)[ 9] = ((uint8_t*)s)[ 9]; - ((uint8_t*)d)[10] = ((uint8_t*)s)[10]; - ((uint8_t*)d)[11] = ((uint8_t*)s)[11]; - ((uint8_t*)d)[12] = ((uint8_t*)s)[12]; - ((uint8_t*)d)[13] = ((uint8_t*)s)[13]; - ((uint8_t*)d)[14] = ((uint8_t*)s)[14]; - ((uint8_t*)d)[15] = ((uint8_t*)s)[15]; -#endif -} - -static void copy_block_nn( uint8_t * d, const uint8_t *s, uint8_t nn ) -{ - while( nn-- ) - //*((uint8_t*)d)++ = *((uint8_t*)s)++; - *d++ = *s++; -} - -static void xor_block( void *d, const void *s ) -{ -#if defined( HAVE_UINT_32T ) - ((uint32_t*)d)[ 0] ^= ((uint32_t*)s)[ 0]; - ((uint32_t*)d)[ 1] ^= ((uint32_t*)s)[ 1]; - ((uint32_t*)d)[ 2] ^= ((uint32_t*)s)[ 2]; - ((uint32_t*)d)[ 3] ^= ((uint32_t*)s)[ 3]; + ((uint8_t *)d)[0] = ((uint8_t *)s)[0]; + ((uint8_t *)d)[1] = ((uint8_t *)s)[1]; + ((uint8_t *)d)[2] = ((uint8_t *)s)[2]; + ((uint8_t *)d)[3] = ((uint8_t *)s)[3]; + ((uint8_t *)d)[4] = ((uint8_t *)s)[4]; + ((uint8_t *)d)[5] = ((uint8_t *)s)[5]; + ((uint8_t *)d)[6] = ((uint8_t *)s)[6]; + ((uint8_t *)d)[7] = ((uint8_t *)s)[7]; + ((uint8_t *)d)[8] = ((uint8_t *)s)[8]; + ((uint8_t *)d)[9] = ((uint8_t *)s)[9]; + ((uint8_t *)d)[10] = ((uint8_t *)s)[10]; + ((uint8_t *)d)[11] = ((uint8_t *)s)[11]; + ((uint8_t *)d)[12] = ((uint8_t *)s)[12]; + ((uint8_t *)d)[13] = ((uint8_t *)s)[13]; + ((uint8_t *)d)[14] = ((uint8_t *)s)[14]; + ((uint8_t *)d)[15] = ((uint8_t *)s)[15]; +#endif + } + + static void copy_block_nn(uint8_t *d, const uint8_t *s, uint8_t nn) + { + while (nn--) + //*((uint8_t*)d)++ = *((uint8_t*)s)++; + *d++ = *s++; + } + + static void xor_block(void *d, const void *s) + { +#if defined(HAVE_UINT_32T) + ((uint32_t *)d)[0] ^= ((uint32_t *)s)[0]; + ((uint32_t *)d)[1] ^= ((uint32_t *)s)[1]; + ((uint32_t *)d)[2] ^= ((uint32_t *)s)[2]; + ((uint32_t *)d)[3] ^= ((uint32_t *)s)[3]; #else - ((uint8_t*)d)[ 0] ^= ((uint8_t*)s)[ 0]; - ((uint8_t*)d)[ 1] ^= ((uint8_t*)s)[ 1]; - ((uint8_t*)d)[ 2] ^= ((uint8_t*)s)[ 2]; - ((uint8_t*)d)[ 3] ^= ((uint8_t*)s)[ 3]; - ((uint8_t*)d)[ 4] ^= ((uint8_t*)s)[ 4]; - ((uint8_t*)d)[ 5] ^= ((uint8_t*)s)[ 5]; - ((uint8_t*)d)[ 6] ^= ((uint8_t*)s)[ 6]; - ((uint8_t*)d)[ 7] ^= ((uint8_t*)s)[ 7]; - ((uint8_t*)d)[ 8] ^= ((uint8_t*)s)[ 8]; - ((uint8_t*)d)[ 9] ^= ((uint8_t*)s)[ 9]; - ((uint8_t*)d)[10] ^= ((uint8_t*)s)[10]; - ((uint8_t*)d)[11] ^= ((uint8_t*)s)[11]; - ((uint8_t*)d)[12] ^= ((uint8_t*)s)[12]; - ((uint8_t*)d)[13] ^= ((uint8_t*)s)[13]; - ((uint8_t*)d)[14] ^= ((uint8_t*)s)[14]; - ((uint8_t*)d)[15] ^= ((uint8_t*)s)[15]; -#endif -} - -static void copy_and_key( void *d, const void *s, const void *k ) -{ -#if defined( HAVE_UINT_32T ) - ((uint32_t*)d)[ 0] = ((uint32_t*)s)[ 0] ^ ((uint32_t*)k)[ 0]; - ((uint32_t*)d)[ 1] = ((uint32_t*)s)[ 1] ^ ((uint32_t*)k)[ 1]; - ((uint32_t*)d)[ 2] = ((uint32_t*)s)[ 2] ^ ((uint32_t*)k)[ 2]; - ((uint32_t*)d)[ 3] = ((uint32_t*)s)[ 3] ^ ((uint32_t*)k)[ 3]; + ((uint8_t *)d)[0] ^= ((uint8_t *)s)[0]; + ((uint8_t *)d)[1] ^= ((uint8_t *)s)[1]; + ((uint8_t *)d)[2] ^= ((uint8_t *)s)[2]; + ((uint8_t *)d)[3] ^= ((uint8_t *)s)[3]; + ((uint8_t *)d)[4] ^= ((uint8_t *)s)[4]; + ((uint8_t *)d)[5] ^= ((uint8_t *)s)[5]; + ((uint8_t *)d)[6] ^= ((uint8_t *)s)[6]; + ((uint8_t *)d)[7] ^= ((uint8_t *)s)[7]; + ((uint8_t *)d)[8] ^= ((uint8_t *)s)[8]; + ((uint8_t *)d)[9] ^= ((uint8_t *)s)[9]; + ((uint8_t *)d)[10] ^= ((uint8_t *)s)[10]; + ((uint8_t *)d)[11] ^= ((uint8_t *)s)[11]; + ((uint8_t *)d)[12] ^= ((uint8_t *)s)[12]; + ((uint8_t *)d)[13] ^= ((uint8_t *)s)[13]; + ((uint8_t *)d)[14] ^= ((uint8_t *)s)[14]; + ((uint8_t *)d)[15] ^= ((uint8_t *)s)[15]; +#endif + } + + static void copy_and_key(void *d, const void *s, const void *k) + { +#if defined(HAVE_UINT_32T) + ((uint32_t *)d)[0] = ((uint32_t *)s)[0] ^ ((uint32_t *)k)[0]; + ((uint32_t *)d)[1] = ((uint32_t *)s)[1] ^ ((uint32_t *)k)[1]; + ((uint32_t *)d)[2] = ((uint32_t *)s)[2] ^ ((uint32_t *)k)[2]; + ((uint32_t *)d)[3] = ((uint32_t *)s)[3] ^ ((uint32_t *)k)[3]; #elif 1 - ((uint8_t*)d)[ 0] = ((uint8_t*)s)[ 0] ^ ((uint8_t*)k)[ 0]; - ((uint8_t*)d)[ 1] = ((uint8_t*)s)[ 1] ^ ((uint8_t*)k)[ 1]; - ((uint8_t*)d)[ 2] = ((uint8_t*)s)[ 2] ^ ((uint8_t*)k)[ 2]; - ((uint8_t*)d)[ 3] = ((uint8_t*)s)[ 3] ^ ((uint8_t*)k)[ 3]; - ((uint8_t*)d)[ 4] = ((uint8_t*)s)[ 4] ^ ((uint8_t*)k)[ 4]; - ((uint8_t*)d)[ 5] = ((uint8_t*)s)[ 5] ^ ((uint8_t*)k)[ 5]; - ((uint8_t*)d)[ 6] = ((uint8_t*)s)[ 6] ^ ((uint8_t*)k)[ 6]; - ((uint8_t*)d)[ 7] = ((uint8_t*)s)[ 7] ^ ((uint8_t*)k)[ 7]; - ((uint8_t*)d)[ 8] = ((uint8_t*)s)[ 8] ^ ((uint8_t*)k)[ 8]; - ((uint8_t*)d)[ 9] = ((uint8_t*)s)[ 9] ^ ((uint8_t*)k)[ 9]; - ((uint8_t*)d)[10] = ((uint8_t*)s)[10] ^ ((uint8_t*)k)[10]; - ((uint8_t*)d)[11] = ((uint8_t*)s)[11] ^ ((uint8_t*)k)[11]; - ((uint8_t*)d)[12] = ((uint8_t*)s)[12] ^ ((uint8_t*)k)[12]; - ((uint8_t*)d)[13] = ((uint8_t*)s)[13] ^ ((uint8_t*)k)[13]; - ((uint8_t*)d)[14] = ((uint8_t*)s)[14] ^ ((uint8_t*)k)[14]; - ((uint8_t*)d)[15] = ((uint8_t*)s)[15] ^ ((uint8_t*)k)[15]; + ((uint8_t *)d)[0] = ((uint8_t *)s)[0] ^ ((uint8_t *)k)[0]; + ((uint8_t *)d)[1] = ((uint8_t *)s)[1] ^ ((uint8_t *)k)[1]; + ((uint8_t *)d)[2] = ((uint8_t *)s)[2] ^ ((uint8_t *)k)[2]; + ((uint8_t *)d)[3] = ((uint8_t *)s)[3] ^ ((uint8_t *)k)[3]; + ((uint8_t *)d)[4] = ((uint8_t *)s)[4] ^ ((uint8_t *)k)[4]; + ((uint8_t *)d)[5] = ((uint8_t *)s)[5] ^ ((uint8_t *)k)[5]; + ((uint8_t *)d)[6] = ((uint8_t *)s)[6] ^ ((uint8_t *)k)[6]; + ((uint8_t *)d)[7] = ((uint8_t *)s)[7] ^ ((uint8_t *)k)[7]; + ((uint8_t *)d)[8] = ((uint8_t *)s)[8] ^ ((uint8_t *)k)[8]; + ((uint8_t *)d)[9] = ((uint8_t *)s)[9] ^ ((uint8_t *)k)[9]; + ((uint8_t *)d)[10] = ((uint8_t *)s)[10] ^ ((uint8_t *)k)[10]; + ((uint8_t *)d)[11] = ((uint8_t *)s)[11] ^ ((uint8_t *)k)[11]; + ((uint8_t *)d)[12] = ((uint8_t *)s)[12] ^ ((uint8_t *)k)[12]; + ((uint8_t *)d)[13] = ((uint8_t *)s)[13] ^ ((uint8_t *)k)[13]; + ((uint8_t *)d)[14] = ((uint8_t *)s)[14] ^ ((uint8_t *)k)[14]; + ((uint8_t *)d)[15] = ((uint8_t *)s)[15] ^ ((uint8_t *)k)[15]; #else - block_copy(d, s); - xor_block(d, k); -#endif -} - -static void add_round_key( uint8_t d[N_BLOCK], const uint8_t k[N_BLOCK] ) -{ - xor_block(d, k); -} - -static void shift_sub_rows( uint8_t st[N_BLOCK] ) -{ uint8_t tt; - - st[ 0] = s_box(st[ 0]); st[ 4] = s_box(st[ 4]); - st[ 8] = s_box(st[ 8]); st[12] = s_box(st[12]); - - tt = st[1]; st[ 1] = s_box(st[ 5]); st[ 5] = s_box(st[ 9]); - st[ 9] = s_box(st[13]); st[13] = s_box( tt ); - - tt = st[2]; st[ 2] = s_box(st[10]); st[10] = s_box( tt ); - tt = st[6]; st[ 6] = s_box(st[14]); st[14] = s_box( tt ); - - tt = st[15]; st[15] = s_box(st[11]); st[11] = s_box(st[ 7]); - st[ 7] = s_box(st[ 3]); st[ 3] = s_box( tt ); -} - -#if defined( AES_DEC_PREKEYED ) - -static void inv_shift_sub_rows( uint8_t st[N_BLOCK] ) -{ uint8_t tt; - - st[ 0] = is_box(st[ 0]); st[ 4] = is_box(st[ 4]); - st[ 8] = is_box(st[ 8]); st[12] = is_box(st[12]); - - tt = st[13]; st[13] = is_box(st[9]); st[ 9] = is_box(st[5]); - st[ 5] = is_box(st[1]); st[ 1] = is_box( tt ); - - tt = st[2]; st[ 2] = is_box(st[10]); st[10] = is_box( tt ); - tt = st[6]; st[ 6] = is_box(st[14]); st[14] = is_box( tt ); - - tt = st[3]; st[ 3] = is_box(st[ 7]); st[ 7] = is_box(st[11]); - st[11] = is_box(st[15]); st[15] = is_box( tt ); -} - -#endif - -#if defined( VERSION_1 ) - static void mix_sub_columns( uint8_t dt[N_BLOCK] ) - { uint8_t st[N_BLOCK]; - block_copy(st, dt); + block_copy(d, s); + xor_block(d, k); +#endif + } + + static void add_round_key(uint8_t d[N_BLOCK], const uint8_t k[N_BLOCK]) + { + xor_block(d, k); + } + + static void shift_sub_rows(uint8_t st[N_BLOCK]) + { + uint8_t tt; + + st[0] = s_box(st[0]); + st[4] = s_box(st[4]); + st[8] = s_box(st[8]); + st[12] = s_box(st[12]); + + tt = st[1]; + st[1] = s_box(st[5]); + st[5] = s_box(st[9]); + st[9] = s_box(st[13]); + st[13] = s_box(tt); + + tt = st[2]; + st[2] = s_box(st[10]); + st[10] = s_box(tt); + tt = st[6]; + st[6] = s_box(st[14]); + st[14] = s_box(tt); + + tt = st[15]; + st[15] = s_box(st[11]); + st[11] = s_box(st[7]); + st[7] = s_box(st[3]); + st[3] = s_box(tt); + } + +#if defined(AES_DEC_PREKEYED) + + static void inv_shift_sub_rows(uint8_t st[N_BLOCK]) + { + uint8_t tt; + + st[0] = is_box(st[0]); + st[4] = is_box(st[4]); + st[8] = is_box(st[8]); + st[12] = is_box(st[12]); + + tt = st[13]; + st[13] = is_box(st[9]); + st[9] = is_box(st[5]); + st[5] = is_box(st[1]); + st[1] = is_box(tt); + + tt = st[2]; + st[2] = is_box(st[10]); + st[10] = is_box(tt); + tt = st[6]; + st[6] = is_box(st[14]); + st[14] = is_box(tt); + + tt = st[3]; + st[3] = is_box(st[7]); + st[7] = is_box(st[11]); + st[11] = is_box(st[15]); + st[15] = is_box(tt); + } + +#endif + +#if defined(VERSION_1) + static void mix_sub_columns(uint8_t dt[N_BLOCK]) + { + uint8_t st[N_BLOCK]; + block_copy(st, dt); #else - static void mix_sub_columns( uint8_t dt[N_BLOCK], uint8_t st[N_BLOCK] ) - { -#endif - dt[ 0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]); - dt[ 1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]); - dt[ 2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]); - dt[ 3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]); - - dt[ 4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]); - dt[ 5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]); - dt[ 6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]); - dt[ 7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]); - - dt[ 8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]); - dt[ 9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]); - dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]); - dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]); - - dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]); - dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]); - dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]); - dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]); - } - -#if defined( AES_DEC_PREKEYED ) - -#if defined( VERSION_1 ) - static void inv_mix_sub_columns( uint8_t dt[N_BLOCK] ) - { uint8_t st[N_BLOCK]; - block_copy(st, dt); + static void mix_sub_columns(uint8_t dt[N_BLOCK], uint8_t st[N_BLOCK]) + { +#endif + dt[0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]); + dt[1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]); + dt[2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]); + dt[3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]); + + dt[4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]); + dt[5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]); + dt[6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]); + dt[7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]); + + dt[8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]); + dt[9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]); + dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]); + dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]); + + dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]); + dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]); + dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]); + dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]); + } + +#if defined(AES_DEC_PREKEYED) + +#if defined(VERSION_1) + static void inv_mix_sub_columns(uint8_t dt[N_BLOCK]) + { + uint8_t st[N_BLOCK]; + block_copy(st, dt); #else - static void inv_mix_sub_columns( uint8_t dt[N_BLOCK], uint8_t st[N_BLOCK] ) - { -#endif - dt[ 0] = is_box(gfm_e(st[ 0]) ^ gfm_b(st[ 1]) ^ gfm_d(st[ 2]) ^ gfm_9(st[ 3])); - dt[ 5] = is_box(gfm_9(st[ 0]) ^ gfm_e(st[ 1]) ^ gfm_b(st[ 2]) ^ gfm_d(st[ 3])); - dt[10] = is_box(gfm_d(st[ 0]) ^ gfm_9(st[ 1]) ^ gfm_e(st[ 2]) ^ gfm_b(st[ 3])); - dt[15] = is_box(gfm_b(st[ 0]) ^ gfm_d(st[ 1]) ^ gfm_9(st[ 2]) ^ gfm_e(st[ 3])); - - dt[ 4] = is_box(gfm_e(st[ 4]) ^ gfm_b(st[ 5]) ^ gfm_d(st[ 6]) ^ gfm_9(st[ 7])); - dt[ 9] = is_box(gfm_9(st[ 4]) ^ gfm_e(st[ 5]) ^ gfm_b(st[ 6]) ^ gfm_d(st[ 7])); - dt[14] = is_box(gfm_d(st[ 4]) ^ gfm_9(st[ 5]) ^ gfm_e(st[ 6]) ^ gfm_b(st[ 7])); - dt[ 3] = is_box(gfm_b(st[ 4]) ^ gfm_d(st[ 5]) ^ gfm_9(st[ 6]) ^ gfm_e(st[ 7])); - - dt[ 8] = is_box(gfm_e(st[ 8]) ^ gfm_b(st[ 9]) ^ gfm_d(st[10]) ^ gfm_9(st[11])); - dt[13] = is_box(gfm_9(st[ 8]) ^ gfm_e(st[ 9]) ^ gfm_b(st[10]) ^ gfm_d(st[11])); - dt[ 2] = is_box(gfm_d(st[ 8]) ^ gfm_9(st[ 9]) ^ gfm_e(st[10]) ^ gfm_b(st[11])); - dt[ 7] = is_box(gfm_b(st[ 8]) ^ gfm_d(st[ 9]) ^ gfm_9(st[10]) ^ gfm_e(st[11])); - - dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15])); - dt[ 1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15])); - dt[ 6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15])); - dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15])); - } - -#endif - -#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) - -/* Set the cipher key for the pre-keyed version */ - -return_type lora_aes_set_key( const uint8_t key[], length_type keylen, lora_aes_context ctx[1] ) -{ - uint8_t cc, rc, hi; - - switch( keylen ) - { - case 16: - case 24: - case 32: - break; - default: - ctx->rnd = 0; - return ( uint8_t )-1; - } - block_copy_nn(ctx->ksch, key, keylen); - hi = (keylen + 28) << 2; - ctx->rnd = (hi >> 4) - 1; - for( cc = keylen, rc = 1; cc < hi; cc += 4 ) - { uint8_t tt, t0, t1, t2, t3; - - t0 = ctx->ksch[cc - 4]; - t1 = ctx->ksch[cc - 3]; - t2 = ctx->ksch[cc - 2]; - t3 = ctx->ksch[cc - 1]; - if( cc % keylen == 0 ) - { - tt = t0; - t0 = s_box(t1) ^ rc; - t1 = s_box(t2); - t2 = s_box(t3); - t3 = s_box(tt); - rc = f2(rc); - } - else if( keylen > 24 && cc % keylen == 16 ) - { - t0 = s_box(t0); - t1 = s_box(t1); - t2 = s_box(t2); - t3 = s_box(t3); - } - tt = cc - keylen; - ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0; - ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1; - ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2; - ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3; - } - return 0; -} - -#endif - -#if defined( AES_ENC_PREKEYED ) - -/* Encrypt a single block of 16 bytes */ - -return_type lora_aes_encrypt( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], const lora_aes_context ctx[1] ) -{ - if( ctx->rnd ) - { - uint8_t s1[N_BLOCK], r; - copy_and_key( s1, in, ctx->ksch ); - - for( r = 1 ; r < ctx->rnd ; ++r ) -#if defined( VERSION_1 ) - { - mix_sub_columns( s1 ); - add_round_key( s1, ctx->ksch + r * N_BLOCK); - } + static void inv_mix_sub_columns(uint8_t dt[N_BLOCK], uint8_t st[N_BLOCK]) + { +#endif + dt[0] = is_box(gfm_e(st[0]) ^ gfm_b(st[1]) ^ gfm_d(st[2]) ^ gfm_9(st[3])); + dt[5] = is_box(gfm_9(st[0]) ^ gfm_e(st[1]) ^ gfm_b(st[2]) ^ gfm_d(st[3])); + dt[10] = is_box(gfm_d(st[0]) ^ gfm_9(st[1]) ^ gfm_e(st[2]) ^ gfm_b(st[3])); + dt[15] = is_box(gfm_b(st[0]) ^ gfm_d(st[1]) ^ gfm_9(st[2]) ^ gfm_e(st[3])); + + dt[4] = is_box(gfm_e(st[4]) ^ gfm_b(st[5]) ^ gfm_d(st[6]) ^ gfm_9(st[7])); + dt[9] = is_box(gfm_9(st[4]) ^ gfm_e(st[5]) ^ gfm_b(st[6]) ^ gfm_d(st[7])); + dt[14] = is_box(gfm_d(st[4]) ^ gfm_9(st[5]) ^ gfm_e(st[6]) ^ gfm_b(st[7])); + dt[3] = is_box(gfm_b(st[4]) ^ gfm_d(st[5]) ^ gfm_9(st[6]) ^ gfm_e(st[7])); + + dt[8] = is_box(gfm_e(st[8]) ^ gfm_b(st[9]) ^ gfm_d(st[10]) ^ gfm_9(st[11])); + dt[13] = is_box(gfm_9(st[8]) ^ gfm_e(st[9]) ^ gfm_b(st[10]) ^ gfm_d(st[11])); + dt[2] = is_box(gfm_d(st[8]) ^ gfm_9(st[9]) ^ gfm_e(st[10]) ^ gfm_b(st[11])); + dt[7] = is_box(gfm_b(st[8]) ^ gfm_d(st[9]) ^ gfm_9(st[10]) ^ gfm_e(st[11])); + + dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15])); + dt[1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15])); + dt[6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15])); + dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15])); + } + +#endif + +#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED) + + /* Set the cipher key for the pre-keyed version */ + + return_type lora_aes_set_key(const uint8_t key[], length_type keylen, lora_aes_context ctx[1]) + { + uint8_t cc, rc, hi; + + switch (keylen) + { + case 16: + case 24: + case 32: + break; + default: + ctx->rnd = 0; + return (uint8_t)-1; + } + block_copy_nn(ctx->ksch, key, keylen); + hi = (keylen + 28) << 2; + ctx->rnd = (hi >> 4) - 1; + for (cc = keylen, rc = 1; cc < hi; cc += 4) + { + uint8_t tt, t0, t1, t2, t3; + + t0 = ctx->ksch[cc - 4]; + t1 = ctx->ksch[cc - 3]; + t2 = ctx->ksch[cc - 2]; + t3 = ctx->ksch[cc - 1]; + if (cc % keylen == 0) + { + tt = t0; + t0 = s_box(t1) ^ rc; + t1 = s_box(t2); + t2 = s_box(t3); + t3 = s_box(tt); + rc = f2(rc); + } + else if (keylen > 24 && cc % keylen == 16) + { + t0 = s_box(t0); + t1 = s_box(t1); + t2 = s_box(t2); + t3 = s_box(t3); + } + tt = cc - keylen; + ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0; + ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1; + ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2; + ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3; + } + return 0; + } + +#endif + +#if defined(AES_ENC_PREKEYED) + + /* Encrypt a single block of 16 bytes */ + + return_type lora_aes_encrypt(const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], const lora_aes_context ctx[1]) + { + if (ctx->rnd) + { + uint8_t s1[N_BLOCK], r; + copy_and_key(s1, in, ctx->ksch); + + for (r = 1; r < ctx->rnd; ++r) +#if defined(VERSION_1) + { + mix_sub_columns(s1); + add_round_key(s1, ctx->ksch + r * N_BLOCK); + } #else - { uint8_t s2[N_BLOCK]; - mix_sub_columns( s2, s1 ); - copy_and_key( s1, s2, ctx->ksch + r * N_BLOCK); - } -#endif - shift_sub_rows( s1 ); - copy_and_key( out, s1, ctx->ksch + r * N_BLOCK ); - } - else - return ( uint8_t )-1; - return 0; -} - -/* CBC encrypt a number of blocks (input and return an IV) */ - -return_type lora_aes_cbc_encrypt( const uint8_t *in, uint8_t *out, - int32_t n_block, uint8_t iv[N_BLOCK], const lora_aes_context ctx[1] ) -{ - - while(n_block--) - { - xor_block(iv, in); - if(lora_aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - //memcpy(out, iv, N_BLOCK); - block_copy(out, iv); - in += N_BLOCK; - out += N_BLOCK; - } - return EXIT_SUCCESS; -} - -#endif - -#if defined( AES_DEC_PREKEYED ) - -/* Decrypt a single block of 16 bytes */ - -return_type lora_aes_decrypt( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], const lora_aes_context ctx[1] ) -{ - if( ctx->rnd ) - { - uint8_t s1[N_BLOCK], r; - copy_and_key( s1, in, ctx->ksch + ctx->rnd * N_BLOCK ); - inv_shift_sub_rows( s1 ); - - for( r = ctx->rnd ; --r ; ) -#if defined( VERSION_1 ) - { - add_round_key( s1, ctx->ksch + r * N_BLOCK ); - inv_mix_sub_columns( s1 ); - } + { + uint8_t s2[N_BLOCK]; + mix_sub_columns(s2, s1); + copy_and_key(s1, s2, ctx->ksch + r * N_BLOCK); + } +#endif + shift_sub_rows(s1); + copy_and_key(out, s1, ctx->ksch + r * N_BLOCK); + } + else + return (uint8_t)-1; + return 0; + } + + /* CBC encrypt a number of blocks (input and return an IV) */ + + return_type lora_aes_cbc_encrypt(const uint8_t *in, uint8_t *out, + int32_t n_block, uint8_t iv[N_BLOCK], const lora_aes_context ctx[1]) + { + + while (n_block--) + { + xor_block(iv, in); + if (lora_aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + //memcpy(out, iv, N_BLOCK); + block_copy(out, iv); + in += N_BLOCK; + out += N_BLOCK; + } + return EXIT_SUCCESS; + } + +#endif + +#if defined(AES_DEC_PREKEYED) + + /* Decrypt a single block of 16 bytes */ + + return_type lora_aes_decrypt(const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], const lora_aes_context ctx[1]) + { + if (ctx->rnd) + { + uint8_t s1[N_BLOCK], r; + copy_and_key(s1, in, ctx->ksch + ctx->rnd * N_BLOCK); + inv_shift_sub_rows(s1); + + for (r = ctx->rnd; --r;) +#if defined(VERSION_1) + { + add_round_key(s1, ctx->ksch + r * N_BLOCK); + inv_mix_sub_columns(s1); + } #else - { uint8_t s2[N_BLOCK]; - copy_and_key( s2, s1, ctx->ksch + r * N_BLOCK ); - inv_mix_sub_columns( s1, s2 ); - } -#endif - copy_and_key( out, s1, ctx->ksch ); - } - else - return -1; - return 0; -} - -/* CBC decrypt a number of blocks (input and return an IV) */ - -return_type lora_aes_cbc_decrypt( const uint8_t *in, uint8_t *out, - int32_t n_block, uint8_t iv[N_BLOCK], const lora_aes_context ctx[1] ) -{ - while(n_block--) - { uint8_t tmp[N_BLOCK]; - - //memcpy(tmp, in, N_BLOCK); - block_copy(tmp, in); - if(lora_aes_decrypt(in, out, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - xor_block(out, iv); - //memcpy(iv, tmp, N_BLOCK); - block_copy(iv, tmp); - in += N_BLOCK; - out += N_BLOCK; - } - return EXIT_SUCCESS; -} - -#endif - -#if defined( AES_ENC_128_OTFK ) - -/* The 'on the fly' encryption key update for for 128 bit keys */ - -static void update_encrypt_key_128( uint8_t k[N_BLOCK], uint8_t *rc ) -{ uint8_t cc; - - k[0] ^= s_box(k[13]) ^ *rc; - k[1] ^= s_box(k[14]); - k[2] ^= s_box(k[15]); - k[3] ^= s_box(k[12]); - *rc = f2( *rc ); - - for(cc = 4; cc < 16; cc += 4 ) - { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } -} - -/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ - -void lora_aes_encrypt_128( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], - const uint8_t key[N_BLOCK], uint8_t o_key[N_BLOCK] ) -{ uint8_t s1[N_BLOCK], r, rc = 1; - - if(o_key != key) - block_copy( o_key, key ); - copy_and_key( s1, in, o_key ); - - for( r = 1 ; r < 10 ; ++r ) -#if defined( VERSION_1 ) - { - mix_sub_columns( s1 ); - update_encrypt_key_128( o_key, &rc ); - add_round_key( s1, o_key ); - } + { + uint8_t s2[N_BLOCK]; + copy_and_key(s2, s1, ctx->ksch + r * N_BLOCK); + inv_mix_sub_columns(s1, s2); + } +#endif + copy_and_key(out, s1, ctx->ksch); + } + else + return -1; + return 0; + } + + /* CBC decrypt a number of blocks (input and return an IV) */ + + return_type lora_aes_cbc_decrypt(const uint8_t *in, uint8_t *out, + int32_t n_block, uint8_t iv[N_BLOCK], const lora_aes_context ctx[1]) + { + while (n_block--) + { + uint8_t tmp[N_BLOCK]; + + //memcpy(tmp, in, N_BLOCK); + block_copy(tmp, in); + if (lora_aes_decrypt(in, out, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + xor_block(out, iv); + //memcpy(iv, tmp, N_BLOCK); + block_copy(iv, tmp); + in += N_BLOCK; + out += N_BLOCK; + } + return EXIT_SUCCESS; + } + +#endif + +#if defined(AES_ENC_128_OTFK) + + /* The 'on the fly' encryption key update for for 128 bit keys */ + + static void update_encrypt_key_128(uint8_t k[N_BLOCK], uint8_t *rc) + { + uint8_t cc; + + k[0] ^= s_box(k[13]) ^ *rc; + k[1] ^= s_box(k[14]); + k[2] ^= s_box(k[15]); + k[3] ^= s_box(k[12]); + *rc = f2(*rc); + + for (cc = 4; cc < 16; cc += 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + } + + /* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ + + void lora_aes_encrypt_128(const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], + const uint8_t key[N_BLOCK], uint8_t o_key[N_BLOCK]) + { + uint8_t s1[N_BLOCK], r, rc = 1; + + if (o_key != key) + block_copy(o_key, key); + copy_and_key(s1, in, o_key); + + for (r = 1; r < 10; ++r) +#if defined(VERSION_1) + { + mix_sub_columns(s1); + update_encrypt_key_128(o_key, &rc); + add_round_key(s1, o_key); + } #else - { uint8_t s2[N_BLOCK]; - mix_sub_columns( s2, s1 ); - update_encrypt_key_128( o_key, &rc ); - copy_and_key( s1, s2, o_key ); - } -#endif - - shift_sub_rows( s1 ); - update_encrypt_key_128( o_key, &rc ); - copy_and_key( out, s1, o_key ); -} - -#endif - -#if defined( AES_DEC_128_OTFK ) - -/* The 'on the fly' decryption key update for for 128 bit keys */ - -static void update_decrypt_key_128( uint8_t k[N_BLOCK], uint8_t *rc ) -{ uint8_t cc; - - for( cc = 12; cc > 0; cc -= 4 ) - { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } - *rc = d2(*rc); - k[0] ^= s_box(k[13]) ^ *rc; - k[1] ^= s_box(k[14]); - k[2] ^= s_box(k[15]); - k[3] ^= s_box(k[12]); -} - -/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ - -void lora_aes_decrypt_128( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], - const uint8_t key[N_BLOCK], uint8_t o_key[N_BLOCK] ) -{ - uint8_t s1[N_BLOCK], r, rc = 0x6c; - if(o_key != key) - block_copy( o_key, key ); - - copy_and_key( s1, in, o_key ); - inv_shift_sub_rows( s1 ); - - for( r = 10 ; --r ; ) -#if defined( VERSION_1 ) - { - update_decrypt_key_128( o_key, &rc ); - add_round_key( s1, o_key ); - inv_mix_sub_columns( s1 ); - } + { + uint8_t s2[N_BLOCK]; + mix_sub_columns(s2, s1); + update_encrypt_key_128(o_key, &rc); + copy_and_key(s1, s2, o_key); + } +#endif + + shift_sub_rows(s1); + update_encrypt_key_128(o_key, &rc); + copy_and_key(out, s1, o_key); + } + +#endif + +#if defined(AES_DEC_128_OTFK) + + /* The 'on the fly' decryption key update for for 128 bit keys */ + + static void update_decrypt_key_128(uint8_t k[N_BLOCK], uint8_t *rc) + { + uint8_t cc; + + for (cc = 12; cc > 0; cc -= 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + *rc = d2(*rc); + k[0] ^= s_box(k[13]) ^ *rc; + k[1] ^= s_box(k[14]); + k[2] ^= s_box(k[15]); + k[3] ^= s_box(k[12]); + } + + /* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ + + void lora_aes_decrypt_128(const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], + const uint8_t key[N_BLOCK], uint8_t o_key[N_BLOCK]) + { + uint8_t s1[N_BLOCK], r, rc = 0x6c; + if (o_key != key) + block_copy(o_key, key); + + copy_and_key(s1, in, o_key); + inv_shift_sub_rows(s1); + + for (r = 10; --r;) +#if defined(VERSION_1) + { + update_decrypt_key_128(o_key, &rc); + add_round_key(s1, o_key); + inv_mix_sub_columns(s1); + } #else - { uint8_t s2[N_BLOCK]; - update_decrypt_key_128( o_key, &rc ); - copy_and_key( s2, s1, o_key ); - inv_mix_sub_columns( s1, s2 ); - } -#endif - update_decrypt_key_128( o_key, &rc ); - copy_and_key( out, s1, o_key ); -} - -#endif - -#if defined( AES_ENC_256_OTFK ) - -/* The 'on the fly' encryption key update for for 256 bit keys */ - -static void update_encrypt_key_256( uint8_t k[2 * N_BLOCK], uint8_t *rc ) -{ uint8_t cc; - - k[0] ^= s_box(k[29]) ^ *rc; - k[1] ^= s_box(k[30]); - k[2] ^= s_box(k[31]); - k[3] ^= s_box(k[28]); - *rc = f2( *rc ); - - for(cc = 4; cc < 16; cc += 4) - { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } - - k[16] ^= s_box(k[12]); - k[17] ^= s_box(k[13]); - k[18] ^= s_box(k[14]); - k[19] ^= s_box(k[15]); - - for( cc = 20; cc < 32; cc += 4 ) - { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } -} - -/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */ - -void lora_aes_encrypt_256( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], - const uint8_t key[2 * N_BLOCK], uint8_t o_key[2 * N_BLOCK] ) -{ - uint8_t s1[N_BLOCK], r, rc = 1; - if(o_key != key) - { - block_copy( o_key, key ); - block_copy( o_key + 16, key + 16 ); - } - copy_and_key( s1, in, o_key ); - - for( r = 1 ; r < 14 ; ++r ) -#if defined( VERSION_1 ) - { - mix_sub_columns(s1); - if( r & 1 ) - add_round_key( s1, o_key + 16 ); - else - { - update_encrypt_key_256( o_key, &rc ); - add_round_key( s1, o_key ); - } - } + { + uint8_t s2[N_BLOCK]; + update_decrypt_key_128(o_key, &rc); + copy_and_key(s2, s1, o_key); + inv_mix_sub_columns(s1, s2); + } +#endif + update_decrypt_key_128(o_key, &rc); + copy_and_key(out, s1, o_key); + } + +#endif + +#if defined(AES_ENC_256_OTFK) + + /* The 'on the fly' encryption key update for for 256 bit keys */ + + static void update_encrypt_key_256(uint8_t k[2 * N_BLOCK], uint8_t *rc) + { + uint8_t cc; + + k[0] ^= s_box(k[29]) ^ *rc; + k[1] ^= s_box(k[30]); + k[2] ^= s_box(k[31]); + k[3] ^= s_box(k[28]); + *rc = f2(*rc); + + for (cc = 4; cc < 16; cc += 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + k[16] ^= s_box(k[12]); + k[17] ^= s_box(k[13]); + k[18] ^= s_box(k[14]); + k[19] ^= s_box(k[15]); + + for (cc = 20; cc < 32; cc += 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + } + + /* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */ + + void lora_aes_encrypt_256(const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], + const uint8_t key[2 * N_BLOCK], uint8_t o_key[2 * N_BLOCK]) + { + uint8_t s1[N_BLOCK], r, rc = 1; + if (o_key != key) + { + block_copy(o_key, key); + block_copy(o_key + 16, key + 16); + } + copy_and_key(s1, in, o_key); + + for (r = 1; r < 14; ++r) +#if defined(VERSION_1) + { + mix_sub_columns(s1); + if (r & 1) + add_round_key(s1, o_key + 16); + else + { + update_encrypt_key_256(o_key, &rc); + add_round_key(s1, o_key); + } + } #else - { uint8_t s2[N_BLOCK]; - mix_sub_columns( s2, s1 ); - if( r & 1 ) - copy_and_key( s1, s2, o_key + 16 ); - else - { - update_encrypt_key_256( o_key, &rc ); - copy_and_key( s1, s2, o_key ); - } - } -#endif - - shift_sub_rows( s1 ); - update_encrypt_key_256( o_key, &rc ); - copy_and_key( out, s1, o_key ); -} - -#endif - -#if defined( AES_DEC_256_OTFK ) - -/* The 'on the fly' encryption key update for for 256 bit keys */ - -static void update_decrypt_key_256( uint8_t k[2 * N_BLOCK], uint8_t *rc ) -{ uint8_t cc; - - for(cc = 28; cc > 16; cc -= 4) - { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } - - k[16] ^= s_box(k[12]); - k[17] ^= s_box(k[13]); - k[18] ^= s_box(k[14]); - k[19] ^= s_box(k[15]); - - for(cc = 12; cc > 0; cc -= 4) - { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } - - *rc = d2(*rc); - k[0] ^= s_box(k[29]) ^ *rc; - k[1] ^= s_box(k[30]); - k[2] ^= s_box(k[31]); - k[3] ^= s_box(k[28]); -} - -/* Decrypt a single block of 16 bytes with 'on the fly' + { + uint8_t s2[N_BLOCK]; + mix_sub_columns(s2, s1); + if (r & 1) + copy_and_key(s1, s2, o_key + 16); + else + { + update_encrypt_key_256(o_key, &rc); + copy_and_key(s1, s2, o_key); + } + } +#endif + + shift_sub_rows(s1); + update_encrypt_key_256(o_key, &rc); + copy_and_key(out, s1, o_key); + } + +#endif + +#if defined(AES_DEC_256_OTFK) + + /* The 'on the fly' encryption key update for for 256 bit keys */ + + static void update_decrypt_key_256(uint8_t k[2 * N_BLOCK], uint8_t *rc) + { + uint8_t cc; + + for (cc = 28; cc > 16; cc -= 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + k[16] ^= s_box(k[12]); + k[17] ^= s_box(k[13]); + k[18] ^= s_box(k[14]); + k[19] ^= s_box(k[15]); + + for (cc = 12; cc > 0; cc -= 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + *rc = d2(*rc); + k[0] ^= s_box(k[29]) ^ *rc; + k[1] ^= s_box(k[30]); + k[2] ^= s_box(k[31]); + k[3] ^= s_box(k[28]); + } + + /* Decrypt a single block of 16 bytes with 'on the fly' 256 bit keying */ -void lora_aes_decrypt_256( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], - const uint8_t key[2 * N_BLOCK], uint8_t o_key[2 * N_BLOCK] ) -{ - uint8_t s1[N_BLOCK], r, rc = 0x80; - - if(o_key != key) - { - block_copy( o_key, key ); - block_copy( o_key + 16, key + 16 ); - } - - copy_and_key( s1, in, o_key ); - inv_shift_sub_rows( s1 ); - - for( r = 14 ; --r ; ) -#if defined( VERSION_1 ) - { - if( ( r & 1 ) ) - { - update_decrypt_key_256( o_key, &rc ); - add_round_key( s1, o_key + 16 ); - } - else - add_round_key( s1, o_key ); - inv_mix_sub_columns( s1 ); - } + void lora_aes_decrypt_256(const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], + const uint8_t key[2 * N_BLOCK], uint8_t o_key[2 * N_BLOCK]) + { + uint8_t s1[N_BLOCK], r, rc = 0x80; + + if (o_key != key) + { + block_copy(o_key, key); + block_copy(o_key + 16, key + 16); + } + + copy_and_key(s1, in, o_key); + inv_shift_sub_rows(s1); + + for (r = 14; --r;) +#if defined(VERSION_1) + { + if ((r & 1)) + { + update_decrypt_key_256(o_key, &rc); + add_round_key(s1, o_key + 16); + } + else + add_round_key(s1, o_key); + inv_mix_sub_columns(s1); + } #else - { uint8_t s2[N_BLOCK]; - if( ( r & 1 ) ) - { - update_decrypt_key_256( o_key, &rc ); - copy_and_key( s2, s1, o_key + 16 ); - } - else - copy_and_key( s2, s1, o_key ); - inv_mix_sub_columns( s1, s2 ); - } -#endif - copy_and_key( out, s1, o_key ); -} + { + uint8_t s2[N_BLOCK]; + if ((r & 1)) + { + update_decrypt_key_256(o_key, &rc); + copy_and_key(s2, s1, o_key + 16); + } + else + copy_and_key(s2, s1, o_key); + inv_mix_sub_columns(s1, s2); + } +#endif + copy_and_key(out, s1, o_key); + } #endif }; \ No newline at end of file diff --git a/src/system/crypto/aes.h b/src/system/crypto/aes.h index 45a404d..a228922 100644 --- a/src/system/crypto/aes.h +++ b/src/system/crypto/aes.h @@ -31,45 +31,47 @@ #ifndef AES_H #define AES_H -extern "C" { +extern "C" +{ #if 1 -# define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */ +#define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */ #endif #if 0 -# define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */ +#define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */ #endif #if 0 -# define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */ +#define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */ #endif #if 0 -# define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */ +#define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */ #endif #if 0 -# define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */ +#define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */ #endif #if 0 -# define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */ +#define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */ #endif -#define N_ROW 4 -#define N_COL 4 -#define N_BLOCK (N_ROW * N_COL) -#define N_MAX_ROUNDS 14 +#define N_ROW 4 +#define N_COL 4 +#define N_BLOCK (N_ROW * N_COL) +#define N_MAX_ROUNDS 14 -typedef uint8_t return_type; + typedef uint8_t return_type; -/* Warning: The key length for 256 bit keys overflows a byte + /* Warning: The key length for 256 bit keys overflows a byte (see comment below) */ -typedef uint8_t length_type; + typedef uint8_t length_type; -typedef struct -{ uint8_t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK]; - uint8_t rnd; -} lora_aes_context; + typedef struct + { + uint8_t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK]; + uint8_t rnd; + } lora_aes_context; -/* The following calls are for a precomputed key schedule + /* The following calls are for a precomputed key schedule NOTE: If the length_type used for the key length is an unsigned 8-bit character, a key length of 256 bits must @@ -77,40 +79,40 @@ typedef struct 128, 192, 16, 24 and 32). */ -#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) +#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED) -return_type lora_aes_set_key( const uint8_t key[], - length_type keylen, - lora_aes_context ctx[1] ); + return_type lora_aes_set_key(const uint8_t key[], + length_type keylen, + lora_aes_context ctx[1]); #endif -#if defined( AES_ENC_PREKEYED ) +#if defined(AES_ENC_PREKEYED) -return_type lora_aes_encrypt( const uint8_t in[N_BLOCK], - uint8_t out[N_BLOCK], - const lora_aes_context ctx[1] ); + return_type lora_aes_encrypt(const uint8_t in[N_BLOCK], + uint8_t out[N_BLOCK], + const lora_aes_context ctx[1]); -return_type lora_aes_cbc_encrypt( const uint8_t *in, - uint8_t *out, - int32_t n_block, - uint8_t iv[N_BLOCK], - const lora_aes_context ctx[1] ); + return_type lora_aes_cbc_encrypt(const uint8_t *in, + uint8_t *out, + int32_t n_block, + uint8_t iv[N_BLOCK], + const lora_aes_context ctx[1]); #endif -#if defined( AES_DEC_PREKEYED ) +#if defined(AES_DEC_PREKEYED) -return_type lora_aes_decrypt( const uint8_t in[N_BLOCK], - uint8_t out[N_BLOCK], - const lora_aes_context ctx[1] ); + return_type lora_aes_decrypt(const uint8_t in[N_BLOCK], + uint8_t out[N_BLOCK], + const lora_aes_context ctx[1]); -return_type lora_aes_cbc_decrypt( const uint8_t *in, - uint8_t *out, - int32_t n_block, - uint8_t iv[N_BLOCK], - const lora_aes_context ctx[1] ); + return_type lora_aes_cbc_decrypt(const uint8_t *in, + uint8_t *out, + int32_t n_block, + uint8_t iv[N_BLOCK], + const lora_aes_context ctx[1]); #endif -/* The following calls are for 'on the fly' keying. In this case the + /* The following calls are for 'on the fly' keying. In this case the encryption and decryption keys are different. The encryption subroutines take a key in an array of bytes in @@ -130,32 +132,32 @@ return_type lora_aes_cbc_decrypt( const uint8_t *in, modes. */ -#if defined( AES_ENC_128_OTFK ) -void lora_aes_encrypt_128( const uint8_t in[N_BLOCK], - uint8_t out[N_BLOCK], - const uint8_t key[N_BLOCK], - uint8_t o_key[N_BLOCK] ); +#if defined(AES_ENC_128_OTFK) + void lora_aes_encrypt_128(const uint8_t in[N_BLOCK], + uint8_t out[N_BLOCK], + const uint8_t key[N_BLOCK], + uint8_t o_key[N_BLOCK]); #endif -#if defined( AES_DEC_128_OTFK ) -void lora_aes_decrypt_128( const uint8_t in[N_BLOCK], - uint8_t out[N_BLOCK], - const uint8_t key[N_BLOCK], - uint8_t o_key[N_BLOCK] ); +#if defined(AES_DEC_128_OTFK) + void lora_aes_decrypt_128(const uint8_t in[N_BLOCK], + uint8_t out[N_BLOCK], + const uint8_t key[N_BLOCK], + uint8_t o_key[N_BLOCK]); #endif -#if defined( AES_ENC_256_OTFK ) -void lora_aes_encrypt_256( const uint8_t in[N_BLOCK], - uint8_t out[N_BLOCK], - const uint8_t key[2 * N_BLOCK], - uint8_t o_key[2 * N_BLOCK] ); +#if defined(AES_ENC_256_OTFK) + void lora_aes_encrypt_256(const uint8_t in[N_BLOCK], + uint8_t out[N_BLOCK], + const uint8_t key[2 * N_BLOCK], + uint8_t o_key[2 * N_BLOCK]); #endif -#if defined( AES_DEC_256_OTFK ) -void lora_aes_decrypt_256( const uint8_t in[N_BLOCK], - uint8_t out[N_BLOCK], - const uint8_t key[2 * N_BLOCK], - uint8_t o_key[2 * N_BLOCK] ); +#if defined(AES_DEC_256_OTFK) + void lora_aes_decrypt_256(const uint8_t in[N_BLOCK], + uint8_t out[N_BLOCK], + const uint8_t key[2 * N_BLOCK], + uint8_t o_key[2 * N_BLOCK]); #endif }; diff --git a/src/system/crypto/cmac.cpp b/src/system/crypto/cmac.cpp index 785fb20..3835ab0 100644 --- a/src/system/crypto/cmac.cpp +++ b/src/system/crypto/cmac.cpp @@ -39,115 +39,126 @@ DEALINGS WITH THE SOFTWARE #include "cmac.h" #include "system/utilities.h" -extern "C" { -#define LSHIFT(v, r) do { \ - int32_t i; \ - for (i = 0; i < 15; i++) \ - (r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7; \ - (r)[15] = (v)[15] << 1; \ - } while (0) - -#define XOR(v, r) do { \ - int32_t i; \ - for (i = 0; i < 16; i++) \ - { \ - (r)[i] = (r)[i] ^ (v)[i]; \ - } \ - } while (0) \ - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -void AES_CMAC_Init(AES_CMAC_CTX *ctx) -{ - memset1(ctx->X, 0, sizeof ctx->X); - ctx->M_n = 0; - memset1(ctx->rijndael.ksch, '\0', 240); -} - -void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const uint8_t key[AES_CMAC_KEY_LENGTH]) +extern "C" { - //rijndael_set_key_enc_only(&ctx->rijndael, key, 128); - lora_aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael); -} - -void AES_CMAC_Update(AES_CMAC_CTX *ctx, const uint8_t *data, uint32_t len) -{ - uint32_t mlen; - uint8_t in[16]; - - if (ctx->M_n > 0) { - mlen = MIN(16 - ctx->M_n, len); - memcpy1(ctx->M_last + ctx->M_n, data, mlen); - ctx->M_n += mlen; - if (ctx->M_n < 16 || len == mlen) - return; - XOR(ctx->M_last, ctx->X); - //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X); - lora_aes_encrypt( ctx->X, ctx->X, &ctx->rijndael); - data += mlen; - len -= mlen; - } - while (len > 16) { /* not last block */ - - XOR(data, ctx->X); - //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X); - - memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten - lora_aes_encrypt( in, in, &ctx->rijndael); - memcpy1(&ctx->X[0], in, 16); - - data += 16; - len -= 16; - } - /* potential last block, save it */ - memcpy1(ctx->M_last, data, len); - ctx->M_n = len; -} - -void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx) -{ - uint8_t K[16]; - uint8_t in[16]; - /* generate subkey K1 */ - memset1(K, '\0', 16); - - //rijndael_encrypt(&ctx->rijndael, K, K); +#define LSHIFT(v, r) \ + do \ + { \ + int32_t i; \ + for (i = 0; i < 15; i++) \ + (r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7; \ + (r)[15] = (v)[15] << 1; \ + } while (0) + +#define XOR(v, r) \ + do \ + { \ + int32_t i; \ + for (i = 0; i < 16; i++) \ + { \ + (r)[i] = (r)[i] ^ (v)[i]; \ + } \ + } while (0) - lora_aes_encrypt( K, K, &ctx->rijndael); - - if (K[0] & 0x80) { - LSHIFT(K, K); - K[15] ^= 0x87; - } else - LSHIFT(K, K); - - if (ctx->M_n == 16) { - /* last block was a complete block */ - XOR(K, ctx->M_last); - - } else { - /* generate subkey K2 */ - if (K[0] & 0x80) { - LSHIFT(K, K); - K[15] ^= 0x87; - } else - LSHIFT(K, K); - - /* padding(M_last) */ - ctx->M_last[ctx->M_n] = 0x80; - while (++ctx->M_n < 16) - ctx->M_last[ctx->M_n] = 0; - - XOR(K, ctx->M_last); - - } - XOR(ctx->M_last, ctx->X); - - //rijndael_encrypt(&ctx->rijndael, ctx->X, digest); - - memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten - lora_aes_encrypt(in, digest, &ctx->rijndael); - memset1(K, 0, sizeof K); +#define MIN(a, b) ((a) < (b) ? (a) : (b)) -} + void AES_CMAC_Init(AES_CMAC_CTX *ctx) + { + memset1(ctx->X, 0, sizeof ctx->X); + ctx->M_n = 0; + memset1(ctx->rijndael.ksch, '\0', 240); + } + + void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const uint8_t key[AES_CMAC_KEY_LENGTH]) + { + //rijndael_set_key_enc_only(&ctx->rijndael, key, 128); + lora_aes_set_key(key, AES_CMAC_KEY_LENGTH, &ctx->rijndael); + } + + void AES_CMAC_Update(AES_CMAC_CTX *ctx, const uint8_t *data, uint32_t len) + { + uint32_t mlen; + uint8_t in[16]; + + if (ctx->M_n > 0) + { + mlen = MIN(16 - ctx->M_n, len); + memcpy1(ctx->M_last + ctx->M_n, data, mlen); + ctx->M_n += mlen; + if (ctx->M_n < 16 || len == mlen) + return; + XOR(ctx->M_last, ctx->X); + //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X); + lora_aes_encrypt(ctx->X, ctx->X, &ctx->rijndael); + data += mlen; + len -= mlen; + } + while (len > 16) + { /* not last block */ + + XOR(data, ctx->X); + //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X); + + memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten + lora_aes_encrypt(in, in, &ctx->rijndael); + memcpy1(&ctx->X[0], in, 16); + + data += 16; + len -= 16; + } + /* potential last block, save it */ + memcpy1(ctx->M_last, data, len); + ctx->M_n = len; + } + + void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx) + { + uint8_t K[16]; + uint8_t in[16]; + /* generate subkey K1 */ + memset1(K, '\0', 16); + + //rijndael_encrypt(&ctx->rijndael, K, K); + + lora_aes_encrypt(K, K, &ctx->rijndael); + + if (K[0] & 0x80) + { + LSHIFT(K, K); + K[15] ^= 0x87; + } + else + LSHIFT(K, K); + + if (ctx->M_n == 16) + { + /* last block was a complete block */ + XOR(K, ctx->M_last); + } + else + { + /* generate subkey K2 */ + if (K[0] & 0x80) + { + LSHIFT(K, K); + K[15] ^= 0x87; + } + else + LSHIFT(K, K); + + /* padding(M_last) */ + ctx->M_last[ctx->M_n] = 0x80; + while (++ctx->M_n < 16) + ctx->M_last[ctx->M_n] = 0; + + XOR(K, ctx->M_last); + } + XOR(ctx->M_last, ctx->X); + + //rijndael_encrypt(&ctx->rijndael, ctx->X, digest); + + memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten + lora_aes_encrypt(in, digest, &ctx->rijndael); + memset1(K, 0, sizeof K); + } }; diff --git a/src/system/crypto/cmac.h b/src/system/crypto/cmac.h index cdd6594..30daaca 100644 --- a/src/system/crypto/cmac.h +++ b/src/system/crypto/cmac.h @@ -38,26 +38,28 @@ DEALINGS WITH THE SOFTWARE #include "aes.h" -extern "C" { -#define AES_CMAC_KEY_LENGTH 16 -#define AES_CMAC_DIGEST_LENGTH 16 - -typedef struct _AES_CMAC_CTX { - lora_aes_context rijndael; - uint8_t X[16]; - uint8_t M_last[16]; - uint32_t M_n; - } AES_CMAC_CTX; - -//#include - -//__BEGIN_DECLS -void AES_CMAC_Init(AES_CMAC_CTX * ctx); -void AES_CMAC_SetKey(AES_CMAC_CTX * ctx, const uint8_t key[AES_CMAC_KEY_LENGTH]); -void AES_CMAC_Update(AES_CMAC_CTX * ctx, const uint8_t * data, uint32_t len); - // __attribute__((__bounded__(__string__,2,3))); -void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX * ctx); - // __attribute__((__bounded__(__minbytes__,1,AES_CMAC_DIGEST_LENGTH))); -//__END_DECLS +extern "C" +{ +#define AES_CMAC_KEY_LENGTH 16 +#define AES_CMAC_DIGEST_LENGTH 16 + + typedef struct _AES_CMAC_CTX + { + lora_aes_context rijndael; + uint8_t X[16]; + uint8_t M_last[16]; + uint32_t M_n; + } AES_CMAC_CTX; + + //#include + + //__BEGIN_DECLS + void AES_CMAC_Init(AES_CMAC_CTX *ctx); + void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const uint8_t key[AES_CMAC_KEY_LENGTH]); + void AES_CMAC_Update(AES_CMAC_CTX *ctx, const uint8_t *data, uint32_t len); + // __attribute__((__bounded__(__string__,2,3))); + void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx); + // __attribute__((__bounded__(__minbytes__,1,AES_CMAC_DIGEST_LENGTH))); + //__END_DECLS }; #endif /* _CMAC_H_ */ diff --git a/src/system/delay.cpp b/src/system/delay.cpp deleted file mode 100644 index e420963..0000000 --- a/src/system/delay.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - -Description: Delay functions implementation - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis and Gregory Cristian -*/ - -/****************************************************************************** - * @file delay.c - * @author Insight SiP - * @version V1.0.0 - * @date 02-mars-2018 - * @brief delay implementation functions for LORA. - * - * @attention - * THIS SOFTWARE IS PROVIDED BY INSIGHT SIP "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL INSIGHT SIP OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ - -#include "delay.h" -// #include "nrf_delay.h" - -extern "C" -{ - void DelayMs(uint32_t ms) - { - delay(ms); - } - - void Delay(uint32_t s) - { - delay(s * 1000); - } -}; \ No newline at end of file diff --git a/src/system/delay.h b/src/system/delay.h deleted file mode 100644 index 0e55a0e..0000000 --- a/src/system/delay.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - -Description: Delay functions implementation - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis and Gregory Cristian -*/ - -/****************************************************************************** - * @file delay.h - * @author Insight SiP - * @version V1.0.0 - * @date 02-mars-2018 - * @brief delay header functions for LORA. - * - * @attention - * THIS SOFTWARE IS PROVIDED BY INSIGHT SIP "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL INSIGHT SIP OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ - -#ifndef __DELAY_H__ -#define __DELAY_H__ - -#include -#include "stdint.h" - -extern "C" -{ - /**@brief Blocking delay of "s" seconds - */ - void Delay(uint32_t s); - - /**@brief Blocking delay of "ms" milliseconds - */ - void DelayMs(uint32_t ms); -}; -#endif // __DELAY_H__