diff --git a/README.MD b/README.MD
index 5d72d08..80b956e 100644
--- a/README.MD
+++ b/README.MD
@@ -11,13 +11,14 @@
- ⚠️ If using the PA version, please carefully read the PA power setting limits on the corresponding page. Incorrect output power settings may damage the PA.
- ⚠️ 如果使用PA版本,请仔细阅读对应页面的PA功率设置限制,错误的设置输出功率很有可能会损坏PA
-
### `1` Get Started
- 🔧 **[T-Beam Quick Start](./docs/en/t_beam/t_beam_hw.md)**
- 🔧 **[T-Beam Supreme Quick Start](./docs/en/t_beam_supreme/t_beam_supreme_hw.md)**
- 🔧 **[T-Beam BPF Quick Start](./docs/en/t_beam_bpf/t_beam_bpf_hw.md)**
-- 🔧 **[T-Beam 1W Quick Start](./docs/en/t_beam_1w/t_beam_1w_hw.md)**
+- 🔧 **[T-Beam 1W SX1262 Quick Start](./docs/en/t_beam_1w_sx1262/t_beam_1w_sx1262.md)**
+- 🔧 **[T-Beam 1W LR1121 Quick Start](./docs/en/t_beam_1w_lr1121/t_beam_1w_lr1121.md)**
+- 🔧 **[T-Beam 1W LR2021 Quick Start](./docs/en/t_beam_1w_lr2021/t_beam_1w_lr2021.md)**
- 🔧 **[LoRa32 V1.3 Quick Start](./docs/en/t3_v13_sx1276/t3_v13_sx1276.md)**
- 🔧 **[LoRa32 V1.6.1 Quick Start](./docs/en/t3_v161_sx1276/t3_v161_sx1276_hw.md)**
- 🔧 **[LoRa32 TCXO Quick Start](./docs/en/t3_tcxo_sx1276/t3_tcxo_sx1276_hw.md)**
diff --git a/dimensions/T-Beam-1W-batteryCase.zip b/dimensions/T-Beam-1W-batteryCase.zip
new file mode 100644
index 0000000..0f1be2c
Binary files /dev/null and b/dimensions/T-Beam-1W-batteryCase.zip differ
diff --git a/docs/en/t3_c6_sx1262/t3_c6_sx1262_hw.md b/docs/en/t3_c6_sx1262/t3_c6_sx1262_hw.md
index 342dbe4..55881a8 100644
--- a/docs/en/t3_c6_sx1262/t3_c6_sx1262_hw.md
+++ b/docs/en/t3_c6_sx1262/t3_c6_sx1262_hw.md
@@ -20,7 +20,7 @@
[1]: https://www.lilygo.cc/products/t-lora-c6 "T-Lora C6"
-### PlatformIO Quick Start
+
+
+### PlatformIO Not support ESP32C6
### Arduino IDE quick start
diff --git a/docs/en/t3_s3_lr1121/t3_s3_lr1121_hw.md b/docs/en/t3_s3_lr1121/t3_s3_lr1121_hw.md
index 49bacee..e005472 100644
--- a/docs/en/t3_s3_lr1121/t3_s3_lr1121_hw.md
+++ b/docs/en/t3_s3_lr1121/t3_s3_lr1121_hw.md
@@ -12,6 +12,7 @@
1. This version does not have BMS, please use a lithium-ion battery with battery protection function
2. Please be sure to connect the antenna before transmitting, otherwise it is easy to damage the RF module
+3. The T3-S3 V1.2 and T3-S3 V1.3 use the same pins; the only difference is the charging circuit.
### Product
@@ -103,6 +104,7 @@
| On Board LED | 37 | ❌ |
* You can use GPIO10,21 by removing the two resistors in the figure below. Otherwise, the GPIO is connected to DIO8,DIO7 of Radio by default.
+* SDA(18) and SCL(17) are not brought out and cannot be accessed. They can only be used as other GPIOs through QWIIC or header pins. During initialization, use explicit initialization `Wire.begin(sda,scl);` Any unused GPIO can be used as SDA and SCL.
| T3 V1.2 | T3 V1.3 |
| ------------------------------------------------ | ------------------------------------------------ |
@@ -171,12 +173,16 @@
| ---------------------------------------------- | ---------------------------------------------- |
|  |  |
-## LoRa-IPEX
+## LoRa Ant
-* The following figure shows how to switch the onboard LoRa SMA antenna to IPEX
+* For instructions on how to configure LoRa antenna control, please refer to the [example](https://github.com/Xinyuan-LilyGO/LilyGo-LoRa-Series/blob/d04e9c4c66516ad918c7fafbd63b477822066ec8/examples/T3S3Factory/T3S3Factory.ino#L562)
+* LR1121 The 2.4G antenna interface is located on the LoRa module and cannot be changed.
+* LoRa 2.4G and Sub1G antennas are independent and cannot be shared.
+* The following figure shows how to switch the onboard LoRa-Sub1G SMA antenna to IPEX

+
### LR1121 RF Block Diagram

diff --git a/docs/en/t3_s3_lr1121_pa/t3_s3_lr1121_pa_hw.md b/docs/en/t3_s3_lr1121_pa/t3_s3_lr1121_pa_hw.md
index 883ad3f..545176b 100644
--- a/docs/en/t3_s3_lr1121_pa/t3_s3_lr1121_pa_hw.md
+++ b/docs/en/t3_s3_lr1121_pa/t3_s3_lr1121_pa_hw.md
@@ -12,6 +12,7 @@
1. This version does not have BMS, please use a lithium-ion battery with battery protection function
2. Please be sure to connect the antenna before transmitting, otherwise it is easy to damage the RF module
+3. The T3-S3 V1.2 and T3-S3 V1.3 use the same pins; the only difference is the charging circuit.
### Product
@@ -100,6 +101,7 @@
| On Board LED | 37 | ❌ |
* You can use GPIO10,21 by removing the two resistors in the figure below. Otherwise, the GPIO is connected to DIO8,DIO7 of Radio by default.
+* SDA(18) and SCL(17) are not brought out and cannot be accessed. They can only be used as other GPIOs through QWIIC or header pins. During initialization, use explicit initialization `Wire.begin(sda,scl);` Any unused GPIO can be used as SDA and SCL.
| T3 V1.2 | T3 V1.3 |
| ------------------------------------------------ | ------------------------------------------------ |
diff --git a/docs/en/t3_s3_sx1262/t3_s3_sx1262_hw.md b/docs/en/t3_s3_sx1262/t3_s3_sx1262_hw.md
index a6dbac4..43f00f3 100644
--- a/docs/en/t3_s3_sx1262/t3_s3_sx1262_hw.md
+++ b/docs/en/t3_s3_sx1262/t3_s3_sx1262_hw.md
@@ -12,6 +12,7 @@
1. This version does not have BMS, please use a lithium-ion battery with battery protection function
2. Please be sure to connect the antenna before transmitting, otherwise it is easy to damage the RF module
+3. The T3-S3 V1.2 and T3-S3 V1.3 use the same pins; the only difference is the charging circuit.
### Product
@@ -103,6 +104,7 @@
| On Board LED | 37 | ❌ |
* You can use GPIO10,21 by removing the two resistors in the figure below. Otherwise, the GPIO is connected to DIO3,DIO4 of Radio by default.
+* SDA(18) and SCL(17) are not brought out and cannot be accessed. They can only be used as other GPIOs through QWIIC or header pins. During initialization, use explicit initialization `Wire.begin(sda,scl);` Any unused GPIO can be used as SDA and SCL.
| T3 V1.2 | T3 V1.3 |
| ------------------------------------------------ | ------------------------------------------------ |
diff --git a/docs/en/t3_s3_sx1276/t3_s3_sx1276_hw.md b/docs/en/t3_s3_sx1276/t3_s3_sx1276_hw.md
index c1a4cfd..8d89ab2 100644
--- a/docs/en/t3_s3_sx1276/t3_s3_sx1276_hw.md
+++ b/docs/en/t3_s3_sx1276/t3_s3_sx1276_hw.md
@@ -12,6 +12,7 @@
1. This version does not have BMS, please use a lithium-ion battery with battery protection function
2. Please be sure to connect the antenna before transmitting, otherwise it is easy to damage the RF module
+3. The T3-S3 V1.2 and T3-S3 V1.3 use the same pins; the only difference is the charging circuit.
### Product
@@ -107,6 +108,7 @@
| On Board LED | 37 | ❌ |
* You can use GPIO10,21 by removing the two resistors in the figure below. Otherwise, the GPIO is connected to DIO3,DIO4 of Radio by default.
+* SDA(18) and SCL(17) are not brought out and cannot be accessed. They can only be used as other GPIOs through QWIIC or header pins. During initialization, use explicit initialization `Wire.begin(sda,scl);` Any unused GPIO can be used as SDA and SCL.
| T3 V1.2 | T3 V1.3 |
| ------------------------------------------------ | ------------------------------------------------ |
diff --git a/docs/en/t3_s3_sx1278/t3_s3_sx1278_hw.md b/docs/en/t3_s3_sx1278/t3_s3_sx1278_hw.md
index 753c98f..31eca0c 100644
--- a/docs/en/t3_s3_sx1278/t3_s3_sx1278_hw.md
+++ b/docs/en/t3_s3_sx1278/t3_s3_sx1278_hw.md
@@ -12,6 +12,7 @@
1. This version does not have BMS, please use a lithium-ion battery with battery protection function
2. Please be sure to connect the antenna before transmitting, otherwise it is easy to damage the RF module
+3. The T3-S3 V1.2 and T3-S3 V1.3 use the same pins; the only difference is the charging circuit.
### Product
@@ -107,6 +108,7 @@
| On Board LED | 37 | ❌ |
* You can use GPIO10,21 by removing the two resistors in the figure below. Otherwise, the GPIO is connected to DIO3,DIO4 of Radio by default.
+* SDA(18) and SCL(17) are not brought out and cannot be accessed. They can only be used as other GPIOs through QWIIC or header pins. During initialization, use explicit initialization `Wire.begin(sda,scl);` Any unused GPIO can be used as SDA and SCL.
| T3 V1.2 | T3 V1.3 |
| ------------------------------------------------ | ------------------------------------------------ |
diff --git a/docs/en/t3_s3_sx1280/t3_s3_sx1280_hw.md b/docs/en/t3_s3_sx1280/t3_s3_sx1280_hw.md
index d750273..3083c21 100644
--- a/docs/en/t3_s3_sx1280/t3_s3_sx1280_hw.md
+++ b/docs/en/t3_s3_sx1280/t3_s3_sx1280_hw.md
@@ -12,6 +12,7 @@
1. This version does not have BMS, please use a lithium-ion battery with battery protection function
2. Please be sure to connect the antenna before transmitting, otherwise it is easy to damage the RF module
+3. The T3-S3 V1.2 and T3-S3 V1.3 use the same pins; the only difference is the charging circuit.
### Product
@@ -102,6 +103,8 @@
| Battery ADC | 1 | ❌ |
| On Board LED | 37 | ❌ |
+* SDA(18) and SCL(17) are not brought out and cannot be accessed. They can only be used as other GPIOs through QWIIC or header pins. During initialization, use explicit initialization `Wire.begin(sda,scl);` Any unused GPIO can be used as SDA and SCL.
+
### 🧑🏼🔧 I2C Devices Address
| Devices | 7-Bit Address | Share Bus |
diff --git a/docs/en/t3_s3_sx1280pa/t3_s3_sx1280pa.md b/docs/en/t3_s3_sx1280pa/t3_s3_sx1280pa.md
index b4e31a7..0b2bd5d 100644
--- a/docs/en/t3_s3_sx1280pa/t3_s3_sx1280pa.md
+++ b/docs/en/t3_s3_sx1280pa/t3_s3_sx1280pa.md
@@ -12,6 +12,7 @@
1. This version does not have BMS, please use a lithium-ion battery with battery protection function
2. Please be sure to connect the antenna before transmitting, otherwise it is easy to damage the RF module
+3. The T3-S3 V1.2 and T3-S3 V1.3 use the same pins; the only difference is the charging circuit.
### Product
@@ -105,6 +106,7 @@
| On Board LED | 37 | ❌ |
* QWIIC IO10/IO21 GPIOs are already connected to the Radio TX/RX Pin and cannot be used.
+* SDA(18) and SCL(17) are not brought out and cannot be accessed. They can only be used as other GPIOs through QWIIC or header pins. During initialization, use explicit initialization `Wire.begin(sda,scl);` Any unused GPIO can be used as SDA and SCL.
### 🧑🏼🔧 I2C Devices Address
diff --git a/docs/en/t_beam_1w_lr1121/images/XY16EXP33.png b/docs/en/t_beam_1w_lr1121/images/XY16EXP33.png
new file mode 100644
index 0000000..902a33e
Binary files /dev/null and b/docs/en/t_beam_1w_lr1121/images/XY16EXP33.png differ
diff --git a/docs/en/t_beam_1w_lr1121/images/currnetA.png b/docs/en/t_beam_1w_lr1121/images/currnetA.png
new file mode 100644
index 0000000..c9d4b05
Binary files /dev/null and b/docs/en/t_beam_1w_lr1121/images/currnetA.png differ
diff --git a/docs/en/t_beam_1w_lr1121/images/currnetB.png b/docs/en/t_beam_1w_lr1121/images/currnetB.png
new file mode 100644
index 0000000..90573cb
Binary files /dev/null and b/docs/en/t_beam_1w_lr1121/images/currnetB.png differ
diff --git a/docs/en/t_beam_1w_lr1121/t_beam_1w_lr1121.md b/docs/en/t_beam_1w_lr1121/t_beam_1w_lr1121.md
new file mode 100644
index 0000000..d01bfdc
--- /dev/null
+++ b/docs/en/t_beam_1w_lr1121/t_beam_1w_lr1121.md
@@ -0,0 +1,176 @@
+
+

+
+
+🌟LilyGo T-Beam-1W-LR1121
+
+## Overview
+
+* This page introduces the hardware parameters related to `LilyGo T-Beam-1W-LR1121`
+
+### Notes on use
+
+1. This board will not charge the external 7.4V battery, it is only powered by the battery.
+2. Please be sure to connect the antenna before transmitting, otherwise it is easy to damage the RF module.
+3. Please note that the GPIO with * added to the external pin header GPIO name is already connected to the internal module and cannot be used
+4. This RF module provides a maximum power output of 30dBm on this board
+
+## PlatformIO Quick Start
+
+1. Install [Visual Studio Code](https://code.visualstudio.com/) and [Python](https://www.python.org/)
+2. Search for the `PlatformIO` plugin in the `Visual Studio Code` extension and install it.
+3. After the installation is complete, you need to restart `Visual Studio Code`
+4. After restarting `Visual Studio Code`, select `File` in the upper left corner of `Visual Studio Code` -> `Open Folder` -> select the `LilyGo-LoRa-Series` directory
+5. Wait for the installation of third-party dependent libraries to complete
+6. Click on the `platformio.ini` file, and in the `platformio` column
+7. Select the board name you want to use in `default_envs` and uncomment it.
+8. Uncomment one of the lines `src_dir = xxxx` to make sure only one line works , Please note the example comments, indicating what works and what does not.
+9. Click the (✔) symbol in the lower left corner to compile
+10. Connect the board to the computer USB-C , Micro-USB is used for module firmware upgrade
+11. Click (→) to upload firmware
+12. Click (plug symbol) to monitor serial output
+13. If it cannot be written, or the USB device keeps flashing, please check the **FAQ** below
+
+## Arduino IDE quick start
+
+1. Install [Arduino IDE](https://www.arduino.cc/en/software)
+2. Install [Arduino ESP32](https://docs.espressif.com/projects/arduino-esp32/en/latest/)
+3. Copy all folders in the `lib` directory to the `Sketchbook location` directory. How to find the location of your own libraries, [please see here](https://support.arduino.cc/hc/en-us/articles/4415103213714-Find-sketches-libraries-board-cores-and-other-files-on-your-computer)
+ * Windows: `C:\Users\{username}\Documents\Arduino`
+ * macOS: `/Users/{username}/Documents/Arduino`
+ * Linux: `/home/{username}/Arduino`
+4. Open the corresponding example
+ * Open the downloaded `LilyGo-LoRa-Series`
+ * Open `examples`
+ * Select the sample file and open the file ending with `ino`
+5. On Arduino Select the corresponding board in the IDE tool project and click on the corresponding option in the list below to select
+
+ | Name | Value |
+ | ------------------------------------ | ---------------------------------------------------- |
+ | Board | **ESP32S3 Dev Module** |
+ | Port | Your port |
+ | USB CDC On Boot | Enable |
+ | CPU Frequency | 240MHZ(WiFi) |
+ | Core Debug Level | None |
+ | USB DFU On Boot | Disable |
+ | Erase All Flash Before Sketch Upload | Disable |
+ | Flash Mode | QIO 80Mhz |
+ | Flash Size | **16MB(128Mb)** |
+ | Arduino Runs On | Core1 |
+ | USB Firmware MSC On Boot | Disable |
+ | Partition Scheme | **Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)** |
+ | PSRAM | **QSPI PSRAM** |
+ | Upload Speed | 921600 |
+ | Programmer | **Esptool** |
+
+6. Please uncomment the `utilities.h` file of each sketch according to your board model e.g `T_BEAM_1W_LR1121`, otherwise the compilation will report an error.
+7. Upload sketch
+
+### 📍 Pins Map
+
+| Name | GPIO NUM | Free |
+| ----------------------- | ------------------------------ | ---- |
+| Uart1 TX | 43(External QWIIC Socket) | ✅️ |
+| Uart1 RX | 44(External QWIIC Socket) | ✅️ |
+| SDA | 8 (External QWIIC Socket same) | ❌ |
+| SCL | 9 (External QWIIC Socket same) | ❌ |
+| SPI MOSI | 11 | ❌ |
+| SPI MISO | 12 | ❌ |
+| SPI SCK | 13 | ❌ |
+| SD CS | 10 | ❌ |
+| SD MOSI | Share with SPI bus | ❌ |
+| SD MISO | Share with SPI bus | ❌ |
+| SD SCK | Share with SPI bus | ❌ |
+| GNSS(**L76K**) TX | 6 | ❌ |
+| GNSS(**L76K**) RX | 5 | ❌ |
+| GNSS(**L76K**) PPS | 7 | ❌ |
+| GNSS(**L76K**) Wake-up | 16 | ❌ |
+| LoRa(**LR1121**) SCK | Share with SPI bus | ❌ |
+| LoRa(**LR1121**) MISO | Share with SPI bus | ❌ |
+| LoRa(**LR1121**) MOSI | Share with SPI bus | ❌ |
+| LoRa(**LR1121**) RESET | 3 | ❌ |
+| LoRa(**LR1121**) DIO10 | 1 | ❌ |
+| LoRa(**LR1121**) DIO11 | 21 | ❌ |
+| LoRa(**LR1121**) CS | 15 | ❌ |
+| LoRa(**LR1121**) LDO EN | 40 | ❌ |
+| LoRa(**LR1121**) BUSY | 38 | ❌ |
+| Button1 (BOOT) | 0 | ❌ |
+| Button2 | 17 | ❌ |
+| On Board LED | 18 | ❌ |
+| NTC ADC | 14 | ❌ |
+| Battery ADC | 4 | ❌ |
+| Fan control | 41 | ❌ |
+
+> \[!IMPORTANT]
+>
+> LDO EN pin is control pin inside the module:
+>
+> 1. High level turns on the Radio
+> 2. Low level turns off the Radio
+>
+
+### 🧑🏼🔧 I2C Devices Address
+
+| Devices | 7-Bit Address | Share Bus |
+| ------------------- | ------------- | --------- |
+| OLED Display SH1106 | 0x3C | ✅️ |
+
+### ⚡ Electrical parameters
+
+| Features | Details |
+| -------------------- | ------- |
+| 🔗USB-C Input Voltage | 3.9V-6V |
+| ⚡Charge Function | ❌ |
+| 🔋Battery Voltage | 7.4V |
+
+> \[!IMPORTANT]
+>
+> The battery used must have a discharge capacity of 2A or greater; otherwise, it may trigger battery protection during high-power transmission.
+>
+
+### Button Description
+
+| Channel | Peripherals |
+| ------- | ------------------------------ |
+| IO17 | Customizable buttons |
+| BOOT | Boot mode button, customizable |
+| RST | Reset button |
+
+### LED Description
+
+* IO18 LED
+ 1. Connect to GPIO18, you can turn the LED on or off by writing high or low level.
+
+* PPS LED
+ 1. This LED cannot be turned off and is connected to the GPS PPS Pin. This LED flashes to indicate that the PPS pulse has arrived.
+
+* USB LED
+ 1. LED On means the USB cable is connected,LED off means the USB cable is disconnected
+
+### RF parameters
+
+| Features | 868MHz |
+| ------------------------- | ----------------------- |
+| RF Module | LR1121 TCXO (XY16E8P33) |
+| Frequency range | 840~930MHz |
+| Transfer rate(FSK) | 0.6 ~ 300 kbps |
+| Transfer rate(LoRa) Sub1G | 0.091 ~ 62.5 kbps |
+| Transfer rate(LoRa) 2.4G | 0.476 ~ 101.5 kbps |
+| Modulation | FSK, MSK, GMSK, LoRa |
+
+
+### RF Block Diagram
+
+
+
+### VCC=+5V, 840MHz~930MHz module output power dBm and current
+
+
+
+### VCC=+5V, 2400MHz~2500MHz module output power dBm and current
+
+
+
+### Resource
+
+* [Schematic](../../../schematic/T-Beam_1W_V1.1.pdf)
diff --git a/docs/en/t_beam_1w_lr2021/images/XY16E3AXP33.png b/docs/en/t_beam_1w_lr2021/images/XY16E3AXP33.png
new file mode 100644
index 0000000..0bd7b36
Binary files /dev/null and b/docs/en/t_beam_1w_lr2021/images/XY16E3AXP33.png differ
diff --git a/docs/en/t_beam_1w_lr2021/images/currentA.png b/docs/en/t_beam_1w_lr2021/images/currentA.png
new file mode 100644
index 0000000..29c7f4d
Binary files /dev/null and b/docs/en/t_beam_1w_lr2021/images/currentA.png differ
diff --git a/docs/en/t_beam_1w_lr2021/images/currentB.png b/docs/en/t_beam_1w_lr2021/images/currentB.png
new file mode 100644
index 0000000..c0a405b
Binary files /dev/null and b/docs/en/t_beam_1w_lr2021/images/currentB.png differ
diff --git a/docs/en/t_beam_1w_lr2021/t_beam_1w_lr2021.md b/docs/en/t_beam_1w_lr2021/t_beam_1w_lr2021.md
new file mode 100644
index 0000000..bafb7e7
--- /dev/null
+++ b/docs/en/t_beam_1w_lr2021/t_beam_1w_lr2021.md
@@ -0,0 +1,208 @@
+
+

+
+
+🌟LilyGo T-Beam-1W-LR2021
+
+## Overview
+
+* This page introduces the hardware parameters related to `LilyGo T-Beam-1W-LR2021`
+
+### Notes on use
+
+1. This board will not charge the external 7.4V battery, it is only powered by the battery.
+2. Please be sure to connect the antenna before transmitting, otherwise it is easy to damage the RF module.
+3. Please note that the GPIO with * added to the external pin header GPIO name is already connected to the internal module and cannot be used
+4. This RF module provides a maximum power output of 30dBm on this board
+
+## PlatformIO Quick Start
+
+1. Install [Visual Studio Code](https://code.visualstudio.com/) and [Python](https://www.python.org/)
+2. Search for the `PlatformIO` plugin in the `Visual Studio Code` extension and install it.
+3. After the installation is complete, you need to restart `Visual Studio Code`
+4. After restarting `Visual Studio Code`, select `File` in the upper left corner of `Visual Studio Code` -> `Open Folder` -> select the `LilyGo-LoRa-Series` directory
+5. Wait for the installation of third-party dependent libraries to complete
+6. Click on the `platformio.ini` file, and in the `platformio` column
+7. Select the board name you want to use in `default_envs` and uncomment it.
+8. Uncomment one of the lines `src_dir = xxxx` to make sure only one line works , Please note the example comments, indicating what works and what does not.
+9. Click the (✔) symbol in the lower left corner to compile
+10. Connect the board to the computer USB-C , Micro-USB is used for module firmware upgrade
+11. Click (→) to upload firmware
+12. Click (plug symbol) to monitor serial output
+13. If it cannot be written, or the USB device keeps flashing, please check the **FAQ** below
+
+## Arduino IDE quick start
+
+1. Install [Arduino IDE](https://www.arduino.cc/en/software)
+2. Install [Arduino ESP32](https://docs.espressif.com/projects/arduino-esp32/en/latest/)
+3. Copy all folders in the `lib` directory to the `Sketchbook location` directory. How to find the location of your own libraries, [please see here](https://support.arduino.cc/hc/en-us/articles/4415103213714-Find-sketches-libraries-board-cores-and-other-files-on-your-computer)
+ * Windows: `C:\Users\{username}\Documents\Arduino`
+ * macOS: `/Users/{username}/Documents/Arduino`
+ * Linux: `/home/{username}/Arduino`
+4. Open the corresponding example
+ * Open the downloaded `LilyGo-LoRa-Series`
+ * Open `examples`
+ * Select the sample file and open the file ending with `ino`
+5. On Arduino Select the corresponding board in the IDE tool project and click on the corresponding option in the list below to select
+
+ | Name | Value |
+ | ------------------------------------ | ---------------------------------------------------- |
+ | Board | **ESP32S3 Dev Module** |
+ | Port | Your port |
+ | USB CDC On Boot | Enable |
+ | CPU Frequency | 240MHZ(WiFi) |
+ | Core Debug Level | None |
+ | USB DFU On Boot | Disable |
+ | Erase All Flash Before Sketch Upload | Disable |
+ | Flash Mode | QIO 80Mhz |
+ | Flash Size | **16MB(128Mb)** |
+ | Arduino Runs On | Core1 |
+ | USB Firmware MSC On Boot | Disable |
+ | Partition Scheme | **Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)** |
+ | PSRAM | **QSPI PSRAM** |
+ | Upload Speed | 921600 |
+ | Programmer | **Esptool** |
+
+6. Please uncomment the `utilities.h` file of each sketch according to your board model e.g `T_BEAM_1W_LR2021`, otherwise the compilation will report an error.
+7. Upload sketch
+
+### 📍 Pins Map
+
+| Name | GPIO NUM | Free |
+| ----------------------- | ------------------------------ | ---- |
+| Uart1 TX | 43(External QWIIC Socket) | ✅️ |
+| Uart1 RX | 44(External QWIIC Socket) | ✅️ |
+| SDA | 8 (External QWIIC Socket same) | ❌ |
+| SCL | 9 (External QWIIC Socket same) | ❌ |
+| SPI MOSI | 11 | ❌ |
+| SPI MISO | 12 | ❌ |
+| SPI SCK | 13 | ❌ |
+| SD CS | 10 | ❌ |
+| SD MOSI | Share with SPI bus | ❌ |
+| SD MISO | Share with SPI bus | ❌ |
+| SD SCK | Share with SPI bus | ❌ |
+| GNSS(**L76K**) TX | 6 | ❌ |
+| GNSS(**L76K**) RX | 5 | ❌ |
+| GNSS(**L76K**) PPS | 7 | ❌ |
+| GNSS(**L76K**) Wake-up | 16 | ❌ |
+| LoRa(**LR2021**) SCK | Share with SPI bus | ❌ |
+| LoRa(**LR2021**) MISO | Share with SPI bus | ❌ |
+| LoRa(**LR2021**) MOSI | Share with SPI bus | ❌ |
+| LoRa(**LR2021**) RESET | 3 | ❌ |
+| LoRa(**LR2021**) DIO10 | 1 | ❌ |
+| LoRa(**LR2021**) DIO11 | 21 | ❌ |
+| LoRa(**LR2021**) CS | 15 | ❌ |
+| LoRa(**LR2021**) LDO EN | 40 | ❌ |
+| LoRa(**LR2021**) BUSY | 38 | ❌ |
+| Button1 (BOOT) | 0 | ❌ |
+| Button2 | 17 | ❌ |
+| On Board LED | 18 | ❌ |
+| NTC ADC | 14 | ❌ |
+| Battery ADC | 4 | ❌ |
+| Fan control | 41 | ❌ |
+
+> \[!IMPORTANT]
+>
+> LDO EN pin is control pin inside the module:
+>
+> 1. High level turns on the Radio
+> 2. Low level turns off the Radio
+>
+
+### 🧑🏼🔧 I2C Devices Address
+
+| Devices | 7-Bit Address | Share Bus |
+| ------------------- | ------------- | --------- |
+| OLED Display SH1106 | 0x3C | ✅️ |
+
+### ⚡ Electrical parameters
+
+| Features | Details |
+| -------------------- | ------- |
+| 🔗USB-C Input Voltage | 3.9V-6V |
+| ⚡Charge Function | ❌ |
+| 🔋Battery Voltage | 7.4V |
+
+> \[!IMPORTANT]
+>
+> The battery used must have a discharge capacity of 2A or greater; otherwise, it may trigger battery protection during high-power transmission.
+>
+
+### Button Description
+
+| Channel | Peripherals |
+| ------- | ------------------------------ |
+| IO17 | Customizable buttons |
+| BOOT | Boot mode button, customizable |
+| RST | Reset button |
+
+### LED Description
+
+* IO18 LED
+ 1. Connect to GPIO18, you can turn the LED on or off by writing high or low level.
+
+* PPS LED
+ 1. This LED cannot be turned off and is connected to the GPS PPS Pin. This LED flashes to indicate that the PPS pulse has arrived.
+
+* USB LED
+ 1. LED On means the USB cable is connected,LED off means the USB cable is disconnected
+
+### RF parameters
+
+| Features | LR2021 (XY16E3AXP33) |
+| ------------------------- | ----------------------------- |
+| RF Module | LR2021 TCXO |
+| Frequency range | 840 ~ 930MHz |
+| Transfer rate(FSK) | 0.5 ~ 2000 kbps |
+| Transfer rate(LoRa Sub1G) | 0.091 ~ 62.5kbps |
+| Transfer rate(FSK 2.4G) | 0.476 ~ 101.5 Kbps |
+| Transfer rate(FLRC) | 0.13 ~ 2.6 Mbps |
+| Modulation | FSK, MSK, LoRa ,FLRC |
+
+
+### RadioLib RF Setting
+
+```c
+static const uint32_t pa_version_rf_switch_dio_pins[] = {
+ RADIOLIB_LR2021_DIO5, RADIOLIB_LR2021_DIO6, RADIOLIB_LR2021_DIO7, RADIOLIB_LR2021_DIO8, RADIOLIB_NC
+};
+
+static const Module::RfSwitchMode_t low_sub1g_switch_table[] = {
+ // mode DIO5 DIO6 DIO7 DIO8
+ { LR2021::MODE_STBY, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_TX, { LOW, LOW, LOW, HIGH} }, // Sub1G DIO8 SET HIGH
+ { LR2021::MODE_RX, { LOW, LOW, LOW, LOW} }, // Sub1G ALL DIO SET LOW
+ { LR2021::MODE_RX_HF, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_TX_HF, { LOW, LOW, LOW, LOW} },
+ END_OF_MODE_TABLE,
+};
+
+static const Module::RfSwitchMode_t high_2g4_switch_table[] = {
+ // mode DIO5 DIO6 DIO7 DIO8
+ { LR2021::MODE_STBY, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_TX, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_RX, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_RX_HF, { LOW, HIGH, LOW, LOW} }, //2.4G RX DIO6 SET HIGH
+ { LR2021::MODE_TX_HF, { LOW, LOW, HIGH, LOW} }, //2.4G TX DIO7 SET HIGH
+ END_OF_MODE_TABLE,
+};
+
+```
+
+
+
+### RF Block Diagram
+
+
+
+### VCC=+5V, 840MHz~930MHz module output power dBm and current
+
+
+
+### VCC=+5V, 2400MHz~2500MHz module output power dBm and current
+
+
+
+### Resource
+
+* [Schematic](../../../schematic/T-Beam_1W_V1.1.pdf)
diff --git a/docs/en/t_beam_1w/images/RampTime.jpg b/docs/en/t_beam_1w_sx1262/images/RampTime.jpg
similarity index 100%
rename from docs/en/t_beam_1w/images/RampTime.jpg
rename to docs/en/t_beam_1w_sx1262/images/RampTime.jpg
diff --git a/docs/en/t_beam_1w/images/XY16P35.jpg b/docs/en/t_beam_1w_sx1262/images/XY16P35.jpg
similarity index 100%
rename from docs/en/t_beam_1w/images/XY16P35.jpg
rename to docs/en/t_beam_1w_sx1262/images/XY16P35.jpg
diff --git a/docs/en/t_beam_1w/images/currnetA.jpg b/docs/en/t_beam_1w_sx1262/images/currnetA.jpg
similarity index 100%
rename from docs/en/t_beam_1w/images/currnetA.jpg
rename to docs/en/t_beam_1w_sx1262/images/currnetA.jpg
diff --git a/docs/en/t_beam_1w/images/currnetB.jpg b/docs/en/t_beam_1w_sx1262/images/currnetB.jpg
similarity index 100%
rename from docs/en/t_beam_1w/images/currnetB.jpg
rename to docs/en/t_beam_1w_sx1262/images/currnetB.jpg
diff --git a/docs/en/t_beam_1w/t_beam_1w_hw.md b/docs/en/t_beam_1w_sx1262/t_beam_1w_sx1262.md
similarity index 98%
rename from docs/en/t_beam_1w/t_beam_1w_hw.md
rename to docs/en/t_beam_1w_sx1262/t_beam_1w_sx1262.md
index 9ae1744..611aaf7 100644
--- a/docs/en/t_beam_1w/t_beam_1w_hw.md
+++ b/docs/en/t_beam_1w_sx1262/t_beam_1w_sx1262.md
@@ -141,10 +141,6 @@
| BOOT | Boot mode button, customizable |
| RST | Reset button |
-* The PWR button is connected to the PMU
- 1. In shutdown mode, press the PWR button to turn on the power supply
- 2. In power-on mode, press the PWR button for 6 seconds (default time) to turn off the power supply
-
### LED Description
* IO18 LED
diff --git a/docs/en/t_beam_supreme/t_beam_supreme_hw.md b/docs/en/t_beam_supreme/t_beam_supreme_hw.md
index 0715503..55488b4 100644
--- a/docs/en/t_beam_supreme/t_beam_supreme_hw.md
+++ b/docs/en/t_beam_supreme/t_beam_supreme_hw.md
@@ -79,52 +79,55 @@
### 📍 Pins Map
-| Name | GPIO NUM | Free |
-| ------------------------------------- | -------------------------- | ---- |
-| Uart1 TX | 43(External QWIIC Socket) | ✅️ |
-| Uart1 RX | 44(External QWIIC Socket) | ✅️ |
-| SDA | 17 | ❌ |
-| SCL | 18 | ❌ |
-| OLED(**SH1106**) SDA | Share with I2C bus | ❌ |
-| OLED(**SH1106**) SCL | Share with I2C bus | ❌ |
-| RTC(**PCF8563**) SDA | Share with **PMU** I2C bus | ❌ |
-| RTC(**PCF8563**) SCL | Share with **PMU** I2C bus | ❌ |
-| MAG Sensor(**QMC6310U/QMC6310N**) SDA | Share with I2C bus | ❌ |
-| MAG Sensor(**QMC6310U/QMC6310N**) SCL | Share with I2C bus | ❌ |
-| RTC(**PCF8563**) Interrupt | 14 | ❌ |
-| IMU Sensor(**QMI8658**) Interrupt | 33 | ❌ |
-| IMU Sensor(**QMI8658**) MISO | Share with SPI bus | ❌ |
-| IMU Sensor(**QMI8658**) MOSI | Share with SPI bus | ❌ |
-| IMU Sensor(**QMI8658**) SCK | Share with SPI bus | ❌ |
-| IMU Sensor(**QMI8658**) CS | 34 | ❌ |
-| SPI MOSI | 35 | ❌ |
-| SPI MISO | 37 | ❌ |
-| SPI SCK | 36 | ❌ |
-| SD CS | 47 | ❌ |
-| SD MOSI | Share with SPI bus | ❌ |
-| SD MISO | Share with SPI bus | ❌ |
-| SD SCK | Share with SPI bus | ❌ |
-| GNSS(**L76K or Ublox M10**) TX | 8 | ❌ |
-| GNSS(**L76K or Ublox M10**) RX | 9 | ❌ |
-| GNSS(**L76K or Ublox M10**) PPS | 6 | ❌ |
-| GNSS(**L76K**) Wake-up | 7 | ❌ |
-| LoRa(**SX1262 or LR1121**) SCK | 12 | ❌ |
-| LoRa(**SX1262 or LR1121**) MISO | 13 | ❌ |
-| LoRa(**SX1262 or LR1121**) MOSI | 11 | ❌ |
-| LoRa(**SX1262 or LR1121**) RESET | 5 | ❌ |
-| LoRa(**SX1262 or LR1121**) DIO1/DIO9 | 1 | ❌ |
-| LoRa(**SX1262 or LR1121**) BUSY | 4 | ❌ |
-| LoRa(**SX1262 or LR1121**) CS | 10 | ❌ |
-| Button1 (BOOT) | 0 | ❌ |
-| PMU (**AXP2101**) IRQ | 40 | ❌ |
-| PMU (**AXP2101**) SDA | 42 | ❌ |
-| PMU (**AXP2101**) SCL | 41 | ❌ |
+| Name | GPIO NUM | Free |
+| -------------------------------------------- | -------------------------- | ---- |
+| Uart1 TX | 43(External QWIIC Socket) | ✅️ |
+| Uart1 RX | 44(External QWIIC Socket) | ✅️ |
+| SDA | 17 | ❌ |
+| SCL | 18 | ❌ |
+| OLED(**SH1106**) SDA | Share with I2C bus | ❌ |
+| OLED(**SH1106**) SCL | Share with I2C bus | ❌ |
+| RTC(**PCF8563**) SDA | Share with **PMU** I2C bus | ❌ |
+| RTC(**PCF8563**) SCL | Share with **PMU** I2C bus | ❌ |
+| MAG Sensor(**QMC6310U/QMC6310N/QC6309**) SDA | Share with I2C bus | ❌ |
+| MAG Sensor(**QMC6310U/QMC6310N/QC6309**) SCL | Share with I2C bus | ❌ |
+| RTC(**PCF8563**) Interrupt | 14 | ❌ |
+| IMU Sensor(**QMI8658**) Interrupt | 33 | ❌ |
+| IMU Sensor(**QMI8658**) MISO | Share with SPI bus | ❌ |
+| IMU Sensor(**QMI8658**) MOSI | Share with SPI bus | ❌ |
+| IMU Sensor(**QMI8658**) SCK | Share with SPI bus | ❌ |
+| IMU Sensor(**QMI8658**) CS | 34 | ❌ |
+| SPI MOSI | 35 | ❌ |
+| SPI MISO | 37 | ❌ |
+| SPI SCK | 36 | ❌ |
+| SD CS | 47 | ❌ |
+| SD MOSI | Share with SPI bus | ❌ |
+| SD MISO | Share with SPI bus | ❌ |
+| SD SCK | Share with SPI bus | ❌ |
+| GNSS(**L76K or Ublox M10**) TX | 8 | ❌ |
+| GNSS(**L76K or Ublox M10**) RX | 9 | ❌ |
+| GNSS(**L76K or Ublox M10**) PPS | 6 | ❌ |
+| GNSS(**L76K**) Wake-up | 7 | ❌ |
+| LoRa(**SX1262 or LR1121**) SCK | 12 | ❌ |
+| LoRa(**SX1262 or LR1121**) MISO | 13 | ❌ |
+| LoRa(**SX1262 or LR1121**) MOSI | 11 | ❌ |
+| LoRa(**SX1262 or LR1121**) RESET | 5 | ❌ |
+| LoRa(**SX1262 or LR1121**) DIO1/DIO9 | 1 | ❌ |
+| LoRa(**SX1262 or LR1121**) BUSY | 4 | ❌ |
+| LoRa(**SX1262 or LR1121**) CS | 10 | ❌ |
+| Button1 (BOOT) | 0 | ❌ |
+| PMU (**AXP2101**) IRQ | 40 | ❌ |
+| PMU (**AXP2101**) SDA | 42 | ❌ |
+| PMU (**AXP2101**) SCL | 41 | ❌ |
> \[!IMPORTANT]
>
> 1. GNSS Wake-up is only available in L76K version
>
> 2. Radio has its own SPI bus, and other peripheral SPI devices share the SPI bus.
+>
+> 3. T-BeamSupreme has three magnetometer versions: QMC6310N, QMC6310U, and QMC6309, each with a different device address.
+>
### 🧑🏼🔧 I2C Devices Address
@@ -132,6 +135,7 @@
| --------------------------------------- | ------------- | -------------- |
| OLED Display (**SH1106**) | 0x3C/0x3D | ✅️ (I2C Bus 0) |
| MAG Sensor(**QMC6310U OR QMC6310N**) | 0x1C/0x3C | ✅️ (I2C Bus 0) |
+| MAG Sensor(**QMC6309**) | 0x7C | ✅️ (I2C Bus 0) |
| Temperature/humidity Sensor(**BME280**) | 0x77 | ✅️ (I2C Bus 0) |
| RTC (**PCF8563**) | 0x51 | ❌ (I2C Bus 1) |
| Power Manager (**AXP2101**) | 0x34 | ❌ (I2C Bus 1) |
@@ -144,6 +148,7 @@
>
> The QMC6310U and QMC6310N use different device addresses: QMC6310U (0x1C) and QMC6310N (0x3C).
> The SH1106 uses either device address 0x3C or 0x3D. If using the QMC6310U version, the device address is 0x3C; if using the QMC6310N version, the device address is 0x3D.
+> The screen device address using the QMC6309 magnetic sensor is 0x3C, the same as the QMC6310U.
>
### BME280 Address
diff --git a/examples/ArduinoLoRa/LoRaReceiver/LoRaBoards.cpp b/examples/ArduinoLoRa/LoRaReceiver/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/ArduinoLoRa/LoRaReceiver/LoRaBoards.cpp
+++ b/examples/ArduinoLoRa/LoRaReceiver/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/ArduinoLoRa/LoRaReceiver/LoRaBoards.h b/examples/ArduinoLoRa/LoRaReceiver/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/ArduinoLoRa/LoRaReceiver/LoRaBoards.h
+++ b/examples/ArduinoLoRa/LoRaReceiver/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/ArduinoLoRa/LoRaSender/LoRaBoards.cpp b/examples/ArduinoLoRa/LoRaSender/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/ArduinoLoRa/LoRaSender/LoRaBoards.cpp
+++ b/examples/ArduinoLoRa/LoRaSender/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/ArduinoLoRa/LoRaSender/LoRaBoards.h b/examples/ArduinoLoRa/LoRaSender/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/ArduinoLoRa/LoRaSender/LoRaBoards.h
+++ b/examples/ArduinoLoRa/LoRaSender/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Display/Free_Font_Demo/LoRaBoards.cpp b/examples/Display/Free_Font_Demo/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Display/Free_Font_Demo/LoRaBoards.cpp
+++ b/examples/Display/Free_Font_Demo/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Display/Free_Font_Demo/LoRaBoards.h b/examples/Display/Free_Font_Demo/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Display/Free_Font_Demo/LoRaBoards.h
+++ b/examples/Display/Free_Font_Demo/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Display/TBeam_TFT_Shield/LoRaBoards.cpp b/examples/Display/TBeam_TFT_Shield/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Display/TBeam_TFT_Shield/LoRaBoards.cpp
+++ b/examples/Display/TBeam_TFT_Shield/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Display/TBeam_TFT_Shield/LoRaBoards.h b/examples/Display/TBeam_TFT_Shield/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Display/TBeam_TFT_Shield/LoRaBoards.h
+++ b/examples/Display/TBeam_TFT_Shield/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Display/TFT_Char_times/LoRaBoards.cpp b/examples/Display/TFT_Char_times/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Display/TFT_Char_times/LoRaBoards.cpp
+++ b/examples/Display/TFT_Char_times/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Display/TFT_Char_times/LoRaBoards.h b/examples/Display/TFT_Char_times/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Display/TFT_Char_times/LoRaBoards.h
+++ b/examples/Display/TFT_Char_times/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Display/UTFT_demo/LoRaBoards.cpp b/examples/Display/UTFT_demo/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Display/UTFT_demo/LoRaBoards.cpp
+++ b/examples/Display/UTFT_demo/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Display/UTFT_demo/LoRaBoards.h b/examples/Display/UTFT_demo/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Display/UTFT_demo/LoRaBoards.h
+++ b/examples/Display/UTFT_demo/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Factory/Factory.ino b/examples/Factory/Factory.ino
index cb5a8f1..a42538a 100644
--- a/examples/Factory/Factory.ino
+++ b/examples/Factory/Factory.ino
@@ -4,11 +4,19 @@
* @license MIT
* @copyright Copyright (c) 2024 Shenzhen Xin Yuan Electronic Technology Co., Ltd
* @date 2024-12-18
- * @note This example is for T-beam V1.2, T-Beam-BPF, T-Beam SUPREME factory examples
- * @note This example is for T-beam V1.2, T-Beam-BPF, T-Beam SUPREME factory examples
- * @note This example is for T-beam V1.2, T-Beam-BPF, T-Beam SUPREME factory examples
- * @note This example is for T-beam V1.2, T-Beam-BPF, T-Beam SUPREME factory examples
- */
+ * @note This example is for T-beam V1.2, T-Beam-BPF,T-Beam-1W-xxxx, T-Beam SUPREME factory examples
+ * @note This example is for T-beam V1.2, T-Beam-BPF,T-Beam-1W-xxxx, T-Beam SUPREME factory examples
+ * @note This example is for T-beam V1.2, T-Beam-BPF,T-Beam-1W-xxxx, T-Beam SUPREME factory examples
+ * @note This example is for T-beam V1.2, T-Beam-BPF,T-Beam-1W-xxxx, T-Beam SUPREME factory examples
+ *
+ * | Board | B1 | B2 |
+ * | ---------------- | ----------- | ------------ |
+ * | T-Bema Supreme | Boot button | Power button |
+ * | T-Bema 1W SX1262 | Boot button | IO17 |
+ * | T-Bema 1W LR1121 | Boot button | IO17 |
+ * | T-Bema 1W LR2021 | Boot button | IO17 |
+ * | | | |
+ **/
#include
#include
@@ -42,9 +50,10 @@
#include
#include
#include
+#include
#include
-SensorQMC6310 qmc;
+MagnetometerBase *magnetometer = nullptr;
SensorQMI8658 qmi;
SensorPCF8563 rtc;
Adafruit_BME280 bme;
@@ -77,64 +86,44 @@ static void beginSensor();
#if defined(USING_SX1276)
-#ifdef T_BEAM_S3_BPF
-// BPF Freq range : 144Mhz ~ 148MHz
-#define CONFIG_RADIO_FREQ 144.0
-#else /*T_BEAM_S3_BPF*/
-#define CONFIG_RADIO_FREQ 868.0
-#endif /*T_BEAM_S3_BPF*/
-
-#define CONFIG_RADIO_OUTPUT_POWER 17
-#define CONFIG_RADIO_BW 125.0
-
+int txPowerLevel = CONFIG_RADIO_SUB1G_OUTPUT_POWER;
SX1276 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO1_PIN);
#elif defined(USING_SX1278)
-#ifdef T_BEAM_S3_BPF
-// BPF Freq range : 144Mhz ~ 148MHz
-#define CONFIG_RADIO_FREQ 144.0
-#else
-#define CONFIG_RADIO_FREQ 433.0
-#endif /*T_BEAM_S3_BPF*/
-#define CONFIG_RADIO_OUTPUT_POWER 17
-#define CONFIG_RADIO_BW 125.0
+int txPowerLevel = CONFIG_RADIO_SUB1G_OUTPUT_POWER;
SX1278 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO1_PIN);
#elif defined(USING_SX1262)
-#ifndef CONFIG_RADIO_FREQ
-#define CONFIG_RADIO_FREQ 868.0
-#endif
-#define CONFIG_RADIO_OUTPUT_POWER 22
-#define CONFIG_RADIO_BW 125.0
+int txPowerLevel = CONFIG_RADIO_SUB1G_OUTPUT_POWER;
SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#elif defined(USING_SX1280)
-#define CONFIG_RADIO_FREQ 2400.0
-#define CONFIG_RADIO_OUTPUT_POWER 13
-#define CONFIG_RADIO_BW 203.125
+
+int txPowerLevel = CONFIG_RADIO_2G4_OUTPUT_POWER;
SX1280 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#elif defined(USING_SX1280PA)
-#define CONFIG_RADIO_FREQ 2400.0
-#define CONFIG_RADIO_OUTPUT_POWER 3 // PA Version power range : -18 ~ 3dBm
-#define CONFIG_RADIO_BW 203.125
+
+int txPowerLevel = CONFIG_RADIO_2G4_OUTPUT_POWER; // PA Version power range : -18 ~ 3dBm
SX1280 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#elif defined(USING_LR1121)
// The maximum power of LR1121 2.4G band can only be set to 13 dBm
-#define CONFIG_RADIO_FREQ 2450.0
-#define CONFIG_RADIO_OUTPUT_POWER 13
-#define CONFIG_RADIO_BW 125.0
+// int txPowerLevel = CONFIG_RADIO_2G4_OUTPUT_POWER;
// The maximum power of LR1121 Sub 1G band can only be set to 22 dBm
-// #define CONFIG_RADIO_FREQ 868.0
-// #define CONFIG_RADIO_OUTPUT_POWER 22
-// #define CONFIG_RADIO_BW 125.0
+int txPowerLevel = CONFIG_RADIO_SUB1G_OUTPUT_POWER;
+
+LR1121 radio = new Module(RADIO_CS_PIN, RADIO_DIO_IRQ_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
+
+#elif defined(USING_LR2021)
+
+int txPowerLevel = CONFIG_RADIO_SUB1G_OUTPUT_POWER;
+LR2021 radio = new Module(RADIO_CS_PIN, RADIO_IRQ_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
-LR1121 radio = new Module(RADIO_CS_PIN, RADIO_DIO9_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#endif /*Radio option*/
@@ -144,6 +133,65 @@ LR1121 radio = new Module(RADIO_CS_PIN, RADIO_DIO9_PIN, RADIO_RST_PIN, RADIO_BUS
#endif
+#if defined(T_BEAM_1W_LR1121)
+// LR1121 Version PA RF switch table
+static const uint32_t pa_version_rf_switch_dio_pins[] = {
+ RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, RADIOLIB_NC
+};
+
+static const Module::RfSwitchMode_t low_sub1g_switch_table[] = {
+ // mode DIO5 DIO6 DIO7 DIO8
+ { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW} },
+ { LR11x0::MODE_TX, { LOW, LOW, LOW, LOW} },
+ { LR11x0::MODE_RX, { LOW, LOW, LOW, LOW} },
+ { LR11x0::MODE_TX_HP, { LOW, LOW, LOW, HIGH} }, //Sub1G DIO8 SET HIGH
+ { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW} },
+ { LR11x0::MODE_GNSS, { LOW, LOW, LOW, HIGH} },
+ { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH} },
+ END_OF_MODE_TABLE,
+};
+
+static const Module::RfSwitchMode_t high_2g4_switch_table[] = {
+ // mode DIO5 DIO6 DIO7 DIO8
+ { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW} },
+ { LR11x0::MODE_TX, { LOW, LOW, LOW, LOW} },
+ { LR11x0::MODE_RX, { LOW, LOW, LOW, LOW} },
+ { LR11x0::MODE_TX_HP, { LOW, LOW, LOW, LOW} },
+ { LR11x0::MODE_TX_HF, { LOW, LOW, HIGH, LOW} }, //2.4G TX DIO7 SET HIGH
+ { LR11x0::MODE_GNSS, { LOW, LOW, LOW, LOW} },
+ { LR11x0::MODE_WIFI, { LOW, HIGH, LOW, LOW} }, //2.4G RX DIO6 SET HIGH
+ END_OF_MODE_TABLE,
+};
+#elif defined(T_BEAM_1W_LR2021)
+// LR1121 Version PA RF switch table
+static const uint32_t pa_version_rf_switch_dio_pins[] = {
+ RADIOLIB_LR2021_DIO5, RADIOLIB_LR2021_DIO6, RADIOLIB_LR2021_DIO7, RADIOLIB_LR2021_DIO8, RADIOLIB_NC
+};
+
+static const Module::RfSwitchMode_t low_sub1g_switch_table[] = {
+ // mode DIO5 DIO6 DIO7 DIO8
+ { LR2021::MODE_STBY, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_TX, { LOW, LOW, LOW, HIGH} }, // Sub1G DIO8 SET HIGH
+ { LR2021::MODE_RX, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_RX_HF, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_TX_HF, { LOW, LOW, LOW, LOW} },
+ END_OF_MODE_TABLE,
+};
+
+static const Module::RfSwitchMode_t high_2g4_switch_table[] = {
+ //2.4G RX DIO6 SET HIGH
+ // mode DIO5 DIO6 DIO7 DIO8
+ { LR2021::MODE_STBY, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_TX, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_RX, { LOW, LOW, LOW, LOW} },
+ { LR2021::MODE_RX_HF, { HIGH, LOW, LOW, LOW} },
+ { LR2021::MODE_TX_HF, { LOW, LOW, HIGH, LOW} }, //2.4G TX DIO7 SET HIGH
+ END_OF_MODE_TABLE,
+};
+#endif /*T_BEAM_1W_LR1121 | T_BEAM_1W_LR2021*/
+
+
+
enum TransmissionDirection {
TRANSMISSION,
RECEIVE,
@@ -164,6 +212,33 @@ uint32_t gps_use_second = 0;
uint32_t gps_start_ms = 0;
extern uint8_t display_address;
+static uint8_t freq_index = 0;
+static const float factory_freq[] = {
+#ifdef T_BEAM_S3_BPF
+ 144.0, 148.0
+#else
+ 433.0, 470.0,
+ 850.0, 868.0,
+ 915.0, 920.0, 923.0,
+#if defined(USING_LR1121) || defined(USING_LR2021)
+ 2400, 2450
+#endif
+#endif
+
+};
+static const char *freq_table[] = {
+#ifdef T_BEAM_S3_BPF
+ "144.0MHz", "148.0MHz"
+#endif
+ "433MHz", "470MHz",
+ "850MHz", "868MHz",
+ "915MHz", "920MHz", "923MHz",
+#if defined(USING_LR1121) || defined(USING_LR2021)
+ "2400MHz", "2450MHz"
+#endif
+};
+static float current_freq = CONFIG_RADIO_FREQ;
+
FrameCallback frames[] = {
hwProbe,
radioTx,
@@ -197,6 +272,8 @@ AceButton button2;
#endif /*BUTTON2_PIN*/
String macStr;
+volatile bool freqSelectDone = false;
+volatile bool freqSelectMode = false;
void setFlag(void)
{
@@ -217,7 +294,10 @@ void sleepDevice()
radio.sleep();
display->clear();
- display->drawString(60, 28, "Sleep");
+
+ display->setFont(Roboto_Mono_Medium_12);
+ display->setTextAlignment(TEXT_ALIGN_CENTER);
+ display->drawString(64, 28, "DEVICE ENTER SLEEP");
display->display();
delay(2000);
display->displayOff();
@@ -385,7 +465,9 @@ void sleepDevice()
* | T-BeamV 1.2 OLED | ~ 450 uA |
* | T-BeamV 1.2 | ~ 440 uA |
* | T-Beam BPF V1.2 | ~ 350 uA |
- * | T-Beam 2W v1.0 | ~ 442 uA |
+ * | T-Beam 1W SX1262 | ~ 442 uA |
+ * | T-Beam 1W LR1121 | ~ 450 uA |
+ * | T-Beam 1W LR2021 | ~ 450 uA |
* | T-BeamS3 Supreme | ~ 1.45mA |
*
*/
@@ -436,20 +518,22 @@ void handleMenu()
#ifdef RADIO_CTRL
Serial.println("Turn off LAN,Trun on PA, Enter Tx mode.");
/*
- * 2W and BPF LoRa LAN Control ,set Low turn off LAN , TX Mode
+ * T-Beam 1W SX1262 Version and T-Beam BPF LoRa LAN Control ,set Low turn off LAN , TX Mode
* */
digitalWrite(RADIO_CTRL, LOW);
#endif /*RADIO_CTRL*/
#ifdef RADIO_TX_CW
- radio.transmitDirect();
+ {
+ int16_t state = radio.transmitDirect();
+ Serial.printf("transmitDirect:%d\n", state);
+ }
#else /*RADIO_TX_CW*/
Serial.println("Start transmit");
transmissionDirection = TRANSMISSION;
transmissionState = radio.transmit((uint8_t *)&transmissionCounter, 4);
if (transmissionState != RADIOLIB_ERR_NONE) {
- Serial.print(F("[Radio] transmit packet failed! err:"));
- Serial.println(transmissionState);
+ Serial.printf("[Radio] transmit packet failed! err: %d\n", transmissionState);
}
#endif /*RADIO_TX_CW*/
break;
@@ -458,7 +542,7 @@ void handleMenu()
#ifdef RADIO_CTRL
Serial.println("Turn on LAN, Enter Rx mode.");
/*
- * 2W and BPF LoRa LAN Control ,set HIGH turn on LAN ,RX Mode
+ * T-Beam 1W SX1262 Version and T-Beam BPF LoRa LAN Control ,set HIGH turn on LAN ,RX Mode
* */
digitalWrite(RADIO_CTRL, HIGH);
#endif /*RADIO_CTRL*/
@@ -466,7 +550,7 @@ void handleMenu()
transmissionDirection = RECEIVE;
transmissionState = radio.startReceive();
if (transmissionState != RADIOLIB_ERR_NONE) {
- Serial.println(F("[Radio] Received packet failed!"));
+ Serial.printf("[Radio] Received packet failed! err: %d\n", transmissionState);
}
break;
@@ -474,7 +558,7 @@ void handleMenu()
#ifdef RADIO_CTRL
Serial.println("Turn on LAN, Enter Rx mode.");
/*
- * 2W and BPF LoRa LAN Control ,set HIGH turn on LAN ,RX Mode
+ * T-Beam 1W SX1262 Version and T-Beam BPF LoRa LAN Control ,set HIGH turn on LAN ,RX Mode
* */
digitalWrite(RADIO_CTRL, HIGH);
#endif /*RADIO_CTRL*/
@@ -488,30 +572,42 @@ void prevButtonHandleEvent(AceButton *button, uint8_t eventType, uint8_t butto
{
switch (eventType) {
case AceButton::kEventClicked:
- Serial.printf("prevButtonHandleEvent currentFrames:%d frames_count:%d\n", currentFrames, max_frames);
+ if (freqSelectMode) {
+ freq_index = (freq_index + 1) % (sizeof(freq_table) / sizeof(freq_table[0]));
+ } else {
+ Serial.printf("prevButtonHandleEvent currentFrames:%d frames_count:%d\n", currentFrames, max_frames);
#ifdef BUTTON2_PIN
- currentFrames = ((currentFrames + 1) >= max_frames) ? currentFrames : currentFrames + 1;
+ currentFrames = ((currentFrames + 1) >= max_frames) ? currentFrames : currentFrames + 1;
#else /*BUTTON2_PIN*/
- currentFrames++;
- currentFrames %= max_frames;
+ currentFrames++;
+ currentFrames %= max_frames;
#endif /*BUTTON2_PIN*/
- handleMenu();
+ handleMenu();
+ }
break;
case AceButton::kEventLongPressed:
- sleepDevice();
+ if (!freqSelectMode) {
+ sleepDevice();
+ }
break;
default:
break;
}
}
+#ifdef BUTTON2_PIN
void nextButtonHandleEvent(AceButton *button, uint8_t eventType, uint8_t buttonState)
{
switch (eventType) {
case AceButton::kEventClicked:
- Serial.printf("nextButtonHandleEvent currentFrames:%d frames_count:%d\n", currentFrames, max_frames);
- currentFrames = ((currentFrames - 1) < 0) ? currentFrames : currentFrames - 1;
- handleMenu();
+ if (freqSelectMode) {
+ int tableSize = sizeof(freq_table) / sizeof(freq_table[0]);
+ freq_index = (freq_index - 1 < 0) ? (tableSize - 1) : freq_index - 1;
+ } else {
+ Serial.printf("nextButtonHandleEvent currentFrames:%d frames_count:%d\n", currentFrames, max_frames);
+ currentFrames = ((currentFrames - 1) < 0) ? currentFrames : currentFrames - 1;
+ handleMenu();
+ }
break;
case AceButton::kEventLongPressed:
Serial.println("Long pressed!");
@@ -519,9 +615,14 @@ void nextButtonHandleEvent(AceButton *button, uint8_t eventType, uint8_t butto
Serial.println("Long pressed! ,on/off FAN");
digitalWrite(FAN_CTRL, 1 - digitalRead(FAN_CTRL));
#endif /*FAN_CTRL*/
+ if (freqSelectMode) {
+ freqSelectDone = true;
+ }
break;
}
}
+#endif /*BUTTON2_PIN*/
+
void timeavailable(struct timeval *t)
{
@@ -565,7 +666,7 @@ void setup()
Serial.println(info.wifi_sta_disconnected.reason);
}, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
- setupBoards(true);
+ setupBoards(false);
setupBLE();
@@ -659,7 +760,43 @@ void setup()
Serial.printf("[%s]:", RADIO_TYPE_STR);
Serial.println(F(" Selected"));
-#if defined(RADIO_TX_CW) && !defined(USING_LR1121)
+
+ /***********************
+ * Frequency Selection
+ ***********************/
+ freqSelectMode = true;
+ freqSelectDone = false;
+ freq_index = 0;
+ display->clear();
+ display->setFont(Roboto_Mono_Medium_12);
+ display->setTextAlignment(TEXT_ALIGN_CENTER);
+ while (!freqSelectDone) {
+ display->clear();
+ display->drawString(64, 10, "Select Frequency");
+ display->drawLine(0, 28, 128, 28);
+ display->drawString(64, 32, freq_table[freq_index]);
+ display->drawString(64, 48, "B1:Up B2:Down L:OK");
+ display->display();
+ button.check();
+#ifdef BUTTON2_PIN
+ button2.check();
+#endif
+#ifdef HAS_PMU
+ loopPMU(power_key_pressed, power_key_long_pressed);
+#endif
+ delay(50);
+ }
+ freqSelectMode = false;
+ current_freq = factory_freq[freq_index];
+ Serial.printf("Selected frequency: %s\n", freq_table[freq_index]);
+
+
+
+#if defined(USING_LR2021)
+ radio.irqDioNum = RADIO_DIO_NUM;
+#endif
+
+#if defined(RADIO_TX_CW) && !defined(USING_LR1121) && !defined(USING_LR2021)
Serial.print("Begin Radio FSK ");
int state = radio.beginFSK();
#else
@@ -673,7 +810,11 @@ void setup()
Serial.println(F("Failed!"));
}
- Serial.printf("Freq:%.2f TxPower:%d Bandwidth:%.2f\n", CONFIG_RADIO_FREQ, CONFIG_RADIO_OUTPUT_POWER, CONFIG_RADIO_BW);
+ Serial.printf("\nRadioParams:\n\t->Freq:%.2fMhz\n\tSub1G TxPower:%d\n\t2.4G TxPower:%d\n\tBandwidth:%.2f\n",
+ factory_freq[freq_index],
+ CONFIG_RADIO_SUB1G_OUTPUT_POWER,
+ CONFIG_RADIO_2G4_OUTPUT_POWER,
+ CONFIG_RADIO_BW);
#if defined(RADIO_RX_PIN) && defined(RADIO_TX_PIN)
//The SX1280 version needs to set RX, TX antenna switching pins
@@ -689,7 +830,7 @@ void setup()
* LR1121 : Allowed values are in range from 150.0 to 960.0 MHz, 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations.
* * * */
- if (radio.setFrequency(CONFIG_RADIO_FREQ) == RADIOLIB_ERR_INVALID_FREQUENCY) {
+ if (radio.setFrequency(factory_freq[freq_index]) == RADIOLIB_ERR_INVALID_FREQUENCY) {
Serial.println(F("Selected frequency is invalid for this module!"));
while (true);
}
@@ -741,6 +882,13 @@ void setup()
}
#endif /*RADIO_TX_CW*/
+#if defined(USING_LR1121) || defined(USING_LR2021)
+ if (current_freq < 2400) {
+ txPowerLevel = CONFIG_RADIO_SUB1G_OUTPUT_POWER;
+ } else {
+ txPowerLevel = CONFIG_RADIO_2G4_OUTPUT_POWER;
+ }
+#endif
/*
* Sets transmission output power.
* SX1278/SX1276 : Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). High power +20 dBm operation is also supported, on the PA_BOOST pin. Defaults to PA_BOOST.
@@ -748,13 +896,15 @@ void setup()
* SX1268 : Allowed values are in range from -9 to 22 dBm.
* SX1280 : Allowed values are in range from -18 to 13 dBm. PA Version range : -18 ~ 3dBm
* LR1121 : Allowed values are in range from -17 to 22 dBm (high-power PA) or -18 to 13 dBm (High-frequency PA)
+ * LR2021 : Allowed values are in range from -9 to 22 dBm (sub-GHz PA) or -19 to 12 dBm (high-frequency PA).
+
* * * */
- if (radio.setOutputPower(CONFIG_RADIO_OUTPUT_POWER) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
+ if (radio.setOutputPower(txPowerLevel) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
Serial.println(F("Selected output power is invalid for this module!"));
while (true);
}
-#if !defined(USING_SX1280) && !defined(USING_LR1121) && !defined(USING_SX1280PA)
+#if !defined(USING_SX1280) && !defined(USING_LR1121) && !defined(USING_SX1280PA) && !defined(USING_LR2021)
/*
* Sets current limit for over current protection at transmitter amplifier.
* SX1278/SX1276 : Allowed values range from 45 to 120 mA in 5 mA steps and 120 to 240 mA in 10 mA steps.
@@ -786,7 +936,7 @@ void setup()
}
-#if defined(USING_LR1121)
+#if defined(USING_LR1121) && !defined(T_BEAM_1W_LR1121)
// LR1121
// set RF switch configuration for Wio WM1110
// Wio WM1110 uses DIO5 and DIO6 for RF switching
@@ -811,6 +961,19 @@ void setup()
// LR1121 TCXO Voltage 2.85~3.15V
radio.setTCXO(3.0);
+#elif defined(USING_LR1121) || defined(USING_LR2021)
+
+ // radio.setDioIrqParams(RADIOLIB_LR11X0_DIO10);
+
+ if (current_freq < 2400) {
+ Serial.printf("Using low frequency switch table for PA version\n");
+ radio.setRfSwitchTable(pa_version_rf_switch_dio_pins, low_sub1g_switch_table);
+ } else {
+ Serial.printf("Using high frequency switch table for PA version\n");
+ radio.setRfSwitchTable(pa_version_rf_switch_dio_pins, high_2g4_switch_table);
+ }
+ // LR1121 TCXO Voltage 2.85~3.15V
+ radio.setTCXO(3.0);
#endif
#if defined(USING_SX1262)
@@ -821,6 +984,7 @@ void setup()
// when new packet is received
radio.setPacketReceivedAction(setFlag);
+ // radio.standby();
// start listening for LoRa packets
Serial.println(F("[Radio] Starting to listen ... "));
state = radio.startReceive();
@@ -839,25 +1003,10 @@ void setup()
}
// PMU Power key callback
-static uint8_t freq_index = 0;
-const float factory_freq[] = {433.0, 470.0, 850.0, 868.0, 915.0, 923.0
-#if defined(USING_LR1121)
- , 2400, 2450
-#endif
- };
-float current_freq = CONFIG_RADIO_FREQ;
-void power_key_pressed()
+void changeFreq()
{
-#if defined(JAPAN_MIC_CERTIFICATION) || defined(T_BEAM_S3_BPF)
- // Turn on/off display
- static bool isOn = true;
- isOn ? display->displayOff() : display->displayOn();
- isOn ^= 1;
- return;
-#else /*defined(JAPAN_MIC_CERTIFICATION) || defined(T_BEAM_S3_BPF)*/
-
// Set freq function
radio.standby();
#if defined(USING_LR1121)
@@ -883,6 +1032,15 @@ void power_key_pressed()
if (current_freq < 2400) {
max_tx_power = 22;
forceHighPower = true;
+ // #ifdef T_BEAM_1W_LR1121
+ // Serial.printf("Using low frequency switch table for PA version\n");
+ // radio.setRfSwitchTable(pa_version_rf_switch_dio_pins, high_2g4_switch_table);
+ // #endif
+ } else {
+ // #ifdef T_BEAM_1W_LR1121
+ // Serial.printf("Using high frequency switch table for PA version\n");
+ // radio.setRfSwitchTable(pa_version_rf_switch_dio_pins, low_sub1g_switch_table);
+ // #endif
}
if (radio.setOutputPower(max_tx_power, forceHighPower) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
Serial.printf("Selected output power %d is invalid for this module!\n", max_tx_power);
@@ -907,6 +1065,33 @@ void power_key_pressed()
}
break;
}
+}
+
+void power_key_long_pressed()
+{
+ if (freqSelectMode) {
+ freqSelectDone = true;
+ }
+}
+
+void power_key_pressed()
+{
+#if defined(JAPAN_MIC_CERTIFICATION) || defined(T_BEAM_S3_BPF)
+ // Turn on/off display
+ static bool isOn = true;
+ isOn ? display->displayOff() : display->displayOn();
+ isOn ^= 1;
+ return;
+#else /*defined(JAPAN_MIC_CERTIFICATION) || defined(T_BEAM_S3_BPF)*/
+ // changeFreq();
+ if (freqSelectMode) {
+ int tableSize = sizeof(freq_table) / sizeof(freq_table[0]);
+ freq_index = (freq_index - 1 < 0) ? (tableSize - 1) : freq_index - 1;
+ } else {
+ Serial.printf("nextButtonHandleEvent currentFrames:%d frames_count:%d\n", currentFrames, max_frames);
+ currentFrames = ((currentFrames - 1) < 0) ? currentFrames : currentFrames - 1;
+ handleMenu();
+ }
#endif /*defined(JAPAN_MIC_CERTIFICATION) || defined(T_BEAM_S3_BPF)*/
}
@@ -1006,7 +1191,7 @@ void radioTx(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t
display->drawString(64 + x, 32 + y, buffer);
} else {
display->setTextAlignment(TEXT_ALIGN_LEFT);
- display->drawString(0 + x, 16 + y, "Freq:" + String(current_freq) + "MHz");
+ display->drawString(0 + x, 16 + y, "Freq:" + String(freq_table[freq_index]));
display->drawString(0 + x, 32 + y, "TX :" + String(transmissionCounter));
}
@@ -1072,8 +1257,8 @@ void radioRx(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t
} else {
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
- display->drawString(0 + x, 16 + y, "Freq:" + String(current_freq) + "MHz");
- display->drawString(0 + x, 32 + y, "RX :" + String(recvCounter));
+ display->drawString(0 + x, 16 + y, "Freq:" + String(freq_table[freq_index]));
+ display->drawString(0 + x, 32 + y, "RX :" + String(recvCounter));
display->drawString(0 + x, 48 + y, "RSSI:" + String(radioRSSI));
}
}
@@ -1082,6 +1267,7 @@ void hwProbe(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t
{
display->setFont(Roboto_Mono_Medium_12);
display->setTextAlignment(TEXT_ALIGN_LEFT);
+
#if defined(T_BEAM_S3_SUPREME)
display->drawString(x, 3 + y, "6DOF");
display->drawString(x, 15 + y, "Power");
@@ -1104,7 +1290,7 @@ void hwProbe(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t
display->drawString(62 + x, 51 + y, "OSC");
display->setTextAlignment(TEXT_ALIGN_RIGHT);
- display->drawString(display->width() + x, 3 + y, ((deviceOnline & QMC6310U_ONLINE) || (deviceOnline & QMC6310N_ONLINE)) ? "+" : "-");
+ display->drawString(display->width() + x, 3 + y, ((deviceOnline & QMC6310U_ONLINE) || (deviceOnline & QMC6310N_ONLINE) || (deviceOnline & QMC6309_ONLINE)) ? "+" : "-");
display->drawString(display->width() + x, 15 + y, (deviceOnline & BME280_ONLINE ) || (deviceOnline & BMP280_ONLINE ) ? "+" : "-");
display->drawString(display->width() + x, 27 + y, (deviceOnline & PSRAM_ONLINE ) ? "+" : "-");
display->drawString(display->width() + x, 39 + y, (deviceOnline & SDCARD_ONLINE ) ? "+" : "-");
@@ -1116,6 +1302,7 @@ void hwProbe(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t
display->drawString(x, 48 + y, "OLED");
display->setTextAlignment(TEXT_ALIGN_CENTER);
+ display->drawString(52 + x, 0 + y, BOARD_VARIANT_NAME " " RADIO_TYPE_STR);
display->drawString(52 + x, 16 + y, (deviceOnline & RADIO_ONLINE ) ? "+" : "-");
display->drawString(52 + x, 32 + y, (deviceOnline & GPS_ONLINE ) ? "+" : "-");
@@ -1327,90 +1514,33 @@ void sensorInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x,
display->drawString(display->width() + x, y + 48, String(pressure / 1000.0) + " kPa");
}
-
-static const int centreX = 32;
-static const int centreY = 40;
-static const int radius = 10;
Madgwick filter;
-int last_dx = centreX, last_dy = centreY, dx, dy;
-
-void arrow(OLEDDisplay *display, int offsetX, int offsetY, int x2, int y2, int x1, int y1, int alength, int awidth, OLEDDISPLAY_COLOR color)
-{
- display->setColor(color);
- float distance;
- int dx, dy, x2o, y2o, x3, y3, x4, y4, k;
- distance = sqrt(pow((x1 - x2), 2) + pow((y1 - y2), 2));
- dx = x2 + (x1 - x2) * alength / distance;
- dy = y2 + (y1 - y2) * alength / distance;
- k = awidth / alength;
- x2o = x2 - dx;
- y2o = dy - y2;
- x3 = y2o * k + dx;
- y3 = x2o * k + dy;
- x4 = dx - y2o * k;
- y4 = dy - x2o * k;
- display->drawLine(x1 + offsetX, y1 + offsetY, offsetX + x2, offsetY + y2);
- display->drawLine(x1 + offsetX, y1 + offsetY, offsetX + dx, offsetY + dy);
- display->drawLine(x3 + offsetX, y3 + offsetY, offsetX + x4, offsetY + y4);
- display->drawLine(x3 + offsetX, y3 + offsetY, offsetX + x2, offsetY + y2);
- display->drawLine(x2 + offsetX, y2 + offsetY, offsetX + x4, offsetY + y4);
-}
-
-int drawCompass(OLEDDisplay *display, int16_t x, int16_t y, float magX, float magY)
-{
- int angle;
- display->drawString(x + 29, y + 16, "N");
- display->drawString(x + 0, y + 32, "W");
- display->drawString(x + 58, y + 32, "E");
- display->drawString(x + 29, y + 50, "S");
-
- float heading = atan2(magY, magX); // Result is in radians
- // Now add the 'Declination Angle' for you location. Declination is the variation in magnetic field at your location.
- // Find your declination here: http://www.magnetic-declination.com/
- // At my location it is : -2° 20' W, or -2.33 Degrees, which needs to be in radians so = -2.33 / 180 * PI = -0.041 West is + E is -
- // Make declination = 0 if you can't find your Declination value, the error is negible for nearly all locations
- float declination = -0.041;
- heading = heading + declination;
- if (heading < 0) heading += 2 * PI; // Correct for when signs are reversed.
- if (heading > 2 * PI) heading -= 2 * PI; // Correct for when heading exceeds 360-degree, especially when declination is included
- angle = int(heading * 180 / M_PI); // Convert radians to degrees for more a more usual result
- // For the screen -X = up and +X = down and -Y = left and +Y = right, so does not follow coordinate conventions
- dx = (0.7 * radius * cos((angle - 90) * 3.14 / 180)) + centreX + x; // calculate X position for the screen coordinates - can be confusing!
- dy = (0.7 * radius * sin((angle - 90) * 3.14 / 180)) + centreY + y; // calculate Y position for the screen coordinates - can be confusing!
- arrow(display, x, y, last_dx, last_dy, centreX + x, centreY + y, 2, 2, BLACK); // Erase last arrow
- arrow(display, x, y, dx, dy, x + centreX, centreY + y, 2, 2, WHITE); // Draw arrow in new position
- return angle;
-}
-
-void getMagData(float *x, float *y)
-{
- float z = 0;
- if (qmc.isDataReady()) {
- qmc.readData();
- qmc.getMag(*x, *y, z);
- }
-}
void imuInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, int16_t y)
{
- static float magX = 0, magY = 0;
- static int angle = 0;
- static float roll, pitch, heading;
+ static float roll, pitch, heading, strength;
+ static uint32_t interval = 0;
- getMagData(&magX, &magY);
- angle = drawCompass(display, x, y, magX, magY);
+ MagnetometerData data;
+ if (millis() - interval > 100) {
+ if (magnetometer) {
+ if (magnetometer->readData(data)) {
+ strength = MagnetometerUtils::calculateMagneticStrength(data);
+ strength = MagnetometerUtils::gaussToMicroTesla(strength);
+ }
+ }
+ interval = millis();
+ }
display->setFont(Roboto_Mono_Medium_12);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, 0 + y, "IMU");
display->setTextAlignment(TEXT_ALIGN_LEFT);
- display->setColor(BLACK);
- display->fillRect(x + 80, y + 16, 25, 50);
- display->setColor(WHITE);
- display->setFont(Roboto_Mono_Medium_12);
- display->drawString(x + 75, y + 16, String(angle) + "°");
+ display->drawString(x + 0, y + 16, "STRENGTH:");
+ display->drawString(x + 0, y + 32, "ROLL:");
+ display->drawString(x + 0, y + 48, "HEADING:");
// Read raw data from IMU
if (digitalRead(IMU_INT) == HIGH) {
@@ -1422,29 +1552,112 @@ void imuInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, in
roll = filter.getRoll();
pitch = filter.getPitch();
heading = filter.getYaw();
- // Serial.printf("roll:%.2f pitch:%.2f heading:%.2f\n", roll, pitch, heading);
}
- display->drawString(x + 75, y + 32, String(heading) + "°");
+ display->setTextAlignment(TEXT_ALIGN_RIGHT);
+ display->drawString(display->width() + x, y + 16, String(strength) + "uT");
+ display->drawString(display->width() + x, y + 32, String(roll) + "°");
+ display->drawString(display->width() + x, y + 48, String(heading) + "°");
}
static void beginSensor()
{
extern uint8_t mag_address;
+
// PMU and RTC share I2C bus
if (!rtc.begin(PMU_WIRE_PORT, I2C_SDA, I2C_SCL)) {
Serial.println("Failed to find PCF8563 - check your wiring!");
}
- if (!qmc.begin(Wire, mag_address, I2C_SDA, I2C_SCL)) {
- Serial.println("Failed to find QMC6310 - check your wiring!");
- } else {
- qmc.configMagnetometer(
- SensorQMC6310::MODE_CONTINUOUS,
- SensorQMC6310::RANGE_8G,
- SensorQMC6310::DATARATE_200HZ,
- SensorQMC6310::OSR_1,
- SensorQMC6310::DSR_1);
+
+ // The desired output data rate in Hz. Allowed values are 1.0, 10.0, 50.0, 100.0 and 200.0HZ.
+ float data_rate_hz = 200.0f;
+ // op_mode: Allowed values are SUSPEND, NORMAL, SINGLE_MEASUREMENT, CONTINUOUS_MEASUREMENT
+ OperationMode op_mode = OperationMode::CONTINUOUS_MEASUREMENT;
+ // full_scale: Allowed values are FS_8G, FS_16G ,FS_32G
+ MagFullScaleRange full_scale = MagFullScaleRange::FS_8G;
+ // over_sample_ratio: Allowed values are OSR_1, OSR_2, OSR_4, OSR_8
+ MagOverSampleRatio over_sample_ratio = MagOverSampleRatio::OSR_1;
+ // down_sample_ratio: QMC6309 does not support downsampling rate settings; this parameter is ignored.
+ MagDownSampleRatio down_sample_ratio = MagDownSampleRatio::DSR_1;
+
+ Serial.printf("Probing magnetometer at address 0x%02X...\n", mag_address);
+ if (magnetometer == nullptr && mag_address == QMC6310U_SLAVE_ADDRESS) {
+ magnetometer = new SensorQMC6310();
+ if (!static_cast(magnetometer)->begin(Wire, QMC6310U_SLAVE_ADDRESS, I2C_SDA, I2C_SCL)) {
+ Serial.println("Failed to find QMC6310U - check your wiring!");
+ delete magnetometer;
+ magnetometer = nullptr;
+ } else {
+ Serial.println("QMC6310U found!");
+ // The desired output data rate in Hz. Allowed values are 10.0, 50.0, 100.0 and 200.0HZ.
+ data_rate_hz = 10.0f;
+ // op_mode: Allowed values are SUSPEND, NORMAL, SINGLE_MEASUREMENT, CONTINUOUS_MEASUREMENT
+ op_mode = OperationMode::CONTINUOUS_MEASUREMENT;
+ // full_scale: Allowed values are FS_2G, FS_8G, FS_12G ,FS_30G
+ full_scale = MagFullScaleRange::FS_8G;
+ // over_sample_ratio: Allowed values are OSR_1, OSR_2, OSR_4, OSR_8
+ over_sample_ratio = MagOverSampleRatio::OSR_1;
+ // down_sample_ratio: Allowed values are DSR_1, DSR_2, DSR_4, DSR_8
+ down_sample_ratio = MagDownSampleRatio::DSR_1;
+ }
}
+
+ if (magnetometer == nullptr && mag_address == QMC6310N_SLAVE_ADDRESS) {
+ magnetometer = new SensorQMC6310();
+ if (!static_cast(magnetometer)->begin(Wire, QMC6310N_SLAVE_ADDRESS, I2C_SDA, I2C_SCL)) {
+ Serial.println("Failed to find QMC6310 - check your wiring!");
+ delete magnetometer;
+ magnetometer = nullptr;
+ } else {
+ Serial.println("QMC6310N found!");
+ // The desired output data rate in Hz. Allowed values are 10.0, 50.0, 100.0 and 200.0HZ.
+ data_rate_hz = 10.0f;
+ // op_mode: Allowed values are SUSPEND, NORMAL, SINGLE_MEASUREMENT, CONTINUOUS_MEASUREMENT
+ op_mode = OperationMode::CONTINUOUS_MEASUREMENT;
+ // full_scale: Allowed values are FS_2G, FS_8G, FS_12G ,FS_30G
+ full_scale = MagFullScaleRange::FS_8G;
+ // over_sample_ratio: Allowed values are OSR_1, OSR_2, OSR_4, OSR_8
+ over_sample_ratio = MagOverSampleRatio::OSR_1;
+ // down_sample_ratio: Allowed values are DSR_1, DSR_2, DSR_4, DSR_8
+ down_sample_ratio = MagDownSampleRatio::DSR_1;
+ }
+ }
+
+ if (magnetometer == nullptr && mag_address == QMC6309_SLAVE_ADDRESS) {
+ magnetometer = new SensorQMC6309();
+ if (!static_cast(magnetometer)->begin(Wire, QMC6309_SLAVE_ADDRESS, I2C_SDA, I2C_SCL)) {
+ Serial.println("Failed to find QMC6309 - check your wiring!");
+ delete magnetometer;
+ magnetometer = nullptr;
+ } else {
+ Serial.println("QMC6309 found!");
+ // The desired output data rate in Hz. Allowed values are 1.0, 10.0, 50.0, 100.0 and 200.0HZ.
+ data_rate_hz = 10.0f;
+ // op_mode: Allowed values are SUSPEND, NORMAL, SINGLE_MEASUREMENT, CONTINUOUS_MEASUREMENT
+ op_mode = OperationMode::CONTINUOUS_MEASUREMENT;
+ // full_scale: Allowed values are FS_8G, FS_16G ,FS_32G
+ full_scale = MagFullScaleRange::FS_8G;
+ // over_sample_ratio: Allowed values are OSR_1, OSR_2, OSR_4, OSR_8
+ over_sample_ratio = MagOverSampleRatio::OSR_1;
+ // down_sample_ratio: QMC6309 does not support downsampling rate settings; this parameter is ignored.
+ down_sample_ratio = MagDownSampleRatio::DSR_1;
+ }
+ }
+
+ if (magnetometer) {
+ /* Config Magnetometer */
+ if (magnetometer->configMagnetometer(
+ op_mode,
+ full_scale,
+ data_rate_hz,
+ over_sample_ratio,
+ down_sample_ratio)) {
+ Serial.println("Magnetometer configured successfully.");
+ } else {
+ Serial.println("Magnetometer configuration failed.");
+ }
+ }
+
extern uint8_t bme280_address;
if (!bme.begin(bme280_address)) {
Serial.println("Failed to find BME280 - check your wiring!");
diff --git a/examples/Factory/LoRaBoards.cpp b/examples/Factory/LoRaBoards.cpp
index 8acfe74..66384de 100644
--- a/examples/Factory/LoRaBoards.cpp
+++ b/examples/Factory/LoRaBoards.cpp
@@ -326,7 +326,7 @@ bool beginPower()
// Set the time of pressing the button to turn off
- PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
+ PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_8S);
uint8_t opt = PMU->getPowerKeyPressOffTime();
Serial.print("PowerKeyPressOffTime:");
switch (opt) {
@@ -407,7 +407,7 @@ void disablePeripherals()
#endif
}
-void loopPMU(void (*pressed_cb)(void))
+void loopPMU(void (*pressed_cb)(void), void (*long_press_cb)(void))
{
if (!PMU) {
return;
@@ -444,6 +444,9 @@ void loopPMU(void (*pressed_cb)(void))
}
if (PMU->isPekeyLongPressIrq()) {
Serial.println("isPekeyLongPress");
+ if (long_press_cb) {
+ long_press_cb();
+ }
}
if (PMU->isBatChargeDoneIrq()) {
Serial.println("isBatChargeDone");
@@ -834,7 +837,7 @@ void setupBoards(bool disable_u8g2 )
#ifdef HAS_GPS
-#if defined(T_BEAM_S3_SUPREME) || defined(T_BEAM_1W) || defined(T_BEAM_S3_BPF)
+#if defined(T_BEAM_S3_SUPREME) || defined(T_BEAM_1W_SX1262) || defined(T_BEAM_1W_LR1121) || defined(T_BEAM_1W_LR2021) || defined(T_BEAM_S3_BPF)
// T-Beam v1.2 skips L76K
find_gps = beginGPS();
#endif
@@ -996,6 +999,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Factory/LoRaBoards.h b/examples/Factory/LoRaBoards.h
index 58288ef..b218eb5 100644
--- a/examples/Factory/LoRaBoards.h
+++ b/examples/Factory/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
@@ -105,7 +106,7 @@ void scanWiFi();
#ifdef HAS_PMU
extern XPowersLibInterface *PMU;
extern bool pmuInterrupt;
-void loopPMU(void (*pressed_cb)(void));
+void loopPMU(void (*pressed_cb)(void), void (*long_press_cb)(void) = NULL);
bool beginPower();
void disablePeripherals();
#else
diff --git a/examples/Factory/utilities.h b/examples/Factory/utilities.h
index 08b2145..b2c294a 100644
--- a/examples/Factory/utilities.h
+++ b/examples/Factory/utilities.h
@@ -28,7 +28,7 @@
// 3. --------------T3 V3.0 TCXO-------------------------------
// Product: https://lilygo.cc/products/t3-tcxo
-// #define T3_V3_0_SX1276_TCXO
+// #define T3_V3_0_SX1276_TCXO
// 4. --------------T-BEAM ESP32-------------------------------
// Product: https://lilygo.cc/products/t-beam
@@ -46,7 +46,7 @@
// 6. --------------T3 S3 V1.0 or T3 S3 V1.3 -------------------
// Product: https://lilygo.cc/products/t3s3-v1-0 , same v1.3
-// Product: https://lilygo.cc/products/t3-s3-v1-3
+// Product: https://lilygo.cc/products/t3-s3-v1-3
// #define T3_S3_V1_2_SX1262
// #define T3_S3_V1_2_SX1276
@@ -72,9 +72,10 @@
// #define T_BEAM_S3_BPF
// --------------LoRa 2W -------------------------------------
-// Product: ...
-// #define T_BEAM_1W
-
+// Product: https://lilygo.cc/products/t-beam-1w
+// #define T_BEAM_1W_SX1262
+// #define T_BEAM_1W_LR1121
+// #define T_BEAM_1W_LR2021
// #define T3_V1_6_SX1276_TCXO // Production has stopped
@@ -86,7 +87,6 @@
#if defined(T_BEAM_SX1262) || defined(T_BEAM_SX1276) || defined(T_BEAM_SX1278) || defined(T_BEAM_LR1121)
-
#if defined(T_BEAM_SX1262)
#ifndef USING_SX1262
#define USING_SX1262
@@ -128,6 +128,7 @@
// LR1121 Only
#define RADIO_DIO9_PIN 33
+#define RADIO_DIO_IRQ_PIN (RADIO_DIO9_PIN)
#define BOARD_LED 4
@@ -330,6 +331,7 @@
#define RADIO_DIO9_PIN 26 //LR1121 DIO9
#define RADIO_BUSY_PIN 32 //LR1121 BUSY
+#define RADIO_DIO_IRQ_PIN (RADIO_DIO9_PIN)
#endif
@@ -384,6 +386,10 @@
#ifndef USING_SX1280PA
#define USING_SX1280PA
#endif
+#pragma message "Using SX1280PA,The transmit power must not exceed 3dBm, otherwise it will cause permanent damage to LoRa."
+#define CONFIG_RADIO_2G4_OUTPUT_POWER 3
+#define CONFIG_RADIO_OUTPUT_POWER CONFIG_RADIO_2G4_OUTPUT_POWER
+
#elif defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121)
#ifndef USING_LR1121
#define USING_LR1121
@@ -392,6 +398,10 @@
#ifndef USING_LR1121PA
#define USING_LR1121PA
#endif
+#pragma message "Using LR1121PA,The transmit power must not exceed 0dBm, otherwise it will cause permanent damage to LoRa."
+#define CONFIG_RADIO_2G4_OUTPUT_POWER 0
+#define CONFIG_RADIO_OUTPUT_POWER CONFIG_RADIO_2G4_OUTPUT_POWER
+
#endif // T3_S3_V1_2_SX1262
@@ -455,6 +465,7 @@
#define RADIO_DIO9_PIN 36 //LR1121 DIO9 = IO36
#define RADIO_BUSY_PIN 34 //LR1121 BUSY = IO34
+#define RADIO_DIO_IRQ_PIN (RADIO_DIO9_PIN)
#define LILYGO_RADIO_2G4_TX_POWER_LIMIT 13 //LR1121 2.4G TX Power Limit
@@ -462,6 +473,7 @@
#define RADIO_DIO9_PIN 36 //LR1121 DIO9 = IO36
#define RADIO_BUSY_PIN 34 //LR1121 BUSY = IO34
+#define RADIO_DIO_IRQ_PIN (RADIO_DIO9_PIN)
#define LILYGO_RADIO_2G4_TX_POWER_LIMIT 0 //LR1121 2.4G TX Power Limit
#define USING_LR1121
@@ -521,6 +533,7 @@
// LR1121 Version
#define RADIO_DIO9_PIN (1)
+#define RADIO_DIO_IRQ_PIN (RADIO_DIO9_PIN)
#define SPI_MOSI (35)
#define SPI_SCK (36)
@@ -686,10 +699,28 @@
#define BOARD_VARIANT_NAME "T-Beam BPF"
-#elif defined(T_BEAM_1W)
+#elif defined(T_BEAM_1W_SX1262) || defined(T_BEAM_1W_LR1121) || defined(T_BEAM_1W_LR2021)
+#ifdef T_BEAM_1W_SX1262
#ifndef USING_SX1262
#define USING_SX1262
+#endif
+#endif
+
+#ifdef T_BEAM_1W_LR1121
+#ifndef USING_LR1121
+#define USING_LR1121
+#endif
+#pragma message "Using LR1121 PA Version,The transmit power must not exceed 0dBm, otherwise it will cause permanent damage to LoRa."
+#define CONFIG_RADIO_2G4_OUTPUT_POWER 0
+#endif
+
+#ifdef T_BEAM_1W_LR2021
+#ifndef USING_LR2021
+#define USING_LR2021
+#endif
+
+
#endif
#define I2C_SDA (8)
@@ -720,10 +751,31 @@
#define RADIO_CS_PIN (15)
#define RADIO_RST_PIN (3)
+#define RADIO_BUSY_PIN (38)
#define RADIO_LDO_EN (40)
+
+#if defined(T_BEAM_1W_SX1262)
#define RADIO_CTRL (21)
#define RADIO_DIO1_PIN (1)
-#define RADIO_BUSY_PIN (38)
+#endif
+
+#if defined(T_BEAM_1W_LR1121)
+#define RADIO_DIO10_PIN (1) // Connect to DIO10
+#define RADIO_DIO11_PIN (21) // Connect to DIO11
+#define RADIO_DIO_IRQ_PIN (RADIO_DIO11_PIN)
+#pragma message "Using LR2021 PA Version,The transmit power must not exceed 0dBm, otherwise it will cause permanent damage to LoRa."
+#define CONFIG_RADIO_2G4_OUTPUT_POWER 1
+#define CONFIG_RADIO_SUB1G_OUTPUT_POWER 22
+#endif
+
+#if defined(T_BEAM_1W_LR2021)
+#define RADIO_IRQ_PIN (1) // Connect to DIO10
+#define RADIO_DIO11_PIN (21) // Connect to DIO11
+#define RADIO_DIO_NUM (10) // LR2021 DIO NUM NOT ESP32S3 GPIO NUM
+#define CONFIG_RADIO_2G4_OUTPUT_POWER 8
+#define CONFIG_RADIO_SUB1G_OUTPUT_POWER 22
+#pragma message "Using LR2021 PA Version,The transmit power must not exceed 8dBm, otherwise it will cause permanent damage to LoRa."
+#endif
#define BOARD_LED 18
#define LED_ON HIGH
@@ -750,7 +802,7 @@
#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "LoRa 2W"
+#define BOARD_VARIANT_NAME "LoRa 1W"
#else
#error "When using it for the first time, please define the board model in 首次使用时,请在 文件最上方定义板卡模型"
@@ -761,20 +813,103 @@
#if defined(USING_SX1262)
+
#define RADIO_TYPE_STR "SX1262"
+
+#ifndef CONFIG_RADIO_SUB1G_OUTPUT_POWER
+#define CONFIG_RADIO_SUB1G_OUTPUT_POWER 22
+#endif
+
#elif defined(USING_SX1276)
+
#define RADIO_TYPE_STR "SX1276"
+
+#ifndef CONFIG_RADIO_SUB1G_OUTPUT_POWER
+#define CONFIG_RADIO_SUB1G_OUTPUT_POWER 17
+#endif
+
#elif defined(USING_SX1278)
+
#define RADIO_TYPE_STR "SX1278"
+
+#ifndef CONFIG_RADIO_SUB1G_OUTPUT_POWER
+#define CONFIG_RADIO_SUB1G_OUTPUT_POWER 17
+#endif
+
+#ifndef CONFIG_RADIO_FREQ
+#define CONFIG_RADIO_FREQ 433.0
+#endif
+
#elif defined(USING_LR1121)
+
#define RADIO_TYPE_STR "LR1121"
+
+#ifndef CONFIG_RADIO_SUB1G_OUTPUT_POWER
+#define CONFIG_RADIO_SUB1G_OUTPUT_POWER 22
+#endif
+
+#ifndef CONFIG_RADIO_2G4_OUTPUT_POWER
+#define CONFIG_RADIO_2G4_OUTPUT_POWER 13
+#endif
+
#elif defined(USING_SX1280)
+
#define RADIO_TYPE_STR "SX1280"
+
+#ifndef CONFIG_RADIO_2G4_OUTPUT_POWER
+#define CONFIG_RADIO_2G4_OUTPUT_POWER 13
+#endif
+
+#ifndef CONFIG_RADIO_FREQ
+#define CONFIG_RADIO_FREQ 2400.0
+#endif
+
+#ifndef CONFIG_RADIO_BW
+#define CONFIG_RADIO_BW 203.125
+#endif
+
#elif defined(USING_SX1280PA)
+
#define RADIO_TYPE_STR "SX1280PA"
+
+#ifndef CONFIG_RADIO_2G4_OUTPUT_POWER
+#define CONFIG_RADIO_2G4_OUTPUT_POWER 13
+#endif
+
+#ifndef CONFIG_RADIO_FREQ
+#define CONFIG_RADIO_FREQ 2400.0
+#endif
+
+#ifndef CONFIG_RADIO_BW
+#define CONFIG_RADIO_BW 203.125
#endif
+#elif defined(USING_LR2021)
+
+#define RADIO_TYPE_STR "LR2021"
+
+#ifndef CONFIG_RADIO_2G4_OUTPUT_POWER
+#define CONFIG_RADIO_2G4_OUTPUT_POWER 12
+#endif
+
+#ifndef CONFIG_RADIO_SUB1G_OUTPUT_POWER
+#define CONFIG_RADIO_SUB1G_OUTPUT_POWER 22
+#endif
+
+#endif
+#ifndef CONFIG_RADIO_2G4_OUTPUT_POWER
+#define CONFIG_RADIO_2G4_OUTPUT_POWER -1
+#endif
+
+#ifndef CONFIG_RADIO_FREQ
+#define CONFIG_RADIO_FREQ 868.0
+#endif
+
+
+#ifndef CONFIG_RADIO_BW
+#define CONFIG_RADIO_BW 125.0
+#endif
diff --git a/examples/GPS/TinyGPS_Example/LoRaBoards.cpp b/examples/GPS/TinyGPS_Example/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/GPS/TinyGPS_Example/LoRaBoards.cpp
+++ b/examples/GPS/TinyGPS_Example/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/GPS/TinyGPS_Example/LoRaBoards.h b/examples/GPS/TinyGPS_Example/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/GPS/TinyGPS_Example/LoRaBoards.h
+++ b/examples/GPS/TinyGPS_Example/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/GPS/TinyGPS_FullExample/LoRaBoards.cpp b/examples/GPS/TinyGPS_FullExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/GPS/TinyGPS_FullExample/LoRaBoards.cpp
+++ b/examples/GPS/TinyGPS_FullExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/GPS/TinyGPS_FullExample/LoRaBoards.h b/examples/GPS/TinyGPS_FullExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/GPS/TinyGPS_FullExample/LoRaBoards.h
+++ b/examples/GPS/TinyGPS_FullExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/GPS/TinyGPS_KitchenSink/LoRaBoards.cpp b/examples/GPS/TinyGPS_KitchenSink/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/GPS/TinyGPS_KitchenSink/LoRaBoards.cpp
+++ b/examples/GPS/TinyGPS_KitchenSink/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/GPS/TinyGPS_KitchenSink/LoRaBoards.h b/examples/GPS/TinyGPS_KitchenSink/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/GPS/TinyGPS_KitchenSink/LoRaBoards.h
+++ b/examples/GPS/TinyGPS_KitchenSink/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/GPS/UBlox_BasicNMEARead/LoRaBoards.cpp b/examples/GPS/UBlox_BasicNMEARead/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/GPS/UBlox_BasicNMEARead/LoRaBoards.cpp
+++ b/examples/GPS/UBlox_BasicNMEARead/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/GPS/UBlox_BasicNMEARead/LoRaBoards.h b/examples/GPS/UBlox_BasicNMEARead/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/GPS/UBlox_BasicNMEARead/LoRaBoards.h
+++ b/examples/GPS/UBlox_BasicNMEARead/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/GPS/UBlox_NMEAParsing/LoRaBoards.cpp b/examples/GPS/UBlox_NMEAParsing/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/GPS/UBlox_NMEAParsing/LoRaBoards.cpp
+++ b/examples/GPS/UBlox_NMEAParsing/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/GPS/UBlox_NMEAParsing/LoRaBoards.h b/examples/GPS/UBlox_NMEAParsing/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/GPS/UBlox_NMEAParsing/LoRaBoards.h
+++ b/examples/GPS/UBlox_NMEAParsing/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/GPS/UBlox_OutputRate/LoRaBoards.cpp b/examples/GPS/UBlox_OutputRate/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/GPS/UBlox_OutputRate/LoRaBoards.cpp
+++ b/examples/GPS/UBlox_OutputRate/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/GPS/UBlox_OutputRate/LoRaBoards.h b/examples/GPS/UBlox_OutputRate/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/GPS/UBlox_OutputRate/LoRaBoards.h
+++ b/examples/GPS/UBlox_OutputRate/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/GPS/UBlox_Recovery/LoRaBoards.cpp b/examples/GPS/UBlox_Recovery/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/GPS/UBlox_Recovery/LoRaBoards.cpp
+++ b/examples/GPS/UBlox_Recovery/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/GPS/UBlox_Recovery/LoRaBoards.h b/examples/GPS/UBlox_Recovery/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/GPS/UBlox_Recovery/LoRaBoards.h
+++ b/examples/GPS/UBlox_Recovery/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/LoRaWAN/LMIC_Library_OTTA/LoRaBoards.cpp b/examples/LoRaWAN/LMIC_Library_OTTA/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/LoRaWAN/LMIC_Library_OTTA/LoRaBoards.cpp
+++ b/examples/LoRaWAN/LMIC_Library_OTTA/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/LoRaWAN/LMIC_Library_OTTA/LoRaBoards.h b/examples/LoRaWAN/LMIC_Library_OTTA/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/LoRaWAN/LMIC_Library_OTTA/LoRaBoards.h
+++ b/examples/LoRaWAN/LMIC_Library_OTTA/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaBoards.cpp b/examples/LoRaWAN/LoRaWAN_ABP/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaBoards.cpp
+++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaBoards.h b/examples/LoRaWAN/LoRaWAN_ABP/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaBoards.h
+++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/LoRaWAN/RadioLib_OTAA/LoRaBoards.cpp b/examples/LoRaWAN/RadioLib_OTAA/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/LoRaWAN/RadioLib_OTAA/LoRaBoards.cpp
+++ b/examples/LoRaWAN/RadioLib_OTAA/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/LoRaWAN/RadioLib_OTAA/LoRaBoards.h b/examples/LoRaWAN/RadioLib_OTAA/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/LoRaWAN/RadioLib_OTAA/LoRaBoards.h
+++ b/examples/LoRaWAN/RadioLib_OTAA/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/OLED/SH1106FontUsage/LoRaBoards.cpp b/examples/OLED/SH1106FontUsage/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/OLED/SH1106FontUsage/LoRaBoards.cpp
+++ b/examples/OLED/SH1106FontUsage/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/OLED/SH1106FontUsage/LoRaBoards.h b/examples/OLED/SH1106FontUsage/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/OLED/SH1106FontUsage/LoRaBoards.h
+++ b/examples/OLED/SH1106FontUsage/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/OLED/SH1106GraphicsTest/LoRaBoards.cpp b/examples/OLED/SH1106GraphicsTest/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/OLED/SH1106GraphicsTest/LoRaBoards.cpp
+++ b/examples/OLED/SH1106GraphicsTest/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/OLED/SH1106GraphicsTest/LoRaBoards.h b/examples/OLED/SH1106GraphicsTest/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/OLED/SH1106GraphicsTest/LoRaBoards.h
+++ b/examples/OLED/SH1106GraphicsTest/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/OLED/SH1106IconMenu/LoRaBoards.cpp b/examples/OLED/SH1106IconMenu/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/OLED/SH1106IconMenu/LoRaBoards.cpp
+++ b/examples/OLED/SH1106IconMenu/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/OLED/SH1106IconMenu/LoRaBoards.h b/examples/OLED/SH1106IconMenu/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/OLED/SH1106IconMenu/LoRaBoards.h
+++ b/examples/OLED/SH1106IconMenu/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/OLED/SH1106PrintUTF8/LoRaBoards.cpp b/examples/OLED/SH1106PrintUTF8/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/OLED/SH1106PrintUTF8/LoRaBoards.cpp
+++ b/examples/OLED/SH1106PrintUTF8/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/OLED/SH1106PrintUTF8/LoRaBoards.h b/examples/OLED/SH1106PrintUTF8/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/OLED/SH1106PrintUTF8/LoRaBoards.h
+++ b/examples/OLED/SH1106PrintUTF8/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/OLED/SSD1306SimpleDemo/LoRaBoards.cpp b/examples/OLED/SSD1306SimpleDemo/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/OLED/SSD1306SimpleDemo/LoRaBoards.cpp
+++ b/examples/OLED/SSD1306SimpleDemo/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/OLED/SSD1306SimpleDemo/LoRaBoards.h b/examples/OLED/SSD1306SimpleDemo/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/OLED/SSD1306SimpleDemo/LoRaBoards.h
+++ b/examples/OLED/SSD1306SimpleDemo/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/OLED/SSD1306UiDemo/LoRaBoards.cpp b/examples/OLED/SSD1306UiDemo/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/OLED/SSD1306UiDemo/LoRaBoards.cpp
+++ b/examples/OLED/SSD1306UiDemo/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/OLED/SSD1306UiDemo/LoRaBoards.h b/examples/OLED/SSD1306UiDemo/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/OLED/SSD1306UiDemo/LoRaBoards.h
+++ b/examples/OLED/SSD1306UiDemo/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/PMU/LoRaBoards.cpp b/examples/PMU/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/PMU/LoRaBoards.cpp
+++ b/examples/PMU/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/PMU/LoRaBoards.h b/examples/PMU/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/PMU/LoRaBoards.h
+++ b/examples/PMU/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/RadioLibExamples/Receive_Interrupt/LoRaBoards.cpp b/examples/RadioLibExamples/Receive_Interrupt/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/RadioLibExamples/Receive_Interrupt/LoRaBoards.cpp
+++ b/examples/RadioLibExamples/Receive_Interrupt/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/RadioLibExamples/Receive_Interrupt/LoRaBoards.h b/examples/RadioLibExamples/Receive_Interrupt/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/RadioLibExamples/Receive_Interrupt/LoRaBoards.h
+++ b/examples/RadioLibExamples/Receive_Interrupt/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/RadioLibExamples/SX1280_Ranging/LoRaBoards.cpp b/examples/RadioLibExamples/SX1280_Ranging/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/RadioLibExamples/SX1280_Ranging/LoRaBoards.cpp
+++ b/examples/RadioLibExamples/SX1280_Ranging/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/RadioLibExamples/SX1280_Ranging/LoRaBoards.h b/examples/RadioLibExamples/SX1280_Ranging/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/RadioLibExamples/SX1280_Ranging/LoRaBoards.h
+++ b/examples/RadioLibExamples/SX1280_Ranging/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/RadioLibExamples/Transmit_Interrupt/LoRaBoards.cpp b/examples/RadioLibExamples/Transmit_Interrupt/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/RadioLibExamples/Transmit_Interrupt/LoRaBoards.cpp
+++ b/examples/RadioLibExamples/Transmit_Interrupt/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/RadioLibExamples/Transmit_Interrupt/LoRaBoards.h b/examples/RadioLibExamples/Transmit_Interrupt/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/RadioLibExamples/Transmit_Interrupt/LoRaBoards.h
+++ b/examples/RadioLibExamples/Transmit_Interrupt/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/BME280_AdvancedsettingsExample/LoRaBoards.cpp b/examples/Sensor/BME280_AdvancedsettingsExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/BME280_AdvancedsettingsExample/LoRaBoards.cpp
+++ b/examples/Sensor/BME280_AdvancedsettingsExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/BME280_AdvancedsettingsExample/LoRaBoards.h b/examples/Sensor/BME280_AdvancedsettingsExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/BME280_AdvancedsettingsExample/LoRaBoards.h
+++ b/examples/Sensor/BME280_AdvancedsettingsExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/BME280_TestExample/LoRaBoards.cpp b/examples/Sensor/BME280_TestExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/BME280_TestExample/LoRaBoards.cpp
+++ b/examples/Sensor/BME280_TestExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/BME280_TestExample/LoRaBoards.h b/examples/Sensor/BME280_TestExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/BME280_TestExample/LoRaBoards.h
+++ b/examples/Sensor/BME280_TestExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/BME280_UnifiedExample/LoRaBoards.cpp b/examples/Sensor/BME280_UnifiedExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/BME280_UnifiedExample/LoRaBoards.cpp
+++ b/examples/Sensor/BME280_UnifiedExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/BME280_UnifiedExample/LoRaBoards.h b/examples/Sensor/BME280_UnifiedExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/BME280_UnifiedExample/LoRaBoards.h
+++ b/examples/Sensor/BME280_UnifiedExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/I2CScanner/LoRaBoards.cpp b/examples/Sensor/I2CScanner/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/I2CScanner/LoRaBoards.cpp
+++ b/examples/Sensor/I2CScanner/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/I2CScanner/LoRaBoards.h b/examples/Sensor/I2CScanner/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/I2CScanner/LoRaBoards.h
+++ b/examples/Sensor/I2CScanner/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/PCF8563_AlarmByUnits/LoRaBoards.cpp b/examples/Sensor/PCF8563_AlarmByUnits/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/PCF8563_AlarmByUnits/LoRaBoards.cpp
+++ b/examples/Sensor/PCF8563_AlarmByUnits/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/PCF8563_AlarmByUnits/LoRaBoards.h b/examples/Sensor/PCF8563_AlarmByUnits/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/PCF8563_AlarmByUnits/LoRaBoards.h
+++ b/examples/Sensor/PCF8563_AlarmByUnits/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/PCF8563_SimpleTime/LoRaBoards.cpp b/examples/Sensor/PCF8563_SimpleTime/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/PCF8563_SimpleTime/LoRaBoards.cpp
+++ b/examples/Sensor/PCF8563_SimpleTime/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/PCF8563_SimpleTime/LoRaBoards.h b/examples/Sensor/PCF8563_SimpleTime/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/PCF8563_SimpleTime/LoRaBoards.h
+++ b/examples/Sensor/PCF8563_SimpleTime/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/PCF8563_TimeLib/LoRaBoards.cpp b/examples/Sensor/PCF8563_TimeLib/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/PCF8563_TimeLib/LoRaBoards.cpp
+++ b/examples/Sensor/PCF8563_TimeLib/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/PCF8563_TimeLib/LoRaBoards.h b/examples/Sensor/PCF8563_TimeLib/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/PCF8563_TimeLib/LoRaBoards.h
+++ b/examples/Sensor/PCF8563_TimeLib/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/PCF8563_TimeSynchronization/LoRaBoards.cpp b/examples/Sensor/PCF8563_TimeSynchronization/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/PCF8563_TimeSynchronization/LoRaBoards.cpp
+++ b/examples/Sensor/PCF8563_TimeSynchronization/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/PCF8563_TimeSynchronization/LoRaBoards.h b/examples/Sensor/PCF8563_TimeSynchronization/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/PCF8563_TimeSynchronization/LoRaBoards.h
+++ b/examples/Sensor/PCF8563_TimeSynchronization/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMC6310_CalibrateExample/LoRaBoards.cpp b/examples/Sensor/QMC6310_CalibrateExample/LoRaBoards.cpp
deleted file mode 100644
index 8acfe74..0000000
--- a/examples/Sensor/QMC6310_CalibrateExample/LoRaBoards.cpp
+++ /dev/null
@@ -1,1353 +0,0 @@
-/**
- * @file boards.cpp
- * @author Lewis He (lewishe@outlook.com)
- * @license MIT
- * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
- * @date 2024-04-24
- * @last-update 2025-05-26
- *
- */
-
-#include "LoRaBoards.h"
-
-#include "soc/rtc.h"
-#ifdef ENABLE_BLE
-#include
-#include
-#include
-#endif
-
-#if defined(HAS_SDCARD) && !defined(SD_SHARE_SPI_BUS)
-SPIClass SDCardSPI(HSPI);
-#endif
-
-
-#if defined(ARDUINO_ARCH_STM32)
-HardwareSerial SerialGPS(GPS_RX_PIN, GPS_TX_PIN);
-#endif
-
-#if defined(ARDUINO_ARCH_ESP32)
-#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,0,0)
-#include "hal/gpio_hal.h"
-#endif
-#include "driver/gpio.h"
-#endif //ARDUINO_ARCH_ESP32
-
-#ifdef DISPLAY_MODEL
-U8G2 *disp = NULL;
-#endif
-
-
-static DevInfo_t devInfo;
-
-#ifdef HAS_GPS
-static bool find_gps = false;
-String gps_model = "None";
-#endif
-
-// I2S Devices default address
-uint8_t bme280_address = 0x77; // It might be 0x76
-uint8_t mag_address = 0x1C; // QMC6310U=0x1C QMC6310N=0x3C
-uint8_t display_address = 0x3c; // It might be 0x3D
-
-uint32_t deviceOnline = 0x00;
-
-static void enable_slow_clock();
-
-#ifdef HAS_PMU
-XPowersLibInterface *PMU = NULL;
-bool pmuInterrupt;
-
-static void setPmuFlag()
-{
- pmuInterrupt = true;
-}
-bool beginPower()
-{
- if (!PMU) {
- PMU = new XPowersAXP2101(PMU_WIRE_PORT);
- if (!PMU->init()) {
- Serial.println("Warning: Failed to find AXP2101 power management");
- delete PMU;
- PMU = NULL;
- } else {
- Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU");
- }
- }
-
- if (!PMU) {
- PMU = new XPowersAXP192(PMU_WIRE_PORT);
- if (!PMU->init()) {
- Serial.println("Warning: Failed to find AXP192 power management");
- delete PMU;
- PMU = NULL;
- } else {
- Serial.println("AXP192 PMU init succeeded, using AXP192 PMU");
- }
- }
-
- if (!PMU) {
- return false;
- }
-
- deviceOnline |= POWERMANAGE_ONLINE;
-
- PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
-
- pinMode(PMU_IRQ, INPUT_PULLUP);
- attachInterrupt(PMU_IRQ, setPmuFlag, FALLING);
-
- if (PMU->getChipModel() == XPOWERS_AXP192) {
-
- PMU->setProtectedChannel(XPOWERS_DCDC3);
-
- // lora
- PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
- // gps
- PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
- // oled
- PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
-
- PMU->enablePowerOutput(XPOWERS_LDO2);
- PMU->enablePowerOutput(XPOWERS_LDO3);
-
- //protected oled power source
- PMU->setProtectedChannel(XPOWERS_DCDC1);
- //protected esp32 power source
- PMU->setProtectedChannel(XPOWERS_DCDC3);
- // enable oled power
- PMU->enablePowerOutput(XPOWERS_DCDC1);
-
- //disable not use channel
- PMU->disablePowerOutput(XPOWERS_DCDC2);
-
- PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
-
- PMU->enableIRQ(XPOWERS_AXP192_VBUS_REMOVE_IRQ |
- XPOWERS_AXP192_VBUS_INSERT_IRQ |
- XPOWERS_AXP192_BAT_CHG_DONE_IRQ |
- XPOWERS_AXP192_BAT_CHG_START_IRQ |
- XPOWERS_AXP192_BAT_REMOVE_IRQ |
- XPOWERS_AXP192_BAT_INSERT_IRQ |
- XPOWERS_AXP192_PKEY_SHORT_IRQ
- );
-
- } else if (PMU->getChipModel() == XPOWERS_AXP2101) {
-
-#if defined(CONFIG_IDF_TARGET_ESP32)
- //Unuse power channel
- PMU->disablePowerOutput(XPOWERS_DCDC2);
- PMU->disablePowerOutput(XPOWERS_DCDC3);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_ALDO1);
- PMU->disablePowerOutput(XPOWERS_ALDO4);
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO2);
- PMU->disablePowerOutput(XPOWERS_DLDO1);
- PMU->disablePowerOutput(XPOWERS_DLDO2);
- PMU->disablePowerOutput(XPOWERS_CPULDO);
-
- // GNSS RTC PowerVDD 3300mV
- PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
- PMU->enablePowerOutput(XPOWERS_VBACKUP);
-
- //ESP32 VDD 3300mV
- // ! No need to set, automatically open , Don't close it
- // PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
- // PMU->setProtectedChannel(XPOWERS_DCDC1);
- PMU->setProtectedChannel(XPOWERS_DCDC1);
-
- // LoRa VDD 3300mV
- PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO2);
-
- //GNSS VDD 3300mV
- PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO3);
-
-#endif /*CONFIG_IDF_TARGET_ESP32*/
-
-
-#if defined(T_BEAM_S3_SUPREME)
-
- //t-beam m.2 inface
- //gps
- PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO4);
-
- // lora
- PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO3);
-
- // In order to avoid bus occupation, during initialization, the SD card and QMC sensor are powered off and restarted
- if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()) {
- Serial.println("Power off and restart ALDO BLDO..");
- PMU->disablePowerOutput(XPOWERS_ALDO1);
- PMU->disablePowerOutput(XPOWERS_ALDO2);
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- delay(250);
- }
-
- // Sensor
- PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO1);
-
- PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO2);
-
- //Sdcard
-
- PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
- PMU->enablePowerOutput(XPOWERS_BLDO1);
-
- PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_BLDO2);
-
- //face m.2
- PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC3);
-
- PMU->setPowerChannelVoltage(XPOWERS_DCDC4, XPOWERS_AXP2101_DCDC4_VOL2_MAX);
- PMU->enablePowerOutput(XPOWERS_DCDC4);
-
- PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC5);
-
-
- //not use channel
- PMU->disablePowerOutput(XPOWERS_DCDC2);
- // PMU->disablePowerOutput(XPOWERS_DCDC4);
- // PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_DLDO1);
- PMU->disablePowerOutput(XPOWERS_DLDO2);
- PMU->disablePowerOutput(XPOWERS_VBACKUP);
-
-
-#elif defined(T_BEAM_S3_BPF)
-
- //gps
- PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO4);
-
- //Sdcard
- PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO2);
-
- // Extern Power source
- PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC3);
-
- PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC5);
-
- PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO1);
-
- //not use channel
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO2);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC2);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_DLDO1);
- PMU->disablePowerOutput(XPOWERS_DLDO2);
- PMU->disablePowerOutput(XPOWERS_VBACKUP);
-
-
-#endif
-
- // Set constant current charge current limit
- PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
-
- // Set charge cut-off voltage
- PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
-
- // Disable all interrupts
- PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
- // Clear all interrupt flags
- PMU->clearIrqStatus();
- // Enable the required interrupt function
- PMU->enableIRQ(
- XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | //BATTERY
- XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | //VBUS
- XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | //POWER KEY
- XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ //CHARGE
- // XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ | XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | //POWER KEY
- );
-
- }
-
- PMU->enableSystemVoltageMeasure();
- PMU->enableVbusVoltageMeasure();
- PMU->enableBattVoltageMeasure();
-
- Serial.printf("=========================================\n");
- if (PMU->isChannelAvailable(XPOWERS_DCDC1)) {
- Serial.printf("DC1 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC2)) {
- Serial.printf("DC2 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC3)) {
- Serial.printf("DC3 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC4)) {
- Serial.printf("DC4 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC5)) {
- Serial.printf("DC5 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC5) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC5));
- }
- if (PMU->isChannelAvailable(XPOWERS_LDO2)) {
- Serial.printf("LDO2 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO2));
- }
- if (PMU->isChannelAvailable(XPOWERS_LDO3)) {
- Serial.printf("LDO3 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO3));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO1)) {
- Serial.printf("ALDO1: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO2)) {
- Serial.printf("ALDO2: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO3)) {
- Serial.printf("ALDO3: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO4)) {
- Serial.printf("ALDO4: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
- }
- if (PMU->isChannelAvailable(XPOWERS_BLDO1)) {
- Serial.printf("BLDO1: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
- }
- if (PMU->isChannelAvailable(XPOWERS_BLDO2)) {
- Serial.printf("BLDO2: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
- }
-
-
- // Set the time of pressing the button to turn off
- PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
- uint8_t opt = PMU->getPowerKeyPressOffTime();
- Serial.print("PowerKeyPressOffTime:");
- switch (opt) {
- case XPOWERS_POWEROFF_4S: Serial.println("4 Second");
- break;
- case XPOWERS_POWEROFF_6S: Serial.println("6 Second");
- break;
- case XPOWERS_POWEROFF_8S: Serial.println("8 Second");
- break;
- case XPOWERS_POWEROFF_10S: Serial.println("10 Second");
- break;
- default:
- break;
- }
-
- Serial.printf("=========================================\n");
-
- return true;
-}
-
-void disablePeripherals()
-{
-
- if (!PMU)return;
-
- PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
- // Disable the PMU measurement section
- PMU->disableSystemVoltageMeasure();
- PMU->disableVbusVoltageMeasure();
- PMU->disableBattVoltageMeasure();
- PMU->disableTemperatureMeasure();
- PMU->disableBattDetection();
-
-#if defined(T_BEAM_S3_BPF)
- PMU->disablePowerOutput(XPOWERS_ALDO4); //gps
- PMU->disablePowerOutput(XPOWERS_ALDO2); //Sdcard
- PMU->disablePowerOutput(XPOWERS_DCDC3); // Extern Power source
- PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_ALDO1);
-#else
-
- if (PMU->getChipModel() == XPOWERS_AXP2101) {
-
- // Disable all PMU interrupts
- PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
- // Clear the PMU interrupt status before sleeping, otherwise the sleep current will increase
- PMU->clearIrqStatus();
- // GNSS RTC Power , Turning off GPS backup voltage and current can further reduce ~ 100 uA
- PMU->disablePowerOutput(XPOWERS_VBACKUP);
- // LoRa VDD
- PMU->disablePowerOutput(XPOWERS_ALDO2);
- // GNSS VDD
- PMU->disablePowerOutput(XPOWERS_ALDO3);
-
-#if defined(T_BEAM_S3_SUPREME)
- PMU->disablePowerOutput(XPOWERS_ALDO4);
- PMU->disablePowerOutput(XPOWERS_ALDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO2);
- PMU->disablePowerOutput(XPOWERS_DCDC3);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC5);
-#endif
-
- } else if (PMU->getChipModel() == XPOWERS_AXP192) {
-
- // Disable all PMU interrupts
- PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
- // Clear the PMU interrupt status before sleeping, otherwise the sleep current will increase
- PMU->clearIrqStatus();
- // LoRa VDD
- PMU->disablePowerOutput(XPOWERS_LDO2);
- // GNSS VDD
- PMU->disablePowerOutput(XPOWERS_LDO3);
-
-
- }
-#endif
-}
-
-void loopPMU(void (*pressed_cb)(void))
-{
- if (!PMU) {
- return;
- }
- if (!pmuInterrupt) {
- return;
- }
-
- pmuInterrupt = false;
- // Get PMU Interrupt Status Register
- uint32_t status = PMU->getIrqStatus();
- Serial.print("STATUS => HEX:");
- Serial.print(status, HEX);
- Serial.print(" BIN:");
- Serial.println(status, BIN);
-
- if (PMU->isVbusInsertIrq()) {
- Serial.println("isVbusInsert");
- }
- if (PMU->isVbusRemoveIrq()) {
- Serial.println("isVbusRemove");
- }
- if (PMU->isBatInsertIrq()) {
- Serial.println("isBatInsert");
- }
- if (PMU->isBatRemoveIrq()) {
- Serial.println("isBatRemove");
- }
- if (PMU->isPekeyShortPressIrq()) {
- Serial.println("isPekeyShortPress");
- if (pressed_cb) {
- pressed_cb();
- }
- }
- if (PMU->isPekeyLongPressIrq()) {
- Serial.println("isPekeyLongPress");
- }
- if (PMU->isBatChargeDoneIrq()) {
- Serial.println("isBatChargeDone");
- }
- if (PMU->isBatChargeStartIrq()) {
- Serial.println("isBatChargeStart");
- }
- // Clear PMU Interrupt Status Register
- PMU->clearIrqStatus();
-}
-#endif
-
-#ifdef DISPLAY_MODEL
-bool beginDisplay()
-{
- Wire.beginTransmission(display_address);
- if (Wire.endTransmission() == 0) {
- disp = new DISPLAY_MODEL(U8G2_R0, U8X8_PIN_NONE);
- Serial.printf("Find Display model at 0x%X address\n", display_address);
- disp->begin();
- disp->clearBuffer();
- disp->setFont(u8g2_font_inb19_mr);
- disp->drawStr(0, 30, "LilyGo");
- disp->drawHLine(2, 35, 47);
- disp->drawHLine(3, 36, 47);
- disp->drawVLine(45, 32, 12);
- disp->drawVLine(46, 33, 12);
- disp->setFont(u8g2_font_inb19_mf);
- disp->drawStr(58, 60, "LoRa");
- disp->sendBuffer();
- disp->setFont(u8g2_font_fur11_tf);
- delay(3000);
- return true;
- }
-
- Serial.printf("Warning: Failed to find Display at 0x%0X address\n", display_address);
- return false;
-}
-#endif
-
-#ifdef HAS_SDCARD
-bool writeFile(const char *path, const char *buffer)
-{
- bool rlst = false;
- File file = SD.open(path, FILE_WRITE);
- if (!file) {
- Serial.println("Failed to open file for writing");
- return false;
- }
- if (file.print(buffer)) {
- Serial.println("File written");
- rlst = true;
- } else {
- Serial.println("Write failed");
- rlst = false;
- }
- file.close();
- return rlst;
-}
-
-
-bool readFile(const char *path, uint8_t *buffer, size_t size)
-{
- File file = SD.open(path, FILE_READ);
- if (!file) {
- Serial.println("Failed to open file for reading");
- return false;
- }
- file.read(buffer, size);
- file.close();
- return false;
-}
-
-bool testSDWriteAndRead()
-{
- const char *path = "/test_sd.txt";
- const char *message = "This is a string for reading and writing SD card.";
- uint8_t buffer[128] = {0};
-
- if (!writeFile(path, message)) {
- Serial.println("SD Text write failed");
- return false;
- }
- delay(100);
-
- readFile(path, buffer, 128);
-
- if (memcmp(buffer, message, strlen(message)) != 0) {
- Serial.println("SD verification failed");
- return false;
- }
- Serial.println("SD verification successful");
- return true;
-}
-#endif /*HAS_SDCARD*/
-
-#ifdef HAS_SDCARD
-bool beginSDCard()
-{
-#if defined(HAS_SDCARD) && defined(SD_SHARE_SPI_BUS)
- bool rlst = SD.begin(SDCARD_CS);
-#else
- bool rlst = SD.begin(SDCARD_CS, SDCardSPI);
-#endif
-
- if (rlst) {
- uint32_t cardSize = SD.cardSize() / (1024 * 1024);
- Serial.print("Sd Card init succeeded, The current available capacity is ");
- Serial.print(cardSize / 1024.0);
- Serial.println(" GB");
- deviceOnline |= SDCARD_ONLINE;
- return testSDWriteAndRead();
- } else {
- Serial.println("Warning: Failed to init Sd Card");
- }
- return false;
-}
-#endif /*HAS_SDCARD*/
-
-void beginWiFi()
-{
-#ifdef ARDUINO_ARCH_ESP32
- if (!WiFi.softAP(BOARD_VARIANT_NAME)) {
- log_e("Soft AP creation failed.");
- }
- IPAddress myIP = WiFi.softAPIP();
- Serial.print("AP IP address: ");
- Serial.println(myIP);
-#endif
-}
-
-
-void printWakeupReason()
-{
-#ifdef ARDUINO_ARCH_ESP32
- Serial.print("Reset reason:");
- esp_sleep_wakeup_cause_t wakeup_reason;
- wakeup_reason = esp_sleep_get_wakeup_cause();
- switch (wakeup_reason) {
- case ESP_SLEEP_WAKEUP_UNDEFINED:
- Serial.println(" In case of deep sleep, reset was not caused by exit from deep sleep");
- break;
- case ESP_SLEEP_WAKEUP_ALL :
- break;
- case ESP_SLEEP_WAKEUP_EXT0 :
- Serial.println("Wakeup caused by external signal using RTC_IO");
- break;
- case ESP_SLEEP_WAKEUP_EXT1 :
- Serial.println("Wakeup caused by external signal using RTC_CNTL");
- break;
- case ESP_SLEEP_WAKEUP_TIMER :
- Serial.println("Wakeup caused by timer");
- break;
- case ESP_SLEEP_WAKEUP_TOUCHPAD :
- Serial.println("Wakeup caused by touchpad");
- break;
- case ESP_SLEEP_WAKEUP_ULP :
- Serial.println("Wakeup caused by ULP program");
- break;
- default :
- Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
- break;
- }
-#endif
-}
-
-
-void getChipInfo()
-{
-#if defined(ARDUINO_ARCH_ESP32)
-
- Serial.println("-----------------------------------");
-
- printWakeupReason();
-
-
- if (psramFound()) {
- uint32_t psram = ESP.getPsramSize();
- devInfo.psramSize = psram / 1024.0 / 1024.0;
- Serial.printf("PSRAM is enable! PSRAM: %.2fMB\n", devInfo.psramSize);
- deviceOnline |= PSRAM_ONLINE;
- } else {
- Serial.println("PSRAM is disable!");
- devInfo.psramSize = 0;
- }
-
-
- Serial.print("Flash:");
- devInfo.flashSize = ESP.getFlashChipSize() / 1024.0 / 1024.0;
- devInfo.flashSpeed = ESP.getFlashChipSpeed() / 1000 / 1000;
- devInfo.chipModel = ESP.getChipModel();
- devInfo.chipModelRev = ESP.getChipRevision();
- devInfo.chipFreq = ESP.getCpuFreqMHz();
-
- Serial.print(devInfo.flashSize);
- Serial.println(" MB");
- Serial.print("Flash speed:");
- Serial.print(devInfo.flashSpeed);
- Serial.println(" M");
- Serial.print("Model:");
-
- Serial.println(devInfo.chipModel);
- Serial.print("Chip Revision:");
- Serial.println(devInfo.chipModelRev);
- Serial.print("Freq:");
- Serial.print(devInfo.chipFreq);
- Serial.println(" MHZ");
- Serial.print("SDK Ver:");
- Serial.println(ESP.getSdkVersion());
- Serial.print("DATE:");
- Serial.println(__DATE__);
- Serial.print("TIME:");
- Serial.println(__TIME__);
-
- uint8_t mac[6];
- char macStr[18] = { 0 };
- esp_efuse_mac_get_default(mac);
- sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- Serial.print("EFUSE MAC: ");
- Serial.print(macStr);
- Serial.println();
-
- Serial.println("-----------------------------------");
-
-#elif defined(ARDUINO_ARCH_STM32)
- uint32_t uid[3];
-
- uid[0] = HAL_GetUIDw0();
- uid[1] = HAL_GetUIDw1();
- uid[2] = HAL_GetUIDw2();
- Serial.print("STM UID: 0X");
- Serial.print( uid[0], HEX);
- Serial.print( uid[1], HEX);
- Serial.print( uid[2], HEX);
- Serial.println();
-#endif
-}
-
-
-void setupBoards(bool disable_u8g2 )
-{
- Serial.begin(115200);
-
- // while (!Serial);
-
- Serial.println("setupBoards");
-
- getChipInfo();
-
-#if defined(ARDUINO_ARCH_ESP32)
- SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
-#elif defined(ARDUINO_ARCH_STM32)
- SPI.setMISO(RADIO_MISO_PIN);
- SPI.setMOSI(RADIO_MOSI_PIN);
- SPI.setSCLK(RADIO_SCLK_PIN);
- SPI.begin();
-#endif
-
-
-#if defined(HAS_SDCARD)
-#if defined(SD_SHARE_SPI_BUS)
- // Share spi bus with lora , set lora cs,rst to high
- pinMode(RADIO_CS_PIN, OUTPUT);
- pinMode(RADIO_RST_PIN, OUTPUT);
- digitalWrite(RADIO_CS_PIN, HIGH);
- digitalWrite(RADIO_RST_PIN, HIGH);
-#else
- SDCardSPI.begin(SDCARD_SCLK, SDCARD_MISO, SDCARD_MOSI);
-#endif /*SD_SHARE_SPI_BUS*/
-#endif /*HAS_SDCARD*/
-
-
-
-#ifdef I2C1_SDA
- Wire1.begin(I2C1_SDA, I2C1_SCL);
-#endif
-
-#ifdef HAS_GPS
-
-#ifdef GPS_EN_PIN
- pinMode(GPS_EN_PIN, OUTPUT);
- digitalWrite(GPS_EN_PIN, HIGH);
-#endif /*GPS_EN_PIN*/
-
-#ifdef GPS_PPS_PIN
- pinMode(GPS_PPS_PIN, INPUT);
-#endif
-
-#if defined(ARDUINO_ARCH_ESP32)
- SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
-#elif defined(ARDUINO_ARCH_STM32)
- SerialGPS.setRx(GPS_RX_PIN);
- SerialGPS.setTx(GPS_TX_PIN);
- SerialGPS.begin(GPS_BAUD_RATE);
-#endif // ARDUINO_ARCH_
-#endif // HAS_GPS
-
-#if OLED_RST
- pinMode(OLED_RST, OUTPUT);
- digitalWrite(OLED_RST, HIGH); delay(20);
- digitalWrite(OLED_RST, LOW); delay(20);
- digitalWrite(OLED_RST, HIGH); delay(20);
-#endif
-
-#ifdef BOARD_LED
- /*
- * T-Beam LED defaults to low level as turn on,
- * so it needs to be forced to pull up
- * * * * */
-#if LED_ON == LOW
-#if defined(ARDUINO_ARCH_ESP32)
- gpio_hold_dis((gpio_num_t)BOARD_LED);
-#endif //ARDUINO_ARCH_ESP32
-#endif
-
- pinMode(BOARD_LED, OUTPUT);
- digitalWrite(BOARD_LED, LED_ON);
-#endif
-
-
-#ifdef GPS_RST_PIN
- pinMode(GPS_RST_PIN, OUTPUT);
- digitalWrite(GPS_RST_PIN, HIGH);
-#endif
-
-#if defined(ARDUINO_ARCH_STM32)
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
-#endif
-
-
-#ifdef RADIO_LDO_EN
- /*
- * 2W and BPF LoRa LDO enable , Control SX1262 , LNA
- * 2W and BPF Radio version must set LDO_EN to HIGH to initialize the Radio
- * */
- pinMode(RADIO_LDO_EN, OUTPUT);
- digitalWrite(RADIO_LDO_EN, HIGH);
-#endif
-
-#ifdef RADIO_CTRL
- /*
- * 2W and BPF LoRa RX TX Control
- * CTRL controls the LNA, not the PA.
- * Only when RX DATA is on, set to 1 to turn on LNA
- * When TX DATA is on, CTL is set to 0 and LNA is turned off.
- * */
- pinMode(RADIO_CTRL, OUTPUT);
- digitalWrite(RADIO_CTRL, LOW);
-#endif
-
-#ifdef RADIO_DIO2_PIN
- pinMode(RADIO_DIO2_PIN, INPUT);
-#endif
-
- beginPower();
-
- // Perform an I2C scan after power-on operation
-#ifdef I2C_SDA
- Wire.begin(I2C_SDA, I2C_SCL);
- Serial.println("==================Scan Wire ==================");
- scanDevices(&Wire);
-#endif
-
-#ifdef I2C1_SDA
- Serial.println("==================Scan Wire1==================");
- scanDevices(&Wire1);
-#endif
-
- beginSDCard();
-
-#ifdef HAS_DISPLAY
- if (!disable_u8g2) {
- beginDisplay();
- }
-#endif
-
- // scanWiFi();
-
- // beginWiFi();
-
-#ifdef FAN_CTRL
- pinMode(FAN_CTRL, OUTPUT);
-#endif
-
-#ifdef HAS_GPS
-
-#if defined(T_BEAM_S3_SUPREME) || defined(T_BEAM_1W) || defined(T_BEAM_S3_BPF)
- // T-Beam v1.2 skips L76K
- find_gps = beginGPS();
-#endif
- uint32_t baudrate[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 4800};
- if (!find_gps) {
- // Restore factory settings
- for ( int i = 0; i < sizeof(baudrate) / sizeof(baudrate[0]); ++i) {
- Serial.printf("Update baudrate : %u\n", baudrate[i]);
- SerialGPS.updateBaudRate(baudrate[i]);
- if (recoveryGPS()) {
- Serial.println("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
- gps_model = "UBlox";
- find_gps = true;
- break;
- }
- }
- } else {
- gps_model = "L76K";
- }
-
- if (find_gps) {
- deviceOnline |= GPS_ONLINE;
- }
-
-#ifdef T_BEAM_S3_SUPREME
- enable_slow_clock();
-#endif
-
-#endif
-}
-
-
-void printResult(bool radio_online)
-{
- Serial.print("Radio : ");
- Serial.println((radio_online) ? "+" : "-");
-
-#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)
-
- Serial.print("PSRAM : ");
- Serial.println((psramFound()) ? "+" : "-");
-
-#ifdef DISPLAY_MODEL
- Serial.print("Display : ");
- Serial.println(( disp) ? "+" : "-");
-#endif
-
-#ifdef HAS_SDCARD
- Serial.print("Sd Card : ");
- Serial.println((SD.cardSize() != 0) ? "+" : "-");
-#endif
-
-#ifdef HAS_PMU
- Serial.print("Power : ");
- Serial.println(( PMU ) ? "+" : "-");
-#endif
-
-#ifdef HAS_GPS
- Serial.print("GPS : ");
- Serial.println(( find_gps ) ? "+" : "-");
-#endif
-
-#ifdef DISPLAY_MODEL
- if (disp) {
-
- disp->clearBuffer();
- disp->setFont(u8g2_font_NokiaLargeBold_tf );
- uint16_t str_w = disp->getStrWidth(BOARD_VARIANT_NAME);
- disp->drawStr((disp->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME);
- disp->drawHLine(5, 21, disp->getWidth() - 5);
-
- disp->drawStr( 0, 38, "Disp:"); disp->drawStr( 45, 38, ( disp) ? "+" : "-");
-
-#ifdef HAS_SDCARD
- disp->drawStr( 0, 54, "SD :"); disp->drawStr( 45, 54, (SD.cardSize() != 0) ? "+" : "-");
-#endif
-
- disp->drawStr( 62, 38, "Radio:"); disp->drawStr( 120, 38, ( radio_online ) ? "+" : "-");
-
-#ifdef HAS_PMU
- disp->drawStr( 62, 54, "Power:"); disp->drawStr( 120, 54, ( PMU ) ? "+" : "-");
-#endif
-
- disp->sendBuffer();
-
- delay(2000);
- }
-#endif
-#endif /*DISPLAY_MODEL*/
-}
-
-
-#ifdef BOARD_LED
-static uint8_t ledState = LOW;
-static const uint32_t debounceDelay = 50;
-static uint32_t lastDebounceTime = 0;
-#endif
-
-
-#ifdef BOARD_LED
-void flashLed()
-{
- if ((millis() - lastDebounceTime) > debounceDelay) {
- ledState = !ledState;
- if (ledState) {
- digitalWrite(BOARD_LED, LED_ON);
- } else {
- digitalWrite(BOARD_LED, !LED_ON);
- }
- lastDebounceTime = millis();
- }
-}
-#endif
-
-
-void scanDevices(TwoWire *w)
-{
- uint8_t err, addr;
- int nDevices = 0;
- uint32_t start = 0;
-
- Serial.println("I2C Devices scanning");
- for (addr = 1; addr < 127; addr++) {
- start = millis();
- w->beginTransmission(addr); delay(2);
- err = w->endTransmission();
- if (err == 0) {
- nDevices++;
- switch (addr) {
- case 0x77:
- bme280_address = addr;
- Serial.printf("\tFound BME280 Sensor at address 0x%02X\n", addr);
- deviceOnline |= BME280_ONLINE;
- break;
- case 0x76:
- bme280_address = addr;
- Serial.printf("\tFound BME280 Sensor at address 0x%02X\n", addr);
- deviceOnline |= BME280_ONLINE;
- break;
- case 0x34:
- Serial.printf("\tFound AXP192/AXP2101 PMU at address 0x%02X\n", addr);
- deviceOnline |= POWERMANAGE_ONLINE;
- break;
- case 0x3C:
- case 0x3D: {
- w->beginTransmission(addr);
- w->write((uint8_t)0x00);
- w->endTransmission();
- w->requestFrom((int)addr, 1);
- uint8_t r = w->read();
- if (r == 0x80) {
- Serial.printf("\tFound QMC6310N MAG Sensor at address 0x%02X\n", addr);
- mag_address = addr;
- deviceOnline |= QMC6310N_ONLINE;
- } else {
- Serial.printf("\tFound OLED display at address 0x%02X\n", addr);
- display_address = addr;
- deviceOnline |= DISPLAY_ONLINE;
- }
- }
- break;
- case 0x51:
- Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
- deviceOnline |= PCF8563_ONLINE;
- break;
- case 0x1C:
- Serial.printf("\tFound QMC6310U MAG Sensor at address 0x%02X\n", addr);
- deviceOnline |= QMC6310U_ONLINE;
- mag_address = addr;
- break;
- default:
- Serial.print("\tI2C device found at address 0x");
- if (addr < 16) {
- Serial.print("0");
- }
- Serial.print(addr, HEX);
- Serial.println(" !");
- break;
- }
-
- } else if (err == 4) {
- Serial.print("Unknow error at address 0x");
- if (addr < 16) {
- Serial.print("0");
- }
- Serial.println(addr, HEX);
- }
- }
- if (nDevices == 0)
- Serial.println("No I2C devices found\n");
-}
-
-
-#ifdef HAS_GPS
-
-bool l76kProbe()
-{
- bool result = false;
- uint32_t startTimeout ;
- SerialGPS.write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
- delay(5);
- // Get version information
- startTimeout = millis() + 3000;
- Serial.print("Try to init L76K . Wait stop .");
- // SerialGPS.flush();
- while (SerialGPS.available()) {
- int c = SerialGPS.read();
- // Serial.write(c);
- // Serial.print(".");
- // Serial.flush();
- // SerialGPS.flush();
- if (millis() > startTimeout) {
- Serial.println("Wait L76K stop NMEA timeout!");
- return false;
- }
- };
- Serial.println();
- SerialGPS.flush();
- delay(200);
-
- SerialGPS.write("$PCAS06,0*1B\r\n");
- startTimeout = millis() + 500;
- String ver = "";
- while (!SerialGPS.available()) {
- if (millis() > startTimeout) {
- Serial.println("Get L76K timeout!");
- return false;
- }
- }
- SerialGPS.setTimeout(10);
- ver = SerialGPS.readStringUntil('\n');
- if (ver.startsWith("$GPTXT,01,01,02")) {
- Serial.println("L76K GNSS init succeeded, using L76K GNSS Module\n");
- result = true;
- }
- delay(500);
-
- // Initialize the L76K Chip, use GPS + GLONASS
- SerialGPS.write("$PCAS04,5*1C\r\n");
- delay(250);
- // only ask for RMC and GGA
- SerialGPS.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
- delay(250);
- // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
- SerialGPS.write("$PCAS11,3*1E\r\n");
- return result;
-}
-
-bool beginGPS()
-{
- SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
- bool result = false;
- for ( int i = 0; i < 3; ++i) {
- result = l76kProbe();
- if (result) {
- return result;
- }
- }
- return result;
-}
-
-
-
-static int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID)
-{
- uint16_t ubxFrameCounter = 0;
- bool ubxFrame = 0;
- uint32_t startTime = millis();
- uint16_t needRead;
-
- while (millis() - startTime < 800) {
- while (SerialGPS.available()) {
- int c = SerialGPS.read();
- switch (ubxFrameCounter) {
- case 0:
- if (c == 0xB5) {
- ubxFrameCounter++;
- }
- break;
- case 1:
- if (c == 0x62) {
- ubxFrameCounter++;
- } else {
- ubxFrameCounter = 0;
- }
- break;
- case 2:
- if (c == requestedClass) {
- ubxFrameCounter++;
- } else {
- ubxFrameCounter = 0;
- }
- break;
- case 3:
- if (c == requestedID) {
- ubxFrameCounter++;
- } else {
- ubxFrameCounter = 0;
- }
- break;
- case 4:
- needRead = c;
- ubxFrameCounter++;
- break;
- case 5:
- needRead |= (c << 8);
- ubxFrameCounter++;
- break;
- case 6:
- if (needRead >= size) {
- ubxFrameCounter = 0;
- break;
- }
- if (SerialGPS.readBytes(buffer, needRead) != needRead) {
- ubxFrameCounter = 0;
- } else {
- return needRead;
- }
- break;
-
- default:
- break;
- }
- }
- }
- return 0;
-}
-
-bool recoveryGPS()
-{
- uint8_t buffer[256];
- uint8_t cfg_clear1[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xA2};
- uint8_t cfg_clear2[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1B, 0xA1};
- uint8_t cfg_clear3[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1D, 0xB3};
- SerialGPS.write(cfg_clear1, sizeof(cfg_clear1));
-
- if (getAck(buffer, 256, 0x05, 0x01)) {
- Serial.println("Get ack successes!");
- }
- SerialGPS.write(cfg_clear2, sizeof(cfg_clear2));
- if (getAck(buffer, 256, 0x05, 0x01)) {
- Serial.println("Get ack successes!");
- }
- SerialGPS.write(cfg_clear3, sizeof(cfg_clear3));
- if (getAck(buffer, 256, 0x05, 0x01)) {
- Serial.println("Get ack successes!");
- }
- // UBX-CFG-RATE, Size 8, 'Navigation/measurement rate settings'
- uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
- SerialGPS.write(cfg_rate, sizeof(cfg_rate));
- if (getAck(buffer, 256, 0x06, 0x08)) {
- Serial.println("Get ack successes!");
- } else {
- return false;
- }
- return true;
-}
-
-#endif
-
-
-#if defined(ARDUINO_ARCH_ESP32)
-
-//NCP18XH103F03RB: https://item.szlcsc.com/14214.html
-// #define NTC_PIN 14 // NTC connection pins
-#define SERIES_RESISTOR 10000 // Series resistance value (10kΩ)
-#define B_COEFFICIENT 3950 // B value, set according to the NTC specification
-#define ROOM_TEMP 298.15 // 25°C absolute temperature (K)
-#define ROOM_TEMP_RESISTANCE 10000 // Resistance of NTC at 25°C (10kΩ)
-
-float getTempForNTC()
-{
- static float temperature = 0.0f;
-#ifdef NTC_PIN
- static uint32_t check_temperature = 0;
- if (millis() > check_temperature) {
- float voltage = analogReadMilliVolts(NTC_PIN) / 1000.0;
- float resistance = SERIES_RESISTOR * ((3.3 / voltage) - 1); // Calculate the resistance of NTC
-
- // Calculate temperature using the Steinhart-Hart equation
- temperature = (1.0 / (log(resistance / ROOM_TEMP_RESISTANCE) / B_COEFFICIENT + 1.0 / ROOM_TEMP)) - 273.15;
-
- // Serial.print("Temperature: ");
- // Serial.print(temperature);
- // Serial.println(" °C");
-
- check_temperature = millis() + 1000;
- }
-#endif
- return temperature;
-}
-
-#ifdef ENABLE_BLE
-
-#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
-#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
-
-void setupBLE()
-{
-
- uint8_t mac[6];
- char macStr[18] = { 0 };
- esp_efuse_mac_get_default(mac);
- sprintf(macStr, "%02X:%02X", mac[0], mac[1]);
-
- String dev = BOARD_VARIANT_NAME;
- dev.concat('-');
- dev.concat(macStr);
-
- Serial.print("Starting BLE:");
- Serial.println(dev);
-
- BLEDevice::init(dev.c_str());
- BLEServer *pServer = BLEDevice::createServer();
- BLEService *pService = pServer->createService(SERVICE_UUID);
- BLECharacteristic *pCharacteristic = pService->createCharacteristic(
- CHARACTERISTIC_UUID,
- BLECharacteristic::PROPERTY_READ |
- BLECharacteristic::PROPERTY_WRITE);
-
- pCharacteristic->setValue("Hello World");
- pService->start();
- // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
- BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
- pAdvertising->addServiceUUID(SERVICE_UUID);
- pAdvertising->setScanResponse(true);
- pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
- pAdvertising->setMinPreferred(0x12);
- BLEDevice::startAdvertising();
- Serial.println("Characteristic defined! Now you can read it in your phone!");
-}
-#endif
-
-#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
-
-static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
-{
- const uint32_t cal_count = 1000;
- const float factor = (1 << 19) * 1000.0f;
- uint32_t cali_val;
- for (int i = 0; i < 5; ++i) {
- cali_val = rtc_clk_cal(cal_clk, cal_count);
- }
- return cali_val;
-}
-
-static void enable_slow_clock()
-{
- rtc_clk_32k_enable(true);
- CALIBRATE_ONE(RTC_CAL_RTC_MUX);
- uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);
- if (cal_32k == 0) {
- Serial.printf("32K XTAL OSC has not started up");
- } else {
- rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
- Serial.println("Switching RTC Source to 32.768Khz succeeded, using 32K XTAL");
- CALIBRATE_ONE(RTC_CAL_RTC_MUX);
- CALIBRATE_ONE(RTC_CAL_32K_XTAL);
- }
- CALIBRATE_ONE(RTC_CAL_RTC_MUX);
- CALIBRATE_ONE(RTC_CAL_32K_XTAL);
- if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
- Serial.println("Warning: Failed to set rtc clk to 32.768Khz !!! "); return;
- }
- deviceOnline |= OSC32768_ONLINE;
-}
-
-
-void scanWiFi()
-{
- WiFi.mode(WIFI_STA);
- WiFi.disconnect();
- Serial.println("WiFi Scan start");
- // WiFi.scanNetworks will return the number of networks found.
- int n = WiFi.scanNetworks();
- Serial.println("WiFi Scan done");
- if (n == 0) {
- Serial.println("no networks found");
- } else {
- Serial.print(n);
- Serial.println(" networks found");
- Serial.println("Nr | SSID | RSSI | CH | Encryption");
- for (int i = 0; i < n; ++i) {
- // Print SSID and RSSI for each network found
- Serial.printf("%2d", i + 1);
- Serial.print(" | ");
- Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
- Serial.print(" | ");
- Serial.printf("%4ld", WiFi.RSSI(i));
- Serial.print(" | ");
- Serial.printf("%2ld", WiFi.channel(i));
- Serial.print(" | ");
- switch (WiFi.encryptionType(i)) {
- case WIFI_AUTH_OPEN: Serial.print("open"); break;
- case WIFI_AUTH_WEP: Serial.print("WEP"); break;
- case WIFI_AUTH_WPA_PSK: Serial.print("WPA"); break;
- case WIFI_AUTH_WPA2_PSK: Serial.print("WPA2"); break;
- case WIFI_AUTH_WPA_WPA2_PSK: Serial.print("WPA+WPA2"); break;
- case WIFI_AUTH_WPA2_ENTERPRISE: Serial.print("WPA2-EAP"); break;
- case WIFI_AUTH_WPA3_PSK: Serial.print("WPA3"); break;
- case WIFI_AUTH_WPA2_WPA3_PSK: Serial.print("WPA2+WPA3"); break;
- case WIFI_AUTH_WAPI_PSK: Serial.print("WAPI"); break;
- default: Serial.print("unknown");
- }
- Serial.println();
- delay(10);
- }
- }
- Serial.println("");
-
- // Delete the scan result to free memory for code below.
- WiFi.scanDelete();
-}
-
-#endif /*ARDUINO_ARCH_ESP32*/
-
diff --git a/examples/Sensor/QMC6310_CalibrateExample/LoRaBoards.h b/examples/Sensor/QMC6310_CalibrateExample/LoRaBoards.h
deleted file mode 100644
index 58288ef..0000000
--- a/examples/Sensor/QMC6310_CalibrateExample/LoRaBoards.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * @file boards.h
- * @author Lewis He (lewishe@outlook.com)
- * @license MIT
- * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
- * @date 2024-04-25
- * @last-update 2024-08-07
- */
-
-#pragma once
-
-
-#include "utilities.h"
-
-#ifdef HAS_SDCARD
-#include
-#endif
-
-#if defined(ARDUINO_ARCH_ESP32)
-#include
-#include
-#endif
-
-#include
-#include
-#include
-
-#ifdef DISPLAY_MODEL
-#include
-#endif
-
-#ifdef HAS_PMU
-#include
-#endif
-
-#include
-
-
-#ifndef DISPLAY_ADDR
-#define DISPLAY_ADDR 0x3C
-#endif
-
-
-// #define ENABLE_BLE //Enable ble function
-
-enum {
- POWERMANAGE_ONLINE = _BV(0),
- DISPLAY_ONLINE = _BV(1),
- RADIO_ONLINE = _BV(2),
- GPS_ONLINE = _BV(3),
- PSRAM_ONLINE = _BV(4),
- SDCARD_ONLINE = _BV(5),
- AXDL345_ONLINE = _BV(6),
- BME280_ONLINE = _BV(7),
- BMP280_ONLINE = _BV(8),
- BME680_ONLINE = _BV(9),
- QMC6310U_ONLINE = _BV(10),
- QMC6310N_ONLINE = _BV(11),
- QMI8658_ONLINE = _BV(12),
- PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
-};
-
-
-
-typedef struct {
- String chipModel;
- float psramSize;
- uint8_t chipModelRev;
- uint8_t chipFreq;
- uint8_t flashSize;
- uint8_t flashSpeed;
-} DevInfo_t;
-
-
-void setupBoards(bool disable_u8g2 = false);
-
-#ifdef HAS_SDCARD
-bool beginSDCard();
-#else
-#define beginSDCard()
-#endif
-
-#ifdef DISPLAY_MODEL
-bool beginDisplay();
-#endif
-
-
-void printResult(bool radio_online);
-
-#ifdef BOARD_LED
-void flashLed();
-#else
-#define flashLed()
-#endif
-
-void scanDevices(TwoWire *w);
-
-bool beginGPS();
-
-bool recoveryGPS();
-
-void scanWiFi();
-
-#ifdef HAS_PMU
-extern XPowersLibInterface *PMU;
-extern bool pmuInterrupt;
-void loopPMU(void (*pressed_cb)(void));
-bool beginPower();
-void disablePeripherals();
-#else
-#define beginPower()
-#define disablePeripherals()
-#endif
-
-#ifdef DISPLAY_MODEL
-extern U8G2 *disp;
-#define U8G2_HOR_ALIGN_CENTER(t) ((disp->getDisplayWidth() - (disp->getUTF8Width(t))) / 2)
-#define U8G2_HOR_ALIGN_RIGHT(t) ( disp->getDisplayWidth() - disp->getUTF8Width(t))
-#endif
-
-
-#if defined(ARDUINO_ARCH_ESP32)
-
-#if defined(HAS_SDCARD)
-extern SPIClass SDCardSPI;
-#endif
-
-#define SerialGPS Serial1
-#elif defined(ARDUINO_ARCH_STM32)
-extern HardwareSerial SerialGPS;
-#endif
-
-#ifdef NTC_PIN
-float getTempForNTC();
-#endif
-
-#ifdef ENABLE_BLE
-void setupBLE();
-#else
-#define setupBLE()
-#endif
-
-extern uint32_t deviceOnline;
diff --git a/examples/Sensor/QMC6310_CalibrateExample/QMC6310_CalibrateExample.ino b/examples/Sensor/QMC6310_CalibrateExample/QMC6310_CalibrateExample.ino
index b07b118..967afaa 100644
--- a/examples/Sensor/QMC6310_CalibrateExample/QMC6310_CalibrateExample.ino
+++ b/examples/Sensor/QMC6310_CalibrateExample/QMC6310_CalibrateExample.ino
@@ -2,7 +2,7 @@
*
* @license MIT License
*
- * Copyright (c) 2022 lewis he
+ * Copyright (c) 2026 lewis he
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,20 +24,63 @@
*
* @file QMC6310_CalibrateExample.ino
* @author Lewis He (lewishe@outlook.com)
- * @date 2022-10-16
+ * @date 2026-01-26
*
*/
#include
#include
#include
#include "SensorQMC6310.hpp"
-#include "LoRaBoards.h"
+#define ARDUINO_T_BEAM_S3_SUPREME
+#ifdef ARDUINO_T_BEAM_S3_SUPREME
+#include //PMU Library https://github.com/lewisxhe/XPowersLib.git
+#endif
-SensorQMC6310 qmc;
+#ifndef SENSOR_SDA
+#define SENSOR_SDA 17
+#endif
+
+#ifndef SENSOR_SCL
+#define SENSOR_SCL 18
+#endif
+
+SensorQMC6310 magnetometer;
+
+void beginPower()
+{
+#if defined(ARDUINO_T_BEAM_S3_SUPREME)
+ XPowersAXP2101 power;
+ power.begin(Wire1, AXP2101_SLAVE_ADDRESS, 42, 41);
+ power.disableALDO1();
+ power.disableALDO2();
+ delay(250);
+ power.setALDO1Voltage(3300);
+ power.enableALDO1();
+ power.setALDO2Voltage(3300);
+ power.enableALDO2();
+#endif
+}
void calibrate()
{
- qmc.setDataOutputRate(SensorQMC6310::DATARATE_200HZ);
+ if (!magnetometer.setOutputDataRate(200.0f)) {
+ Serial.println("Failed to set output data rate");
+ return ;
+ }
+
+ Serial.println("========================================");
+ Serial.println("Calibration Instructions:");
+ Serial.println("1. Rotate sensor in FIGURE-8 pattern");
+ Serial.println("2. Cover all axes (X, Y, Z directions)");
+ Serial.println("3. Rotate slowly and completely");
+ Serial.println("4. Wait for progress bar to complete");
+ Serial.println("5. Expected: Magnetic Strength ~25-65 uT");
+ Serial.println("========================================");
+ Serial.println();
+
+ Serial.println("Place the sensor on the plane and slowly rotate the sensor...");
+ Serial.println("Rotate in FIGURE-8 pattern to cover all directions!");
+ Serial.println();
int32_t x_min = 65535;
int32_t x_max = -65535;
@@ -45,26 +88,25 @@ void calibrate()
int32_t y_max = -65535;
int32_t z_min = 65535;
int32_t z_max = -65535;
- Serial.println("Place the sensor on the plane and slowly rotate the sensor...");
int32_t range = 1000;
int32_t i = 0;
int32_t x = 0, y = 0, z = 0;;
- float a = 0.5 ;
- float x_offset = 0;
- float y_offset = 0;
- float z_offset = 0;
+ int16_t x_offset = 0;
+ int16_t y_offset = 0;
+ int16_t z_offset = 0;
+ MagnetometerData data;
while (i < range) {
i += 1;
- if (qmc.isDataReady()) {
+ if (magnetometer.isDataReady()) {
- qmc.readData();
+ magnetometer.readData(data);
- x = a * qmc.getRawX() + (1 - a) * x;
- y = a * qmc.getRawY() + (1 - a) * y;
- z = a * qmc.getRawZ() + (1 - a) * z;
+ x = (data.raw.x + x) / 2;
+ y = (data.raw.y + y) / 2;
+ z = (data.raw.z + z) / 2;
if (x < x_min) {
x_min = x;
i = 0;
@@ -104,11 +146,41 @@ void calibrate()
y_offset = (y_max + y_min) / 2;
z_offset = (z_max + z_min) / 2;
- Serial.printf("x_min:%d x_max:%d y_min:%d y_max:%d z_min:%d z_max:%d\n", x_min, x_max, y_min, y_max, z_min, z_max);
- Serial.printf("x_offset:%.2f y_offset:%.2f z_offset:%.2f \n", x_offset, y_offset, z_offset);
+ Serial.print("x_min:");
+ Serial.println(x_min);
+
+ Serial.print("x_max:");
+ Serial.println(x_max);
+
+ Serial.print("y_min:");
+ Serial.println(y_min);
+
+ Serial.print("y_max:");
+ Serial.println(y_max);
+
+ Serial.print("z_min:");
+ Serial.println(z_min);
+
+ Serial.print("z_max:");
+ Serial.println(z_max);
+
+ Serial.print("x_offset:");
+ Serial.println(x_offset);
+
+ Serial.print("y_offset:");
+ Serial.println(y_offset);
+
+ Serial.print("z_offset:");
+ Serial.println(z_offset);
+
// Set the calibration value and the user calculates the deviation
- qmc.setOffset(x_offset, y_offset, z_offset);
+ magnetometer.setOffset(x_offset, y_offset, z_offset);
+
+ Serial.println();
+ Serial.println("Calibration complete!");
+ Serial.println("Check if Magnetic Strength is ~25-65 uT");
+ Serial.println("If too low, repeat calibration with better rotation");
}
@@ -117,118 +189,136 @@ void setup()
Serial.begin(115200);
while (!Serial);
- setupBoards();
+ // LilyGo T-Beam-Supreme sensor requires a power source to function.
+ beginPower();
- // For QMC6310U, the device address is 0x1C.
- // For QMC6310N, the device address is 0x3C.
- // The sensor device address is provided by the setupBoards I2C scanner.
- extern uint8_t mag_address;
- if (!qmc.begin(Wire, mag_address, I2C_SDA, I2C_SCL)) {
- Serial.println("Failed to find QMC6310 - check your wiring!");
+ /**
+ * Supports QMC6310U and QMC6310N; simply pass the corresponding device address
+ * during initialization.
+ * - QMC6310U_SLAVE_ADDRESS
+ * - QMC6310N_SLAVE_ADDRESS
+ */
+ uint8_t address = QMC6310U_SLAVE_ADDRESS;
+ // uint8_t address = QMC6310N_SLAVE_ADDRESS;
+
+ if (!magnetometer.begin(Wire, address, SENSOR_SDA, SENSOR_SCL)) {
while (1) {
+ Serial.println("Failed to find QMC6310 - check your wiring!");
delay(1000);
}
}
- /* Get Magnetometer chip id*/
- Serial.print("Device ID:");
- Serial.println(qmc.getChipID(), HEX);
+ // The desired output data rate in Hz. Allowed values are 10.0, 50.0, 100.0 and 200.0HZ.
+ float data_rate_hz = 200.0f;
+ // op_mode: Allowed values are SUSPEND, NORMAL, SINGLE_MEASUREMENT, CONTINUOUS_MEASUREMENT
+ OperationMode op_mode = OperationMode::CONTINUOUS_MEASUREMENT;
+ // full_scale: Allowed values are FS_2G, FS_8G, FS_12G ,FS_30G
+ MagFullScaleRange full_scale = MagFullScaleRange::FS_8G;
+ // over_sample_ratio: Allowed values are OSR_1, OSR_2, OSR_4, OSR_8
+ MagOverSampleRatio over_sample_ratio = MagOverSampleRatio::OSR_1;
+ // down_sample_ratio: Allowed values are DSR_1, DSR_2, DSR_4, DSR_8
+ MagDownSampleRatio down_sample_ratio = MagDownSampleRatio::DSR_1;
/* Config Magnetometer */
- qmc.configMagnetometer(
- /*
- * Run Mode
- * MODE_SUSPEND
- * MODE_NORMAL
- * MODE_SINGLE
- * MODE_CONTINUOUS
- * * */
- SensorQMC6310::MODE_CONTINUOUS,
- /*
- * Full Range
- * RANGE_30G
- * RANGE_12G
- * RANGE_8G
- * RANGE_2G
- * * */
- SensorQMC6310::RANGE_8G,
- /*
- * Output data rate
- * DATARATE_10HZ
- * DATARATE_50HZ
- * DATARATE_100HZ
- * DATARATE_200HZ
- * * */
- SensorQMC6310::DATARATE_200HZ,
- /*
- * Over sample Ratio1
- * OSR_8
- * OSR_4
- * OSR_2
- * OSR_1
- * * * */
- SensorQMC6310::OSR_1,
-
- /*
- * Down sample Ratio1
- * DSR_8
- * DSR_4
- * DSR_2
- * DSR_1
- * * */
- SensorQMC6310::DSR_1);
-
-
-
+ if (magnetometer.configMagnetometer(
+ op_mode,
+ full_scale,
+ data_rate_hz,
+ over_sample_ratio,
+ down_sample_ratio)) {
+ Serial.println("Magnetometer configured successfully.");
+ } else {
+ Serial.println("Magnetometer configuration failed.");
+ while (1);
+ }
// Calibration algorithm reference from
// https://github.com/CoreElectronics/CE-PiicoDev-QMC6310-MicroPython-Module
calibrate();
- Serial.println("Calibration done .");
+ Serial.println("Calibration done.");
delay(5000);
+ SensorInfo info = magnetometer.getSensorInfo();
+ Serial.print("Manufacturer: "); Serial.println(info.manufacturer);
+ Serial.print("Model: "); Serial.println(info.model);
+ Serial.print("I2C Address: 0x"); Serial.println(info.i2c_address, HEX);
+ Serial.print("Version: "); Serial.println(info.version);
+ Serial.print("UID: 0x"); Serial.println(info.uid);
+ Serial.print("Type: "); Serial.println(SensorUtils::typeToString(info.type));
+
+ SensorConfig cfg = magnetometer.getConfig();
+ Serial.print("DataRate: "); Serial.println(cfg.sample_rate);
+ Serial.print("FullScaleRange: "); Serial.println(cfg.range);
+ Serial.print("Mode: "); Serial.println((uint8_t)cfg.mode);
+ Serial.println();
+
+ //Find the magnetic declination : https://www.magnetic-declination.com/
+ float declination_deg = MagnetometerUtils::dmsToDecimalDegrees(-3, 20); // -3.3333
+
+ magnetometer.setDeclination(declination_deg);
+
+ Serial.print(" Magnetic Declination: ");
+ Serial.print(declination_deg, 2);
+ Serial.println("°");
+
+ Serial.print(" Sensitivity: ");
+ Serial.print(magnetometer.getSensitivity(), 6);
+ Serial.println(" Gauss/LSB");
+
+ delay(3000);
+
Serial.println("Read data now...");
}
void loop()
{
+ MagnetometerData data;
- //Wiat data ready
- if (qmc.isDataReady()) {
+ if (magnetometer.readData(data)) {
- qmc.readData();
+ // Gauss to μT
+ float x = MagnetometerUtils::gaussToMicroTesla(data.magnetic_field.x);
+ float y = MagnetometerUtils::gaussToMicroTesla(data.magnetic_field.y);
+ float z = MagnetometerUtils::gaussToMicroTesla(data.magnetic_field.z);
- Serial.print("GYR: ");
- Serial.print("X:");
- Serial.print(qmc.getX());
+ Serial.print("Mag:");
+ Serial.print(" X:"); Serial.print(x);
+ Serial.print(" Y:"); Serial.print(y);
+ Serial.print(" Z:"); Serial.print(z);
+ Serial.print(" μT");
+
+ Serial.print(" Sensitivity: ");
+ Serial.print(magnetometer.getSensitivity(), 6);
+ Serial.print(" Gauss/LSB");
+
+ Serial.print(" Metadata:");
+ Serial.print(" X:");
+ Serial.print(data.raw.x);
Serial.print(" Y:");
- Serial.print(qmc.getY());
+ Serial.print(data.raw.y);
Serial.print(" Z:");
- Serial.print(qmc.getZ());
- Serial.println(" uT");
- Serial.print("RAW: ");
- Serial.print("X:");
- Serial.print(qmc.getRawX());
- Serial.print(" Y:");
- Serial.print(qmc.getRawY());
- Serial.print(" Z:");
- Serial.println(qmc.getRawZ());
+ Serial.print(data.raw.z);
- /*
- float x, y, z;
- qmc.getMag(x, y, z);
- Serial.print("X:");
- Serial.print(x);
- Serial.print(" Y:");
- Serial.print(y);
- Serial.print(" Z:");
- Serial.println(x);
- */
+ Serial.print(" Heading (rad): ");
+ Serial.print(data.heading, 6);
+ Serial.print(" rad");
+
+ Serial.print(" Heading (deg): ");
+ Serial.print(data.heading_degrees, 2);
+ Serial.print("°");
+
+ float strength = MagnetometerUtils::calculateMagneticStrength(data);
+ strength = MagnetometerUtils::gaussToMicroTesla(strength);
+ Serial.print(" Magnetic Strength: ");
+ Serial.print(strength, 2);
+ Serial.println(" μT");
+
+ if (data.overflow) {
+ Serial.println("\tWarning: Data Overflow occurred!");
+ }
}
-
-
- delay(100);
+ delay(10);
}
diff --git a/examples/Sensor/QMC6310_CompassExample/LoRaBoards.cpp b/examples/Sensor/QMC6310_CompassExample/LoRaBoards.cpp
deleted file mode 100644
index 8acfe74..0000000
--- a/examples/Sensor/QMC6310_CompassExample/LoRaBoards.cpp
+++ /dev/null
@@ -1,1353 +0,0 @@
-/**
- * @file boards.cpp
- * @author Lewis He (lewishe@outlook.com)
- * @license MIT
- * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
- * @date 2024-04-24
- * @last-update 2025-05-26
- *
- */
-
-#include "LoRaBoards.h"
-
-#include "soc/rtc.h"
-#ifdef ENABLE_BLE
-#include
-#include
-#include
-#endif
-
-#if defined(HAS_SDCARD) && !defined(SD_SHARE_SPI_BUS)
-SPIClass SDCardSPI(HSPI);
-#endif
-
-
-#if defined(ARDUINO_ARCH_STM32)
-HardwareSerial SerialGPS(GPS_RX_PIN, GPS_TX_PIN);
-#endif
-
-#if defined(ARDUINO_ARCH_ESP32)
-#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,0,0)
-#include "hal/gpio_hal.h"
-#endif
-#include "driver/gpio.h"
-#endif //ARDUINO_ARCH_ESP32
-
-#ifdef DISPLAY_MODEL
-U8G2 *disp = NULL;
-#endif
-
-
-static DevInfo_t devInfo;
-
-#ifdef HAS_GPS
-static bool find_gps = false;
-String gps_model = "None";
-#endif
-
-// I2S Devices default address
-uint8_t bme280_address = 0x77; // It might be 0x76
-uint8_t mag_address = 0x1C; // QMC6310U=0x1C QMC6310N=0x3C
-uint8_t display_address = 0x3c; // It might be 0x3D
-
-uint32_t deviceOnline = 0x00;
-
-static void enable_slow_clock();
-
-#ifdef HAS_PMU
-XPowersLibInterface *PMU = NULL;
-bool pmuInterrupt;
-
-static void setPmuFlag()
-{
- pmuInterrupt = true;
-}
-bool beginPower()
-{
- if (!PMU) {
- PMU = new XPowersAXP2101(PMU_WIRE_PORT);
- if (!PMU->init()) {
- Serial.println("Warning: Failed to find AXP2101 power management");
- delete PMU;
- PMU = NULL;
- } else {
- Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU");
- }
- }
-
- if (!PMU) {
- PMU = new XPowersAXP192(PMU_WIRE_PORT);
- if (!PMU->init()) {
- Serial.println("Warning: Failed to find AXP192 power management");
- delete PMU;
- PMU = NULL;
- } else {
- Serial.println("AXP192 PMU init succeeded, using AXP192 PMU");
- }
- }
-
- if (!PMU) {
- return false;
- }
-
- deviceOnline |= POWERMANAGE_ONLINE;
-
- PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
-
- pinMode(PMU_IRQ, INPUT_PULLUP);
- attachInterrupt(PMU_IRQ, setPmuFlag, FALLING);
-
- if (PMU->getChipModel() == XPOWERS_AXP192) {
-
- PMU->setProtectedChannel(XPOWERS_DCDC3);
-
- // lora
- PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
- // gps
- PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
- // oled
- PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
-
- PMU->enablePowerOutput(XPOWERS_LDO2);
- PMU->enablePowerOutput(XPOWERS_LDO3);
-
- //protected oled power source
- PMU->setProtectedChannel(XPOWERS_DCDC1);
- //protected esp32 power source
- PMU->setProtectedChannel(XPOWERS_DCDC3);
- // enable oled power
- PMU->enablePowerOutput(XPOWERS_DCDC1);
-
- //disable not use channel
- PMU->disablePowerOutput(XPOWERS_DCDC2);
-
- PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
-
- PMU->enableIRQ(XPOWERS_AXP192_VBUS_REMOVE_IRQ |
- XPOWERS_AXP192_VBUS_INSERT_IRQ |
- XPOWERS_AXP192_BAT_CHG_DONE_IRQ |
- XPOWERS_AXP192_BAT_CHG_START_IRQ |
- XPOWERS_AXP192_BAT_REMOVE_IRQ |
- XPOWERS_AXP192_BAT_INSERT_IRQ |
- XPOWERS_AXP192_PKEY_SHORT_IRQ
- );
-
- } else if (PMU->getChipModel() == XPOWERS_AXP2101) {
-
-#if defined(CONFIG_IDF_TARGET_ESP32)
- //Unuse power channel
- PMU->disablePowerOutput(XPOWERS_DCDC2);
- PMU->disablePowerOutput(XPOWERS_DCDC3);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_ALDO1);
- PMU->disablePowerOutput(XPOWERS_ALDO4);
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO2);
- PMU->disablePowerOutput(XPOWERS_DLDO1);
- PMU->disablePowerOutput(XPOWERS_DLDO2);
- PMU->disablePowerOutput(XPOWERS_CPULDO);
-
- // GNSS RTC PowerVDD 3300mV
- PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
- PMU->enablePowerOutput(XPOWERS_VBACKUP);
-
- //ESP32 VDD 3300mV
- // ! No need to set, automatically open , Don't close it
- // PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
- // PMU->setProtectedChannel(XPOWERS_DCDC1);
- PMU->setProtectedChannel(XPOWERS_DCDC1);
-
- // LoRa VDD 3300mV
- PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO2);
-
- //GNSS VDD 3300mV
- PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO3);
-
-#endif /*CONFIG_IDF_TARGET_ESP32*/
-
-
-#if defined(T_BEAM_S3_SUPREME)
-
- //t-beam m.2 inface
- //gps
- PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO4);
-
- // lora
- PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO3);
-
- // In order to avoid bus occupation, during initialization, the SD card and QMC sensor are powered off and restarted
- if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()) {
- Serial.println("Power off and restart ALDO BLDO..");
- PMU->disablePowerOutput(XPOWERS_ALDO1);
- PMU->disablePowerOutput(XPOWERS_ALDO2);
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- delay(250);
- }
-
- // Sensor
- PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO1);
-
- PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO2);
-
- //Sdcard
-
- PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
- PMU->enablePowerOutput(XPOWERS_BLDO1);
-
- PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_BLDO2);
-
- //face m.2
- PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC3);
-
- PMU->setPowerChannelVoltage(XPOWERS_DCDC4, XPOWERS_AXP2101_DCDC4_VOL2_MAX);
- PMU->enablePowerOutput(XPOWERS_DCDC4);
-
- PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC5);
-
-
- //not use channel
- PMU->disablePowerOutput(XPOWERS_DCDC2);
- // PMU->disablePowerOutput(XPOWERS_DCDC4);
- // PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_DLDO1);
- PMU->disablePowerOutput(XPOWERS_DLDO2);
- PMU->disablePowerOutput(XPOWERS_VBACKUP);
-
-
-#elif defined(T_BEAM_S3_BPF)
-
- //gps
- PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO4);
-
- //Sdcard
- PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO2);
-
- // Extern Power source
- PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC3);
-
- PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC5);
-
- PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO1);
-
- //not use channel
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO2);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC2);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_DLDO1);
- PMU->disablePowerOutput(XPOWERS_DLDO2);
- PMU->disablePowerOutput(XPOWERS_VBACKUP);
-
-
-#endif
-
- // Set constant current charge current limit
- PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
-
- // Set charge cut-off voltage
- PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
-
- // Disable all interrupts
- PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
- // Clear all interrupt flags
- PMU->clearIrqStatus();
- // Enable the required interrupt function
- PMU->enableIRQ(
- XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | //BATTERY
- XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | //VBUS
- XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | //POWER KEY
- XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ //CHARGE
- // XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ | XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | //POWER KEY
- );
-
- }
-
- PMU->enableSystemVoltageMeasure();
- PMU->enableVbusVoltageMeasure();
- PMU->enableBattVoltageMeasure();
-
- Serial.printf("=========================================\n");
- if (PMU->isChannelAvailable(XPOWERS_DCDC1)) {
- Serial.printf("DC1 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC2)) {
- Serial.printf("DC2 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC3)) {
- Serial.printf("DC3 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC4)) {
- Serial.printf("DC4 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC5)) {
- Serial.printf("DC5 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC5) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC5));
- }
- if (PMU->isChannelAvailable(XPOWERS_LDO2)) {
- Serial.printf("LDO2 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO2));
- }
- if (PMU->isChannelAvailable(XPOWERS_LDO3)) {
- Serial.printf("LDO3 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO3));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO1)) {
- Serial.printf("ALDO1: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO2)) {
- Serial.printf("ALDO2: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO3)) {
- Serial.printf("ALDO3: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO4)) {
- Serial.printf("ALDO4: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
- }
- if (PMU->isChannelAvailable(XPOWERS_BLDO1)) {
- Serial.printf("BLDO1: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
- }
- if (PMU->isChannelAvailable(XPOWERS_BLDO2)) {
- Serial.printf("BLDO2: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
- }
-
-
- // Set the time of pressing the button to turn off
- PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
- uint8_t opt = PMU->getPowerKeyPressOffTime();
- Serial.print("PowerKeyPressOffTime:");
- switch (opt) {
- case XPOWERS_POWEROFF_4S: Serial.println("4 Second");
- break;
- case XPOWERS_POWEROFF_6S: Serial.println("6 Second");
- break;
- case XPOWERS_POWEROFF_8S: Serial.println("8 Second");
- break;
- case XPOWERS_POWEROFF_10S: Serial.println("10 Second");
- break;
- default:
- break;
- }
-
- Serial.printf("=========================================\n");
-
- return true;
-}
-
-void disablePeripherals()
-{
-
- if (!PMU)return;
-
- PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
- // Disable the PMU measurement section
- PMU->disableSystemVoltageMeasure();
- PMU->disableVbusVoltageMeasure();
- PMU->disableBattVoltageMeasure();
- PMU->disableTemperatureMeasure();
- PMU->disableBattDetection();
-
-#if defined(T_BEAM_S3_BPF)
- PMU->disablePowerOutput(XPOWERS_ALDO4); //gps
- PMU->disablePowerOutput(XPOWERS_ALDO2); //Sdcard
- PMU->disablePowerOutput(XPOWERS_DCDC3); // Extern Power source
- PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_ALDO1);
-#else
-
- if (PMU->getChipModel() == XPOWERS_AXP2101) {
-
- // Disable all PMU interrupts
- PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
- // Clear the PMU interrupt status before sleeping, otherwise the sleep current will increase
- PMU->clearIrqStatus();
- // GNSS RTC Power , Turning off GPS backup voltage and current can further reduce ~ 100 uA
- PMU->disablePowerOutput(XPOWERS_VBACKUP);
- // LoRa VDD
- PMU->disablePowerOutput(XPOWERS_ALDO2);
- // GNSS VDD
- PMU->disablePowerOutput(XPOWERS_ALDO3);
-
-#if defined(T_BEAM_S3_SUPREME)
- PMU->disablePowerOutput(XPOWERS_ALDO4);
- PMU->disablePowerOutput(XPOWERS_ALDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO2);
- PMU->disablePowerOutput(XPOWERS_DCDC3);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC5);
-#endif
-
- } else if (PMU->getChipModel() == XPOWERS_AXP192) {
-
- // Disable all PMU interrupts
- PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
- // Clear the PMU interrupt status before sleeping, otherwise the sleep current will increase
- PMU->clearIrqStatus();
- // LoRa VDD
- PMU->disablePowerOutput(XPOWERS_LDO2);
- // GNSS VDD
- PMU->disablePowerOutput(XPOWERS_LDO3);
-
-
- }
-#endif
-}
-
-void loopPMU(void (*pressed_cb)(void))
-{
- if (!PMU) {
- return;
- }
- if (!pmuInterrupt) {
- return;
- }
-
- pmuInterrupt = false;
- // Get PMU Interrupt Status Register
- uint32_t status = PMU->getIrqStatus();
- Serial.print("STATUS => HEX:");
- Serial.print(status, HEX);
- Serial.print(" BIN:");
- Serial.println(status, BIN);
-
- if (PMU->isVbusInsertIrq()) {
- Serial.println("isVbusInsert");
- }
- if (PMU->isVbusRemoveIrq()) {
- Serial.println("isVbusRemove");
- }
- if (PMU->isBatInsertIrq()) {
- Serial.println("isBatInsert");
- }
- if (PMU->isBatRemoveIrq()) {
- Serial.println("isBatRemove");
- }
- if (PMU->isPekeyShortPressIrq()) {
- Serial.println("isPekeyShortPress");
- if (pressed_cb) {
- pressed_cb();
- }
- }
- if (PMU->isPekeyLongPressIrq()) {
- Serial.println("isPekeyLongPress");
- }
- if (PMU->isBatChargeDoneIrq()) {
- Serial.println("isBatChargeDone");
- }
- if (PMU->isBatChargeStartIrq()) {
- Serial.println("isBatChargeStart");
- }
- // Clear PMU Interrupt Status Register
- PMU->clearIrqStatus();
-}
-#endif
-
-#ifdef DISPLAY_MODEL
-bool beginDisplay()
-{
- Wire.beginTransmission(display_address);
- if (Wire.endTransmission() == 0) {
- disp = new DISPLAY_MODEL(U8G2_R0, U8X8_PIN_NONE);
- Serial.printf("Find Display model at 0x%X address\n", display_address);
- disp->begin();
- disp->clearBuffer();
- disp->setFont(u8g2_font_inb19_mr);
- disp->drawStr(0, 30, "LilyGo");
- disp->drawHLine(2, 35, 47);
- disp->drawHLine(3, 36, 47);
- disp->drawVLine(45, 32, 12);
- disp->drawVLine(46, 33, 12);
- disp->setFont(u8g2_font_inb19_mf);
- disp->drawStr(58, 60, "LoRa");
- disp->sendBuffer();
- disp->setFont(u8g2_font_fur11_tf);
- delay(3000);
- return true;
- }
-
- Serial.printf("Warning: Failed to find Display at 0x%0X address\n", display_address);
- return false;
-}
-#endif
-
-#ifdef HAS_SDCARD
-bool writeFile(const char *path, const char *buffer)
-{
- bool rlst = false;
- File file = SD.open(path, FILE_WRITE);
- if (!file) {
- Serial.println("Failed to open file for writing");
- return false;
- }
- if (file.print(buffer)) {
- Serial.println("File written");
- rlst = true;
- } else {
- Serial.println("Write failed");
- rlst = false;
- }
- file.close();
- return rlst;
-}
-
-
-bool readFile(const char *path, uint8_t *buffer, size_t size)
-{
- File file = SD.open(path, FILE_READ);
- if (!file) {
- Serial.println("Failed to open file for reading");
- return false;
- }
- file.read(buffer, size);
- file.close();
- return false;
-}
-
-bool testSDWriteAndRead()
-{
- const char *path = "/test_sd.txt";
- const char *message = "This is a string for reading and writing SD card.";
- uint8_t buffer[128] = {0};
-
- if (!writeFile(path, message)) {
- Serial.println("SD Text write failed");
- return false;
- }
- delay(100);
-
- readFile(path, buffer, 128);
-
- if (memcmp(buffer, message, strlen(message)) != 0) {
- Serial.println("SD verification failed");
- return false;
- }
- Serial.println("SD verification successful");
- return true;
-}
-#endif /*HAS_SDCARD*/
-
-#ifdef HAS_SDCARD
-bool beginSDCard()
-{
-#if defined(HAS_SDCARD) && defined(SD_SHARE_SPI_BUS)
- bool rlst = SD.begin(SDCARD_CS);
-#else
- bool rlst = SD.begin(SDCARD_CS, SDCardSPI);
-#endif
-
- if (rlst) {
- uint32_t cardSize = SD.cardSize() / (1024 * 1024);
- Serial.print("Sd Card init succeeded, The current available capacity is ");
- Serial.print(cardSize / 1024.0);
- Serial.println(" GB");
- deviceOnline |= SDCARD_ONLINE;
- return testSDWriteAndRead();
- } else {
- Serial.println("Warning: Failed to init Sd Card");
- }
- return false;
-}
-#endif /*HAS_SDCARD*/
-
-void beginWiFi()
-{
-#ifdef ARDUINO_ARCH_ESP32
- if (!WiFi.softAP(BOARD_VARIANT_NAME)) {
- log_e("Soft AP creation failed.");
- }
- IPAddress myIP = WiFi.softAPIP();
- Serial.print("AP IP address: ");
- Serial.println(myIP);
-#endif
-}
-
-
-void printWakeupReason()
-{
-#ifdef ARDUINO_ARCH_ESP32
- Serial.print("Reset reason:");
- esp_sleep_wakeup_cause_t wakeup_reason;
- wakeup_reason = esp_sleep_get_wakeup_cause();
- switch (wakeup_reason) {
- case ESP_SLEEP_WAKEUP_UNDEFINED:
- Serial.println(" In case of deep sleep, reset was not caused by exit from deep sleep");
- break;
- case ESP_SLEEP_WAKEUP_ALL :
- break;
- case ESP_SLEEP_WAKEUP_EXT0 :
- Serial.println("Wakeup caused by external signal using RTC_IO");
- break;
- case ESP_SLEEP_WAKEUP_EXT1 :
- Serial.println("Wakeup caused by external signal using RTC_CNTL");
- break;
- case ESP_SLEEP_WAKEUP_TIMER :
- Serial.println("Wakeup caused by timer");
- break;
- case ESP_SLEEP_WAKEUP_TOUCHPAD :
- Serial.println("Wakeup caused by touchpad");
- break;
- case ESP_SLEEP_WAKEUP_ULP :
- Serial.println("Wakeup caused by ULP program");
- break;
- default :
- Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
- break;
- }
-#endif
-}
-
-
-void getChipInfo()
-{
-#if defined(ARDUINO_ARCH_ESP32)
-
- Serial.println("-----------------------------------");
-
- printWakeupReason();
-
-
- if (psramFound()) {
- uint32_t psram = ESP.getPsramSize();
- devInfo.psramSize = psram / 1024.0 / 1024.0;
- Serial.printf("PSRAM is enable! PSRAM: %.2fMB\n", devInfo.psramSize);
- deviceOnline |= PSRAM_ONLINE;
- } else {
- Serial.println("PSRAM is disable!");
- devInfo.psramSize = 0;
- }
-
-
- Serial.print("Flash:");
- devInfo.flashSize = ESP.getFlashChipSize() / 1024.0 / 1024.0;
- devInfo.flashSpeed = ESP.getFlashChipSpeed() / 1000 / 1000;
- devInfo.chipModel = ESP.getChipModel();
- devInfo.chipModelRev = ESP.getChipRevision();
- devInfo.chipFreq = ESP.getCpuFreqMHz();
-
- Serial.print(devInfo.flashSize);
- Serial.println(" MB");
- Serial.print("Flash speed:");
- Serial.print(devInfo.flashSpeed);
- Serial.println(" M");
- Serial.print("Model:");
-
- Serial.println(devInfo.chipModel);
- Serial.print("Chip Revision:");
- Serial.println(devInfo.chipModelRev);
- Serial.print("Freq:");
- Serial.print(devInfo.chipFreq);
- Serial.println(" MHZ");
- Serial.print("SDK Ver:");
- Serial.println(ESP.getSdkVersion());
- Serial.print("DATE:");
- Serial.println(__DATE__);
- Serial.print("TIME:");
- Serial.println(__TIME__);
-
- uint8_t mac[6];
- char macStr[18] = { 0 };
- esp_efuse_mac_get_default(mac);
- sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- Serial.print("EFUSE MAC: ");
- Serial.print(macStr);
- Serial.println();
-
- Serial.println("-----------------------------------");
-
-#elif defined(ARDUINO_ARCH_STM32)
- uint32_t uid[3];
-
- uid[0] = HAL_GetUIDw0();
- uid[1] = HAL_GetUIDw1();
- uid[2] = HAL_GetUIDw2();
- Serial.print("STM UID: 0X");
- Serial.print( uid[0], HEX);
- Serial.print( uid[1], HEX);
- Serial.print( uid[2], HEX);
- Serial.println();
-#endif
-}
-
-
-void setupBoards(bool disable_u8g2 )
-{
- Serial.begin(115200);
-
- // while (!Serial);
-
- Serial.println("setupBoards");
-
- getChipInfo();
-
-#if defined(ARDUINO_ARCH_ESP32)
- SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
-#elif defined(ARDUINO_ARCH_STM32)
- SPI.setMISO(RADIO_MISO_PIN);
- SPI.setMOSI(RADIO_MOSI_PIN);
- SPI.setSCLK(RADIO_SCLK_PIN);
- SPI.begin();
-#endif
-
-
-#if defined(HAS_SDCARD)
-#if defined(SD_SHARE_SPI_BUS)
- // Share spi bus with lora , set lora cs,rst to high
- pinMode(RADIO_CS_PIN, OUTPUT);
- pinMode(RADIO_RST_PIN, OUTPUT);
- digitalWrite(RADIO_CS_PIN, HIGH);
- digitalWrite(RADIO_RST_PIN, HIGH);
-#else
- SDCardSPI.begin(SDCARD_SCLK, SDCARD_MISO, SDCARD_MOSI);
-#endif /*SD_SHARE_SPI_BUS*/
-#endif /*HAS_SDCARD*/
-
-
-
-#ifdef I2C1_SDA
- Wire1.begin(I2C1_SDA, I2C1_SCL);
-#endif
-
-#ifdef HAS_GPS
-
-#ifdef GPS_EN_PIN
- pinMode(GPS_EN_PIN, OUTPUT);
- digitalWrite(GPS_EN_PIN, HIGH);
-#endif /*GPS_EN_PIN*/
-
-#ifdef GPS_PPS_PIN
- pinMode(GPS_PPS_PIN, INPUT);
-#endif
-
-#if defined(ARDUINO_ARCH_ESP32)
- SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
-#elif defined(ARDUINO_ARCH_STM32)
- SerialGPS.setRx(GPS_RX_PIN);
- SerialGPS.setTx(GPS_TX_PIN);
- SerialGPS.begin(GPS_BAUD_RATE);
-#endif // ARDUINO_ARCH_
-#endif // HAS_GPS
-
-#if OLED_RST
- pinMode(OLED_RST, OUTPUT);
- digitalWrite(OLED_RST, HIGH); delay(20);
- digitalWrite(OLED_RST, LOW); delay(20);
- digitalWrite(OLED_RST, HIGH); delay(20);
-#endif
-
-#ifdef BOARD_LED
- /*
- * T-Beam LED defaults to low level as turn on,
- * so it needs to be forced to pull up
- * * * * */
-#if LED_ON == LOW
-#if defined(ARDUINO_ARCH_ESP32)
- gpio_hold_dis((gpio_num_t)BOARD_LED);
-#endif //ARDUINO_ARCH_ESP32
-#endif
-
- pinMode(BOARD_LED, OUTPUT);
- digitalWrite(BOARD_LED, LED_ON);
-#endif
-
-
-#ifdef GPS_RST_PIN
- pinMode(GPS_RST_PIN, OUTPUT);
- digitalWrite(GPS_RST_PIN, HIGH);
-#endif
-
-#if defined(ARDUINO_ARCH_STM32)
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
-#endif
-
-
-#ifdef RADIO_LDO_EN
- /*
- * 2W and BPF LoRa LDO enable , Control SX1262 , LNA
- * 2W and BPF Radio version must set LDO_EN to HIGH to initialize the Radio
- * */
- pinMode(RADIO_LDO_EN, OUTPUT);
- digitalWrite(RADIO_LDO_EN, HIGH);
-#endif
-
-#ifdef RADIO_CTRL
- /*
- * 2W and BPF LoRa RX TX Control
- * CTRL controls the LNA, not the PA.
- * Only when RX DATA is on, set to 1 to turn on LNA
- * When TX DATA is on, CTL is set to 0 and LNA is turned off.
- * */
- pinMode(RADIO_CTRL, OUTPUT);
- digitalWrite(RADIO_CTRL, LOW);
-#endif
-
-#ifdef RADIO_DIO2_PIN
- pinMode(RADIO_DIO2_PIN, INPUT);
-#endif
-
- beginPower();
-
- // Perform an I2C scan after power-on operation
-#ifdef I2C_SDA
- Wire.begin(I2C_SDA, I2C_SCL);
- Serial.println("==================Scan Wire ==================");
- scanDevices(&Wire);
-#endif
-
-#ifdef I2C1_SDA
- Serial.println("==================Scan Wire1==================");
- scanDevices(&Wire1);
-#endif
-
- beginSDCard();
-
-#ifdef HAS_DISPLAY
- if (!disable_u8g2) {
- beginDisplay();
- }
-#endif
-
- // scanWiFi();
-
- // beginWiFi();
-
-#ifdef FAN_CTRL
- pinMode(FAN_CTRL, OUTPUT);
-#endif
-
-#ifdef HAS_GPS
-
-#if defined(T_BEAM_S3_SUPREME) || defined(T_BEAM_1W) || defined(T_BEAM_S3_BPF)
- // T-Beam v1.2 skips L76K
- find_gps = beginGPS();
-#endif
- uint32_t baudrate[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 4800};
- if (!find_gps) {
- // Restore factory settings
- for ( int i = 0; i < sizeof(baudrate) / sizeof(baudrate[0]); ++i) {
- Serial.printf("Update baudrate : %u\n", baudrate[i]);
- SerialGPS.updateBaudRate(baudrate[i]);
- if (recoveryGPS()) {
- Serial.println("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
- gps_model = "UBlox";
- find_gps = true;
- break;
- }
- }
- } else {
- gps_model = "L76K";
- }
-
- if (find_gps) {
- deviceOnline |= GPS_ONLINE;
- }
-
-#ifdef T_BEAM_S3_SUPREME
- enable_slow_clock();
-#endif
-
-#endif
-}
-
-
-void printResult(bool radio_online)
-{
- Serial.print("Radio : ");
- Serial.println((radio_online) ? "+" : "-");
-
-#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)
-
- Serial.print("PSRAM : ");
- Serial.println((psramFound()) ? "+" : "-");
-
-#ifdef DISPLAY_MODEL
- Serial.print("Display : ");
- Serial.println(( disp) ? "+" : "-");
-#endif
-
-#ifdef HAS_SDCARD
- Serial.print("Sd Card : ");
- Serial.println((SD.cardSize() != 0) ? "+" : "-");
-#endif
-
-#ifdef HAS_PMU
- Serial.print("Power : ");
- Serial.println(( PMU ) ? "+" : "-");
-#endif
-
-#ifdef HAS_GPS
- Serial.print("GPS : ");
- Serial.println(( find_gps ) ? "+" : "-");
-#endif
-
-#ifdef DISPLAY_MODEL
- if (disp) {
-
- disp->clearBuffer();
- disp->setFont(u8g2_font_NokiaLargeBold_tf );
- uint16_t str_w = disp->getStrWidth(BOARD_VARIANT_NAME);
- disp->drawStr((disp->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME);
- disp->drawHLine(5, 21, disp->getWidth() - 5);
-
- disp->drawStr( 0, 38, "Disp:"); disp->drawStr( 45, 38, ( disp) ? "+" : "-");
-
-#ifdef HAS_SDCARD
- disp->drawStr( 0, 54, "SD :"); disp->drawStr( 45, 54, (SD.cardSize() != 0) ? "+" : "-");
-#endif
-
- disp->drawStr( 62, 38, "Radio:"); disp->drawStr( 120, 38, ( radio_online ) ? "+" : "-");
-
-#ifdef HAS_PMU
- disp->drawStr( 62, 54, "Power:"); disp->drawStr( 120, 54, ( PMU ) ? "+" : "-");
-#endif
-
- disp->sendBuffer();
-
- delay(2000);
- }
-#endif
-#endif /*DISPLAY_MODEL*/
-}
-
-
-#ifdef BOARD_LED
-static uint8_t ledState = LOW;
-static const uint32_t debounceDelay = 50;
-static uint32_t lastDebounceTime = 0;
-#endif
-
-
-#ifdef BOARD_LED
-void flashLed()
-{
- if ((millis() - lastDebounceTime) > debounceDelay) {
- ledState = !ledState;
- if (ledState) {
- digitalWrite(BOARD_LED, LED_ON);
- } else {
- digitalWrite(BOARD_LED, !LED_ON);
- }
- lastDebounceTime = millis();
- }
-}
-#endif
-
-
-void scanDevices(TwoWire *w)
-{
- uint8_t err, addr;
- int nDevices = 0;
- uint32_t start = 0;
-
- Serial.println("I2C Devices scanning");
- for (addr = 1; addr < 127; addr++) {
- start = millis();
- w->beginTransmission(addr); delay(2);
- err = w->endTransmission();
- if (err == 0) {
- nDevices++;
- switch (addr) {
- case 0x77:
- bme280_address = addr;
- Serial.printf("\tFound BME280 Sensor at address 0x%02X\n", addr);
- deviceOnline |= BME280_ONLINE;
- break;
- case 0x76:
- bme280_address = addr;
- Serial.printf("\tFound BME280 Sensor at address 0x%02X\n", addr);
- deviceOnline |= BME280_ONLINE;
- break;
- case 0x34:
- Serial.printf("\tFound AXP192/AXP2101 PMU at address 0x%02X\n", addr);
- deviceOnline |= POWERMANAGE_ONLINE;
- break;
- case 0x3C:
- case 0x3D: {
- w->beginTransmission(addr);
- w->write((uint8_t)0x00);
- w->endTransmission();
- w->requestFrom((int)addr, 1);
- uint8_t r = w->read();
- if (r == 0x80) {
- Serial.printf("\tFound QMC6310N MAG Sensor at address 0x%02X\n", addr);
- mag_address = addr;
- deviceOnline |= QMC6310N_ONLINE;
- } else {
- Serial.printf("\tFound OLED display at address 0x%02X\n", addr);
- display_address = addr;
- deviceOnline |= DISPLAY_ONLINE;
- }
- }
- break;
- case 0x51:
- Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
- deviceOnline |= PCF8563_ONLINE;
- break;
- case 0x1C:
- Serial.printf("\tFound QMC6310U MAG Sensor at address 0x%02X\n", addr);
- deviceOnline |= QMC6310U_ONLINE;
- mag_address = addr;
- break;
- default:
- Serial.print("\tI2C device found at address 0x");
- if (addr < 16) {
- Serial.print("0");
- }
- Serial.print(addr, HEX);
- Serial.println(" !");
- break;
- }
-
- } else if (err == 4) {
- Serial.print("Unknow error at address 0x");
- if (addr < 16) {
- Serial.print("0");
- }
- Serial.println(addr, HEX);
- }
- }
- if (nDevices == 0)
- Serial.println("No I2C devices found\n");
-}
-
-
-#ifdef HAS_GPS
-
-bool l76kProbe()
-{
- bool result = false;
- uint32_t startTimeout ;
- SerialGPS.write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
- delay(5);
- // Get version information
- startTimeout = millis() + 3000;
- Serial.print("Try to init L76K . Wait stop .");
- // SerialGPS.flush();
- while (SerialGPS.available()) {
- int c = SerialGPS.read();
- // Serial.write(c);
- // Serial.print(".");
- // Serial.flush();
- // SerialGPS.flush();
- if (millis() > startTimeout) {
- Serial.println("Wait L76K stop NMEA timeout!");
- return false;
- }
- };
- Serial.println();
- SerialGPS.flush();
- delay(200);
-
- SerialGPS.write("$PCAS06,0*1B\r\n");
- startTimeout = millis() + 500;
- String ver = "";
- while (!SerialGPS.available()) {
- if (millis() > startTimeout) {
- Serial.println("Get L76K timeout!");
- return false;
- }
- }
- SerialGPS.setTimeout(10);
- ver = SerialGPS.readStringUntil('\n');
- if (ver.startsWith("$GPTXT,01,01,02")) {
- Serial.println("L76K GNSS init succeeded, using L76K GNSS Module\n");
- result = true;
- }
- delay(500);
-
- // Initialize the L76K Chip, use GPS + GLONASS
- SerialGPS.write("$PCAS04,5*1C\r\n");
- delay(250);
- // only ask for RMC and GGA
- SerialGPS.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
- delay(250);
- // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
- SerialGPS.write("$PCAS11,3*1E\r\n");
- return result;
-}
-
-bool beginGPS()
-{
- SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
- bool result = false;
- for ( int i = 0; i < 3; ++i) {
- result = l76kProbe();
- if (result) {
- return result;
- }
- }
- return result;
-}
-
-
-
-static int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID)
-{
- uint16_t ubxFrameCounter = 0;
- bool ubxFrame = 0;
- uint32_t startTime = millis();
- uint16_t needRead;
-
- while (millis() - startTime < 800) {
- while (SerialGPS.available()) {
- int c = SerialGPS.read();
- switch (ubxFrameCounter) {
- case 0:
- if (c == 0xB5) {
- ubxFrameCounter++;
- }
- break;
- case 1:
- if (c == 0x62) {
- ubxFrameCounter++;
- } else {
- ubxFrameCounter = 0;
- }
- break;
- case 2:
- if (c == requestedClass) {
- ubxFrameCounter++;
- } else {
- ubxFrameCounter = 0;
- }
- break;
- case 3:
- if (c == requestedID) {
- ubxFrameCounter++;
- } else {
- ubxFrameCounter = 0;
- }
- break;
- case 4:
- needRead = c;
- ubxFrameCounter++;
- break;
- case 5:
- needRead |= (c << 8);
- ubxFrameCounter++;
- break;
- case 6:
- if (needRead >= size) {
- ubxFrameCounter = 0;
- break;
- }
- if (SerialGPS.readBytes(buffer, needRead) != needRead) {
- ubxFrameCounter = 0;
- } else {
- return needRead;
- }
- break;
-
- default:
- break;
- }
- }
- }
- return 0;
-}
-
-bool recoveryGPS()
-{
- uint8_t buffer[256];
- uint8_t cfg_clear1[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xA2};
- uint8_t cfg_clear2[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1B, 0xA1};
- uint8_t cfg_clear3[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1D, 0xB3};
- SerialGPS.write(cfg_clear1, sizeof(cfg_clear1));
-
- if (getAck(buffer, 256, 0x05, 0x01)) {
- Serial.println("Get ack successes!");
- }
- SerialGPS.write(cfg_clear2, sizeof(cfg_clear2));
- if (getAck(buffer, 256, 0x05, 0x01)) {
- Serial.println("Get ack successes!");
- }
- SerialGPS.write(cfg_clear3, sizeof(cfg_clear3));
- if (getAck(buffer, 256, 0x05, 0x01)) {
- Serial.println("Get ack successes!");
- }
- // UBX-CFG-RATE, Size 8, 'Navigation/measurement rate settings'
- uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
- SerialGPS.write(cfg_rate, sizeof(cfg_rate));
- if (getAck(buffer, 256, 0x06, 0x08)) {
- Serial.println("Get ack successes!");
- } else {
- return false;
- }
- return true;
-}
-
-#endif
-
-
-#if defined(ARDUINO_ARCH_ESP32)
-
-//NCP18XH103F03RB: https://item.szlcsc.com/14214.html
-// #define NTC_PIN 14 // NTC connection pins
-#define SERIES_RESISTOR 10000 // Series resistance value (10kΩ)
-#define B_COEFFICIENT 3950 // B value, set according to the NTC specification
-#define ROOM_TEMP 298.15 // 25°C absolute temperature (K)
-#define ROOM_TEMP_RESISTANCE 10000 // Resistance of NTC at 25°C (10kΩ)
-
-float getTempForNTC()
-{
- static float temperature = 0.0f;
-#ifdef NTC_PIN
- static uint32_t check_temperature = 0;
- if (millis() > check_temperature) {
- float voltage = analogReadMilliVolts(NTC_PIN) / 1000.0;
- float resistance = SERIES_RESISTOR * ((3.3 / voltage) - 1); // Calculate the resistance of NTC
-
- // Calculate temperature using the Steinhart-Hart equation
- temperature = (1.0 / (log(resistance / ROOM_TEMP_RESISTANCE) / B_COEFFICIENT + 1.0 / ROOM_TEMP)) - 273.15;
-
- // Serial.print("Temperature: ");
- // Serial.print(temperature);
- // Serial.println(" °C");
-
- check_temperature = millis() + 1000;
- }
-#endif
- return temperature;
-}
-
-#ifdef ENABLE_BLE
-
-#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
-#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
-
-void setupBLE()
-{
-
- uint8_t mac[6];
- char macStr[18] = { 0 };
- esp_efuse_mac_get_default(mac);
- sprintf(macStr, "%02X:%02X", mac[0], mac[1]);
-
- String dev = BOARD_VARIANT_NAME;
- dev.concat('-');
- dev.concat(macStr);
-
- Serial.print("Starting BLE:");
- Serial.println(dev);
-
- BLEDevice::init(dev.c_str());
- BLEServer *pServer = BLEDevice::createServer();
- BLEService *pService = pServer->createService(SERVICE_UUID);
- BLECharacteristic *pCharacteristic = pService->createCharacteristic(
- CHARACTERISTIC_UUID,
- BLECharacteristic::PROPERTY_READ |
- BLECharacteristic::PROPERTY_WRITE);
-
- pCharacteristic->setValue("Hello World");
- pService->start();
- // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
- BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
- pAdvertising->addServiceUUID(SERVICE_UUID);
- pAdvertising->setScanResponse(true);
- pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
- pAdvertising->setMinPreferred(0x12);
- BLEDevice::startAdvertising();
- Serial.println("Characteristic defined! Now you can read it in your phone!");
-}
-#endif
-
-#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
-
-static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
-{
- const uint32_t cal_count = 1000;
- const float factor = (1 << 19) * 1000.0f;
- uint32_t cali_val;
- for (int i = 0; i < 5; ++i) {
- cali_val = rtc_clk_cal(cal_clk, cal_count);
- }
- return cali_val;
-}
-
-static void enable_slow_clock()
-{
- rtc_clk_32k_enable(true);
- CALIBRATE_ONE(RTC_CAL_RTC_MUX);
- uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);
- if (cal_32k == 0) {
- Serial.printf("32K XTAL OSC has not started up");
- } else {
- rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
- Serial.println("Switching RTC Source to 32.768Khz succeeded, using 32K XTAL");
- CALIBRATE_ONE(RTC_CAL_RTC_MUX);
- CALIBRATE_ONE(RTC_CAL_32K_XTAL);
- }
- CALIBRATE_ONE(RTC_CAL_RTC_MUX);
- CALIBRATE_ONE(RTC_CAL_32K_XTAL);
- if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
- Serial.println("Warning: Failed to set rtc clk to 32.768Khz !!! "); return;
- }
- deviceOnline |= OSC32768_ONLINE;
-}
-
-
-void scanWiFi()
-{
- WiFi.mode(WIFI_STA);
- WiFi.disconnect();
- Serial.println("WiFi Scan start");
- // WiFi.scanNetworks will return the number of networks found.
- int n = WiFi.scanNetworks();
- Serial.println("WiFi Scan done");
- if (n == 0) {
- Serial.println("no networks found");
- } else {
- Serial.print(n);
- Serial.println(" networks found");
- Serial.println("Nr | SSID | RSSI | CH | Encryption");
- for (int i = 0; i < n; ++i) {
- // Print SSID and RSSI for each network found
- Serial.printf("%2d", i + 1);
- Serial.print(" | ");
- Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
- Serial.print(" | ");
- Serial.printf("%4ld", WiFi.RSSI(i));
- Serial.print(" | ");
- Serial.printf("%2ld", WiFi.channel(i));
- Serial.print(" | ");
- switch (WiFi.encryptionType(i)) {
- case WIFI_AUTH_OPEN: Serial.print("open"); break;
- case WIFI_AUTH_WEP: Serial.print("WEP"); break;
- case WIFI_AUTH_WPA_PSK: Serial.print("WPA"); break;
- case WIFI_AUTH_WPA2_PSK: Serial.print("WPA2"); break;
- case WIFI_AUTH_WPA_WPA2_PSK: Serial.print("WPA+WPA2"); break;
- case WIFI_AUTH_WPA2_ENTERPRISE: Serial.print("WPA2-EAP"); break;
- case WIFI_AUTH_WPA3_PSK: Serial.print("WPA3"); break;
- case WIFI_AUTH_WPA2_WPA3_PSK: Serial.print("WPA2+WPA3"); break;
- case WIFI_AUTH_WAPI_PSK: Serial.print("WAPI"); break;
- default: Serial.print("unknown");
- }
- Serial.println();
- delay(10);
- }
- }
- Serial.println("");
-
- // Delete the scan result to free memory for code below.
- WiFi.scanDelete();
-}
-
-#endif /*ARDUINO_ARCH_ESP32*/
-
diff --git a/examples/Sensor/QMC6310_CompassExample/QMC6310_CompassExample.ino b/examples/Sensor/QMC6310_CompassExample/QMC6310_CompassExample.ino
deleted file mode 100644
index 7514fc9..0000000
--- a/examples/Sensor/QMC6310_CompassExample/QMC6310_CompassExample.ino
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- *
- * @license MIT License
- *
- * Copyright (c) 2022 lewis he
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * @file QMC6310_GetDataExample.ino
- * @author Lewis He (lewishe@outlook.com)
- * @date 2022-10-16
- *
- */
-#include
-#include
-#include
-#include "SensorQMC6310.hpp"
-#include "SH1106Wire.h" //Oled display from https://github.com/ThingPulse/esp8266-oled-ssd1306
-#include "LoRaBoards.h"
-
-SH1106Wire display(0x3c, I2C_SDA, I2C_SCL);
-SensorQMC6310 qmc;
-
-int last_dx, last_dy, dx, dy, angle;
-
-const int centreX = 32;
-const int centreY = 30;
-const int radius = 22;
-
-//Compass application from https://github.com/G6EJD/ESP8266_micro_compass_HMC5883_OLED
-void arrow(int x2, int y2, int x1, int y1, int alength, int awidth, OLEDDISPLAY_COLOR color)
-{
- display.setColor(color);
- float distance;
- int dx, dy, x2o, y2o, x3, y3, x4, y4, k;
- distance = sqrt(pow((x1 - x2), 2) + pow((y1 - y2), 2));
- dx = x2 + (x1 - x2) * alength / distance;
- dy = y2 + (y1 - y2) * alength / distance;
- k = awidth / alength;
- x2o = x2 - dx;
- y2o = dy - y2;
- x3 = y2o * k + dx;
- y3 = x2o * k + dy;
- x4 = dx - y2o * k;
- y4 = dy - x2o * k;
- display.drawLine(x1, y1, x2, y2);
- display.drawLine(x1, y1, dx, dy);
- display.drawLine(x3, y3, x4, y4);
- display.drawLine(x3, y3, x2, y2);
- display.drawLine(x2, y2, x4, y4);
-}
-
-void setup()
-{
- Serial.begin(115200);
- while (!Serial);
-
- setupBoards();
-
- // For QMC6310U, the device address is 0x1C.
- // For QMC6310N, the device address is 0x3C.
- // The sensor device address is provided by the setupBoards I2C scanner.
- extern uint8_t mag_address;
- if (!qmc.begin(Wire, mag_address, I2C_SDA, I2C_SCL)) {
- Serial.println("Failed to find QMC6310 - check your wiring!");
- while (1) {
- delay(1000);
- }
- }
-
- display.init();
-
- last_dx = centreX;
- last_dy = centreY;
-
- /* Get Magnetometer chip id*/
- Serial.print("Device ID:");
- Serial.println(qmc.getChipID(), HEX);
-
- /* Config Magnetometer */
- int r = qmc.configMagnetometer(
- /*
- * Run Mode
- * MODE_SUSPEND
- * MODE_NORMAL
- * MODE_SINGLE
- * MODE_CONTINUOUS
- * * */
- SensorQMC6310::MODE_NORMAL,
- /*
- * Full Range
- * RANGE_30G
- * RANGE_12G
- * RANGE_8G
- * RANGE_2G
- * * */
- SensorQMC6310::RANGE_2G,
- /*
- * Output data rate
- * DATARATE_10HZ
- * DATARATE_50HZ
- * DATARATE_100HZ
- * DATARATE_200HZ
- * * */
- SensorQMC6310::DATARATE_100HZ,
- /*
- * Over sample Ratio1
- * OSR_8
- * OSR_4
- * OSR_2
- * OSR_1
- * * * */
- SensorQMC6310::OSR_1,
-
- /*
- * Down sample Ratio1
- * DSR_8
- * DSR_4
- * DSR_2
- * DSR_1
- * * */
- SensorQMC6310::DSR_1);
-
- if (r != 0) {
- Serial.println("Device config failed!");
- while (1)delay(1000);
- }
-
- // Print register configuration information
- qmc.dumpCtrlRegister();
-
- Serial.println("Read data now...");
-}
-
-void loop()
-{
-
- //Wiat data ready
- if (qmc.isDataReady()) {
-
- qmc.readData();
-
-
- display.drawString(29, 0, "N");
- display.drawString( 0, 28, "W");
- display.drawString(60, 28, "E");
- display.drawString(29, 53, "S");
-
- display.drawLine(1, 1, 7, 7);
- display.drawLine(62, 1, 56, 7);
- display.drawLine(1, 62, 7, 56);
- display.drawLine(56, 56, 62, 62);
-
- //Compass application from https://github.com/G6EJD/ESP8266_micro_compass_HMC5883_OLED
- float heading = atan2(qmc.getY(), qmc.getX()); // Result is in radians
- // Now add the 'Declination Angle' for you location. Declination is the variation in magnetic field at your location.
- // Find your declination here: http://www.magnetic-declination.com/
- // At my location it is : -2° 20' W, or -2.33 Degrees, which needs to be in radians so = -2.33 / 180 * PI = -0.041 West is + E is -
- // Make declination = 0 if you can't find your Declination value, the error is negible for nearly all locations
- float declination = -0.041;
- heading = heading + declination;
-
- if (heading < 0) heading += 2 * PI; // Correct for when signs are reversed.
- if (heading > 2 * PI) heading -= 2 * PI; // Correct for when heading exceeds 360-degree, especially when declination is included
- angle = int(heading * 180 / M_PI); // Convert radians to degrees for more a more usual result
- // For the screen -X = up and +X = down and -Y = left and +Y = right, so does not follow coordinate conventions
- dx = (0.7 * radius * cos((angle - 90) * 3.14 / 180)) + centreX; // calculate X position for the screen coordinates - can be confusing!
- dy = (0.7 * radius * sin((angle - 90) * 3.14 / 180)) + centreY; // calculate Y position for the screen coordinates - can be confusing!
- arrow(last_dx, last_dy, centreX, centreY, 2, 2, BLACK); // Erase last arrow
- arrow(dx, dy, centreX, centreY, 2, 2, WHITE); // Draw arrow in new position
-
- display.setColor(BLACK);
- display.fillRect(80, 50, 25, 48);
- display.setColor(WHITE);
- display.drawString(80, 50, String(angle) + "°");
- display.display();
-
- last_dx = dx;
- last_dy = dy;
-
- // for debug.
- Serial.print("GYR: ");
- Serial.print("X:");
- Serial.print(qmc.getX());
- Serial.print(" Y:");
- Serial.print(qmc.getY());
- Serial.print(" Z:");
- Serial.print(qmc.getZ());
- Serial.println(" uT");
- }
-
-
- delay(100);
-}
-
diff --git a/examples/Sensor/QMC6310_CompassExample/utilities.h b/examples/Sensor/QMC6310_CompassExample/utilities.h
deleted file mode 100644
index 08b2145..0000000
--- a/examples/Sensor/QMC6310_CompassExample/utilities.h
+++ /dev/null
@@ -1,780 +0,0 @@
-/**
- * @file utilities.h
- * @author Lewis He (lewishe@outlook.com)
- * @license MIT
- * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
- * @date 2024-05-12
- * @last-update 2025-07-07
- */
-#pragma once
-
-
-// Support board list , Macro definition below, select the board definition to be used
-// 将要使用的板子型号注释打开,只能打开一个型号,如果不明白自己买的型号是什么,请找客服核对型号
-
-/*********************************** Model definition start 型号定义起始 ***********************************/
-
-// 1. --------------T3 V1.3 -------------------------------
-// https://lilygo.cc/products/lora-v1-3
-// #define T3_V1_3_SX1276
-// #define T3_V1_3_SX1278
-
-// 2. --------------T3 V1.6.1 -------------------------------
-// https://lilygo.cc/products/lora3
-
-// #define T3_V1_6_SX1276
-// #define T3_V1_6_SX1278
-
-// 3. --------------T3 V3.0 TCXO-------------------------------
-// Product: https://lilygo.cc/products/t3-tcxo
-
-// #define T3_V3_0_SX1276_TCXO
-
-// 4. --------------T-BEAM ESP32-------------------------------
-// Product: https://lilygo.cc/products/t-beam
-
-// #define T_BEAM_SX1262
-// #define T_BEAM_SX1276
-// #define T_BEAM_SX1278
-// #define T_BEAM_LR1121
-
-// 5. --------------T-BEAM S3------------------------------
-// Product: https://lilygo.cc/products/t-beam-supreme
-
-// #define T_BEAM_S3_SUPREME_SX1262
-// #define T_BEAM_S3_SUPREME_LR1121
-
-// 6. --------------T3 S3 V1.0 or T3 S3 V1.3 -------------------
-// Product: https://lilygo.cc/products/t3s3-v1-0 , same v1.3
-// Product: https://lilygo.cc/products/t3-s3-v1-3
-
-// #define T3_S3_V1_2_SX1262
-// #define T3_S3_V1_2_SX1276
-// #define T3_S3_V1_2_SX1278
-// #define T3_S3_V1_2_SX1280
-// #define T3_S3_V1_2_SX1280_PA
-// #define T3_S3_V1_2_LR1121
-// #define T3_S3_V1_2_LR1121_PA
-
-// 7. --------------T-Motion -------------------------------------
-// Product: https://lilygo.cc/products/t-motion-s76g-stm32-lora
-
-// #define T_MOTION
-
-// --------------T3 C6 -------------------------------------
-// Product: https://lilygo.cc/products/t-lora-c6
-
-// #define T3_C6
-
-
-// --------------T-Beam BPF -------------------------------------
-// Product: https://lilygo.cc/products/t-beam-bpf
-// #define T_BEAM_S3_BPF
-
-// --------------LoRa 2W -------------------------------------
-// Product: ...
-// #define T_BEAM_1W
-
-
-
-// #define T3_V1_6_SX1276_TCXO // Production has stopped
-
-/*********************************** Model definition end 型号定义结尾 ***********************************/
-
-
-#define UNUSED_PIN (0)
-
-#if defined(T_BEAM_SX1262) || defined(T_BEAM_SX1276) || defined(T_BEAM_SX1278) || defined(T_BEAM_LR1121)
-
-
-#if defined(T_BEAM_SX1262)
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-#elif defined(T_BEAM_SX1276)
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#elif defined(T_BEAM_SX1278)
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-#elif defined(T_BEAM_LR1121)
-#ifndef USING_LR1121
-#define USING_LR1121
-#endif
-#endif // T_BEAM_SX1262
-
-
-#define GPS_RX_PIN 34
-#define GPS_TX_PIN 12
-#define BUTTON_PIN 38
-#define BUTTON_PIN_MASK GPIO_SEL_38
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define PMU_IRQ 35
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 23
-#define RADIO_DIO1_PIN 33
-// SX1276/78
-#define RADIO_DIO2_PIN 32
-// SX1262
-#define RADIO_BUSY_PIN 32
-
-// LR1121 Only
-#define RADIO_DIO9_PIN 33
-
-
-#define BOARD_LED 4
-#define LED_ON LOW
-#define LED_OFF HIGH
-
-#define BUTTON_PIN 38
-
-#define GPS_BAUD_RATE 9600
-#define HAS_GPS
-#define HAS_DISPLAY //Optional, bring your own board, no OLED !!
-#define HAS_PMU
-
-#define PMU_WIRE_PORT Wire
-#define BOARD_VARIANT_NAME "T-Beam"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-
-#elif defined(T3_V1_3_SX1276) || defined(T3_V1_3_SX1278)
-
-
-#if defined(T3_V1_3_SX1276)
-
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-
-#elif defined(T3_V1_3_SX1278)
-
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-
-#endif // T3_V1_3_SX1276
-
-
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 14
-#define RADIO_DIO1_PIN 33
-
-// SX1276/78
-#define RADIO_DIO2_PIN 32
-// SX1262
-#define RADIO_BUSY_PIN 32
-
-
-#define ADC_PIN 35
-#define HAS_DISPLAY
-#define BOARD_VARIANT_NAME "T3 V1.3"
-
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_V1_6_SX1276) || defined(T3_V1_6_SX1278)
-
-
-#if defined(T3_V1_6_SX1276)
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#elif defined(T3_V1_6_SX1278)
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-#endif // T3_V1_6_SX1276
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 23
-#define RADIO_DIO1_PIN 33
-// SX1276/78
-#define RADIO_DIO2_PIN 32
-// SX1262
-#define RADIO_BUSY_PIN 32
-
-#define SDCARD_MOSI 15
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 25
-#define LED_ON HIGH
-
-#define ADC_PIN 35
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3 V1.6"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_V1_6_SX1276_TCXO)
-
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 23
-#define RADIO_DIO1_PIN -1//33
-/*
-* In the T3 V1.6.1 TCXO version, Radio DIO1 is connected to Radio’s
-* internal temperature-compensated crystal oscillator enable
-* */
-// TCXO pin must be set to HIGH before enabling Radio
-#define RADIO_TCXO_ENABLE 33
-#define RADIO_BUSY_PIN 32
-
-#define SDCARD_MOSI 15
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 25
-#define LED_ON HIGH
-
-#define ADC_PIN 35
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3 V1.6 TCXO"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_V3_0) || defined(T3_V3_0_SX1276_TCXO)
-
-#ifdef T3_V3_0_SX1276_TCXO
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#endif
-
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST 4
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_RST_PIN 23
-
-// TCXO pin must be set to HIGH before enabling Radio
-#define RADIO_TCXO_ENABLE 12 //only sx1276 tcxo version
-#define RADIO_BUSY_PIN 32
-
-
-#if defined(USING_SX1262)
-
-#define RADIO_DIO1_PIN 26
-#define RADIO_BUSY_PIN 32
-
-#elif defined(USING_SX1276) || defined(USING_SX1278)
-//!SX1276/78 module only
-
-#define RADIO_DIO0_PIN 26
-#define RADIO_DIO1_PIN 32
-
-#elif defined(USING_LR1121)
-
-#define RADIO_DIO9_PIN 26 //LR1121 DIO9
-#define RADIO_BUSY_PIN 32 //LR1121 BUSY
-
-#endif
-
-#define SDCARD_MOSI 15
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 25
-#define LED_ON HIGH
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3 V3.0"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-#define BUTTON_PIN 0
-#define ADC_PIN 35
-
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262) || \
- defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276) || \
- defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278) || \
- defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280) || \
- defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA) || \
- defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121) || \
- defined(T3_S3_V1_2_LR1121_PA) || defined(ARDUINO_LILYGO_T3S3_LR1121PA)
-
-
-#if defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262)
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-#elif defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276)
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#elif defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278)
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-#elif defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280)
-#ifndef USING_SX1280
-#define USING_SX1280
-#endif
-#elif defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA)
-#ifndef USING_SX1280PA
-#define USING_SX1280PA
-#endif
-#elif defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121)
-#ifndef USING_LR1121
-#define USING_LR1121
-#endif
-#elif defined(T3_S3_V1_2_LR1121_PA) || defined(ARDUINO_LILYGO_T3S3_LR1121PA)
-#ifndef USING_LR1121PA
-#define USING_LR1121PA
-#endif
-#endif // T3_S3_V1_2_SX1262
-
-
-#define I2C_SDA 18
-#define I2C_SCL 17
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 3
-#define RADIO_MOSI_PIN 6
-#define RADIO_CS_PIN 7
-
-#define SDCARD_MOSI 11
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 37
-#define LED_ON HIGH
-
-#define BUTTON_PIN 0
-#define ADC_PIN 1
-
-#define RADIO_RST_PIN 8
-
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#if defined(USING_SX1262)
-
-#define RADIO_DIO1_PIN 33
-#define RADIO_BUSY_PIN 34
-
-#elif defined(USING_SX1276) || defined(USING_SX1278)
-//!SX1276/78 module only
-#define RADIO_BUSY_PIN 33 //DIO1
-
-#define RADIO_DIO0_PIN 9
-#define RADIO_DIO1_PIN 33
-#define RADIO_DIO2_PIN 34
-#define RADIO_DIO3_PIN 21
-#define RADIO_DIO4_PIN 10
-#define RADIO_DIO5_PIN 36
-
-#elif defined(USING_SX1280)
-
-#define RADIO_DIO1_PIN 9 //SX1280 DIO1 = IO9
-#define RADIO_BUSY_PIN 36 //SX1280 BUSY = IO36
-
-#elif defined(USING_SX1280PA)
-
-#define RADIO_DIO1_PIN 9 //SX1280 DIO1 = IO9
-#define RADIO_BUSY_PIN 36 //SX1280 BUSY = IO36
-#define RADIO_RX_PIN 21
-#define RADIO_TX_PIN 10
-
-
-#elif defined(USING_LR1121)
-
-#define RADIO_DIO9_PIN 36 //LR1121 DIO9 = IO36
-#define RADIO_BUSY_PIN 34 //LR1121 BUSY = IO34
-
-#define LILYGO_RADIO_2G4_TX_POWER_LIMIT 13 //LR1121 2.4G TX Power Limit
-
-#elif defined(USING_LR1121PA)
-
-#define RADIO_DIO9_PIN 36 //LR1121 DIO9 = IO36
-#define RADIO_BUSY_PIN 34 //LR1121 BUSY = IO34
-
-#define LILYGO_RADIO_2G4_TX_POWER_LIMIT 0 //LR1121 2.4G TX Power Limit
-#define USING_LR1121
-
-#endif
-
-#define BUTTON_PIN 0
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3-S3-V1.X"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-
-#elif defined(T_BEAM_S3_SUPREME_SX1262) || defined(T_BEAM_S3_SUPREME_LR1121)
-
-#ifndef T_BEAM_S3_SUPREME
-#define T_BEAM_S3_SUPREME
-#endif
-
-#if defined(T_BEAM_S3_SUPREME_SX1262)
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-#elif defined(T_BEAM_S3_SUPREME_LR1121)
-#ifndef USING_LR1121
-#define USING_LR1121
-#endif
-#endif
-
-#define I2C_SDA (17)
-#define I2C_SCL (18)
-
-#define I2C1_SDA (42)
-#define I2C1_SCL (41)
-#define PMU_IRQ (40)
-
-#define GPS_RX_PIN (9)
-#define GPS_TX_PIN (8)
-#define GPS_EN_PIN (7)
-#define GPS_PPS_PIN (6)
-
-#define BUTTON_PIN (0)
-#define BUTTON_PIN_MASK (GPIO_SEL_0)
-#define BUTTON_COUNT (1)
-#define BUTTON_ARRAY {BUTTON_PIN}
-
-#define RADIO_SCLK_PIN (12)
-#define RADIO_MISO_PIN (13)
-#define RADIO_MOSI_PIN (11)
-#define RADIO_CS_PIN (10)
-#define RADIO_DIO0_PIN (-1)
-#define RADIO_RST_PIN (5)
-#define RADIO_DIO1_PIN (1)
-#define RADIO_BUSY_PIN (4)
-
-// LR1121 Version
-#define RADIO_DIO9_PIN (1)
-
-#define SPI_MOSI (35)
-#define SPI_SCK (36)
-#define SPI_MISO (37)
-#define SPI_CS (47)
-#define IMU_CS (34)
-#define IMU_INT (33)
-
-#define SDCARD_MOSI SPI_MOSI
-#define SDCARD_MISO SPI_MISO
-#define SDCARD_SCLK SPI_SCK
-#define SDCARD_CS SPI_CS
-
-#define RTC_INT (14)
-
-#define GPS_BAUD_RATE (9600)
-
-#define HAS_SDCARD
-#define HAS_GPS
-#define HAS_DISPLAY
-#define HAS_PMU
-
-#define __HAS_SPI1__
-#define HAS_SENSOR
-
-#define PMU_WIRE_PORT Wire1
-#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
-#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "T-Beam S3"
-
-#elif defined(T_MOTION_S76G)
-
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-
-
-#define RADIO_SCLK_PIN PB13
-#define RADIO_MISO_PIN PB14
-#define RADIO_MOSI_PIN PB15
-#define RADIO_CS_PIN PB12
-#define RADIO_RST_PIN PB10
-
-#define RADIO_DIO0_PIN PB11
-#define RADIO_DIO1_PIN PC13
-#define RADIO_DIO2_PIN PB9
-#define RADIO_DIO3_PIN PB4
-#define RADIO_DIO4_PIN PB3
-#define RADIO_DIO5_PIN PA15
-
-#undef RADIO_BUSY_PIN
-#undef RADIO_DIO1_PIN
-#define RADIO_BUSY_PIN PC13 //DIO1
-#define RADIO_DIO1_PIN PB11 //DIO0
-
-#define RADIO_SWITCH_PIN PA1 //1:Rx, 0:Tx
-
-#define GPS_EN_PIN PC6
-#define GPS_RST_PIN PB2
-#define GPS_RX_PIN PC11
-#define GPS_TX_PIN PC10
-#define GPS_ENABLE_PIN PC6
-#define GPS_BAUD_RATE 115200
-#define GPS_PPS_PIN PB5
-
-#define UART_RX_PIN PA10
-#define UART_TX_PIN PA9
-
-#define I2C_SCL PB6
-#define I2C_SDA PB7
-
-#define BOARD_VARIANT_NAME "T-Motion S76G"
-
-#define HAS_GPS
-
-#elif defined(T3_C6)
-
-
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-
-
-#define RADIO_SCLK_PIN 6
-#define RADIO_MISO_PIN 1
-#define RADIO_MOSI_PIN 0
-#define RADIO_CS_PIN 18
-#define RADIO_DIO1_PIN 23
-#define RADIO_BUSY_PIN 22
-#define RADIO_RST_PIN 21
-
-#define I2C_SDA 8
-#define I2C_SCL 9
-
-#define BOARD_LED 7
-#define LED_ON HIGH
-#define RADIO_RX_PIN 15
-#define RADIO_TX_PIN 14
-
-
-#define BOARD_VARIANT_NAME "T3-C6"
-
-#define USING_DIO2_AS_RF_SWITCH
-
-
-#elif defined(T_BEAM_S3_BPF)
-
-
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-
-#define I2C_SDA (8)
-#define I2C_SCL (9)
-
-#define PMU_IRQ (4)
-
-#define GPS_RX_PIN (5)
-#define GPS_TX_PIN (6)
-#define GPS_PPS_PIN (7)
-
-#define BUTTON_PIN (0)
-#define BUTTON2_PIN (3) /*BUTTON 2 = GPIO3*/
-#define BUTTON_PIN_MASK GPIO_SEL_0 /*BUTTON 1 = GPIO0*/
-#define BUTTON_COUNT (2)
-#define BUTTON_ARRAY {BUTTON_PIN, BUTTON2_PIN /*BUTTON 2 = GPIO3*/}
-
-#define RADIO_SCLK_PIN (12)//(41)
-#define RADIO_MISO_PIN (13)//(42)
-#define RADIO_MOSI_PIN (11)//(2)
-#define RADIO_CS_PIN (1)
-#define RADIO_RST_PIN (18)
-
-#define RADIO_DIO0_PIN (14)
-#define RADIO_DIO1_PIN (21)
-
-// #define RADIO_TCXO_ENABLE (17)
-#define RADIO_LDO_EN (16)
-#define RADIO_CTRL (39)
-
-#define SPI_MOSI (11)
-#define SPI_SCK (12)
-#define SPI_MISO (13)
-#define SPI_CS (10)
-
-#define SDCARD_MOSI SPI_MOSI
-#define SDCARD_MISO SPI_MISO
-#define SDCARD_SCLK SPI_SCK
-#define SDCARD_CS SPI_CS
-
-
-#define GPS_BAUD_RATE 9600
-
-#define HAS_SDCARD
-#define HAS_GPS
-#define HAS_DISPLAY
-#define HAS_PMU
-#define SD_SHARE_SPI_BUS
-
-#define PMU_WIRE_PORT Wire
-#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
-#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "T-Beam BPF"
-
-
-#elif defined(T_BEAM_1W)
-
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-
-#define I2C_SDA (8)
-#define I2C_SCL (9)
-
-#define GPS_RX_PIN (5)
-#define GPS_TX_PIN (6)
-#define GPS_PPS_PIN (7)
-#define GPS_EN_PIN (16)
-
-#define BUTTON_PIN (0) /*BUTTON 1 = GPIO0*/
-#define BUTTON2_PIN (17) /*BUTTON 2 = GPIO17*/
-
-#define BUTTON_PIN_MASK GPIO_SEL_0
-#define BUTTON_COUNT (2)
-#define BUTTON_ARRAY {BUTTON_PIN,BUTTON2_PIN/*BUTTON 2 = GPIO3*/}
-
-#define SPI_MOSI (11)
-#define SPI_SCK (13)
-#define SPI_MISO (12)
-#define SPI_CS (10)
-
-#define SDCARD_CS SPI_CS
-
-#define RADIO_SCLK_PIN (SPI_SCK)
-#define RADIO_MISO_PIN (SPI_MISO)
-#define RADIO_MOSI_PIN (SPI_MOSI)
-
-#define RADIO_CS_PIN (15)
-#define RADIO_RST_PIN (3)
-#define RADIO_LDO_EN (40)
-#define RADIO_CTRL (21)
-#define RADIO_DIO1_PIN (1)
-#define RADIO_BUSY_PIN (38)
-
-#define BOARD_LED 18
-#define LED_ON HIGH
-#define LED_OFF LOW
-
-
-#define NTC_PIN (14)
-#define FAN_CTRL (41)
-#define ADC_PIN (4)
-
-#define BAT_ADC_PULLUP_RES (300000.0)
-#define BAT_ADC_PULLDOWN_RES (150000.0)
-#define BAT_MAX_VOLTAGE (7.4)
-#define BAT_VOL_COMPENSATION (0.25)
-#define GPS_SLEEP_HOLD_ON_LOW
-
-#define GPS_BAUD_RATE 9600
-
-#define HAS_SDCARD
-#define HAS_GPS
-#define HAS_DISPLAY
-#define SD_SHARE_SPI_BUS // SD-CARD AND RADIO SHARE SPI BUS
-#define __HAS_SPI1__
-
-#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
-#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "LoRa 2W"
-
-#else
-#error "When using it for the first time, please define the board model in 首次使用时,请在 文件最上方定义板卡模型"
-#endif
-
-
-
-
-
-#if defined(USING_SX1262)
-#define RADIO_TYPE_STR "SX1262"
-#elif defined(USING_SX1276)
-#define RADIO_TYPE_STR "SX1276"
-#elif defined(USING_SX1278)
-#define RADIO_TYPE_STR "SX1278"
-#elif defined(USING_LR1121)
-#define RADIO_TYPE_STR "LR1121"
-#elif defined(USING_SX1280)
-#define RADIO_TYPE_STR "SX1280"
-#elif defined(USING_SX1280PA)
-#define RADIO_TYPE_STR "SX1280PA"
-#endif
-
-
-
-
-
diff --git a/examples/Sensor/QMC6310_GetDataExample/LoRaBoards.cpp b/examples/Sensor/QMC6310_GetDataExample/LoRaBoards.cpp
deleted file mode 100644
index 8acfe74..0000000
--- a/examples/Sensor/QMC6310_GetDataExample/LoRaBoards.cpp
+++ /dev/null
@@ -1,1353 +0,0 @@
-/**
- * @file boards.cpp
- * @author Lewis He (lewishe@outlook.com)
- * @license MIT
- * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
- * @date 2024-04-24
- * @last-update 2025-05-26
- *
- */
-
-#include "LoRaBoards.h"
-
-#include "soc/rtc.h"
-#ifdef ENABLE_BLE
-#include
-#include
-#include
-#endif
-
-#if defined(HAS_SDCARD) && !defined(SD_SHARE_SPI_BUS)
-SPIClass SDCardSPI(HSPI);
-#endif
-
-
-#if defined(ARDUINO_ARCH_STM32)
-HardwareSerial SerialGPS(GPS_RX_PIN, GPS_TX_PIN);
-#endif
-
-#if defined(ARDUINO_ARCH_ESP32)
-#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,0,0)
-#include "hal/gpio_hal.h"
-#endif
-#include "driver/gpio.h"
-#endif //ARDUINO_ARCH_ESP32
-
-#ifdef DISPLAY_MODEL
-U8G2 *disp = NULL;
-#endif
-
-
-static DevInfo_t devInfo;
-
-#ifdef HAS_GPS
-static bool find_gps = false;
-String gps_model = "None";
-#endif
-
-// I2S Devices default address
-uint8_t bme280_address = 0x77; // It might be 0x76
-uint8_t mag_address = 0x1C; // QMC6310U=0x1C QMC6310N=0x3C
-uint8_t display_address = 0x3c; // It might be 0x3D
-
-uint32_t deviceOnline = 0x00;
-
-static void enable_slow_clock();
-
-#ifdef HAS_PMU
-XPowersLibInterface *PMU = NULL;
-bool pmuInterrupt;
-
-static void setPmuFlag()
-{
- pmuInterrupt = true;
-}
-bool beginPower()
-{
- if (!PMU) {
- PMU = new XPowersAXP2101(PMU_WIRE_PORT);
- if (!PMU->init()) {
- Serial.println("Warning: Failed to find AXP2101 power management");
- delete PMU;
- PMU = NULL;
- } else {
- Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU");
- }
- }
-
- if (!PMU) {
- PMU = new XPowersAXP192(PMU_WIRE_PORT);
- if (!PMU->init()) {
- Serial.println("Warning: Failed to find AXP192 power management");
- delete PMU;
- PMU = NULL;
- } else {
- Serial.println("AXP192 PMU init succeeded, using AXP192 PMU");
- }
- }
-
- if (!PMU) {
- return false;
- }
-
- deviceOnline |= POWERMANAGE_ONLINE;
-
- PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
-
- pinMode(PMU_IRQ, INPUT_PULLUP);
- attachInterrupt(PMU_IRQ, setPmuFlag, FALLING);
-
- if (PMU->getChipModel() == XPOWERS_AXP192) {
-
- PMU->setProtectedChannel(XPOWERS_DCDC3);
-
- // lora
- PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
- // gps
- PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
- // oled
- PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
-
- PMU->enablePowerOutput(XPOWERS_LDO2);
- PMU->enablePowerOutput(XPOWERS_LDO3);
-
- //protected oled power source
- PMU->setProtectedChannel(XPOWERS_DCDC1);
- //protected esp32 power source
- PMU->setProtectedChannel(XPOWERS_DCDC3);
- // enable oled power
- PMU->enablePowerOutput(XPOWERS_DCDC1);
-
- //disable not use channel
- PMU->disablePowerOutput(XPOWERS_DCDC2);
-
- PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
-
- PMU->enableIRQ(XPOWERS_AXP192_VBUS_REMOVE_IRQ |
- XPOWERS_AXP192_VBUS_INSERT_IRQ |
- XPOWERS_AXP192_BAT_CHG_DONE_IRQ |
- XPOWERS_AXP192_BAT_CHG_START_IRQ |
- XPOWERS_AXP192_BAT_REMOVE_IRQ |
- XPOWERS_AXP192_BAT_INSERT_IRQ |
- XPOWERS_AXP192_PKEY_SHORT_IRQ
- );
-
- } else if (PMU->getChipModel() == XPOWERS_AXP2101) {
-
-#if defined(CONFIG_IDF_TARGET_ESP32)
- //Unuse power channel
- PMU->disablePowerOutput(XPOWERS_DCDC2);
- PMU->disablePowerOutput(XPOWERS_DCDC3);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_ALDO1);
- PMU->disablePowerOutput(XPOWERS_ALDO4);
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO2);
- PMU->disablePowerOutput(XPOWERS_DLDO1);
- PMU->disablePowerOutput(XPOWERS_DLDO2);
- PMU->disablePowerOutput(XPOWERS_CPULDO);
-
- // GNSS RTC PowerVDD 3300mV
- PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
- PMU->enablePowerOutput(XPOWERS_VBACKUP);
-
- //ESP32 VDD 3300mV
- // ! No need to set, automatically open , Don't close it
- // PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
- // PMU->setProtectedChannel(XPOWERS_DCDC1);
- PMU->setProtectedChannel(XPOWERS_DCDC1);
-
- // LoRa VDD 3300mV
- PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO2);
-
- //GNSS VDD 3300mV
- PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO3);
-
-#endif /*CONFIG_IDF_TARGET_ESP32*/
-
-
-#if defined(T_BEAM_S3_SUPREME)
-
- //t-beam m.2 inface
- //gps
- PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO4);
-
- // lora
- PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO3);
-
- // In order to avoid bus occupation, during initialization, the SD card and QMC sensor are powered off and restarted
- if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()) {
- Serial.println("Power off and restart ALDO BLDO..");
- PMU->disablePowerOutput(XPOWERS_ALDO1);
- PMU->disablePowerOutput(XPOWERS_ALDO2);
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- delay(250);
- }
-
- // Sensor
- PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO1);
-
- PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO2);
-
- //Sdcard
-
- PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
- PMU->enablePowerOutput(XPOWERS_BLDO1);
-
- PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_BLDO2);
-
- //face m.2
- PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC3);
-
- PMU->setPowerChannelVoltage(XPOWERS_DCDC4, XPOWERS_AXP2101_DCDC4_VOL2_MAX);
- PMU->enablePowerOutput(XPOWERS_DCDC4);
-
- PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC5);
-
-
- //not use channel
- PMU->disablePowerOutput(XPOWERS_DCDC2);
- // PMU->disablePowerOutput(XPOWERS_DCDC4);
- // PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_DLDO1);
- PMU->disablePowerOutput(XPOWERS_DLDO2);
- PMU->disablePowerOutput(XPOWERS_VBACKUP);
-
-
-#elif defined(T_BEAM_S3_BPF)
-
- //gps
- PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO4);
-
- //Sdcard
- PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO2);
-
- // Extern Power source
- PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC3);
-
- PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300);
- PMU->enablePowerOutput(XPOWERS_DCDC5);
-
- PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
- PMU->enablePowerOutput(XPOWERS_ALDO1);
-
- //not use channel
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO2);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC2);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_DLDO1);
- PMU->disablePowerOutput(XPOWERS_DLDO2);
- PMU->disablePowerOutput(XPOWERS_VBACKUP);
-
-
-#endif
-
- // Set constant current charge current limit
- PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
-
- // Set charge cut-off voltage
- PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
-
- // Disable all interrupts
- PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
- // Clear all interrupt flags
- PMU->clearIrqStatus();
- // Enable the required interrupt function
- PMU->enableIRQ(
- XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | //BATTERY
- XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | //VBUS
- XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | //POWER KEY
- XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ //CHARGE
- // XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ | XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | //POWER KEY
- );
-
- }
-
- PMU->enableSystemVoltageMeasure();
- PMU->enableVbusVoltageMeasure();
- PMU->enableBattVoltageMeasure();
-
- Serial.printf("=========================================\n");
- if (PMU->isChannelAvailable(XPOWERS_DCDC1)) {
- Serial.printf("DC1 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC2)) {
- Serial.printf("DC2 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC3)) {
- Serial.printf("DC3 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC4)) {
- Serial.printf("DC4 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
- }
- if (PMU->isChannelAvailable(XPOWERS_DCDC5)) {
- Serial.printf("DC5 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC5) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC5));
- }
- if (PMU->isChannelAvailable(XPOWERS_LDO2)) {
- Serial.printf("LDO2 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO2));
- }
- if (PMU->isChannelAvailable(XPOWERS_LDO3)) {
- Serial.printf("LDO3 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO3));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO1)) {
- Serial.printf("ALDO1: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO2)) {
- Serial.printf("ALDO2: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO3)) {
- Serial.printf("ALDO3: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
- }
- if (PMU->isChannelAvailable(XPOWERS_ALDO4)) {
- Serial.printf("ALDO4: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
- }
- if (PMU->isChannelAvailable(XPOWERS_BLDO1)) {
- Serial.printf("BLDO1: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
- }
- if (PMU->isChannelAvailable(XPOWERS_BLDO2)) {
- Serial.printf("BLDO2: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
- }
-
-
- // Set the time of pressing the button to turn off
- PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
- uint8_t opt = PMU->getPowerKeyPressOffTime();
- Serial.print("PowerKeyPressOffTime:");
- switch (opt) {
- case XPOWERS_POWEROFF_4S: Serial.println("4 Second");
- break;
- case XPOWERS_POWEROFF_6S: Serial.println("6 Second");
- break;
- case XPOWERS_POWEROFF_8S: Serial.println("8 Second");
- break;
- case XPOWERS_POWEROFF_10S: Serial.println("10 Second");
- break;
- default:
- break;
- }
-
- Serial.printf("=========================================\n");
-
- return true;
-}
-
-void disablePeripherals()
-{
-
- if (!PMU)return;
-
- PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
- // Disable the PMU measurement section
- PMU->disableSystemVoltageMeasure();
- PMU->disableVbusVoltageMeasure();
- PMU->disableBattVoltageMeasure();
- PMU->disableTemperatureMeasure();
- PMU->disableBattDetection();
-
-#if defined(T_BEAM_S3_BPF)
- PMU->disablePowerOutput(XPOWERS_ALDO4); //gps
- PMU->disablePowerOutput(XPOWERS_ALDO2); //Sdcard
- PMU->disablePowerOutput(XPOWERS_DCDC3); // Extern Power source
- PMU->disablePowerOutput(XPOWERS_DCDC5);
- PMU->disablePowerOutput(XPOWERS_ALDO1);
-#else
-
- if (PMU->getChipModel() == XPOWERS_AXP2101) {
-
- // Disable all PMU interrupts
- PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
- // Clear the PMU interrupt status before sleeping, otherwise the sleep current will increase
- PMU->clearIrqStatus();
- // GNSS RTC Power , Turning off GPS backup voltage and current can further reduce ~ 100 uA
- PMU->disablePowerOutput(XPOWERS_VBACKUP);
- // LoRa VDD
- PMU->disablePowerOutput(XPOWERS_ALDO2);
- // GNSS VDD
- PMU->disablePowerOutput(XPOWERS_ALDO3);
-
-#if defined(T_BEAM_S3_SUPREME)
- PMU->disablePowerOutput(XPOWERS_ALDO4);
- PMU->disablePowerOutput(XPOWERS_ALDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO1);
- PMU->disablePowerOutput(XPOWERS_BLDO2);
- PMU->disablePowerOutput(XPOWERS_DCDC3);
- PMU->disablePowerOutput(XPOWERS_DCDC4);
- PMU->disablePowerOutput(XPOWERS_DCDC5);
-#endif
-
- } else if (PMU->getChipModel() == XPOWERS_AXP192) {
-
- // Disable all PMU interrupts
- PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
- // Clear the PMU interrupt status before sleeping, otherwise the sleep current will increase
- PMU->clearIrqStatus();
- // LoRa VDD
- PMU->disablePowerOutput(XPOWERS_LDO2);
- // GNSS VDD
- PMU->disablePowerOutput(XPOWERS_LDO3);
-
-
- }
-#endif
-}
-
-void loopPMU(void (*pressed_cb)(void))
-{
- if (!PMU) {
- return;
- }
- if (!pmuInterrupt) {
- return;
- }
-
- pmuInterrupt = false;
- // Get PMU Interrupt Status Register
- uint32_t status = PMU->getIrqStatus();
- Serial.print("STATUS => HEX:");
- Serial.print(status, HEX);
- Serial.print(" BIN:");
- Serial.println(status, BIN);
-
- if (PMU->isVbusInsertIrq()) {
- Serial.println("isVbusInsert");
- }
- if (PMU->isVbusRemoveIrq()) {
- Serial.println("isVbusRemove");
- }
- if (PMU->isBatInsertIrq()) {
- Serial.println("isBatInsert");
- }
- if (PMU->isBatRemoveIrq()) {
- Serial.println("isBatRemove");
- }
- if (PMU->isPekeyShortPressIrq()) {
- Serial.println("isPekeyShortPress");
- if (pressed_cb) {
- pressed_cb();
- }
- }
- if (PMU->isPekeyLongPressIrq()) {
- Serial.println("isPekeyLongPress");
- }
- if (PMU->isBatChargeDoneIrq()) {
- Serial.println("isBatChargeDone");
- }
- if (PMU->isBatChargeStartIrq()) {
- Serial.println("isBatChargeStart");
- }
- // Clear PMU Interrupt Status Register
- PMU->clearIrqStatus();
-}
-#endif
-
-#ifdef DISPLAY_MODEL
-bool beginDisplay()
-{
- Wire.beginTransmission(display_address);
- if (Wire.endTransmission() == 0) {
- disp = new DISPLAY_MODEL(U8G2_R0, U8X8_PIN_NONE);
- Serial.printf("Find Display model at 0x%X address\n", display_address);
- disp->begin();
- disp->clearBuffer();
- disp->setFont(u8g2_font_inb19_mr);
- disp->drawStr(0, 30, "LilyGo");
- disp->drawHLine(2, 35, 47);
- disp->drawHLine(3, 36, 47);
- disp->drawVLine(45, 32, 12);
- disp->drawVLine(46, 33, 12);
- disp->setFont(u8g2_font_inb19_mf);
- disp->drawStr(58, 60, "LoRa");
- disp->sendBuffer();
- disp->setFont(u8g2_font_fur11_tf);
- delay(3000);
- return true;
- }
-
- Serial.printf("Warning: Failed to find Display at 0x%0X address\n", display_address);
- return false;
-}
-#endif
-
-#ifdef HAS_SDCARD
-bool writeFile(const char *path, const char *buffer)
-{
- bool rlst = false;
- File file = SD.open(path, FILE_WRITE);
- if (!file) {
- Serial.println("Failed to open file for writing");
- return false;
- }
- if (file.print(buffer)) {
- Serial.println("File written");
- rlst = true;
- } else {
- Serial.println("Write failed");
- rlst = false;
- }
- file.close();
- return rlst;
-}
-
-
-bool readFile(const char *path, uint8_t *buffer, size_t size)
-{
- File file = SD.open(path, FILE_READ);
- if (!file) {
- Serial.println("Failed to open file for reading");
- return false;
- }
- file.read(buffer, size);
- file.close();
- return false;
-}
-
-bool testSDWriteAndRead()
-{
- const char *path = "/test_sd.txt";
- const char *message = "This is a string for reading and writing SD card.";
- uint8_t buffer[128] = {0};
-
- if (!writeFile(path, message)) {
- Serial.println("SD Text write failed");
- return false;
- }
- delay(100);
-
- readFile(path, buffer, 128);
-
- if (memcmp(buffer, message, strlen(message)) != 0) {
- Serial.println("SD verification failed");
- return false;
- }
- Serial.println("SD verification successful");
- return true;
-}
-#endif /*HAS_SDCARD*/
-
-#ifdef HAS_SDCARD
-bool beginSDCard()
-{
-#if defined(HAS_SDCARD) && defined(SD_SHARE_SPI_BUS)
- bool rlst = SD.begin(SDCARD_CS);
-#else
- bool rlst = SD.begin(SDCARD_CS, SDCardSPI);
-#endif
-
- if (rlst) {
- uint32_t cardSize = SD.cardSize() / (1024 * 1024);
- Serial.print("Sd Card init succeeded, The current available capacity is ");
- Serial.print(cardSize / 1024.0);
- Serial.println(" GB");
- deviceOnline |= SDCARD_ONLINE;
- return testSDWriteAndRead();
- } else {
- Serial.println("Warning: Failed to init Sd Card");
- }
- return false;
-}
-#endif /*HAS_SDCARD*/
-
-void beginWiFi()
-{
-#ifdef ARDUINO_ARCH_ESP32
- if (!WiFi.softAP(BOARD_VARIANT_NAME)) {
- log_e("Soft AP creation failed.");
- }
- IPAddress myIP = WiFi.softAPIP();
- Serial.print("AP IP address: ");
- Serial.println(myIP);
-#endif
-}
-
-
-void printWakeupReason()
-{
-#ifdef ARDUINO_ARCH_ESP32
- Serial.print("Reset reason:");
- esp_sleep_wakeup_cause_t wakeup_reason;
- wakeup_reason = esp_sleep_get_wakeup_cause();
- switch (wakeup_reason) {
- case ESP_SLEEP_WAKEUP_UNDEFINED:
- Serial.println(" In case of deep sleep, reset was not caused by exit from deep sleep");
- break;
- case ESP_SLEEP_WAKEUP_ALL :
- break;
- case ESP_SLEEP_WAKEUP_EXT0 :
- Serial.println("Wakeup caused by external signal using RTC_IO");
- break;
- case ESP_SLEEP_WAKEUP_EXT1 :
- Serial.println("Wakeup caused by external signal using RTC_CNTL");
- break;
- case ESP_SLEEP_WAKEUP_TIMER :
- Serial.println("Wakeup caused by timer");
- break;
- case ESP_SLEEP_WAKEUP_TOUCHPAD :
- Serial.println("Wakeup caused by touchpad");
- break;
- case ESP_SLEEP_WAKEUP_ULP :
- Serial.println("Wakeup caused by ULP program");
- break;
- default :
- Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
- break;
- }
-#endif
-}
-
-
-void getChipInfo()
-{
-#if defined(ARDUINO_ARCH_ESP32)
-
- Serial.println("-----------------------------------");
-
- printWakeupReason();
-
-
- if (psramFound()) {
- uint32_t psram = ESP.getPsramSize();
- devInfo.psramSize = psram / 1024.0 / 1024.0;
- Serial.printf("PSRAM is enable! PSRAM: %.2fMB\n", devInfo.psramSize);
- deviceOnline |= PSRAM_ONLINE;
- } else {
- Serial.println("PSRAM is disable!");
- devInfo.psramSize = 0;
- }
-
-
- Serial.print("Flash:");
- devInfo.flashSize = ESP.getFlashChipSize() / 1024.0 / 1024.0;
- devInfo.flashSpeed = ESP.getFlashChipSpeed() / 1000 / 1000;
- devInfo.chipModel = ESP.getChipModel();
- devInfo.chipModelRev = ESP.getChipRevision();
- devInfo.chipFreq = ESP.getCpuFreqMHz();
-
- Serial.print(devInfo.flashSize);
- Serial.println(" MB");
- Serial.print("Flash speed:");
- Serial.print(devInfo.flashSpeed);
- Serial.println(" M");
- Serial.print("Model:");
-
- Serial.println(devInfo.chipModel);
- Serial.print("Chip Revision:");
- Serial.println(devInfo.chipModelRev);
- Serial.print("Freq:");
- Serial.print(devInfo.chipFreq);
- Serial.println(" MHZ");
- Serial.print("SDK Ver:");
- Serial.println(ESP.getSdkVersion());
- Serial.print("DATE:");
- Serial.println(__DATE__);
- Serial.print("TIME:");
- Serial.println(__TIME__);
-
- uint8_t mac[6];
- char macStr[18] = { 0 };
- esp_efuse_mac_get_default(mac);
- sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- Serial.print("EFUSE MAC: ");
- Serial.print(macStr);
- Serial.println();
-
- Serial.println("-----------------------------------");
-
-#elif defined(ARDUINO_ARCH_STM32)
- uint32_t uid[3];
-
- uid[0] = HAL_GetUIDw0();
- uid[1] = HAL_GetUIDw1();
- uid[2] = HAL_GetUIDw2();
- Serial.print("STM UID: 0X");
- Serial.print( uid[0], HEX);
- Serial.print( uid[1], HEX);
- Serial.print( uid[2], HEX);
- Serial.println();
-#endif
-}
-
-
-void setupBoards(bool disable_u8g2 )
-{
- Serial.begin(115200);
-
- // while (!Serial);
-
- Serial.println("setupBoards");
-
- getChipInfo();
-
-#if defined(ARDUINO_ARCH_ESP32)
- SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
-#elif defined(ARDUINO_ARCH_STM32)
- SPI.setMISO(RADIO_MISO_PIN);
- SPI.setMOSI(RADIO_MOSI_PIN);
- SPI.setSCLK(RADIO_SCLK_PIN);
- SPI.begin();
-#endif
-
-
-#if defined(HAS_SDCARD)
-#if defined(SD_SHARE_SPI_BUS)
- // Share spi bus with lora , set lora cs,rst to high
- pinMode(RADIO_CS_PIN, OUTPUT);
- pinMode(RADIO_RST_PIN, OUTPUT);
- digitalWrite(RADIO_CS_PIN, HIGH);
- digitalWrite(RADIO_RST_PIN, HIGH);
-#else
- SDCardSPI.begin(SDCARD_SCLK, SDCARD_MISO, SDCARD_MOSI);
-#endif /*SD_SHARE_SPI_BUS*/
-#endif /*HAS_SDCARD*/
-
-
-
-#ifdef I2C1_SDA
- Wire1.begin(I2C1_SDA, I2C1_SCL);
-#endif
-
-#ifdef HAS_GPS
-
-#ifdef GPS_EN_PIN
- pinMode(GPS_EN_PIN, OUTPUT);
- digitalWrite(GPS_EN_PIN, HIGH);
-#endif /*GPS_EN_PIN*/
-
-#ifdef GPS_PPS_PIN
- pinMode(GPS_PPS_PIN, INPUT);
-#endif
-
-#if defined(ARDUINO_ARCH_ESP32)
- SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
-#elif defined(ARDUINO_ARCH_STM32)
- SerialGPS.setRx(GPS_RX_PIN);
- SerialGPS.setTx(GPS_TX_PIN);
- SerialGPS.begin(GPS_BAUD_RATE);
-#endif // ARDUINO_ARCH_
-#endif // HAS_GPS
-
-#if OLED_RST
- pinMode(OLED_RST, OUTPUT);
- digitalWrite(OLED_RST, HIGH); delay(20);
- digitalWrite(OLED_RST, LOW); delay(20);
- digitalWrite(OLED_RST, HIGH); delay(20);
-#endif
-
-#ifdef BOARD_LED
- /*
- * T-Beam LED defaults to low level as turn on,
- * so it needs to be forced to pull up
- * * * * */
-#if LED_ON == LOW
-#if defined(ARDUINO_ARCH_ESP32)
- gpio_hold_dis((gpio_num_t)BOARD_LED);
-#endif //ARDUINO_ARCH_ESP32
-#endif
-
- pinMode(BOARD_LED, OUTPUT);
- digitalWrite(BOARD_LED, LED_ON);
-#endif
-
-
-#ifdef GPS_RST_PIN
- pinMode(GPS_RST_PIN, OUTPUT);
- digitalWrite(GPS_RST_PIN, HIGH);
-#endif
-
-#if defined(ARDUINO_ARCH_STM32)
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
- SerialGPS.println("@GSR"); delay(300);
-#endif
-
-
-#ifdef RADIO_LDO_EN
- /*
- * 2W and BPF LoRa LDO enable , Control SX1262 , LNA
- * 2W and BPF Radio version must set LDO_EN to HIGH to initialize the Radio
- * */
- pinMode(RADIO_LDO_EN, OUTPUT);
- digitalWrite(RADIO_LDO_EN, HIGH);
-#endif
-
-#ifdef RADIO_CTRL
- /*
- * 2W and BPF LoRa RX TX Control
- * CTRL controls the LNA, not the PA.
- * Only when RX DATA is on, set to 1 to turn on LNA
- * When TX DATA is on, CTL is set to 0 and LNA is turned off.
- * */
- pinMode(RADIO_CTRL, OUTPUT);
- digitalWrite(RADIO_CTRL, LOW);
-#endif
-
-#ifdef RADIO_DIO2_PIN
- pinMode(RADIO_DIO2_PIN, INPUT);
-#endif
-
- beginPower();
-
- // Perform an I2C scan after power-on operation
-#ifdef I2C_SDA
- Wire.begin(I2C_SDA, I2C_SCL);
- Serial.println("==================Scan Wire ==================");
- scanDevices(&Wire);
-#endif
-
-#ifdef I2C1_SDA
- Serial.println("==================Scan Wire1==================");
- scanDevices(&Wire1);
-#endif
-
- beginSDCard();
-
-#ifdef HAS_DISPLAY
- if (!disable_u8g2) {
- beginDisplay();
- }
-#endif
-
- // scanWiFi();
-
- // beginWiFi();
-
-#ifdef FAN_CTRL
- pinMode(FAN_CTRL, OUTPUT);
-#endif
-
-#ifdef HAS_GPS
-
-#if defined(T_BEAM_S3_SUPREME) || defined(T_BEAM_1W) || defined(T_BEAM_S3_BPF)
- // T-Beam v1.2 skips L76K
- find_gps = beginGPS();
-#endif
- uint32_t baudrate[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 4800};
- if (!find_gps) {
- // Restore factory settings
- for ( int i = 0; i < sizeof(baudrate) / sizeof(baudrate[0]); ++i) {
- Serial.printf("Update baudrate : %u\n", baudrate[i]);
- SerialGPS.updateBaudRate(baudrate[i]);
- if (recoveryGPS()) {
- Serial.println("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
- gps_model = "UBlox";
- find_gps = true;
- break;
- }
- }
- } else {
- gps_model = "L76K";
- }
-
- if (find_gps) {
- deviceOnline |= GPS_ONLINE;
- }
-
-#ifdef T_BEAM_S3_SUPREME
- enable_slow_clock();
-#endif
-
-#endif
-}
-
-
-void printResult(bool radio_online)
-{
- Serial.print("Radio : ");
- Serial.println((radio_online) ? "+" : "-");
-
-#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)
-
- Serial.print("PSRAM : ");
- Serial.println((psramFound()) ? "+" : "-");
-
-#ifdef DISPLAY_MODEL
- Serial.print("Display : ");
- Serial.println(( disp) ? "+" : "-");
-#endif
-
-#ifdef HAS_SDCARD
- Serial.print("Sd Card : ");
- Serial.println((SD.cardSize() != 0) ? "+" : "-");
-#endif
-
-#ifdef HAS_PMU
- Serial.print("Power : ");
- Serial.println(( PMU ) ? "+" : "-");
-#endif
-
-#ifdef HAS_GPS
- Serial.print("GPS : ");
- Serial.println(( find_gps ) ? "+" : "-");
-#endif
-
-#ifdef DISPLAY_MODEL
- if (disp) {
-
- disp->clearBuffer();
- disp->setFont(u8g2_font_NokiaLargeBold_tf );
- uint16_t str_w = disp->getStrWidth(BOARD_VARIANT_NAME);
- disp->drawStr((disp->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME);
- disp->drawHLine(5, 21, disp->getWidth() - 5);
-
- disp->drawStr( 0, 38, "Disp:"); disp->drawStr( 45, 38, ( disp) ? "+" : "-");
-
-#ifdef HAS_SDCARD
- disp->drawStr( 0, 54, "SD :"); disp->drawStr( 45, 54, (SD.cardSize() != 0) ? "+" : "-");
-#endif
-
- disp->drawStr( 62, 38, "Radio:"); disp->drawStr( 120, 38, ( radio_online ) ? "+" : "-");
-
-#ifdef HAS_PMU
- disp->drawStr( 62, 54, "Power:"); disp->drawStr( 120, 54, ( PMU ) ? "+" : "-");
-#endif
-
- disp->sendBuffer();
-
- delay(2000);
- }
-#endif
-#endif /*DISPLAY_MODEL*/
-}
-
-
-#ifdef BOARD_LED
-static uint8_t ledState = LOW;
-static const uint32_t debounceDelay = 50;
-static uint32_t lastDebounceTime = 0;
-#endif
-
-
-#ifdef BOARD_LED
-void flashLed()
-{
- if ((millis() - lastDebounceTime) > debounceDelay) {
- ledState = !ledState;
- if (ledState) {
- digitalWrite(BOARD_LED, LED_ON);
- } else {
- digitalWrite(BOARD_LED, !LED_ON);
- }
- lastDebounceTime = millis();
- }
-}
-#endif
-
-
-void scanDevices(TwoWire *w)
-{
- uint8_t err, addr;
- int nDevices = 0;
- uint32_t start = 0;
-
- Serial.println("I2C Devices scanning");
- for (addr = 1; addr < 127; addr++) {
- start = millis();
- w->beginTransmission(addr); delay(2);
- err = w->endTransmission();
- if (err == 0) {
- nDevices++;
- switch (addr) {
- case 0x77:
- bme280_address = addr;
- Serial.printf("\tFound BME280 Sensor at address 0x%02X\n", addr);
- deviceOnline |= BME280_ONLINE;
- break;
- case 0x76:
- bme280_address = addr;
- Serial.printf("\tFound BME280 Sensor at address 0x%02X\n", addr);
- deviceOnline |= BME280_ONLINE;
- break;
- case 0x34:
- Serial.printf("\tFound AXP192/AXP2101 PMU at address 0x%02X\n", addr);
- deviceOnline |= POWERMANAGE_ONLINE;
- break;
- case 0x3C:
- case 0x3D: {
- w->beginTransmission(addr);
- w->write((uint8_t)0x00);
- w->endTransmission();
- w->requestFrom((int)addr, 1);
- uint8_t r = w->read();
- if (r == 0x80) {
- Serial.printf("\tFound QMC6310N MAG Sensor at address 0x%02X\n", addr);
- mag_address = addr;
- deviceOnline |= QMC6310N_ONLINE;
- } else {
- Serial.printf("\tFound OLED display at address 0x%02X\n", addr);
- display_address = addr;
- deviceOnline |= DISPLAY_ONLINE;
- }
- }
- break;
- case 0x51:
- Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
- deviceOnline |= PCF8563_ONLINE;
- break;
- case 0x1C:
- Serial.printf("\tFound QMC6310U MAG Sensor at address 0x%02X\n", addr);
- deviceOnline |= QMC6310U_ONLINE;
- mag_address = addr;
- break;
- default:
- Serial.print("\tI2C device found at address 0x");
- if (addr < 16) {
- Serial.print("0");
- }
- Serial.print(addr, HEX);
- Serial.println(" !");
- break;
- }
-
- } else if (err == 4) {
- Serial.print("Unknow error at address 0x");
- if (addr < 16) {
- Serial.print("0");
- }
- Serial.println(addr, HEX);
- }
- }
- if (nDevices == 0)
- Serial.println("No I2C devices found\n");
-}
-
-
-#ifdef HAS_GPS
-
-bool l76kProbe()
-{
- bool result = false;
- uint32_t startTimeout ;
- SerialGPS.write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
- delay(5);
- // Get version information
- startTimeout = millis() + 3000;
- Serial.print("Try to init L76K . Wait stop .");
- // SerialGPS.flush();
- while (SerialGPS.available()) {
- int c = SerialGPS.read();
- // Serial.write(c);
- // Serial.print(".");
- // Serial.flush();
- // SerialGPS.flush();
- if (millis() > startTimeout) {
- Serial.println("Wait L76K stop NMEA timeout!");
- return false;
- }
- };
- Serial.println();
- SerialGPS.flush();
- delay(200);
-
- SerialGPS.write("$PCAS06,0*1B\r\n");
- startTimeout = millis() + 500;
- String ver = "";
- while (!SerialGPS.available()) {
- if (millis() > startTimeout) {
- Serial.println("Get L76K timeout!");
- return false;
- }
- }
- SerialGPS.setTimeout(10);
- ver = SerialGPS.readStringUntil('\n');
- if (ver.startsWith("$GPTXT,01,01,02")) {
- Serial.println("L76K GNSS init succeeded, using L76K GNSS Module\n");
- result = true;
- }
- delay(500);
-
- // Initialize the L76K Chip, use GPS + GLONASS
- SerialGPS.write("$PCAS04,5*1C\r\n");
- delay(250);
- // only ask for RMC and GGA
- SerialGPS.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
- delay(250);
- // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
- SerialGPS.write("$PCAS11,3*1E\r\n");
- return result;
-}
-
-bool beginGPS()
-{
- SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
- bool result = false;
- for ( int i = 0; i < 3; ++i) {
- result = l76kProbe();
- if (result) {
- return result;
- }
- }
- return result;
-}
-
-
-
-static int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID)
-{
- uint16_t ubxFrameCounter = 0;
- bool ubxFrame = 0;
- uint32_t startTime = millis();
- uint16_t needRead;
-
- while (millis() - startTime < 800) {
- while (SerialGPS.available()) {
- int c = SerialGPS.read();
- switch (ubxFrameCounter) {
- case 0:
- if (c == 0xB5) {
- ubxFrameCounter++;
- }
- break;
- case 1:
- if (c == 0x62) {
- ubxFrameCounter++;
- } else {
- ubxFrameCounter = 0;
- }
- break;
- case 2:
- if (c == requestedClass) {
- ubxFrameCounter++;
- } else {
- ubxFrameCounter = 0;
- }
- break;
- case 3:
- if (c == requestedID) {
- ubxFrameCounter++;
- } else {
- ubxFrameCounter = 0;
- }
- break;
- case 4:
- needRead = c;
- ubxFrameCounter++;
- break;
- case 5:
- needRead |= (c << 8);
- ubxFrameCounter++;
- break;
- case 6:
- if (needRead >= size) {
- ubxFrameCounter = 0;
- break;
- }
- if (SerialGPS.readBytes(buffer, needRead) != needRead) {
- ubxFrameCounter = 0;
- } else {
- return needRead;
- }
- break;
-
- default:
- break;
- }
- }
- }
- return 0;
-}
-
-bool recoveryGPS()
-{
- uint8_t buffer[256];
- uint8_t cfg_clear1[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xA2};
- uint8_t cfg_clear2[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1B, 0xA1};
- uint8_t cfg_clear3[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1D, 0xB3};
- SerialGPS.write(cfg_clear1, sizeof(cfg_clear1));
-
- if (getAck(buffer, 256, 0x05, 0x01)) {
- Serial.println("Get ack successes!");
- }
- SerialGPS.write(cfg_clear2, sizeof(cfg_clear2));
- if (getAck(buffer, 256, 0x05, 0x01)) {
- Serial.println("Get ack successes!");
- }
- SerialGPS.write(cfg_clear3, sizeof(cfg_clear3));
- if (getAck(buffer, 256, 0x05, 0x01)) {
- Serial.println("Get ack successes!");
- }
- // UBX-CFG-RATE, Size 8, 'Navigation/measurement rate settings'
- uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
- SerialGPS.write(cfg_rate, sizeof(cfg_rate));
- if (getAck(buffer, 256, 0x06, 0x08)) {
- Serial.println("Get ack successes!");
- } else {
- return false;
- }
- return true;
-}
-
-#endif
-
-
-#if defined(ARDUINO_ARCH_ESP32)
-
-//NCP18XH103F03RB: https://item.szlcsc.com/14214.html
-// #define NTC_PIN 14 // NTC connection pins
-#define SERIES_RESISTOR 10000 // Series resistance value (10kΩ)
-#define B_COEFFICIENT 3950 // B value, set according to the NTC specification
-#define ROOM_TEMP 298.15 // 25°C absolute temperature (K)
-#define ROOM_TEMP_RESISTANCE 10000 // Resistance of NTC at 25°C (10kΩ)
-
-float getTempForNTC()
-{
- static float temperature = 0.0f;
-#ifdef NTC_PIN
- static uint32_t check_temperature = 0;
- if (millis() > check_temperature) {
- float voltage = analogReadMilliVolts(NTC_PIN) / 1000.0;
- float resistance = SERIES_RESISTOR * ((3.3 / voltage) - 1); // Calculate the resistance of NTC
-
- // Calculate temperature using the Steinhart-Hart equation
- temperature = (1.0 / (log(resistance / ROOM_TEMP_RESISTANCE) / B_COEFFICIENT + 1.0 / ROOM_TEMP)) - 273.15;
-
- // Serial.print("Temperature: ");
- // Serial.print(temperature);
- // Serial.println(" °C");
-
- check_temperature = millis() + 1000;
- }
-#endif
- return temperature;
-}
-
-#ifdef ENABLE_BLE
-
-#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
-#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
-
-void setupBLE()
-{
-
- uint8_t mac[6];
- char macStr[18] = { 0 };
- esp_efuse_mac_get_default(mac);
- sprintf(macStr, "%02X:%02X", mac[0], mac[1]);
-
- String dev = BOARD_VARIANT_NAME;
- dev.concat('-');
- dev.concat(macStr);
-
- Serial.print("Starting BLE:");
- Serial.println(dev);
-
- BLEDevice::init(dev.c_str());
- BLEServer *pServer = BLEDevice::createServer();
- BLEService *pService = pServer->createService(SERVICE_UUID);
- BLECharacteristic *pCharacteristic = pService->createCharacteristic(
- CHARACTERISTIC_UUID,
- BLECharacteristic::PROPERTY_READ |
- BLECharacteristic::PROPERTY_WRITE);
-
- pCharacteristic->setValue("Hello World");
- pService->start();
- // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
- BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
- pAdvertising->addServiceUUID(SERVICE_UUID);
- pAdvertising->setScanResponse(true);
- pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
- pAdvertising->setMinPreferred(0x12);
- BLEDevice::startAdvertising();
- Serial.println("Characteristic defined! Now you can read it in your phone!");
-}
-#endif
-
-#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
-
-static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
-{
- const uint32_t cal_count = 1000;
- const float factor = (1 << 19) * 1000.0f;
- uint32_t cali_val;
- for (int i = 0; i < 5; ++i) {
- cali_val = rtc_clk_cal(cal_clk, cal_count);
- }
- return cali_val;
-}
-
-static void enable_slow_clock()
-{
- rtc_clk_32k_enable(true);
- CALIBRATE_ONE(RTC_CAL_RTC_MUX);
- uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);
- if (cal_32k == 0) {
- Serial.printf("32K XTAL OSC has not started up");
- } else {
- rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
- Serial.println("Switching RTC Source to 32.768Khz succeeded, using 32K XTAL");
- CALIBRATE_ONE(RTC_CAL_RTC_MUX);
- CALIBRATE_ONE(RTC_CAL_32K_XTAL);
- }
- CALIBRATE_ONE(RTC_CAL_RTC_MUX);
- CALIBRATE_ONE(RTC_CAL_32K_XTAL);
- if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
- Serial.println("Warning: Failed to set rtc clk to 32.768Khz !!! "); return;
- }
- deviceOnline |= OSC32768_ONLINE;
-}
-
-
-void scanWiFi()
-{
- WiFi.mode(WIFI_STA);
- WiFi.disconnect();
- Serial.println("WiFi Scan start");
- // WiFi.scanNetworks will return the number of networks found.
- int n = WiFi.scanNetworks();
- Serial.println("WiFi Scan done");
- if (n == 0) {
- Serial.println("no networks found");
- } else {
- Serial.print(n);
- Serial.println(" networks found");
- Serial.println("Nr | SSID | RSSI | CH | Encryption");
- for (int i = 0; i < n; ++i) {
- // Print SSID and RSSI for each network found
- Serial.printf("%2d", i + 1);
- Serial.print(" | ");
- Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
- Serial.print(" | ");
- Serial.printf("%4ld", WiFi.RSSI(i));
- Serial.print(" | ");
- Serial.printf("%2ld", WiFi.channel(i));
- Serial.print(" | ");
- switch (WiFi.encryptionType(i)) {
- case WIFI_AUTH_OPEN: Serial.print("open"); break;
- case WIFI_AUTH_WEP: Serial.print("WEP"); break;
- case WIFI_AUTH_WPA_PSK: Serial.print("WPA"); break;
- case WIFI_AUTH_WPA2_PSK: Serial.print("WPA2"); break;
- case WIFI_AUTH_WPA_WPA2_PSK: Serial.print("WPA+WPA2"); break;
- case WIFI_AUTH_WPA2_ENTERPRISE: Serial.print("WPA2-EAP"); break;
- case WIFI_AUTH_WPA3_PSK: Serial.print("WPA3"); break;
- case WIFI_AUTH_WPA2_WPA3_PSK: Serial.print("WPA2+WPA3"); break;
- case WIFI_AUTH_WAPI_PSK: Serial.print("WAPI"); break;
- default: Serial.print("unknown");
- }
- Serial.println();
- delay(10);
- }
- }
- Serial.println("");
-
- // Delete the scan result to free memory for code below.
- WiFi.scanDelete();
-}
-
-#endif /*ARDUINO_ARCH_ESP32*/
-
diff --git a/examples/Sensor/QMC6310_GetDataExample/LoRaBoards.h b/examples/Sensor/QMC6310_GetDataExample/LoRaBoards.h
deleted file mode 100644
index 58288ef..0000000
--- a/examples/Sensor/QMC6310_GetDataExample/LoRaBoards.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * @file boards.h
- * @author Lewis He (lewishe@outlook.com)
- * @license MIT
- * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
- * @date 2024-04-25
- * @last-update 2024-08-07
- */
-
-#pragma once
-
-
-#include "utilities.h"
-
-#ifdef HAS_SDCARD
-#include
-#endif
-
-#if defined(ARDUINO_ARCH_ESP32)
-#include
-#include
-#endif
-
-#include
-#include
-#include
-
-#ifdef DISPLAY_MODEL
-#include
-#endif
-
-#ifdef HAS_PMU
-#include
-#endif
-
-#include
-
-
-#ifndef DISPLAY_ADDR
-#define DISPLAY_ADDR 0x3C
-#endif
-
-
-// #define ENABLE_BLE //Enable ble function
-
-enum {
- POWERMANAGE_ONLINE = _BV(0),
- DISPLAY_ONLINE = _BV(1),
- RADIO_ONLINE = _BV(2),
- GPS_ONLINE = _BV(3),
- PSRAM_ONLINE = _BV(4),
- SDCARD_ONLINE = _BV(5),
- AXDL345_ONLINE = _BV(6),
- BME280_ONLINE = _BV(7),
- BMP280_ONLINE = _BV(8),
- BME680_ONLINE = _BV(9),
- QMC6310U_ONLINE = _BV(10),
- QMC6310N_ONLINE = _BV(11),
- QMI8658_ONLINE = _BV(12),
- PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
-};
-
-
-
-typedef struct {
- String chipModel;
- float psramSize;
- uint8_t chipModelRev;
- uint8_t chipFreq;
- uint8_t flashSize;
- uint8_t flashSpeed;
-} DevInfo_t;
-
-
-void setupBoards(bool disable_u8g2 = false);
-
-#ifdef HAS_SDCARD
-bool beginSDCard();
-#else
-#define beginSDCard()
-#endif
-
-#ifdef DISPLAY_MODEL
-bool beginDisplay();
-#endif
-
-
-void printResult(bool radio_online);
-
-#ifdef BOARD_LED
-void flashLed();
-#else
-#define flashLed()
-#endif
-
-void scanDevices(TwoWire *w);
-
-bool beginGPS();
-
-bool recoveryGPS();
-
-void scanWiFi();
-
-#ifdef HAS_PMU
-extern XPowersLibInterface *PMU;
-extern bool pmuInterrupt;
-void loopPMU(void (*pressed_cb)(void));
-bool beginPower();
-void disablePeripherals();
-#else
-#define beginPower()
-#define disablePeripherals()
-#endif
-
-#ifdef DISPLAY_MODEL
-extern U8G2 *disp;
-#define U8G2_HOR_ALIGN_CENTER(t) ((disp->getDisplayWidth() - (disp->getUTF8Width(t))) / 2)
-#define U8G2_HOR_ALIGN_RIGHT(t) ( disp->getDisplayWidth() - disp->getUTF8Width(t))
-#endif
-
-
-#if defined(ARDUINO_ARCH_ESP32)
-
-#if defined(HAS_SDCARD)
-extern SPIClass SDCardSPI;
-#endif
-
-#define SerialGPS Serial1
-#elif defined(ARDUINO_ARCH_STM32)
-extern HardwareSerial SerialGPS;
-#endif
-
-#ifdef NTC_PIN
-float getTempForNTC();
-#endif
-
-#ifdef ENABLE_BLE
-void setupBLE();
-#else
-#define setupBLE()
-#endif
-
-extern uint32_t deviceOnline;
diff --git a/examples/Sensor/QMC6310_GetDataExample/QMC6310_GetDataExample.ino b/examples/Sensor/QMC6310_GetDataExample/QMC6310_GetDataExample.ino
deleted file mode 100644
index 1bc480f..0000000
--- a/examples/Sensor/QMC6310_GetDataExample/QMC6310_GetDataExample.ino
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- *
- * @license MIT License
- *
- * Copyright (c) 2022 lewis he
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * @file QMC6310_GetDataExample.ino
- * @author Lewis He (lewishe@outlook.com)
- * @date 2022-10-16
- *
- */
-#include
-#include
-#include
-#include "SensorQMC6310.hpp"
-#include "LoRaBoards.h"
-
-
-SensorQMC6310 qmc;
-
-void setup()
-{
- Serial.begin(115200);
- while (!Serial);
-
- setupBoards();
-
- // For QMC6310U, the device address is 0x1C.
- // For QMC6310N, the device address is 0x3C.
- // The sensor device address is provided by the setupBoards I2C scanner.
- extern uint8_t mag_address;
- if (!qmc.begin(Wire, mag_address, I2C_SDA, I2C_SCL)) {
- Serial.println("Failed to find QMC6310 - check your wiring!");
- while (1) {
- delay(1000);
- }
- }
-
- /* Get Magnetometer chip id*/
- Serial.print("Device ID:");
- Serial.println(qmc.getChipID(), HEX);
-
- /* Config Magnetometer */
- qmc.configMagnetometer(
- /*
- * Run Mode
- * MODE_SUSPEND
- * MODE_NORMAL
- * MODE_SINGLE
- * MODE_CONTINUOUS
- * * */
- SensorQMC6310::MODE_CONTINUOUS,
- /*
- * Full Range
- * RANGE_30G
- * RANGE_12G
- * RANGE_8G
- * RANGE_2G
- * * */
- SensorQMC6310::RANGE_8G,
- /*
- * Output data rate
- * DATARATE_10HZ
- * DATARATE_50HZ
- * DATARATE_100HZ
- * DATARATE_200HZ
- * * */
- SensorQMC6310::DATARATE_200HZ,
- /*
- * Over sample Ratio1
- * OSR_8
- * OSR_4
- * OSR_2
- * OSR_1
- * * * */
- SensorQMC6310::OSR_1,
-
- /*
- * Down sample Ratio1
- * DSR_8
- * DSR_4
- * DSR_2
- * DSR_1
- * * */
- SensorQMC6310::DSR_1);
-
- Serial.println("Read data now...");
-}
-
-void loop()
-{
-
- //Wiat data ready
- if (qmc.isDataReady()) {
-
- qmc.readData();
-
- Serial.print("GYR: ");
- Serial.print("X:");
- Serial.print(qmc.getX());
- Serial.print(" Y:");
- Serial.print(qmc.getY());
- Serial.print(" Z:");
- Serial.print(qmc.getZ());
- Serial.println(" uT");
- Serial.print("RAW: ");
- Serial.print("X:");
- Serial.print(qmc.getRawX());
- Serial.print(" Y:");
- Serial.print(qmc.getRawY());
- Serial.print(" Z:");
- Serial.println(qmc.getRawZ());
-
- /*
- float x, y, z;
- qmc.getMag(x, y, z);
- Serial.print("X:");
- Serial.print(x);
- Serial.print(" Y:");
- Serial.print(y);
- Serial.print(" Z:");
- Serial.println(x);
- */
- }
-
-
- delay(100);
-}
-
-
-
diff --git a/examples/Sensor/QMC6310_GetDataExample/utilities.h b/examples/Sensor/QMC6310_GetDataExample/utilities.h
deleted file mode 100644
index 08b2145..0000000
--- a/examples/Sensor/QMC6310_GetDataExample/utilities.h
+++ /dev/null
@@ -1,780 +0,0 @@
-/**
- * @file utilities.h
- * @author Lewis He (lewishe@outlook.com)
- * @license MIT
- * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
- * @date 2024-05-12
- * @last-update 2025-07-07
- */
-#pragma once
-
-
-// Support board list , Macro definition below, select the board definition to be used
-// 将要使用的板子型号注释打开,只能打开一个型号,如果不明白自己买的型号是什么,请找客服核对型号
-
-/*********************************** Model definition start 型号定义起始 ***********************************/
-
-// 1. --------------T3 V1.3 -------------------------------
-// https://lilygo.cc/products/lora-v1-3
-// #define T3_V1_3_SX1276
-// #define T3_V1_3_SX1278
-
-// 2. --------------T3 V1.6.1 -------------------------------
-// https://lilygo.cc/products/lora3
-
-// #define T3_V1_6_SX1276
-// #define T3_V1_6_SX1278
-
-// 3. --------------T3 V3.0 TCXO-------------------------------
-// Product: https://lilygo.cc/products/t3-tcxo
-
-// #define T3_V3_0_SX1276_TCXO
-
-// 4. --------------T-BEAM ESP32-------------------------------
-// Product: https://lilygo.cc/products/t-beam
-
-// #define T_BEAM_SX1262
-// #define T_BEAM_SX1276
-// #define T_BEAM_SX1278
-// #define T_BEAM_LR1121
-
-// 5. --------------T-BEAM S3------------------------------
-// Product: https://lilygo.cc/products/t-beam-supreme
-
-// #define T_BEAM_S3_SUPREME_SX1262
-// #define T_BEAM_S3_SUPREME_LR1121
-
-// 6. --------------T3 S3 V1.0 or T3 S3 V1.3 -------------------
-// Product: https://lilygo.cc/products/t3s3-v1-0 , same v1.3
-// Product: https://lilygo.cc/products/t3-s3-v1-3
-
-// #define T3_S3_V1_2_SX1262
-// #define T3_S3_V1_2_SX1276
-// #define T3_S3_V1_2_SX1278
-// #define T3_S3_V1_2_SX1280
-// #define T3_S3_V1_2_SX1280_PA
-// #define T3_S3_V1_2_LR1121
-// #define T3_S3_V1_2_LR1121_PA
-
-// 7. --------------T-Motion -------------------------------------
-// Product: https://lilygo.cc/products/t-motion-s76g-stm32-lora
-
-// #define T_MOTION
-
-// --------------T3 C6 -------------------------------------
-// Product: https://lilygo.cc/products/t-lora-c6
-
-// #define T3_C6
-
-
-// --------------T-Beam BPF -------------------------------------
-// Product: https://lilygo.cc/products/t-beam-bpf
-// #define T_BEAM_S3_BPF
-
-// --------------LoRa 2W -------------------------------------
-// Product: ...
-// #define T_BEAM_1W
-
-
-
-// #define T3_V1_6_SX1276_TCXO // Production has stopped
-
-/*********************************** Model definition end 型号定义结尾 ***********************************/
-
-
-#define UNUSED_PIN (0)
-
-#if defined(T_BEAM_SX1262) || defined(T_BEAM_SX1276) || defined(T_BEAM_SX1278) || defined(T_BEAM_LR1121)
-
-
-#if defined(T_BEAM_SX1262)
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-#elif defined(T_BEAM_SX1276)
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#elif defined(T_BEAM_SX1278)
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-#elif defined(T_BEAM_LR1121)
-#ifndef USING_LR1121
-#define USING_LR1121
-#endif
-#endif // T_BEAM_SX1262
-
-
-#define GPS_RX_PIN 34
-#define GPS_TX_PIN 12
-#define BUTTON_PIN 38
-#define BUTTON_PIN_MASK GPIO_SEL_38
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define PMU_IRQ 35
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 23
-#define RADIO_DIO1_PIN 33
-// SX1276/78
-#define RADIO_DIO2_PIN 32
-// SX1262
-#define RADIO_BUSY_PIN 32
-
-// LR1121 Only
-#define RADIO_DIO9_PIN 33
-
-
-#define BOARD_LED 4
-#define LED_ON LOW
-#define LED_OFF HIGH
-
-#define BUTTON_PIN 38
-
-#define GPS_BAUD_RATE 9600
-#define HAS_GPS
-#define HAS_DISPLAY //Optional, bring your own board, no OLED !!
-#define HAS_PMU
-
-#define PMU_WIRE_PORT Wire
-#define BOARD_VARIANT_NAME "T-Beam"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-
-#elif defined(T3_V1_3_SX1276) || defined(T3_V1_3_SX1278)
-
-
-#if defined(T3_V1_3_SX1276)
-
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-
-#elif defined(T3_V1_3_SX1278)
-
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-
-#endif // T3_V1_3_SX1276
-
-
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 14
-#define RADIO_DIO1_PIN 33
-
-// SX1276/78
-#define RADIO_DIO2_PIN 32
-// SX1262
-#define RADIO_BUSY_PIN 32
-
-
-#define ADC_PIN 35
-#define HAS_DISPLAY
-#define BOARD_VARIANT_NAME "T3 V1.3"
-
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_V1_6_SX1276) || defined(T3_V1_6_SX1278)
-
-
-#if defined(T3_V1_6_SX1276)
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#elif defined(T3_V1_6_SX1278)
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-#endif // T3_V1_6_SX1276
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 23
-#define RADIO_DIO1_PIN 33
-// SX1276/78
-#define RADIO_DIO2_PIN 32
-// SX1262
-#define RADIO_BUSY_PIN 32
-
-#define SDCARD_MOSI 15
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 25
-#define LED_ON HIGH
-
-#define ADC_PIN 35
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3 V1.6"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_V1_6_SX1276_TCXO)
-
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 23
-#define RADIO_DIO1_PIN -1//33
-/*
-* In the T3 V1.6.1 TCXO version, Radio DIO1 is connected to Radio’s
-* internal temperature-compensated crystal oscillator enable
-* */
-// TCXO pin must be set to HIGH before enabling Radio
-#define RADIO_TCXO_ENABLE 33
-#define RADIO_BUSY_PIN 32
-
-#define SDCARD_MOSI 15
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 25
-#define LED_ON HIGH
-
-#define ADC_PIN 35
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3 V1.6 TCXO"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_V3_0) || defined(T3_V3_0_SX1276_TCXO)
-
-#ifdef T3_V3_0_SX1276_TCXO
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#endif
-
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST 4
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_RST_PIN 23
-
-// TCXO pin must be set to HIGH before enabling Radio
-#define RADIO_TCXO_ENABLE 12 //only sx1276 tcxo version
-#define RADIO_BUSY_PIN 32
-
-
-#if defined(USING_SX1262)
-
-#define RADIO_DIO1_PIN 26
-#define RADIO_BUSY_PIN 32
-
-#elif defined(USING_SX1276) || defined(USING_SX1278)
-//!SX1276/78 module only
-
-#define RADIO_DIO0_PIN 26
-#define RADIO_DIO1_PIN 32
-
-#elif defined(USING_LR1121)
-
-#define RADIO_DIO9_PIN 26 //LR1121 DIO9
-#define RADIO_BUSY_PIN 32 //LR1121 BUSY
-
-#endif
-
-#define SDCARD_MOSI 15
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 25
-#define LED_ON HIGH
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3 V3.0"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-#define BUTTON_PIN 0
-#define ADC_PIN 35
-
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262) || \
- defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276) || \
- defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278) || \
- defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280) || \
- defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA) || \
- defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121) || \
- defined(T3_S3_V1_2_LR1121_PA) || defined(ARDUINO_LILYGO_T3S3_LR1121PA)
-
-
-#if defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262)
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-#elif defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276)
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#elif defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278)
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-#elif defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280)
-#ifndef USING_SX1280
-#define USING_SX1280
-#endif
-#elif defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA)
-#ifndef USING_SX1280PA
-#define USING_SX1280PA
-#endif
-#elif defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121)
-#ifndef USING_LR1121
-#define USING_LR1121
-#endif
-#elif defined(T3_S3_V1_2_LR1121_PA) || defined(ARDUINO_LILYGO_T3S3_LR1121PA)
-#ifndef USING_LR1121PA
-#define USING_LR1121PA
-#endif
-#endif // T3_S3_V1_2_SX1262
-
-
-#define I2C_SDA 18
-#define I2C_SCL 17
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 3
-#define RADIO_MOSI_PIN 6
-#define RADIO_CS_PIN 7
-
-#define SDCARD_MOSI 11
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 37
-#define LED_ON HIGH
-
-#define BUTTON_PIN 0
-#define ADC_PIN 1
-
-#define RADIO_RST_PIN 8
-
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#if defined(USING_SX1262)
-
-#define RADIO_DIO1_PIN 33
-#define RADIO_BUSY_PIN 34
-
-#elif defined(USING_SX1276) || defined(USING_SX1278)
-//!SX1276/78 module only
-#define RADIO_BUSY_PIN 33 //DIO1
-
-#define RADIO_DIO0_PIN 9
-#define RADIO_DIO1_PIN 33
-#define RADIO_DIO2_PIN 34
-#define RADIO_DIO3_PIN 21
-#define RADIO_DIO4_PIN 10
-#define RADIO_DIO5_PIN 36
-
-#elif defined(USING_SX1280)
-
-#define RADIO_DIO1_PIN 9 //SX1280 DIO1 = IO9
-#define RADIO_BUSY_PIN 36 //SX1280 BUSY = IO36
-
-#elif defined(USING_SX1280PA)
-
-#define RADIO_DIO1_PIN 9 //SX1280 DIO1 = IO9
-#define RADIO_BUSY_PIN 36 //SX1280 BUSY = IO36
-#define RADIO_RX_PIN 21
-#define RADIO_TX_PIN 10
-
-
-#elif defined(USING_LR1121)
-
-#define RADIO_DIO9_PIN 36 //LR1121 DIO9 = IO36
-#define RADIO_BUSY_PIN 34 //LR1121 BUSY = IO34
-
-#define LILYGO_RADIO_2G4_TX_POWER_LIMIT 13 //LR1121 2.4G TX Power Limit
-
-#elif defined(USING_LR1121PA)
-
-#define RADIO_DIO9_PIN 36 //LR1121 DIO9 = IO36
-#define RADIO_BUSY_PIN 34 //LR1121 BUSY = IO34
-
-#define LILYGO_RADIO_2G4_TX_POWER_LIMIT 0 //LR1121 2.4G TX Power Limit
-#define USING_LR1121
-
-#endif
-
-#define BUTTON_PIN 0
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3-S3-V1.X"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-
-#elif defined(T_BEAM_S3_SUPREME_SX1262) || defined(T_BEAM_S3_SUPREME_LR1121)
-
-#ifndef T_BEAM_S3_SUPREME
-#define T_BEAM_S3_SUPREME
-#endif
-
-#if defined(T_BEAM_S3_SUPREME_SX1262)
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-#elif defined(T_BEAM_S3_SUPREME_LR1121)
-#ifndef USING_LR1121
-#define USING_LR1121
-#endif
-#endif
-
-#define I2C_SDA (17)
-#define I2C_SCL (18)
-
-#define I2C1_SDA (42)
-#define I2C1_SCL (41)
-#define PMU_IRQ (40)
-
-#define GPS_RX_PIN (9)
-#define GPS_TX_PIN (8)
-#define GPS_EN_PIN (7)
-#define GPS_PPS_PIN (6)
-
-#define BUTTON_PIN (0)
-#define BUTTON_PIN_MASK (GPIO_SEL_0)
-#define BUTTON_COUNT (1)
-#define BUTTON_ARRAY {BUTTON_PIN}
-
-#define RADIO_SCLK_PIN (12)
-#define RADIO_MISO_PIN (13)
-#define RADIO_MOSI_PIN (11)
-#define RADIO_CS_PIN (10)
-#define RADIO_DIO0_PIN (-1)
-#define RADIO_RST_PIN (5)
-#define RADIO_DIO1_PIN (1)
-#define RADIO_BUSY_PIN (4)
-
-// LR1121 Version
-#define RADIO_DIO9_PIN (1)
-
-#define SPI_MOSI (35)
-#define SPI_SCK (36)
-#define SPI_MISO (37)
-#define SPI_CS (47)
-#define IMU_CS (34)
-#define IMU_INT (33)
-
-#define SDCARD_MOSI SPI_MOSI
-#define SDCARD_MISO SPI_MISO
-#define SDCARD_SCLK SPI_SCK
-#define SDCARD_CS SPI_CS
-
-#define RTC_INT (14)
-
-#define GPS_BAUD_RATE (9600)
-
-#define HAS_SDCARD
-#define HAS_GPS
-#define HAS_DISPLAY
-#define HAS_PMU
-
-#define __HAS_SPI1__
-#define HAS_SENSOR
-
-#define PMU_WIRE_PORT Wire1
-#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
-#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "T-Beam S3"
-
-#elif defined(T_MOTION_S76G)
-
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-
-
-#define RADIO_SCLK_PIN PB13
-#define RADIO_MISO_PIN PB14
-#define RADIO_MOSI_PIN PB15
-#define RADIO_CS_PIN PB12
-#define RADIO_RST_PIN PB10
-
-#define RADIO_DIO0_PIN PB11
-#define RADIO_DIO1_PIN PC13
-#define RADIO_DIO2_PIN PB9
-#define RADIO_DIO3_PIN PB4
-#define RADIO_DIO4_PIN PB3
-#define RADIO_DIO5_PIN PA15
-
-#undef RADIO_BUSY_PIN
-#undef RADIO_DIO1_PIN
-#define RADIO_BUSY_PIN PC13 //DIO1
-#define RADIO_DIO1_PIN PB11 //DIO0
-
-#define RADIO_SWITCH_PIN PA1 //1:Rx, 0:Tx
-
-#define GPS_EN_PIN PC6
-#define GPS_RST_PIN PB2
-#define GPS_RX_PIN PC11
-#define GPS_TX_PIN PC10
-#define GPS_ENABLE_PIN PC6
-#define GPS_BAUD_RATE 115200
-#define GPS_PPS_PIN PB5
-
-#define UART_RX_PIN PA10
-#define UART_TX_PIN PA9
-
-#define I2C_SCL PB6
-#define I2C_SDA PB7
-
-#define BOARD_VARIANT_NAME "T-Motion S76G"
-
-#define HAS_GPS
-
-#elif defined(T3_C6)
-
-
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-
-
-#define RADIO_SCLK_PIN 6
-#define RADIO_MISO_PIN 1
-#define RADIO_MOSI_PIN 0
-#define RADIO_CS_PIN 18
-#define RADIO_DIO1_PIN 23
-#define RADIO_BUSY_PIN 22
-#define RADIO_RST_PIN 21
-
-#define I2C_SDA 8
-#define I2C_SCL 9
-
-#define BOARD_LED 7
-#define LED_ON HIGH
-#define RADIO_RX_PIN 15
-#define RADIO_TX_PIN 14
-
-
-#define BOARD_VARIANT_NAME "T3-C6"
-
-#define USING_DIO2_AS_RF_SWITCH
-
-
-#elif defined(T_BEAM_S3_BPF)
-
-
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-
-#define I2C_SDA (8)
-#define I2C_SCL (9)
-
-#define PMU_IRQ (4)
-
-#define GPS_RX_PIN (5)
-#define GPS_TX_PIN (6)
-#define GPS_PPS_PIN (7)
-
-#define BUTTON_PIN (0)
-#define BUTTON2_PIN (3) /*BUTTON 2 = GPIO3*/
-#define BUTTON_PIN_MASK GPIO_SEL_0 /*BUTTON 1 = GPIO0*/
-#define BUTTON_COUNT (2)
-#define BUTTON_ARRAY {BUTTON_PIN, BUTTON2_PIN /*BUTTON 2 = GPIO3*/}
-
-#define RADIO_SCLK_PIN (12)//(41)
-#define RADIO_MISO_PIN (13)//(42)
-#define RADIO_MOSI_PIN (11)//(2)
-#define RADIO_CS_PIN (1)
-#define RADIO_RST_PIN (18)
-
-#define RADIO_DIO0_PIN (14)
-#define RADIO_DIO1_PIN (21)
-
-// #define RADIO_TCXO_ENABLE (17)
-#define RADIO_LDO_EN (16)
-#define RADIO_CTRL (39)
-
-#define SPI_MOSI (11)
-#define SPI_SCK (12)
-#define SPI_MISO (13)
-#define SPI_CS (10)
-
-#define SDCARD_MOSI SPI_MOSI
-#define SDCARD_MISO SPI_MISO
-#define SDCARD_SCLK SPI_SCK
-#define SDCARD_CS SPI_CS
-
-
-#define GPS_BAUD_RATE 9600
-
-#define HAS_SDCARD
-#define HAS_GPS
-#define HAS_DISPLAY
-#define HAS_PMU
-#define SD_SHARE_SPI_BUS
-
-#define PMU_WIRE_PORT Wire
-#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
-#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "T-Beam BPF"
-
-
-#elif defined(T_BEAM_1W)
-
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-
-#define I2C_SDA (8)
-#define I2C_SCL (9)
-
-#define GPS_RX_PIN (5)
-#define GPS_TX_PIN (6)
-#define GPS_PPS_PIN (7)
-#define GPS_EN_PIN (16)
-
-#define BUTTON_PIN (0) /*BUTTON 1 = GPIO0*/
-#define BUTTON2_PIN (17) /*BUTTON 2 = GPIO17*/
-
-#define BUTTON_PIN_MASK GPIO_SEL_0
-#define BUTTON_COUNT (2)
-#define BUTTON_ARRAY {BUTTON_PIN,BUTTON2_PIN/*BUTTON 2 = GPIO3*/}
-
-#define SPI_MOSI (11)
-#define SPI_SCK (13)
-#define SPI_MISO (12)
-#define SPI_CS (10)
-
-#define SDCARD_CS SPI_CS
-
-#define RADIO_SCLK_PIN (SPI_SCK)
-#define RADIO_MISO_PIN (SPI_MISO)
-#define RADIO_MOSI_PIN (SPI_MOSI)
-
-#define RADIO_CS_PIN (15)
-#define RADIO_RST_PIN (3)
-#define RADIO_LDO_EN (40)
-#define RADIO_CTRL (21)
-#define RADIO_DIO1_PIN (1)
-#define RADIO_BUSY_PIN (38)
-
-#define BOARD_LED 18
-#define LED_ON HIGH
-#define LED_OFF LOW
-
-
-#define NTC_PIN (14)
-#define FAN_CTRL (41)
-#define ADC_PIN (4)
-
-#define BAT_ADC_PULLUP_RES (300000.0)
-#define BAT_ADC_PULLDOWN_RES (150000.0)
-#define BAT_MAX_VOLTAGE (7.4)
-#define BAT_VOL_COMPENSATION (0.25)
-#define GPS_SLEEP_HOLD_ON_LOW
-
-#define GPS_BAUD_RATE 9600
-
-#define HAS_SDCARD
-#define HAS_GPS
-#define HAS_DISPLAY
-#define SD_SHARE_SPI_BUS // SD-CARD AND RADIO SHARE SPI BUS
-#define __HAS_SPI1__
-
-#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
-#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "LoRa 2W"
-
-#else
-#error "When using it for the first time, please define the board model in 首次使用时,请在 文件最上方定义板卡模型"
-#endif
-
-
-
-
-
-#if defined(USING_SX1262)
-#define RADIO_TYPE_STR "SX1262"
-#elif defined(USING_SX1276)
-#define RADIO_TYPE_STR "SX1276"
-#elif defined(USING_SX1278)
-#define RADIO_TYPE_STR "SX1278"
-#elif defined(USING_LR1121)
-#define RADIO_TYPE_STR "LR1121"
-#elif defined(USING_SX1280)
-#define RADIO_TYPE_STR "SX1280"
-#elif defined(USING_SX1280PA)
-#define RADIO_TYPE_STR "SX1280PA"
-#endif
-
-
-
-
-
diff --git a/examples/Sensor/QMC6310_GetPolarExample/LoRaBoards.h b/examples/Sensor/QMC6310_GetPolarExample/LoRaBoards.h
deleted file mode 100644
index 58288ef..0000000
--- a/examples/Sensor/QMC6310_GetPolarExample/LoRaBoards.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * @file boards.h
- * @author Lewis He (lewishe@outlook.com)
- * @license MIT
- * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
- * @date 2024-04-25
- * @last-update 2024-08-07
- */
-
-#pragma once
-
-
-#include "utilities.h"
-
-#ifdef HAS_SDCARD
-#include
-#endif
-
-#if defined(ARDUINO_ARCH_ESP32)
-#include
-#include
-#endif
-
-#include
-#include
-#include
-
-#ifdef DISPLAY_MODEL
-#include
-#endif
-
-#ifdef HAS_PMU
-#include
-#endif
-
-#include
-
-
-#ifndef DISPLAY_ADDR
-#define DISPLAY_ADDR 0x3C
-#endif
-
-
-// #define ENABLE_BLE //Enable ble function
-
-enum {
- POWERMANAGE_ONLINE = _BV(0),
- DISPLAY_ONLINE = _BV(1),
- RADIO_ONLINE = _BV(2),
- GPS_ONLINE = _BV(3),
- PSRAM_ONLINE = _BV(4),
- SDCARD_ONLINE = _BV(5),
- AXDL345_ONLINE = _BV(6),
- BME280_ONLINE = _BV(7),
- BMP280_ONLINE = _BV(8),
- BME680_ONLINE = _BV(9),
- QMC6310U_ONLINE = _BV(10),
- QMC6310N_ONLINE = _BV(11),
- QMI8658_ONLINE = _BV(12),
- PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
-};
-
-
-
-typedef struct {
- String chipModel;
- float psramSize;
- uint8_t chipModelRev;
- uint8_t chipFreq;
- uint8_t flashSize;
- uint8_t flashSpeed;
-} DevInfo_t;
-
-
-void setupBoards(bool disable_u8g2 = false);
-
-#ifdef HAS_SDCARD
-bool beginSDCard();
-#else
-#define beginSDCard()
-#endif
-
-#ifdef DISPLAY_MODEL
-bool beginDisplay();
-#endif
-
-
-void printResult(bool radio_online);
-
-#ifdef BOARD_LED
-void flashLed();
-#else
-#define flashLed()
-#endif
-
-void scanDevices(TwoWire *w);
-
-bool beginGPS();
-
-bool recoveryGPS();
-
-void scanWiFi();
-
-#ifdef HAS_PMU
-extern XPowersLibInterface *PMU;
-extern bool pmuInterrupt;
-void loopPMU(void (*pressed_cb)(void));
-bool beginPower();
-void disablePeripherals();
-#else
-#define beginPower()
-#define disablePeripherals()
-#endif
-
-#ifdef DISPLAY_MODEL
-extern U8G2 *disp;
-#define U8G2_HOR_ALIGN_CENTER(t) ((disp->getDisplayWidth() - (disp->getUTF8Width(t))) / 2)
-#define U8G2_HOR_ALIGN_RIGHT(t) ( disp->getDisplayWidth() - disp->getUTF8Width(t))
-#endif
-
-
-#if defined(ARDUINO_ARCH_ESP32)
-
-#if defined(HAS_SDCARD)
-extern SPIClass SDCardSPI;
-#endif
-
-#define SerialGPS Serial1
-#elif defined(ARDUINO_ARCH_STM32)
-extern HardwareSerial SerialGPS;
-#endif
-
-#ifdef NTC_PIN
-float getTempForNTC();
-#endif
-
-#ifdef ENABLE_BLE
-void setupBLE();
-#else
-#define setupBLE()
-#endif
-
-extern uint32_t deviceOnline;
diff --git a/examples/Sensor/QMC6310_GetPolarExample/QMC6310_GetPolarExample.ino b/examples/Sensor/QMC6310_GetPolarExample/QMC6310_GetPolarExample.ino
deleted file mode 100644
index 4e4d5ad..0000000
--- a/examples/Sensor/QMC6310_GetPolarExample/QMC6310_GetPolarExample.ino
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- *
- * @license MIT License
- *
- * Copyright (c) 2022 lewis he
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * @file QMC6310_GetPolarExample.ino
- * @author Lewis He (lewishe@outlook.com)
- * @date 2022-10-16
- *
- */
-#include
-#include
-#include
-#include "SensorQMC6310.hpp"
-#include "LoRaBoards.h"
-
-SensorQMC6310 qmc;
-
-void setup()
-{
- Serial.begin(115200);
- while (!Serial);
-
- setupBoards();
-
- // For QMC6310U, the device address is 0x1C.
- // For QMC6310N, the device address is 0x3C.
- // The sensor device address is provided by the setupBoards I2C scanner.
- extern uint8_t mag_address;
- if (!qmc.begin(Wire, mag_address, I2C_SDA, I2C_SCL)) {
- Serial.println("Failed to find QMC6310 - check your wiring!");
- while (1) {
- delay(1000);
- }
- }
-
- /* Get Magnetometer chip id*/
- Serial.print("Device ID:");
- Serial.println(qmc.getChipID(), HEX);
-
- /* Config Magnetometer */
- qmc.configMagnetometer(
- /*
- * Run Mode
- * MODE_SUSPEND
- * MODE_NORMAL
- * MODE_SINGLE
- * MODE_CONTINUOUS
- * * */
- SensorQMC6310::MODE_NORMAL,
- /*
- * Full Range
- * RANGE_30G
- * RANGE_12G
- * RANGE_8G
- * RANGE_2G
- * * */
- SensorQMC6310::RANGE_8G,
- /*
- * Output data rate
- * DATARATE_10HZ
- * DATARATE_50HZ
- * DATARATE_100HZ
- * DATARATE_200HZ
- * * */
- SensorQMC6310::DATARATE_200HZ,
- /*
- * Over sample Ratio1
- * OSR_8
- * OSR_4
- * OSR_2
- * OSR_1
- * * * */
- SensorQMC6310::OSR_8,
-
- /*
- * Down sample Ratio1
- * DSR_8
- * DSR_4
- * DSR_2
- * DSR_1
- * * */
- SensorQMC6310::DSR_1);
-
- qmc.dumpCtrlRegister();
-
- // Declination is the difference between magnetic-north and true-north ("heading") and depends on location
- qmc.setDeclination(-2.77); // Found with: https://www.magnetic-declination.com/CHINA/SHENZHEN/475119.html
-
- Serial.println("Read data now...");
-}
-
-void loop()
-{
- Polar data;
- // Wait for data ready
- if (qmc.readPolar(data)) {
- Serial.print(" polar:"); Serial.print(data.polar); Serial.print("°");
- Serial.print(" Gauss:"); Serial.print(data.Gauss);
- Serial.print(" uT:"); Serial.println(data.uT);
- }
-
- delay(100);
-}
-
-
-
diff --git a/examples/Sensor/QMC6310_GetPolarExample/utilities.h b/examples/Sensor/QMC6310_GetPolarExample/utilities.h
deleted file mode 100644
index 08b2145..0000000
--- a/examples/Sensor/QMC6310_GetPolarExample/utilities.h
+++ /dev/null
@@ -1,780 +0,0 @@
-/**
- * @file utilities.h
- * @author Lewis He (lewishe@outlook.com)
- * @license MIT
- * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
- * @date 2024-05-12
- * @last-update 2025-07-07
- */
-#pragma once
-
-
-// Support board list , Macro definition below, select the board definition to be used
-// 将要使用的板子型号注释打开,只能打开一个型号,如果不明白自己买的型号是什么,请找客服核对型号
-
-/*********************************** Model definition start 型号定义起始 ***********************************/
-
-// 1. --------------T3 V1.3 -------------------------------
-// https://lilygo.cc/products/lora-v1-3
-// #define T3_V1_3_SX1276
-// #define T3_V1_3_SX1278
-
-// 2. --------------T3 V1.6.1 -------------------------------
-// https://lilygo.cc/products/lora3
-
-// #define T3_V1_6_SX1276
-// #define T3_V1_6_SX1278
-
-// 3. --------------T3 V3.0 TCXO-------------------------------
-// Product: https://lilygo.cc/products/t3-tcxo
-
-// #define T3_V3_0_SX1276_TCXO
-
-// 4. --------------T-BEAM ESP32-------------------------------
-// Product: https://lilygo.cc/products/t-beam
-
-// #define T_BEAM_SX1262
-// #define T_BEAM_SX1276
-// #define T_BEAM_SX1278
-// #define T_BEAM_LR1121
-
-// 5. --------------T-BEAM S3------------------------------
-// Product: https://lilygo.cc/products/t-beam-supreme
-
-// #define T_BEAM_S3_SUPREME_SX1262
-// #define T_BEAM_S3_SUPREME_LR1121
-
-// 6. --------------T3 S3 V1.0 or T3 S3 V1.3 -------------------
-// Product: https://lilygo.cc/products/t3s3-v1-0 , same v1.3
-// Product: https://lilygo.cc/products/t3-s3-v1-3
-
-// #define T3_S3_V1_2_SX1262
-// #define T3_S3_V1_2_SX1276
-// #define T3_S3_V1_2_SX1278
-// #define T3_S3_V1_2_SX1280
-// #define T3_S3_V1_2_SX1280_PA
-// #define T3_S3_V1_2_LR1121
-// #define T3_S3_V1_2_LR1121_PA
-
-// 7. --------------T-Motion -------------------------------------
-// Product: https://lilygo.cc/products/t-motion-s76g-stm32-lora
-
-// #define T_MOTION
-
-// --------------T3 C6 -------------------------------------
-// Product: https://lilygo.cc/products/t-lora-c6
-
-// #define T3_C6
-
-
-// --------------T-Beam BPF -------------------------------------
-// Product: https://lilygo.cc/products/t-beam-bpf
-// #define T_BEAM_S3_BPF
-
-// --------------LoRa 2W -------------------------------------
-// Product: ...
-// #define T_BEAM_1W
-
-
-
-// #define T3_V1_6_SX1276_TCXO // Production has stopped
-
-/*********************************** Model definition end 型号定义结尾 ***********************************/
-
-
-#define UNUSED_PIN (0)
-
-#if defined(T_BEAM_SX1262) || defined(T_BEAM_SX1276) || defined(T_BEAM_SX1278) || defined(T_BEAM_LR1121)
-
-
-#if defined(T_BEAM_SX1262)
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-#elif defined(T_BEAM_SX1276)
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#elif defined(T_BEAM_SX1278)
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-#elif defined(T_BEAM_LR1121)
-#ifndef USING_LR1121
-#define USING_LR1121
-#endif
-#endif // T_BEAM_SX1262
-
-
-#define GPS_RX_PIN 34
-#define GPS_TX_PIN 12
-#define BUTTON_PIN 38
-#define BUTTON_PIN_MASK GPIO_SEL_38
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define PMU_IRQ 35
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 23
-#define RADIO_DIO1_PIN 33
-// SX1276/78
-#define RADIO_DIO2_PIN 32
-// SX1262
-#define RADIO_BUSY_PIN 32
-
-// LR1121 Only
-#define RADIO_DIO9_PIN 33
-
-
-#define BOARD_LED 4
-#define LED_ON LOW
-#define LED_OFF HIGH
-
-#define BUTTON_PIN 38
-
-#define GPS_BAUD_RATE 9600
-#define HAS_GPS
-#define HAS_DISPLAY //Optional, bring your own board, no OLED !!
-#define HAS_PMU
-
-#define PMU_WIRE_PORT Wire
-#define BOARD_VARIANT_NAME "T-Beam"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-
-#elif defined(T3_V1_3_SX1276) || defined(T3_V1_3_SX1278)
-
-
-#if defined(T3_V1_3_SX1276)
-
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-
-#elif defined(T3_V1_3_SX1278)
-
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-
-#endif // T3_V1_3_SX1276
-
-
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 14
-#define RADIO_DIO1_PIN 33
-
-// SX1276/78
-#define RADIO_DIO2_PIN 32
-// SX1262
-#define RADIO_BUSY_PIN 32
-
-
-#define ADC_PIN 35
-#define HAS_DISPLAY
-#define BOARD_VARIANT_NAME "T3 V1.3"
-
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_V1_6_SX1276) || defined(T3_V1_6_SX1278)
-
-
-#if defined(T3_V1_6_SX1276)
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#elif defined(T3_V1_6_SX1278)
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-#endif // T3_V1_6_SX1276
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 23
-#define RADIO_DIO1_PIN 33
-// SX1276/78
-#define RADIO_DIO2_PIN 32
-// SX1262
-#define RADIO_BUSY_PIN 32
-
-#define SDCARD_MOSI 15
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 25
-#define LED_ON HIGH
-
-#define ADC_PIN 35
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3 V1.6"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_V1_6_SX1276_TCXO)
-
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_DIO0_PIN 26
-#define RADIO_RST_PIN 23
-#define RADIO_DIO1_PIN -1//33
-/*
-* In the T3 V1.6.1 TCXO version, Radio DIO1 is connected to Radio’s
-* internal temperature-compensated crystal oscillator enable
-* */
-// TCXO pin must be set to HIGH before enabling Radio
-#define RADIO_TCXO_ENABLE 33
-#define RADIO_BUSY_PIN 32
-
-#define SDCARD_MOSI 15
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 25
-#define LED_ON HIGH
-
-#define ADC_PIN 35
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3 V1.6 TCXO"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_V3_0) || defined(T3_V3_0_SX1276_TCXO)
-
-#ifdef T3_V3_0_SX1276_TCXO
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#endif
-
-
-#define I2C_SDA 21
-#define I2C_SCL 22
-#define OLED_RST 4
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 19
-#define RADIO_MOSI_PIN 27
-#define RADIO_CS_PIN 18
-#define RADIO_RST_PIN 23
-
-// TCXO pin must be set to HIGH before enabling Radio
-#define RADIO_TCXO_ENABLE 12 //only sx1276 tcxo version
-#define RADIO_BUSY_PIN 32
-
-
-#if defined(USING_SX1262)
-
-#define RADIO_DIO1_PIN 26
-#define RADIO_BUSY_PIN 32
-
-#elif defined(USING_SX1276) || defined(USING_SX1278)
-//!SX1276/78 module only
-
-#define RADIO_DIO0_PIN 26
-#define RADIO_DIO1_PIN 32
-
-#elif defined(USING_LR1121)
-
-#define RADIO_DIO9_PIN 26 //LR1121 DIO9
-#define RADIO_BUSY_PIN 32 //LR1121 BUSY
-
-#endif
-
-#define SDCARD_MOSI 15
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 25
-#define LED_ON HIGH
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3 V3.0"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-#define BUTTON_PIN 0
-#define ADC_PIN 35
-
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#elif defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262) || \
- defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276) || \
- defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278) || \
- defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280) || \
- defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA) || \
- defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121) || \
- defined(T3_S3_V1_2_LR1121_PA) || defined(ARDUINO_LILYGO_T3S3_LR1121PA)
-
-
-#if defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262)
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-#elif defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276)
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-#elif defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278)
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-#elif defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280)
-#ifndef USING_SX1280
-#define USING_SX1280
-#endif
-#elif defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA)
-#ifndef USING_SX1280PA
-#define USING_SX1280PA
-#endif
-#elif defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121)
-#ifndef USING_LR1121
-#define USING_LR1121
-#endif
-#elif defined(T3_S3_V1_2_LR1121_PA) || defined(ARDUINO_LILYGO_T3S3_LR1121PA)
-#ifndef USING_LR1121PA
-#define USING_LR1121PA
-#endif
-#endif // T3_S3_V1_2_SX1262
-
-
-#define I2C_SDA 18
-#define I2C_SCL 17
-#define OLED_RST UNUSED_PIN
-
-#define RADIO_SCLK_PIN 5
-#define RADIO_MISO_PIN 3
-#define RADIO_MOSI_PIN 6
-#define RADIO_CS_PIN 7
-
-#define SDCARD_MOSI 11
-#define SDCARD_MISO 2
-#define SDCARD_SCLK 14
-#define SDCARD_CS 13
-
-#define BOARD_LED 37
-#define LED_ON HIGH
-
-#define BUTTON_PIN 0
-#define ADC_PIN 1
-
-#define RADIO_RST_PIN 8
-
-#define BAT_ADC_PULLUP_RES (100000.0)
-#define BAT_ADC_PULLDOWN_RES (100000.0)
-#define BAT_MAX_VOLTAGE (4.2)
-#define BAT_VOL_COMPENSATION (0.0)
-
-#if defined(USING_SX1262)
-
-#define RADIO_DIO1_PIN 33
-#define RADIO_BUSY_PIN 34
-
-#elif defined(USING_SX1276) || defined(USING_SX1278)
-//!SX1276/78 module only
-#define RADIO_BUSY_PIN 33 //DIO1
-
-#define RADIO_DIO0_PIN 9
-#define RADIO_DIO1_PIN 33
-#define RADIO_DIO2_PIN 34
-#define RADIO_DIO3_PIN 21
-#define RADIO_DIO4_PIN 10
-#define RADIO_DIO5_PIN 36
-
-#elif defined(USING_SX1280)
-
-#define RADIO_DIO1_PIN 9 //SX1280 DIO1 = IO9
-#define RADIO_BUSY_PIN 36 //SX1280 BUSY = IO36
-
-#elif defined(USING_SX1280PA)
-
-#define RADIO_DIO1_PIN 9 //SX1280 DIO1 = IO9
-#define RADIO_BUSY_PIN 36 //SX1280 BUSY = IO36
-#define RADIO_RX_PIN 21
-#define RADIO_TX_PIN 10
-
-
-#elif defined(USING_LR1121)
-
-#define RADIO_DIO9_PIN 36 //LR1121 DIO9 = IO36
-#define RADIO_BUSY_PIN 34 //LR1121 BUSY = IO34
-
-#define LILYGO_RADIO_2G4_TX_POWER_LIMIT 13 //LR1121 2.4G TX Power Limit
-
-#elif defined(USING_LR1121PA)
-
-#define RADIO_DIO9_PIN 36 //LR1121 DIO9 = IO36
-#define RADIO_BUSY_PIN 34 //LR1121 BUSY = IO34
-
-#define LILYGO_RADIO_2G4_TX_POWER_LIMIT 0 //LR1121 2.4G TX Power Limit
-#define USING_LR1121
-
-#endif
-
-#define BUTTON_PIN 0
-
-#define HAS_SDCARD
-#define HAS_DISPLAY
-
-#define BOARD_VARIANT_NAME "T3-S3-V1.X"
-#define DISPLAY_MODEL_SSD_LIB SSD1306Wire
-#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
-
-#elif defined(T_BEAM_S3_SUPREME_SX1262) || defined(T_BEAM_S3_SUPREME_LR1121)
-
-#ifndef T_BEAM_S3_SUPREME
-#define T_BEAM_S3_SUPREME
-#endif
-
-#if defined(T_BEAM_S3_SUPREME_SX1262)
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-#elif defined(T_BEAM_S3_SUPREME_LR1121)
-#ifndef USING_LR1121
-#define USING_LR1121
-#endif
-#endif
-
-#define I2C_SDA (17)
-#define I2C_SCL (18)
-
-#define I2C1_SDA (42)
-#define I2C1_SCL (41)
-#define PMU_IRQ (40)
-
-#define GPS_RX_PIN (9)
-#define GPS_TX_PIN (8)
-#define GPS_EN_PIN (7)
-#define GPS_PPS_PIN (6)
-
-#define BUTTON_PIN (0)
-#define BUTTON_PIN_MASK (GPIO_SEL_0)
-#define BUTTON_COUNT (1)
-#define BUTTON_ARRAY {BUTTON_PIN}
-
-#define RADIO_SCLK_PIN (12)
-#define RADIO_MISO_PIN (13)
-#define RADIO_MOSI_PIN (11)
-#define RADIO_CS_PIN (10)
-#define RADIO_DIO0_PIN (-1)
-#define RADIO_RST_PIN (5)
-#define RADIO_DIO1_PIN (1)
-#define RADIO_BUSY_PIN (4)
-
-// LR1121 Version
-#define RADIO_DIO9_PIN (1)
-
-#define SPI_MOSI (35)
-#define SPI_SCK (36)
-#define SPI_MISO (37)
-#define SPI_CS (47)
-#define IMU_CS (34)
-#define IMU_INT (33)
-
-#define SDCARD_MOSI SPI_MOSI
-#define SDCARD_MISO SPI_MISO
-#define SDCARD_SCLK SPI_SCK
-#define SDCARD_CS SPI_CS
-
-#define RTC_INT (14)
-
-#define GPS_BAUD_RATE (9600)
-
-#define HAS_SDCARD
-#define HAS_GPS
-#define HAS_DISPLAY
-#define HAS_PMU
-
-#define __HAS_SPI1__
-#define HAS_SENSOR
-
-#define PMU_WIRE_PORT Wire1
-#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
-#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "T-Beam S3"
-
-#elif defined(T_MOTION_S76G)
-
-#ifndef USING_SX1276
-#define USING_SX1276
-#endif
-
-
-#define RADIO_SCLK_PIN PB13
-#define RADIO_MISO_PIN PB14
-#define RADIO_MOSI_PIN PB15
-#define RADIO_CS_PIN PB12
-#define RADIO_RST_PIN PB10
-
-#define RADIO_DIO0_PIN PB11
-#define RADIO_DIO1_PIN PC13
-#define RADIO_DIO2_PIN PB9
-#define RADIO_DIO3_PIN PB4
-#define RADIO_DIO4_PIN PB3
-#define RADIO_DIO5_PIN PA15
-
-#undef RADIO_BUSY_PIN
-#undef RADIO_DIO1_PIN
-#define RADIO_BUSY_PIN PC13 //DIO1
-#define RADIO_DIO1_PIN PB11 //DIO0
-
-#define RADIO_SWITCH_PIN PA1 //1:Rx, 0:Tx
-
-#define GPS_EN_PIN PC6
-#define GPS_RST_PIN PB2
-#define GPS_RX_PIN PC11
-#define GPS_TX_PIN PC10
-#define GPS_ENABLE_PIN PC6
-#define GPS_BAUD_RATE 115200
-#define GPS_PPS_PIN PB5
-
-#define UART_RX_PIN PA10
-#define UART_TX_PIN PA9
-
-#define I2C_SCL PB6
-#define I2C_SDA PB7
-
-#define BOARD_VARIANT_NAME "T-Motion S76G"
-
-#define HAS_GPS
-
-#elif defined(T3_C6)
-
-
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-
-
-#define RADIO_SCLK_PIN 6
-#define RADIO_MISO_PIN 1
-#define RADIO_MOSI_PIN 0
-#define RADIO_CS_PIN 18
-#define RADIO_DIO1_PIN 23
-#define RADIO_BUSY_PIN 22
-#define RADIO_RST_PIN 21
-
-#define I2C_SDA 8
-#define I2C_SCL 9
-
-#define BOARD_LED 7
-#define LED_ON HIGH
-#define RADIO_RX_PIN 15
-#define RADIO_TX_PIN 14
-
-
-#define BOARD_VARIANT_NAME "T3-C6"
-
-#define USING_DIO2_AS_RF_SWITCH
-
-
-#elif defined(T_BEAM_S3_BPF)
-
-
-#ifndef USING_SX1278
-#define USING_SX1278
-#endif
-
-#define I2C_SDA (8)
-#define I2C_SCL (9)
-
-#define PMU_IRQ (4)
-
-#define GPS_RX_PIN (5)
-#define GPS_TX_PIN (6)
-#define GPS_PPS_PIN (7)
-
-#define BUTTON_PIN (0)
-#define BUTTON2_PIN (3) /*BUTTON 2 = GPIO3*/
-#define BUTTON_PIN_MASK GPIO_SEL_0 /*BUTTON 1 = GPIO0*/
-#define BUTTON_COUNT (2)
-#define BUTTON_ARRAY {BUTTON_PIN, BUTTON2_PIN /*BUTTON 2 = GPIO3*/}
-
-#define RADIO_SCLK_PIN (12)//(41)
-#define RADIO_MISO_PIN (13)//(42)
-#define RADIO_MOSI_PIN (11)//(2)
-#define RADIO_CS_PIN (1)
-#define RADIO_RST_PIN (18)
-
-#define RADIO_DIO0_PIN (14)
-#define RADIO_DIO1_PIN (21)
-
-// #define RADIO_TCXO_ENABLE (17)
-#define RADIO_LDO_EN (16)
-#define RADIO_CTRL (39)
-
-#define SPI_MOSI (11)
-#define SPI_SCK (12)
-#define SPI_MISO (13)
-#define SPI_CS (10)
-
-#define SDCARD_MOSI SPI_MOSI
-#define SDCARD_MISO SPI_MISO
-#define SDCARD_SCLK SPI_SCK
-#define SDCARD_CS SPI_CS
-
-
-#define GPS_BAUD_RATE 9600
-
-#define HAS_SDCARD
-#define HAS_GPS
-#define HAS_DISPLAY
-#define HAS_PMU
-#define SD_SHARE_SPI_BUS
-
-#define PMU_WIRE_PORT Wire
-#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
-#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "T-Beam BPF"
-
-
-#elif defined(T_BEAM_1W)
-
-#ifndef USING_SX1262
-#define USING_SX1262
-#endif
-
-#define I2C_SDA (8)
-#define I2C_SCL (9)
-
-#define GPS_RX_PIN (5)
-#define GPS_TX_PIN (6)
-#define GPS_PPS_PIN (7)
-#define GPS_EN_PIN (16)
-
-#define BUTTON_PIN (0) /*BUTTON 1 = GPIO0*/
-#define BUTTON2_PIN (17) /*BUTTON 2 = GPIO17*/
-
-#define BUTTON_PIN_MASK GPIO_SEL_0
-#define BUTTON_COUNT (2)
-#define BUTTON_ARRAY {BUTTON_PIN,BUTTON2_PIN/*BUTTON 2 = GPIO3*/}
-
-#define SPI_MOSI (11)
-#define SPI_SCK (13)
-#define SPI_MISO (12)
-#define SPI_CS (10)
-
-#define SDCARD_CS SPI_CS
-
-#define RADIO_SCLK_PIN (SPI_SCK)
-#define RADIO_MISO_PIN (SPI_MISO)
-#define RADIO_MOSI_PIN (SPI_MOSI)
-
-#define RADIO_CS_PIN (15)
-#define RADIO_RST_PIN (3)
-#define RADIO_LDO_EN (40)
-#define RADIO_CTRL (21)
-#define RADIO_DIO1_PIN (1)
-#define RADIO_BUSY_PIN (38)
-
-#define BOARD_LED 18
-#define LED_ON HIGH
-#define LED_OFF LOW
-
-
-#define NTC_PIN (14)
-#define FAN_CTRL (41)
-#define ADC_PIN (4)
-
-#define BAT_ADC_PULLUP_RES (300000.0)
-#define BAT_ADC_PULLDOWN_RES (150000.0)
-#define BAT_MAX_VOLTAGE (7.4)
-#define BAT_VOL_COMPENSATION (0.25)
-#define GPS_SLEEP_HOLD_ON_LOW
-
-#define GPS_BAUD_RATE 9600
-
-#define HAS_SDCARD
-#define HAS_GPS
-#define HAS_DISPLAY
-#define SD_SHARE_SPI_BUS // SD-CARD AND RADIO SHARE SPI BUS
-#define __HAS_SPI1__
-
-#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C
-#define DISPLAY_MODEL_SSD_LIB SH1106Wire
-#define BOARD_VARIANT_NAME "LoRa 2W"
-
-#else
-#error "When using it for the first time, please define the board model in 首次使用时,请在 文件最上方定义板卡模型"
-#endif
-
-
-
-
-
-#if defined(USING_SX1262)
-#define RADIO_TYPE_STR "SX1262"
-#elif defined(USING_SX1276)
-#define RADIO_TYPE_STR "SX1276"
-#elif defined(USING_SX1278)
-#define RADIO_TYPE_STR "SX1278"
-#elif defined(USING_LR1121)
-#define RADIO_TYPE_STR "LR1121"
-#elif defined(USING_SX1280)
-#define RADIO_TYPE_STR "SX1280"
-#elif defined(USING_SX1280PA)
-#define RADIO_TYPE_STR "SX1280PA"
-#endif
-
-
-
-
-
diff --git a/examples/Sensor/QMC6310_GetPolarExample/LoRaBoards.cpp b/examples/Sensor/QMC63xx_GetDataExample/LoRaBoards.cpp
similarity index 99%
rename from examples/Sensor/QMC6310_GetPolarExample/LoRaBoards.cpp
rename to examples/Sensor/QMC63xx_GetDataExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMC6310_GetPolarExample/LoRaBoards.cpp
+++ b/examples/Sensor/QMC63xx_GetDataExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMC6310_CompassExample/LoRaBoards.h b/examples/Sensor/QMC63xx_GetDataExample/LoRaBoards.h
similarity index 97%
rename from examples/Sensor/QMC6310_CompassExample/LoRaBoards.h
rename to examples/Sensor/QMC63xx_GetDataExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMC6310_CompassExample/LoRaBoards.h
+++ b/examples/Sensor/QMC63xx_GetDataExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMC63xx_GetDataExample/QMC63xx_GetDataExample.ino b/examples/Sensor/QMC63xx_GetDataExample/QMC63xx_GetDataExample.ino
new file mode 100644
index 0000000..6bba26e
--- /dev/null
+++ b/examples/Sensor/QMC63xx_GetDataExample/QMC63xx_GetDataExample.ino
@@ -0,0 +1,357 @@
+/**
+ *
+ * @license MIT License
+ *
+ * Copyright (c) 2026 lewis he
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @file QMC63xx_GetDataExample.ino
+ * @author Lewis He (lewishe@outlook.com)
+ * @date 2026-04-08
+ *
+ */
+#include
+#include
+#include
+#include "LoRaBoards.h"
+
+void calibrate();
+MagnetometerBase *magnetometer;
+
+void setup()
+{
+ Serial.begin(115200);
+ while (!Serial);
+
+ setupBoards();
+
+ // The desired output data rate in Hz. Allowed values are 1.0, 10.0, 50.0, 100.0 and 200.0HZ.
+ float data_rate_hz = 200.0f;
+ // op_mode: Allowed values are SUSPEND, NORMAL, SINGLE_MEASUREMENT, CONTINUOUS_MEASUREMENT
+ OperationMode op_mode = OperationMode::CONTINUOUS_MEASUREMENT;
+ // full_scale: Allowed values are FS_8G, FS_16G ,FS_32G
+ MagFullScaleRange full_scale = MagFullScaleRange::FS_8G;
+ // over_sample_ratio: Allowed values are OSR_1, OSR_2, OSR_4, OSR_8
+ MagOverSampleRatio over_sample_ratio = MagOverSampleRatio::OSR_1;
+ // down_sample_ratio: QMC6309 does not support downsampling rate settings; this parameter is ignored.
+ MagDownSampleRatio down_sample_ratio = MagDownSampleRatio::DSR_1;
+
+
+
+ SensorWireHelper::dumpDevices(Wire);
+
+ if (magnetometer == nullptr) {
+ magnetometer = new SensorQMC6310();
+ if (!static_cast(magnetometer)->begin(Wire, QMC6310U_SLAVE_ADDRESS, I2C_SDA, I2C_SCL)) {
+ Serial.println("Failed to find QMC6310U - check your wiring!");
+ delete magnetometer;
+ magnetometer = nullptr;
+ } else {
+ Serial.println("QMC6310U found!");
+ // The desired output data rate in Hz. Allowed values are 10.0, 50.0, 100.0 and 200.0HZ.
+ data_rate_hz = 200.0f;
+ // op_mode: Allowed values are SUSPEND, NORMAL, SINGLE_MEASUREMENT, CONTINUOUS_MEASUREMENT
+ op_mode = OperationMode::CONTINUOUS_MEASUREMENT;
+ // full_scale: Allowed values are FS_2G, FS_8G, FS_12G ,FS_30G
+ full_scale = MagFullScaleRange::FS_8G;
+ // over_sample_ratio: Allowed values are OSR_1, OSR_2, OSR_4, OSR_8
+ over_sample_ratio = MagOverSampleRatio::OSR_1;
+ // down_sample_ratio: Allowed values are DSR_1, DSR_2, DSR_4, DSR_8
+ down_sample_ratio = MagDownSampleRatio::DSR_1;
+ }
+ }
+
+ if (magnetometer == nullptr) {
+ magnetometer = new SensorQMC6310();
+ if (!static_cast(magnetometer)->begin(Wire, QMC6310N_SLAVE_ADDRESS, I2C_SDA, I2C_SCL)) {
+ Serial.println("Failed to find QMC6310 - check your wiring!");
+ delete magnetometer;
+ magnetometer = nullptr;
+ } else {
+ Serial.println("QMC6310N found!");
+ // The desired output data rate in Hz. Allowed values are 10.0, 50.0, 100.0 and 200.0HZ.
+ data_rate_hz = 200.0f;
+ // op_mode: Allowed values are SUSPEND, NORMAL, SINGLE_MEASUREMENT, CONTINUOUS_MEASUREMENT
+ op_mode = OperationMode::CONTINUOUS_MEASUREMENT;
+ // full_scale: Allowed values are FS_2G, FS_8G, FS_12G ,FS_30G
+ full_scale = MagFullScaleRange::FS_8G;
+ // over_sample_ratio: Allowed values are OSR_1, OSR_2, OSR_4, OSR_8
+ over_sample_ratio = MagOverSampleRatio::OSR_1;
+ // down_sample_ratio: Allowed values are DSR_1, DSR_2, DSR_4, DSR_8
+ down_sample_ratio = MagDownSampleRatio::DSR_1;
+ }
+ }
+
+ if (magnetometer == nullptr) {
+ magnetometer = new SensorQMC6309();
+ if (!static_cast(magnetometer)->begin(Wire, QMC6309_SLAVE_ADDRESS, I2C_SDA, I2C_SCL)) {
+ Serial.println("Failed to find QMC6309 - check your wiring!");
+ delete magnetometer;
+ magnetometer = nullptr;
+ } else {
+ Serial.println("QMC6309 found!");
+ // The desired output data rate in Hz. Allowed values are 1.0, 10.0, 50.0, 100.0 and 200.0HZ.
+ data_rate_hz = 200.0f;
+ // op_mode: Allowed values are SUSPEND, NORMAL, SINGLE_MEASUREMENT, CONTINUOUS_MEASUREMENT
+ op_mode = OperationMode::CONTINUOUS_MEASUREMENT;
+ // full_scale: Allowed values are FS_8G, FS_16G ,FS_32G
+ full_scale = MagFullScaleRange::FS_8G;
+ // over_sample_ratio: Allowed values are OSR_1, OSR_2, OSR_4, OSR_8
+ over_sample_ratio = MagOverSampleRatio::OSR_1;
+ // down_sample_ratio: QMC6309 does not support downsampling rate settings; this parameter is ignored.
+ down_sample_ratio = MagDownSampleRatio::DSR_1;
+ }
+ }
+
+ while (magnetometer == nullptr) {
+ Serial.println("No magnetometer found!");
+ delay(1000);
+ }
+
+ /* Config Magnetometer */
+ if (magnetometer->configMagnetometer(
+ op_mode,
+ full_scale,
+ data_rate_hz,
+ over_sample_ratio,
+ down_sample_ratio)) {
+ Serial.println("Magnetometer configured successfully.");
+ } else {
+ Serial.println("Magnetometer configuration failed.");
+ while (1);
+ }
+
+
+
+
+ // Calibration algorithm reference from
+ // https://github.com/CoreElectronics/CE-PiicoDev-QMC6310-MicroPython-Module
+ calibrate();
+
+ Serial.println("Calibration done.");
+ delay(5000);
+
+
+
+ SensorInfo info = magnetometer->getSensorInfo();
+ Serial.print("Manufacturer: "); Serial.println(info.manufacturer);
+ Serial.print("Model: "); Serial.println(info.model);
+ Serial.print("I2C Address: 0x"); Serial.println(info.i2c_address, HEX);
+ Serial.print("Version: "); Serial.println(info.version);
+ Serial.print("UID: 0x"); Serial.println(info.uid);
+ Serial.print("Type: "); Serial.println(SensorUtils::typeToString(info.type));
+
+ SensorConfig cfg = magnetometer->getConfig();
+ Serial.print("DataRate: "); Serial.println(cfg.sample_rate);
+ Serial.print("FullScaleRange: "); Serial.println(cfg.range);
+ Serial.print("Mode: "); Serial.println((uint8_t)cfg.mode);
+ Serial.println();
+
+ //Find the magnetic declination : https://www.magnetic-declination.com/
+ float declination_deg = MagnetometerUtils::dmsToDecimalDegrees(-3, 20); // -3.3333
+
+ magnetometer->setDeclination(declination_deg);
+
+ Serial.print(" Magnetic Declination: ");
+ Serial.print(declination_deg, 2);
+ Serial.println("°");
+
+ Serial.print(" Sensitivity: ");
+ Serial.print(magnetometer->getSensitivity(), 6);
+ Serial.println(" Gauss/LSB");
+
+ delay(3000);
+
+ Serial.println("Read data now...");
+}
+
+void loop()
+{
+
+ MagnetometerData data;
+
+ if (magnetometer->readData(data)) {
+
+ // Gauss to μT
+ float x = MagnetometerUtils::gaussToMicroTesla(data.magnetic_field.x);
+ float y = MagnetometerUtils::gaussToMicroTesla(data.magnetic_field.y);
+ float z = MagnetometerUtils::gaussToMicroTesla(data.magnetic_field.z);
+
+ Serial.print("Mag:");
+ Serial.print(" X:"); Serial.print(x);
+ Serial.print(" Y:"); Serial.print(y);
+ Serial.print(" Z:"); Serial.print(z);
+ Serial.print(" μT");
+
+ Serial.print(" Metadata:");
+ Serial.print(" X:");
+ Serial.print(data.raw.x);
+ Serial.print(" Y:");
+ Serial.print(data.raw.y);
+ Serial.print(" Z:");
+ Serial.print(data.raw.z);
+
+ Serial.print(" Heading (rad): ");
+ Serial.print(data.heading, 6);
+ Serial.print(" rad");
+
+ Serial.print(" Heading (deg): ");
+ Serial.print(data.heading_degrees, 2);
+ Serial.print("°");
+
+ float strength = MagnetometerUtils::calculateMagneticStrength(data);
+ strength = MagnetometerUtils::gaussToMicroTesla(strength);
+ Serial.print(" Magnetic Strength: ");
+ Serial.print(strength, 2);
+ Serial.println(" μT");
+
+ if (data.overflow) {
+ Serial.println("\tWarning: Data Overflow occurred!");
+ }
+ }
+ delay(10);
+}
+
+
+
+
+void calibrate()
+{
+ if (!magnetometer)return;
+
+ if (!magnetometer->setOutputDataRate(200.0f)) {
+ Serial.println("Failed to set output data rate");
+ return ;
+ }
+
+ Serial.println("========================================");
+ Serial.println("Calibration Instructions:");
+ Serial.println("1. Rotate sensor in FIGURE-8 pattern");
+ Serial.println("2. Cover all axes (X, Y, Z directions)");
+ Serial.println("3. Rotate slowly and completely");
+ Serial.println("4. Wait for progress bar to complete");
+ Serial.println("5. Expected: Magnetic Strength ~25-65 uT");
+ Serial.println("========================================");
+ Serial.println();
+
+ Serial.println("Place the sensor on the plane and slowly rotate the sensor...");
+ Serial.println("Rotate in FIGURE-8 pattern to cover all directions!");
+ Serial.println();
+
+ int32_t x_min = 65535;
+ int32_t x_max = -65535;
+ int32_t y_min = 65535;
+ int32_t y_max = -65535;
+ int32_t z_min = 65535;
+ int32_t z_max = -65535;
+
+ int32_t range = 1000;
+ int32_t i = 0;
+ int32_t x = 0, y = 0, z = 0;;
+ int16_t x_offset = 0;
+ int16_t y_offset = 0;
+ int16_t z_offset = 0;
+
+ MagnetometerData data;
+ while (i < range) {
+ i += 1;
+
+ if (magnetometer->isDataReady()) {
+
+ magnetometer->readData(data);
+
+ x = (data.raw.x + x) / 2;
+ y = (data.raw.y + y) / 2;
+ z = (data.raw.z + z) / 2;
+ if (x < x_min) {
+ x_min = x;
+ i = 0;
+ }
+ if (x > x_max) {
+ x_max = x;
+ i = 0;
+ }
+ if (y < y_min) {
+ y_min = y;
+ i = 0;
+ }
+ if (y > y_max) {
+ y_max = y;
+ i = 0;
+ }
+ if (z < z_min) {
+ z_min = z;
+ i = 0;
+ }
+ if (z > z_max) {
+ z_max = z;
+ i = 0;
+ }
+ int j = round(10 * i / range);
+
+ Serial.print("[");
+ for (int k = 0; k < j; ++k) {
+ Serial.print("*");
+ }
+ Serial.println("]");
+ }
+ delay(5);
+ }
+
+ x_offset = (x_max + x_min) / 2;
+ y_offset = (y_max + y_min) / 2;
+ z_offset = (z_max + z_min) / 2;
+
+ Serial.print("x_min:");
+ Serial.println(x_min);
+
+ Serial.print("x_max:");
+ Serial.println(x_max);
+
+ Serial.print("y_min:");
+ Serial.println(y_min);
+
+ Serial.print("y_max:");
+ Serial.println(y_max);
+
+ Serial.print("z_min:");
+ Serial.println(z_min);
+
+ Serial.print("z_max:");
+ Serial.println(z_max);
+
+ Serial.print("x_offset:");
+ Serial.println(x_offset);
+
+ Serial.print("y_offset:");
+ Serial.println(y_offset);
+
+ Serial.print("z_offset:");
+ Serial.println(z_offset);
+
+
+ // Set the calibration value and the user calculates the deviation
+ magnetometer->setOffset(x_offset, y_offset, z_offset);
+
+ Serial.println();
+ Serial.println("Calibration complete!");
+ Serial.println("Check if Magnetic Strength is ~25-65 uT");
+ Serial.println("If too low, repeat calibration with better rotation");
+}
\ No newline at end of file
diff --git a/examples/Sensor/QMC6310_CalibrateExample/utilities.h b/examples/Sensor/QMC63xx_GetDataExample/utilities.h
similarity index 100%
rename from examples/Sensor/QMC6310_CalibrateExample/utilities.h
rename to examples/Sensor/QMC63xx_GetDataExample/utilities.h
diff --git a/examples/Sensor/QMI8658_BlockExample/LoRaBoards.cpp b/examples/Sensor/QMI8658_BlockExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMI8658_BlockExample/LoRaBoards.cpp
+++ b/examples/Sensor/QMI8658_BlockExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMI8658_BlockExample/LoRaBoards.h b/examples/Sensor/QMI8658_BlockExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMI8658_BlockExample/LoRaBoards.h
+++ b/examples/Sensor/QMI8658_BlockExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMI8658_GetDataExample/LoRaBoards.cpp b/examples/Sensor/QMI8658_GetDataExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMI8658_GetDataExample/LoRaBoards.cpp
+++ b/examples/Sensor/QMI8658_GetDataExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMI8658_GetDataExample/LoRaBoards.h b/examples/Sensor/QMI8658_GetDataExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMI8658_GetDataExample/LoRaBoards.h
+++ b/examples/Sensor/QMI8658_GetDataExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMI8658_InterruptBlockExample/LoRaBoards.cpp b/examples/Sensor/QMI8658_InterruptBlockExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMI8658_InterruptBlockExample/LoRaBoards.cpp
+++ b/examples/Sensor/QMI8658_InterruptBlockExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMI8658_InterruptBlockExample/LoRaBoards.h b/examples/Sensor/QMI8658_InterruptBlockExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMI8658_InterruptBlockExample/LoRaBoards.h
+++ b/examples/Sensor/QMI8658_InterruptBlockExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMI8658_InterruptExample/LoRaBoards.cpp b/examples/Sensor/QMI8658_InterruptExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMI8658_InterruptExample/LoRaBoards.cpp
+++ b/examples/Sensor/QMI8658_InterruptExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMI8658_InterruptExample/LoRaBoards.h b/examples/Sensor/QMI8658_InterruptExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMI8658_InterruptExample/LoRaBoards.h
+++ b/examples/Sensor/QMI8658_InterruptExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMI8658_LockingMechanismExample/LoRaBoards.cpp b/examples/Sensor/QMI8658_LockingMechanismExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMI8658_LockingMechanismExample/LoRaBoards.cpp
+++ b/examples/Sensor/QMI8658_LockingMechanismExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMI8658_LockingMechanismExample/LoRaBoards.h b/examples/Sensor/QMI8658_LockingMechanismExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMI8658_LockingMechanismExample/LoRaBoards.h
+++ b/examples/Sensor/QMI8658_LockingMechanismExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMI8658_MadgwickAHRS/LoRaBoards.cpp b/examples/Sensor/QMI8658_MadgwickAHRS/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMI8658_MadgwickAHRS/LoRaBoards.cpp
+++ b/examples/Sensor/QMI8658_MadgwickAHRS/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMI8658_MadgwickAHRS/LoRaBoards.h b/examples/Sensor/QMI8658_MadgwickAHRS/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMI8658_MadgwickAHRS/LoRaBoards.h
+++ b/examples/Sensor/QMI8658_MadgwickAHRS/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMI8658_PedometerExample/LoRaBoards.cpp b/examples/Sensor/QMI8658_PedometerExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMI8658_PedometerExample/LoRaBoards.cpp
+++ b/examples/Sensor/QMI8658_PedometerExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMI8658_PedometerExample/LoRaBoards.h b/examples/Sensor/QMI8658_PedometerExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMI8658_PedometerExample/LoRaBoards.h
+++ b/examples/Sensor/QMI8658_PedometerExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMI8658_ReadFromFifoExample/LoRaBoards.cpp b/examples/Sensor/QMI8658_ReadFromFifoExample/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMI8658_ReadFromFifoExample/LoRaBoards.cpp
+++ b/examples/Sensor/QMI8658_ReadFromFifoExample/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMI8658_ReadFromFifoExample/LoRaBoards.h b/examples/Sensor/QMI8658_ReadFromFifoExample/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMI8658_ReadFromFifoExample/LoRaBoards.h
+++ b/examples/Sensor/QMI8658_ReadFromFifoExample/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/Sensor/QMI8658_WakeOnMotion/LoRaBoards.cpp b/examples/Sensor/QMI8658_WakeOnMotion/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/Sensor/QMI8658_WakeOnMotion/LoRaBoards.cpp
+++ b/examples/Sensor/QMI8658_WakeOnMotion/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/Sensor/QMI8658_WakeOnMotion/LoRaBoards.h b/examples/Sensor/QMI8658_WakeOnMotion/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/Sensor/QMI8658_WakeOnMotion/LoRaBoards.h
+++ b/examples/Sensor/QMI8658_WakeOnMotion/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/T3S3Factory/LoRaBoards.cpp b/examples/T3S3Factory/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/T3S3Factory/LoRaBoards.cpp
+++ b/examples/T3S3Factory/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/T3S3Factory/LoRaBoards.h b/examples/T3S3Factory/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/T3S3Factory/LoRaBoards.h
+++ b/examples/T3S3Factory/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/TBeamFactory/LoRaBoards.cpp b/examples/TBeamFactory/LoRaBoards.cpp
index 8acfe74..707005a 100644
--- a/examples/TBeamFactory/LoRaBoards.cpp
+++ b/examples/TBeamFactory/LoRaBoards.cpp
@@ -996,6 +996,11 @@ void scanDevices(TwoWire *w)
}
}
break;
+ case 0x7C:
+ Serial.printf("\tFound QMC6309 Sensor at address 0x%02X\n", addr);
+ mag_address = addr;
+ deviceOnline |= QMC6309_ONLINE;
+ break;
case 0x51:
Serial.printf("\tFound PCF8563 RTC at address 0x%02X\n", addr);
deviceOnline |= PCF8563_ONLINE;
diff --git a/examples/TBeamFactory/LoRaBoards.h b/examples/TBeamFactory/LoRaBoards.h
index 58288ef..db1af54 100644
--- a/examples/TBeamFactory/LoRaBoards.h
+++ b/examples/TBeamFactory/LoRaBoards.h
@@ -58,7 +58,8 @@ enum {
QMC6310N_ONLINE = _BV(11),
QMI8658_ONLINE = _BV(12),
PCF8563_ONLINE = _BV(13),
- OSC32768_ONLINE = _BV(14)
+ OSC32768_ONLINE = _BV(14),
+ QMC6309_ONLINE = _BV(15),
};
diff --git a/examples/TBeamFactory/TBeamFactory.ino b/examples/TBeamFactory/TBeamFactory.ino
index 45def58..f52ce7c 100644
--- a/examples/TBeamFactory/TBeamFactory.ino
+++ b/examples/TBeamFactory/TBeamFactory.ino
@@ -554,7 +554,9 @@ void radioTx(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.startTransmit(byteArr, 8);
*/
+#ifdef BOARD_LED
digitalWrite(BOARD_LED, 1 - digitalRead(BOARD_LED));
+#endif
}
Serial.println("Radio TX done !");
@@ -577,7 +579,9 @@ void radioRx(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t
if (transmittedFlag) {
Serial.println("Radio RX done !");
+#ifdef BOARD_LED
digitalWrite(BOARD_LED, 1 - digitalRead(BOARD_LED));
+#endif
// reset flag
transmittedFlag = false;
diff --git a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_Factory_260408.bin b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_Factory_260408.bin
new file mode 100644
index 0000000..b922493
Binary files /dev/null and b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_Factory_260408.bin differ
diff --git a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_Factory_920MHZ_260114.bin b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_Factory_920MHZ_260114.bin
deleted file mode 100644
index 28adcae..0000000
Binary files a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_Factory_920MHZ_260114.bin and /dev/null differ
diff --git a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_Factory_AllFreband_260114.bin b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_Factory_AllFreband_260114.bin
deleted file mode 100644
index 33ea6c7..0000000
Binary files a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_Factory_AllFreband_260114.bin and /dev/null differ
diff --git a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_JP_Factory_260408.bin b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_JP_Factory_260408.bin
new file mode 100644
index 0000000..c0aeb49
Binary files /dev/null and b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_LR1121_JP_Factory_260408.bin differ
diff --git a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_Factory_260408.bin b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_Factory_260408.bin
new file mode 100644
index 0000000..6b59ea4
Binary files /dev/null and b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_Factory_260408.bin differ
diff --git a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_Factory_920MHZ_260114.bin b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_Factory_920MHZ_260114.bin
deleted file mode 100644
index 2c51f42..0000000
Binary files a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_Factory_920MHZ_260114.bin and /dev/null differ
diff --git a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_Factory_AllFreqband_260114.bin b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_Factory_AllFreqband_260114.bin
deleted file mode 100644
index 773c052..0000000
Binary files a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_Factory_AllFreqband_260114.bin and /dev/null differ
diff --git a/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_JP_Factory_260408.bin b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_JP_Factory_260408.bin
new file mode 100644
index 0000000..b173039
Binary files /dev/null and b/firmware/hardware_test/t-beam-supreme/T_BEAM_S3_SUPREME_SX1262_JP_Factory_260408.bin differ
diff --git a/lib/RadioLib/.github/workflows/main.yml b/lib/RadioLib/.github/workflows/main.yml
index 22383d8..977edb4 100644
--- a/lib/RadioLib/.github/workflows/main.yml
+++ b/lib/RadioLib/.github/workflows/main.yml
@@ -83,12 +83,14 @@ jobs:
echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT
echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT
- - id: STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC
+ - id: STMicroelectronics:stm32:GenF3
run: |
+ echo "options=':pnum=BLACKPILL_F303CC'" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT
echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT
- - id: STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_WL55JC1
+ - id: STMicroelectronics:stm32:Nucleo_64
run: |
+ echo "options=':pnum=NUCLEO_WL55JC1'" >> $GITHUB_OUTPUT
# Do *not* skip STM32WL examples
echo "skip-pattern=(LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT
@@ -183,19 +185,20 @@ jobs:
cd $PWD/extras/test/ci
./build_examples.sh ${{ matrix.id }} "${{ steps.prep.outputs.skip-pattern }}" ${{ steps.prep.outputs.options }}
+ - name: Extract short commit hash
+ id: short-hash
+ run: echo "::set-output name=short_sha::$(git rev-parse --short HEAD)"
+
- name: Parse sizes
if: ${{ env.run-build == 'true' }}
run:
|
cd $PWD/extras/test/ci
./parse_size.sh ${{ matrix.id }}
-
- - name: Extract short commit hash
- id: short-hash
- run: echo "::set-output name=short_sha::$(git rev-parse --short HEAD)"
+ cat size_${{ steps.short-hash.outputs.short_sha }}_${{ steps.split.outputs._0 }}-${{ steps.split.outputs._1 }}-${{ steps.split.outputs._2 }}.csv
- name: Upload size report as artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: size-file-${{ steps.split.outputs._0 }}-${{ steps.split.outputs._1 }}-${{ steps.split.outputs._2 }}
path: extras/test/ci/size_${{ steps.short-hash.outputs.short_sha }}_${{ steps.split.outputs._0 }}-${{ steps.split.outputs._1 }}-${{ steps.split.outputs._2 }}.csv
@@ -203,6 +206,7 @@ jobs:
metrics:
runs-on: ubuntu-latest
needs: build
+ if: github.ref == 'refs/heads/master'
steps:
- name: Set up SSH
run: |
@@ -221,7 +225,7 @@ jobs:
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
- name: Download size artifacts
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
path: aggregated-sizes
@@ -250,9 +254,13 @@ jobs:
- name: Clone ESP-IDF
run: |
+ rm -rf ~/esp
mkdir -p ~/esp
cd ~/esp
- git clone --recursive https://github.com/espressif/esp-idf.git
+ git clone https://github.com/espressif/esp-idf.git
+ cd esp-idf
+ git checkout v5.4.3
+ git submodule update --init --recursive
- name: Install ESP-IDF
run: |
@@ -289,6 +297,7 @@ jobs:
LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh
rpi-build:
+ if: false # self-hosted runner temporarily disabled
runs-on: [self-hosted, ARM64]
steps:
- name: Checkout repository
@@ -320,6 +329,7 @@ jobs:
./build.sh
rpi-test:
+ if: false # self-hosted runner temporarily disabled
needs: rpi-build
runs-on: [self-hosted, ARM64]
steps:
@@ -346,7 +356,7 @@ jobs:
mkdir -p ~/rpi-pico
cd ~/rpi-pico
git clone https://github.com/raspberrypi/pico-sdk.git
- cd pico-sdk && git checkout 1.5.1
+ cd pico-sdk && git checkout 2.2.0
- name: Build the example
run: |
diff --git a/lib/RadioLib/.github/workflows/static.yml b/lib/RadioLib/.github/workflows/static.yml
new file mode 100644
index 0000000..74b53f2
--- /dev/null
+++ b/lib/RadioLib/.github/workflows/static.yml
@@ -0,0 +1,46 @@
+name: "Static Memory Management Test"
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ branches: [master]
+ workflow_dispatch:
+
+jobs:
+ static-memory:
+ name: Build Arduino and non-Arduino with enabled static memory management
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Install dependencies for unit test
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y libboost-all-dev libfmt-dev lcov
+
+ - name: Run unit test for static memory management
+ run: |
+ cd extras/test/unit
+ ./test.sh -DRADIOLIB_STATIC_ONLY
+
+ - name: Install arduino-cli
+ run:
+ |
+ mkdir -p ~/.local/bin
+ echo "~/.local/bin" >> $GITHUB_PATH
+ curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=~/.local/bin sh
+
+ - name: Install platform
+ run:
+ |
+ arduino-cli core update-index
+ arduino-cli core install arduino:avr
+
+ - name: Build Arduino example
+ run:
+ arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn arduino:avr:mega $PWD/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino --warnings=all --build-property compiler.cpp.extra_flags="-DRADIOLIB_STATIC_ONLY"
+
+
diff --git a/lib/RadioLib/.github/workflows/unit-test.yml b/lib/RadioLib/.github/workflows/unit-test.yml
index 58a7d72..b46a516 100644
--- a/lib/RadioLib/.github/workflows/unit-test.yml
+++ b/lib/RadioLib/.github/workflows/unit-test.yml
@@ -10,7 +10,7 @@ on:
jobs:
unit-test:
name: Build and run unit test
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- name: Checkout repository
@@ -19,9 +19,30 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
- sudo apt-get install -y libboost-all-dev libfmt-dev
+ sudo apt-get install -y libboost-all-dev libfmt-dev lcov
- name: Run unit test
run: |
cd extras/test/unit
./test.sh
+
+ - name: Measure test coverage
+ run: |
+ cd extras/test/unit
+ ./coverage.sh
+
+ - name: Upload coverage report as artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: coverage_report
+ path: extras/test/unit/lcov.report
+
+ - name: Deploy to GitHub Pages
+ if: github.ref == 'refs/heads/master'
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_branch: gh-pages
+ publish_dir: extras/test/unit/lcov.report
+ destination_dir: coverage
+ keep_files: true
diff --git a/lib/RadioLib/CMakeLists.txt b/lib/RadioLib/CMakeLists.txt
index 2291050..b208f79 100644
--- a/lib/RadioLib/CMakeLists.txt
+++ b/lib/RadioLib/CMakeLists.txt
@@ -1,15 +1,20 @@
cmake_minimum_required(VERSION 3.13)
+# first gather the files since this is needed for both ESP-IDF as well as other builds
+file(GLOB_RECURSE RADIOLIB_SOURCES
+ "src/*.cpp"
+)
+
+# exclude all HAL source files
+list(FILTER RADIOLIB_SOURCES EXCLUDE REGEX "src/hal/.*\\.cpp")
+
if(ESP_PLATFORM)
# Build RadioLib as an ESP-IDF component
# required because ESP-IDF runs cmake in script mode
# and needs idf_component_register()
- file(GLOB_RECURSE RADIOLIB_ESP_SOURCES
- "src/*.*"
- )
idf_component_register(
- SRCS ${RADIOLIB_ESP_SOURCES}
+ SRCS ${RADIOLIB_SOURCES}
INCLUDE_DIRS . src
)
@@ -22,10 +27,6 @@ endif()
project(radiolib)
-file(GLOB_RECURSE RADIOLIB_SOURCES
- "src/*.cpp"
-)
-
add_library(RadioLib ${RADIOLIB_SOURCES})
target_include_directories(RadioLib
@@ -36,7 +37,7 @@ target_include_directories(RadioLib
set_property(TARGET RadioLib PROPERTY CXX_STANDARD 20)
# enable most warnings
-target_compile_options(RadioLib PRIVATE -Wall -Wextra)
+target_compile_options(RadioLib PRIVATE -Wall -Wextra -Wpedantic -Wdouble-promotion)
include(GNUInstallDirs)
diff --git a/lib/RadioLib/CONTRIBUTING.md b/lib/RadioLib/CONTRIBUTING.md
index 4bf9619..71e6958 100644
--- a/lib/RadioLib/CONTRIBUTING.md
+++ b/lib/RadioLib/CONTRIBUTING.md
@@ -16,6 +16,19 @@ Issues with generic titles (e.g. "not working", "lora", etc.) will be **CLOSED**
4. **Issues deserve some attention too.**
Issues that are left for 2 weeks without response by the original author when asked for further information will be closed due to inactivity. This is to keep track of important issues, the author is encouraged to reopen the issue at a later date.
+## AI Use
+
+**RadioLib was written by humans, for humans**. Its authors, contributors, maintainers and community members were not asked for permission or approval when billion-dollar companies decided to scrape our hard work for training data, to be sold back to the world at a profit. While we consider this approach to be bordering on violating our license, this seems to be the world we live in. Therefore, if you decide to contribute to RadioLib while using an AI-based tool, please follow the rules below.
+
+1. **Mark the slop**
+The issue or pull request must be clearly marked as fully or partially AI-generated. If you don't do it, we'll do it for you by the means of a dedicated label - and then consider whether to process your input at all. Since people like that have not even bothered to read this statement, it would be unreasonable to expect they will read the code the machine generated and that is not code we want.
+2. **Less is more**
+If your AI has produced a novel-length wall of text to describe a miniscule change, we consider it somewhat rude to copy-paste that output into the issue/PR description. Not only are you ignoring the templates which are asking for generally useful info; this approach also has the added bonus of explaining our own codebase back to us, while trying to sound as simple as possible. In reality though, it sounds like a junior developer giving us a lecture on a project that is older then they are. So please, try to get the actual point across in your own, human-generated words.
+3. **Discuss first**
+It is usually not a great idea to hit us with a large, unsolicited pull request. Especially if it changes APIs or tries to work around something. It's a lot easier to discuss these things in advance and agree on an approach in an issue. Your AI can write the PR quickly; but then we need to spend our free time on reviewing something that we did not ask for.
+
+RadioLib maintainers reserve the right to reject your contribution if it is not following these rules without further explanation other than directing you to this guideline document.
+
## Code style guidelines
I like pretty code! Or at least, I like *consistent* code style. When creating pull requests, please follow these style guidelines, they're in place to keep high code readability.
diff --git a/lib/RadioLib/README.md b/lib/RadioLib/README.md
index 92ffe44..218bb15 100644
--- a/lib/RadioLib/README.md
+++ b/lib/RadioLib/README.md
@@ -22,10 +22,11 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
* __CC1101__ FSK radio module
* __LLCC68__ LoRa module
* __LR11x0__ series LoRa/GFSK modules (LR1110, LR1120, LR1121)
+* __LR2021__ series LoRa/GFSK/LR-FHSS/FLRC/OOK modules
* __nRF24L01__ 2.4 GHz module
* __RF69__ FSK/OOK radio module
-* __RFM2x__ series FSK modules (RFM22, RM23)
-* __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98)
+* __RFM2x__ series FSK modules (RFM22, RFM23)
+* __RFM9x__ series LoRa modules (RFM95, RFM96, RFM97, RFM98)
* __Si443x__ series FSK modules (Si4430, Si4431, Si4432)
* __STM32WL__ integrated microcontroller/LoRa module
* __SX126x__ series LoRa modules (SX1261, SX1262, SX1268)
@@ -34,22 +35,26 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
* __SX123x__ FSK/OOK radio modules (SX1231, SX1233)
### Supported protocols and digital modes:
+* [__ADS-B__](https://mode-s.org/1090mhz/content/ads-b/1-basics.html) using OOK for LR2021
* [__AX.25__](https://www.sigidwiki.com/wiki/PACKET) using 2-FSK or AFSK for modules:
-SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x, Si443x, LR11x0 and SX128x
+SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x, Si443x, LR11x0, LR2021 and SX128x
* [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules:
-SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x
+SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0, LR2021 and SX128x
* [__Morse Code__](https://www.sigidwiki.com/wiki/Morse_Code_(CW)) using 2-FSK or AFSK for modules:
-SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x
+SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0, LR2021 and SX128x
* [__SSTV__](https://www.sigidwiki.com/wiki/SSTV) using 2-FSK or AFSK for modules:
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x
* [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules:
-SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x
+SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0, LR2021 and SX128x
* [__APRS__](https://www.sigidwiki.com/wiki/APRS) using AFSK for modules:
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
* [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules:
SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x
* [__LoRaWAN__](https://lora-alliance.org/) using LoRa and FSK for modules:
-SX127x, RFM9x, SX126x, LR11x0 and SX128x
+SX127x, RFM9x, SX126x, LR11x0, LR2021 and SX128x
+ * Supports Class A and C (and Multicast over C).
+ * Pre-certified for Class A.
+ * See the [wiki](https://github.com/jgromes/RadioLib/wiki/LoRaWAN) and [notes](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for more information.
### Supported Arduino platforms:
* __Arduino__
diff --git a/lib/RadioLib/examples/ADSB/ADSB_Monitor/ADSB_Monitor.ino b/lib/RadioLib/examples/ADSB/ADSB_Monitor/ADSB_Monitor.ino
new file mode 100644
index 0000000..5e9508e
--- /dev/null
+++ b/lib/RadioLib/examples/ADSB/ADSB_Monitor/ADSB_Monitor.ino
@@ -0,0 +1,166 @@
+/*
+ RadioLib ADS-B Monitor Example
+
+ This example shows how to receive ADS-B messages
+ using LR2021 OOK modem and forward them to be displayed
+ in a live dashboard.
+
+ To show the live dashboard in a terminal, run the Python script
+ RadioLib/extras/ADSB_Monitor/ADSBMonitorServer.py,
+ and then connect to from "modeslive" from the pyModeS package
+ (see the script helptext for installation instructions).
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+// create ADS-B client instance using the module
+ADSBClient adsb(&radio);
+
+// flag to indicate that a packet was received
+volatile bool receivedFlag = false;
+
+// this function is called when a complete packet
+// is received by the module
+// IMPORTANT: this function MUST be 'void' type
+// and MUST NOT have any arguments!
+#if defined(ESP8266) || defined(ESP32)
+ ICACHE_RAM_ATTR
+#endif
+void setFlag(void) {
+ // we got a packet, set the flag
+ receivedFlag = true;
+}
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 OOK modem at 1090 MHz,
+ // 2 Mbps bit rate and receiver bandwidth 3076 kHz
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.beginOOK(1090, 2000, 3076);
+
+ if(state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // initialize ADS-B client
+ Serial.print(F("[ADS-B] Initializing ... "));
+ state = adsb.begin();
+ if(state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // apply LR2021-specific settings
+ Serial.print(F("[LR2021] Setting configuration ... "));
+ state = radio.setRxBoostedGainMode(7);
+ state += radio.setCRC(3, 0, 0x1FFF409UL, false);
+ state += radio.ookDetector();
+ state += radio.fixedPacketLengthMode(11);
+ state += radio.setGain(13);
+ if(state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // measure current noise floor and add some margin
+ // this values is later used to set the signal detection threshold
+ float threshold = radio.getRSSI(false) + 10;
+ Serial.print(F("[LR2021] Detection threshold: "));
+ Serial.print(threshold, 2);
+ Serial.println(F(" dBm"));
+
+ Serial.print(F("[LR2021] Setting threshold ... "));
+ state = radio.setOokDetectionThreshold(threshold);
+ if(state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // set the function that will be called
+ // when new packet is received
+ radio.setPacketReceivedAction(setFlag);
+
+ // start listening for LoRa packets
+ Serial.print(F("[LR2021] Starting to listen ... "));
+ state = radio.startReceive();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+}
+
+void loop() {
+ // check if the flag is set
+ if(receivedFlag) {
+ // reset flag
+ receivedFlag = false;
+
+ // read the received binary data
+ // ADS-B frames have fixed length of 14 bytes,
+ // 3 of which are used as CRC which is handled automatically
+ uint8_t buff[11] = { 0 };
+ int state = radio.readData(buff, 11);
+
+ if (state == RADIOLIB_ERR_NONE) {
+ // packet was successfully received
+ // print it out, further processing is done by pyModeS
+ Serial.print(F("[ADS-B] "));
+ for(int i = 0; i < 11; i++) {
+ if(buff[i] < 0x10) { Serial.print('0'); }
+ Serial.print(buff[i], HEX);
+ }
+
+ // pyModeS expects the data to include the CRC
+ // but does not seem to be actually checking it
+ // since we handle CRC automatically, just append 3 null bytes
+ Serial.println(F("000000"));
+
+ }
+
+ }
+
+}
diff --git a/lib/RadioLib/examples/ADSB/ADSB_Receive/ADSB_Receive.ino b/lib/RadioLib/examples/ADSB/ADSB_Receive/ADSB_Receive.ino
new file mode 100644
index 0000000..5bd2592
--- /dev/null
+++ b/lib/RadioLib/examples/ADSB/ADSB_Receive/ADSB_Receive.ino
@@ -0,0 +1,223 @@
+/*
+ RadioLib ADS-B Reception Example
+
+ This example shows how to receive ADS-B messages
+ using LR2021 OOK modem.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+// create ADS-B client instance using the module
+ADSBClient adsb(&radio);
+
+// flag to indicate that a packet was received
+volatile bool receivedFlag = false;
+
+// this function is called when a complete packet
+// is received by the module
+// IMPORTANT: this function MUST be 'void' type
+// and MUST NOT have any arguments!
+#if defined(ESP8266) || defined(ESP32)
+ ICACHE_RAM_ATTR
+#endif
+void setFlag(void) {
+ // we got a packet, set the flag
+ receivedFlag = true;
+}
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 OOK modem at 1090 MHz,
+ // 2 Mbps bit rate and receiver bandwidth 3076 kHz
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.beginOOK(1090, 2000, 3076);
+
+ if(state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // initialize ADS-B client
+ Serial.print(F("[ADS-B] Initializing ... "));
+ state = adsb.begin();
+ if(state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // apply LR2021-specific settings
+ Serial.print(F("[LR2021] Setting configuration ... "));
+ state = radio.setRxBoostedGainMode(7);
+ state += radio.setCRC(3, 0, 0x1FFF409UL, false);
+ state += radio.ookDetector();
+ state += radio.fixedPacketLengthMode(11);
+ state += radio.setGain(13);
+ if(state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // measure current noise floor and add some margin
+ // this values is later used to set the signal detection threshold
+ float threshold = radio.getRSSI(false) + 10;
+ Serial.print(F("[LR2021] Detection threshold: "));
+ Serial.print(threshold, 2);
+ Serial.println(F(" dBm"));
+
+ Serial.print(F("[LR2021] Setting threshold ... "));
+ state = radio.setOokDetectionThreshold(threshold);
+ if(state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // set the reference position (position of the receiver)
+ // this will be used later to calculate the aircraft position
+ adsb.setReferencePosition(46.24722039359617f, 12.097993784412322f);
+
+ // set the function that will be called
+ // when new packet is received
+ radio.setPacketReceivedAction(setFlag);
+
+ // start listening for LoRa packets
+ Serial.print(F("[LR2021] Starting to listen ... "));
+ state = radio.startReceive();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+}
+
+// these variables will be used later to save decoded information
+ADSBFrame frame;
+ADSBAircraftCategory category;
+char callsign[RADIOLIB_ADSB_CALLSIGN_LEN];
+char hexId[RADIOLIB_ADSB_HEX_ID_LEN];
+ADSBAircraftCategory cat;
+int alt;
+float lat, lon;
+bool altGnss;
+
+void loop() {
+ // check if the flag is set
+ if(receivedFlag) {
+ // reset flag
+ receivedFlag = false;
+
+ // read the received binary data
+ // ADS-B frames have fixed length of 14 bytes,
+ // 3 of which are used as CRC which is handled automatically
+ uint8_t buff[11] = { 0 };
+ int state = radio.readData(buff, 11);
+
+ if (state == RADIOLIB_ERR_NONE) {
+ // packet was successfully received
+ Serial.println(F("[LR2021] Received packet!"));
+
+ state = adsb.decode(buff, &frame);
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("[ADS-B] Decoded frame!"));
+ // print the decoded information
+ Serial.print(F("[ADS-B] DF = "));
+ Serial.println(frame.downlinkFormat);
+ Serial.print(F("[ADS-B] CA = "));
+ Serial.println(frame.capability);
+ Serial.print(F("[ADS-B] Message type = "));
+ Serial.println((int)frame.messageType);
+
+ // get the hexadecimal ID (ICAO address) of the transceiver
+ state = adsb.parseHexId(&frame, hexId);
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.print(F("[ADS-B] Hex ID = "));
+ Serial.println(hexId);
+ }
+
+ // further information depends on the message type
+ switch(frame.messageType) {
+ case(ADSBMessageType::AIRCRAFT_ID):
+ adsb.parseCallsign(&frame, callsign, &cat);
+ Serial.print(F("[ADS-B] Callsign = "));
+ Serial.println(callsign);
+ Serial.print(F("[ADS-B] Category = "));
+ Serial.println((int)category);
+ break;
+
+ case(ADSBMessageType::AIRBORNE_POS_ALT_BARO):
+ case(ADSBMessageType::AIRBORNE_POS_ALT_GNSS):
+ adsb.parseAirbornePosition(&frame, &alt, &lat, &lon, &altGnss);
+ Serial.print(F("[ADS-B] Altitude = "));
+ Serial.print(alt);
+ if(altGnss) { Serial.println(" meters\n"); } else { Serial.println(" feet\n"); }
+ Serial.print(F("[ADS-B] Latitude = "));
+ Serial.println(lat, 6);
+ Serial.print(F("[ADS-B] Longitude = "));
+ Serial.println(lon, 6);
+ break;
+
+ default:
+ break;
+
+ }
+
+ } else {
+ Serial.print(F("[ADS-B] Failed to decode, code "));
+ Serial.println(state);
+
+ }
+
+
+ } else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
+ // packet was received, but is malformed
+ Serial.println(F("CRC error!"));
+
+ } else {
+ // some other error occurred
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+
+ }
+ }
+}
diff --git a/lib/RadioLib/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/lib/RadioLib/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino
index 89fef51..7042015 100644
--- a/lib/RadioLib/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino
+++ b/lib/RadioLib/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino
@@ -82,10 +82,11 @@ void setup() {
void loop() {
Serial.print(F("[CC1101] Transmitting packet ... "));
- // you can transmit C-string or Arduino string up to 64 characters long
+ // you can transmit C-string or Arduino string up to 255 characters long
int state = radio.transmit("Hello World!");
- // you can also transmit byte array up to 64 bytes long
+ // you can also transmit byte array up to 255 bytes long
+ // With some limitations see here: https://github.com/jgromes/RadioLib/discussions/1138
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
int state = radio.transmit(byteArr, 8);
diff --git a/lib/RadioLib/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino b/lib/RadioLib/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino
index 3f45061..809cfa6 100644
--- a/lib/RadioLib/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino
+++ b/lib/RadioLib/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino
@@ -2,7 +2,7 @@
RadioLib CC1101 Blocking Transmit Example
This example transmits packets using CC1101 FSK radio module.
- Each packet contains up to 64 bytes of data, in the form of:
+ Each packet contains up to 255 bytes of data with some limitations (https://github.com/jgromes/RadioLib/discussions/1138), in the form of:
- Arduino String
- null-terminated char array (C-string)
- arbitrary binary data (byte array)
@@ -57,11 +57,11 @@ int count = 0;
void loop() {
Serial.print(F("[CC1101] Transmitting packet ... "));
- // you can transmit C-string or Arduino string up to 64 characters long
+ // you can transmit C-string or Arduino string up to 255 characters long
String str = "Hello World! #" + String(count++);
int state = radio.transmit(str);
- // you can also transmit byte array up to 64 bytes long
+ // you can also transmit byte array up to 255 bytes long with some limitations; https://github.com/jgromes/RadioLib/discussions/1138
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
int state = radio.transmit(byteArr, 8);
@@ -72,7 +72,7 @@ void loop() {
Serial.println(F("success!"));
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
- // the supplied packet was longer than 64 bytes
+ // the supplied packet was longer than 255 bytes
Serial.println(F("too long!"));
} else {
diff --git a/lib/RadioLib/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/lib/RadioLib/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino
index e1d8862..0a87645 100644
--- a/lib/RadioLib/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino
+++ b/lib/RadioLib/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino
@@ -3,7 +3,7 @@
This example transmits packets using CC1101 FSK radio module.
Once a packet is transmitted, an interrupt is triggered.
- Each packet contains up to 64 bytes of data, in the form of:
+ Each packet contains up to 255 bytes of data with some limitations (https://github.com/jgromes/RadioLib/discussions/1138), in the form of:
- Arduino String
- null-terminated char array (C-string)
- arbitrary binary data (byte array)
@@ -73,10 +73,12 @@ void setup() {
Serial.print(F("[CC1101] Sending first packet ... "));
// you can transmit C-string or Arduino string up to
- // 64 characters long
+ // 255 characters long
transmissionState = radio.startTransmit("Hello World!");
- // you can also transmit byte array up to 64 bytes long
+ // you can also transmit byte array up to 255 bytes long
+ // When transmitting more than 64 bytes startTransmit blocks to refill the FIFO.
+ // Blocking ceases once the last bytes have been placed in the FIFO
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
0x78, 0xAB, 0xCD, 0xEF};
@@ -97,10 +99,6 @@ void loop() {
// packet was successfully sent
Serial.println(F("transmission finished!"));
- // NOTE: when using interrupt-driven transmit method,
- // it is not possible to automatically measure
- // transmission data rate using getDataRate()
-
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
@@ -119,11 +117,11 @@ void loop() {
Serial.print(F("[CC1101] Sending another packet ... "));
// you can transmit C-string or Arduino string up to
- // 64 characters long
+ // 255 characters long
String str = "Hello World! #" + String(count++);
transmissionState = radio.startTransmit(str);
- // you can also transmit byte array up to 64 bytes long
+ // you can also transmit byte array up to 255 bytes long with limitations https://github.com/jgromes/RadioLib/discussions/1138
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
diff --git a/lib/RadioLib/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino b/lib/RadioLib/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino
index 85e7bd4..c3a8003 100644
--- a/lib/RadioLib/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino
+++ b/lib/RadioLib/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino
@@ -70,13 +70,6 @@ void setup() {
while (true) { delay(10); }
}
- // GFSK modem on LR11x0 can handle the sync word setting in bits, not just
- // whole bytes. The value used is left-justified.
- // This makes same result as radio.setSyncWord(syncWord, 8):
- state = radio.setSyncBits(syncWord, 64);
- // This will use 0x012 as sync word (12 bits only):
- state = radio.setSyncBits(syncWord, 12);
-
// GFSK modem allows advanced CRC configuration
// Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted)
// Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted)
diff --git a/lib/RadioLib/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino b/lib/RadioLib/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino
index f1c7c19..a0dc436 100644
--- a/lib/RadioLib/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino
+++ b/lib/RadioLib/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino
@@ -57,8 +57,8 @@ void setup() {
// the following settings can also
// be modified at run-time
state = radio.setFrequency(433.5);
- state = radio.setLrFhssConfig(RADIOLIB_LR11X0_LR_FHSS_BW_1523_4, // bandwidth
- RADIOLIB_LR11X0_LR_FHSS_CR_1_2, // coding rate
+ state = radio.setLrFhssConfig(RADIOLIB_LRXXXX_LR_FHSS_BW_1523_4, // bandwidth
+ RADIOLIB_LRXXXX_LR_FHSS_CR_1_2, // coding rate
3, // header count
0x13A); // hopping sequence seed
state = radio.setOutputPower(10.0);
diff --git a/lib/RadioLib/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino b/lib/RadioLib/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino
index 66a9058..9824011 100644
--- a/lib/RadioLib/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino
+++ b/lib/RadioLib/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino
@@ -101,11 +101,6 @@ void loop() {
// the packet was successfully transmitted
Serial.println(F("success!"));
- // print measured data rate
- Serial.print(F("[LR1110] Datarate:\t"));
- Serial.print(radio.getDataRate());
- Serial.println(F(" bps"));
-
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
// the supplied packet was longer than 256 bytes
Serial.println(F("too long!"));
diff --git a/lib/RadioLib/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/lib/RadioLib/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino
index 3086a9a..14942de 100644
--- a/lib/RadioLib/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino
+++ b/lib/RadioLib/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino
@@ -126,10 +126,6 @@ void loop() {
// packet was successfully sent
Serial.println(F("transmission finished!"));
- // NOTE: when using interrupt-driven transmit method,
- // it is not possible to automatically measure
- // transmission data rate using getDataRate()
-
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
diff --git a/lib/RadioLib/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino b/lib/RadioLib/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino
new file mode 100644
index 0000000..31fe6be
--- /dev/null
+++ b/lib/RadioLib/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino
@@ -0,0 +1,82 @@
+/*
+ RadioLib LR2021 Blocking Channel Activity Detection Example
+
+ This example uses LR2021 to scan the current LoRa
+ channel and detect ongoing LoRa transmissions.
+ Unlike SX127x CAD, LR2021 can detect any part
+ of LoRa transmission, not just the preamble.
+
+ Using blocking CAD is not recommended, as it will lead
+ to significant amount of timeouts, inefficient use of processor
+ time and can some miss packets!
+ Instead, interrupt CAD is recommended.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.begin();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+}
+
+void loop() {
+ Serial.print(F("[LR2021] Scanning channel for LoRa transmission ... "));
+
+ // start scanning current channel
+ int state = radio.scanChannel();
+
+ if (state == RADIOLIB_LORA_DETECTED) {
+ // LoRa preamble was detected
+ Serial.println(F("detected!"));
+
+ } else if (state == RADIOLIB_CHANNEL_FREE) {
+ // no preamble was detected, channel is free
+ Serial.println(F("channel is free!"));
+
+ } else {
+ // some other error occurred
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+
+ }
+
+ // wait 100 ms before new scan
+ delay(100);
+}
diff --git a/lib/RadioLib/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino b/lib/RadioLib/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino
new file mode 100644
index 0000000..e3ff802
--- /dev/null
+++ b/lib/RadioLib/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino
@@ -0,0 +1,117 @@
+/*
+ RadioLib LR2021 Channel Activity Detection Example
+
+ This example uses LR2021 to scan the current LoRa
+ channel and detect ongoing LoRa transmissions.
+ Unlike SX127x CAD, LR2021 can detect any part
+ of LoRa transmission, not just the preamble.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+// flag to indicate that a packet was detected or CAD timed out
+volatile bool scanFlag = false;
+
+// this function is called when a complete packet
+// is received by the module
+// IMPORTANT: this function MUST be 'void' type
+// and MUST NOT have any arguments!
+#if defined(ESP8266) || defined(ESP32)
+ ICACHE_RAM_ATTR
+#endif
+void setFlag(void) {
+ // something happened, set the flag
+ scanFlag = true;
+}
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.begin();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // set the function that will be called
+ // when LoRa packet or timeout is detected
+ radio.setIrqAction(setFlag);
+
+ // start scanning the channel
+ Serial.print(F("[LR2021] Starting scan for LoRa preamble ... "));
+ state = radio.startChannelScan();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ }
+}
+
+void loop() {
+ // check if the flag is set
+ if(scanFlag) {
+ // reset flag
+ scanFlag = false;
+
+ // check CAD result
+ int state = radio.getChannelScanResult();
+
+ if (state == RADIOLIB_LORA_DETECTED) {
+ // LoRa packet was detected
+ Serial.println(F("[LR2021] Packet detected!"));
+
+ } else if (state == RADIOLIB_CHANNEL_FREE) {
+ // channel is free
+ Serial.println(F("[LR2021] Channel is free!"));
+
+ } else {
+ // some other error occurred
+ Serial.print(F("[LR2021] Failed, code "));
+ Serial.println(state);
+
+ }
+
+ // start scanning the channel again
+ Serial.print(F("[LR2021] Starting scan for LoRa preamble ... "));
+ state = radio.startChannelScan();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ }
+ }
+}
diff --git a/lib/RadioLib/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino b/lib/RadioLib/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino
new file mode 100644
index 0000000..ad8997a
--- /dev/null
+++ b/lib/RadioLib/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino
@@ -0,0 +1,155 @@
+/*
+ RadioLib LR2021 GFSK Modem Example
+
+ This example shows how to use GFSK modem in LR2021 chips.
+
+ NOTE: The sketch below is just a guide on how to use
+ GFSK modem, so this code should not be run directly!
+ Instead, modify the other examples to use GFSK
+ modem and use the appropriate configuration
+ methods.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---gfsk-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.beginGFSK();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // if needed, you can switch between any of the modems
+ //
+ // radio.begin() start LoRa modem (and disable GFSK)
+ // radio.beginGFSK() start GFSK modem (and disable LoRa)
+
+ // the following settings can also
+ // be modified at run-time
+ state = radio.setFrequency(433.5);
+ state = radio.setBitRate(100.0);
+ state = radio.setFrequencyDeviation(10.0);
+ state = radio.setRxBandwidth(250.0);
+ state = radio.setOutputPower(10.0);
+ state = radio.setDataShaping(RADIOLIB_SHAPING_1_0);
+ uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67,
+ 0x89, 0xAB, 0xCD, 0xEF};
+ state = radio.setSyncWord(syncWord, 8);
+ if (state != RADIOLIB_ERR_NONE) {
+ Serial.print(F("Unable to set configuration, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // GFSK modem allows advanced CRC configuration
+ // Default is CCITT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted)
+ // Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted)
+ state = radio.setCRC(2, 0xFFFF, 0x8005, false);
+ // set CRC length to 0 to disable CRC
+
+ #warning "This sketch is just an API guide! Read the note at line 6."
+}
+
+void loop() {
+ // GFSK modem can use the same transmit/receive methods
+ // as the LoRa modem, even their interrupt-driven versions
+
+ // transmit GFSK packet
+ int state = radio.transmit("Hello World!");
+ /*
+ byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
+ 0x89, 0xAB, 0xCD, 0xEF};
+ int state = radio.transmit(byteArr, 8);
+ */
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("[LR2021] Packet transmitted successfully!"));
+ } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
+ Serial.println(F("[LR2021] Packet too long!"));
+ } else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
+ Serial.println(F("[LR2021] Timed out while transmitting!"));
+ } else {
+ Serial.println(F("[LR2021] Failed to transmit packet, code "));
+ Serial.println(state);
+ }
+
+ // receive GFSK packet
+ String str;
+ state = radio.receive(str);
+ /*
+ byte byteArr[8];
+ int state = radio.receive(byteArr, 8);
+ */
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("[LR2021] Received packet!"));
+ Serial.print(F("[LR2021] Data:\t"));
+ Serial.println(str);
+ } else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
+ Serial.println(F("[LR2021] Timed out while waiting for packet!"));
+ } else {
+ Serial.print(F("[LR2021] Failed to receive packet, code "));
+ Serial.println(state);
+ }
+
+ // GFSK modem has built-in address filtering system
+ // it can be enabled by setting node address, broadcast
+ // address, or both
+ //
+ // to transmit packet to a particular address,
+ // use the following methods:
+ //
+ // radio.transmit("Hello World!", address);
+ // radio.startTransmit("Hello World!", address);
+
+ // set node address to 0x02
+ state = radio.setNodeAddress(0x02);
+ // set broadcast address to 0xFF
+ state = radio.setBroadcastAddress(0xFF);
+ if (state != RADIOLIB_ERR_NONE) {
+ Serial.println(F("[LR2021] Unable to set address filter, code "));
+ Serial.println(state);
+ }
+
+ // address filtering can also be disabled
+ // NOTE: calling this method will also erase previously set
+ // node and broadcast address
+ /*
+ state = radio.disableAddressFiltering();
+ if (state != RADIOLIB_ERR_NONE) {
+ Serial.println(F("Unable to remove address filter, code "));
+ }
+ */
+}
diff --git a/lib/RadioLib/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino b/lib/RadioLib/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino
similarity index 73%
rename from lib/RadioLib/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino
rename to lib/RadioLib/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino
index 44519d5..097c1f3 100644
--- a/lib/RadioLib/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino
+++ b/lib/RadioLib/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino
@@ -1,7 +1,7 @@
/*
- RadioLib SX126x LR-FHSS Modem Example
+ RadioLib LR2021 LR-FHSS Modem Example
- This example shows how to use LR-FHSS modem in SX126x chips.
+ This example shows how to use LR-FHSS modem in LR2021 chips.
This modem can only transmit data, and is not able to receive.
NOTE: The sketch below is just a guide on how to use
@@ -11,7 +11,7 @@
methods.
For default module settings, see the wiki page
- https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lr-fhss-modem
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lr-fhss-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
@@ -20,12 +20,12 @@
// include the library
#include
-// SX1262 has the following connections:
+// LR2021 has the following connections:
// NSS pin: 10
// IRQ pin: 2
// NRST pin: 3
// BUSY pin: 9
-SX1262 radio = new Module(10, 2, 3, 9);
+LR2021 radio = new Module(10, 2, 3, 9);
// or detect the pinout automatically using RadioBoards
// https://github.com/radiolib-org/RadioBoards
@@ -38,8 +38,13 @@ Radio radio = new RadioModule();
void setup() {
Serial.begin(9600);
- // initialize SX1262 with default settings
- Serial.print(F("[SX1262] Initializing ... "));
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
int state = radio.beginLRFHSS();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
@@ -57,8 +62,8 @@ void setup() {
// the following settings can also
// be modified at run-time
state = radio.setFrequency(433.5);
- state = radio.setLrFhssConfig(RADIOLIB_SX126X_LR_FHSS_BW_1523_4, // bandwidth
- RADIOLIB_SX126X_LR_FHSS_CR_1_2, // coding rate
+ state = radio.setLrFhssConfig(RADIOLIB_LRXXXX_LR_FHSS_BW_1523_4, // bandwidth
+ RADIOLIB_LRXXXX_LR_FHSS_CR_1_2, // coding rate
3, // header count
0x13A); // hopping sequence seed
state = radio.setOutputPower(10.0);
@@ -83,13 +88,13 @@ void loop() {
int state = radio.transmit(byteArr, 8);
*/
if (state == RADIOLIB_ERR_NONE) {
- Serial.println(F("[SX1262] Packet transmitted successfully!"));
+ Serial.println(F("[LR2021] Packet transmitted successfully!"));
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
- Serial.println(F("[SX1262] Packet too long!"));
+ Serial.println(F("[LR2021] Packet too long!"));
} else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
- Serial.println(F("[SX1262] Timed out while transmitting!"));
+ Serial.println(F("[LR2021] Timed out while transmitting!"));
} else {
- Serial.println(F("[SX1262] Failed to transmit packet, code "));
+ Serial.println(F("[LR2021] Failed to transmit packet, code "));
Serial.println(state);
}
diff --git a/lib/RadioLib/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino b/lib/RadioLib/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino
new file mode 100644
index 0000000..4a399d8
--- /dev/null
+++ b/lib/RadioLib/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino
@@ -0,0 +1,155 @@
+/*
+ RadioLib LR2021 Ping-Pong Example
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// uncomment the following only on one
+// of the nodes to initiate the pings
+//#define INITIATING_NODE
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+// save transmission states between loops
+int transmissionState = RADIOLIB_ERR_NONE;
+
+// flag to indicate transmission or reception state
+bool transmitFlag = false;
+
+// flag to indicate that a packet was sent or received
+volatile bool operationDone = false;
+
+// this function is called when a complete packet
+// is transmitted or received by the module
+// IMPORTANT: this function MUST be 'void' type
+// and MUST NOT have any arguments!
+#if defined(ESP8266) || defined(ESP32)
+ ICACHE_RAM_ATTR
+#endif
+void setFlag(void) {
+ // we sent or received a packet, set the flag
+ operationDone = true;
+}
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.begin();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // set the function that will be called
+ // when new packet is received
+ radio.setIrqAction(setFlag);
+
+ #if defined(INITIATING_NODE)
+ // send the first packet on this node
+ Serial.print(F("[LR2021] Sending first packet ... "));
+ transmissionState = radio.startTransmit("Hello World!");
+ transmitFlag = true;
+ #else
+ // start listening for LoRa packets on this node
+ Serial.print(F("[LR2021] Starting to listen ... "));
+ state = radio.startReceive();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+ #endif
+}
+
+void loop() {
+ // check if the previous operation finished
+ if(operationDone) {
+ // reset flag
+ operationDone = false;
+
+ if(transmitFlag) {
+ // the previous operation was transmission, listen for response
+ // print the result
+ if (transmissionState == RADIOLIB_ERR_NONE) {
+ // packet was successfully sent
+ Serial.println(F("transmission finished!"));
+
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(transmissionState);
+
+ }
+
+ // listen for response
+ radio.startReceive();
+ transmitFlag = false;
+
+ } else {
+ // the previous operation was reception
+ // print data and send another packet
+ String str;
+ int state = radio.readData(str);
+
+ if (state == RADIOLIB_ERR_NONE) {
+ // packet was successfully received
+ Serial.println(F("[LR2021] Received packet!"));
+
+ // print data of the packet
+ Serial.print(F("[LR2021] Data:\t\t"));
+ Serial.println(str);
+
+ // print RSSI (Received Signal Strength Indicator)
+ Serial.print(F("[LR2021] RSSI:\t\t"));
+ Serial.print(radio.getRSSI());
+ Serial.println(F(" dBm"));
+
+ // print SNR (Signal-to-Noise Ratio)
+ Serial.print(F("[LR2021] SNR:\t\t"));
+ Serial.print(radio.getSNR());
+ Serial.println(F(" dB"));
+
+ }
+
+ // wait a second before transmitting again
+ delay(1000);
+
+ // send another one
+ Serial.print(F("[LR2021] Sending another packet ... "));
+ transmissionState = radio.startTransmit("Hello World!");
+ transmitFlag = true;
+ }
+
+ }
+}
diff --git a/lib/RadioLib/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino b/lib/RadioLib/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino
new file mode 100644
index 0000000..709d61d
--- /dev/null
+++ b/lib/RadioLib/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino
@@ -0,0 +1,111 @@
+/*
+ RadioLib LR2021 Blocking Receive Example
+
+ This example listens for LoRa transmissions using LR2021 Lora modules.
+ To successfully receive data, the following settings have to be the same
+ on both transmitter and receiver:
+ - carrier frequency
+ - bandwidth
+ - spreading factor
+ - coding rate
+ - sync word
+ - preamble length
+
+ Using blocking receive is not recommended, as it will lead
+ to significant amount of timeouts, inefficient use of processor
+ time and can some miss packets!
+ Instead, interrupt receive is recommended.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.begin();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+}
+
+void loop() {
+ Serial.print(F("[LR2021] Waiting for incoming transmission ... "));
+
+ // you can receive data as an Arduino String
+ String str;
+ int state = radio.receive(str);
+
+ // you can also receive data as byte array
+ /*
+ byte byteArr[8];
+ int state = radio.receive(byteArr, 8);
+ */
+
+ if (state == RADIOLIB_ERR_NONE) {
+ // packet was successfully received
+ Serial.println(F("success!"));
+
+ // print the data of the packet
+ Serial.print(F("[LR2021] Data:\t\t"));
+ Serial.println(str);
+
+ // print the RSSI (Received Signal Strength Indicator)
+ // of the last received packet
+ Serial.print(F("[LR2021] RSSI:\t\t"));
+ Serial.print(radio.getRSSI());
+ Serial.println(F(" dBm"));
+
+ // print the SNR (Signal-to-Noise Ratio)
+ // of the last received packet
+ Serial.print(F("[LR2021] SNR:\t\t"));
+ Serial.print(radio.getSNR());
+ Serial.println(F(" dB"));
+
+ } else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
+ // timeout occurred while waiting for a packet
+ Serial.println(F("timeout!"));
+
+ } else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
+ // packet was received, but is malformed
+ Serial.println(F("CRC error!"));
+
+ } else {
+ // some other error occurred
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+
+ }
+}
diff --git a/lib/RadioLib/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino b/lib/RadioLib/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino
new file mode 100644
index 0000000..bcc63ab
--- /dev/null
+++ b/lib/RadioLib/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino
@@ -0,0 +1,145 @@
+/*
+ RadioLib LR2021 Receive with Interrupts Example
+
+ This example listens for LoRa transmissions and tries to
+ receive them. Once a packet is received, an interrupt is
+ triggered. To successfully receive data, the following
+ settings have to be the same on both transmitter
+ and receiver:
+ - carrier frequency
+ - bandwidth
+ - spreading factor
+ - coding rate
+ - sync word
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+// flag to indicate that a packet was received
+volatile bool receivedFlag = false;
+
+// this function is called when a complete packet
+// is received by the module
+// IMPORTANT: this function MUST be 'void' type
+// and MUST NOT have any arguments!
+#if defined(ESP8266) || defined(ESP32)
+ ICACHE_RAM_ATTR
+#endif
+void setFlag(void) {
+ // we got a packet, set the flag
+ receivedFlag = true;
+}
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.begin();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // set the function that will be called
+ // when new packet is received
+ radio.setPacketReceivedAction(setFlag);
+
+ // start listening for LoRa packets
+ Serial.print(F("[LR2021] Starting to listen ... "));
+ state = radio.startReceive();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // if needed, 'listen' mode can be disabled by calling
+ // any of the following methods:
+ //
+ // radio.standby()
+ // radio.sleep()
+ // radio.transmit();
+ // radio.receive();
+ // radio.scanChannel();
+}
+
+void loop() {
+ // check if the flag is set
+ if(receivedFlag) {
+ // reset flag
+ receivedFlag = false;
+
+ // you can read received data as an Arduino String
+ String str;
+ int state = radio.readData(str);
+
+ // you can also read received data as byte array
+ /*
+ byte byteArr[8];
+ int numBytes = radio.getPacketLength();
+ int state = radio.readData(byteArr, numBytes);
+ */
+
+ if (state == RADIOLIB_ERR_NONE) {
+ // packet was successfully received
+ Serial.println(F("[LR2021] Received packet!"));
+
+ // print data of the packet
+ Serial.print(F("[LR2021] Data:\t\t"));
+ Serial.println(str);
+
+ // print RSSI (Received Signal Strength Indicator)
+ Serial.print(F("[LR2021] RSSI:\t\t"));
+ Serial.print(radio.getRSSI());
+ Serial.println(F(" dBm"));
+
+ // print SNR (Signal-to-Noise Ratio)
+ Serial.print(F("[LR2021] SNR:\t\t"));
+ Serial.print(radio.getSNR());
+ Serial.println(F(" dB"));
+
+ } else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
+ // packet was received, but is malformed
+ Serial.println(F("CRC error!"));
+
+ } else {
+ // some other error occurred
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+
+ }
+ }
+}
diff --git a/lib/RadioLib/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino b/lib/RadioLib/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino
new file mode 100644
index 0000000..d516a7c
--- /dev/null
+++ b/lib/RadioLib/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino
@@ -0,0 +1,179 @@
+/*
+ RadioLib LR2021 Receive Multi-SF Example
+
+ This example listens for LoRa transmissions with different
+ spreading factors and tries to receive them.
+ Once a packet is received, an interrupt is triggered.
+
+ There are the following limits on configuration of multi-SF
+ (or side-detect) reception:
+ * In Rx mode, all side-detector spreading factors must be higher
+ than the primary one (configured via begin or setSpreadingFactor).
+ * For CAD mode, the above condition is inverted,
+ all side-detector spreading factors must be smaller.
+ * All packets to be detected/received must have the same header type
+ (implicit or explicit).
+ * If bandwidth is higher than 500 kHz,
+ at most 2 side detectors are allowed.
+ * If the primary spreading factor is 10, 11 or 12,
+ at most 2 side detectors are allowed.
+ * All spreading factors must be different.
+ * The difference between maximum and minimum spreading factor used
+ must be less than or equal to 4.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+// flag to indicate that a packet was received
+volatile bool receivedFlag = false;
+
+// this function is called when a complete packet
+// is received by the module
+// IMPORTANT: this function MUST be 'void' type
+// and MUST NOT have any arguments!
+#if defined(ESP8266) || defined(ESP32)
+ ICACHE_RAM_ATTR
+#endif
+void setFlag(void) {
+ // we got a packet, set the flag
+ receivedFlag = true;
+}
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.begin();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // prepare array of side detector configuration structures
+ // for spreading factors 10 - 12
+ // as the default spreading factor is 9, this satisfies
+ // the conditions listed at the top of this example
+ // this is just an example; you can also set different
+ // sync words, IQ inversions and low data-rate optimization
+ // depending on the types of transmitters you expect
+ const struct LR2021LoRaSideDetector_t sideDet[3] = {
+ { .sf = 10, .ldro = false, .invertIQ = false,
+ .syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE },
+ { .sf = 11, .ldro = true, .invertIQ = false,
+ .syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE },
+ { .sf = 12, .ldro = true, .invertIQ = false,
+ .syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE },
+ };
+ Serial.print(F("[LR2021] Setting side detector configuration ... "));
+ state = radio.setSideDetector(sideDet, 3);
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // set the function that will be called
+ // when new packet is received
+ radio.setPacketReceivedAction(setFlag);
+
+ // start listening for LoRa packets
+ Serial.print(F("[LR2021] Starting to listen ... "));
+ state = radio.startReceive();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // if needed, 'listen' mode can be disabled by calling
+ // any of the following methods:
+ //
+ // radio.standby()
+ // radio.sleep()
+ // radio.transmit();
+ // radio.receive();
+ // radio.scanChannel();
+}
+
+void loop() {
+ // check if the flag is set
+ if(receivedFlag) {
+ // reset flag
+ receivedFlag = false;
+
+ // you can read received data as an Arduino String
+ String str;
+ int state = radio.readData(str);
+
+ // you can also read received data as byte array
+ /*
+ byte byteArr[8];
+ int numBytes = radio.getPacketLength();
+ int state = radio.readData(byteArr, numBytes);
+ */
+
+ if (state == RADIOLIB_ERR_NONE) {
+ // packet was successfully received
+ Serial.println(F("[LR2021] Received packet!"));
+
+ // print data of the packet
+ Serial.print(F("[LR2021] Data:\t\t"));
+ Serial.println(str);
+
+ // print RSSI (Received Signal Strength Indicator)
+ Serial.print(F("[LR2021] RSSI:\t\t"));
+ Serial.print(radio.getRSSI());
+ Serial.println(F(" dBm"));
+
+ // print SNR (Signal-to-Noise Ratio)
+ Serial.print(F("[LR2021] SNR:\t\t"));
+ Serial.print(radio.getSNR());
+ Serial.println(F(" dB"));
+
+ } else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
+ // packet was received, but is malformed
+ Serial.println(F("CRC error!"));
+
+ } else {
+ // some other error occurred
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+
+ }
+ }
+}
diff --git a/lib/RadioLib/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino b/lib/RadioLib/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino
new file mode 100644
index 0000000..7b6518b
--- /dev/null
+++ b/lib/RadioLib/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino
@@ -0,0 +1,97 @@
+/*
+ RadioLib LR2021 Blocking Transmit Example
+
+ This example transmits packets using LR2021 LoRa radio module.
+ Each packet contains up to 256 bytes of data, in the form of:
+ - Arduino String
+ - null-terminated char array (C-string)
+ - arbitrary binary data (byte array)
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.begin();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ delay(1000);
+ while (true) { delay(10); }
+ }
+}
+
+// counter to keep track of transmitted packets
+int count = 0;
+
+void loop() {
+ Serial.print(F("[LR2021] Transmitting packet ... "));
+
+ // you can transmit C-string or Arduino string up to
+ // 256 characters long
+ // NOTE: transmit() is a blocking method!
+ // See example LR11x0_Transmit_Interrupt for details
+ // on non-blocking transmission method.
+ String str = "Hello World! #" + String(count++);
+ int state = radio.transmit(str);
+
+ // you can also transmit byte array up to 256 bytes long
+ /*
+ byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF};
+ int state = radio.transmit(byteArr, 8);
+ */
+
+ if (state == RADIOLIB_ERR_NONE) {
+ // the packet was successfully transmitted
+ Serial.println(F("success!"));
+
+ } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
+ // the supplied packet was longer than 256 bytes
+ Serial.println(F("too long!"));
+
+ } else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
+ // timeout occurred while transmitting packet
+ Serial.println(F("timeout!"));
+
+ } else {
+ // some other error occurred
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+
+ }
+
+ // wait for a second before transmitting again
+ delay(1000);
+}
diff --git a/lib/RadioLib/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino b/lib/RadioLib/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino
new file mode 100644
index 0000000..8265ed2
--- /dev/null
+++ b/lib/RadioLib/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino
@@ -0,0 +1,134 @@
+/*
+ RadioLib LR2021 Transmit with Interrupts Example
+
+ This example transmits LoRa packets with one second delays
+ between them. Each packet contains up to 256 bytes
+ of data, in the form of:
+ - Arduino String
+ - null-terminated char array (C-string)
+ - arbitrary binary data (byte array)
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// LR2021 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+LR2021 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+// save transmission state between loops
+int transmissionState = RADIOLIB_ERR_NONE;
+
+// flag to indicate that a packet was sent
+volatile bool transmittedFlag = false;
+
+// this function is called when a complete packet
+// is transmitted by the module
+// IMPORTANT: this function MUST be 'void' type
+// and MUST NOT have any arguments!
+#if defined(ESP8266) || defined(ESP32)
+ ICACHE_RAM_ATTR
+#endif
+void setFlag(void) {
+ // we sent a packet, set the flag
+ transmittedFlag = true;
+}
+
+void setup() {
+ Serial.begin(9600);
+
+ // LR2021 allows to use any DIO pin as the interrupt
+ // as an example, we set DIO10 to be the IRQ
+ // this has to be done prior to calling begin()!
+ radio.irqDioNum = 10;
+
+ // initialize LR2021 with default settings
+ Serial.print(F("[LR2021] Initializing ... "));
+ int state = radio.begin();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // set the function that will be called
+ // when packet transmission is finished
+ radio.setPacketSentAction(setFlag);
+
+ // start transmitting the first packet
+ Serial.print(F("[LR2021] Sending first packet ... "));
+
+ // you can transmit C-string or Arduino string up to
+ // 256 characters long
+ transmissionState = radio.startTransmit("Hello World!");
+
+ // you can also transmit byte array up to 256 bytes long
+ /*
+ byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
+ 0x89, 0xAB, 0xCD, 0xEF};
+ state = radio.startTransmit(byteArr, 8);
+ */
+}
+
+// counter to keep track of transmitted packets
+int count = 0;
+
+void loop() {
+ // check if the previous transmission finished
+ if(transmittedFlag) {
+ // reset flag
+ transmittedFlag = false;
+
+ if (transmissionState == RADIOLIB_ERR_NONE) {
+ // packet was successfully sent
+ Serial.println(F("transmission finished!"));
+
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(transmissionState);
+
+ }
+
+ // clean up after transmission is finished
+ // this will ensure transmitter is disabled,
+ // RF switch is powered down etc.
+ radio.finishTransmit();
+
+ // wait a second before transmitting again
+ delay(1000);
+
+ // send another one
+ Serial.print(F("[LR2021] Sending another packet ... "));
+
+ // you can transmit C-string or Arduino string up to
+ // 256 characters long
+ String str = "Hello World! #" + String(count++);
+ transmissionState = radio.startTransmit(str);
+
+ // you can also transmit byte array up to 256 bytes long
+ /*
+ byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
+ 0x89, 0xAB, 0xCD, 0xEF};
+ transmissionState = radio.startTransmit(byteArr, 8);
+ */
+ }
+}
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_ABP/configABP.h
index 61bc63e..a19a1dc 100644
--- a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_ABP/configABP.h
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_ABP/configABP.h
@@ -41,9 +41,11 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds
// for the curious, the #ifndef blocks allow for automated testing &/or you can
// put your EUI & keys in to your platformio.ini - see wiki for more tips
-// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500
+// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN470
const LoRaWANBand_t Region = EU868;
-const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
+
+// subband choice: for US915/AU915 set to 2, for CN470 set to 1, otherwise leave on 0
+const uint8_t subBand = 0;
// ============================================================================
// Below is to support the sketch - only make changes if the notes say so ...
@@ -70,8 +72,8 @@ String stateDecode(const int16_t result) {
return "ERR_PACKET_TOO_LONG";
case RADIOLIB_ERR_RX_TIMEOUT:
return "ERR_RX_TIMEOUT";
- case RADIOLIB_ERR_CRC_MISMATCH:
- return "ERR_CRC_MISMATCH";
+ case RADIOLIB_ERR_MIC_MISMATCH:
+ return "ERR_MIC_MISMATCH";
case RADIOLIB_ERR_INVALID_BANDWIDTH:
return "ERR_INVALID_BANDWIDTH";
case RADIOLIB_ERR_INVALID_SPREADING_FACTOR:
@@ -102,10 +104,6 @@ String stateDecode(const int16_t result) {
return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND";
case RADIOLIB_ERR_JOIN_NONCE_INVALID:
return "RADIOLIB_ERR_JOIN_NONCE_INVALID";
- case RADIOLIB_ERR_N_FCNT_DOWN_INVALID:
- return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID";
- case RADIOLIB_ERR_A_FCNT_DOWN_INVALID:
- return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID";
case RADIOLIB_ERR_DWELL_TIME_EXCEEDED:
return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED";
case RADIOLIB_ERR_CHECKSUM_MISMATCH:
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino
new file mode 100644
index 0000000..db2a5e7
--- /dev/null
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino
@@ -0,0 +1,136 @@
+/*
+ RadioLib LoRaWAN Class C Example
+
+ This example joins a LoRaWAN network and switches to Class C.
+ Note that a confirmed uplink with a confirming downlink is
+ required for the switch to Class C to complete. This example
+ assumes that coverage is good enough to receive the downlink
+ at once. It is up to you to handle the situation if coverage
+ is worse.
+
+ Running this examples REQUIRES you to check "Resets DevNonces"
+ on your LoRaWAN dashboard. Refer to the network's
+ documentation on how to do this.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+
+ For LoRaWAN details, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/LoRaWAN
+
+*/
+
+#include "config.h"
+
+void setup() {
+ Serial.begin(115200);
+ while(!Serial);
+ delay(5000); // Give time to switch to the serial monitor
+ Serial.println(F("\nSetup ... "));
+
+ Serial.println(F("Initialise the radio"));
+ int16_t state = radio.begin();
+ debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);
+
+ // Setup the OTAA session information
+ state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
+ debug(state != RADIOLIB_ERR_NONE, F("Initialise node failed"), state, true);
+
+ Serial.println(F("Join ('login') the LoRaWAN Network"));
+ state = node.activateOTAA();
+ debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true);
+
+ // switch class
+ node.setClass(RADIOLIB_LORAWAN_CLASS_C);
+
+ // read the note at the top about this first confirmed uplink
+ const char* payload = "C";
+ Serial.println(F("Sending a confirmed uplink"));
+ state = node.sendReceive(payload, 1, true);
+ debug(state <= 0, F("No downlink received"), state, true);
+
+ Serial.println(F("Ready!\n"));
+}
+
+uint32_t lastUplink = 0;
+
+void loop() {
+ uint8_t downlinkPayload[255];
+ size_t downlinkLen = 0;
+ LoRaWANEvent_t downlinkEvent;
+
+ // check if a Class C downlink is ready for processing
+ // tip: internally, this just checks a boolean;
+ // it does not poll the radio over SPI.
+ // tip: you are not required to continuously call
+ // this function; you can do other stuff in between.
+ // however, a downlink may be overwritten if you
+ // don't call this function in time for the previous one.
+ int16_t state = node.getDownlinkClassC(downlinkPayload, &downlinkLen, &downlinkEvent);
+ if(state > 0) {
+ Serial.println(F("Received a Class C downlink!"));
+ // Did we get a downlink with data for us
+ if(downlinkLen > 0) {
+ Serial.println(F("Downlink data: "));
+ arrayDump(downlinkPayload, downlinkLen);
+ }
+
+ // print extra information about the event
+ Serial.println(F("[LoRaWAN] Event information:"));
+ Serial.print(F("[LoRaWAN] Datarate:\t"));
+ Serial.println(downlinkEvent.datarate);
+ Serial.print(F("[LoRaWAN] Frequency:\t"));
+ Serial.print(downlinkEvent.freq, 3);
+ Serial.println(F(" MHz"));
+ Serial.print(F("[LoRaWAN] Frame count:\t"));
+ Serial.println(downlinkEvent.fCnt);
+ Serial.print(F("[LoRaWAN] Port:\t\t"));
+ Serial.println(downlinkEvent.fPort);
+ Serial.println(F(" ms"));
+ Serial.print(F("[LoRaWAN] Rx window: \t"));
+ Serial.println(state);
+ Serial.print(F("[LoRaWAN] Cast:\t\t"));
+ Serial.println(downlinkEvent.multicast ? "Multi" : "Uni");
+ }
+
+ // if less than uplinkIntervalSeconds have elapsed since previous uplink,
+ // stop and go back to the top of the loop()
+ if(millis() - lastUplink < uplinkIntervalSeconds * 1000) {
+ return;
+ }
+
+ Serial.println(F("Sending uplink"));
+
+ // This is the place to gather the sensor inputs
+ // Instead of reading any real sensor, we just generate some random numbers as example
+ uint8_t value1 = radio.random(100);
+ uint16_t value2 = radio.random(2000);
+
+ // Build payload byte array
+ uint8_t uplinkPayload[3];
+ uplinkPayload[0] = value1;
+ uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions
+ uplinkPayload[2] = lowByte(value2);
+
+ // Perform an uplink
+ state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload));
+ debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false);
+
+ // Check if a downlink was received
+ // (state 0 = no downlink, state 1/2/3 = downlink in window Rx1/Rx2/RxC)
+ if(state > 0) {
+ Serial.println(F("Received a downlink"));
+ } else {
+ Serial.println(F("No downlink received"));
+ }
+
+ Serial.print(F("Next uplink in "));
+ Serial.print(uplinkIntervalSeconds);
+ Serial.println(F(" seconds\n"));
+
+ // set timestamp of last uplink
+ lastUplink = millis();
+}
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Class_C/config.h b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Class_C/config.h
new file mode 100644
index 0000000..dd85327
--- /dev/null
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Class_C/config.h
@@ -0,0 +1,141 @@
+#ifndef _RADIOLIB_EX_LORAWAN_CONFIG_H
+#define _RADIOLIB_EX_LORAWAN_CONFIG_H
+
+#include
+
+// first you have to set your radio model and pin configuration
+// this is provided just as a default example
+SX1262 radio = new Module(8, 14, 12, 13);
+
+// if you have RadioBoards (https://github.com/radiolib-org/RadioBoards)
+// and are using one of the supported boards, you can do the following:
+/*
+#define RADIO_BOARD_AUTO
+#include
+
+Radio radio = new RadioModule();
+*/
+
+// how often to send an uplink - consider legal & FUP constraints - see notes
+const uint32_t uplinkIntervalSeconds = 1UL * 60UL; // minutes x seconds
+
+// joinEUI - previous versions of LoRaWAN called this AppEUI
+// for development purposes you can use all zeros - see wiki for details
+#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000
+
+// the Device EUI & two keys can be generated on the TTN console
+#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI
+#define RADIOLIB_LORAWAN_DEV_EUI 0x---------------
+#endif
+#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key
+#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here
+#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+
+// for the curious, the #ifndef blocks allow for automated testing &/or you can
+// put your EUI & keys in to your platformio.ini - see wiki for more tips
+
+// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500
+const LoRaWANBand_t Region = EU868;
+const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
+
+// ============================================================================
+// Below is to support the sketch - only make changes if the notes say so ...
+
+// copy over the EUI's & keys in to the something that will not compile if incorrectly formatted
+uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI;
+uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI;
+uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY };
+uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY };
+
+// create the LoRaWAN node
+LoRaWANNode node(&radio, &Region, subBand);
+
+// result code to text - these are error codes that can be raised when using LoRaWAN
+// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list
+String stateDecode(const int16_t result) {
+ switch (result) {
+ case RADIOLIB_ERR_NONE:
+ return "ERR_NONE";
+ case RADIOLIB_ERR_CHIP_NOT_FOUND:
+ return "ERR_CHIP_NOT_FOUND";
+ case RADIOLIB_ERR_PACKET_TOO_LONG:
+ return "ERR_PACKET_TOO_LONG";
+ case RADIOLIB_ERR_RX_TIMEOUT:
+ return "ERR_RX_TIMEOUT";
+ case RADIOLIB_ERR_MIC_MISMATCH:
+ return "ERR_MIC_MISMATCH";
+ case RADIOLIB_ERR_INVALID_BANDWIDTH:
+ return "ERR_INVALID_BANDWIDTH";
+ case RADIOLIB_ERR_INVALID_SPREADING_FACTOR:
+ return "ERR_INVALID_SPREADING_FACTOR";
+ case RADIOLIB_ERR_INVALID_CODING_RATE:
+ return "ERR_INVALID_CODING_RATE";
+ case RADIOLIB_ERR_INVALID_FREQUENCY:
+ return "ERR_INVALID_FREQUENCY";
+ case RADIOLIB_ERR_INVALID_OUTPUT_POWER:
+ return "ERR_INVALID_OUTPUT_POWER";
+ case RADIOLIB_ERR_NETWORK_NOT_JOINED:
+ return "RADIOLIB_ERR_NETWORK_NOT_JOINED";
+ case RADIOLIB_ERR_DOWNLINK_MALFORMED:
+ return "RADIOLIB_ERR_DOWNLINK_MALFORMED";
+ case RADIOLIB_ERR_INVALID_REVISION:
+ return "RADIOLIB_ERR_INVALID_REVISION";
+ case RADIOLIB_ERR_INVALID_PORT:
+ return "RADIOLIB_ERR_INVALID_PORT";
+ case RADIOLIB_ERR_NO_RX_WINDOW:
+ return "RADIOLIB_ERR_NO_RX_WINDOW";
+ case RADIOLIB_ERR_INVALID_CID:
+ return "RADIOLIB_ERR_INVALID_CID";
+ case RADIOLIB_ERR_UPLINK_UNAVAILABLE:
+ return "RADIOLIB_ERR_UPLINK_UNAVAILABLE";
+ case RADIOLIB_ERR_COMMAND_QUEUE_FULL:
+ return "RADIOLIB_ERR_COMMAND_QUEUE_FULL";
+ case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND:
+ return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND";
+ case RADIOLIB_ERR_JOIN_NONCE_INVALID:
+ return "RADIOLIB_ERR_JOIN_NONCE_INVALID";
+ case RADIOLIB_ERR_DWELL_TIME_EXCEEDED:
+ return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED";
+ case RADIOLIB_ERR_CHECKSUM_MISMATCH:
+ return "RADIOLIB_ERR_CHECKSUM_MISMATCH";
+ case RADIOLIB_ERR_NO_JOIN_ACCEPT:
+ return "RADIOLIB_ERR_NO_JOIN_ACCEPT";
+ case RADIOLIB_LORAWAN_SESSION_RESTORED:
+ return "RADIOLIB_LORAWAN_SESSION_RESTORED";
+ case RADIOLIB_LORAWAN_NEW_SESSION:
+ return "RADIOLIB_LORAWAN_NEW_SESSION";
+ case RADIOLIB_ERR_NONCES_DISCARDED:
+ return "RADIOLIB_ERR_NONCES_DISCARDED";
+ case RADIOLIB_ERR_SESSION_DISCARDED:
+ return "RADIOLIB_ERR_SESSION_DISCARDED";
+ }
+ return "See https://jgromes.github.io/RadioLib/group__status__codes.html";
+}
+
+// helper function to display any issues
+void debug(bool failed, const __FlashStringHelper* message, int state, bool halt) {
+ if(failed) {
+ Serial.print(message);
+ Serial.print(" - ");
+ Serial.print(stateDecode(state));
+ Serial.print(" (");
+ Serial.print(state);
+ Serial.println(")");
+ while(halt) { delay(1); }
+ }
+}
+
+// helper function to display a byte array
+void arrayDump(uint8_t *buffer, uint16_t len) {
+ for(uint16_t c = 0; c < len; c++) {
+ char b = buffer[c];
+ if(b < 0x10) { Serial.print('0'); }
+ Serial.print(b, HEX);
+ }
+ Serial.println();
+}
+
+#endif
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino
new file mode 100644
index 0000000..7e5be0b
--- /dev/null
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino
@@ -0,0 +1,133 @@
+/*
+ RadioLib LoRaWAN Multicast Example
+
+ This example joins a LoRaWAN network and starts a
+ Multicast session (only Multicast over Class C is implemented).
+ You should refer to the network's documentation on how
+ to create a Multicast group (or device).
+ Note that you can switch the device to Class C as well
+ to receive Unicast downlinks. In this case, you must
+ use the downlink event details to discern whether a
+ downlink belongs to the Unicast or Multicast session.
+
+ Running this examples REQUIRES you to check "Resets DevNonces"
+ on your LoRaWAN dashboard. Refer to the network's
+ documentation on how to do this.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+
+ For LoRaWAN details, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/LoRaWAN
+
+*/
+
+#include "config.h"
+
+void setup() {
+ Serial.begin(115200);
+ while(!Serial);
+ delay(5000); // Give time to switch to the serial monitor
+ Serial.println(F("\nSetup ... "));
+
+ Serial.println(F("Initialise the radio"));
+ int16_t state = radio.begin();
+ debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);
+
+ // Setup the OTAA session information
+ state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
+ debug(state != RADIOLIB_ERR_NONE, F("Initialise node failed"), state, true);
+
+ Serial.println(F("Join ('login') the LoRaWAN Network"));
+ state = node.activateOTAA();
+ debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true);
+
+ // Start a Multicast session over Class C
+ // (this will automatically perform a switch to Class C for Multicast)
+ node.startMulticastSession(RADIOLIB_LORAWAN_CLASS_C, mcDevAddr, mcAppSKey, mcNwkSKey);
+
+ Serial.println(F("Ready!\n"));
+}
+
+uint32_t lastUplink = 0;
+
+void loop() {
+ uint8_t downlinkPayload[255];
+ size_t downlinkLen = 0;
+ LoRaWANEvent_t downlinkEvent;
+
+ // check if a Class C downlink is ready for processing
+ // tip: internally, this just checks a boolean;
+ // it does not poll the radio over SPI.
+ // tip: you are not required to continuously call
+ // this function; you can do other stuff in between.
+ // however, a downlink may be overwritten if you
+ // don't call this function in time for the previous one.
+ int16_t state = node.getDownlinkClassC(downlinkPayload, &downlinkLen, &downlinkEvent);
+ if(state > 0) {
+ Serial.println(F("Received a Class C downlink!"));
+ // Did we get a downlink with data for us
+ if(downlinkLen > 0) {
+ Serial.println(F("Downlink data: "));
+ arrayDump(downlinkPayload, downlinkLen);
+ }
+
+ // print extra information about the event
+ Serial.println(F("[LoRaWAN] Event information:"));
+ Serial.print(F("[LoRaWAN] Datarate:\t"));
+ Serial.println(downlinkEvent.datarate);
+ Serial.print(F("[LoRaWAN] Frequency:\t"));
+ Serial.print(downlinkEvent.freq, 3);
+ Serial.println(F(" MHz"));
+ Serial.print(F("[LoRaWAN] Frame count:\t"));
+ Serial.println(downlinkEvent.fCnt);
+ Serial.print(F("[LoRaWAN] Port:\t\t"));
+ Serial.println(downlinkEvent.fPort);
+ Serial.println(F(" ms"));
+ Serial.print(F("[LoRaWAN] Rx window: \t"));
+ Serial.println(state);
+ Serial.print(F("[LoRaWAN] Cast:\t\t"));
+ Serial.println(downlinkEvent.multicast ? "Multi" : "Uni");
+ }
+
+ // if less than uplinkIntervalSeconds have elapsed since previous uplink,
+ // stop and go back to the top of the loop()
+ if(millis() - lastUplink < uplinkIntervalSeconds * 1000) {
+ return;
+ }
+
+ Serial.println(F("Sending uplink"));
+
+ // This is the place to gather the sensor inputs
+ // Instead of reading any real sensor, we just generate some random numbers as example
+ uint8_t value1 = radio.random(100);
+ uint16_t value2 = radio.random(2000);
+
+ // Build payload byte array
+ uint8_t uplinkPayload[3];
+ uplinkPayload[0] = value1;
+ uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions
+ uplinkPayload[2] = lowByte(value2);
+
+ // Perform an uplink
+ state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload));
+ debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false);
+
+ // Check if a downlink was received
+ // (state 0 = no downlink, state 1/2/3 = downlink in window Rx1/Rx2/RxC)
+ if(state > 0) {
+ Serial.println(F("Received a downlink"));
+ } else {
+ Serial.println(F("No downlink received"));
+ }
+
+ Serial.print(F("Next uplink in "));
+ Serial.print(uplinkIntervalSeconds);
+ Serial.println(F(" seconds\n"));
+
+ // set timestamp of last uplink
+ lastUplink = millis();
+}
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Multicast/config.h b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Multicast/config.h
new file mode 100644
index 0000000..bbe12e7
--- /dev/null
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Multicast/config.h
@@ -0,0 +1,154 @@
+#ifndef _RADIOLIB_EX_LORAWAN_CONFIG_H
+#define _RADIOLIB_EX_LORAWAN_CONFIG_H
+
+#include
+
+// first you have to set your radio model and pin configuration
+// this is provided just as a default example
+SX1262 radio = new Module(8, 14, 12, 13);
+
+// if you have RadioBoards (https://github.com/radiolib-org/RadioBoards)
+// and are using one of the supported boards, you can do the following:
+/*
+#define RADIO_BOARD_AUTO
+#include
+
+Radio radio = new RadioModule();
+*/
+
+// how often to send an uplink - consider legal & FUP constraints - see notes
+const uint32_t uplinkIntervalSeconds = 1UL * 60UL; // minutes x seconds
+
+// joinEUI - previous versions of LoRaWAN called this AppEUI
+// for development purposes you can use all zeros - see wiki for details
+#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000
+
+// the Device EUI & two keys can be generated on the TTN console
+#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI
+#define RADIOLIB_LORAWAN_DEV_EUI 0x---------------
+#endif
+#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key
+#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here
+#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+
+#ifndef RADIOLIB_LORAWAN_MC_DEV_ADDR // Replace with your Multicast Device Address
+#define RADIOLIB_LORAWAN_MC_DEV_ADDR 0x---------------
+#endif
+#ifndef RADIOLIB_LORAWAN_MC_APP_SKEY // Replace with your Multicast App SKey
+#define RADIOLIB_LORAWAN_MC_APP_SKEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+#ifndef RADIOLIB_LORAWAN_MC_NWK_SKEY // Put your Multicast Nwk SKey here
+#define RADIOLIB_LORAWAN_MC_NWK_SKEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+
+// for the curious, the #ifndef blocks allow for automated testing &/or you can
+// put your EUI & keys in to your platformio.ini - see wiki for more tips
+
+// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500
+const LoRaWANBand_t Region = EU868;
+const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
+
+// ============================================================================
+// Below is to support the sketch - only make changes if the notes say so ...
+
+// copy over the EUI's & keys in to the something that will not compile if incorrectly formatted
+uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI;
+uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI;
+uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY };
+uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY };
+uint32_t mcDevAddr = RADIOLIB_LORAWAN_MC_DEV_ADDR;
+uint8_t mcAppSKey[] = { RADIOLIB_LORAWAN_MC_APP_SKEY };
+uint8_t mcNwkSKey[] = { RADIOLIB_LORAWAN_MC_NWK_SKEY };
+
+// create the LoRaWAN node
+LoRaWANNode node(&radio, &Region, subBand);
+
+// result code to text - these are error codes that can be raised when using LoRaWAN
+// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list
+String stateDecode(const int16_t result) {
+ switch (result) {
+ case RADIOLIB_ERR_NONE:
+ return "ERR_NONE";
+ case RADIOLIB_ERR_CHIP_NOT_FOUND:
+ return "ERR_CHIP_NOT_FOUND";
+ case RADIOLIB_ERR_PACKET_TOO_LONG:
+ return "ERR_PACKET_TOO_LONG";
+ case RADIOLIB_ERR_RX_TIMEOUT:
+ return "ERR_RX_TIMEOUT";
+ case RADIOLIB_ERR_MIC_MISMATCH:
+ return "ERR_MIC_MISMATCH";
+ case RADIOLIB_ERR_INVALID_BANDWIDTH:
+ return "ERR_INVALID_BANDWIDTH";
+ case RADIOLIB_ERR_INVALID_SPREADING_FACTOR:
+ return "ERR_INVALID_SPREADING_FACTOR";
+ case RADIOLIB_ERR_INVALID_CODING_RATE:
+ return "ERR_INVALID_CODING_RATE";
+ case RADIOLIB_ERR_INVALID_FREQUENCY:
+ return "ERR_INVALID_FREQUENCY";
+ case RADIOLIB_ERR_INVALID_OUTPUT_POWER:
+ return "ERR_INVALID_OUTPUT_POWER";
+ case RADIOLIB_ERR_NETWORK_NOT_JOINED:
+ return "RADIOLIB_ERR_NETWORK_NOT_JOINED";
+ case RADIOLIB_ERR_DOWNLINK_MALFORMED:
+ return "RADIOLIB_ERR_DOWNLINK_MALFORMED";
+ case RADIOLIB_ERR_INVALID_REVISION:
+ return "RADIOLIB_ERR_INVALID_REVISION";
+ case RADIOLIB_ERR_INVALID_PORT:
+ return "RADIOLIB_ERR_INVALID_PORT";
+ case RADIOLIB_ERR_NO_RX_WINDOW:
+ return "RADIOLIB_ERR_NO_RX_WINDOW";
+ case RADIOLIB_ERR_INVALID_CID:
+ return "RADIOLIB_ERR_INVALID_CID";
+ case RADIOLIB_ERR_UPLINK_UNAVAILABLE:
+ return "RADIOLIB_ERR_UPLINK_UNAVAILABLE";
+ case RADIOLIB_ERR_COMMAND_QUEUE_FULL:
+ return "RADIOLIB_ERR_COMMAND_QUEUE_FULL";
+ case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND:
+ return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND";
+ case RADIOLIB_ERR_JOIN_NONCE_INVALID:
+ return "RADIOLIB_ERR_JOIN_NONCE_INVALID";
+ case RADIOLIB_ERR_DWELL_TIME_EXCEEDED:
+ return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED";
+ case RADIOLIB_ERR_CHECKSUM_MISMATCH:
+ return "RADIOLIB_ERR_CHECKSUM_MISMATCH";
+ case RADIOLIB_ERR_NO_JOIN_ACCEPT:
+ return "RADIOLIB_ERR_NO_JOIN_ACCEPT";
+ case RADIOLIB_LORAWAN_SESSION_RESTORED:
+ return "RADIOLIB_LORAWAN_SESSION_RESTORED";
+ case RADIOLIB_LORAWAN_NEW_SESSION:
+ return "RADIOLIB_LORAWAN_NEW_SESSION";
+ case RADIOLIB_ERR_NONCES_DISCARDED:
+ return "RADIOLIB_ERR_NONCES_DISCARDED";
+ case RADIOLIB_ERR_SESSION_DISCARDED:
+ return "RADIOLIB_ERR_SESSION_DISCARDED";
+ }
+ return "See https://jgromes.github.io/RadioLib/group__status__codes.html";
+}
+
+// helper function to display any issues
+void debug(bool failed, const __FlashStringHelper* message, int state, bool halt) {
+ if(failed) {
+ Serial.print(message);
+ Serial.print(" - ");
+ Serial.print(stateDecode(state));
+ Serial.print(" (");
+ Serial.print(state);
+ Serial.println(")");
+ while(halt) { delay(1); }
+ }
+}
+
+// helper function to display a byte array
+void arrayDump(uint8_t *buffer, uint16_t len) {
+ for(uint16_t c = 0; c < len; c++) {
+ char b = buffer[c];
+ if(b < 0x10) { Serial.print('0'); }
+ Serial.print(b, HEX);
+ }
+ Serial.println();
+}
+
+#endif
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino
index 87d7f1e..f39d08b 100644
--- a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino
@@ -44,15 +44,18 @@ void setup() {
Serial.println(F("Initialise the radio"));
state = radio.begin();
debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);
-
- // Override the default join rate
- uint8_t joinDR = 4;
-
+
+ // Optionally provide a custom sleep function - see config.h
+ //node.setSleepFunction(customDelay);
+
// Setup the OTAA session information
node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
+ // Override the default join rate
+ node.setDatarate(4);
+
Serial.println(F("Join ('login') the LoRaWAN Network"));
- state = node.activateOTAA(joinDR);
+ state = node.activateOTAA();
debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true);
// Print the DevAddr
@@ -175,13 +178,14 @@ void loop() {
Serial.println(gwCnt);
}
- uint32_t networkTime = 0;
- uint8_t fracSecond = 0;
- if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) {
+ uint32_t timestamp = 0;
+ uint16_t milliseconds = 0;
+ if(node.getMacDeviceTimeAns(×tamp, &milliseconds, true) == RADIOLIB_ERR_NONE) {
Serial.print(F("[LoRaWAN] DeviceTime Unix:\t"));
- Serial.println(networkTime);
- Serial.print(F("[LoRaWAN] DeviceTime second:\t1/"));
- Serial.println(fracSecond);
+ Serial.println(timestamp);
+ Serial.print(F("[LoRaWAN] DeviceTime frac:\t"));
+ Serial.print(milliseconds);
+ Serial.println(F(" ms"));
}
} else {
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Reference/config.h b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Reference/config.h
index 21c79f8..5de9cc9 100644
--- a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Reference/config.h
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Reference/config.h
@@ -37,9 +37,11 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds
// for the curious, the #ifndef blocks allow for automated testing &/or you can
// put your EUI & keys in to your platformio.ini - see wiki for more tips
-// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500
+// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN470
const LoRaWANBand_t Region = EU868;
-const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
+
+// subband choice: for US915/AU915 set to 2, for CN470 set to 1, otherwise leave on 0
+const uint8_t subBand = 0;
// ============================================================================
// Below is to support the sketch - only make changes if the notes say so ...
@@ -65,8 +67,8 @@ String stateDecode(const int16_t result) {
return "ERR_PACKET_TOO_LONG";
case RADIOLIB_ERR_RX_TIMEOUT:
return "ERR_RX_TIMEOUT";
- case RADIOLIB_ERR_CRC_MISMATCH:
- return "ERR_CRC_MISMATCH";
+ case RADIOLIB_ERR_MIC_MISMATCH:
+ return "ERR_MIC_MISMATCH";
case RADIOLIB_ERR_INVALID_BANDWIDTH:
return "ERR_INVALID_BANDWIDTH";
case RADIOLIB_ERR_INVALID_SPREADING_FACTOR:
@@ -97,10 +99,6 @@ String stateDecode(const int16_t result) {
return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND";
case RADIOLIB_ERR_JOIN_NONCE_INVALID:
return "RADIOLIB_ERR_JOIN_NONCE_INVALID";
- case RADIOLIB_ERR_N_FCNT_DOWN_INVALID:
- return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID";
- case RADIOLIB_ERR_A_FCNT_DOWN_INVALID:
- return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID";
case RADIOLIB_ERR_DWELL_TIME_EXCEEDED:
return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED";
case RADIOLIB_ERR_CHECKSUM_MISMATCH:
@@ -142,4 +140,19 @@ void arrayDump(uint8_t *buffer, uint16_t len) {
Serial.println();
}
+// Custom delay function:
+// Communication over LoRaWAN includes a lot of delays.
+// By default, RadioLib will use the Arduino delay() function,
+// which will waste a lot of power. However, you can put your
+// microcontroller to sleep instead by customizing the function below,
+// and providing it to RadioLib via "node.setSleepFunction".
+// NOTE: You ahve to ensure that this function is timed precisely, and
+// does actually wait for the amount of time specified!
+// Failure to do so will result in missed downlinks or failed join!
+void customDelay(RadioLibTime_t ms) {
+ // this is just an example, so we use the Arduino delay() function,
+ // but you can put your microcontroller to sleep here
+ ::delay(ms);
+}
+
#endif
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Starter/config.h b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Starter/config.h
index 21c79f8..7d025ab 100644
--- a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Starter/config.h
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Starter/config.h
@@ -37,9 +37,11 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds
// for the curious, the #ifndef blocks allow for automated testing &/or you can
// put your EUI & keys in to your platformio.ini - see wiki for more tips
-// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500
+// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN470
const LoRaWANBand_t Region = EU868;
-const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
+
+// subband choice: for US915/AU915 set to 2, for CN470 set to 1, otherwise leave on 0
+const uint8_t subBand = 0;
// ============================================================================
// Below is to support the sketch - only make changes if the notes say so ...
@@ -65,8 +67,8 @@ String stateDecode(const int16_t result) {
return "ERR_PACKET_TOO_LONG";
case RADIOLIB_ERR_RX_TIMEOUT:
return "ERR_RX_TIMEOUT";
- case RADIOLIB_ERR_CRC_MISMATCH:
- return "ERR_CRC_MISMATCH";
+ case RADIOLIB_ERR_MIC_MISMATCH:
+ return "ERR_MIC_MISMATCH";
case RADIOLIB_ERR_INVALID_BANDWIDTH:
return "ERR_INVALID_BANDWIDTH";
case RADIOLIB_ERR_INVALID_SPREADING_FACTOR:
@@ -97,10 +99,6 @@ String stateDecode(const int16_t result) {
return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND";
case RADIOLIB_ERR_JOIN_NONCE_INVALID:
return "RADIOLIB_ERR_JOIN_NONCE_INVALID";
- case RADIOLIB_ERR_N_FCNT_DOWN_INVALID:
- return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID";
- case RADIOLIB_ERR_A_FCNT_DOWN_INVALID:
- return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID";
case RADIOLIB_ERR_DWELL_TIME_EXCEEDED:
return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED";
case RADIOLIB_ERR_CHECKSUM_MISMATCH:
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Starter/notes.md b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Starter/notes.md
index 49a37f8..9305968 100644
--- a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Starter/notes.md
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_Starter/notes.md
@@ -1,10 +1,8 @@
-
-
# RadioLib LoRaWAN on TTN starter script
## Welcome
-These notes are for someone who has successfully created a few sketches for their Arduino based device but is starting out with LoRaWAN. You don't have to be a C coding ninja but some familarity with C and procedural programming is assumed. The absolutely simplest way to get started is to buy some known good hardware that's all done for you so you can concentrate on the code & configuration.
+These notes are for someone who has successfully created a few sketches for their Arduino based device but is starting out with LoRaWAN. You don't have to be a C++ coding ninja but some familarity with C++ and procedural programming is assumed. The absolutely simplest way to get started is to buy some known good hardware that's all done for you so you can concentrate on the code & configuration.
## Introduction
@@ -18,7 +16,7 @@ For questions about using RadioLib there is the discussions section (https://git
## Register & setup on TTN
-This sketch isn't particularly aimed at The Things Stack (TTS) but you can get a free Sandbox account and the following instructions are for that. Helium does not support LoRaWAN v1.1 which is the version implemented by RadioLib. Chirpstack & other LoRaWAN Network Server (LNS) stacks have not yet been tried so YMMV.
+This sketch isn't particularly aimed at The Things Stack (TTS) but you can get a free Sandbox account and the following instructions are for that. Chirpstack works just as well, but the buttons and labels may have different names. We discourage the use of Helium as it does not support LoRaWAN v1.1 and has some other odd limitations. Other LoRaWAN Network Servers (LNS) have not been tested by the developers, so YMMV.
Why no screen shots? TTS is a web based app, one that you will need to become familiar with and we will need to direct you to some of the less obvious parts. So much better that you learn the layouts in concept than slavishly follow screen shots that can & will go stale.
@@ -52,13 +50,13 @@ You are making your own device using a third party LoRaWAN stack so there will n
Choose the Frequency plan appropriate for your region. Consider that almost all countries have laws relating to what frequencies you use so don't get creative. For Europe please use the recommended option. For other regions use the entry marked 'used by TTN'.
-Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP001 Regional Parameters 1.1 revision B.
+Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP002 Regional Parameters 1.0.4.
At this point you will be asked for your JoinEUI. As this is a DIY device and we are using RadioLib, you can use all zero's as recommended by The LoRa Alliance TR007 Technical Recommendations document. Once you've put in all zeros and clicked confirm you will be asked for a DevEUI, AppKey and NwkKey. It is preferable to have the console generate them so they are properly formatted.
-Your End device ID can be changed to make the device more identifiable. Something related to your hardware helps - like devicename-01. The you can click the blue 'Register device'.
+Your End device ID can be changed to make the device more identifiable. Something related to your hardware helps - like `devicename-01`. The you can click the blue 'Register device'.
-When many sensors are big deployed, a device is registered, batteries put in, it joins and gets on with sending data for the next few years. For development purposes we need to turn off one of the security settings so that you can join & uplink out of the normal sequence that a device in the field would do.
+When retail sensors are being deployed, a device is registered, batteries put in, it joins and gets on with sending data for the next few years. For development purposes however we need to turn off one of the security settings so that you can join & uplink out of the normal sequence that a device in the field would do.
Click on General Settings, scroll down to Join settings, click the Expand button, scroll down and click the 'Resets join nonces' option. You will see a warning about replay attacks which is entirely proper & correct. If anyone eavesdropping in your area on your LoRa transmissions could fake a join and send uplinks from their device but only if they happened to find out your AppKey & NwkKey which is kept securely on the TTN servers and is never transmitted over the air, so they'd also have to login to your account, which is protected by your password.
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h
new file mode 100644
index 0000000..63704d8
--- /dev/null
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h
@@ -0,0 +1,238 @@
+#include
+#include
+// #include
+
+#warning "The variables below must match your main code. Please check your radio type!"
+extern SX1278 radio; // this can be any LoRaWAN-compatible type (e.g. SX1262)
+extern LoRaWANNode node;
+extern uint32_t periodicity;
+extern bool isConfirmed;
+extern bool reply;
+extern uint8_t dataUp[255];
+extern size_t lenUp;
+extern uint8_t fPort;
+
+#define RADIOLIB_LORAWAN_TS009_PACKAGE_VERSION (0x00)
+#define RADIOLIB_LORAWAN_TS009_DUT_RESET (0x01)
+#define RADIOLIB_LORAWAN_TS009_DUT_JOIN (0x02)
+#define RADIOLIB_LORAWAN_TS009_SWITCH_CLASS (0x03)
+#define RADIOLIB_LORAWAN_TS009_ADR_BIT_CHANGE (0x04)
+#define RADIOLIB_LORAWAN_TS009_REGIONAL_DUTY_CYCLE (0x05)
+#define RADIOLIB_LORAWAN_TS009_TX_PERIODICITY_CHANGE (0x06)
+#define RADIOLIB_LORAWAN_TS009_TX_FRAMES_CTRL (0x07)
+#define RADIOLIB_LORAWAN_TS009_ECHO_PAYLOAD (0x08)
+#define RADIOLIB_LORAWAN_TS009_RX_APP_CNT (0x09)
+#define RADIOLIB_LORAWAN_TS009_RX_APP_CNT_RESET (0x0A)
+#define RADIOLIB_LORAWAN_TS009_LINK_CHECK (0x20)
+#define RADIOLIB_LORAWAN_TS009_DEVICE_TIME (0x21)
+#define RADIOLIB_LORAWAN_TS009_PING_SLOT_INFO (0x22)
+#define RADIOLIB_LORAWAN_TS009_TX_CW (0x7D)
+#define RADIOLIB_LORAWAN_TS009_DUT_FPORT224_DISABLE (0x7E)
+#define RADIOLIB_LORAWAN_TS009_DUT_VERSIONS (0x7F)
+
+/*!
+ \brief This function implements the TS009 specification.
+ To enable this package, add this to your setup:
+ `node.addAppPackage(RADIOLIB_LORAWAN_PACKAGE_TS009, handleTS009)`
+ Make sure that all `extern` variables are handled in your user code!
+*/
+void handleTS009(uint8_t* dataDown, size_t lenDown) {
+ if(lenDown == 0 || dataDown == NULL) {
+ return;
+ }
+ RADIOLIB_DEBUG_PRINTLN("CID = %02x, len = %d", dataDown[0], lenDown - 1);
+
+ switch(dataDown[0]) {
+ case(RADIOLIB_LORAWAN_TS009_PACKAGE_VERSION): {
+ lenUp = 3;
+ dataUp[1] = 5; // PackageIdentifier
+ dataUp[2] = 1; // PackageVersion
+ fPort = RADIOLIB_LORAWAN_FPORT_TS009;
+ RADIOLIB_DEBUG_PRINTLN("PackageIdentifier: %d, PackageVersion: %d", dataUp[1], dataUp[2]);
+
+ reply = true;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_DUT_RESET): {
+ RADIOLIB_DEBUG_PRINTLN("Restarting...");
+
+ #warning "Please implement this reset function yourself!"
+
+ // the function to reset the MCU is platform-dependent
+ // for ESP32 for example, this would be:
+ // ESP.restart();
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_DUT_JOIN): {
+ RADIOLIB_DEBUG_PRINTLN("Reverting to Join state");
+ node.clearSession();
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_SWITCH_CLASS): {
+ uint8_t classType = dataDown[1];
+ node.setClass(classType);
+ RADIOLIB_DEBUG_PRINTLN("Switching to class: %s", classType == 0 ? "A" : (classType == 1 ? "B" : "C"));
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_ADR_BIT_CHANGE): {
+ bool adr = (bool)dataDown[1];
+ node.setADR(adr);
+ RADIOLIB_DEBUG_PRINTLN("ADR: %d", adr);
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_REGIONAL_DUTY_CYCLE): {
+ bool dutycycle = (bool)dataDown[1];
+ node.setDutyCycle(dutycycle, 36000);
+ RADIOLIB_DEBUG_PRINTLN("Dutycycle: %d", dutycycle);
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_TX_PERIODICITY_CHANGE): {
+ uint32_t defaultIntervalSecs = 30;
+ uint32_t intervals[11] = {defaultIntervalSecs, 5, 10, 20, 30, 40, 50, 60, 120, 240, 480};
+ periodicity = intervals[dataDown[1]];
+
+ RADIOLIB_DEBUG_PRINTLN("Tx Periodicity: %d", periodicity);
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_TX_FRAMES_CTRL): {
+ switch(dataDown[1]) {
+ case(0):
+ // no change
+ // isConfirmed = isConfirmed;
+ break;
+ case(1):
+ isConfirmed = false;
+ break;
+ case(2):
+ isConfirmed = true;
+ break;
+ }
+ RADIOLIB_DEBUG_PRINTLN("Confirmed: %d", isConfirmed);
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_ECHO_PAYLOAD): {
+ lenUp = lenDown;
+ for (size_t i = 1; i < lenDown; i++) {
+ dataUp[i] = dataDown[i] + 1;
+ }
+ fPort = RADIOLIB_LORAWAN_FPORT_TS009;
+ RADIOLIB_DEBUG_PRINTLN("Echoing payload");
+
+ reply = true;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_RX_APP_CNT): {
+ lenUp = 3;
+ uint16_t aFcntDown16 = (uint16_t)node.getAFCntDown();
+ dataUp[1] = aFcntDown16 & 0xFF;
+ dataUp[2] = aFcntDown16 >> 8;
+ fPort = RADIOLIB_LORAWAN_FPORT_TS009;
+ RADIOLIB_DEBUG_PRINTLN("aFCntDown16: %d", aFcntDown16);
+
+ reply = true;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_RX_APP_CNT_RESET): {
+ RADIOLIB_DEBUG_PRINTLN("Resetting Application Frame count");
+ RADIOLIB_DEBUG_PRINTLN("WARNING: not implemented - never used in tests!");
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_LINK_CHECK): {
+ lenUp = 0;
+ fPort = RADIOLIB_LORAWAN_FPORT_MAC_COMMAND;
+ node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK);
+ RADIOLIB_DEBUG_PRINTLN("Requesting LinkCheck");
+
+ reply = true;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_DEVICE_TIME): {
+ lenUp = 0;
+ fPort = RADIOLIB_LORAWAN_FPORT_MAC_COMMAND;
+ node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME);
+ RADIOLIB_DEBUG_PRINTLN("Requesting DeviceTime");
+
+ reply = true;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_PING_SLOT_INFO): {
+ lenUp = 0;
+ RADIOLIB_DEBUG_PRINTLN("Requesting PingSlotInfo not implemented");
+ // send PingSlotInfo MAC command which is not implemented
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_TX_CW): {
+ uint16_t timeout = ((uint16_t)dataDown[2] << 8) | (uint16_t)dataDown[1];
+ uint32_t freqRaw = ((uint32_t)dataDown[5] << 16) | ((uint32_t)dataDown[4] << 8) | ((uint32_t)dataDown[3]);
+ float freq = (float)freqRaw/10000.0;
+ uint8_t txPower = dataDown[6];
+ RADIOLIB_DEBUG_PRINTLN("Continuous wave: %7.3f MHz, %d dBm, %d s", freq, txPower, timeout);
+ radio.setFrequency(freq);
+ radio.setOutputPower(txPower);
+ radio.transmitDirect();
+ delay(timeout * 1000);
+ radio.standby();
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_DUT_FPORT224_DISABLE): {
+ RADIOLIB_DEBUG_PRINTLN("Disabling FPort 224");
+ node.removePackage(RADIOLIB_LORAWAN_PACKAGE_TS009);
+
+ reply = false;
+ } break;
+
+ case(RADIOLIB_LORAWAN_TS009_DUT_VERSIONS): {
+ lenUp = 13;
+ // firmware version - this is RadioLib's version as an example
+ dataUp[1] = RADIOLIB_VERSION_MAJOR;
+ dataUp[2] = RADIOLIB_VERSION_MINOR;
+ dataUp[3] = RADIOLIB_VERSION_PATCH;
+ dataUp[4] = RADIOLIB_VERSION_EXTRA;
+
+ // lorawan version
+ dataUp[5] = 1;
+#if (LORAWAN_VERSION == 1)
+ dataUp[6] = 1;
+ dataUp[7] = 0;
+#else
+ dataUp[6] = 0;
+ dataUp[7] = 4;
+#endif
+ dataUp[8] = 0;
+
+ // regional parameters version
+ dataUp[9] = 1;
+ dataUp[10] = 0;
+ dataUp[11] = 4;
+ dataUp[12] = 0;
+ fPort = RADIOLIB_LORAWAN_FPORT_TS009;
+ RADIOLIB_DEBUG_PRINTLN("Requested DUT versions");
+
+ reply = true;
+ } break;
+ }
+
+ // if we must reply, copy the command ID into the uplink buffer
+ if(reply) {
+ dataUp[0] = dataDown[0];
+ }
+}
\ No newline at end of file
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino
new file mode 100644
index 0000000..df1cf5f
--- /dev/null
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino
@@ -0,0 +1,171 @@
+/*
+ RadioLib LoRaWAN Packages Example
+
+ This example shows how the TS009 package can be used
+ and is the sketch used for passing pre-certification testing.
+ This scheme can also be used for other future packages
+ such as TS003/004/005/006/007 which, combined, build FUOTA.
+
+ PLEASE NOTE that this is a highly customized sketch with
+ settings that likely violate laws & regulations, and it is
+ intended to be used with RF blocking materials and attenuators.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+
+ For LoRaWAN details, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/LoRaWAN
+
+*/
+
+#include
+#include
+
+#include "LoRaWAN_TS009.h"
+#include "config.h"
+#include "lorawan.h"
+
+uint32_t periodicity = uplinkIntervalSeconds;
+bool isConfirmed = false;
+bool reply = false;
+
+uint8_t fPort = 1;
+uint8_t dataUp[255];
+uint8_t dataDown[255];
+size_t lenUp = 0;
+size_t lenDown = 0;
+
+void setup() {
+ Serial.begin(115200);
+ delay(3000);
+
+ Serial.print(F("Initialise the radio ... "));
+ int state = radio.begin();
+ if(state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while(true);
+ }
+
+ // setup, restore and join the network
+ lwBegin();
+ lwRestore();
+ lwActivate();
+
+ // add TS009 package
+ node.addAppPackage(RADIOLIB_LORAWAN_PACKAGE_TS009, handleTS009);
+
+ // LCTT (TS009 testing) has a huge timing problem on the JoinAccept Rx2 window...
+ node.scanGuard = 100;
+
+ // these settings are totally not recommended
+ // but unfortunately they are the default settings for TS009 testing
+ node.setDutyCycle(false);
+ node.setADR(false);
+}
+
+void loop() {
+ while(!node.isActivated()) {
+ lwActivate();
+ // this 5s interval is way too short for normal use!
+ // but you'd be waiting around for long minutes during TS009 testing otherwise
+ if(!node.isActivated()) {
+ delay(5000);
+ }
+ node.setDutyCycle(false);
+ }
+
+ int state = RADIOLIB_ERR_NONE;
+ LoRaWANEvent_t eventUp;
+ LoRaWANEvent_t eventDown;
+
+ uint32_t start = millis();
+
+ Serial.println("--------------------");
+ Serial.println("[LoRaWAN] Sending uplink packet ... ");
+ if (!reply) {
+ memset(dataUp, 0, 255);
+ lenUp = 4;
+ fPort = 1;
+ sprintf((char*)dataUp, "%04lu", node.getFCntUp());
+ state = node.sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, &eventUp, &eventDown);
+ } else {
+ reply = false;
+ state = node.sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, &eventUp, &eventDown);
+ }
+
+ if(state >= RADIOLIB_ERR_NONE) {
+ Serial.println(F("[LoRaWAN] success!"));
+ }
+
+ if(state > 0) {
+ // print data of the packet (if there are any)
+ Serial.print(F("[LoRaWAN] Data:\t\t"));
+ if(lenDown > 0) {
+ arrayDump(dataDown, lenDown);
+ } else {
+ Serial.println(F(""));
+ }
+
+ Serial.print(F("[LoRaWAN] FPort:\t"));
+ Serial.print(eventDown.fPort);
+
+ // print RSSI (Received Signal Strength Indicator)
+ Serial.print(F("[LoRaWAN] RSSI:\t\t"));
+ Serial.print(radio.getRSSI());
+ Serial.println(F(" dBm"));
+
+ // print SNR (Signal-to-Noise Ratio)
+ Serial.print(F("[LoRaWAN] SNR:\t\t"));
+ Serial.print(radio.getSNR());
+ Serial.println(F(" dB"));
+
+ uint8_t margin = 0;
+ uint8_t gwCnt = 0;
+ if(node.getMacLinkCheckAns(&margin, &gwCnt) == RADIOLIB_ERR_NONE) {
+ Serial.print(F("[LoRaWAN] LinkCheck margin:\t"));
+ Serial.println(margin);
+ Serial.print(F("[LoRaWAN] LinkCheck count:\t"));
+ Serial.println(gwCnt);
+ }
+
+ uint32_t timestamp = 0;
+ uint16_t milliseconds = 0;
+ if(node.getMacDeviceTimeAns(×tamp, &milliseconds, true) == RADIOLIB_ERR_NONE) {
+ Serial.print(F("[LoRaWAN] DeviceTime Unix:\t"));
+ Serial.println(timestamp);
+ Serial.print(F("[LoRaWAN] DeviceTime frac:\t"));
+ Serial.print(milliseconds);
+ Serial.println(F(" ms"));
+ }
+
+ } else if(state == 0) {
+ Serial.println(F("No downlink!"));
+
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ }
+
+ uint32_t end = millis();
+
+ uint32_t delayDc = node.timeUntilUplink();
+ uint32_t delayMs = periodicity*1000;
+ if(delayMs > end - start) {
+ delayMs -= (end - start);
+ } else {
+ delayMs = 1;
+ }
+ delayMs += 50;
+ Serial.print(F("Delay: "));
+ Serial.print(max(delayDc, delayMs));
+ Serial.println(F(" ms"));
+
+ // wait before sending another packet
+ delay(max(delayDc, delayMs));
+}
\ No newline at end of file
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/config.h b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/config.h
new file mode 100644
index 0000000..9c64a4d
--- /dev/null
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/config.h
@@ -0,0 +1,115 @@
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+#include
+
+// first you have to set your radio model and pin configuration
+// this is provided just as a default example
+SX1278 radio = new Module(10, 2, 9, 3);
+
+// if you have RadioBoards (https://github.com/radiolib-org/RadioBoards)
+// and are using one of the supported boards, you can do the following:
+/*
+#define RADIO_BOARD_AUTO
+#include
+
+Radio radio = new RadioModule();
+*/
+
+// how often to send an uplink - consider legal & FUP constraints
+const uint32_t uplinkIntervalSeconds = 1UL * 60UL; // minutes x seconds
+
+#define LORAWAN_VERSION (0) // use version 1.LORAWAN_VERSION when joining
+#define LORAWAN_OTAA (1) // use OTAA (1) or ABP (0)
+
+#if (LORAWAN_OTAA == 1)
+// joinEUI - previous versions of LoRaWAN called this AppEUI
+// for development purposes you can use all zeros - see wiki for details
+#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000
+
+// the Device EUI & two keys can be generated on the TTN console
+#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI
+#define RADIOLIB_LORAWAN_DEV_EUI 0x----------------
+#endif
+#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key
+#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+
+// copy over the EUI's & keys in to the something that will not compile if incorrectly formatted
+uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI;
+uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI;
+uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY };
+
+#if (LORAWAN_VERSION == 1)
+#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here
+#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; // LW v1.1 only
+#endif
+
+#else // ABP
+
+#ifndef RADIOLIB_LORAWAN_DEV_ADDR // Replace with your DevAddr
+#define RADIOLIB_LORAWAN_DEV_ADDR 0x------
+#endif
+
+#ifndef RADIOLIB_LORAWAN_NWKSENC_KEY // Replace with your NwkSEnc Key
+#define RADIOLIB_LORAWAN_NWKSENC_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+#ifndef RADIOLIB_LORAWAN_APPS_KEY // Replace with your AppS Key
+#define RADIOLIB_LORAWAN_APPS_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+
+// copy over the keys in to the something that will not compile if incorrectly formatted
+uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR;
+uint8_t sNwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY };
+uint8_t appSKey[] = { RADIOLIB_LORAWAN_APPS_KEY };
+
+#if (LORAWAN_VERSION == 1)
+#ifndef RADIOLIB_LORAWAN_FNWKSINT_KEY // Replace with your FNwkSInt Key
+#define RADIOLIB_LORAWAN_FNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+#ifndef RADIOLIB_LORAWAN_SNWKSINT_KEY // Replace with your SNwkSInt Key
+#define RADIOLIB_LORAWAN_SNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
+#endif
+uint8_t fNwkSIntKey[] = { RADIOLIB_LORAWAN_FNWKSINT_KEY }; // LW v1.1 only
+uint8_t sNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY }; // LW v1.1 only
+#endif
+
+#endif // OTAA/ABP
+
+// for the curious, the #ifndef blocks allow for automated testing &/or you can
+// put your EUI & keys in to your platformio.ini - see wiki for more tips
+
+// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500
+const LoRaWANBand_t Region = EU868;
+const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
+
+// ============================================================================
+// Below is to support the sketch - only make changes if the notes say so ...
+
+// create the LoRaWAN node
+LoRaWANNode node(&radio, &Region, subBand);
+
+// helper function to display any issues
+void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) {
+ if (isFail) {
+ Serial.print(message);
+ Serial.print("(");
+ Serial.print(state);
+ Serial.println(")");
+ while (Freeze);
+ }
+}
+
+// helper function to display a byte array
+void arrayDump(uint8_t *buffer, uint16_t len) {
+ for(uint16_t c = 0; c < len; c++) {
+ char b = buffer[c];
+ if(b < 0x10) { Serial.print('0'); }
+ Serial.print(b, HEX);
+ }
+ Serial.println();
+}
+
+#endif
\ No newline at end of file
diff --git a/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/lorawan.h b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/lorawan.h
new file mode 100644
index 0000000..95220fc
--- /dev/null
+++ b/lib/RadioLib/examples/LoRaWAN/LoRaWAN_TS_Packages/lorawan.h
@@ -0,0 +1,76 @@
+#ifndef _LORAWAN_H
+#define _LORAWAN_H
+
+#include
+#include "config.h"
+
+#warning "You are required to implement persistence here! (ESP32 example provided in comments)"
+
+// #include
+// Preferences store;
+// uint8_t LWnonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE];
+
+bool lwBegin() {
+#if (LORAWAN_OTAA == 1)
+ #if (LORAWAN_VERSION == 1)
+ node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
+ #else
+ node.beginOTAA(joinEUI, devEUI, NULL, appKey);
+ #endif
+#else
+ #if (LORAWAN_VERSION == 1)
+ node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, sNwkSEncKey, appSKey);
+ #else
+ node.beginABP(devAddr, NULL, NULL, sNwkSEncKey, appSKey);
+ #endif
+#endif
+ return(true);
+}
+
+int16_t lwRestore() {
+ int16_t state = RADIOLIB_ERR_UNKNOWN;
+
+ // store.begin("radiolib");
+ // if (store.isKey("nonces")) {
+ // radio.standby();
+
+ // store.getBytes("nonces", LWnonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE);
+ // state = node.setBufferNonces(LWnonces);
+ // }
+ // store.end();
+
+ return(state);
+}
+
+void lwActivate() {
+ int16_t state = RADIOLIB_ERR_NETWORK_NOT_JOINED;
+ Serial.println(F("[LoRaWAN] Attempting network join ... "));
+
+ radio.standby();
+
+#if (LORAWAN_OTAA == 1)
+ state = node.activateOTAA();
+#else
+ state = node.activateABP();
+#endif
+
+ if(state == RADIOLIB_LORAWAN_SESSION_RESTORED) {
+ Serial.println(F("[LoRaWAN] Session restored!"));
+ return;
+ }
+
+ // store.begin("radiolib");
+ // uint8_t *persist = node.getBufferNonces();
+ // store.putBytes("nonces", persist, RADIOLIB_LORAWAN_NONCES_BUF_SIZE);
+ // store.end();
+
+ if(state == RADIOLIB_LORAWAN_NEW_SESSION) {
+ Serial.println(F("[LoRaWAN] Successfully started new session!"));
+ return;
+ }
+
+ Serial.print(F("[LoRaWAN] Failed, code "));
+ Serial.println(state);
+}
+
+#endif
\ No newline at end of file
diff --git a/lib/RadioLib/examples/LoRaWAN/README.md b/lib/RadioLib/examples/LoRaWAN/README.md
index d2a7325..2ad96c2 100644
--- a/lib/RadioLib/examples/LoRaWAN/README.md
+++ b/lib/RadioLib/examples/LoRaWAN/README.md
@@ -3,35 +3,12 @@ RadioLib LoRaWAN examples.
* [LoRaWAN_Starter](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Starter): this is the recommended entry point for new users. Please read the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) that come with this example to learn more about LoRaWAN and how to use it in RadioLib!
* [LoRaWAN_Reference](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Reference): this sketch showcases most of the available API for LoRaWAN in RadioLib. Be frightened by the possibilities! It is recommended you have read all the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for the Starter sketch first, as well as the [Learn section on The Things Network](https://www.thethingsnetwork.org/docs/lorawan/)!
-* [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA (but why?), this example shows how you can do this using RadioLib.
+* [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA, this example shows how you can do this using RadioLib. However, to comply with the specification, the full session must persist through resets and power loss - you would need proper NVM for this. Really, we recommend using OTAA.
+* [LoRaWAN_Class_C](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Class_C): this shows how to use Class C on top of Class A. This is useful for continuously-powered devices (no batteries) such as lights. If you deploy multiple similar devices, please use Multicast instead.
+* [LoRaWAN_Multicast](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Multicast): a showcase of Multicast over Class C. This is particularly useful for groups of devices such as a series of street lights.
-## LoRaWAN versions & regional parameters
-RadioLib implements both LoRaWAN Specification 1.1 and 1.0.4. Confusingly, 1.0.4 is newer than 1.1, but 1.1 includes more security checks and as such **LoRaWAN 1.1 is preferred**.
-The catch is in the Regional Parameters: as RP002 1.0.4 is newer than RP001 1.1, it is more up to date regarding local laws & regulations. Therefore, RadioLib implements 1.0.4 as baseline and 1.1 (revision B) as fallback, and as such **RP002 Regional Parameters 1.0.4 is preferred**.
-_Note: the CN500 band is implemented as specified in RP001 1.1 revision B, as the RP002 1.0.4 version is much too complex._
+> [!CAUTION]
+> These examples are quick wins during development. However, for production devices, you will need to add persistence to your device. See the wiki for more details, or head straight to some [persistence examples](https://github.com/radiolib-org/radiolib-persistence).
-To activate a LoRaWAN 1.1 session, supply all the required keys:
-```cpp
-node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
-node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey);
-```
-
-To activate a LoRaWAN 1.0.4 session, set the keys that are not available to `NULL`:
-```cpp
-node.beginOTAA(joinEUI, devEUI, NULL, appKey);
-node.beginABP(devAddr, NULL, NULL, nwkSEncKey, appSKey);
-```
-
-The device doesn't need to know the Regional Parameters version - that is of importance on the console.
-
-## LoRaWAN persistence
-> [!WARNING]
-> These examples do not actually comply with LoRaWAN 1.0.4/1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below:
-
-In [this repository](https://github.com/radiolib-org/radiolib-persistence), examples are provided that do comply with the required persistence of certain parameters for LoRaWAN 1.1. Examples are (or will become) available for some of the most popular platforms. **These examples assume you have successfully used the Starter sketch and understood (most of) the accompanying notes!**
-Currently, examples are available for the following platforms:
-
-* [LoRaWAN for ESP32](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP32)
-* [LoRaWAN for ESP8266](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP8266)
-
-_This list is last updated at 30/03/2024._
+> [!TIP]
+> Refer to the [Wiki](https://github.com/jgromes/RadioLib/wiki/LoRaWAN) for guides and information, for example on LoRaWAN versions, registering your device and more.
diff --git a/lib/RadioLib/examples/NonArduino/ESP-IDF/README.md b/lib/RadioLib/examples/NonArduino/ESP-IDF/README.md
index 401785e..df1d0b7 100644
--- a/lib/RadioLib/examples/NonArduino/ESP-IDF/README.md
+++ b/lib/RadioLib/examples/NonArduino/ESP-IDF/README.md
@@ -8,3 +8,4 @@ This example shows how to use RadioLib as ESP-IDF component, without the Arduino
* `main/EspHal.h` - RadioLib HAL example implementation
* `main/idf_component.yml` - declaration of the RadioLib dependency for this example
* `main/main.cpp` - the example source code
+* `sdkconfig.defaults` - List of preset configuration option values for ESP-IDF. All other options use default values provided by ESP-IDF.
diff --git a/lib/RadioLib/examples/NonArduino/ESP-IDF/sdkconfig b/lib/RadioLib/examples/NonArduino/ESP-IDF/sdkconfig
deleted file mode 100644
index ea8d756..0000000
--- a/lib/RadioLib/examples/NonArduino/ESP-IDF/sdkconfig
+++ /dev/null
@@ -1,1669 +0,0 @@
-#
-# Automatically generated file. DO NOT EDIT.
-# Espressif IoT Development Framework (ESP-IDF) Project Configuration
-#
-CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined"
-CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined"
-CONFIG_SOC_DPORT_WORKAROUND="Not determined"
-CONFIG_SOC_CAPS_ECO_VER_MAX=301
-CONFIG_SOC_ADC_SUPPORTED=y
-CONFIG_SOC_DAC_SUPPORTED=y
-CONFIG_SOC_MCPWM_SUPPORTED=y
-CONFIG_SOC_SDMMC_HOST_SUPPORTED=y
-CONFIG_SOC_BT_SUPPORTED=y
-CONFIG_SOC_PCNT_SUPPORTED=y
-CONFIG_SOC_WIFI_SUPPORTED=y
-CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y
-CONFIG_SOC_TWAI_SUPPORTED=y
-CONFIG_SOC_EMAC_SUPPORTED=y
-CONFIG_SOC_ULP_SUPPORTED=y
-CONFIG_SOC_CCOMP_TIMER_SUPPORTED=y
-CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y
-CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED=y
-CONFIG_SOC_RTC_MEM_SUPPORTED=y
-CONFIG_SOC_I2S_SUPPORTED=y
-CONFIG_SOC_RMT_SUPPORTED=y
-CONFIG_SOC_SDM_SUPPORTED=y
-CONFIG_SOC_SUPPORT_COEXISTENCE=y
-CONFIG_SOC_AES_SUPPORTED=y
-CONFIG_SOC_MPI_SUPPORTED=y
-CONFIG_SOC_SHA_SUPPORTED=y
-CONFIG_SOC_FLASH_ENC_SUPPORTED=y
-CONFIG_SOC_SECURE_BOOT_SUPPORTED=y
-CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y
-CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5
-CONFIG_SOC_XTAL_SUPPORT_26M=y
-CONFIG_SOC_XTAL_SUPPORT_40M=y
-CONFIG_SOC_XTAL_SUPPORT_AUTO_DETECT=y
-CONFIG_SOC_ADC_RTC_CTRL_SUPPORTED=y
-CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y
-CONFIG_SOC_ADC_DMA_SUPPORTED=y
-CONFIG_SOC_ADC_PERIPH_NUM=2
-CONFIG_SOC_ADC_MAX_CHANNEL_NUM=10
-CONFIG_SOC_ADC_ATTEN_NUM=4
-CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=2
-CONFIG_SOC_ADC_PATT_LEN_MAX=16
-CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=9
-CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12
-CONFIG_SOC_ADC_DIGI_RESULT_BYTES=2
-CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4
-CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=2
-CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=20
-CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=9
-CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12
-CONFIG_SOC_RTC_SLOW_CLOCK_SUPPORT_8MD256=y
-CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y
-CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=5
-CONFIG_SOC_CPU_CORES_NUM=2
-CONFIG_SOC_CPU_INTR_NUM=32
-CONFIG_SOC_CPU_HAS_FPU=y
-CONFIG_SOC_CPU_BREAKPOINTS_NUM=2
-CONFIG_SOC_CPU_WATCHPOINTS_NUM=2
-CONFIG_SOC_CPU_WATCHPOINT_SIZE=64
-CONFIG_SOC_DAC_PERIPH_NUM=2
-CONFIG_SOC_DAC_RESOLUTION=8
-CONFIG_SOC_GPIO_PORT=1
-CONFIG_SOC_GPIO_PIN_COUNT=40
-CONFIG_SOC_GPIO_VALID_GPIO_MASK=0xFFFFFFFFFF
-CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA
-CONFIG_SOC_I2C_NUM=2
-CONFIG_SOC_I2C_FIFO_LEN=32
-CONFIG_SOC_I2C_SUPPORT_SLAVE=y
-CONFIG_SOC_I2C_SUPPORT_APB=y
-CONFIG_SOC_CLK_APLL_SUPPORTED=y
-CONFIG_SOC_APLL_MULTIPLIER_OUT_MIN_HZ=350000000
-CONFIG_SOC_APLL_MULTIPLIER_OUT_MAX_HZ=500000000
-CONFIG_SOC_APLL_MIN_HZ=5303031
-CONFIG_SOC_APLL_MAX_HZ=125000000
-CONFIG_SOC_I2S_NUM=2
-CONFIG_SOC_I2S_HW_VERSION_1=y
-CONFIG_SOC_I2S_SUPPORTS_APLL=y
-CONFIG_SOC_I2S_SUPPORTS_PDM=y
-CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y
-CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y
-CONFIG_SOC_I2S_SUPPORTS_ADC_DAC=y
-CONFIG_SOC_I2S_SUPPORTS_ADC=y
-CONFIG_SOC_I2S_SUPPORTS_DAC=y
-CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y
-CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y
-CONFIG_SOC_I2S_LCD_I80_VARIANT=y
-CONFIG_SOC_LCD_I80_SUPPORTED=y
-CONFIG_SOC_LCD_I80_BUSES=2
-CONFIG_SOC_LCD_I80_BUS_WIDTH=24
-CONFIG_SOC_LEDC_HAS_TIMER_SPECIFIC_MUX=y
-CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y
-CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y
-CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y
-CONFIG_SOC_LEDC_CHANNEL_NUM=8
-CONFIG_SOC_LEDC_TIMER_BIT_WIDE_NUM=20
-CONFIG_SOC_MCPWM_GROUPS=2
-CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3
-CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3
-CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2
-CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2
-CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2
-CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3
-CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y
-CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3
-CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3
-CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000
-CONFIG_SOC_MPU_REGIONS_MAX_NUM=8
-CONFIG_SOC_PCNT_GROUPS=1
-CONFIG_SOC_PCNT_UNITS_PER_GROUP=8
-CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2
-CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2
-CONFIG_SOC_RMT_GROUPS=1
-CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=8
-CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=8
-CONFIG_SOC_RMT_CHANNELS_PER_GROUP=8
-CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=64
-CONFIG_SOC_RMT_SUPPORT_REF_TICK=y
-CONFIG_SOC_RMT_SUPPORT_APB=y
-CONFIG_SOC_RMT_CHANNEL_CLK_INDEPENDENT=y
-CONFIG_SOC_RTCIO_PIN_COUNT=18
-CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y
-CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y
-CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y
-CONFIG_SOC_SDM_GROUPS=1
-CONFIG_SOC_SDM_CHANNELS_PER_GROUP=8
-CONFIG_SOC_SPI_HD_BOTH_INOUT_SUPPORTED=y
-CONFIG_SOC_SPI_AS_CS_SUPPORTED=y
-CONFIG_SOC_SPI_PERIPH_NUM=3
-CONFIG_SOC_SPI_DMA_CHAN_NUM=2
-CONFIG_SOC_SPI_MAX_CS_NUM=3
-CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64
-CONFIG_SOC_SPI_MAX_PRE_DIVIDER=8192
-CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y
-CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y
-CONFIG_SOC_MEMSPI_SRC_FREQ_26M_SUPPORTED=y
-CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y
-CONFIG_SOC_TIMER_GROUPS=2
-CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2
-CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64
-CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4
-CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y
-CONFIG_SOC_TOUCH_VERSION_1=y
-CONFIG_SOC_TOUCH_SENSOR_NUM=10
-CONFIG_SOC_TOUCH_PAD_MEASURE_WAIT_MAX=0xFF
-CONFIG_SOC_TWAI_BRP_MIN=2
-CONFIG_SOC_TWAI_SUPPORT_MULTI_ADDRESS_LAYOUT=y
-CONFIG_SOC_UART_NUM=3
-CONFIG_SOC_UART_SUPPORT_APB_CLK=y
-CONFIG_SOC_UART_SUPPORT_REF_TICK=y
-CONFIG_SOC_UART_FIFO_LEN=128
-CONFIG_SOC_UART_BITRATE_MAX=5000000
-CONFIG_SOC_SPIRAM_SUPPORTED=y
-CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y
-CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG=y
-CONFIG_SOC_SHA_SUPPORT_SHA1=y
-CONFIG_SOC_SHA_SUPPORT_SHA256=y
-CONFIG_SOC_SHA_SUPPORT_SHA384=y
-CONFIG_SOC_SHA_SUPPORT_SHA512=y
-CONFIG_SOC_RSA_MAX_BIT_LEN=4096
-CONFIG_SOC_AES_SUPPORT_AES_128=y
-CONFIG_SOC_AES_SUPPORT_AES_192=y
-CONFIG_SOC_AES_SUPPORT_AES_256=y
-CONFIG_SOC_SECURE_BOOT_V1=y
-CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=y
-CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=32
-CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21
-CONFIG_SOC_PM_SUPPORT_EXT_WAKEUP=y
-CONFIG_SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP=y
-CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y
-CONFIG_SOC_PM_SUPPORT_RTC_FAST_MEM_PD=y
-CONFIG_SOC_PM_SUPPORT_RTC_SLOW_MEM_PD=y
-CONFIG_SOC_PM_SUPPORT_MODEM_PD=y
-CONFIG_SOC_SDMMC_USE_IOMUX=y
-CONFIG_SOC_SDMMC_NUM_SLOTS=2
-CONFIG_SOC_WIFI_WAPI_SUPPORT=y
-CONFIG_SOC_WIFI_CSI_SUPPORT=y
-CONFIG_SOC_WIFI_MESH_SUPPORT=y
-CONFIG_SOC_BLE_SUPPORTED=y
-CONFIG_SOC_BLE_MESH_SUPPORTED=y
-CONFIG_SOC_BT_CLASSIC_SUPPORTED=y
-CONFIG_IDF_CMAKE=y
-CONFIG_IDF_TARGET_ARCH_XTENSA=y
-CONFIG_IDF_TARGET_ARCH="xtensa"
-CONFIG_IDF_TARGET="esp32"
-CONFIG_IDF_TARGET_ESP32=y
-CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
-
-#
-# Build type
-#
-CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y
-# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set
-CONFIG_APP_BUILD_GENERATE_BINARIES=y
-CONFIG_APP_BUILD_BOOTLOADER=y
-CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y
-# CONFIG_APP_REPRODUCIBLE_BUILD is not set
-# CONFIG_APP_NO_BLOBS is not set
-# CONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
-# CONFIG_APP_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set
-# end of Build type
-
-#
-# Bootloader config
-#
-CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000
-CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
-# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set
-# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set
-# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
-# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
-# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
-# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
-CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
-# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
-# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
-CONFIG_BOOTLOADER_LOG_LEVEL=3
-# CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V is not set
-CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
-# CONFIG_BOOTLOADER_FACTORY_RESET is not set
-# CONFIG_BOOTLOADER_APP_TEST is not set
-CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y
-CONFIG_BOOTLOADER_WDT_ENABLE=y
-# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
-CONFIG_BOOTLOADER_WDT_TIME_MS=9000
-# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set
-# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set
-# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set
-# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set
-CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0
-# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set
-CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y
-# end of Bootloader config
-
-#
-# Security features
-#
-CONFIG_SECURE_BOOT_V1_SUPPORTED=y
-# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set
-# CONFIG_SECURE_BOOT is not set
-# CONFIG_SECURE_FLASH_ENC_ENABLED is not set
-# end of Security features
-
-#
-# Application manager
-#
-CONFIG_APP_COMPILE_TIME_DATE=y
-# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
-# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
-# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set
-CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16
-# end of Application manager
-
-CONFIG_ESP_ROM_HAS_CRC_LE=y
-CONFIG_ESP_ROM_HAS_CRC_BE=y
-CONFIG_ESP_ROM_HAS_MZ_CRC32=y
-CONFIG_ESP_ROM_HAS_JPEG_DECODE=y
-CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y
-
-#
-# Serial flasher config
-#
-# CONFIG_ESPTOOLPY_NO_STUB is not set
-# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
-# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
-CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
-# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
-CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y
-CONFIG_ESPTOOLPY_FLASHMODE="dio"
-# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set
-CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
-# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
-# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
-CONFIG_ESPTOOLPY_FLASHFREQ="40m"
-# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
-CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
-# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
-# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
-# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
-# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
-# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
-# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
-CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
-# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set
-CONFIG_ESPTOOLPY_BEFORE_RESET=y
-# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
-CONFIG_ESPTOOLPY_BEFORE="default_reset"
-CONFIG_ESPTOOLPY_AFTER_RESET=y
-# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
-CONFIG_ESPTOOLPY_AFTER="hard_reset"
-CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
-# end of Serial flasher config
-
-#
-# Partition Table
-#
-CONFIG_PARTITION_TABLE_SINGLE_APP=y
-# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
-# CONFIG_PARTITION_TABLE_TWO_OTA is not set
-# CONFIG_PARTITION_TABLE_CUSTOM is not set
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
-CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
-CONFIG_PARTITION_TABLE_OFFSET=0x8000
-CONFIG_PARTITION_TABLE_MD5=y
-# end of Partition Table
-
-#
-# Compiler options
-#
-CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
-# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
-# CONFIG_COMPILER_OPTIMIZATION_PERF is not set
-# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
-CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
-# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
-# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
-CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y
-CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2
-# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set
-CONFIG_COMPILER_HIDE_PATHS_MACROS=y
-# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
-# CONFIG_COMPILER_CXX_RTTI is not set
-CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
-# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
-# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
-# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
-# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
-# CONFIG_COMPILER_DUMP_RTL_FILES is not set
-# end of Compiler options
-
-#
-# Component config
-#
-
-#
-# Application Level Tracing
-#
-# CONFIG_APPTRACE_DEST_JTAG is not set
-CONFIG_APPTRACE_DEST_NONE=y
-# CONFIG_APPTRACE_DEST_UART1 is not set
-# CONFIG_APPTRACE_DEST_UART2 is not set
-CONFIG_APPTRACE_DEST_UART_NONE=y
-CONFIG_APPTRACE_UART_TASK_PRIO=1
-CONFIG_APPTRACE_LOCK_ENABLE=y
-# end of Application Level Tracing
-
-#
-# Bluetooth
-#
-# CONFIG_BT_ENABLED is not set
-# end of Bluetooth
-
-#
-# Driver Configurations
-#
-
-#
-# Legacy ADC Configuration
-#
-CONFIG_ADC_DISABLE_DAC=y
-# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set
-
-#
-# Legacy ADC Calibration Configuration
-#
-CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
-CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
-CONFIG_ADC_CAL_LUT_ENABLE=y
-# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set
-# end of Legacy ADC Calibration Configuration
-# end of Legacy ADC Configuration
-
-#
-# SPI Configuration
-#
-# CONFIG_SPI_MASTER_IN_IRAM is not set
-CONFIG_SPI_MASTER_ISR_IN_IRAM=y
-# CONFIG_SPI_SLAVE_IN_IRAM is not set
-CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
-# end of SPI Configuration
-
-#
-# TWAI Configuration
-#
-# CONFIG_TWAI_ISR_IN_IRAM is not set
-CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC=y
-CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST=y
-CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID=y
-CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT=y
-CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y
-# end of TWAI Configuration
-
-#
-# UART Configuration
-#
-# CONFIG_UART_ISR_IN_IRAM is not set
-# end of UART Configuration
-
-#
-# GPIO Configuration
-#
-# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set
-# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set
-# end of GPIO Configuration
-
-#
-# Sigma Delta Modulator Configuration
-#
-# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set
-# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set
-# CONFIG_SDM_ENABLE_DEBUG_LOG is not set
-# end of Sigma Delta Modulator Configuration
-
-#
-# GPTimer Configuration
-#
-# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set
-# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set
-# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set
-# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set
-# end of GPTimer Configuration
-
-#
-# PCNT Configuration
-#
-# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set
-# CONFIG_PCNT_ISR_IRAM_SAFE is not set
-# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set
-# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set
-# end of PCNT Configuration
-
-#
-# RMT Configuration
-#
-# CONFIG_RMT_ISR_IRAM_SAFE is not set
-# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set
-# CONFIG_RMT_ENABLE_DEBUG_LOG is not set
-# end of RMT Configuration
-
-#
-# MCPWM Configuration
-#
-# CONFIG_MCPWM_ISR_IRAM_SAFE is not set
-# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set
-# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set
-# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set
-# end of MCPWM Configuration
-
-#
-# I2S Configuration
-#
-# CONFIG_I2S_ISR_IRAM_SAFE is not set
-# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set
-# CONFIG_I2S_ENABLE_DEBUG_LOG is not set
-# end of I2S Configuration
-# end of Driver Configurations
-
-#
-# eFuse Bit Manager
-#
-# CONFIG_EFUSE_CUSTOM_TABLE is not set
-# CONFIG_EFUSE_VIRTUAL is not set
-# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set
-CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y
-# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set
-CONFIG_EFUSE_MAX_BLK_LEN=192
-# end of eFuse Bit Manager
-
-#
-# ESP-TLS
-#
-CONFIG_ESP_TLS_USING_MBEDTLS=y
-# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set
-# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set
-# CONFIG_ESP_TLS_SERVER is not set
-# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
-# CONFIG_ESP_TLS_INSECURE is not set
-# end of ESP-TLS
-
-#
-# ADC and ADC Calibration
-#
-# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set
-# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set
-
-#
-# ADC Calibration Configurations
-#
-CONFIG_ADC_CALI_EFUSE_TP_ENABLE=y
-CONFIG_ADC_CALI_EFUSE_VREF_ENABLE=y
-CONFIG_ADC_CALI_LUT_ENABLE=y
-# end of ADC Calibration Configurations
-
-CONFIG_ADC_DISABLE_DAC_OUTPUT=y
-# end of ADC and ADC Calibration
-
-#
-# Common ESP-related
-#
-CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
-# end of Common ESP-related
-
-#
-# Ethernet
-#
-CONFIG_ETH_ENABLED=y
-CONFIG_ETH_USE_ESP32_EMAC=y
-CONFIG_ETH_PHY_INTERFACE_RMII=y
-CONFIG_ETH_RMII_CLK_INPUT=y
-# CONFIG_ETH_RMII_CLK_OUTPUT is not set
-CONFIG_ETH_RMII_CLK_IN_GPIO=0
-CONFIG_ETH_DMA_BUFFER_SIZE=512
-CONFIG_ETH_DMA_RX_BUFFER_NUM=10
-CONFIG_ETH_DMA_TX_BUFFER_NUM=10
-CONFIG_ETH_USE_SPI_ETHERNET=y
-# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set
-# CONFIG_ETH_SPI_ETHERNET_W5500 is not set
-# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set
-# CONFIG_ETH_USE_OPENETH is not set
-# CONFIG_ETH_TRANSMIT_MUTEX is not set
-# end of Ethernet
-
-#
-# Event Loop Library
-#
-# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
-CONFIG_ESP_EVENT_POST_FROM_ISR=y
-CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
-# end of Event Loop Library
-
-#
-# GDB Stub
-#
-# end of GDB Stub
-
-#
-# ESP HTTP client
-#
-CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
-# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
-# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set
-# end of ESP HTTP client
-
-#
-# HTTP Server
-#
-CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
-CONFIG_HTTPD_MAX_URI_LEN=512
-CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
-CONFIG_HTTPD_PURGE_BUF_LEN=32
-# CONFIG_HTTPD_LOG_PURGE_DATA is not set
-# CONFIG_HTTPD_WS_SUPPORT is not set
-# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set
-# end of HTTP Server
-
-#
-# ESP HTTPS OTA
-#
-# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set
-# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set
-# end of ESP HTTPS OTA
-
-#
-# ESP HTTPS server
-#
-# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
-# end of ESP HTTPS server
-
-#
-# Hardware Settings
-#
-
-#
-# Chip revision
-#
-CONFIG_ESP32_REV_MIN_0=y
-# CONFIG_ESP32_REV_MIN_1 is not set
-# CONFIG_ESP32_REV_MIN_1_1 is not set
-# CONFIG_ESP32_REV_MIN_2 is not set
-# CONFIG_ESP32_REV_MIN_3 is not set
-# CONFIG_ESP32_REV_MIN_3_1 is not set
-CONFIG_ESP32_REV_MIN=0
-CONFIG_ESP32_REV_MIN_FULL=0
-CONFIG_ESP_REV_MIN_FULL=0
-
-#
-# Maximum Supported ESP32 Revision (Rev v3.99)
-#
-CONFIG_ESP32_REV_MAX_FULL=399
-CONFIG_ESP_REV_MAX_FULL=399
-# end of Chip revision
-
-#
-# MAC Config
-#
-CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y
-CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
-CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
-CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
-# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
-CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y
-CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4
-# CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR is not set
-# end of MAC Config
-
-#
-# Sleep Config
-#
-# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set
-CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
-# CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set
-CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y
-# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set
-CONFIG_ESP_SLEEP_DEEP_SLEEP_WAKEUP_DELAY=2000
-# end of Sleep Config
-
-#
-# RTC Clock Config
-#
-CONFIG_RTC_CLK_SRC_INT_RC=y
-# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set
-# CONFIG_RTC_CLK_SRC_EXT_OSC is not set
-# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set
-CONFIG_RTC_CLK_CAL_CYCLES=1024
-# end of RTC Clock Config
-
-#
-# Peripheral Control
-#
-# CONFIG_PERIPH_CTRL_FUNC_IN_IRAM is not set
-# end of Peripheral Control
-
-#
-# Main XTAL Config
-#
-# CONFIG_XTAL_FREQ_26 is not set
-CONFIG_XTAL_FREQ_40=y
-# CONFIG_XTAL_FREQ_AUTO is not set
-CONFIG_XTAL_FREQ=40
-# end of Main XTAL Config
-# end of Hardware Settings
-
-#
-# LCD and Touch Panel
-#
-
-#
-# LCD Touch Drivers are maintained in the IDF Component Registry
-#
-
-#
-# LCD Peripheral Configuration
-#
-CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32
-# CONFIG_LCD_ENABLE_DEBUG_LOG is not set
-# end of LCD Peripheral Configuration
-# end of LCD and Touch Panel
-
-#
-# ESP NETIF Adapter
-#
-CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
-CONFIG_ESP_NETIF_TCPIP_LWIP=y
-# CONFIG_ESP_NETIF_LOOPBACK is not set
-# CONFIG_ESP_NETIF_L2_TAP is not set
-# CONFIG_ESP_NETIF_BRIDGE_EN is not set
-# end of ESP NETIF Adapter
-
-#
-# PHY
-#
-CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
-# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
-CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
-CONFIG_ESP_PHY_MAX_TX_POWER=20
-CONFIG_ESP_PHY_REDUCE_TX_POWER=y
-# end of PHY
-
-#
-# Power Management
-#
-# CONFIG_PM_ENABLE is not set
-# end of Power Management
-
-#
-# ESP PSRAM
-#
-# CONFIG_SPIRAM is not set
-# end of ESP PSRAM
-
-#
-# ESP Ringbuf
-#
-# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set
-# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set
-# end of ESP Ringbuf
-
-#
-# ESP System Settings
-#
-# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set
-CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
-# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240 is not set
-CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160
-
-#
-# Memory
-#
-# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set
-# end of Memory
-
-#
-# Trace memory
-#
-# CONFIG_ESP32_TRAX is not set
-CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0
-# end of Trace memory
-
-# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
-CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
-# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
-# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
-# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set
-
-#
-# Memory protection
-#
-# end of Memory protection
-
-CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
-CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
-CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584
-CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y
-# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set
-# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
-CONFIG_ESP_MAIN_TASK_AFFINITY=0x0
-CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
-CONFIG_ESP_CONSOLE_UART_DEFAULT=y
-# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
-# CONFIG_ESP_CONSOLE_NONE is not set
-CONFIG_ESP_CONSOLE_UART=y
-CONFIG_ESP_CONSOLE_MULTIPLE_UART=y
-CONFIG_ESP_CONSOLE_UART_NUM=0
-CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
-CONFIG_ESP_INT_WDT=y
-CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
-CONFIG_ESP_INT_WDT_CHECK_CPU1=y
-CONFIG_ESP_TASK_WDT_EN=y
-CONFIG_ESP_TASK_WDT_INIT=y
-# CONFIG_ESP_TASK_WDT_PANIC is not set
-CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
-CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
-CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
-# CONFIG_ESP_PANIC_HANDLER_IRAM is not set
-# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set
-CONFIG_ESP_DEBUG_OCDAWARE=y
-# CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 is not set
-CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y
-
-#
-# Brownout Detector
-#
-CONFIG_ESP_BROWNOUT_DET=y
-CONFIG_ESP_BROWNOUT_DET_LVL_SEL_0=y
-# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_1 is not set
-# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set
-# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set
-# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set
-# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set
-# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set
-# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7 is not set
-CONFIG_ESP_BROWNOUT_DET_LVL=0
-# end of Brownout Detector
-
-# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set
-CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y
-# end of ESP System Settings
-
-#
-# IPC (Inter-Processor Call)
-#
-CONFIG_ESP_IPC_TASK_STACK_SIZE=1024
-CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y
-CONFIG_ESP_IPC_ISR_ENABLE=y
-# end of IPC (Inter-Processor Call)
-
-#
-# High resolution timer (esp_timer)
-#
-# CONFIG_ESP_TIMER_PROFILING is not set
-CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
-CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y
-CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584
-CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1
-# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set
-CONFIG_ESP_TIMER_IMPL_TG0_LAC=y
-# end of High resolution timer (esp_timer)
-
-#
-# Wi-Fi
-#
-CONFIG_ESP32_WIFI_ENABLED=y
-CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10
-CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32
-# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
-CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y
-CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1
-CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
-# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
-CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
-CONFIG_ESP32_WIFI_TX_BA_WIN=6
-CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
-CONFIG_ESP32_WIFI_RX_BA_WIN=6
-CONFIG_ESP32_WIFI_NVS_ENABLED=y
-CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
-# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set
-CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752
-CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
-CONFIG_ESP32_WIFI_IRAM_OPT=y
-CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
-CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
-CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y
-# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
-CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y
-# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set
-CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
-# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set
-CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7
-# end of Wi-Fi
-
-#
-# Core dump
-#
-# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set
-# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set
-CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y
-# end of Core dump
-
-#
-# FAT Filesystem support
-#
-CONFIG_FATFS_VOLUME_COUNT=2
-# CONFIG_FATFS_SECTOR_512 is not set
-# CONFIG_FATFS_SECTOR_1024 is not set
-# CONFIG_FATFS_SECTOR_2048 is not set
-CONFIG_FATFS_SECTOR_4096=y
-CONFIG_FATFS_SECTORS_PER_CLUSTER_1=y
-# CONFIG_FATFS_SECTORS_PER_CLUSTER_2 is not set
-# CONFIG_FATFS_SECTORS_PER_CLUSTER_4 is not set
-# CONFIG_FATFS_SECTORS_PER_CLUSTER_8 is not set
-# CONFIG_FATFS_SECTORS_PER_CLUSTER_16 is not set
-# CONFIG_FATFS_SECTORS_PER_CLUSTER_32 is not set
-# CONFIG_FATFS_SECTORS_PER_CLUSTER_64 is not set
-# CONFIG_FATFS_SECTORS_PER_CLUSTER_128 is not set
-# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set
-CONFIG_FATFS_CODEPAGE_437=y
-# CONFIG_FATFS_CODEPAGE_720 is not set
-# CONFIG_FATFS_CODEPAGE_737 is not set
-# CONFIG_FATFS_CODEPAGE_771 is not set
-# CONFIG_FATFS_CODEPAGE_775 is not set
-# CONFIG_FATFS_CODEPAGE_850 is not set
-# CONFIG_FATFS_CODEPAGE_852 is not set
-# CONFIG_FATFS_CODEPAGE_855 is not set
-# CONFIG_FATFS_CODEPAGE_857 is not set
-# CONFIG_FATFS_CODEPAGE_860 is not set
-# CONFIG_FATFS_CODEPAGE_861 is not set
-# CONFIG_FATFS_CODEPAGE_862 is not set
-# CONFIG_FATFS_CODEPAGE_863 is not set
-# CONFIG_FATFS_CODEPAGE_864 is not set
-# CONFIG_FATFS_CODEPAGE_865 is not set
-# CONFIG_FATFS_CODEPAGE_866 is not set
-# CONFIG_FATFS_CODEPAGE_869 is not set
-# CONFIG_FATFS_CODEPAGE_932 is not set
-# CONFIG_FATFS_CODEPAGE_936 is not set
-# CONFIG_FATFS_CODEPAGE_949 is not set
-# CONFIG_FATFS_CODEPAGE_950 is not set
-CONFIG_FATFS_AUTO_TYPE=y
-# CONFIG_FATFS_FAT12 is not set
-# CONFIG_FATFS_FAT16 is not set
-CONFIG_FATFS_CODEPAGE=437
-CONFIG_FATFS_LFN_NONE=y
-# CONFIG_FATFS_LFN_HEAP is not set
-# CONFIG_FATFS_LFN_STACK is not set
-CONFIG_FATFS_FS_LOCK=0
-CONFIG_FATFS_TIMEOUT_MS=10000
-CONFIG_FATFS_PER_FILE_CACHE=y
-# CONFIG_FATFS_USE_FASTSEEK is not set
-# end of FAT Filesystem support
-
-#
-# FreeRTOS
-#
-
-#
-# Kernel
-#
-# CONFIG_FREERTOS_SMP is not set
-# CONFIG_FREERTOS_UNICORE is not set
-CONFIG_FREERTOS_HZ=1000
-# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
-# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
-CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
-CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
-CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
-# CONFIG_FREERTOS_USE_IDLE_HOOK is not set
-# CONFIG_FREERTOS_USE_TICK_HOOK is not set
-CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
-# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set
-CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
-CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
-CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
-CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
-# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
-# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
-# end of Kernel
-
-#
-# Port
-#
-CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y
-# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
-# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
-CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
-CONFIG_FREERTOS_ISR_STACKSIZE=1536
-CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
-# CONFIG_FREERTOS_FPU_IN_ISR is not set
-CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER=y
-CONFIG_FREERTOS_CORETIMER_0=y
-# CONFIG_FREERTOS_CORETIMER_1 is not set
-CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y
-# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set
-# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set
-# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
-CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
-CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
-# end of Port
-
-CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
-CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
-CONFIG_FREERTOS_DEBUG_OCDAWARE=y
-# end of FreeRTOS
-
-#
-# Hardware Abstraction Layer (HAL) and Low Level (LL)
-#
-CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y
-# CONFIG_HAL_ASSERTION_DISABLE is not set
-# CONFIG_HAL_ASSERTION_SILENT is not set
-# CONFIG_HAL_ASSERTION_ENABLE is not set
-CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2
-# end of Hardware Abstraction Layer (HAL) and Low Level (LL)
-
-#
-# Heap memory debugging
-#
-CONFIG_HEAP_POISONING_DISABLED=y
-# CONFIG_HEAP_POISONING_LIGHT is not set
-# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set
-CONFIG_HEAP_TRACING_OFF=y
-# CONFIG_HEAP_TRACING_STANDALONE is not set
-# CONFIG_HEAP_TRACING_TOHOST is not set
-# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set
-# end of Heap memory debugging
-
-#
-# Log output
-#
-# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
-# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
-# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
-CONFIG_LOG_DEFAULT_LEVEL_INFO=y
-# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
-# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
-CONFIG_LOG_DEFAULT_LEVEL=3
-CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y
-# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set
-# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set
-CONFIG_LOG_MAXIMUM_LEVEL=3
-CONFIG_LOG_COLORS=y
-CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
-# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set
-# end of Log output
-
-#
-# LWIP
-#
-CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
-# CONFIG_LWIP_NETIF_API is not set
-# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set
-# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set
-CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
-# CONFIG_LWIP_L2_TO_L3_COPY is not set
-# CONFIG_LWIP_IRAM_OPTIMIZATION is not set
-CONFIG_LWIP_TIMERS_ONDEMAND=y
-CONFIG_LWIP_MAX_SOCKETS=10
-# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
-# CONFIG_LWIP_SO_LINGER is not set
-CONFIG_LWIP_SO_REUSE=y
-CONFIG_LWIP_SO_REUSE_RXTOALL=y
-# CONFIG_LWIP_SO_RCVBUF is not set
-# CONFIG_LWIP_NETBUF_RECVINFO is not set
-CONFIG_LWIP_IP4_FRAG=y
-CONFIG_LWIP_IP6_FRAG=y
-# CONFIG_LWIP_IP4_REASSEMBLY is not set
-# CONFIG_LWIP_IP6_REASSEMBLY is not set
-# CONFIG_LWIP_IP_FORWARD is not set
-# CONFIG_LWIP_STATS is not set
-CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
-CONFIG_LWIP_GARP_TMR_INTERVAL=60
-CONFIG_LWIP_ESP_MLDV6_REPORT=y
-CONFIG_LWIP_MLDV6_TMR_INTERVAL=40
-CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
-CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
-# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set
-CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y
-# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
-CONFIG_LWIP_DHCP_OPTIONS_LEN=68
-CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0
-CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1
-
-#
-# DHCP server
-#
-CONFIG_LWIP_DHCPS=y
-CONFIG_LWIP_DHCPS_LEASE_UNIT=60
-CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
-# end of DHCP server
-
-# CONFIG_LWIP_AUTOIP is not set
-CONFIG_LWIP_IPV6=y
-# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
-CONFIG_LWIP_IPV6_NUM_ADDRESSES=3
-# CONFIG_LWIP_IPV6_FORWARD is not set
-# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set
-CONFIG_LWIP_NETIF_LOOPBACK=y
-CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
-
-#
-# TCP
-#
-CONFIG_LWIP_MAX_ACTIVE_TCP=16
-CONFIG_LWIP_MAX_LISTENING_TCP=16
-CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y
-CONFIG_LWIP_TCP_MAXRTX=12
-CONFIG_LWIP_TCP_SYNMAXRTX=12
-CONFIG_LWIP_TCP_MSS=1440
-CONFIG_LWIP_TCP_TMR_INTERVAL=250
-CONFIG_LWIP_TCP_MSL=60000
-CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000
-CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744
-CONFIG_LWIP_TCP_WND_DEFAULT=5744
-CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
-CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
-# CONFIG_LWIP_TCP_SACK_OUT is not set
-CONFIG_LWIP_TCP_OVERSIZE_MSS=y
-# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
-# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
-CONFIG_LWIP_TCP_RTO_TIME=1500
-# end of TCP
-
-#
-# UDP
-#
-CONFIG_LWIP_MAX_UDP_PCBS=16
-CONFIG_LWIP_UDP_RECVMBOX_SIZE=6
-# end of UDP
-
-#
-# Checksums
-#
-# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set
-# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set
-CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y
-# end of Checksums
-
-CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072
-CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
-# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
-# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set
-CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
-# CONFIG_LWIP_PPP_SUPPORT is not set
-CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3
-CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5
-# CONFIG_LWIP_SLIP_SUPPORT is not set
-
-#
-# ICMP
-#
-CONFIG_LWIP_ICMP=y
-# CONFIG_LWIP_MULTICAST_PING is not set
-# CONFIG_LWIP_BROADCAST_PING is not set
-# end of ICMP
-
-#
-# LWIP RAW API
-#
-CONFIG_LWIP_MAX_RAW_PCBS=16
-# end of LWIP RAW API
-
-#
-# SNTP
-#
-CONFIG_LWIP_SNTP_MAX_SERVERS=1
-# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set
-CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
-# end of SNTP
-
-CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7
-CONFIG_LWIP_ESP_LWIP_ASSERT=y
-
-#
-# Hooks
-#
-# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set
-CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y
-# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set
-CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y
-# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set
-# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set
-CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y
-# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set
-# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set
-CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y
-# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set
-# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set
-CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y
-# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set
-# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set
-# end of Hooks
-
-# CONFIG_LWIP_DEBUG is not set
-# end of LWIP
-
-#
-# mbedTLS
-#
-CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
-# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
-# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
-CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
-CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
-CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
-# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set
-# CONFIG_MBEDTLS_DEBUG is not set
-
-#
-# mbedTLS v3.x related
-#
-# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set
-# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set
-# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set
-# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set
-CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
-# end of mbedTLS v3.x related
-
-#
-# Certificate Bundle
-#
-CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
-CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
-# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
-# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
-# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
-CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200
-# end of Certificate Bundle
-
-# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
-# CONFIG_MBEDTLS_CMAC_C is not set
-CONFIG_MBEDTLS_HARDWARE_AES=y
-CONFIG_MBEDTLS_HARDWARE_MPI=y
-CONFIG_MBEDTLS_HARDWARE_SHA=y
-CONFIG_MBEDTLS_ROM_MD5=y
-# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set
-# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set
-CONFIG_MBEDTLS_HAVE_TIME=y
-# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set
-# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
-CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y
-CONFIG_MBEDTLS_SHA512_C=y
-CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
-# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
-# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
-# CONFIG_MBEDTLS_TLS_DISABLED is not set
-CONFIG_MBEDTLS_TLS_SERVER=y
-CONFIG_MBEDTLS_TLS_CLIENT=y
-CONFIG_MBEDTLS_TLS_ENABLED=y
-
-#
-# TLS Key Exchange Methods
-#
-# CONFIG_MBEDTLS_PSK_MODES is not set
-CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
-CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
-CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
-CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
-CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
-CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
-# end of TLS Key Exchange Methods
-
-CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
-CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
-# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set
-# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
-CONFIG_MBEDTLS_SSL_ALPN=y
-CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y
-CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y
-
-#
-# Symmetric Ciphers
-#
-CONFIG_MBEDTLS_AES_C=y
-# CONFIG_MBEDTLS_CAMELLIA_C is not set
-# CONFIG_MBEDTLS_DES_C is not set
-# CONFIG_MBEDTLS_BLOWFISH_C is not set
-# CONFIG_MBEDTLS_XTEA_C is not set
-CONFIG_MBEDTLS_CCM_C=y
-CONFIG_MBEDTLS_GCM_C=y
-# CONFIG_MBEDTLS_NIST_KW_C is not set
-# end of Symmetric Ciphers
-
-# CONFIG_MBEDTLS_RIPEMD160_C is not set
-
-#
-# Certificates
-#
-CONFIG_MBEDTLS_PEM_PARSE_C=y
-CONFIG_MBEDTLS_PEM_WRITE_C=y
-CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
-CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
-# end of Certificates
-
-CONFIG_MBEDTLS_ECP_C=y
-# CONFIG_MBEDTLS_DHM_C is not set
-CONFIG_MBEDTLS_ECDH_C=y
-CONFIG_MBEDTLS_ECDSA_C=y
-# CONFIG_MBEDTLS_ECJPAKE_C is not set
-CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
-CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
-CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
-# CONFIG_MBEDTLS_POLY1305_C is not set
-# CONFIG_MBEDTLS_CHACHA20_C is not set
-# CONFIG_MBEDTLS_HKDF_C is not set
-# CONFIG_MBEDTLS_THREADING_C is not set
-# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set
-# CONFIG_MBEDTLS_SECURITY_RISKS is not set
-# end of mbedTLS
-
-#
-# ESP-MQTT Configurations
-#
-CONFIG_MQTT_PROTOCOL_311=y
-# CONFIG_MQTT_PROTOCOL_5 is not set
-CONFIG_MQTT_TRANSPORT_SSL=y
-CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
-CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
-# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set
-# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set
-# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set
-# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set
-# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set
-# CONFIG_MQTT_CUSTOM_OUTBOX is not set
-# end of ESP-MQTT Configurations
-
-#
-# Newlib
-#
-CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
-# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
-# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
-# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set
-# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set
-CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
-# CONFIG_NEWLIB_NANO_FORMAT is not set
-CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y
-# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set
-# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set
-# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set
-# end of Newlib
-
-#
-# NVS
-#
-# CONFIG_NVS_ASSERT_ERROR_CHECK is not set
-# end of NVS
-
-#
-# OpenThread
-#
-# CONFIG_OPENTHREAD_ENABLED is not set
-# end of OpenThread
-
-#
-# Protocomm
-#
-CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y
-CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y
-CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y
-# end of Protocomm
-
-#
-# PThreads
-#
-CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
-CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
-CONFIG_PTHREAD_STACK_MIN=768
-CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y
-# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set
-# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set
-CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1
-CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
-# end of PThreads
-
-#
-# MMU Config
-#
-CONFIG_MMU_PAGE_SIZE_64KB=y
-CONFIG_MMU_PAGE_MODE="64KB"
-CONFIG_MMU_PAGE_SIZE=0x10000
-# end of MMU Config
-
-#
-# SPI Flash driver
-#
-# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
-# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
-CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
-CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y
-# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set
-# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set
-# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set
-# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set
-CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y
-CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20
-CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1
-CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192
-# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set
-# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set
-# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set
-
-#
-# SPI Flash behavior when brownout
-#
-CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y
-CONFIG_SPI_FLASH_BROWNOUT_RESET=y
-# end of SPI Flash behavior when brownout
-
-#
-# Auto-detect flash chips
-#
-CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
-CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y
-CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
-CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y
-# CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP is not set
-# CONFIG_SPI_FLASH_SUPPORT_TH_CHIP is not set
-# end of Auto-detect flash chips
-
-CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y
-# end of SPI Flash driver
-
-#
-# SPIFFS Configuration
-#
-CONFIG_SPIFFS_MAX_PARTITIONS=3
-
-#
-# SPIFFS Cache Configuration
-#
-CONFIG_SPIFFS_CACHE=y
-CONFIG_SPIFFS_CACHE_WR=y
-# CONFIG_SPIFFS_CACHE_STATS is not set
-# end of SPIFFS Cache Configuration
-
-CONFIG_SPIFFS_PAGE_CHECK=y
-CONFIG_SPIFFS_GC_MAX_RUNS=10
-# CONFIG_SPIFFS_GC_STATS is not set
-CONFIG_SPIFFS_PAGE_SIZE=256
-CONFIG_SPIFFS_OBJ_NAME_LEN=32
-# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set
-CONFIG_SPIFFS_USE_MAGIC=y
-CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
-CONFIG_SPIFFS_META_LENGTH=4
-CONFIG_SPIFFS_USE_MTIME=y
-
-#
-# Debug Configuration
-#
-# CONFIG_SPIFFS_DBG is not set
-# CONFIG_SPIFFS_API_DBG is not set
-# CONFIG_SPIFFS_GC_DBG is not set
-# CONFIG_SPIFFS_CACHE_DBG is not set
-# CONFIG_SPIFFS_CHECK_DBG is not set
-# CONFIG_SPIFFS_TEST_VISUALISATION is not set
-# end of Debug Configuration
-# end of SPIFFS Configuration
-
-#
-# TCP Transport
-#
-
-#
-# Websocket
-#
-CONFIG_WS_TRANSPORT=y
-CONFIG_WS_BUFFER_SIZE=1024
-# CONFIG_WS_DYNAMIC_BUFFER is not set
-# end of Websocket
-# end of TCP Transport
-
-#
-# Ultra Low Power (ULP) Co-processor
-#
-# CONFIG_ULP_COPROC_ENABLED is not set
-# end of Ultra Low Power (ULP) Co-processor
-
-#
-# Unity unit testing library
-#
-CONFIG_UNITY_ENABLE_FLOAT=y
-CONFIG_UNITY_ENABLE_DOUBLE=y
-# CONFIG_UNITY_ENABLE_64BIT is not set
-# CONFIG_UNITY_ENABLE_COLOR is not set
-CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
-# CONFIG_UNITY_ENABLE_FIXTURE is not set
-# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set
-# end of Unity unit testing library
-
-#
-# Root Hub configuration
-#
-# end of Root Hub configuration
-
-#
-# Virtual file system
-#
-CONFIG_VFS_SUPPORT_IO=y
-CONFIG_VFS_SUPPORT_DIR=y
-CONFIG_VFS_SUPPORT_SELECT=y
-CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
-CONFIG_VFS_SUPPORT_TERMIOS=y
-
-#
-# Host File System I/O (Semihosting)
-#
-CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
-# end of Host File System I/O (Semihosting)
-# end of Virtual file system
-
-#
-# Wear Levelling
-#
-# CONFIG_WL_SECTOR_SIZE_512 is not set
-CONFIG_WL_SECTOR_SIZE_4096=y
-CONFIG_WL_SECTOR_SIZE=4096
-# end of Wear Levelling
-
-#
-# Wi-Fi Provisioning Manager
-#
-CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
-CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
-# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set
-CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y
-# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set
-# end of Wi-Fi Provisioning Manager
-
-#
-# Supplicant
-#
-CONFIG_WPA_MBEDTLS_CRYPTO=y
-CONFIG_WPA_MBEDTLS_TLS_CLIENT=y
-# CONFIG_WPA_WAPI_PSK is not set
-# CONFIG_WPA_SUITE_B_192 is not set
-# CONFIG_WPA_DEBUG_PRINT is not set
-# CONFIG_WPA_TESTING_OPTIONS is not set
-# CONFIG_WPA_WPS_STRICT is not set
-# CONFIG_WPA_11KV_SUPPORT is not set
-# CONFIG_WPA_MBO_SUPPORT is not set
-# CONFIG_WPA_DPP_SUPPORT is not set
-# CONFIG_WPA_11R_SUPPORT is not set
-# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set
-# end of Supplicant
-# end of Component config
-
-# Deprecated options for backward compatibility
-# CONFIG_NO_BLOBS is not set
-# CONFIG_ESP32_NO_BLOBS is not set
-# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
-# CONFIG_ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set
-# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
-# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
-# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
-CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
-# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
-# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
-CONFIG_LOG_BOOTLOADER_LEVEL=3
-# CONFIG_APP_ROLLBACK_ENABLE is not set
-# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
-# CONFIG_FLASHMODE_QIO is not set
-# CONFIG_FLASHMODE_QOUT is not set
-CONFIG_FLASHMODE_DIO=y
-# CONFIG_FLASHMODE_DOUT is not set
-CONFIG_MONITOR_BAUD=115200
-CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
-CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
-# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set
-# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
-CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
-# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
-# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
-CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2
-# CONFIG_CXX_EXCEPTIONS is not set
-CONFIG_STACK_CHECK_NONE=y
-# CONFIG_STACK_CHECK_NORM is not set
-# CONFIG_STACK_CHECK_STRONG is not set
-# CONFIG_STACK_CHECK_ALL is not set
-# CONFIG_WARN_WRITE_STRINGS is not set
-# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
-CONFIG_ESP32_APPTRACE_DEST_NONE=y
-CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
-CONFIG_ADC2_DISABLE_DAC=y
-# CONFIG_MCPWM_ISR_IN_IRAM is not set
-# CONFIG_EVENT_LOOP_PROFILING is not set
-CONFIG_POST_EVENTS_FROM_ISR=y
-CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
-# CONFIG_OTA_ALLOW_HTTP is not set
-# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set
-CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y
-CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4
-# CONFIG_ESP_SYSTEM_PD_FLASH is not set
-CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000
-CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y
-CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y
-# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set
-# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set
-# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set
-# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set
-# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set
-# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set
-CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024
-# CONFIG_ESP32_XTAL_FREQ_26 is not set
-CONFIG_ESP32_XTAL_FREQ_40=y
-# CONFIG_ESP32_XTAL_FREQ_AUTO is not set
-CONFIG_ESP32_XTAL_FREQ=40
-CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
-# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
-CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
-CONFIG_ESP32_PHY_MAX_TX_POWER=20
-CONFIG_REDUCE_PHY_TX_POWER=y
-CONFIG_ESP32_REDUCE_PHY_TX_POWER=y
-# CONFIG_SPIRAM_SUPPORT is not set
-# CONFIG_ESP32_SPIRAM_SUPPORT is not set
-# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
-CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y
-# CONFIG_ESP32_DEFAULT_CPU_FREQ_240 is not set
-CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160
-CONFIG_TRACEMEM_RESERVE_DRAM=0x0
-# CONFIG_ESP32_PANIC_PRINT_HALT is not set
-CONFIG_ESP32_PANIC_PRINT_REBOOT=y
-# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set
-# CONFIG_ESP32_PANIC_GDBSTUB is not set
-CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
-CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
-CONFIG_MAIN_TASK_STACK_SIZE=3584
-CONFIG_CONSOLE_UART_DEFAULT=y
-# CONFIG_CONSOLE_UART_CUSTOM is not set
-# CONFIG_CONSOLE_UART_NONE is not set
-# CONFIG_ESP_CONSOLE_UART_NONE is not set
-CONFIG_CONSOLE_UART=y
-CONFIG_CONSOLE_UART_NUM=0
-CONFIG_CONSOLE_UART_BAUDRATE=115200
-CONFIG_INT_WDT=y
-CONFIG_INT_WDT_TIMEOUT_MS=300
-CONFIG_INT_WDT_CHECK_CPU1=y
-CONFIG_TASK_WDT=y
-CONFIG_ESP_TASK_WDT=y
-# CONFIG_TASK_WDT_PANIC is not set
-CONFIG_TASK_WDT_TIMEOUT_S=5
-CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
-CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
-# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set
-CONFIG_ESP32_DEBUG_OCDAWARE=y
-CONFIG_BROWNOUT_DET=y
-CONFIG_ESP32_BROWNOUT_DET=y
-CONFIG_BROWNOUT_DET_LVL_SEL_0=y
-CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y
-# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set
-# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set
-# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set
-# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set
-# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set
-# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set
-# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set
-# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set
-# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set
-# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set
-# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set
-# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set
-# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set
-# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set
-CONFIG_BROWNOUT_DET_LVL=0
-CONFIG_ESP32_BROWNOUT_DET_LVL=0
-# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set
-CONFIG_IPC_TASK_STACK_SIZE=1024
-CONFIG_TIMER_TASK_STACK_SIZE=3584
-# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
-# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
-CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
-CONFIG_TIMER_TASK_PRIORITY=1
-CONFIG_TIMER_TASK_STACK_DEPTH=2048
-CONFIG_TIMER_QUEUE_LENGTH=10
-# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
-# CONFIG_HAL_ASSERTION_SILIENT is not set
-# CONFIG_L2_TO_L3_COPY is not set
-CONFIG_ESP_GRATUITOUS_ARP=y
-CONFIG_GARP_TMR_INTERVAL=60
-CONFIG_TCPIP_RECVMBOX_SIZE=32
-CONFIG_TCP_MAXRTX=12
-CONFIG_TCP_SYNMAXRTX=12
-CONFIG_TCP_MSS=1440
-CONFIG_TCP_MSL=60000
-CONFIG_TCP_SND_BUF_DEFAULT=5744
-CONFIG_TCP_WND_DEFAULT=5744
-CONFIG_TCP_RECVMBOX_SIZE=6
-CONFIG_TCP_QUEUE_OOSEQ=y
-CONFIG_TCP_OVERSIZE_MSS=y
-# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set
-# CONFIG_TCP_OVERSIZE_DISABLE is not set
-CONFIG_UDP_RECVMBOX_SIZE=6
-CONFIG_TCPIP_TASK_STACK_SIZE=3072
-CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
-# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set
-# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set
-CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
-# CONFIG_PPP_SUPPORT is not set
-CONFIG_ESP32_TIME_SYSCALL_USE_RTC_HRT=y
-CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y
-# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set
-# CONFIG_ESP32_TIME_SYSCALL_USE_HRT is not set
-# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set
-# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set
-CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
-CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
-CONFIG_ESP32_PTHREAD_STACK_MIN=768
-CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y
-# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set
-# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set
-CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1
-CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
-CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
-# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
-# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
-# CONFIG_ESP32_ULP_COPROC_ENABLED is not set
-CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
-CONFIG_SUPPORT_TERMIOS=y
-CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
-# End of deprecated options
diff --git a/lib/RadioLib/examples/NonArduino/ESP-IDF/sdkconfig.defaults b/lib/RadioLib/examples/NonArduino/ESP-IDF/sdkconfig.defaults
new file mode 100644
index 0000000..c95181c
--- /dev/null
+++ b/lib/RadioLib/examples/NonArduino/ESP-IDF/sdkconfig.defaults
@@ -0,0 +1,2 @@
+# Increase FreeRTOS tick rate to 1000 Hz
+CONFIG_FREERTOS_HZ=1000
diff --git a/lib/RadioLib/examples/NonArduino/Pico/CMakeLists.txt b/lib/RadioLib/examples/NonArduino/Pico/CMakeLists.txt
index c86122f..84729db 100644
--- a/lib/RadioLib/examples/NonArduino/Pico/CMakeLists.txt
+++ b/lib/RadioLib/examples/NonArduino/Pico/CMakeLists.txt
@@ -20,12 +20,13 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CUR
add_executable(${PROJECT_NAME}
main.cpp
+ "${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib/src/hal/RPiPico/PicoHal.cpp"
)
+target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_BUILD_RPI_PICO)
# Pull in common dependencies
target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_spi hardware_gpio hardware_timer pico_multicore hardware_pwm RadioLib)
-
pico_enable_stdio_usb(${PROJECT_NAME} 1)
pico_enable_stdio_uart(${PROJECT_NAME} 0)
diff --git a/lib/RadioLib/examples/Pager/Pager_Receive/Pager_Receive.ino b/lib/RadioLib/examples/Pager/Pager_Receive/Pager_Receive.ino
index edc9786..61a010f 100644
--- a/lib/RadioLib/examples/Pager/Pager_Receive/Pager_Receive.ino
+++ b/lib/RadioLib/examples/Pager/Pager_Receive/Pager_Receive.ino
@@ -39,7 +39,6 @@ SX1278 radio = new Module(10, 2, 9, 3);
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
-// SX126x/LLCC68: DIO2
const int pin = 5;
// create Pager client instance using the FSK module
diff --git a/lib/RadioLib/examples/Pager/Pager_Transmit/Pager_Transmit.ino b/lib/RadioLib/examples/Pager/Pager_Transmit/Pager_Transmit.ino
index 3677fc7..67846e8 100644
--- a/lib/RadioLib/examples/Pager/Pager_Transmit/Pager_Transmit.ino
+++ b/lib/RadioLib/examples/Pager/Pager_Transmit/Pager_Transmit.ino
@@ -93,6 +93,8 @@ void loop() {
delay(500);
// we can also send only a tone
+ state |= pager.sendTone(1234567);
+ delay(500);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
@@ -101,6 +103,6 @@ void loop() {
Serial.println(state);
}
- // wait for a second before transmitting again
+ // wait for 3 seconds before transmitting again
delay(3000);
}
diff --git a/lib/RadioLib/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/lib/RadioLib/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino
index 58a3f07..63b9c8d 100644
--- a/lib/RadioLib/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino
+++ b/lib/RadioLib/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino
@@ -113,10 +113,6 @@ void loop() {
// packet was successfully sent
Serial.println(F("transmission finished!"));
- // NOTE: when using interrupt-driven transmit method,
- // it is not possible to automatically measure
- // transmission data rate using getDataRate()
-
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
diff --git a/lib/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino b/lib/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino
index 5a7d7b0..4a366da 100644
--- a/lib/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino
+++ b/lib/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino
@@ -94,11 +94,6 @@ void loop() {
// the packet was successfully transmitted
Serial.println(F("success!"));
- // print measured data rate
- Serial.print(F("[STM32WL] Datarate:\t"));
- Serial.print(radio.getDataRate());
- Serial.println(F(" bps"));
-
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
// the supplied packet was longer than 256 bytes
Serial.println(F("too long!"));
diff --git a/lib/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/lib/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino
index 736be3b..77dcc29 100644
--- a/lib/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino
+++ b/lib/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino
@@ -110,10 +110,6 @@ void loop() {
// packet was successfully sent
Serial.println(F("transmission finished!"));
- // NOTE: when using interrupt-driven transmit method,
- // it is not possible to automatically measure
- // transmission data rate using getDataRate()
-
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
diff --git a/lib/RadioLib/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/lib/RadioLib/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
index cc8849d..04dcbe5 100644
--- a/lib/RadioLib/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
+++ b/lib/RadioLib/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
@@ -71,13 +71,6 @@ void setup() {
while (true) { delay(10); }
}
- // FSK modem on SX126x can handle the sync word setting in bits, not just
- // whole bytes. The value used is left-justified.
- // This makes same result as radio.setSyncWord(syncWord, 8):
- state = radio.setSyncBits(syncWord, 64);
- // This will use 0x012 as sync word (12 bits only):
- state = radio.setSyncBits(syncWord, 12);
-
// FSK modem allows advanced CRC configuration
// Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted)
// Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted)
diff --git a/lib/RadioLib/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino b/lib/RadioLib/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino
new file mode 100644
index 0000000..8e72cb8
--- /dev/null
+++ b/lib/RadioLib/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino
@@ -0,0 +1,108 @@
+/*
+ RadioLib SX126x LR-FHSS Modem Example
+
+ This example shows how to use LR-FHSS modem in SX126x chips.
+ This modem can only transmit data, and is not able to receive.
+
+ This example transmits packets using SX1262 LoRa radio module.
+ Each packet contains up to 256 bytes of data, in the form of:
+ - Arduino String
+ - null-terminated char array (C-string)
+ - arbitrary binary data (byte array)
+
+ Other modules from SX126x family can also be used.
+
+ Using blocking transmit is not recommended, as it will lead
+ to inefficient use of processor time!
+ Instead, interrupt transmit is recommended.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lr-fhss-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// SX1262 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+SX1262 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+void setup() {
+ Serial.begin(9600);
+
+ // initialize SX1262 with default settings
+ Serial.print(F("[SX1262] Initializing ... "));
+ int state = radio.beginLRFHSS();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // some modules have an external RF switch
+ // controlled via two pins (RX enable, TX enable)
+ // to enable automatic control of the switch,
+ // call the following method
+ // RX enable: 4
+ // TX enable: 5
+ /*
+ radio.setRfSwitchPins(4, 5);
+ */
+}
+
+// counter to keep track of transmitted packets
+int count = 0;
+
+void loop() {
+ // LR-FHSS modem can only transmit!
+ Serial.print(F("[SX1262] Transmitting packet ... "));
+
+ // you can transmit C-string or Arduino string up to
+ // 256 characters long
+ String str = "Hello World! #" + String(count++);
+ int state = radio.transmit(str);
+
+ // you can also transmit byte array up to 256 bytes long
+ /*
+ byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF};
+ int state = radio.transmit(byteArr, 8);
+ */
+
+ if (state == RADIOLIB_ERR_NONE) {
+ // the packet was successfully transmitted
+ Serial.println(F("success!"));
+
+ } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
+ // the supplied packet was longer than 256 bytes
+ Serial.println(F("too long!"));
+
+ } else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
+ // timeout occurred while transmitting packet
+ Serial.println(F("timeout!"));
+
+ } else {
+ // some other error occurred
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+
+ }
+
+ // wait for a second before transmitting again
+ delay(1000);
+}
diff --git a/lib/RadioLib/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino b/lib/RadioLib/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino
new file mode 100644
index 0000000..d181245
--- /dev/null
+++ b/lib/RadioLib/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino
@@ -0,0 +1,147 @@
+/*
+ RadioLib SX126x LR-FHSS Transmit with Interrupts Example
+
+ This example shows how to use LR-FHSS modem in SX126x chips.
+ This modem can only transmit data, and is not able to receive.
+
+ This example transmits packets using SX1262 LoRa radio module.
+ Each packet contains up to 256 bytes of data, in the form of:
+ - Arduino String
+ - null-terminated char array (C-string)
+ - arbitrary binary data (byte array)
+
+ Other modules from SX126x family can also be used.
+
+ For default module settings, see the wiki page
+ https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lr-fhss-modem
+
+ For full API reference, see the GitHub Pages
+ https://jgromes.github.io/RadioLib/
+*/
+
+// include the library
+#include
+
+// SX1262 has the following connections:
+// NSS pin: 10
+// IRQ pin: 2
+// NRST pin: 3
+// BUSY pin: 9
+SX1262 radio = new Module(10, 2, 3, 9);
+
+// or detect the pinout automatically using RadioBoards
+// https://github.com/radiolib-org/RadioBoards
+/*
+#define RADIO_BOARD_AUTO
+#include
+Radio radio = new RadioModule();
+*/
+
+// save transmission state between loops
+int transmissionState = RADIOLIB_ERR_NONE;
+
+// flag to indicate that a packet was sent
+// or a frequency hop is needed
+volatile bool flag = false;
+
+// this function is called when a complete packet
+// is transmitted by the module
+// IMPORTANT: this function MUST be 'void' type
+// and MUST NOT have any arguments!
+#if defined(ESP8266) || defined(ESP32)
+ ICACHE_RAM_ATTR
+#endif
+void setFlag(void) {
+ // we sent a packet or need to hop, set the flag
+ flag = true;
+}
+
+void setup() {
+ Serial.begin(9600);
+
+ // initialize SX1262 with default settings
+ Serial.print(F("[SX1262] Initializing ... "));
+ int state = radio.beginLRFHSS();
+ if (state == RADIOLIB_ERR_NONE) {
+ Serial.println(F("success!"));
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(state);
+ while (true) { delay(10); }
+ }
+
+ // set the function that will be called
+ // when packet transmission is finished
+ radio.setPacketSentAction(setFlag);
+
+ // start transmitting the first packet
+ Serial.print(F("[SX1262] Sending first packet ... "));
+
+ // you can transmit C-string or Arduino string up to
+ // 256 characters long
+ transmissionState = radio.startTransmit("Hello World!");
+
+ // you can also transmit byte array up to 256 bytes long
+ /*
+ byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
+ 0x89, 0xAB, 0xCD, 0xEF};
+ state = radio.startTransmit(byteArr, 8);
+ */
+}
+
+// counter to keep track of transmitted packets
+int count = 0;
+
+void loop() {
+ // LR-FHSS modem can only transmit!
+
+ // check if the previous transmission finished
+ if(flag) {
+ // reset flag
+ flag = false;
+
+ // check if this was caused by hopping or transmission finished
+ if(radio.getIrqFlags() & RADIOLIB_SX126X_IRQ_LR_FHSS_HOP) {
+ radio.hopLRFHSS();
+
+ } else {
+ if (transmissionState == RADIOLIB_ERR_NONE) {
+ // packet was successfully sent
+ Serial.println(F("transmission finished!"));
+
+ } else {
+ Serial.print(F("failed, code "));
+ Serial.println(transmissionState);
+
+ }
+
+ // clean up after transmission is finished
+ // this will ensure transmitter is disabled,
+ // RF switch is powered down etc.
+ radio.finishTransmit();
+
+ // wait a second before transmitting again
+ delay(1000);
+
+ // send another one
+ Serial.print(F("[SX1262] Sending another packet ... "));
+
+ // you can transmit C-string or Arduino string up to
+ // 256 characters long
+ String str = "Hello World! #" + String(count++);
+ transmissionState = radio.startTransmit(str);
+
+ // you can also transmit byte array up to 256 bytes long
+ /*
+ byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
+ 0x89, 0xAB, 0xCD, 0xEF};
+ transmissionState = radio.startTransmit(byteArr, 8);
+ */
+
+ }
+
+
+
+ }
+
+}
diff --git a/lib/RadioLib/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino b/lib/RadioLib/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino
index c222e2f..3c34ecd 100644
--- a/lib/RadioLib/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino
+++ b/lib/RadioLib/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino
@@ -84,11 +84,6 @@ void loop() {
// the packet was successfully transmitted
Serial.println(F("success!"));
- // print measured data rate
- Serial.print(F("[SX1262] Datarate:\t"));
- Serial.print(radio.getDataRate());
- Serial.println(F(" bps"));
-
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
// the supplied packet was longer than 256 bytes
Serial.println(F("too long!"));
diff --git a/lib/RadioLib/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/lib/RadioLib/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino
index fcc5c95..b8a3f5c 100644
--- a/lib/RadioLib/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino
+++ b/lib/RadioLib/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino
@@ -99,10 +99,6 @@ void loop() {
// packet was successfully sent
Serial.println(F("transmission finished!"));
- // NOTE: when using interrupt-driven transmit method,
- // it is not possible to automatically measure
- // transmission data rate using getDataRate()
-
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
diff --git a/lib/RadioLib/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino b/lib/RadioLib/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino
index 62264ef..28f5bea 100644
--- a/lib/RadioLib/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino
+++ b/lib/RadioLib/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino
@@ -84,11 +84,6 @@ void loop() {
// the packet was successfully transmitted
Serial.println(F(" success!"));
- // print measured data rate
- Serial.print(F("[SX1278] Datarate:\t"));
- Serial.print(radio.getDataRate());
- Serial.println(F(" bps"));
-
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
// the supplied packet was longer than 256 bytes
Serial.println(F("too long!"));
diff --git a/lib/RadioLib/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/lib/RadioLib/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino
index 04385bc..773a008 100644
--- a/lib/RadioLib/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino
+++ b/lib/RadioLib/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino
@@ -99,10 +99,6 @@ void loop() {
// packet was successfully sent
Serial.println(F("transmission finished!"));
- // NOTE: when using interrupt-driven transmit method,
- // it is not possible to automatically measure
- // transmission data rate using getDataRate()
-
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
diff --git a/lib/RadioLib/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/lib/RadioLib/examples/Stream/Stream_Transmit/Stream_Transmit.ino
index 45b93d3..8280a40 100644
--- a/lib/RadioLib/examples/Stream/Stream_Transmit/Stream_Transmit.ino
+++ b/lib/RadioLib/examples/Stream/Stream_Transmit/Stream_Transmit.ino
@@ -130,10 +130,6 @@ void loop() {
// packet was successfully sent
Serial.println(F("transmission finished!"));
- // NOTE: when using interrupt-driven transmit method,
- // it is not possible to automatically measure
- // transmission data rate using getDataRate()
-
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
diff --git a/lib/RadioLib/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/lib/RadioLib/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino
index 9ee46c4..5d5f5de 100644
--- a/lib/RadioLib/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino
+++ b/lib/RadioLib/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino
@@ -112,10 +112,6 @@ void loop() {
// packet was successfully sent
Serial.println(F("transmission finished!"));
- // NOTE: when using interrupt-driven transmit method,
- // it is not possible to automatically measure
- // transmission data rate using getDataRate()
-
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
diff --git a/lib/RadioLib/extras/ADSB_Monitor/ADSBMonitorServer.py b/lib/RadioLib/extras/ADSB_Monitor/ADSBMonitorServer.py
new file mode 100644
index 0000000..3fbb490
--- /dev/null
+++ b/lib/RadioLib/extras/ADSB_Monitor/ADSBMonitorServer.py
@@ -0,0 +1,141 @@
+#!/usr/bin/python3
+# -*- encoding: utf-8 -*-
+
+import argparse
+import sys
+import zmq
+import serial
+import threading
+import queue
+import time
+
+from argparse import RawTextHelpFormatter
+
+# default settings
+DEFAULT_BAUDRATE = 115200
+DEFAULT_SERVER_PORT = 30002
+
+# marker to filter out ADS-B messages from the rest of the serial stream
+ADSB_MESSAGE_MARKER = '[ADS-B]'
+
+class SerialToZMQBridge:
+ def __init__(self, serial_port, baudrate, zmq_host="0.0.0.0", zmq_port=5555):
+ self.serial_port = serial_port
+ self.baudrate = baudrate
+ self.zmq_host = zmq_host
+ self.zmq_port = zmq_port
+
+ self.context = zmq.Context()
+ self.socket = self.context.socket(zmq.STREAM)
+ self.socket.setsockopt(zmq.LINGER, 0)
+ self.socket.bind(f"tcp://{self.zmq_host}:{self.zmq_port}")
+
+ self.serial = serial.Serial(
+ port=self.serial_port,
+ baudrate=self.baudrate,
+ timeout=1
+ )
+
+ self.clients = set()
+ self.serial_queue = queue.Queue()
+
+ self.running = True
+
+ def serial_reader(self):
+ """Continuously read from serial and queue messages."""
+ while self.running:
+ try:
+ line = self.serial.readline()
+ if line:
+ line = line.decode(errors='ignore').strip()
+ print(f"[SERIAL RX] {line}")
+
+ # read the ADS-B frames and add the markers expected by pyModeS
+ if ADSB_MESSAGE_MARKER in line:
+ msg = '*' + line.split(' ')[1].strip() + ';'
+ self.serial_queue.put(msg.encode('utf-8'))
+
+ except Exception as e:
+ print(f"Serial read error: {e}")
+ time.sleep(1)
+
+ def run(self):
+ print(f"ZMQ STREAM server listening on tcp://{self.zmq_host}:{self.zmq_port}")
+ print(f"Listening to serial port {self.serial_port} @ {self.baudrate}")
+
+ threading.Thread(target=self.serial_reader, daemon=True).start()
+
+ poller = zmq.Poller()
+ poller.register(self.socket, zmq.POLLIN)
+
+ try:
+ while self.running:
+ # Poll ZMQ socket
+ events = dict(poller.poll(100))
+
+ if self.socket in events:
+ identity, message = self.socket.recv_multipart()
+
+ if message == b'':
+ # Connection event
+ print(f"[ZMQ] Client connected/disconnected: {identity}")
+ self.clients.add(identity)
+ continue
+
+ print(f"[ZMQ RX] {identity}: {message.decode(errors='ignore')}")
+
+ # Send serial data to all connected clients
+ while not self.serial_queue.empty():
+ data = self.serial_queue.get()
+ for client_id in list(self.clients):
+ try:
+ self.socket.send_multipart([client_id, data])
+ print(f"[ZMQ TX] Sent to {client_id}")
+ except zmq.ZMQError:
+ self.clients.discard(client_id)
+
+ except KeyboardInterrupt:
+ print("Shutting down...")
+
+ finally:
+ self.running = False
+ self.serial.close()
+ self.socket.close()
+ self.context.term()
+
+
+def main():
+ parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''
+ RadioLib ADS-B Monitor script. Serves as server for "modeslive" live traffic decoder from pyModeS
+ (https://github.com/junzis/pyModeS).
+
+ Depends on pyserial and pyModeS, install by:
+ 'python3 -m pip install pyserial pyModeS'
+
+ Step-by-step guide on how to use the script:
+ 1. Upload the ADSB_Monitor example to your Arduino board with LR2021 connected.
+ 2. Run the script with appropriate arguments.
+ 3. Run "modeslive --source net --connect localhost 30002 raw"
+ ''')
+ parser.add_argument('port',
+ type=str,
+ help='COM port to connect to the device')
+ parser.add_argument('--speed',
+ default=DEFAULT_BAUDRATE,
+ type=int,
+ help=f'COM port baudrate (defaults to {DEFAULT_BAUDRATE})')
+ parser.add_argument('--server-port',
+ default=DEFAULT_SERVER_PORT,
+ type=int,
+ help=f'server port to be used by modeslive (defaults to {DEFAULT_SERVER_PORT})')
+ args = parser.parse_args()
+
+ bridge = SerialToZMQBridge(
+ serial_port=args.port,
+ baudrate=args.speed,
+ zmq_port=args.server_port
+ )
+ bridge.run()
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/lib/RadioLib/extras/SSTV_Image_Converter/ImageConverter.py b/lib/RadioLib/extras/SSTV_Image_Converter/ImageConverter.py
new file mode 100644
index 0000000..8444465
--- /dev/null
+++ b/lib/RadioLib/extras/SSTV_Image_Converter/ImageConverter.py
@@ -0,0 +1,50 @@
+#!/usr/bin/python3
+# -*- encoding: utf-8 -*-
+
+import argparse
+import numpy as np
+from PIL import Image
+from argparse import RawTextHelpFormatter
+
+def main():
+ parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''
+ RadioLib image to array conversion tool.
+
+ Input is a PNG image to be transmitted via RadioLib SSTV.
+ The image must have correct size for the chose SSTV mode!
+
+ Output is a file (by default named "img.h") which can be included and transmitted.
+ The resulting array will be very large (typically 320 kB),
+ make sure your platform has sufficient Flash/RAM space.
+ ''')
+ parser.add_argument('input',
+ type=str,
+ help='Input PNG file')
+ parser.add_argument('output',
+ type=str,
+ nargs='?',
+ default='img',
+ help='Output header file')
+ args = parser.parse_args()
+ outfile = f'{args.output}.h'
+ print(f'Converting "{args.input}" to "{outfile}"')
+
+ # open the image as numpy array
+ img = Image.open(args.input)
+ arr = np.array(img)
+
+ # open the output file
+ with open(outfile, 'w') as f:
+ print(f'const uint32_t img[{arr.shape[0]}][{arr.shape[1]}] = {{', file=f)
+ for row in arr:
+ print(' { ', end='', file=f)
+ for pix in row:
+ rgb = pix[0] << 16 | pix[1] << 8 | pix[2]
+ print(hex(rgb), end=', ', file=f)
+ print(' },', file=f)
+ print('};', file=f)
+
+ print('Done!')
+
+if __name__ == "__main__":
+ main()
diff --git a/lib/RadioLib/extras/SSTV_Image_Converter/radiolib.png b/lib/RadioLib/extras/SSTV_Image_Converter/radiolib.png
new file mode 100644
index 0000000..6a20aa8
Binary files /dev/null and b/lib/RadioLib/extras/SSTV_Image_Converter/radiolib.png differ
diff --git a/lib/RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py b/lib/RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
new file mode 100644
index 0000000..435a27a
--- /dev/null
+++ b/lib/RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
@@ -0,0 +1,176 @@
+#!/usr/bin/python3
+# -*- encoding: utf-8 -*-
+
+import argparse
+import serial
+import sys
+import numpy as np
+import matplotlib as mpl
+import matplotlib.pyplot as plt
+
+from datetime import datetime
+from argparse import RawTextHelpFormatter
+
+# number of samples in each scanline
+SCAN_WIDTH = 33
+
+# scanline Serial start/end markers
+SCAN_MARK_START = 'SCAN '
+SCAN_MARK_FREQ = 'FREQ '
+SCAN_MARK_END = ' END'
+
+# output path
+OUT_PATH = 'out'
+
+# default settings
+DEFAULT_BAUDRATE = 115200
+DEFAULT_COLOR_MAP = 'viridis'
+DEFAULT_SCAN_LEN = 200
+DEFAULT_RSSI_OFFSET = -11
+
+# Print iterations progress
+# from https://stackoverflow.com/questions/3173320/text-progress-bar-in-terminal-with-block-characters
+def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 50, fill = '█', printEnd = "\r"):
+ """
+ Call in a loop to create terminal progress bar
+ @params:
+ iteration - Required : current iteration (Int)
+ total - Required : total iterations (Int)
+ prefix - Optional : prefix string (Str)
+ suffix - Optional : suffix string (Str)
+ decimals - Optional : positive number of decimals in percent complete (Int)
+ length - Optional : character length of bar (Int)
+ fill - Optional : bar fill character (Str)
+ printEnd - Optional : end character (e.g. "\r", "\r\n") (Str)
+ """
+ percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
+ filledLength = int(length * iteration // total)
+ bar = fill * filledLength + '-' * (length - filledLength)
+ print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
+ if iteration == total:
+ print()
+
+
+def main():
+ parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''
+ RadioLib SX126x_Spectrum_Scan plotter script. Displays output from SX126x_Spectrum_Scan example
+ as grayscale and
+
+ Depends on pyserial and matplotlib, install by:
+ 'python3 -m pip install pyserial matplotlib'
+
+ Step-by-step guide on how to use the script:
+ 1. Upload the SX126x_Spectrum_Scan example to your Arduino board with SX1262 connected.
+ 2. Run the script with appropriate arguments.
+ 3. Once the scan is complete, output files will be saved to out/
+ ''')
+ parser.add_argument('port',
+ type=str,
+ help='COM port to connect to the device')
+ parser.add_argument('--speed',
+ default=DEFAULT_BAUDRATE,
+ type=int,
+ help=f'COM port baudrate (defaults to {DEFAULT_BAUDRATE})')
+ parser.add_argument('--map',
+ default=DEFAULT_COLOR_MAP,
+ type=str,
+ help=f'Matplotlib color map to use for the output (defaults to "{DEFAULT_COLOR_MAP}")')
+ parser.add_argument('--len',
+ default=DEFAULT_SCAN_LEN,
+ type=int,
+ help=f'Number of scanlines to record (defaults to {DEFAULT_SCAN_LEN})')
+ parser.add_argument('--offset',
+ default=DEFAULT_RSSI_OFFSET,
+ type=int,
+ help=f'Default RSSI offset in dBm (defaults to {DEFAULT_RSSI_OFFSET})')
+ parser.add_argument('--freq',
+ default=-1,
+ type=float,
+ help=f'Default starting frequency in MHz')
+ args = parser.parse_args()
+
+ freq_mode = False
+ scan_len = args.len
+ if (args.freq != -1):
+ freq_mode = True
+ scan_len = 1000
+
+ # create the color map and the result array
+ arr = np.zeros((SCAN_WIDTH, scan_len))
+
+ # scanline counter
+ row = 0
+
+ # list of frequencies in frequency mode
+ freq_list = []
+
+ # open the COM port
+ with serial.Serial(args.port, args.speed, timeout=None) as com:
+ while(True):
+ # update the progress bar
+ if not freq_mode:
+ printProgressBar(row, scan_len)
+
+ # read a single line
+ try:
+ line = com.readline().decode('utf-8')
+ except:
+ continue
+
+ if SCAN_MARK_FREQ in line:
+ new_freq = float(line.split(' ')[1])
+ if (len(freq_list) > 1) and (new_freq < freq_list[-1]):
+ break
+
+ freq_list.append(new_freq)
+ print('{:.3f}'.format(new_freq), end = '\r')
+ continue
+
+ # check the markers
+ if (SCAN_MARK_START in line) and (SCAN_MARK_END in line):
+ # get the values
+ scanline = line[len(SCAN_MARK_START):-len(SCAN_MARK_END)].split(',')
+ for col in range(SCAN_WIDTH):
+ arr[col][row] = int(scanline[col])
+
+ # increment the row counter
+ row = row + 1
+
+ # check if we're done
+ if (not freq_mode) and (row >= scan_len):
+ break
+
+ # scale to the number of scans (sum of any given scanline)
+ num_samples = arr.sum(axis=0)[0]
+ arr *= (num_samples/arr.max())
+
+ if freq_mode:
+ scan_len = len(freq_list)
+
+ # create the figure
+ fig, ax = plt.subplots()
+
+ # display the result as heatmap
+ extent = [0, scan_len, -4*(SCAN_WIDTH + 1), args.offset]
+ if freq_mode:
+ extent[0] = freq_list[0]
+ extent[1] = freq_list[-1]
+ im = ax.imshow(arr[:,:scan_len], cmap=args.map, extent=extent)
+ fig.colorbar(im)
+
+ # set some properites and show
+ timestamp = datetime.now().strftime('%y-%m-%d %H-%M-%S')
+ title = f'RadioLib SX126x Spectral Scan {timestamp}'
+ if freq_mode:
+ plt.xlabel("Frequency [Hz]")
+ else:
+ plt.xlabel("Time [sample]")
+ plt.ylabel("RSSI [dBm]")
+ ax.set_aspect('auto')
+ fig.suptitle(title)
+ fig.canvas.manager.set_window_title(title)
+ plt.savefig(f'{OUT_PATH}/{title.replace(" ", "_")}.png', dpi=300)
+ plt.show()
+
+if __name__ == "__main__":
+ main()
diff --git a/lib/RadioLib/extras/cppcheck/check_file.sh b/lib/RadioLib/extras/cppcheck/check_file.sh
new file mode 100644
index 0000000..45c3274
--- /dev/null
+++ b/lib/RadioLib/extras/cppcheck/check_file.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+if [[ $# -lt 1 ]]; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+path=$1
+
+cppcheck --version
+cppcheck $path --enable=all \
+ --force \
+ --inline-suppr \
+ --suppress=ConfigurationNotChecked \
+ --suppress=unusedFunction \
+ --suppress=missingIncludeSystem \
+ --suppress=missingInclude \
+ --quiet
diff --git a/lib/RadioLib/extras/cppcheck/cppcheck.sh b/lib/RadioLib/extras/cppcheck/cppcheck.sh
new file mode 100644
index 0000000..08e9a01
--- /dev/null
+++ b/lib/RadioLib/extras/cppcheck/cppcheck.sh
@@ -0,0 +1,27 @@
+#! /bin/bash
+
+file=cppcheck.txt
+cppcheck --version
+cppcheck src --enable=all \
+ --force \
+ --inline-suppr \
+ --suppress=ConfigurationNotChecked \
+ --suppress=unusedFunction \
+ --suppress=missingIncludeSystem \
+ --suppress=missingInclude \
+ --quiet >> $file 2>&1
+echo "Cppcheck finished with exit code $?"
+
+error=$(grep ": error:" $file | wc -l)
+warning=$(grep ": warning:" $file | wc -l)
+style=$(grep ": style:" $file | wc -l)
+performance=$(grep ": performance:" $file | wc -l)
+echo "found $error erros, $warning warnings, $style style and $performance performance issues"
+if [ $error -gt "0" ] || [ $warning -gt "0" ] || [ $style -gt "0" ] || [ $performance -gt "0" ]
+then
+ cat $file
+ exitcode=1
+fi
+
+rm $file
+exit $exitcode
diff --git a/lib/RadioLib/extras/template/ModuleTemplate.cpp b/lib/RadioLib/extras/template/ModuleTemplate.cpp
new file mode 100644
index 0000000..1efb1fc
--- /dev/null
+++ b/lib/RadioLib/extras/template/ModuleTemplate.cpp
@@ -0,0 +1,22 @@
+#include ".h"
+#if !defined(RADIOLIB_EXCLUDE_)
+
+::(Module* mod) {
+ /*
+ Constructor implementation MUST assign the provided "mod" pointer to the private "_mod" pointer.
+ */
+ _mod = mod;
+}
+
+int16_t ::begin() {
+ /*
+ "begin" method implementation MUST call the "init" method with appropriate settings.
+ */
+ _mod->init();
+
+ /*
+ "begin" method SHOULD implement some sort of mechanism to verify the connection between Arduino and the module.
+
+ For example, reading a version register
+ */
+}
diff --git a/lib/RadioLib/extras/template/ModuleTemplate.h b/lib/RadioLib/extras/template/ModuleTemplate.h
new file mode 100644
index 0000000..ee12194
--- /dev/null
+++ b/lib/RadioLib/extras/template/ModuleTemplate.h
@@ -0,0 +1,99 @@
+/*
+ RadioLib Module Template header file
+
+ Before opening pull request, please make sure that:
+ 1. All files MUST be compiled without errors using default Arduino IDE settings.
+ 2. All files SHOULD be compiled without warnings with compiler warnings set to "All".
+ 3. Example sketches MUST be working correctly and MUST be stable enough to run for prolonged periods of time.
+ 4. Writing style SHOULD be consistent.
+ 5. Comments SHOULD be in place for the most important chunks of code and SHOULD be free of typos.
+ 6. To indent, 2 spaces MUST be used.
+
+ If at any point you are unsure about the required style, please refer to the rest of the modules.
+*/
+
+#if !defined(_RADIOLIB__H) && !defined(RADIOLIB_EXCLUDE_)
+#if !defined(_RADIOLIB__H)
+#define _RADIOLIB__H
+
+/*
+ Header file for each module MUST include Module.h and TypeDef.h in the src folder.
+ The header file MAY include additional header files.
+*/
+#include "../../Module.h"
+#include "../../TypeDef.h"
+
+/*
+ Only use the following include if the module implements methods for OSI physical layer control.
+ This concerns only modules similar to SX127x/RF69/CC1101 etc.
+
+ In this case, your class MUST implement all virtual methods of PhysicalLayer class.
+*/
+//#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
+
+/*
+ Register map
+ Definition of SPI register map SHOULD be placed here. The register map SHOULD have two parts:
+
+ 1 - Address map: only defines register names and addresses. Register names MUST match names in
+ official documentation (datasheets etc.).
+ 2 - Variable map: defines variables inside register. This functions as a bit range map for a specific register.
+ Bit range (MSB and LSB) as well as short description for each variable MUST be provided in a comment.
+
+ See RF69 and SX127x header files for examples of register maps.
+*/
+// register map | spaces up to this point
+#define RADIOLIB__REG_ 0x00
+
+// _REG_ MSB LSB DESCRIPTION
+#define RADIOLIB__ 0b00000000 // 7 0
+
+
+/*
+ Module class definition
+
+ The module class MAY inherit from the following classes:
+
+ 1 - PhysicalLayer: In case the module implements methods for OSI physical layer control (e.g. SX127x).
+ 2 - Common class: In case the module further specifies some more generic class (e.g. SX127x/SX1278)
+*/
+class {
+ public:
+ /*
+ Constructor MUST have only one parameter "Module* mod".
+ The class MAY implement additional overloaded constructors.
+ */
+ // constructor
+ (Module* mod);
+
+ /*
+ The class MUST implement at least one basic method called "begin".
+ The "begin" method MUST initialize the module and return the status as int16_t type.
+ */
+ // basic methods
+ int16_t begin();
+
+ /*
+ The class MAY implement additional methods.
+ All implemented methods SHOULD return the status as int16_t type.
+ */
+
+#if !defined(RADIOLIB_GODMODE)
+ private:
+#endif
+ /*
+ The class MUST contain private member "Module* _mod"
+ */
+ Module* _mod;
+
+ /*
+ The class MAY contain additional private variables and/or methods.
+ Private member variables MUST have a name prefixed with "_" (underscore, ASCII 0x5F)
+
+ Usually, these are variables for saving module configuration, or methods that do not have to be exposed to the end user.
+ */
+};
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/idf_component.yml b/lib/RadioLib/idf_component.yml
index e5199c4..94705a9 100644
--- a/lib/RadioLib/idf_component.yml
+++ b/lib/RadioLib/idf_component.yml
@@ -1,4 +1,4 @@
-version: "7.1.2"
+version: "7.6.0"
description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)."
tags:
- radio
@@ -33,6 +33,8 @@ tags:
- lr1110
- lr1120
- lr1121
+ - lr2021
+ - adsb
url: "https://github.com/jgromes/RadioLib"
repository: "https://github.com/jgromes/RadioLib.git"
license: "MIT"
diff --git a/lib/RadioLib/keywords.txt b/lib/RadioLib/keywords.txt
index 9457fcb..1498d81 100644
--- a/lib/RadioLib/keywords.txt
+++ b/lib/RadioLib/keywords.txt
@@ -17,6 +17,7 @@ LLCC68 KEYWORD1
LR1110 KEYWORD1
LR1120 KEYWORD1
LR1121 KEYWORD1
+LR2021 KEYWORD1
nRF24 KEYWORD1
RF69 KEYWORD1
RFM22 KEYWORD1
@@ -86,7 +87,7 @@ EU868 KEYWORD1
US915 KEYWORD1
EU433 KEYWORD1
AU915 KEYWORD1
-CN500 KEYWORD1
+CN470 KEYWORD1
AS923 KEYWORD1
AS923_2 KEYWORD1
AS923_3 KEYWORD1
@@ -105,6 +106,9 @@ LR11x0GnssSatellite_t KEYWORD1
LR11x0GnssAlmanacStatusPart_t KEYWORD1
LR11x0GnssAlmanacStatus_t KEYWORD1
+# LR2021 structures
+LR2021LoRaSideDetector_t KEYWORD1
+
#######################################
# Methods and Functions (KEYWORD2)
#######################################
@@ -133,6 +137,7 @@ startTransmit KEYWORD2
finishTransmit KEYWORD2
startReceive KEYWORD2
readData KEYWORD2
+finishReceive KEYWORD2
startChannelScan KEYWORD2
getChannelScanResult KEYWORD2
setBandwidth KEYWORD2
@@ -195,6 +200,7 @@ getFHSSChannel KEYWORD2
clearFHSSInt KEYWORD2
randomByte KEYWORD2
getPacketLength KEYWORD2
+getLoRaRxHeaderInfo KEYWORD2
setFifoEmptyAction KEYWORD2
clearFifoEmptyAction KEYWORD2
setFifoThreshold KEYWORD2
@@ -225,12 +231,13 @@ setCrcFiltering KEYWORD2
beginFSK4 KEYWORD2
# SX126x-specific
+beginBPSK KEYWORD2
setTCXO KEYWORD2
setDio2AsRfSwitch KEYWORD2
getTimeOnAir KEYWORD2
+calculateTimeOnAir KEYWORD2
implicitHeader KEYWORD2
explicitHeader KEYWORD2
-setSyncBits KEYWORD2
setWhitening KEYWORD2
startReceiveDutyCycle KEYWORD2
startReceiveDutyCycleAuto KEYWORD2
@@ -246,6 +253,7 @@ spectralScanAbort KEYWORD2
spectralScanGetStatus KEYWORD2
spectralScanGetResult KEYWORD2
setPaRampTime KEYWORD2
+hopLRFHSS KEYWORD2
# nRF24
setIrqAction KEYWORD2
@@ -276,6 +284,10 @@ updateGnssAlmanac KEYWORD2
getGnssPosition KEYWORD2
getGnssSatellites KEYWORD2
+# LR2021
+beginOOK KEYWORD2
+setSideDetector KEYWORD2
+
# RTTY
idle KEYWORD2
byteArr KEYWORD2
@@ -302,7 +314,9 @@ beginBLE KEYWORD2
setAccessAddress KEYWORD2
range KEYWORD2
startRanging KEYWORD2
+finishRanging KEYWORD2
getRangingResult KEYWORD2
+getRangingResultRaw KEYWORD2
# Hellschreiber
printGlyph KEYWORD2
@@ -342,6 +356,8 @@ setDataRate KEYWORD2
checkDataRate KEYWORD2
setModem KEYWORD2
getModem KEYWORD2
+stageMode KEYWORD2
+launchMode KEYWORD2
# LoRaWAN
getBufferNonces KEYWORD2
@@ -354,6 +370,9 @@ beginABP KEYWORD2
activateOTAA KEYWORD2
activateABP KEYWORD2
isActivated KEYWORD2
+setClass KEYWORD2
+startMulticastSession KEYWORD2
+stopMulticastSession KEYWORD2
sendReceive KEYWORD2
sendMacCommandReq KEYWORD2
getMacLinkCheckAns KEYWORD2
@@ -366,16 +385,20 @@ setDutyCycle KEYWORD2
setDwellTime KEYWORD2
setCSMA KEYWORD2
setDeviceStatus KEYWORD2
+setActivityLeds KEYWORD2
scheduleTransmission KEYWORD2
+getBand KEYWORD2
+getClass KEYWORD2
+getVersionMajor KEYWORD2
getFCntUp KEYWORD2
getNFCntDown KEYWORD2
getAFCntDown KEYWORD2
-resetFCntDown KEYWORD2
getDevAddr KEYWORD2
getLastToA KEYWORD2
dutyCycleInterval KEYWORD2
timeUntilUplink KEYWORD2
getMaxPayloadLen KEYWORD2
+setSleepFunction KEYWORD2
#######################################
# Constants (LITERAL1)
@@ -485,8 +508,8 @@ RADIOLIB_ERR_UPLINK_UNAVAILABLE LITERAL1
RADIOLIB_ERR_COMMAND_QUEUE_FULL LITERAL1
RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1
RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1
-RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1
-RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1
+RADIOLIB_ERR_MIC_MISMATCH LITERAL1
+RADIOLIB_ERR_MULTICAST_FCNT_INVALID LITERAL1
RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1
RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1
RADIOLIB_ERR_NO_JOIN_ACCEPT LITERAL1
@@ -517,3 +540,6 @@ RADIOLIB_LR1120_FIRMWARE_0102 LITERAL1
RADIOLIB_LR1120_FIRMWARE_0201 LITERAL1
RADIOLIB_LR1121_FIRMWARE_0102 LITERAL1
RADIOLIB_LR1121_FIRMWARE_0103 LITERAL1
+
+RADIOLIB_ERR_FRONTEND_CALIBRATION_FAILED LITERAL1
+RADIOLIB_ERR_INVALID_SIDE_DETECT LITERAL1
diff --git a/lib/RadioLib/library.json b/lib/RadioLib/library.json
index 6182a0c..073d2f2 100644
--- a/lib/RadioLib/library.json
+++ b/lib/RadioLib/library.json
@@ -1,8 +1,8 @@
{
"name": "RadioLib",
- "version": "7.1.2",
+ "version": "7.6.0",
"description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).",
- "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121",
+ "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121, lr2021, adsb",
"homepage": "https://github.com/jgromes/RadioLib",
"repository":
{
diff --git a/lib/RadioLib/library.properties b/lib/RadioLib/library.properties
index f4a9586..bad6c1e 100644
--- a/lib/RadioLib/library.properties
+++ b/lib/RadioLib/library.properties
@@ -1,9 +1,9 @@
name=RadioLib
-version=7.1.2
+version=7.6.0
author=Jan Gromes
maintainer=Jan Gromes
sentence=Universal wireless communication library
-paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, LR1110 and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).
+paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, LR1110, LR2021 and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN, ADS-B).
category=Communication
url=https://github.com/jgromes/RadioLib
architectures=*
diff --git a/lib/RadioLib/src/BuildOpt.h b/lib/RadioLib/src/BuildOpt.h
index d64f500..0ed4ef8 100644
--- a/lib/RadioLib/src/BuildOpt.h
+++ b/lib/RadioLib/src/BuildOpt.h
@@ -29,7 +29,11 @@
// set which output port should be used for debug output
// may be Serial port (on Arduino) or file like stdout or stderr (on generic platforms)
#if !defined(RADIOLIB_DEBUG_PORT)
- #define RADIOLIB_DEBUG_PORT Serial
+ #if ARDUINO >= 100
+ #define RADIOLIB_DEBUG_PORT Serial
+ #else
+ #define RADIOLIB_DEBUG_PORT stdout
+ #endif
#endif
/*
@@ -102,6 +106,12 @@
#define RADIOLIB_STATIC_ARRAY_SIZE (256)
#endif
+// allow user to set custom SPI buffer size
+// the default covers the maximum supported SPI command, address and status
+#if !defined(RADIOLIB_STATIC_SPI_ARRAY_SIZE)
+ #define RADIOLIB_STATIC_SPI_ARRAY_SIZE (3*sizeof(uint32_t) + (RADIOLIB_STATIC_ARRAY_SIZE))
+#endif
+
/*
* Uncomment on boards whose clock runs too slow or too fast
* Set the value according to the following scheme:
@@ -114,6 +124,10 @@
//#define RADIOLIB_CLOCK_DRIFT_MS (0)
#endif
+#if !defined(RADIOLIB_LINE_FEED)
+ #define RADIOLIB_LINE_FEED "\r\n"
+#endif
+
#if ARDUINO >= 100
// Arduino build
#include "Arduino.h"
@@ -188,6 +202,12 @@
//#define RADIOLIB_EXCLUDE_RTTY (1)
//#define RADIOLIB_EXCLUDE_SSTV (1)
//#define RADIOLIB_EXCLUDE_DIRECT_RECEIVE (1)
+ //#define RADIOLIB_EXCLUDE_BELL (1)
+ //#define RADIOLIB_EXCLUDE_APRS (1)
+ //#define RADIOLIB_EXCLUDE_LORAWAN (1)
+ //#define RADIOLIB_EXCLUDE_LR11X0 (1)
+ //#define RADIOLIB_EXCLUDE_FSK4 (1)
+ //#define RADIOLIB_EXCLUDE_PAGER (1)
#elif defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_MEGAAVR))
// Arduino AVR boards (except for megaAVR) - Uno, Mega etc.
@@ -260,20 +280,24 @@
#define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus)
#define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus)
+ #if defined(ARDUINO_ARCH_MBED)
// Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds
#define RADIOLIB_TONE_UNSUPPORTED
#define RADIOLIB_MBED_TONE_OVERRIDE
+ #endif
-#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4)
+#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_PORTENTA_H7)
// Arduino Portenta H7
#define RADIOLIB_PLATFORM "Portenta H7"
#define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode)
#define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus)
#define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus)
+ #if defined(ARDUINO_ARCH_MBED)
// Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds
#define RADIOLIB_TONE_UNSUPPORTED
#define RADIOLIB_MBED_TONE_OVERRIDE
+ #endif
#elif defined(__STM32F4__) || defined(__STM32F1__)
// Arduino STM32 core by Roger Clark (https://github.com/rogerclarkmelbourne/Arduino_STM32)
@@ -370,6 +394,13 @@
#define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus)
#define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus)
+#elif defined(ARDUINO_ARCH_ZEPHYR) && defined(ARDUINO_UNO_Q)
+ // Arduino Uno Q (Zephyr OS)
+ #define RADIOLIB_PLATFORM "Arduino Uno Q (Zephyr OS)"
+ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode)
+ #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus)
+ #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus)
+
#else
// other Arduino platforms not covered by the above list - this may or may not work
#define RADIOLIB_PLATFORM "Unknown Arduino"
@@ -429,14 +460,10 @@
#define RADIOLIB_NC (0xFFFFFFFF)
#define RADIOLIB_NONVOLATILE
- #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) (*((uint8_t *)(void *)(addr)))
- #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) (*((uint32_t *)(void *)(addr)))
+ #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) (*(reinterpret_cast(reinterpret_cast(addr))))
+ #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) (*(reinterpret_cast(reinterpret_cast(addr))))
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
- #if !defined(RADIOLIB_DEBUG_PORT)
- #define RADIOLIB_DEBUG_PORT stdout
- #endif
-
#define DEC 10
#define HEX 16
#define OCT 8
@@ -465,87 +492,103 @@
#endif
#if RADIOLIB_DEBUG
- #if defined(RADIOLIB_BUILD_ARDUINO)
- #define RADIOLIB_DEBUG_PRINT(...) rlb_printf(__VA_ARGS__)
- #define RADIOLIB_DEBUG_PRINTLN(M, ...) rlb_printf(M "\n", ##__VA_ARGS__)
- #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) rlb_printf(LEVEL "" M, ##__VA_ARGS__)
- #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) rlb_printf(LEVEL "" M "\n", ##__VA_ARGS__)
+ #if !defined(RADIOLIB_DEBUG_PRINT)
+ #define RADIOLIB_DEBUG_PRINT(M, ...) rlb_printf(false, M, ##__VA_ARGS__)
+ #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) rlb_printf(true, LEVEL "" M, ##__VA_ARGS__)
+ #endif
- // some platforms do not support printf("%f"), so it has to be done this way
- #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS)
+ #if !defined(RADIOLIB_DEBUG_PRINTLN)
+ #define RADIOLIB_DEBUG_PRINTLN(M, ...) rlb_printf(false, M RADIOLIB_LINE_FEED, ##__VA_ARGS__)
+ #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) rlb_printf(true, LEVEL "" M RADIOLIB_LINE_FEED, ##__VA_ARGS__)
+ #endif
+
+ // some Arduino platforms do not support printf("%f"), so it has to be done this way
+ #if defined(RADIOLIB_BUILD_ARDUINO)
+ #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS)
+ #define RADIOLIB_DEBUG_PRINT_FLOAT_LVL(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS)
#else
- #if !defined(RADIOLIB_DEBUG_PRINT)
- #define RADIOLIB_DEBUG_PRINT(...) fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__)
- #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M, ##__VA_ARGS__)
- #endif
- #if !defined(RADIOLIB_DEBUG_PRINTLN)
- #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "\n", ##__VA_ARGS__)
- #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M "\n", ##__VA_ARGS__)
- #endif
- #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL)
+ #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PRINT("%.3f", VAL)
+ #define RADIOLIB_DEBUG_PRINT_FLOAT_LVL(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL)
#endif
#define RADIOLIB_DEBUG_HEXDUMP(LEVEL, ...) rlb_hexdump(LEVEL, __VA_ARGS__)
#else
#define RADIOLIB_DEBUG_PRINT(...) {}
#define RADIOLIB_DEBUG_PRINTLN(...) {}
- #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) {}
+ #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) {}
#define RADIOLIB_DEBUG_HEXDUMP(...) {}
#endif
+#define RADIOLIB_DEBUG_TAG ": "
+#define RADIOLIB_DEBUG_TAG_BASIC "RLB_DBG" RADIOLIB_DEBUG_TAG
+#define RADIOLIB_DEBUG_TAG_PROTOCOL "RLB_PRO" RADIOLIB_DEBUG_TAG
+#define RADIOLIB_DEBUG_TAG_SPI "RLB_SPI" RADIOLIB_DEBUG_TAG
+
#if RADIOLIB_DEBUG_BASIC
- #define RADIOLIB_DEBUG_BASIC_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_DBG: ", __VA_ARGS__)
- #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__)
- #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_DBG: ", __VA_ARGS__)
- #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_DBG: ", __VA_ARGS__);
- #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_DBG: ", __VA_ARGS__);
+ #define RADIOLIB_DEBUG_BASIC_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT_LVL(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__)
+ #define RADIOLIB_DEBUG_BASIC_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__)
+ #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT_NOTAG(...) RADIOLIB_DEBUG_PRINT_FLOAT(__VA_ARGS__)
#else
#define RADIOLIB_DEBUG_BASIC_PRINT(...) {}
- #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) {}
#define RADIOLIB_DEBUG_BASIC_PRINTLN(...) {}
- #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) {}
#define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) {}
+ #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) {}
+ #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) {}
+ #define RADIOLIB_DEBUG_BASIC_PRINTLN_NOTAG(...) {}
+ #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT_NOTAG(...) {}
#endif
#if RADIOLIB_DEBUG_PROTOCOL
- #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_PRO: ", __VA_ARGS__)
- #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_PRO: ", __VA_ARGS__)
- #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_PRO: ", __VA_ARGS__);
- #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_PRO: ", __VA_ARGS__);
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT_LVL(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__)
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__)
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG(...) RADIOLIB_DEBUG_PRINT_FLOAT(__VA_ARGS__)
#else
#define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) {}
#define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) {}
- #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) {}
#define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) {}
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) {}
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) {}
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(...) {}
+ #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG(...) {}
#endif
#if RADIOLIB_DEBUG_SPI
- #define RADIOLIB_DEBUG_SPI_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_SPI: ", __VA_ARGS__)
- #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__)
- #define RADIOLIB_DEBUG_SPI_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_SPI: ", __VA_ARGS__)
- #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN_LVL("", __VA_ARGS__)
- #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_SPI: ", __VA_ARGS__);
- #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_SPI: ", __VA_ARGS__);
+ #define RADIOLIB_DEBUG_SPI_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_SPI_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT_LVL(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__)
+ #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__)
+ #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__)
+ #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT_NOTAG(...) RADIOLIB_DEBUG_PRINT_FLOAT(__VA_ARGS__)
#else
#define RADIOLIB_DEBUG_SPI_PRINT(...) {}
- #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) {}
#define RADIOLIB_DEBUG_SPI_PRINTLN(...) {}
- #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) {}
- #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) {}
#define RADIOLIB_DEBUG_SPI_HEXDUMP(...) {}
+ #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) {}
+ #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) {}
+ #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) {}
+ #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT_NOTAG(...) {}
#endif
// debug info strings
#define RADIOLIB_VALUE_TO_STRING(x) #x
#define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x)
-#define RADIOLIB_INFO "\nRadioLib Info\nVersion: \"" \
+#define RADIOLIB_INFO "\r\nRadioLib Info\nVersion: \"" \
RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \
RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \
RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \
- RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\n" \
- "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\n" \
- "Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__)
+ RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\r\n" \
+ "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\r\n" \
+ RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__)
/*!
\brief A simple assert macro, will return on error.
@@ -582,8 +625,8 @@
// version definitions
#define RADIOLIB_VERSION_MAJOR 7
-#define RADIOLIB_VERSION_MINOR 1
-#define RADIOLIB_VERSION_PATCH 2
+#define RADIOLIB_VERSION_MINOR 6
+#define RADIOLIB_VERSION_PATCH 0
#define RADIOLIB_VERSION_EXTRA 0
#define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA))
diff --git a/lib/RadioLib/src/Hal.cpp b/lib/RadioLib/src/Hal.cpp
index acc43bf..9fdf108 100644
--- a/lib/RadioLib/src/Hal.cpp
+++ b/lib/RadioLib/src/Hal.cpp
@@ -1,12 +1,18 @@
#include "Hal.h"
+static RadioLibHal* rlb_timestamp_hal = nullptr;
+
RadioLibHal::RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling)
: GpioModeInput(input),
GpioModeOutput(output),
GpioLevelLow(low),
GpioLevelHigh(high),
GpioInterruptRising(rising),
- GpioInterruptFalling(falling) {}
+ GpioInterruptFalling(falling) {
+ if(!rlb_timestamp_hal) {
+ rlb_timestamp_hal = this;
+ }
+ }
void RadioLibHal::init() {
@@ -33,3 +39,14 @@ void RadioLibHal::yield() {
uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) {
return(pin);
}
+
+void RadioLibHal::pullUpDown(uint32_t pin, bool enable, bool up) {
+ // the default implementation does nothing
+ (void)pin;
+ (void)enable;
+ (void)up;
+}
+
+RadioLibTime_t rlb_time_us() {
+ return(rlb_timestamp_hal == nullptr ? 0 : rlb_timestamp_hal->micros());
+}
diff --git a/lib/RadioLib/src/Hal.h b/lib/RadioLib/src/Hal.h
index 291b347..bda07c7 100644
--- a/lib/RadioLib/src/Hal.h
+++ b/lib/RadioLib/src/Hal.h
@@ -6,6 +6,9 @@
#include "BuildOpt.h"
+/*! \brief Global-scope function that returns timestamp since start (in microseconds). */
+RadioLibTime_t rlb_time_us();
+
/*!
\class RadioLibHal
\brief Hardware abstraction library base interface.
@@ -57,6 +60,11 @@ class RadioLibHal {
*/
RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling);
+ /*!
+ \brief Default destructor.
+ */
+ virtual ~RadioLibHal() = default;
+
// pure virtual methods - these must be implemented by the hardware abstraction for RadioLib to function
/*!
@@ -207,6 +215,14 @@ class RadioLibHal {
\returns The interrupt number of a given pin.
*/
virtual uint32_t pinToInterrupt(uint32_t pin);
+
+ /*!
+ \brief Enable or disable pull up or pull down for a specific pin.
+ \param pin Pin to change.
+ \param enable True to enable, false to disable.
+ \param up Pull direction, true for pull up, false for pull down.
+ */
+ virtual void pullUpDown(uint32_t pin, bool enable, bool up);
};
#endif
diff --git a/lib/RadioLib/src/Module.cpp b/lib/RadioLib/src/Module.cpp
index cd5ddc6..e07c938 100644
--- a/lib/RadioLib/src/Module.cpp
+++ b/lib/RadioLib/src/Module.cpp
@@ -25,7 +25,7 @@ Module::Module(const Module& mod) {
}
Module& Module::operator=(const Module& mod) {
- memcpy((void*)&mod.spiConfig, &this->spiConfig, sizeof(SPIConfig_t));
+ memcpy(reinterpret_cast(&(const_cast(mod)).spiConfig), &this->spiConfig, sizeof(SPIConfig_t));
this->csPin = mod.csPin;
this->irqPin = mod.irqPin;
this->rstPin = mod.rstPin;
@@ -81,7 +81,7 @@ int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t
#if RADIOLIB_DEBUG_SPI
uint8_t readValue = 0x00;
#endif
- while(this->hal->micros() - start < (checkInterval * 1000)) {
+ while(this->hal->micros() - start < ((RadioLibTime_t)checkInterval * 1000UL)) {
uint8_t val = SPIreadRegister(reg);
if((val & checkMask) == (newValue & checkMask)) {
// check passed, we can stop the loop
@@ -142,7 +142,7 @@ uint8_t Module::SPIreadRegister(uint32_t reg) {
return(resp);
}
-void Module::SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes) {
+void Module::SPIwriteRegisterBurst(uint32_t reg, const uint8_t* data, size_t numBytes) {
if(!spiConfig.stream) {
SPItransfer(spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE], reg, data, NULL, numBytes);
} else {
@@ -174,12 +174,12 @@ void Module::SPIwriteRegister(uint32_t reg, uint8_t data) {
}
}
-void Module::SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) {
+void Module::SPItransfer(uint16_t cmd, uint32_t reg, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) {
// prepare the buffers
size_t buffLen = this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8 + numBytes;
#if RADIOLIB_STATIC_ONLY
- uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE];
- uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE];
+ uint8_t buffOut[RADIOLIB_STATIC_SPI_ARRAY_SIZE];
+ uint8_t buffIn[RADIOLIB_STATIC_SPI_ARRAY_SIZE];
#else
uint8_t* buffOut = new uint8_t[buffLen];
uint8_t* buffIn = new uint8_t[buffLen];
@@ -216,7 +216,7 @@ void Module::SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t*
// print debug information
#if RADIOLIB_DEBUG_SPI
- uint8_t* debugBuffPtr = NULL;
+ const uint8_t* debugBuffPtr = NULL;
if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE]) {
RADIOLIB_DEBUG_SPI_PRINT("W\t%X\t", reg);
debugBuffPtr = &buffOut[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8];
@@ -227,7 +227,7 @@ void Module::SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t*
for(size_t n = 0; n < numBytes; n++) {
RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", debugBuffPtr[n]);
}
- RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG();
+ RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG("");
#endif
#if !RADIOLIB_STATIC_ONLY
@@ -245,7 +245,7 @@ int16_t Module::SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool
return(this->SPIreadStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify));
}
-int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
+int16_t Module::SPIreadStream(const uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
// send the command
int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio);
RADIOLIB_ASSERT(state);
@@ -264,7 +264,7 @@ int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_
#endif
}
-int16_t Module::SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
+int16_t Module::SPIwriteStream(uint16_t cmd, const uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
uint8_t cmdBuf[2];
uint8_t* cmdPtr = cmdBuf;
for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
@@ -273,7 +273,7 @@ int16_t Module::SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, boo
return(this->SPIwriteStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify));
}
-int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
+int16_t Module::SPIwriteStream(const uint8_t* cmd, uint8_t cmdLen, const uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
// send the command
int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio);
RADIOLIB_ASSERT(state);
@@ -315,14 +315,15 @@ int16_t Module::SPIcheckStream() {
return(state);
}
-int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio) {
+int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio) {
// prepare the output buffer
+ int16_t state = RADIOLIB_ERR_NONE;
size_t buffLen = cmdLen + numBytes;
if(!write) {
buffLen += (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8);
}
#if RADIOLIB_STATIC_ONLY
- uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE];
+ uint8_t buffOut[RADIOLIB_STATIC_SPI_ARRAY_SIZE];
#else
uint8_t* buffOut = new uint8_t[buffLen];
#endif
@@ -348,6 +349,9 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write
RadioLibTime_t start = this->hal->millis();
while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield();
+
+ // this timeout check triggers a false positive from cppcheck
+ // cppcheck-suppress unsignedLessThanZero
if(this->hal->millis() - start >= this->spiConfig.timeout) {
RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?");
#if !RADIOLIB_STATIC_ONLY
@@ -355,13 +359,14 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write
#endif
return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
}
+
}
}
}
// prepare the input buffer
#if RADIOLIB_STATIC_ONLY
- uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE];
+ uint8_t buffIn[RADIOLIB_STATIC_SPI_ARRAY_SIZE];
#else
uint8_t* buffIn = new uint8_t[buffLen];
#endif
@@ -382,21 +387,23 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write
RadioLibTime_t start = this->hal->millis();
while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield();
+
+ // this timeout check triggers a false positive from cppcheck
+ // cppcheck-suppress unsignedLessThanZero
if(this->hal->millis() - start >= this->spiConfig.timeout) {
RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO post-transfer timeout, is it connected?");
- #if !RADIOLIB_STATIC_ONLY
- delete[] buffOut;
- delete[] buffIn;
- #endif
- return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
+
+ // do not return yet to display the debug output
+ state = RADIOLIB_ERR_SPI_CMD_TIMEOUT;
+ break;
}
+
}
}
}
- // parse status
- int16_t state = RADIOLIB_ERR_NONE;
- if((this->spiConfig.parseStatusCb != nullptr) && (numBytes > 0)) {
+ // parse status (only if GPIO did not timeout)
+ if((state == RADIOLIB_ERR_NONE) && (this->spiConfig.parseStatusCb != nullptr) && (numBytes > 0)) {
state = this->spiConfig.parseStatusCb(buffIn[this->spiConfig.statusPos]);
}
@@ -417,24 +424,27 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write
}
size_t n = 0;
for(; n < cmdLen; n++) {
- RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", cmd[n]);
+ // tab character intentionally omitted here
+ // command is a single number so this is easier to parse
+ RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%02X", cmd[n]);
}
- RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG();
+ RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG("");
// print data bytes
RADIOLIB_DEBUG_SPI_PRINT("SI\t");
for(n = 0; n < cmdLen; n++) {
RADIOLIB_DEBUG_SPI_PRINT_NOTAG("\t");
}
+ // initialization of n to 0 is skipped here, because we want to skip the command bytes
for(; n < buffLen; n++) {
- RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffOut[n]);
+ RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%02X\t", buffOut[n]);
}
- RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG();
+ RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG("");
RADIOLIB_DEBUG_SPI_PRINT("SO\t");
for(n = 0; n < buffLen; n++) {
- RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffIn[n]);
+ RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%02X\t", buffIn[n]);
}
- RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG();
+ RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG("");
#endif
#if !RADIOLIB_STATIC_ONLY
diff --git a/lib/RadioLib/src/Module.h b/lib/RadioLib/src/Module.h
index 328a7f5..ca2c21e 100644
--- a/lib/RadioLib/src/Module.h
+++ b/lib/RadioLib/src/Module.h
@@ -177,6 +177,7 @@ class Module {
BITS_0 = 0,
BITS_8 = 8,
BITS_16 = 16,
+ BITS_24 = 24,
BITS_32 = 32,
};
@@ -298,7 +299,7 @@ class Module {
\param data Pointer to array that holds the data that will be written.
\param numBytes Number of bytes that will be written.
*/
- void SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes);
+ void SPIwriteRegisterBurst(uint32_t reg, const uint8_t* data, size_t numBytes);
/*!
\brief SPI basic write method. Use of this method is reserved for special cases, SPIsetRegValue should be used instead.
@@ -315,7 +316,7 @@ class Module {
\param dataIn Data that was transferred from slave to master.
\param numBytes Number of bytes to transfer.
*/
- void SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes);
+ void SPItransfer(uint16_t cmd, uint32_t reg, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes);
/*!
\brief Method to check the result of last SPI stream transfer.
@@ -344,7 +345,7 @@ class Module {
\param verify Whether to verify the result of the transaction after it is finished.
\returns \ref status_codes
*/
- int16_t SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
+ int16_t SPIreadStream(const uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
/*!
\brief Method to perform a write transaction with SPI stream.
@@ -355,7 +356,7 @@ class Module {
\param verify Whether to verify the result of the transaction after it is finished.
\returns \ref status_codes
*/
- int16_t SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
+ int16_t SPIwriteStream(uint16_t cmd, const uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
/*!
\brief Method to perform a write transaction with SPI stream.
@@ -367,7 +368,7 @@ class Module {
\param verify Whether to verify the result of the transaction after it is finished.
\returns \ref status_codes
*/
- int16_t SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
+ int16_t SPIwriteStream(const uint8_t* cmd, uint8_t cmdLen, const uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
/*!
\brief SPI single transfer method for modules with stream-type SPI interface (SX126x, SX128x etc.).
@@ -380,7 +381,7 @@ class Module {
\param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x).
\returns \ref status_codes
*/
- int16_t SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio);
+ int16_t SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio);
// pin number access methods
// getCs is omitted on purpose, as it can interfere when accessing the SPI in a concurrent environment
diff --git a/lib/RadioLib/src/RadioLib.h b/lib/RadioLib/src/RadioLib.h
index adc6854..602a588 100644
--- a/lib/RadioLib/src/RadioLib.h
+++ b/lib/RadioLib/src/RadioLib.h
@@ -37,6 +37,7 @@
- PhysicalLayer - FSK and LoRa radio modules
\see https://github.com/jgromes/RadioLib
+ \see https://jgromes.github.io/RadioLib/coverage/src/index.html
\copyright Copyright (c) 2019 Jan Gromes
*/
@@ -77,6 +78,7 @@
#include "modules/LR11x0/LR1110.h"
#include "modules/LR11x0/LR1120.h"
#include "modules/LR11x0/LR1121.h"
+#include "modules/LR2021/LR2021.h"
#include "modules/nRF24/nRF24.h"
#include "modules/RF69/RF69.h"
#include "modules/RFM2x/RFM22.h"
@@ -115,6 +117,7 @@
#include "protocols/Print/Print.h"
#include "protocols/BellModem/BellModem.h"
#include "protocols/LoRaWAN/LoRaWAN.h"
+#include "protocols/ADSB/ADSB.h"
// utilities
#include "utils/CRC.h"
diff --git a/lib/RadioLib/src/TypeDef.h b/lib/RadioLib/src/TypeDef.h
index a252568..424d8c2 100644
--- a/lib/RadioLib/src/TypeDef.h
+++ b/lib/RadioLib/src/TypeDef.h
@@ -61,6 +61,11 @@
*/
#define RADIOLIB_ENCODING_WHITENING (0x02)
+/*!
+ \brief Inverted Manchester encoding.
+*/
+#define RADIOLIB_ENCODING_MANCHESTER_INV (0x03)
+
/*!
\}
*/
@@ -255,6 +260,11 @@
*/
#define RADIOLIB_ERR_INVALID_IRQ (-29)
+/*!
+ \brief Packet supplied to transmission method was shorter than required.
+*/
+#define RADIOLIB_ERR_PACKET_TOO_SHORT (-30)
+
// RF69-specific status codes
/*!
@@ -529,7 +539,7 @@
#define RADIOLIB_ERR_INVALID_CID (-1107)
/*!
- \brief User requested to start uplink while still inside RX window or under dutycycle.
+ \brief User requested to start uplink while under dutycycle.
*/
#define RADIOLIB_ERR_UPLINK_UNAVAILABLE (-1108)
@@ -549,14 +559,14 @@
#define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1111)
/*!
- \brief Received downlink Network frame counter is invalid (lower than last heard value).
+ \brief The downlink MIC could not be verified (incorrect key or invalid FCnt)
*/
-#define RADIOLIB_ERR_N_FCNT_DOWN_INVALID (-1112)
+#define RADIOLIB_ERR_MIC_MISMATCH (-1112)
/*!
- \brief Received downlink Application frame counter is invalid (lower than last heard value).
+ \brief Multicast frame counter is invalid (outside bounds).
*/
-#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1113)
+#define RADIOLIB_ERR_MULTICAST_FCNT_INVALID (-1113)
/*!
\brief Uplink payload length at this datarate exceeds the active dwell time limitations.
@@ -626,6 +636,28 @@
#define RADIOLIB_ERR_GNSS_SOLVER(X) (RADIOLIB_ERR_GNSS_SOLVER_OFFSET - (X))
#define RADIOLIB_GET_GNSS_SOLVER_ERROR(X) (-((X) - RADIOLIB_ERR_GNSS_SOLVER_OFFSET))
+// LR2021-specific status codes
+/*!
+ \brief Front end calibration failed. Often this is caused by a neraby high-power transmitter.
+*/
+#define RADIOLIB_ERR_FRONTEND_CALIBRATION_FAILED (-1300)
+
+/*!
+ \brief Multi-SF side detector configuration is invalid.
+*/
+#define RADIOLIB_ERR_INVALID_SIDE_DETECT (-1301)
+
+// ADS-B-specific status codes
+/*!
+ \brief The message type is invalid for this operation.
+*/
+#define RADIOLIB_ERR_ADSB_INVALID_MSG_TYPE (-1400)
+
+/*!
+ \brief The parsed aircraft category is invalid.
+*/
+#define RADIOLIB_ERR_ADSB_INVALID_CATEGORY (-1401)
+
/*!
\}
*/
diff --git a/lib/RadioLib/src/hal/Arduino/ArduinoHal.cpp b/lib/RadioLib/src/hal/Arduino/ArduinoHal.cpp
index 0f3dd3b..c99d0df 100644
--- a/lib/RadioLib/src/hal/Arduino/ArduinoHal.cpp
+++ b/lib/RadioLib/src/hal/Arduino/ArduinoHal.cpp
@@ -10,6 +10,9 @@ void ArduinoHal::init() {
if(initInterface) {
spiBegin();
}
+ #if defined(ARDUINO_ARCH_STM32) && defined(DWT_BASE)
+ dwt_init();
+ #endif
}
void ArduinoHal::term() {
@@ -57,7 +60,7 @@ void inline ArduinoHal::delay(RadioLibTime_t ms) {
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
::delay(ms);
#else
- ::delay(ms * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS));
+ ::delay((RadioLibTime_t)((uint64_t)ms * 1000ULL / (1000ULL + (uint64_t)RADIOLIB_CLOCK_DRIFT_MS)));
#endif
}
@@ -65,7 +68,7 @@ void inline ArduinoHal::delayMicroseconds(RadioLibTime_t us) {
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
::delayMicroseconds(us);
#else
- ::delayMicroseconds(us * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS));
+ ::delayMicroseconds((RadioLibTime_t)((uint64_t)us * 1000ULL / (1000ULL + (uint64_t)RADIOLIB_CLOCK_DRIFT_MS)));
#endif
}
@@ -73,7 +76,7 @@ RadioLibTime_t inline ArduinoHal::millis() {
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
return(::millis());
#else
- return(::millis() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS));
+ return (RadioLibTime_t)((uint64_t)::millis() * 1000ULL / (1000ULL + (uint64_t)RADIOLIB_CLOCK_DRIFT_MS));
#endif
}
@@ -81,7 +84,7 @@ RadioLibTime_t inline ArduinoHal::micros() {
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
return(::micros());
#else
- return(::micros() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS));
+ return (RadioLibTime_t)((uint64_t)::micros() * 1000ULL / (1000ULL + (uint64_t)RADIOLIB_CLOCK_DRIFT_MS));
#endif
}
diff --git a/lib/RadioLib/src/hal/RPi/PiHal.h b/lib/RadioLib/src/hal/RPi/PiHal.h
index 76a6389..f294790 100644
--- a/lib/RadioLib/src/hal/RPi/PiHal.h
+++ b/lib/RadioLib/src/hal/RPi/PiHal.h
@@ -27,8 +27,8 @@ class PiHal : public RadioLibHal {
: RadioLibHal(PI_INPUT, PI_OUTPUT, LG_LOW, LG_HIGH, PI_RISING, PI_FALLING),
_gpioDevice(gpioDevice),
_spiDevice(spiDevice),
- _spiChannel(spiChannel),
- _spiSpeed(spiSpeed) {
+ _spiSpeed(spiSpeed),
+ _spiChannel(spiChannel) {
}
void init() override {
@@ -63,13 +63,12 @@ class PiHal : public RadioLibHal {
}
int result;
- int flags = 0;
switch(mode) {
case PI_INPUT:
- result = lgGpioClaimInput(_gpioHandle, 0, pin);
+ result = lgGpioClaimInput(_gpioHandle, pinFlags[pin], pin);
break;
case PI_OUTPUT:
- result = lgGpioClaimOutput(_gpioHandle, flags, pin, LG_HIGH);
+ result = lgGpioClaimOutput(_gpioHandle, pinFlags[pin], pin, LG_HIGH);
break;
default:
fprintf(stderr, "Unknown pinMode mode %" PRIu32 "\n", mode);
@@ -119,9 +118,11 @@ class PiHal : public RadioLibHal {
// enable emulated interrupt
interruptEnabled[interruptNum] = true;
- interruptModes[interruptNum] = mode;
interruptCallbacks[interruptNum] = interruptCb;
+ // lpgio reports the value of level after an interrupt, not the actual direction
+ interruptModes[interruptNum] = (mode == this->GpioInterruptFalling) ? LG_LOW : LG_HIGH;
+
lgGpioSetAlertsFunc(_gpioHandle, interruptNum, lgpioAlertHandler, (void *)this);
}
@@ -224,6 +225,14 @@ class PiHal : public RadioLibHal {
lgTxPwm(_gpioHandle, pin, 0, 0, 0, 0);
}
+ void pullUpDown(uint32_t pin, bool enable, bool up) {
+ if((pin == RADIOLIB_NC) || (pin > PI_MAX_USER_GPIO)) {
+ return;
+ }
+
+ pinFlags[pin] = enable ? (up ? LG_SET_PULL_UP : LG_SET_PULL_DOWN) : LG_SET_PULL_NONE;
+ }
+
// interrupt emulation
bool interruptEnabled[PI_MAX_USER_GPIO + 1];
uint32_t interruptModes[PI_MAX_USER_GPIO + 1];
@@ -232,12 +241,14 @@ class PiHal : public RadioLibHal {
private:
// the HAL can contain any additional private members
- const unsigned int _spiSpeed;
const uint8_t _gpioDevice;
const uint8_t _spiDevice;
+ const unsigned int _spiSpeed;
const uint8_t _spiChannel;
int _gpioHandle = -1;
int _spiHandle = -1;
+
+ int pinFlags[PI_MAX_USER_GPIO + 1] = { 0 };
};
// this handler emulates interrupts
diff --git a/lib/RadioLib/src/hal/RPiPico/PicoHal.cpp b/lib/RadioLib/src/hal/RPiPico/PicoHal.cpp
new file mode 100644
index 0000000..03e6733
--- /dev/null
+++ b/lib/RadioLib/src/hal/RPiPico/PicoHal.cpp
@@ -0,0 +1,49 @@
+#include "PicoHal.h"
+
+#if defined(RADIOLIB_BUILD_RPI_PICO)
+
+// pre-calculated pulse-widths for 1200 and 2200Hz
+// we do this to save calculation time (see https://github.com/khoih-prog/RP2040_PWM/issues/6)
+#define SLEEP_1200 416.666
+#define SLEEP_2200 227.272
+
+static uint32_t toneLoopPin;
+static unsigned int toneLoopFrequency;
+static unsigned long toneLoopDuration;
+
+// === NOTE ===
+// The tone(...) implementation uses the second core on the RPi Pico. This is to diminish as much
+// jitter in the output tones as possible.
+
+static void toneLoop() {
+ gpio_set_dir(toneLoopPin, GPIO_OUT);
+
+ uint32_t sleep_dur;
+ if(toneLoopFrequency == 1200) {
+ sleep_dur = SLEEP_1200;
+ } else if(toneLoopFrequency == 2200) {
+ sleep_dur = SLEEP_2200;
+ } else {
+ sleep_dur = 500000 / toneLoopFrequency;
+ }
+
+ // tone bitbang
+ while(1) {
+ gpio_put(toneLoopPin, 1);
+ sleep_us(sleep_dur);
+ gpio_put(toneLoopPin, 0);
+ sleep_us(sleep_dur);
+ tight_loop_contents();
+ }
+}
+
+void PicoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) {
+ // tones on the Pico are generated using bitbanging. This process is offloaded to the Pico's second core
+ multicore_reset_core1();
+ toneLoopPin = pin;
+ toneLoopFrequency = frequency;
+ toneLoopDuration = duration;
+ multicore_launch_core1(toneLoop);
+}
+
+#endif
diff --git a/lib/RadioLib/src/hal/RPiPico/PicoHal.h b/lib/RadioLib/src/hal/RPiPico/PicoHal.h
index ec4d12e..daf5a75 100644
--- a/lib/RadioLib/src/hal/RPiPico/PicoHal.h
+++ b/lib/RadioLib/src/hal/RPiPico/PicoHal.h
@@ -1,6 +1,8 @@
#ifndef PICO_HAL_H
#define PICO_HAL_H
+#if defined(RADIOLIB_BUILD_RPI_PICO)
+
// include RadioLib
#include
@@ -10,41 +12,27 @@
#include "hardware/timer.h"
#include "hardware/pwm.h"
#include "hardware/clocks.h"
+#include "hardware/gpio.h"
#include "pico/multicore.h"
-uint32_t toneLoopPin;
-unsigned int toneLoopFrequency;
-unsigned long toneLoopDuration;
+#define PI_PICO_MAX_USER_GPIO (48)
-// pre-calculated pulse-widths for 1200 and 2200Hz
-// we do this to save calculation time (see https://github.com/khoih-prog/RP2040_PWM/issues/6)
-#define SLEEP_1200 416.666
-#define SLEEP_2200 227.272
+// because the Pico SDK does not allow to pass user data into interrupt handlers,
+// we keep it as a global here. This is hacky and means that multiple PicoHal
+// instances share the same interrupts, which is weird and will probably break.
+// However, there seems to be no real use case for creating multiple intances of the HAL
+static irq_handler_t picoHalUserCallbacks[PI_PICO_MAX_USER_GPIO] = { 0 };
+static uint32_t picoHalIrqEventMasks[PI_PICO_MAX_USER_GPIO] = { 0 };
+static uint64_t picoHalIrqMask = 0;
-// === NOTE ===
-// The tone(...) implementation uses the second core on the RPi Pico. This is to diminish as much
-// jitter in the output tones as possible.
-
-void toneLoop(){
- gpio_set_dir(toneLoopPin, GPIO_OUT);
-
- uint32_t sleep_dur;
- if (toneLoopFrequency == 1200) {
- sleep_dur = SLEEP_1200;
- } else if (toneLoopFrequency == 2200) {
- sleep_dur = SLEEP_2200;
- } else {
- sleep_dur = 500000 / toneLoopFrequency;
- }
-
-
- // tone bitbang
- while(1){
- gpio_put(toneLoopPin, 1);
- sleep_us(sleep_dur);
- gpio_put(toneLoopPin, 0);
- sleep_us(sleep_dur);
- tight_loop_contents();
+static void picoInterruptHandler(void) {
+ for(int gpio = 0; gpio < PI_PICO_MAX_USER_GPIO; gpio++) {
+ if(gpio_get_irq_event_mask(gpio) == picoHalIrqEventMasks[gpio]) {
+ gpio_acknowledge_irq(gpio, picoHalIrqEventMasks[gpio]);
+ if(picoHalUserCallbacks[gpio]) {
+ picoHalUserCallbacks[gpio]();
+ }
+ }
}
}
@@ -103,7 +91,28 @@ public:
return;
}
- gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)interruptCb);
+ // set callbacks
+ picoHalUserCallbacks[interruptNum] = (irq_handler_t)interruptCb;
+ picoHalIrqEventMasks[interruptNum] = mode;
+
+ // is it a new interrupt for us to grab ?
+ if (!(picoHalIrqMask & (1ULL << interruptNum))) {
+ // if we have a handler in place, we must remove it to avoid 'assert' in the PDK
+ // and we must disable interrupt to make sure we don't miss anything during that
+ // shuffling
+ if (picoHalIrqMask) {
+ irq_set_enabled(IO_IRQ_BANK0, false);
+ gpio_remove_raw_irq_handler_masked64(picoHalIrqMask, picoInterruptHandler);
+ }
+
+ // (re-)add shared handler with the new mask
+ picoHalIrqMask |= (1ULL << interruptNum);
+ gpio_add_raw_irq_handler_masked64(picoHalIrqMask, picoInterruptHandler);
+ irq_set_enabled(IO_IRQ_BANK0, true);
+ }
+
+ // enable GPIO to generate interrupt
+ gpio_set_irq_enabled(interruptNum, mode, true);
}
void detachInterrupt(uint32_t interruptNum) override {
@@ -111,7 +120,12 @@ public:
return;
}
- gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, NULL);
+ // disable the IRQ
+ gpio_set_irq_enabled(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
+
+ // clear callbacks
+ picoHalUserCallbacks[interruptNum] = NULL;
+ picoHalIrqEventMasks[interruptNum] = 0;
}
void delay(unsigned long ms) override {
@@ -148,14 +162,7 @@ public:
return (this->micros() - start);
}
- void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override {
- // tones on the Pico are generated using bitbanging. This process is offloaded to the Pico's second core
- multicore_reset_core1();
- toneLoopPin = pin;
- toneLoopFrequency = frequency;
- toneLoopDuration = duration;
- multicore_launch_core1(toneLoop);
- }
+ void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override;
void noTone(uint32_t pin) override {
multicore_reset_core1();
@@ -196,3 +203,5 @@ private:
};
#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/CC1101/CC1101.cpp b/lib/RadioLib/src/modules/CC1101/CC1101.cpp
index b91b949..ca0f062 100644
--- a/lib/RadioLib/src/modules/CC1101/CC1101.cpp
+++ b/lib/RadioLib/src/modules/CC1101/CC1101.cpp
@@ -2,7 +2,9 @@
#include
#if !RADIOLIB_EXCLUDE_CC1101
-CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SIZE, RADIOLIB_CC1101_MAX_PACKET_LENGTH) {
+CC1101::CC1101(Module* module) : PhysicalLayer() {
+ this->freqStep = RADIOLIB_CC1101_FREQUENCY_STEP_SIZE;
+ this->maxPacketLength = RADIOLIB_CC1101_MAX_PACKET_LENGTH;
this->mod = module;
}
@@ -37,7 +39,7 @@ int16_t CC1101::transmit(const uint8_t* data, size_t len, uint8_t addr) {
this->mod->hal->yield();
if(this->mod->hal->millis() - start > timeout) {
- finishTransmit();
+ (void)finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
}
@@ -48,7 +50,7 @@ int16_t CC1101::transmit(const uint8_t* data, size_t len, uint8_t addr) {
this->mod->hal->yield();
if(this->mod->hal->millis() - start > timeout) {
- finishTransmit();
+ (void)finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
}
@@ -56,9 +58,12 @@ int16_t CC1101::transmit(const uint8_t* data, size_t len, uint8_t addr) {
return(finishTransmit());
}
-int16_t CC1101::receive(uint8_t* data, size_t len) {
- // calculate timeout (500 ms + 400 full max-length packets at current bit rate)
- RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0);
+int16_t CC1101::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
+ RadioLibTime_t timeoutInternal = timeout;
+ if(!timeoutInternal) {
+ // calculate timeout (500 ms + 400 full max-length packets at current bit rate)
+ timeoutInternal = 500 + (1.0f/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0f);
+ }
// start reception
int16_t state = startReceive();
@@ -69,9 +74,8 @@ int16_t CC1101::receive(uint8_t* data, size_t len) {
while(this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
- if(this->mod->hal->millis() - start > timeout) {
- standby();
- SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
+ if(this->mod->hal->millis() - start > timeoutInternal) {
+ (void)finishReceive();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
}
@@ -81,9 +85,8 @@ int16_t CC1101::receive(uint8_t* data, size_t len) {
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
- if(this->mod->hal->millis() - start > timeout) {
- standby();
- SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
+ if(this->mod->hal->millis() - start > timeoutInternal) {
+ (void)finishReceive();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
}
@@ -116,6 +119,12 @@ int16_t CC1101::standby(uint8_t mode) {
return(standby());
}
+int16_t CC1101::sleep() {
+ int16_t state =standby();
+ SPIsendCommand(RADIOLIB_CC1101_CMD_POWER_DOWN);
+ return(state);
+}
+
int16_t CC1101::transmitDirect(uint32_t frf) {
return transmitDirect(true, frf);
}
@@ -230,23 +239,52 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
// flush Tx FIFO
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX);
- // set GDO0 mapping
- int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0);
- RADIOLIB_ASSERT(state);
+ // Turn on freq oscilator
+ SPIsendCommand(RADIOLIB_CC1101_CMD_FSTXON);
+
+ // Check MARCSTATE and wait until ready to tx
+ // 724us is the longest time for calibrate per datasheet
+ // Needs a bit more time for reliability
+ RadioLibTime_t start = this->mod->hal->micros();
+ while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != 0x12) {
+ if(this->mod->hal->micros() - start > 1600) {
+ standby();
+ return(RADIOLIB_ERR_TX_TIMEOUT);
+ }
+ }
+
+ // set GDO2 mapping only if we aren't refilling the FIFO
+ int16_t state = RADIOLIB_ERR_NONE;
+ if(len <= RADIOLIB_CC1101_FIFO_SIZE) {
+ state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // data put on FIFO
+ uint8_t dataSent = 0;
+ uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0);
// optionally write packet length
if(this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) {
- SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, len);
+ if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH - 1) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+ SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, len + (filter != RADIOLIB_CC1101_ADR_CHK_NONE? 1:0));
+ dataSent+= 1;
}
// check address filtering
- uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0);
if(filter != RADIOLIB_CC1101_ADR_CHK_NONE) {
SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, addr);
+ dataSent += 1;
}
// fill the FIFO
- SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(data), len);
+ uint8_t initialWrite = RADIOLIB_MIN((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent));
+ SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(data), initialWrite);
+
+ // reset the data sent counter as it will be used later to calculate the remaining number of bytes to read from the user buffer
+ dataSent = initialWrite;
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_TX);
@@ -254,18 +292,64 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
// set mode to transmit
SPIsendCommand(RADIOLIB_CC1101_CMD_TX);
+ // keep feeding the FIFO until the packet is done
+ // calculate timeout (5ms + 500 % of expected time-on-air)
+ RadioLibTime_t timeout = 5 + (RadioLibTime_t)((((float)(len * 8)) / this->bitRate) * 5);
+ start = this->mod->hal->millis();
+ while(dataSent < len) {
+ uint8_t fifoBytes = 0;
+ uint8_t prevFifobytes = 0;
+
+ // check number of bytes on FIFO twice due to the CC1101 errata
+ // block until two reads are equal
+ do {
+ fifoBytes = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0);
+ prevFifobytes = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0);
+ } while(fifoBytes != prevFifobytes);
+
+ // if there is room, add more data to the FIFO
+ if(fifoBytes < RADIOLIB_CC1101_FIFO_SIZE) {
+ uint8_t bytesToWrite = RADIOLIB_MIN((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - fifoBytes), (uint8_t)(len - dataSent));
+ SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(&data[dataSent]), bytesToWrite);
+ dataSent += bytesToWrite;
+ }
+
+ // check a timeout - this really shouldn't happen, but some packets can be quite long
+ if(this->mod->hal->millis() - start > timeout) {
+ (void)finishTransmit();
+ return(RADIOLIB_ERR_TX_TIMEOUT);
+ }
+ }
+
+ // enable interrupt for the final part of the packet
+ if(len > RADIOLIB_CC1101_FIFO_SIZE) {
+ state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0);
+ }
+
return(state);
}
int16_t CC1101::finishTransmit() {
// set mode to standby to disable transmitter/RF switch
+
+ // Check MARCSTATE for Idle to let anything in the FIFO empty
+ // Timeout is 2x FIFO transmit time
+ RadioLibTime_t timeout = (1.0f/(this->bitRate))*(RADIOLIB_CC1101_FIFO_SIZE*2.0f);
+ RadioLibTime_t start = this->mod->hal->millis();
+ while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != 0x01) {
+ if(this->mod->hal->millis() - start > timeout) {
+ return(RADIOLIB_ERR_TX_TIMEOUT);
+ }
+ }
+
int16_t state = standby();
RADIOLIB_ASSERT(state);
// flush Tx FIFO
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX);
-
- return(state);
+
+ // reset GDO2 back to high-Z
+ return(SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0));
}
int16_t CC1101::startReceive() {
@@ -277,8 +361,14 @@ int16_t CC1101::startReceive() {
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
// set GDO0 mapping
- // GDO0 is de-asserted at packet end, hence it is inverted here
- state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDO0_INV | RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 6, 0);
+ // this is the only interrupt source that works reliably
+ // RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED gets triggered by both packet received as well as packet discarded,
+ // RADIOLIB_CC1101_GDOX_PKT_RECEIVED_CRC_OK does not get triggered with CRC disabled
+ state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END, 6, 0);
+ RADIOLIB_ASSERT(state);
+
+ // set Rx FIFO threshold to the maximum Rx size
+ state = SPIsetRegValue(RADIOLIB_CC1101_REG_FIFOTHR, RADIOLIB_CC1101_FIFO_THR_TX_1_RX_64, 3, 0);
RADIOLIB_ASSERT(state);
// set RF switch (if present)
@@ -318,7 +408,7 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
// check if status bytes are enabled (default: RADIOLIB_CC1101_APPEND_STATUS_ON)
bool isAppendStatus = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 2, 2) == RADIOLIB_CC1101_APPEND_STATUS_ON;
- // If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO.
+ // if status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO.
int16_t state = RADIOLIB_ERR_NONE;
if (isAppendStatus) {
// read RSSI byte
@@ -338,25 +428,30 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
// clear internal flag so getPacketLength can return the new packet length
this->packetLengthQueried = false;
- // Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE)
+ // flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE)
if(SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) {
-
- // set mode to standby
- standby();
-
- // flush Rx FIFO
- SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
+ (void)finishReceive();
}
return(state);
}
+int16_t CC1101::finishReceive() {
+ // go to standby and flush the FIFO
+ int16_t state = standby();
+ SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
+ RADIOLIB_ASSERT(state);
+
+ // reset GDO0 back to high-Z
+ return(SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0));
+}
+
int16_t CC1101::setFrequency(float freq) {
// check allowed frequency range
#if RADIOLIB_CHECK_PARAMS
- if(!(((freq >= 300.0) && (freq <= 348.0)) ||
- ((freq >= 387.0) && (freq <= 464.0)) ||
- ((freq >= 779.0) && (freq <= 928.0)))) {
+ if(!(((freq >= 300.0f) && (freq <= 348.0f)) ||
+ ((freq >= 387.0f) && (freq <= 464.0f)) ||
+ ((freq >= 779.0f) && (freq <= 928.0f)))) {
return(RADIOLIB_ERR_INVALID_FREQUENCY);
}
#endif
@@ -366,7 +461,7 @@ int16_t CC1101::setFrequency(float freq) {
//set carrier frequency
uint32_t base = 1;
- uint32_t FRF = (freq * (base << 16)) / 26.0;
+ uint32_t FRF = (freq * (base << 16)) / 26.0f;
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16, 7, 0);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8, 7, 0);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0);
@@ -380,7 +475,7 @@ int16_t CC1101::setFrequency(float freq) {
}
int16_t CC1101::setBitRate(float br) {
- RADIOLIB_CHECK_RANGE(br, 0.025, 600.0, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(br, 0.025f, 600.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
// set mode to standby
SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE);
@@ -388,7 +483,7 @@ int16_t CC1101::setBitRate(float br) {
// calculate exponent and mantissa values
uint8_t e = 0;
uint8_t m = 0;
- getExpMant(br * 1000.0, 256, 28, 14, e, m);
+ getExpMant(br * 1000.0f, 256, 28, 14, e, m);
// set bit rate value
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, e, 3, 0);
@@ -409,7 +504,7 @@ int16_t CC1101::setBitRateTolerance(uint8_t brt) {
}
int16_t CC1101::setRxBandwidth(float rxBw) {
- RADIOLIB_CHECK_RANGE(rxBw, 58.0, 812.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(rxBw, 58.0f, 812.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
// set mode to standby
SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE);
@@ -417,8 +512,8 @@ int16_t CC1101::setRxBandwidth(float rxBw) {
// calculate exponent and mantissa values
for(int8_t e = 3; e >= 0; e--) {
for(int8_t m = 3; m >= 0; m --) {
- float point = (RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e));
- if(fabs((rxBw * 1000.0) - point) <= 1000) {
+ float point = (RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0f)/(8 * (m + 4) * ((uint32_t)1 << e));
+ if(fabs((rxBw * 1000.0f - point) <= 1000.0f)) {
// set Rx channel filter bandwidth
return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4));
}
@@ -430,33 +525,33 @@ int16_t CC1101::setRxBandwidth(float rxBw) {
}
int16_t CC1101::autoSetRxBandwidth() {
- // Uncertainty ~ +/- 40ppm for a cheap CC1101
- // Uncertainty * 2 for both transmitter and receiver
- float uncertainty = ((this->frequency) * 40 * 2);
- uncertainty = (uncertainty/1000); //Since bitrate is in kBit
- float minbw = ((this->bitRate) + uncertainty);
-
- int possibles[16] = {58, 68, 81, 102, 116, 135, 162, 203, 232, 270, 325, 406, 464, 541, 650, 812};
-
- for (int i = 0; i < 16; i++) {
- if (possibles[i] > minbw) {
- int16_t state = setRxBandwidth(possibles[i]);
- return(state);
- }
+ // Uncertainty ~ +/- 40ppm for a cheap CC1101
+ // Uncertainty * 2 for both transmitter and receiver
+ float uncertainty = ((this->frequency) * 40 * 2);
+ uncertainty = (uncertainty/1000); //Since bitrate is in kBit
+ float minbw = ((this->bitRate) + uncertainty);
+
+ const int options[16] = { 58, 68, 81, 102, 116, 135, 162, 203, 232, 270, 325, 406, 464, 541, 650, 812 };
+
+ for(int i = 0; i < 16; i++) {
+ if(options[i] > minbw) {
+ return(setRxBandwidth(options[i]));
}
- return(RADIOLIB_ERR_UNKNOWN);
}
+ return(RADIOLIB_ERR_UNKNOWN);
+}
+
int16_t CC1101::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
- if(freqDev < 0.0) {
- newFreqDev = 1.587;
+ if(freqDev < 0.0f) {
+ newFreqDev = 1.587f;
}
// check range unless 0 (special value)
if (freqDev != 0) {
- RADIOLIB_CHECK_RANGE(newFreqDev, 1.587, 380.8, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ RADIOLIB_CHECK_RANGE(newFreqDev, 1.587f, 380.8f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
}
// set mode to standby
@@ -465,7 +560,7 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) {
// calculate exponent and mantissa values
uint8_t e = 0;
uint8_t m = 0;
- getExpMant(newFreqDev * 1000.0, 8, 17, 7, e, m);
+ getExpMant(newFreqDev * 1000.0f, 8, 17, 7, e, m);
// set frequency deviation value
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_DEVIATN, (e << 4), 6, 4);
@@ -494,7 +589,7 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) {
//
// freqDev = (fXosc / 2^17) * (8 + m) * 2^e
//
- *freqDev = (1000.0 / (uint32_t(1) << 17)) - (8 + m) * (uint32_t(1) << e);
+ *freqDev = (1000.0f / (uint32_t(1) << 17)) - (8 + m) * (uint32_t(1) << e);
return(RADIOLIB_ERR_NONE);
}
@@ -513,7 +608,7 @@ int16_t CC1101::setOutputPower(int8_t pwr) {
// PA_TABLE[0] is the power to be used when transmitting a 0 (no power)
// PA_TABLE[1] is the power to be used when transmitting a 1 (full power)
- uint8_t paValues[2] = {0x00, powerRaw};
+ const uint8_t paValues[2] = { 0x00, powerRaw };
SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_PATABLE, paValues, 2);
return(RADIOLIB_ERR_NONE);
@@ -558,13 +653,13 @@ int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) {
// round to the known frequency settings
uint8_t f;
- if(this->frequency < 374.0) {
+ if(this->frequency < 374.0f) {
// 315 MHz
f = 0;
- } else if(this->frequency < 650.5) {
+ } else if(this->frequency < 650.5f) {
// 434 MHz
f = 1;
- } else if(this->frequency < 891.5) {
+ } else if(this->frequency < 891.5f) {
// 868 MHz
f = 2;
} else {
@@ -592,7 +687,11 @@ int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) {
return(RADIOLIB_ERR_INVALID_OUTPUT_POWER);
}
-int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) {
+int16_t CC1101::setSyncWord(uint8_t* sync, size_t len) {
+ return this->setSyncWord(sync, len, 0, false);
+}
+
+int16_t CC1101::setSyncWord(const uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) {
if((maxErrBits > 1) || (len != 2)) {
return(RADIOLIB_ERR_INVALID_SYNC_WORD);
}
@@ -620,6 +719,9 @@ int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits, bo
return(setSyncWord(syncWord, sizeof(syncWord), maxErrBits, requireCarrierSense));
}
+int16_t CC1101::setPreambleLength(size_t len) {
+ return this->setPreambleLength(len, len-4);
+}
int16_t CC1101::setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold) {
// check allowed values
uint8_t value;
@@ -717,9 +819,9 @@ float CC1101::getRSSI() {
if(!this->directModeEnabled) {
if(this->rawRSSI >= 128) {
- rssi = (((float)this->rawRSSI - 256.0)/2.0) - 74.0;
+ rssi = (((float)this->rawRSSI - 256.0f)/2.0f) - 74.0f;
} else {
- rssi = (((float)this->rawRSSI)/2.0) - 74.0;
+ rssi = (((float)this->rawRSSI)/2.0f) - 74.0f;
}
} else {
uint8_t rawRssi = SPIreadRegister(RADIOLIB_CC1101_REG_RSSI);
@@ -1001,7 +1103,7 @@ int16_t CC1101::beginCommon(float freq, float br, float freqDev, float rxBw, int
RADIOLIB_ASSERT(state);
// set default sync word
- uint8_t sw[RADIOLIB_CC1101_DEFAULT_SW_LEN] = RADIOLIB_CC1101_DEFAULT_SW;
+ const uint8_t sw[RADIOLIB_CC1101_DEFAULT_SW_LEN] = RADIOLIB_CC1101_DEFAULT_SW;
state = setSyncWord(sw[0], sw[1], 0, false);
RADIOLIB_ASSERT(state);
@@ -1064,7 +1166,7 @@ int16_t CC1101::directMode(bool sync) {
void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant) {
// get table origin point (exp = 0, mant = 0)
- float origin = (mantOffset * RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/((uint32_t)1 << divExp);
+ float origin = (mantOffset * RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0f)/((uint32_t)1 << divExp);
// iterate over possible exponent values
for(int8_t e = expMax; e >= 0; e--) {
@@ -1155,7 +1257,7 @@ void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) {
return(this->mod->SPIwriteRegister(reg, data));
}
-void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) {
+void CC1101::SPIwriteRegisterBurst(uint8_t reg, const uint8_t* data, size_t len) {
this->mod->SPIwriteRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, data, len);
}
diff --git a/lib/RadioLib/src/modules/CC1101/CC1101.h b/lib/RadioLib/src/modules/CC1101/CC1101.h
index e1a71a4..b894726 100644
--- a/lib/RadioLib/src/modules/CC1101/CC1101.h
+++ b/lib/RadioLib/src/modules/CC1101/CC1101.h
@@ -8,8 +8,9 @@
// CC1101 physical layer properties
#define RADIOLIB_CC1101_FREQUENCY_STEP_SIZE 396.7285156
-#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 64
-#define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0
+#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 255
+#define RADIOLIB_CC1101_FIFO_SIZE 64
+#define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0f
#define RADIOLIB_CC1101_DIV_EXPONENT 16
// CC1101 SPI commands
@@ -182,6 +183,7 @@
#define RADIOLIB_CC1101_RX_ATTEN_18_DB 0b00110000 // 5 4 18 dB
#define RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4 0b00000000 // 3 0 TX fifo threshold: 61, RX fifo threshold: 4
#define RADIOLIB_CC1101_FIFO_THR_TX_33_RX_32 0b00000111 // 3 0 TX fifo threshold: 33, RX fifo threshold: 32
+#define RADIOLIB_CC1101_FIFO_THR_TX_1_RX_64 0b00001111 // 3 0 TX fifo threshold: 1, RX fifo threshold: 64
#define RADIOLIB_CC1101_FIFO_THRESH_TX 33
#define RADIOLIB_CC1101_FIFO_THRESH_RX 32
@@ -595,11 +597,13 @@ class CC1101: public PhysicalLayer {
/*!
\brief Blocking binary receive method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
- \param data Binary data to be sent.
- \param len Number of bytes to send.
+ \param data Pointer to array to save the received binary data.
+ \param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+ \param timeout Reception timeout in milliseconds. If set to 0,
+ timeout period will be calculated automatically based on the radio configuration.
\returns \ref status_codes
*/
- int16_t receive(uint8_t* data, size_t len) override;
+ int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override;
/*!
\brief Sets the module to standby mode.
@@ -614,6 +618,12 @@ class CC1101: public PhysicalLayer {
*/
int16_t standby(uint8_t mode) override;
+ /*!
+ \brief Sets the module to sleep mode.
+ \returns \ref status_codes
+ */
+ int16_t sleep() override;
+
/*!
\brief Starts synchronous direct mode transmission.
\param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY.
@@ -695,7 +705,10 @@ class CC1101: public PhysicalLayer {
void clearPacketSentAction() override;
/*!
- \brief Interrupt-driven binary transmit method.
+ \brief Interrupt-driven binary transmit method for packets less than 64 bytes.
+ Method blocks for packets longer than 64 bytes up to a 255 byte limit, until
+ the last bytes are placed in the FIFO. Some limitations and issues apply; see discussion:
+ https://github.com/jgromes/RadioLib/discussions/1138
Overloads for string-based transmissions are implemented in PhysicalLayer.
\param data Binary data to be sent.
\param len Number of bytes to send.
@@ -736,6 +749,12 @@ class CC1101: public PhysicalLayer {
*/
int16_t readData(uint8_t* data, size_t len) override;
+ /*!
+ \brief Clean up after reception is done.
+ \returns \ref status_codes
+ */
+ int16_t finishReceive() override;
+
// configuration methods
/*!
@@ -815,6 +834,14 @@ class CC1101: public PhysicalLayer {
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw);
+ /*!
+ \brief Set 1 or 2 bytes of sync word.
+ \param sync Pointer to the sync word.
+ \param len Sync word length in bytes. Maximum length depends on the module used.
+ \returns \ref status_codes
+ */
+ int16_t setSyncWord(uint8_t *sync, size_t len) override;
+
/*!
\brief Sets 16-bit sync word as a two byte value.
\param syncH MSB of the sync word.
@@ -833,7 +860,14 @@ class CC1101: public PhysicalLayer {
\param requireCarrierSense Require carrier sense above threshold in addition to sync word.
\returns \ref status_codes
*/
- int16_t setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0, bool requireCarrierSense = false);
+ int16_t setSyncWord(const uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0, bool requireCarrierSense = false);
+
+ /*!
+ \brief Sets preamble length.
+ \param len Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192.
+ \returns \ref status_codes
+ */
+ int16_t setPreambleLength(size_t len) override;
/*!
\brief Sets preamble length.
@@ -866,7 +900,7 @@ class CC1101: public PhysicalLayer {
int16_t setOOK(bool enableOOK);
/*!
- \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet.
+ \brief Gets RSSI (Received Signal Strength Indicator) of the last received packet.
In direct or asynchronous direct mode, returns the current RSSI level.
\returns RSSI in dBm.
*/
@@ -991,7 +1025,7 @@ class CC1101: public PhysicalLayer {
\param value The value that indicates which function to place on that pin. See chip datasheet for details.
\returns \ref status_codes
*/
- int16_t setDIOMapping(uint32_t pin, uint32_t value) override;
+ int16_t setDIOMapping(uint32_t pin, uint32_t value);
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
@@ -1003,7 +1037,7 @@ class CC1101: public PhysicalLayer {
int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2);
void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes);
uint8_t SPIreadRegister(uint8_t reg);
- void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len);
+ void SPIwriteRegisterBurst(uint8_t reg, const uint8_t* data, size_t len);
void SPIwriteRegister(uint8_t reg, uint8_t data);
void SPIsendCommand(uint8_t cmd);
diff --git a/lib/RadioLib/src/modules/LLCC68/LLCC68.cpp b/lib/RadioLib/src/modules/LLCC68/LLCC68.cpp
index 834f5ed..8ea29f9 100644
--- a/lib/RadioLib/src/modules/LLCC68/LLCC68.cpp
+++ b/lib/RadioLib/src/modules/LLCC68/LLCC68.cpp
@@ -37,8 +37,58 @@ int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
return(state);
}
+int16_t LLCC68::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
+ // execute common part
+ int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage, useRegulatorLDO);
+ if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) {
+ // bit of a hack, but some LLCC68 chips report as "SX1261", try that
+ // for full discussion, see https://github.com/jgromes/RadioLib/issues/1329
+ chipType = RADIOLIB_SX1261_CHIP_TYPE;
+ state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage, useRegulatorLDO);
+ RADIOLIB_DEBUG_PRINTLN("LLCC68 version string not found, using SX1261 instead");
+ }
+ RADIOLIB_ASSERT(state);
+
+ // configure publicly accessible settings
+ state = setFrequency(freq);
+ RADIOLIB_ASSERT(state);
+
+ state = SX126x::fixPaClamping();
+ RADIOLIB_ASSERT(state);
+
+ state = setOutputPower(power);
+ RADIOLIB_ASSERT(state);
+
+ return(state);
+}
+
+int16_t LLCC68::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
+ // execute common part
+ int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO);
+ if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) {
+ // bit of a hack, but some LLCC68 chips report as "SX1261", try that
+ // for full discussion, see https://github.com/jgromes/RadioLib/issues/1329
+ chipType = RADIOLIB_SX1261_CHIP_TYPE;
+ state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO);
+ RADIOLIB_DEBUG_PRINTLN("LLCC68 version string not found, using SX1261 instead");
+ }
+ RADIOLIB_ASSERT(state);
+
+ // configure publicly accessible settings
+ state = setFrequency(freq);
+ RADIOLIB_ASSERT(state);
+
+ state = SX126x::fixPaClamping();
+ RADIOLIB_ASSERT(state);
+
+ state = setOutputPower(power);
+ RADIOLIB_ASSERT(state);
+
+ return(state);
+}
+
int16_t LLCC68::setBandwidth(float bw) {
- RADIOLIB_CHECK_RANGE(bw, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(bw, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
return(SX1262::setBandwidth(bw));
}
@@ -60,12 +110,26 @@ int16_t LLCC68::setSpreadingFactor(uint8_t sf) {
return(SX1262::setSpreadingFactor(sf));
}
-int16_t LLCC68::setDataRate(DataRate_t dr) {
- int16_t state = RADIOLIB_ERR_UNKNOWN;
+int16_t LLCC68::setDataRate(DataRate_t dr, ModemType_t modem) {
+ // get the current modem
+ ModemType_t currentModem;
+ int16_t state = this->getModem(¤tModem);
+ RADIOLIB_ASSERT(state);
- // select interpretation based on active modem
- uint8_t modem = this->getPacketType();
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ // switch over if the requested modem is different
+ if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
+ state = this->standby();
+ RADIOLIB_ASSERT(state);
+ state = this->setModem(modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ if(modem == RADIOLIB_MODEM_NONE) {
+ modem = currentModem;
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
// set the bit rate
state = this->setBitRate(dr.fsk.bitRate);
RADIOLIB_ASSERT(state);
@@ -73,7 +137,7 @@ int16_t LLCC68::setDataRate(DataRate_t dr) {
// set the frequency deviation
state = this->setFrequencyDeviation(dr.fsk.freqDev);
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
// set the spreading factor
state = this->setSpreadingFactor(dr.lora.spreadingFactor);
RADIOLIB_ASSERT(state);
@@ -89,20 +153,25 @@ int16_t LLCC68::setDataRate(DataRate_t dr) {
return(state);
}
-int16_t LLCC68::checkDataRate(DataRate_t dr) {
+int16_t LLCC68::checkDataRate(DataRate_t dr, ModemType_t modem) {
int16_t state = RADIOLIB_ERR_UNKNOWN;
- // select interpretation based on active modem
- uint8_t modem = this->getPacketType();
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
- RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ // retrieve modem if not supplied
+ if(modem == RADIOLIB_MODEM_NONE) {
+ state = this->getModem(&modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
return(RADIOLIB_ERR_NONE);
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
- RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
- uint8_t bw_div2 = dr.lora.bandwidth / 2 + 0.01;
+ } else if(modem == RADIOLIB_MODEM_LORA) {
+ RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ uint8_t bw_div2 = dr.lora.bandwidth / 2 + 0.01f;
switch (bw_div2) {
case 62: // 125.0:
RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
diff --git a/lib/RadioLib/src/modules/LLCC68/LLCC68.h b/lib/RadioLib/src/modules/LLCC68/LLCC68.h
index 7809c56..80470be 100644
--- a/lib/RadioLib/src/modules/LLCC68/LLCC68.h
+++ b/lib/RadioLib/src/modules/LLCC68/LLCC68.h
@@ -29,7 +29,8 @@ class LLCC68: public SX1262 {
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz.
\param sf LoRa spreading factor. Defaults to 9.
- \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7).
+ \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12).
\param pwr Output power in dBm. Defaults to 10 dBm.
\param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols.
@@ -39,8 +40,39 @@ class LLCC68: public SX1262 {
\param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 8, float tcxoVoltage = 0, bool useRegulatorLDO = false);
-
+ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 0, bool useRegulatorLDO = false) override;
+
+ /*!
+ \brief Initialization method for FSK modem.
+ \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+ \param br FSK bit rate in kbps. Defaults to 4.8 kbps.
+ \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz.
+ \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz.
+ \param power Output power in dBm. Defaults to 10 dBm.
+ \param preambleLength FSK preamble length in bits. Defaults to 16 bits.
+ \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 0 V (XTAL).
+ If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
+ To use XTAL, either set this value to 0, or set SX126x::XTAL to true.
+ \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
+ \returns \ref status_codes
+ */
+ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 0, bool useRegulatorLDO = false) override;
+
+ /*!
+ \brief Initialization method for LR-FHSS modem. This modem only supports transmission!
+ \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+ \param bw LR-FHSS bandwidth, one of RADIOLIB_SX126X_LR_FHSS_BW_* values. Defaults to 722.66 kHz.
+ \param cr LR-FHSS coding rate, one of RADIOLIB_SX126X_LR_FHSS_CR_* values. Defaults to 2/3 coding rate.
+ \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid.
+ \param power Output power in dBm. Defaults to 10 dBm.
+ \param tcxoVoltage TCXO reference voltage to be set. Defaults to 0 V (XTAL).
+ If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
+ To use XTAL, either set this value to 0, or set SX126x::XTAL to true.
+ \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
+ \returns \ref status_codes
+ */
+ int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 0, bool useRegulatorLDO = false) override;
+
// configuration methods
/*!
@@ -48,28 +80,32 @@ class LLCC68: public SX1262 {
\param bw LoRa bandwidth to be set in kHz.
\returns \ref status_codes
*/
- int16_t setBandwidth(float bw);
+ int16_t setBandwidth(float bw) override;
/*!
\brief Sets LoRa spreading factor. Allowed values range from 5 to 11, depending on currently set spreading factor.
\param sf LoRa spreading factor to be set.
\returns \ref status_codes
*/
- int16_t setSpreadingFactor(uint8_t sf);
+ int16_t setSpreadingFactor(uint8_t sf) override;
/*!
- \brief Set data.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \brief Set data rate.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t setDataRate(DataRate_t dr) override;
+ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Check the data rate can be configured by this module.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t checkDataRate(DataRate_t dr) override;
+ int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Set modem for the radio to use. Will perform full reset and reconfigure the radio
diff --git a/lib/RadioLib/src/modules/LR11x0/LR1110.cpp b/lib/RadioLib/src/modules/LR11x0/LR1110.cpp
index 1fbc696..20bf56c 100644
--- a/lib/RadioLib/src/modules/LR11x0/LR1110.cpp
+++ b/lib/RadioLib/src/modules/LR11x0/LR1110.cpp
@@ -51,7 +51,7 @@ int16_t LR1110::setFrequency(float freq) {
}
int16_t LR1110::setFrequency(float freq, bool skipCalibration, float band) {
- RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ RADIOLIB_CHECK_RANGE(freq, 150.0f, 960.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
// check if we need to recalibrate image
int16_t state;
@@ -71,7 +71,7 @@ int16_t LR1110::setOutputPower(int8_t power) {
return(this->setOutputPower(power, false));
}
-int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower) {
+int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampTimeUs) {
// check if power value is configurable
int16_t state = this->checkOutputPower(power, NULL, forceHighPower);
RADIOLIB_ASSERT(state);
@@ -81,12 +81,9 @@ int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower) {
// TODO how and when to configure OCP?
- // update PA config - always use VBAT for high-power PA
- state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07);
- RADIOLIB_ASSERT(state);
-
- // set output power
- state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U);
+ // update PA config and set output power - always use VBAT for high-power PA
+ // the value returned by LRxxxx class is offset by 3 for LR11x0
+ state = LR11x0::setOutputPower(power, (uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07, roundRampTime(rampTimeUs) - 0x03);
return(state);
}
@@ -122,6 +119,8 @@ int16_t LR1110::setModem(ModemType_t modem) {
case(ModemType_t::RADIOLIB_MODEM_LRFHSS): {
return(this->beginLRFHSS());
} break;
+ default:
+ return(RADIOLIB_ERR_WRONG_MODEM);
}
return(RADIOLIB_ERR_WRONG_MODEM);
}
diff --git a/lib/RadioLib/src/modules/LR11x0/LR1110.h b/lib/RadioLib/src/modules/LR11x0/LR1110.h
index b203885..d5943c5 100644
--- a/lib/RadioLib/src/modules/LR11x0/LR1110.h
+++ b/lib/RadioLib/src/modules/LR11x0/LR1110.h
@@ -27,7 +27,8 @@ class LR1110: public LR11x0 {
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz.
\param sf LoRa spreading factor. Defaults to 9.
- \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7).
+ \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12).
\param power Output power in dBm. Defaults to 10 dBm.
\param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols.
@@ -56,8 +57,8 @@ class LR1110: public LR11x0 {
/*!
\brief Initialization method for LR-FHSS modem.
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
- \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz.
- \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate.
+ \param bw LR-FHSS bandwidth, one of RADIOLIB_LRXXXX_LR_FHSS_BW_* values. Defaults to 722.66 kHz.
+ \param cr LR-FHSS coding rate, one of RADIOLIB_LRXXXX_LR_FHSS_CR_* values. Defaults to 2/3 coding rate.
\param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid.
\param power Output power in dBm. Defaults to 10 dBm.
\param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
@@ -65,7 +66,7 @@ class LR1110: public LR11x0 {
To use XTAL, either set this value to 0, or set LR11x0::XTAL to true.
\returns \ref status_codes
*/
- int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6);
+ int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LRXXXX_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LRXXXX_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6);
// configuration methods
@@ -103,9 +104,11 @@ class LR1110: public LR11x0 {
\param power Output power to be set in dBm.
\param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically
based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used.
+ \param rampTimeUs PA power ramping time in microseconds. Provided value is rounded up to the
+ nearest discrete ramp time supported by the PA. Defaults to 48 us.
\returns \ref status_codes
*/
- int16_t setOutputPower(int8_t power, bool forceHighPower);
+ int16_t setOutputPower(int8_t power, bool forceHighPower, uint32_t rampTimeUs = 48);
/*!
\brief Check if output power is configurable.
diff --git a/lib/RadioLib/src/modules/LR11x0/LR1120.cpp b/lib/RadioLib/src/modules/LR11x0/LR1120.cpp
index fb62782..aa68528 100644
--- a/lib/RadioLib/src/modules/LR11x0/LR1120.cpp
+++ b/lib/RadioLib/src/modules/LR11x0/LR1120.cpp
@@ -9,7 +9,7 @@ LR1120::LR1120(Module* mod) : LR11x0(mod) {
int16_t LR1120::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
// execute common part
- int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage, freq > 1000.0);
+ int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage, freq > 1000.0f);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
@@ -51,11 +51,13 @@ int16_t LR1120::setFrequency(float freq) {
}
int16_t LR1120::setFrequency(float freq, bool skipCalibration, float band) {
- if(!(((freq >= 150.0) && (freq <= 960.0)) ||
- ((freq >= 1900.0) && (freq <= 2200.0)) ||
- ((freq >= 2400.0) && (freq <= 2500.0)))) {
+ #if RADIOLIB_CHECK_PARAMS
+ if(!(((freq >= 150.0f) && (freq <= 960.0f)) ||
+ ((freq >= 1900.0f) && (freq <= 2200.0f)) ||
+ ((freq >= 2400.0f) && (freq <= 2500.0f)))) {
return(RADIOLIB_ERR_INVALID_FREQUENCY);
}
+ #endif
// check if we need to recalibrate image
int16_t state;
@@ -68,15 +70,17 @@ int16_t LR1120::setFrequency(float freq, bool skipCalibration, float band) {
state = LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f));
RADIOLIB_ASSERT(state);
this->freqMHz = freq;
- this->highFreq = (freq > 1000.0);
- return(RADIOLIB_ERR_NONE);
+ this->highFreq = (freq > 1000.0f);
+
+ // apply workaround for GFSK
+ return(workaroundGFSK());
}
int16_t LR1120::setOutputPower(int8_t power) {
return(this->setOutputPower(power, false));
}
-int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower) {
+int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampTimeUs) {
// check if power value is configurable
int16_t state = this->checkOutputPower(power, NULL, forceHighPower);
RADIOLIB_ASSERT(state);
@@ -93,12 +97,9 @@ int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower) {
// TODO how and when to configure OCP?
- // update PA config - always use VBAT for high-power PA
- state = setPaConfig(paSel, paSupply, 0x04, 0x07);
- RADIOLIB_ASSERT(state);
-
- // set output power
- state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U);
+ // update PA config and set output power - always use VBAT for high-power PA
+ // the value returned by LRxxxx class is offset by 3 for LR11x0
+ state = LR11x0::setOutputPower(power, paSel, paSupply, 0x04, 0x07, roundRampTime(rampTimeUs) - 0x03);
return(state);
}
@@ -142,8 +143,10 @@ int16_t LR1120::setModem(ModemType_t modem) {
case(ModemType_t::RADIOLIB_MODEM_LRFHSS): {
return(this->beginLRFHSS());
} break;
+ default:
+ return(RADIOLIB_ERR_WRONG_MODEM);
}
return(RADIOLIB_ERR_WRONG_MODEM);
}
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR1120.h b/lib/RadioLib/src/modules/LR11x0/LR1120.h
index 3c532eb..09d9497 100644
--- a/lib/RadioLib/src/modules/LR11x0/LR1120.h
+++ b/lib/RadioLib/src/modules/LR11x0/LR1120.h
@@ -27,7 +27,8 @@ class LR1120: public LR11x0 {
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz.
\param sf LoRa spreading factor. Defaults to 9.
- \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7).
+ \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12).
\param power Output power in dBm. Defaults to 10 dBm.
\param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols.
@@ -56,8 +57,8 @@ class LR1120: public LR11x0 {
/*!
\brief Initialization method for LR-FHSS modem.
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
- \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz.
- \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate.
+ \param bw LR-FHSS bandwidth, one of RADIOLIB_LRXXXX_LR_FHSS_BW_* values. Defaults to 722.66 kHz.
+ \param cr LR-FHSS coding rate, one of RADIOLIB_LRXXXX_LR_FHSS_CR_* values. Defaults to 2/3 coding rate.
\param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid.
\param power Output power in dBm. Defaults to 10 dBm.
\param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
@@ -65,7 +66,7 @@ class LR1120: public LR11x0 {
To use XTAL, either set this value to 0, or set LR11x0::XTAL to true.
\returns \ref status_codes
*/
- int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6);
+ int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LRXXXX_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LRXXXX_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6);
// configuration methods
@@ -112,9 +113,11 @@ class LR1120: public LR11x0 {
If set to false, PA will be determined automatically based on configured output power and frequency,
preferring the low-power PA but always using high-frequency PA in 2.4 GHz band.
Ignored when operating in 2.4 GHz band.
+ \param rampTimeUs PA power ramping time in microseconds. Provided value is rounded up to the
+ nearest discrete ramp time supported by the PA. Defaults to 48 us.
\returns \ref status_codes
*/
- int16_t setOutputPower(int8_t power, bool forceHighPower);
+ int16_t setOutputPower(int8_t power, bool forceHighPower, uint32_t rampTimeUs = 48);
/*!
\brief Check if output power is configurable.
diff --git a/lib/RadioLib/src/modules/LR11x0/LR11x0.cpp b/lib/RadioLib/src/modules/LR11x0/LR11x0.cpp
index f039bc4..c8f0dc0 100644
--- a/lib/RadioLib/src/modules/LR11x0/LR11x0.cpp
+++ b/lib/RadioLib/src/modules/LR11x0/LR11x0.cpp
@@ -1,16 +1,13 @@
#include "LR11x0.h"
-#include "../../utils/CRC.h"
-#include "../../utils/Cryptography.h"
-
-#include
#include
+#include
#if !RADIOLIB_EXCLUDE_LR11X0
-LR11x0::LR11x0(Module* mod) : PhysicalLayer(RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE, RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
- this->mod = mod;
- this->XTAL = false;
+LR11x0::LR11x0(Module* mod) : LRxxxx(mod) {
+ this->freqStep = RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE;
+ this->maxPacketLength = RADIOLIB_LR11X0_MAX_PACKET_LENGTH;
this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR11X0_IRQ_TX_DONE;
this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR11X0_IRQ_RX_DONE;
this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED;
@@ -104,7 +101,7 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoV
RADIOLIB_ASSERT(state);
// set grid spacing
- this->lrFhssGrid = narrowGrid ? RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC;
+ this->lrFhssGrid = narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC;
// configure publicly accessible settings
state = setLrFhssConfig(bw, cr);
@@ -118,7 +115,7 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoV
RADIOLIB_ASSERT(state);
// set fixed configuration
- return(setModulationParamsLrFhss(RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0));
+ return(setModulationParamsLrFhss(RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0));
}
int16_t LR11x0::beginGNSS(uint8_t constellations, float tcxoVoltage) {
@@ -151,35 +148,23 @@ int16_t LR11x0::beginGNSS(uint8_t constellations, float tcxoVoltage) {
return(RADIOLIB_ERR_NONE);
}
-int16_t LR11x0::reset() {
- // run the reset sequence
- this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput);
- this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow);
- this->mod->hal->delay(10);
- this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh);
-
- // the typical transition duration should be 273 ms
- this->mod->hal->delay(300);
-
- // wait for BUSY to go low
- RadioLibTime_t start = this->mod->hal->millis();
- while(this->mod->hal->digitalRead(this->mod->getGpio())) {
- this->mod->hal->yield();
- if(this->mod->hal->millis() - start >= 3000) {
- RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after reset!");
- return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
- }
- }
-
- return(RADIOLIB_ERR_NONE);
-}
-
int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// check packet length
+ if (this->codingRate > RADIOLIB_LR11X0_LORA_CR_4_8_SHORT) {
+ // Long Interleaver needs at least 8 bytes
+ if(len < 8) {
+ return(RADIOLIB_ERR_PACKET_TOO_SHORT);
+ }
+
+ // Long Interleaver supports up to 253 bytes if CRC is enabled
+ if (this->crcTypeLoRa == RADIOLIB_LRXXXX_LORA_CRC_ENABLED && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 2)) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+ }
if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
@@ -216,52 +201,42 @@ int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) {
return(RADIOLIB_ERR_TX_TIMEOUT);
}
}
- RadioLibTime_t elapsed = this->mod->hal->micros() - start;
-
- // update data rate
- this->dataRateMeasured = (len*8.0)/((float)elapsed/1000000.0);
return(finishTransmit());
}
-int16_t LR11x0::receive(uint8_t* data, size_t len) {
+int16_t LR11x0::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
- RadioLibTime_t timeout = 0;
+ // calculate timeout based on the configured modem
+ RadioLibTime_t timeoutInternal = timeout;
+ if(!timeoutInternal) {
+ // get currently active modem
+ uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if((modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) || (modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
+ // calculate timeout (500 % of expected time-one-air)
+ size_t maxLen = len;
+ if(len == 0) { maxLen = RADIOLIB_LR11X0_MAX_PACKET_LENGTH; }
+ timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
+
+ } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
+ // this modem cannot receive
+ return(RADIOLIB_ERR_WRONG_MODEM);
- // get currently active modem
- uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
- state = getPacketType(&modem);
- RADIOLIB_ASSERT(state);
- if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
- // calculate timeout (100 LoRa symbols, the default for SX127x series)
- float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
- timeout = (RadioLibTime_t)(symbolLength * 100.0);
-
- } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
- // calculate timeout (500 % of expected time-one-air)
- size_t maxLen = len;
- if(len == 0) {
- maxLen = 0xFF;
+ } else {
+ return(RADIOLIB_ERR_UNKNOWN);
+
}
- float brBps = ((float)(RADIOLIB_LR11X0_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate;
- timeout = (RadioLibTime_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0);
-
- } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
- // this modem cannot receive
- return(RADIOLIB_ERR_WRONG_MODEM);
-
- } else {
- return(RADIOLIB_ERR_UNKNOWN);
-
}
- RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
// start reception
- uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0) / 30.52);
+ uint32_t timeoutValue = (uint32_t)(((float)timeoutInternal * 1000.0f) / 30.52f);
state = startReceive(timeoutValue);
RADIOLIB_ASSERT(state);
@@ -271,7 +246,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) {
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
// safety check, the timeout should be done by the radio
- if(this->mod->hal->millis() - start > timeout) {
+ if(this->mod->hal->millis() - start > timeoutInternal) {
softTimeout = true;
break;
}
@@ -285,9 +260,8 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) {
}
// check whether this was a timeout or not
- if((getIrqStatus() & RADIOLIB_LR11X0_IRQ_TIMEOUT) || softTimeout) {
- standby();
- clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
+ if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
+ (void)finishReceive();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
@@ -351,6 +325,10 @@ int16_t LR11x0::standby() {
return(LR11x0::standby(RADIOLIB_LR11X0_STANDBY_RC));
}
+int16_t LR11x0::standby(uint8_t mode) {
+ return(LR11x0::standby(mode, true));
+}
+
int16_t LR11x0::standby(uint8_t mode, bool wakeup) {
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_IDLE);
@@ -382,7 +360,8 @@ int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) {
buff[0] |= RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED;
}
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_SLEEP, true, buff, sizeof(buff));
+ // in sleep, the busy line will remain high, so we have to use this method to disable waiting for it to go low
+ int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_SET_SLEEP, buff, sizeof(buff), false, false);
// wait for the module to safely enter sleep mode
this->mod->hal->delay(1);
@@ -390,100 +369,9 @@ int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) {
return(state);
}
-void LR11x0::setIrqAction(void (*func)(void)) {
- this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
-}
-
-void LR11x0::clearIrqAction() {
- this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
-}
-
-void LR11x0::setPacketReceivedAction(void (*func)(void)) {
- this->setIrqAction(func);
-}
-
-void LR11x0::clearPacketReceivedAction() {
- this->clearIrqAction();
-}
-
-void LR11x0::setPacketSentAction(void (*func)(void)) {
- this->setIrqAction(func);
-}
-
-void LR11x0::clearPacketSentAction() {
- this->clearIrqAction();
-}
-
-int16_t LR11x0::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
- // suppress unused variable warning
- (void)addr;
-
- // check packet length
- if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
- return(RADIOLIB_ERR_PACKET_TOO_LONG);
- }
-
- // maximum packet length is decreased by 1 when address filtering is active
- if((this->addrComp != RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED) && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 1)) {
- return(RADIOLIB_ERR_PACKET_TOO_LONG);
- }
-
- // set packet Length
- int16_t state = RADIOLIB_ERR_NONE;
- uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
- state = getPacketType(&modem);
- RADIOLIB_ASSERT(state);
- if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
- state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcTypeLoRa, this->invertIQEnabled);
-
- } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
- state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening);
-
- } else if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
- return(RADIOLIB_ERR_UNKNOWN);
-
- }
- RADIOLIB_ASSERT(state);
-
- // set DIO mapping
- state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT);
- RADIOLIB_ASSERT(state);
-
- if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
- // in LR-FHSS mode, the packet is built by the device
- // TODO add configurable device offset
- state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, const_cast(data), len);
- RADIOLIB_ASSERT(state);
-
- } else {
- // write packet to buffer
- state = writeBuffer8(const_cast(data), len);
- RADIOLIB_ASSERT(state);
-
- }
-
- // clear interrupt flags
- state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
- RADIOLIB_ASSERT(state);
-
- // set RF switch (if present)
- this->mod->setRfSwitchState(Module::MODE_TX);
-
- // start transmission
- state = setTx(RADIOLIB_LR11X0_TX_TIMEOUT_NONE);
- RADIOLIB_ASSERT(state);
-
- // wait for BUSY to go low (= PA ramp up done)
- while(this->mod->hal->digitalRead(this->mod->getGpio())) {
- this->mod->hal->yield();
- }
-
- return(state);
-}
-
int16_t LR11x0::finishTransmit() {
// clear interrupt flags
- clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
+ clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
// set mode to standby to disable transmitter/RF switch
return(standby());
@@ -493,56 +381,6 @@ int16_t LR11x0::startReceive() {
return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
}
-int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
- (void)len;
-
- // check active modem
- int16_t state = RADIOLIB_ERR_NONE;
- uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
- state = getPacketType(&modem);
- RADIOLIB_ASSERT(state);
- if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) &&
- (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // set DIO mapping
- uint32_t irq = irqMask;
- if(timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) {
- irq |= (1UL << RADIOLIB_IRQ_TIMEOUT);
- }
- state = setDioIrqParams(getIrqMapped(irqFlags & irq));
- RADIOLIB_ASSERT(state);
-
- // clear interrupt flags
- state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
- RADIOLIB_ASSERT(state);
-
- // set implicit mode and expected len if applicable
- if((this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) {
- state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled);
- RADIOLIB_ASSERT(state);
- }
-
- // set RF switch (if present)
- this->mod->setRfSwitchState(Module::MODE_RX);
-
- // set mode to receive
- state = setRx(timeout);
-
- return(state);
-}
-
-uint32_t LR11x0::getIrqStatus() {
- // there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes
- uint8_t buff[6] = { 0 };
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
- mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
- uint32_t irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5];
- return(irq);
-}
-
int16_t LR11x0::readData(uint8_t* data, size_t len) {
// check active modem
int16_t state = RADIOLIB_ERR_NONE;
@@ -580,7 +418,7 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) {
RADIOLIB_ASSERT(state);
// clear interrupt flags
- state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
+ state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
// check if CRC failed - this is done after reading data to give user the option to keep them
RADIOLIB_ASSERT(crcState);
@@ -588,6 +426,15 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) {
return(state);
}
+int16_t LR11x0::finishReceive() {
+ // set mode to standby to disable RF switch
+ int16_t state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ return(clearIrqState(RADIOLIB_LR11X0_IRQ_ALL));
+}
+
int16_t LR11x0::startChannelScan() {
ChannelScanConfig_t cfg = {
.cad = {
@@ -626,7 +473,7 @@ int16_t LR11x0::startChannelScan(const ChannelScanConfig_t &config) {
RADIOLIB_ASSERT(state);
// clear interrupt flags
- state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
+ state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
RADIOLIB_ASSERT(state);
// set mode to CAD
@@ -667,22 +514,22 @@ int16_t LR11x0::setBandwidth(float bw, bool high) {
// ensure byte conversion doesn't overflow
if (high) {
- RADIOLIB_CHECK_RANGE(bw, 203.125, 815.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(bw, 203.125f, 815.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
- if(fabsf(bw - 203.125) <= 0.001) {
+ if(fabsf(bw - 203.125f) <= 0.001f) {
this->bandwidth = RADIOLIB_LR11X0_LORA_BW_203_125;
- } else if(fabsf(bw - 406.25) <= 0.001) {
+ } else if(fabsf(bw - 406.25f) <= 0.001f) {
this->bandwidth = RADIOLIB_LR11X0_LORA_BW_406_25;
- } else if(fabsf(bw - 812.5) <= 0.001) {
+ } else if(fabsf(bw - 812.5f) <= 0.001f) {
this->bandwidth = RADIOLIB_LR11X0_LORA_BW_812_50;
} else {
return(RADIOLIB_ERR_INVALID_BANDWIDTH);
}
} else {
- RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(bw, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
// check allowed bandwidth values
- uint8_t bw_div2 = bw / 2 + 0.01;
+ uint8_t bw_div2 = bw / 2 + 0.01f;
switch (bw_div2) {
case 31: // 62.5:
this->bandwidth = RADIOLIB_LR11X0_LORA_BW_62_5;
@@ -736,10 +583,13 @@ int16_t LR11x0::setCodingRate(uint8_t cr, bool longInterleave) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
- RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
if(longInterleave) {
switch(cr) {
+ case 4:
+ this->codingRate = 0;
+ break;
case 5:
case 6:
this->codingRate = cr;
@@ -773,7 +623,7 @@ int16_t LR11x0::setSyncWord(uint8_t syncWord) {
}
int16_t LR11x0::setBitRate(float br) {
- RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
// check active modem
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
@@ -785,8 +635,12 @@ int16_t LR11x0::setBitRate(float br) {
// set bit rate value
// TODO implement fractional bit rate configuration
- this->bitRate = br * 1000.0;
- return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
+ this->bitRate = br * 1000.0f;
+ state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
+ RADIOLIB_ASSERT(state);
+
+ // apply workaround
+ return(workaroundGFSK());
}
int16_t LR11x0::setFrequencyDeviation(float freqDev) {
@@ -800,13 +654,17 @@ int16_t LR11x0::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
- if(freqDev < 0.0) {
- newFreqDev = 0.6;
+ if(freqDev < 0.0f) {
+ newFreqDev = 0.6f;
}
- RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
- this->frequencyDev = newFreqDev * 1000.0;
- return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
+ RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ this->frequencyDev = newFreqDev * 1000.0f;
+ state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
+ RADIOLIB_ASSERT(state);
+
+ // apply workaround
+ return(workaroundGFSK());
}
int16_t LR11x0::setRxBandwidth(float rxBw) {
@@ -823,55 +681,39 @@ int16_t LR11x0::setRxBandwidth(float rxBw) {
return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
}*/
- // check allowed receiver bandwidth values
- if(fabsf(rxBw - 4.8) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_4_8;
- } else if(fabsf(rxBw - 5.8) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_5_8;
- } else if(fabsf(rxBw - 7.3) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_7_3;
- } else if(fabsf(rxBw - 9.7) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_9_7;
- } else if(fabsf(rxBw - 11.7) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_11_7;
- } else if(fabsf(rxBw - 14.6) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_14_6;
- } else if(fabsf(rxBw - 19.5) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_19_5;
- } else if(fabsf(rxBw - 23.4) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_23_4;
- } else if(fabsf(rxBw - 29.3) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_29_3;
- } else if(fabsf(rxBw - 39.0) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_39_0;
- } else if(fabsf(rxBw - 46.9) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_46_9;
- } else if(fabsf(rxBw - 58.6) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_58_6;
- } else if(fabsf(rxBw - 78.2) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_78_2;
- } else if(fabsf(rxBw - 93.8) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_93_8;
- } else if(fabsf(rxBw - 117.3) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_117_3;
- } else if(fabsf(rxBw - 156.2) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_156_2;
- } else if(fabsf(rxBw - 187.2) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_187_2;
- } else if(fabsf(rxBw - 234.3) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_234_3;
- } else if(fabsf(rxBw - 312.0) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_312_0;
- } else if(fabsf(rxBw - 373.6) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_373_6;
- } else if(fabsf(rxBw - 467.0) <= 0.001) {
- this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_467_0;
- } else {
- return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
- }
+ const uint8_t rxBwLut[] = {
+ RADIOLIB_LR11X0_GFSK_RX_BW_4_8,
+ RADIOLIB_LR11X0_GFSK_RX_BW_5_8,
+ RADIOLIB_LR11X0_GFSK_RX_BW_7_3,
+ RADIOLIB_LR11X0_GFSK_RX_BW_9_7,
+ RADIOLIB_LR11X0_GFSK_RX_BW_11_7,
+ RADIOLIB_LR11X0_GFSK_RX_BW_14_6,
+ RADIOLIB_LR11X0_GFSK_RX_BW_19_5,
+ RADIOLIB_LR11X0_GFSK_RX_BW_23_4,
+ RADIOLIB_LR11X0_GFSK_RX_BW_29_3,
+ RADIOLIB_LR11X0_GFSK_RX_BW_39_0,
+ RADIOLIB_LR11X0_GFSK_RX_BW_46_9,
+ RADIOLIB_LR11X0_GFSK_RX_BW_58_6,
+ RADIOLIB_LR11X0_GFSK_RX_BW_78_2,
+ RADIOLIB_LR11X0_GFSK_RX_BW_93_8,
+ RADIOLIB_LR11X0_GFSK_RX_BW_117_3,
+ RADIOLIB_LR11X0_GFSK_RX_BW_156_2,
+ RADIOLIB_LR11X0_GFSK_RX_BW_187_2,
+ RADIOLIB_LR11X0_GFSK_RX_BW_234_3,
+ RADIOLIB_LR11X0_GFSK_RX_BW_312_0,
+ RADIOLIB_LR11X0_GFSK_RX_BW_373_6,
+ RADIOLIB_LR11X0_GFSK_RX_BW_467_0,
+ };
+
+ state = findRxBw(rxBw, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), 467.0f, &this->rxBandwidth);
+ RADIOLIB_ASSERT(state);
// update modulation parameters
- return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
+ state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
+ RADIOLIB_ASSERT(state);
+
+ // apply workaround
+ return(workaroundGFSK());
}
int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) {
@@ -915,27 +757,6 @@ int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
-int16_t LR11x0::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
- if((!syncWord) || (!bitsLen) || (bitsLen > 8*RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)) {
- return(RADIOLIB_ERR_INVALID_SYNC_WORD);
- }
-
- // check active modem
- uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
- int16_t state = getPacketType(&type);
- RADIOLIB_ASSERT(state);
- if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- uint8_t bytesLen = bitsLen / 8;
- if ((bitsLen % 8) != 0) {
- bytesLen++;
- }
-
- return(setSyncWord(syncWord, bytesLen));
-}
-
int16_t LR11x0::setNodeAddress(uint8_t nodeAddr) {
// check active modem
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
@@ -982,7 +803,7 @@ int16_t LR11x0::disableAddressFiltering() {
return(RADIOLIB_ERR_WRONG_MODEM);
}
- // disable address filterin
+ // disable address filtering
this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED;
return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
}
@@ -1058,13 +879,26 @@ int16_t LR11x0::setWhitening(bool enabled, uint16_t initial) {
return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
}
-int16_t LR11x0::setDataRate(DataRate_t dr) {
- // select interpretation based on active modem
- uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
- int16_t state = getPacketType(&type);
+int16_t LR11x0::setDataRate(DataRate_t dr, ModemType_t modem) {
+ // get the current modem
+ ModemType_t currentModem;
+ int16_t state = this->getModem(¤tModem);
RADIOLIB_ASSERT(state);
+
+ // switch over if the requested modem is different
+ if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
+ state = this->standby();
+ RADIOLIB_ASSERT(state);
+ state = this->setModem(modem);
+ RADIOLIB_ASSERT(state);
+ }
- if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
+ if(modem == RADIOLIB_MODEM_NONE) {
+ modem = currentModem;
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
// set the bit rate
state = this->setBitRate(dr.fsk.bitRate);
RADIOLIB_ASSERT(state);
@@ -1072,7 +906,7 @@ int16_t LR11x0::setDataRate(DataRate_t dr) {
// set the frequency deviation
state = this->setFrequencyDeviation(dr.fsk.freqDev);
- } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
// set the spreading factor
state = this->setSpreadingFactor(dr.lora.spreadingFactor);
RADIOLIB_ASSERT(state);
@@ -1084,39 +918,43 @@ int16_t LR11x0::setDataRate(DataRate_t dr) {
// set the coding rate
state = this->setCodingRate(dr.lora.codingRate);
- } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
+ } else if(modem == RADIOLIB_MODEM_LRFHSS) {
// set the basic config
state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
RADIOLIB_ASSERT(state);
// set hopping grid
- this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC;
+ this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC;
}
return(state);
}
-int16_t LR11x0::checkDataRate(DataRate_t dr) {
- // select interpretation based on active modem
- uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
- int16_t state = getPacketType(&type);
- RADIOLIB_ASSERT(state);
+int16_t LR11x0::checkDataRate(DataRate_t dr, ModemType_t modem) {
+ int16_t state = RADIOLIB_ERR_UNKNOWN;
- if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
- RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
- RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ // retrieve modem if not supplied
+ if(modem == RADIOLIB_MODEM_NONE) {
+ state = this->getModem(&modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
return(RADIOLIB_ERR_NONE);
- } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
- RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
- RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
return(RADIOLIB_ERR_NONE);
}
- return(RADIOLIB_ERR_UNKNOWN);
+ return(state);
}
int16_t LR11x0::setPreambleLength(size_t preambleLength) {
@@ -1129,6 +967,7 @@ int16_t LR11x0::setPreambleLength(size_t preambleLength) {
return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
} else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
this->preambleLengthGFSK = preambleLength;
+ //! \TODO: [LR11x0] this can probably be simplified with a simple calculation
this->preambleDetLength = preambleLength >= 32 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS :
preambleLength >= 24 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS :
preambleLength >= 16 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS :
@@ -1158,29 +997,29 @@ int16_t LR11x0::setTCXO(float voltage, uint32_t delay) {
}
// check 0 V disable
- if(fabsf(voltage - 0.0) <= 0.001) {
+ if(fabsf(voltage - 0.0f) <= 0.001f) {
setTcxoMode(0, 0);
return(reset());
}
// check allowed voltage values
uint8_t tune = 0;
- if(fabsf(voltage - 1.6) <= 0.001) {
- tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6;
- } else if(fabsf(voltage - 1.7) <= 0.001) {
- tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7;
- } else if(fabsf(voltage - 1.8) <= 0.001) {
- tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8;
- } else if(fabsf(voltage - 2.2) <= 0.001) {
- tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2;
- } else if(fabsf(voltage - 2.4) <= 0.001) {
- tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4;
- } else if(fabsf(voltage - 2.7) <= 0.001) {
- tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7;
- } else if(fabsf(voltage - 3.0) <= 0.001) {
- tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0;
- } else if(fabsf(voltage - 3.3) <= 0.001) {
- tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3;
+ if(fabsf(voltage - 1.6f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_6;
+ } else if(fabsf(voltage - 1.7f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_7;
+ } else if(fabsf(voltage - 1.8f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_8;
+ } else if(fabsf(voltage - 2.2f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_2;
+ } else if(fabsf(voltage - 2.4f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_4;
+ } else if(fabsf(voltage - 2.7f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_7;
+ } else if(fabsf(voltage - 3.0f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0;
+ } else if(fabsf(voltage - 3.3f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3;
} else {
return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
}
@@ -1202,7 +1041,7 @@ int16_t LR11x0::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool
RADIOLIB_ASSERT(state);
if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
// LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
- this->crcTypeLoRa = len > 0 ? RADIOLIB_LR11X0_LORA_CRC_ENABLED : RADIOLIB_LR11X0_LORA_CRC_DISABLED;
+ this->crcTypeLoRa = len > 0 ? RADIOLIB_LRXXXX_LORA_CRC_ENABLED : RADIOLIB_LRXXXX_LORA_CRC_DISABLED;
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled);
} else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
@@ -1229,6 +1068,7 @@ int16_t LR11x0::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool
return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
}
+ this->crcLenGFSK = len;
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
RADIOLIB_ASSERT(state);
@@ -1269,6 +1109,22 @@ float LR11x0::getRSSI() {
return(val);
}
+float LR11x0::getRSSI(bool packet, bool skipReceive) {
+ float val = 0;
+
+ // check if RSSI of packet is requested
+ if (packet) {
+ val = getRSSI();
+ } else {
+ if(!skipReceive) { (void)startReceive(); }
+ int16_t state = getRssiInst(&val);
+ if(!skipReceive) { (void)standby(); }
+ if(state != RADIOLIB_ERR_NONE) { return(0); }
+ }
+
+ return(val);
+}
+
float LR11x0::getSNR() {
float val = 0;
@@ -1297,117 +1153,21 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) {
// in implicit mode, return the cached value
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
(void)getPacketType(&type);
- if((type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT)) {
+ if((type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT)) {
return(this->implicitLen);
}
uint8_t len = 0;
- (void)getRxBufferStatus(&len, offset);
+ int state = getRxBufferStatus(&len, offset);
+ RADIOLIB_DEBUG_BASIC_PRINT("getRxBufferStatus state = %d\n", state);
+ (void)state;
return((size_t)len);
}
RadioLibTime_t LR11x0::getTimeOnAir(size_t len) {
- // check active modem
- uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
- (void)getPacketType(&type);
- if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
- // calculate number of symbols
- float N_symbol = 0;
- if(this->codingRate <= RADIOLIB_LR11X0_LORA_CR_4_8_SHORT) {
- // legacy coding rate - nice and simple
-
- // get SF coefficients
- float coeff1 = 0;
- int16_t coeff2 = 0;
- int16_t coeff3 = 0;
- if(this->spreadingFactor < 7) {
- // SF5, SF6
- coeff1 = 6.25;
- coeff2 = 4*this->spreadingFactor;
- coeff3 = 4*this->spreadingFactor;
- } else if(this->spreadingFactor < 11) {
- // SF7. SF8, SF9, SF10
- coeff1 = 4.25;
- coeff2 = 4*this->spreadingFactor + 8;
- coeff3 = 4*this->spreadingFactor;
- } else {
- // SF11, SF12
- coeff1 = 4.25;
- coeff2 = 4*this->spreadingFactor + 8;
- coeff3 = 4*(this->spreadingFactor - 2);
- }
-
- // get CRC length
- int16_t N_bitCRC = 16;
- if(this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_DISABLED) {
- N_bitCRC = 0;
- }
-
- // get header length
- int16_t N_symbolHeader = 20;
- if(this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) {
- N_symbolHeader = 0;
- }
-
- // calculate number of LoRa preamble symbols
- uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4));
-
- // calculate the number of symbols
- N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4);
-
- } else {
- // long interleaving - abandon hope all ye who enter here
- /// \todo implement this mess - SX1280 datasheet v3.0 section 7.4.4.2
-
- }
-
- // get time-on-air in us
- return(((uint32_t(1) << this->spreadingFactor) / this->bandwidthKhz) * N_symbol * 1000.0);
-
- } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
- return(((uint32_t)len * 8 * 1000000UL) / this->bitRate);
-
- } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
- // calculate the number of bits based on coding rate
- uint16_t N_bits;
- switch(this->lrFhssCr) {
- case RADIOLIB_LR11X0_LR_FHSS_CR_5_6:
- N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4?
- break;
- case RADIOLIB_LR11X0_LR_FHSS_CR_2_3:
- N_bits = (len * 3) / 2;
- break;
- case RADIOLIB_LR11X0_LR_FHSS_CR_1_2:
- N_bits = len * 2;
- break;
- case RADIOLIB_LR11X0_LR_FHSS_CR_1_3:
- N_bits = len * 3;
- break;
- default:
- return(RADIOLIB_ERR_INVALID_CODING_RATE);
- }
-
- // calculate number of bits when accounting for unaligned last block
- uint16_t N_payBits = (N_bits / RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS) * RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS;
- uint16_t N_lastBlockBits = N_bits % RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS;
- if(N_lastBlockBits) {
- N_payBits += N_lastBlockBits + 2;
- }
-
- // add header bits
- uint16_t N_totalBits = (RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount) + N_payBits;
- return(((uint32_t)N_totalBits * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE);
-
- }
-
- return(0);
-}
-
-RadioLibTime_t LR11x0::calculateRxTimeout(RadioLibTime_t timeoutUs) {
- // the timeout value is given in units of 30.52 microseconds
- // the calling function should provide some extra width, as this number of units is truncated to integer
- RadioLibTime_t timeout = timeoutUs / 30.52;
- return(timeout);
+ ModemType_t modem;
+ getModem(&modem);
+ return(LRxxxx::getTimeOnAir(len, modem));
}
uint32_t LR11x0::getIrqFlags() {
@@ -1419,7 +1179,7 @@ int16_t LR11x0::setIrqFlags(uint32_t irq) {
}
int16_t LR11x0::clearIrqFlags(uint32_t irq) {
- return(this->clearIrq(irq));
+ return(this->clearIrqState(irq));
}
uint8_t LR11x0::randomByte() {
@@ -1429,15 +1189,11 @@ uint8_t LR11x0::randomByte() {
}
int16_t LR11x0::implicitHeader(size_t len) {
- return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT, len));
+ return(this->setHeaderType(RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT, len));
}
int16_t LR11x0::explicitHeader() {
- return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT));
-}
-
-float LR11x0::getDataRate() const {
- return(this->dataRateMeasured);
+ return(this->setHeaderType(RADIOLIB_LRXXXX_LORA_HEADER_EXPLICIT));
}
int16_t LR11x0::setRegulatorLDO() {
@@ -1453,6 +1209,16 @@ int16_t LR11x0::setRxBoostedGainMode(bool en) {
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED, true, buff, sizeof(buff)));
}
+int16_t LR11x0::setOutputPower(int8_t power, uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel, uint8_t rampTime) {
+ // set PA config
+ int16_t state = setPaConfig(paSel, regPaSupply, paDutyCycle, paHpSel);
+ RADIOLIB_ASSERT(state);
+
+ // set output power
+ state = setTxParams(power, rampTime);
+ return(state);
+}
+
void LR11x0::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
// find which pins are used
uint8_t enable = 0;
@@ -1464,7 +1230,7 @@ void LR11x0::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS],
// only keep DIO pins, there may be some GPIOs in the switch tabke
if(pins[i] & RFSWITCH_PIN_FLAG) {
- enable |= 1UL << RADIOLIB_LR11X0_DIOx_VAL(pins[i]);
+ enable |= 1UL << RADIOLIB_LRXXXX_DIOx_VAL(pins[i]);
}
}
@@ -1531,9 +1297,9 @@ int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16
}
// check and cache all parameters
- RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LR11X0_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LR11X0_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE);
+ RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE);
this->lrFhssCr = cr;
- RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LR11X0_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LR11X0_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH);
this->lrFhssBw = bw;
RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE);
this->lrFhssHdrCount = hdrCount;
@@ -1542,169 +1308,6 @@ int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16
return(RADIOLIB_ERR_NONE);
}
-int16_t LR11x0::startWifiScan(char wifiType, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) {
- // LR1121 cannot do WiFi scanning
- if(this->chipType == RADIOLIB_LR11X0_DEVICE_LR1121) {
- return(RADIOLIB_ERR_UNSUPPORTED);
- }
-
- uint8_t type;
- switch(wifiType) {
- case('b'):
- type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_B;
- break;
- case('g'):
- type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_G;
- break;
- case('n'):
- type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_N;
- break;
- case('*'):
- type = RADIOLIB_LR11X0_WIFI_SCAN_ALL;
- break;
- default:
- return(RADIOLIB_ERR_INVALID_WIFI_TYPE);
- }
-
- // go to standby
- int16_t state = standby();
- RADIOLIB_ASSERT(state);
-
- // reset cumulative timings
- state = wifiResetCumulTimings();
- RADIOLIB_ASSERT(state);
-
- // set DIO mapping
- state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_WIFI_DONE);
- RADIOLIB_ASSERT(state);
-
- // start scan with the maximum number of results and abort on timeout
- this->wifiScanMode = mode;
- state = wifiScan(type, chanMask, this->wifiScanMode, RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS, numScans, timeout, RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED);
- return(state);
-}
-
-void LR11x0::setWiFiScanAction(void (*func)(void)) {
- this->setIrqAction(func);
-}
-
-void LR11x0::clearWiFiScanAction() {
- this->clearIrqAction();
-}
-
-int16_t LR11x0::getWifiScanResultsCount(uint8_t* count) {
- // clear IRQ first, as this is likely to be called right after scan has finished
- int16_t state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
- RADIOLIB_ASSERT(state);
-
- uint8_t buff[1] = { 0 };
- state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS, false, buff, sizeof(buff));
-
- // pass the replies
- if(count) { *count = buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, bool brief) {
- RADIOLIB_ASSERT_PTR(result);
-
- // read a single result
- uint8_t format = brief ? RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC : RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE;
- uint8_t raw[RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN] = { 0 };
- int16_t state = wifiReadResults(index, 1, format, raw);
- RADIOLIB_ASSERT(state);
-
- // parse the information
- switch(raw[0] & 0x03) {
- case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_B):
- result->type = 'b';
- break;
- case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_G):
- result->type = 'g';
- break;
- case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_N):
- result->type = 'n';
- break;
- }
- result->dataRateId = (raw[0] & 0xFC) >> 2;
- result->channelFreq = 2407 + (raw[1] & 0x0F)*5;
- result->origin = (raw[1] & 0x30) >> 4;
- result->ap = (raw[1] & 0x40) != 0;
- result->rssi = (float)raw[2] / -2.0f;;
- memcpy(result->mac, &raw[3], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
-
- if(!brief) {
- if(this->wifiScanMode == RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON) {
- LR11x0WifiResultExtended_t* resultExtended = reinterpret_cast(result);
- resultExtended->rate = raw[3];
- resultExtended->service = (((uint16_t)raw[4] << 8) | ((uint16_t)raw[5]));
- resultExtended->length = (((uint16_t)raw[6] << 8) | ((uint16_t)raw[7]));
- resultExtended->frameType = raw[9] & 0x03;
- resultExtended->frameSubType = (raw[9] & 0x3C) >> 2;
- resultExtended->toDistributionSystem = (raw[9] & 0x40) != 0;
- resultExtended->fromDistributionSystem = (raw[9] & 0x80) != 0;
- memcpy(resultExtended->mac0, &raw[10], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
- memcpy(resultExtended->mac, &raw[16], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
- memcpy(resultExtended->mac2, &raw[22], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
- resultExtended->timestamp = (((uint64_t)raw[28] << 56) | ((uint64_t)raw[29] << 48)) |
- (((uint64_t)raw[30] << 40) | ((uint64_t)raw[31] << 32)) |
- (((uint64_t)raw[32] << 24) | ((uint64_t)raw[33] << 16)) |
- (((uint64_t)raw[34] << 8) | (uint64_t)raw[35]);
- resultExtended->periodBeacon = (((uint16_t)raw[36] << 8) | ((uint16_t)raw[37])) * 1024UL;
- resultExtended->seqCtrl = (((uint16_t)raw[38] << 8) | ((uint16_t)raw[39]));
- memcpy(resultExtended->ssid, &raw[40], RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN);
- resultExtended->currentChannel = raw[72];
- memcpy(resultExtended->countryCode, &raw[73], 2);
- resultExtended->countryCode[2] = '\0';
- resultExtended->ioReg = raw[75];
- resultExtended->fcsCheckOk = (raw[76] != 0);
- resultExtended->phiOffset = (((uint16_t)raw[77] << 8) | ((uint16_t)raw[78]));
- return(RADIOLIB_ERR_NONE);
- }
-
- LR11x0WifiResultFull_t* resultFull = reinterpret_cast(result);
- resultFull->frameType = raw[3] & 0x03;
- resultFull->frameSubType = (raw[3] & 0x3C) >> 2;
- resultFull->toDistributionSystem = (raw[3] & 0x40) != 0;
- resultFull->fromDistributionSystem = (raw[3] & 0x80) != 0;
- memcpy(resultFull->mac, &raw[4], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
- resultFull->phiOffset = (((uint16_t)raw[10] << 8) | ((uint16_t)raw[11]));
- resultFull->timestamp = (((uint64_t)raw[12] << 56) | ((uint64_t)raw[13] << 48)) |
- (((uint64_t)raw[14] << 40) | ((uint64_t)raw[15] << 32)) |
- (((uint64_t)raw[16] << 24) | ((uint64_t)raw[17] << 16)) |
- (((uint64_t)raw[18] << 8) | (uint64_t)raw[19]);
- resultFull->periodBeacon = (((uint16_t)raw[20] << 8) | ((uint16_t)raw[21])) * 1024UL;
- }
-
- return(RADIOLIB_ERR_NONE);
-}
-
-int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) {
- RADIOLIB_ASSERT_PTR(count);
-
- // start scan
- RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan start");
- int16_t state = startWifiScan(wifiType, mode, chanMask, numScans, timeout);
- RADIOLIB_ASSERT(state);
-
- // wait for scan finished or timeout
- RadioLibTime_t softTimeout = 30UL * 1000UL;
- RadioLibTime_t start = this->mod->hal->millis();
- while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
- this->mod->hal->yield();
- if(this->mod->hal->millis() - start > softTimeout) {
- RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ");
- this->standby();
- return(RADIOLIB_ERR_RX_TIMEOUT);
- }
- }
- RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start));
-
- // read number of results
- return(getWifiScanResultsCount(count));
-}
-
int16_t LR11x0::getVersionInfo(LR11x0VersionInfo_t* info) {
RADIOLIB_ASSERT_PTR(info);
@@ -1765,7 +1368,7 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat
uint32_t offset = i * maxLen;
uint32_t len = (i == (numWrites - 1)) ? rem : maxLen;
RADIOLIB_DEBUG_BASIC_PRINTLN("Writing chunk %d at offset %08lx (%u words)", (int)i, (unsigned long)offset, (unsigned int)len);
- this->bootWriteFlashEncrypted(offset*sizeof(uint32_t), (uint32_t*)&image[offset], len, nonvolatile);
+ this->bootWriteFlashEncrypted(offset*sizeof(uint32_t), const_cast(&image[offset]), len, nonvolatile);
}
// kick the device from bootloader
@@ -1783,261 +1386,14 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat
return(state);
}
-int16_t LR11x0::isGnssScanCapable() {
- // get the version
- LR11x0VersionInfo_t version;
- int16_t state = this->getVersionInfo(&version);
- RADIOLIB_ASSERT(state);
-
- // check the device firmware version is sufficient
- uint16_t versionFull = ((uint16_t)version.fwMajor << 8) | (uint16_t)version.fwMinor;
- state = RADIOLIB_ERR_UNSUPPORTED;
- if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) {
- state = RADIOLIB_ERR_NONE;
- } else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) {
- state = RADIOLIB_ERR_NONE;
- }
- RADIOLIB_ASSERT(state);
-
- // in debug mode, dump the almanac
- #if RADIOLIB_DEBUG_PROTOCOL
- uint32_t addr = 0;
- uint16_t sz = 0;
- state = this->gnssAlmanacReadAddrSize(&addr, &sz);
- RADIOLIB_ASSERT(state);
- RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac@%08x, %d bytes", addr, sz);
- uint32_t buff[32] = { 0 };
- while(sz > 0) {
- size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t);
- state = this->readRegMem32(addr, buff, len);
- RADIOLIB_ASSERT(state);
- RADIOLIB_DEBUG_HEXDUMP(NULL, (uint8_t*)buff, len*sizeof(uint32_t), addr);
- addr += len*sizeof(uint32_t);
- sz -= len*sizeof(uint32_t);
- }
-
- uint8_t almanac[22] = { 0 };
- for(uint8_t i = 0; i < 128; i++) {
- RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac[%d]:", i);
- state = this->gnssAlmanacReadSV(i, almanac);
- RADIOLIB_ASSERT(state);
- RADIOLIB_DEBUG_HEXDUMP(NULL, almanac, 22);
- }
-
- #endif
-
- return(state);
-}
-
-int16_t LR11x0::gnssScan(LR11x0GnssResult_t* res) {
- RADIOLIB_ASSERT_PTR(res);
-
- // go to standby
- int16_t state = standby();
- RADIOLIB_ASSERT(state);
-
- // set DIO mapping
- state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT);
- RADIOLIB_ASSERT(state);
-
- // set scan mode (single vs multiple)
- state = this->gnssSetMode(0x03);
- RADIOLIB_ASSERT(state);
-
- // set RF switch
- this->mod->setRfSwitchState(LR11x0::MODE_GNSS);
-
- // start scan with high effort
- RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan start");
- state = this->gnssPerformScan(RADIOLIB_LR11X0_GNSS_EFFORT_MID, 0x3C, 16);
- RADIOLIB_ASSERT(state);
-
- // wait for scan finished or timeout
- // this can take very long if both GPS and BeiDou are enabled
- RadioLibTime_t softTimeout = 300UL * 1000UL;
- RadioLibTime_t start = this->mod->hal->millis();
- while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
- this->mod->hal->yield();
- if(this->mod->hal->millis() - start > softTimeout) {
- this->gnssAbort();
- RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ");
- }
- }
-
- // restore the switch
- this->mod->setRfSwitchState(Module::MODE_IDLE);
- RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start));
-
- // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags
- uint32_t irq = this->getIrqStatus();
- this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
- if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) {
- return(RADIOLIB_ERR_RX_TIMEOUT);
- }
-
- // retrieve the demodulator status
- uint8_t info = 0;
- state = this->gnssReadDemodStatus(&res->demodStat, &info);
- RADIOLIB_ASSERT(state);
- RADIOLIB_DEBUG_BASIC_PRINTLN("Demod status %d, info %02x", (int)res->demodStat, (unsigned int)info);
-
- // retrieve the number of detected satellites
- state = this->gnssGetNbSvDetected(&res->numSatsDet);
- RADIOLIB_ASSERT(state);
-
- // retrieve the result size
- state = this->gnssGetResultSize(&res->resSize);
- RADIOLIB_ASSERT(state);
-
- // check and return demodulator status
- if(res->demodStat < RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND) {
- return(RADIOLIB_ERR_GNSS_DEMOD(res->demodStat));
- }
-
- return(state);
-}
-
-int16_t LR11x0::getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat) {
- RADIOLIB_ASSERT_PTR(stat);
-
- // save the time the time until subframe is relative to
- stat->start = this->mod->hal->millis();
-
- // get the raw data
- uint8_t raw[53] = { 0 };
- int16_t state = this->gnssReadAlmanacStatus(raw);
- RADIOLIB_ASSERT(state);
-
- // parse the reply
- stat->gps.status = (int8_t)raw[0];
- stat->gps.timeUntilSubframe = ((uint32_t)(raw[1]) << 24) | ((uint32_t)(raw[2]) << 16) | ((uint32_t)(raw[3]) << 8) | (uint32_t)raw[4];
- stat->gps.numSubframes = raw[5];
- stat->gps.nextSubframe4SvId = raw[6];
- stat->gps.nextSubframe5SvId = raw[7];
- stat->gps.nextSubframeStart = raw[8];
- stat->gps.numUpdateNeeded = raw[9];
- stat->gps.flagsUpdateNeeded[0] = ((uint32_t)(raw[10]) << 24) | ((uint32_t)(raw[11]) << 16) | ((uint32_t)(raw[12]) << 8) | (uint32_t)raw[13];
- stat->gps.flagsActive[0] = ((uint32_t)(raw[14]) << 24) | ((uint32_t)(raw[15]) << 16) | ((uint32_t)(raw[16]) << 8) | (uint32_t)raw[17];
- stat->beidou.status = (int8_t)raw[18];
- stat->beidou.timeUntilSubframe = ((uint32_t)(raw[19]) << 24) | ((uint32_t)(raw[20]) << 16) | ((uint32_t)(raw[21]) << 8) | (uint32_t)raw[22];
- stat->beidou.numSubframes = raw[23];
- stat->beidou.nextSubframe4SvId = raw[24];
- stat->beidou.nextSubframe5SvId = raw[25];
- stat->beidou.nextSubframeStart = raw[26];
- stat->beidou.numUpdateNeeded = raw[27];
- stat->beidou.flagsUpdateNeeded[0] = ((uint32_t)(raw[28]) << 24) | ((uint32_t)(raw[29]) << 16) | ((uint32_t)(raw[30]) << 8) | (uint32_t)raw[31];
- stat->beidou.flagsUpdateNeeded[1] = ((uint32_t)(raw[32]) << 24) | ((uint32_t)(raw[33]) << 16) | ((uint32_t)(raw[34]) << 8) | (uint32_t)raw[35];
- stat->beidou.flagsActive[0] = ((uint32_t)(raw[36]) << 24) | ((uint32_t)(raw[37]) << 16) | ((uint32_t)(raw[38]) << 8) | (uint32_t)raw[39];
- stat->beidou.flagsActive[1] = ((uint32_t)(raw[40]) << 24) | ((uint32_t)(raw[41]) << 16) | ((uint32_t)(raw[42]) << 8) | (uint32_t)raw[43];
- stat->beidouSvNoAlmanacFlags[0] = ((uint32_t)(raw[44]) << 24) | ((uint32_t)(raw[45]) << 16) | ((uint32_t)(raw[46]) << 8) | (uint32_t)raw[47];
- stat->beidouSvNoAlmanacFlags[1] = ((uint32_t)(raw[18]) << 24) | ((uint32_t)(raw[49]) << 16) | ((uint32_t)(raw[50]) << 8) | (uint32_t)raw[51];
- stat->nextAlmanacId = raw[52];
-
- return(state);
-}
-
-int16_t LR11x0::gnssDelayUntilSubframe(LR11x0GnssAlmanacStatus_t *stat, uint8_t constellation) {
- RADIOLIB_ASSERT_PTR(stat);
-
- // almanac update has to be called at least 1.3 seconds before the subframe
- // we use 2.3 seconds to be on the safe side
-
- // calculate absolute times
- RadioLibTime_t window = stat->start + stat->gps.timeUntilSubframe - 2300;
- if(constellation == RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU) {
- window = stat->start + stat->beidou.timeUntilSubframe - 2300;
- }
- RadioLibTime_t now = this->mod->hal->millis();
- if(now > window) {
- // we missed the window
- return(RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE);
- }
-
- RadioLibTime_t delay = window - now;
- RADIOLIB_DEBUG_BASIC_PRINTLN("Time until subframe %lu ms", delay);
- this->mod->hal->delay(delay);
- return(RADIOLIB_ERR_NONE);
-}
-
-// TODO fix last satellite always out of date
-int16_t LR11x0::updateGnssAlmanac(uint8_t constellation) {
- int16_t state = this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT);
- RADIOLIB_ASSERT(state);
-
- state = this->gnssAlmanacUpdateFromSat(RADIOLIB_LR11X0_GNSS_EFFORT_MID, constellation);
- RADIOLIB_ASSERT(state);
-
- // wait for scan finished or timeout, assumes 2 subframes and up to 2.3s pre-roll
- uint32_t softTimeout = 16UL * 1000UL;
- uint32_t start = this->mod->hal->millis();
- while (!this->mod->hal->digitalRead(this->mod->getIrq())) {
- this->mod->hal->yield();
- if(this->mod->hal->millis() - start > softTimeout) {
- this->gnssAbort();
- RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for almanac update");
- }
- }
-
- RADIOLIB_DEBUG_BASIC_PRINTLN("GPS almanac update done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start));
-
- // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags
- uint32_t irq = this->getIrqStatus();
- this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
- if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) {
- state = RADIOLIB_ERR_RX_TIMEOUT;
- }
-
- return(state);
-}
-
-int16_t LR11x0::getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered) {
- RADIOLIB_ASSERT_PTR(pos);
-
- uint8_t error = 0;
- int16_t state;
- if(filtered) {
- state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, NULL, NULL, NULL, NULL, &pos->latitude, &pos->longitude, &pos->accuracy, NULL);
- } else {
- state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, &pos->latitude, &pos->longitude, &pos->accuracy, NULL, NULL, NULL, NULL, NULL);
- }
- RADIOLIB_ASSERT(state);
-
- // check the solver error
- if(error != 0) {
- return(RADIOLIB_ERR_GNSS_SOLVER(error));
- }
-
- return(state);
-}
-
-int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) {
- RADIOLIB_ASSERT_PTR(sats);
- if(numSats >= 32) {
- return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
- }
-
- uint8_t svId[32] = { 0 };
- uint8_t snr[32] = { 0 };
- int16_t doppler[32] = { 0 };
- int16_t state = this->gnssGetSvDetected(svId, snr, doppler, numSats);
- RADIOLIB_ASSERT(state);
- for(size_t i = 0; i < numSats; i++) {
- sats[i].svId = svId[i];
- sats[i].c_n0 = snr[i] + 31;
- sats[i].doppler = doppler[i];
- }
-
- return(state);
-}
-
int16_t LR11x0::getModem(ModemType_t* modem) {
RADIOLIB_ASSERT_PTR(modem);
- uint8_t packetType = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
- int16_t state = getPacketType(&packetType);
+ uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
RADIOLIB_ASSERT(state);
- switch(packetType) {
+ switch(type) {
case(RADIOLIB_LR11X0_PACKET_TYPE_LORA):
*modem = ModemType_t::RADIOLIB_MODEM_LORA;
return(RADIOLIB_ERR_NONE);
@@ -2052,21 +1408,173 @@ int16_t LR11x0::getModem(ModemType_t* modem) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
+int16_t LR11x0::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
+ int16_t state;
+
+ switch(mode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ // check active modem
+ uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) &&
+ (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set DIO mapping
+ if(cfg->receive.timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) {
+ cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
+ }
+ state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
+ RADIOLIB_ASSERT(state);
+
+ // set implicit mode and expected len if applicable
+ if((this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) {
+ state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // if max(uint32_t) is used, revert to RxContinuous
+ if(cfg->receive.timeout == 0xFFFFFFFF) {
+ cfg->receive.timeout = 0xFFFFFF;
+ }
+ this->rxTimeout = cfg->receive.timeout;
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ // check packet length
+ if(cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+
+ // maximum packet length is decreased by 1 when address filtering is active
+ if((this->addrComp != RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED) && (cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 1)) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+
+ // set packet Length
+ uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
+ state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled);
+
+ } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
+ state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
+
+ } else if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
+ return(RADIOLIB_ERR_UNKNOWN);
+
+ }
+ RADIOLIB_ASSERT(state);
+
+ // set DIO mapping
+ state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT);
+ RADIOLIB_ASSERT(state);
+
+ if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
+ // in LR-FHSS mode, the packet is built by the device
+ // TODO add configurable device offset
+ state = LRxxxx::lrFhssBuildFrame(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len);
+ RADIOLIB_ASSERT(state);
+
+ } else {
+ // write packet to buffer
+ state = writeBuffer8(cfg->transmit.data, cfg->transmit.len);
+ RADIOLIB_ASSERT(state);
+
+ }
+
+ // clear interrupt flags
+ state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
+ RADIOLIB_ASSERT(state);
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = mode;
+ return(state);
+}
+
+int16_t LR11x0::launchMode() {
+ int16_t state;
+ switch(this->stagedMode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ this->mod->setRfSwitchState(Module::MODE_RX);
+ state = setRx(this->rxTimeout);
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ this->mod->setRfSwitchState(Module::MODE_TX);
+ state = setTx(RADIOLIB_LR11X0_TX_TIMEOUT_NONE);
+ RADIOLIB_ASSERT(state);
+
+ // wait for BUSY to go low (= PA ramp up done)
+ while(this->mod->hal->digitalRead(this->mod->getGpio())) {
+ this->mod->hal->yield();
+ }
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
+ return(state);
+}
+
+int16_t LR11x0::workaroundGFSK() {
+ // first, check we are using GFSK modem
+ uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if(modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
+ // not in GFSK, nothing to do here
+ return(RADIOLIB_ERR_NONE);
+ }
+
+ // this seems to always be the first step (even when resetting)
+ state = this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX1, 0x30, 0x10);
+ RADIOLIB_ASSERT(state);
+
+ // these are the default values that will be applied if nothing matches
+ uint32_t valFix2 = 0x01;
+ uint32_t valFix3 = 0x0A01;
+
+ // next, decide what to change based on modulation properties
+ if((this->bitRate == 1200) && (this->frequencyDev == 5000) && (this->rxBandwidth == RADIOLIB_LR11X0_GFSK_RX_BW_19_5)) {
+ // workaround for 1.2 kbps
+ valFix2 = 0x04;
+
+ } else if((this->bitRate == 600) && (this->frequencyDev == 800) && (this->rxBandwidth == RADIOLIB_LR11X0_GFSK_RX_BW_4_8)) {
+ // value to write depends on the frequency
+ valFix3 = (this->freqMHz >= 1000.0f) ? 0x1100 : 0x0600;
+
+ }
+
+ // update the registers
+ state = this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX2, 0x05, valFix2);
+ RADIOLIB_ASSERT(state);
+ return(this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX3, 0x01FF03, valFix3));
+}
+
int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) {
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32;
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16;
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
- this->mod->spiConfig.statusPos = 0;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR11X0_CMD_READ_REG_MEM;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS;
- this->mod->spiConfig.stream = true;
- this->mod->spiConfig.parseStatusCb = SPIparseStatus;
- this->mod->spiConfig.checkStatusCb = SPIcheckStatus;
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32;
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
this->gnss = false;
// try to find the LR11x0 chip - this will also reset the module at least once
@@ -2082,7 +1590,7 @@ int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) {
RADIOLIB_ASSERT(state);
// set TCXO control, if requested
- if(!this->XTAL && tcxoVoltage > 0.0) {
+ if(!this->XTAL && tcxoVoltage > 0.0f) {
state = setTCXO(tcxoVoltage);
RADIOLIB_ASSERT(state);
}
@@ -2091,51 +1599,6 @@ int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) {
return(config(modem));
}
-int16_t LR11x0::SPIparseStatus(uint8_t in) {
- if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_PERR) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- } else if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_FAIL) {
- return(RADIOLIB_ERR_SPI_CMD_FAILED);
- } else if((in == 0x00) || (in == 0xFF)) {
- return(RADIOLIB_ERR_CHIP_NOT_FOUND);
- }
- return(RADIOLIB_ERR_NONE);
-}
-
-int16_t LR11x0::SPIcheckStatus(Module* mod) {
- // the status check command doesn't return status in the same place as other read commands,
- // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used
- // it also seems to ignore the actual command, and just sending in bunch of NOPs will work
- uint8_t buff[6] = { 0 };
- mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
- int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
- mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
- RADIOLIB_ASSERT(state);
- return(LR11x0::SPIparseStatus(buff[0]));
-}
-
-int16_t LR11x0::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, uint8_t* out, size_t outLen) {
- int16_t state = RADIOLIB_ERR_UNKNOWN;
- if(!write) {
- // the SPI interface of LR11x0 requires two separate transactions for reading
- // send the 16-bit command
- state = this->mod->SPIwriteStream(cmd, out, outLen, true, false);
- RADIOLIB_ASSERT(state);
-
- // read the result without command
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_0;
- state = this->mod->SPIreadStream(RADIOLIB_LR11X0_CMD_NOP, data, len, true, false);
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16;
-
- } else {
- // write is just a single transaction
- state = this->mod->SPIwriteStream(cmd, data, len, true, true);
-
- }
-
- return(state);
-}
-
bool LR11x0::findChip(uint8_t ver) {
uint8_t i = 0;
bool flagFound = false;
@@ -2148,13 +1611,16 @@ bool LR11x0::findChip(uint8_t ver) {
int16_t state = getVersionInfo(&info);
RADIOLIB_ASSERT(state);
- if(info.device == ver) {
+ if((info.device == ver) || (info.device == RADIOLIB_LR11X0_DEVICE_BOOT)) {
RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", info.device);
RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)info.fwMajor, (int)info.fwMinor);
if(this->chipType != RADIOLIB_LR11X0_DEVICE_LR1121) {
RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)info.fwMajorWiFi, (int)info.fwMinorWiFi);
RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)info.fwGNSS, (int)info.almanacGNSS);
}
+ if(info.device == RADIOLIB_LR11X0_DEVICE_BOOT) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Warning: device is in bootloader mode! Only FW update is possible now.");
+ }
flagFound = true;
} else {
RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, info.device);
@@ -2163,6 +1629,7 @@ bool LR11x0::findChip(uint8_t ver) {
i++;
}
}
+
return(flagFound);
}
@@ -2175,12 +1642,12 @@ int16_t LR11x0::config(uint8_t modem) {
RADIOLIB_ASSERT(state);
// clear IRQ
- state = this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
+ state = this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
state |= this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_NONE);
RADIOLIB_ASSERT(state);
// calibrate all blocks
- (void)this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL);
+ state = this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL);
// wait for calibration completion
this->mod->hal->delay(5);
@@ -2197,6 +1664,8 @@ int16_t LR11x0::config(uint8_t modem) {
getErrors(&errors);
RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
}
+ #else
+ RADIOLIB_ASSERT(state);
#endif
// set modem
@@ -2289,1660 +1758,4 @@ Module* LR11x0::getMod() {
return(this->mod);
}
-int16_t LR11x0::writeRegMem32(uint32_t addr, uint32_t* data, size_t len) {
- // check maximum size
- if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
- return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false));
-}
-
-int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) {
- // check maximum size
- if(len >= (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
-
- // the request contains the address and length
- uint8_t reqBuff[5] = {
- (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF),
- (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
- (uint8_t)len,
- };
-
- // build buffers - later we need to ensure endians are correct,
- // so there is probably no way to do this without copying buffers and iterating
- #if RADIOLIB_STATIC_ONLY
- uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)];
- #endif
-
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff));
-
- // convert endians
- if(data && (state == RADIOLIB_ERR_NONE)) {
- for(size_t i = 0; i < len; i++) {
- data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)];
- }
- }
-
- #if !RADIOLIB_STATIC_ONLY
- delete[] rplBuff;
- #endif
-
- return(state);
-}
-
-int16_t LR11x0::writeBuffer8(uint8_t* data, size_t len) {
- // check maximum size
- if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, data, len));
-}
-
-int16_t LR11x0::readBuffer8(uint8_t* data, size_t len, size_t offset) {
- // check maximum size
- if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
-
- // build buffers
- size_t reqLen = 2*sizeof(uint8_t) + len;
- #if RADIOLIB_STATIC_ONLY
- uint8_t reqBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* reqBuff = new uint8_t[reqLen];
- #endif
-
- // set the offset and length
- reqBuff[0] = (uint8_t)offset;
- reqBuff[1] = (uint8_t)len;
-
- // send the request
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_BUFFER, false, data, len, reqBuff, reqLen);
- #if !RADIOLIB_STATIC_ONLY
- delete[] reqBuff;
- #endif
- return(state);
-}
-
-int16_t LR11x0::clearRxBuffer(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER, true, NULL, 0));
-}
-
-int16_t LR11x0::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) {
- uint8_t buff[12] = {
- (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
- (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
- (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) {
- uint8_t buff[6] = { 0 };
-
- // the status check command doesn't return status in the same place as other read commands
- // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used
- // it also seems to ignore the actual command, and just sending in bunch of NOPs will work
- int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
-
- // pass the replies
- if(stat1) { *stat1 = buff[0]; }
- if(stat2) { *stat2 = buff[1]; }
- if(irq) { *irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; }
-
- return(state);
-}
-
-int16_t LR11x0::getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor) {
- uint8_t buff[4] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VERSION, false, buff, sizeof(buff));
-
- // pass the replies
- if(hw) { *hw = buff[0]; }
- if(device) { *device = buff[1]; }
- if(major) { *major = buff[2]; }
- if(minor) { *minor = buff[3]; }
-
- return(state);
-}
-
-int16_t LR11x0::getErrors(uint16_t* err) {
- uint8_t buff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_ERRORS, false, buff, sizeof(buff));
-
- // pass the replies
- if(err) { *err = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
-
- return(state);
-}
-
-int16_t LR11x0::clearErrors(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_ERRORS, true, NULL, 0));
-}
-
-int16_t LR11x0::calibrate(uint8_t params) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIBRATE, true, ¶ms, 1));
-}
-
-int16_t LR11x0::setRegMode(uint8_t mode) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_REG_MODE, true, &mode, 1));
-}
-
-int16_t LR11x0::calibrateImageRejection(float freqMin, float freqMax) {
- uint8_t buff[2] = {
- (uint8_t)floor((freqMin - 1.0f) / 4.0f),
- (uint8_t)ceil((freqMax + 1.0f) / 4.0f)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIB_IMAGE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg) {
- uint8_t buff[8] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, txHfCfg, gnssCfg, wifiCfg };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) {
- uint8_t buff[8] = {
- (uint8_t)((irq1 >> 24) & 0xFF), (uint8_t)((irq1 >> 16) & 0xFF), (uint8_t)((irq1 >> 8) & 0xFF), (uint8_t)(irq1 & 0xFF),
- (uint8_t)((irq2 >> 24) & 0xFF), (uint8_t)((irq2 >> 16) & 0xFF), (uint8_t)((irq2 >> 8) & 0xFF), (uint8_t)(irq2 & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setDioIrqParams(uint32_t irq) {
- return(setDioIrqParams(irq, this->gnss ? 0 : irq));
-}
-
-int16_t LR11x0::clearIrq(uint32_t irq) {
- uint8_t buff[4] = {
- (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_IRQ, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::configLfClock(uint8_t setup) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK, true, &setup, 1));
-}
-
-int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) {
- uint8_t buff[4] = {
- tune, (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TCXO_MODE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::reboot(bool stay) {
- uint8_t buff[1] = { (uint8_t)(stay*3) };
- return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_REBOOT, buff, sizeof(buff), true, false));
-}
-
-int16_t LR11x0::getVbat(float* vbat) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VBAT, false, buff, sizeof(buff));
-
- // pass the replies
- if(vbat) { *vbat = (((float)buff[0]/51.0f) - 1.0f)*1.35f; }
-
- return(state);
-}
-
-int16_t LR11x0::getTemp(float* temp) {
- uint8_t buff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_TEMP, false, buff, sizeof(buff));
-
- // pass the replies
- if(temp) {
- uint16_t raw = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1];
- raw = raw & 0x07FF; //According LR1121 datasheet we need [0..10] bits
- *temp = 25.0f - (1000.0f/1.7f)*(((float)raw/2047.0f)*1.35f - 0.7295f); //According LR1121 datasheet 1.35
- }
-
- return(state);
-}
-
-int16_t LR11x0::setFs(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_FS, true, NULL, 0));
-}
-
-int16_t LR11x0::getRandomNumber(uint32_t* rnd) {
- uint8_t buff[4] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER, false, buff, sizeof(buff));
-
- // pass the replies
- if(rnd) { *rnd = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; }
-
- return(state);
-}
-
-int16_t LR11x0::eraseInfoPage(void) {
- // only page 1 can be erased
- uint8_t buff[1] = { RADIOLIB_LR11X0_INFO_PAGE };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::writeInfoPage(uint16_t addr, const uint32_t* data, size_t len) {
- // check maximum size
- if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
-
- // build buffers - later we need to ensure endians are correct,
- // so there is probably no way to do this without copying buffers and iterating
- size_t buffLen = sizeof(uint8_t) + sizeof(uint16_t) + len*sizeof(uint32_t);
- #if RADIOLIB_STATIC_ONLY
- uint8_t dataBuff[sizeof(uint8_t) + sizeof(uint16_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* dataBuff = new uint8_t[buffLen];
- #endif
-
- // set the address
- dataBuff[0] = RADIOLIB_LR11X0_INFO_PAGE;
- dataBuff[1] = (uint8_t)((addr >> 8) & 0xFF);
- dataBuff[2] = (uint8_t)(addr & 0xFF);
-
- // convert endians
- for(size_t i = 0; i < len; i++) {
- dataBuff[3 + i] = (uint8_t)((data[i] >> 24) & 0xFF);
- dataBuff[4 + i] = (uint8_t)((data[i] >> 16) & 0xFF);
- dataBuff[5 + i] = (uint8_t)((data[i] >> 8) & 0xFF);
- dataBuff[6 + i] = (uint8_t)(data[i] & 0xFF);
- }
-
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE, true, dataBuff, buffLen);
- #if !RADIOLIB_STATIC_ONLY
- delete[] dataBuff;
- #endif
- return(state);
-}
-
-int16_t LR11x0::readInfoPage(uint16_t addr, uint32_t* data, size_t len) {
- // check maximum size
- if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
-
- // the request contains the address and length
- uint8_t reqBuff[4] = {
- RADIOLIB_LR11X0_INFO_PAGE,
- (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
- (uint8_t)len,
- };
-
- // build buffers - later we need to ensure endians are correct,
- // so there is probably no way to do this without copying buffers and iterating
- #if RADIOLIB_STATIC_ONLY
- uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)];
- #endif
-
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_INFO_PAGE, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff));
-
- // convert endians
- if(data && (state == RADIOLIB_ERR_NONE)) {
- for(size_t i = 0; i < len; i++) {
- data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)];
- }
- }
-
- #if !RADIOLIB_STATIC_ONLY
- delete[] rplBuff;
- #endif
-
- return(state);
-}
-
-int16_t LR11x0::getChipEui(uint8_t* eui) {
- RADIOLIB_ASSERT_PTR(eui);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
-}
-
-int16_t LR11x0::getSemtechJoinEui(uint8_t* eui) {
- RADIOLIB_ASSERT_PTR(eui);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
-}
-
-int16_t LR11x0::deriveRootKeysAndGetPin(uint8_t* pin) {
- RADIOLIB_ASSERT_PTR(pin);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN));
-}
-
-int16_t LR11x0::enableSpiCrc(bool en) {
- // TODO implement this
- (void)en;
- // LR11X0 CRC is gen 0xA6 (0x65 but reflected), init 0xFF, input and result reflected
- /*RadioLibCRCInstance.size = 8;
- RadioLibCRCInstance.poly = 0xA6;
- RadioLibCRCInstance.init = 0xFF;
- RadioLibCRCInstance.out = 0x00;
- RadioLibCRCInstance.refIn = true;
- RadioLibCRCInstance.refOut = true;*/
- return(RADIOLIB_ERR_UNSUPPORTED);
-}
-
-int16_t LR11x0::driveDiosInSleepMode(bool en) {
- uint8_t buff[1] = { (uint8_t)en };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::resetStats(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_RESET_STATS, true, NULL, 0));
-}
-
-int16_t LR11x0::getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* data1, uint16_t* data2) {
- uint8_t buff[8] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_STATS, false, buff, sizeof(buff));
-
- // pass the replies
- if(nbPktReceived) { *nbPktReceived = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
- if(nbPktCrcError) { *nbPktCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; }
- if(data1) { *data1 = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
- if(data2) { *data2 = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; }
-
- return(state);
-}
-
-int16_t LR11x0::getPacketType(uint8_t* type) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE, false, buff, sizeof(buff));
-
- // pass the replies
- if(type) { *type = buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::getRxBufferStatus(uint8_t* len, uint8_t* startOffset) {
- uint8_t buff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS, false, buff, sizeof(buff));
-
- // pass the replies
- if(len) { *len = buff[0]; }
- if(startOffset) { *startOffset = buff[1]; }
-
- return(state);
-}
-
-int16_t LR11x0::getPacketStatusLoRa(float* rssiPkt, float* snrPkt, float* signalRssiPkt) {
- uint8_t buff[3] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff));
-
- // pass the replies
- if(rssiPkt) { *rssiPkt = (float)buff[0] / -2.0f; }
- if(snrPkt) { *snrPkt = (float)((int8_t)buff[1]) / 4.0f; }
- if(signalRssiPkt) { *signalRssiPkt = buff[2]; }
-
- return(state);
-}
-
-int16_t LR11x0::getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rxLen, uint8_t* stat) {
- uint8_t buff[4] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff));
-
- // pass the replies
- if(rssiSync) { *rssiSync = (float)buff[0] / -2.0f; }
- if(rssiAvg) { *rssiAvg = (float)buff[1] / -2.0f; }
- if(rxLen) { *rxLen = buff[2]; }
- if(stat) { *stat = buff[3]; }
-
- return(state);
-}
-
-int16_t LR11x0::getRssiInst(float* rssi) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RSSI_INST, false, buff, sizeof(buff));
-
- // pass the replies
- if(rssi) { *rssi = (float)buff[0] / -2.0f; }
-
- return(state);
-}
-
-int16_t LR11x0::setGfskSyncWord(uint8_t* sync) {
- RADIOLIB_ASSERT_PTR(sync);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, true, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN));
-}
-
-int16_t LR11x0::setLoRaPublicNetwork(bool pub) {
- uint8_t buff[1] = { (uint8_t)pub };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setRx(uint32_t timeout) {
- uint8_t buff[3] = {
- (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setTx(uint32_t timeout) {
- uint8_t buff[3] = {
- (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setRfFrequency(uint32_t rfFreq) {
- uint8_t buff[4] = {
- (uint8_t)((rfFreq >> 24) & 0xFF), (uint8_t)((rfFreq >> 16) & 0xFF),
- (uint8_t)((rfFreq >> 8) & 0xFF), (uint8_t)(rfFreq & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::autoTxRx(uint32_t delay, uint8_t intMode, uint32_t timeout) {
- uint8_t buff[7] = {
- (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), intMode,
- (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_AUTO_TX_RX, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setCadParams(uint8_t symNum, uint8_t detPeak, uint8_t detMin, uint8_t cadExitMode, uint32_t timeout) {
- uint8_t buff[7] = {
- symNum, detPeak, detMin, cadExitMode,
- (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setPacketType(uint8_t type) {
- uint8_t buff[1] = { type };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
- // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled
- if(this->ldroAuto) {
- float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
- if(symbolLength >= 16.0) {
- this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_ENABLED;
- } else {
- this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_DISABLED;
- }
- } else {
- this->ldrOptimize = ldro;
- }
-
- uint8_t buff[4] = { sf, bw, cr, this->ldrOptimize };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setModulationParamsGFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) {
- uint8_t buff[10] = {
- (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF),
- (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh, rxBw,
- (uint8_t)((freqDev >> 24) & 0xFF), (uint8_t)((freqDev >> 16) & 0xFF),
- (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setModulationParamsLrFhss(uint32_t br, uint8_t sh) {
- uint8_t buff[5] = {
- (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF),
- (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setModulationParamsSigfox(uint32_t br, uint8_t sh) {
- // same as for LR-FHSS
- return(this->setModulationParamsLrFhss(br, sh));
-}
-
-int16_t LR11x0::setPacketParamsLoRa(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ) {
- uint8_t buff[6] = {
- (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
- hdrType, payloadLen, crcType, invertIQ
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setPacketParamsGFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t syncWordLen, uint8_t addrCmp, uint8_t packType, uint8_t payloadLen, uint8_t crcType, uint8_t whiten) {
- uint8_t buff[9] = {
- (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
- preambleDetectorLen, syncWordLen, addrCmp, packType, payloadLen, crcType, whiten
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setPacketParamsSigfox(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t bitNum) {
- uint8_t buff[7] = {
- payloadLen, (uint8_t)((rampUpDelay >> 8) & 0xFF), (uint8_t)(rampUpDelay & 0xFF),
- (uint8_t)((rampDownDelay >> 8) & 0xFF), (uint8_t)(rampDownDelay & 0xFF),
- (uint8_t)((bitNum >> 8) & 0xFF), (uint8_t)(bitNum & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setTxParams(int8_t pwr, uint8_t ramp) {
- uint8_t buff[2] = { (uint8_t)pwr, ramp };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setPacketAdrs(uint8_t node, uint8_t broadcast) {
- uint8_t buff[2] = { node, broadcast };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setRxTxFallbackMode(uint8_t mode) {
- uint8_t buff[1] = { mode };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint8_t mode) {
- uint8_t buff[7] = {
- (uint8_t)((rxPeriod >> 16) & 0xFF), (uint8_t)((rxPeriod >> 8) & 0xFF), (uint8_t)(rxPeriod & 0xFF),
- (uint8_t)((sleepPeriod >> 16) & 0xFF), (uint8_t)((sleepPeriod >> 8) & 0xFF), (uint8_t)(sleepPeriod & 0xFF),
- mode
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setPaConfig(uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel) {
- uint8_t buff[4] = { paSel, regPaSupply, paDutyCycle, paHpSel };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PA_CONFIG, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::stopTimeoutOnPreamble(bool stop) {
- uint8_t buff[1] = { (uint8_t)stop };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setCad(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD, true, NULL, 0));
-}
-
-int16_t LR11x0::setTxCw(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_CW, true, NULL, 0));
-}
-
-int16_t LR11x0::setTxInfinitePreamble(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE, true, NULL, 0));
-}
-
-int16_t LR11x0::setLoRaSynchTimeout(uint8_t symbolNum) {
- uint8_t buff[1] = { symbolNum };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setRangingAddr(uint32_t addr, uint8_t checkLen) {
- uint8_t buff[5] = {
- (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF),
- (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), checkLen
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setRangingReqAddr(uint32_t addr) {
- uint8_t buff[4] = {
- (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF),
- (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::getRangingResult(uint8_t type, float* res) {
- uint8_t reqBuff[1] = { type };
- uint8_t rplBuff[4] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
- RADIOLIB_ASSERT(state);
-
- if(res) {
- if(type == RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE) {
- uint32_t raw = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3];
- *res = ((float)(raw*3e8))/((float)(4096*this->bandwidthKhz*1000));
- } else {
- *res = (float)rplBuff[3]/2.0f;
- }
- }
-
- return(state);
-}
-
-int16_t LR11x0::setRangingTxRxDelay(uint32_t delay) {
- uint8_t buff[4] = {
- (uint8_t)((delay >> 24) & 0xFF), (uint8_t)((delay >> 16) & 0xFF),
- (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setGfskCrcParams(uint32_t init, uint32_t poly) {
- uint8_t buff[8] = {
- (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF),
- (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF),
- (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF),
- (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS, true, buff, sizeof(buff)));
-
-}
-
-int16_t LR11x0::setGfskWhitParams(uint16_t seed) {
- uint8_t buff[2] = {
- (uint8_t)((seed >> 8) & 0xFF), (uint8_t)(seed & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setRangingParameter(uint8_t symbolNum) {
- // the first byte is reserved
- uint8_t buff[2] = { 0x00, symbolNum };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setRssiCalibration(const int8_t* tune, int16_t gainOffset) {
- uint8_t buff[11] = {
- (uint8_t)((tune[0] & 0x0F) | (uint8_t)(tune[1] & 0x0F) << 4),
- (uint8_t)((tune[2] & 0x0F) | (uint8_t)(tune[3] & 0x0F) << 4),
- (uint8_t)((tune[4] & 0x0F) | (uint8_t)(tune[5] & 0x0F) << 4),
- (uint8_t)((tune[6] & 0x0F) | (uint8_t)(tune[7] & 0x0F) << 4),
- (uint8_t)((tune[8] & 0x0F) | (uint8_t)(tune[9] & 0x0F) << 4),
- (uint8_t)((tune[10] & 0x0F) | (uint8_t)(tune[11] & 0x0F) << 4),
- (uint8_t)((tune[12] & 0x0F) | (uint8_t)(tune[13] & 0x0F) << 4),
- (uint8_t)((tune[14] & 0x0F) | (uint8_t)(tune[15] & 0x0F) << 4),
- (uint8_t)((tune[16] & 0x0F) | (uint8_t)(tune[17] & 0x0F) << 4),
- (uint8_t)(((uint16_t)gainOffset >> 8) & 0xFF), (uint8_t)(gainOffset & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::setLoRaSyncWord(uint8_t sync) {
- uint8_t buff[1] = { sync };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, uint8_t* payload, size_t len) {
- // check maximum size
- const uint8_t maxLen[4][4] = {
- { 189, 178, 167, 155, },
- { 151, 142, 133, 123, },
- { 112, 105, 99, 92, },
- { 74, 69, 65, 60, },
- };
- if((cr > RADIOLIB_LR11X0_LR_FHSS_CR_1_3) || ((hdrCount - 1) > (int)sizeof(maxLen[0])) || (len > maxLen[cr][hdrCount - 1])) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
-
- // build buffers
- size_t buffLen = 9 + len;
- #if RADIOLIB_STATIC_ONLY
- uint8_t dataBuff[9 + 190];
- #else
- uint8_t* dataBuff = new uint8_t[buffLen];
- #endif
-
- // set properties of the packet
- dataBuff[0] = hdrCount;
- dataBuff[1] = cr;
- dataBuff[2] = RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK;
- dataBuff[3] = grid;
- dataBuff[4] = (uint8_t)hop;
- dataBuff[5] = bw;
- dataBuff[6] = (uint8_t)((hopSeq >> 8) & 0x01);
- dataBuff[7] = (uint8_t)(hopSeq & 0xFF);
- dataBuff[8] = devOffset;
- memcpy(&dataBuff[9], payload, len);
-
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, true, dataBuff, buffLen);
- #if !RADIOLIB_STATIC_ONLY
- delete[] dataBuff;
- #endif
- return(state);
-}
-
-int16_t LR11x0::lrFhssSetSyncWord(uint32_t sync) {
- uint8_t buff[4] = {
- (uint8_t)((sync >> 24) & 0xFF), (uint8_t)((sync >> 16) & 0xFF),
- (uint8_t)((sync >> 8) & 0xFF), (uint8_t)(sync & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::configBleBeacon(uint8_t chan, uint8_t* payload, size_t len) {
- return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON, chan, payload, len));
-}
-
-int16_t LR11x0::getLoRaRxHeaderInfos(uint8_t* info) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS, false, buff, sizeof(buff));
-
- // pass the replies
- if(info) { *info = buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::bleBeaconSend(uint8_t chan, uint8_t* payload, size_t len) {
- return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND, chan, payload, len));
-}
-
-int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len) {
- // check maximum size
- // TODO what is the actual maximum?
- if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
-
- // build buffers
- #if RADIOLIB_STATIC_ONLY
- uint8_t dataBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* dataBuff = new uint8_t[sizeof(uint8_t) + len];
- #endif
-
- // set the channel
- dataBuff[0] = chan;
- memcpy(&dataBuff[1], payload, len);
-
- int16_t state = this->SPIcommand(cmd, true, dataBuff, sizeof(uint8_t) + len);
- #if !RADIOLIB_STATIC_ONLY
- delete[] dataBuff;
- #endif
- return(state);
-}
-
-int16_t LR11x0::wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) {
- uint8_t buff[9] = {
- type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
- acqMode, nbMaxRes, nbScanPerChan,
- (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
- abortOnTimeout
- };
-
- // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts
- return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_WIFI_SCAN, buff, sizeof(buff), false, false));
-}
-
-int16_t LR11x0::wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) {
- uint8_t buff[9] = {
- type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
- acqMode, nbMaxRes,
- (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF),
- (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::wifiCountryCode(uint16_t mask, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) {
- uint8_t buff[7] = {
- (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
- nbMaxRes, nbScanPerChan,
- (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
- abortOnTimeout
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::wifiCountryCodeTimeLimit(uint16_t mask, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) {
- uint8_t buff[7] = {
- (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
- nbMaxRes,
- (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF),
- (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::wifiReadResults(uint8_t index, uint8_t nbResults, uint8_t format, uint8_t* results) {
- uint8_t buff[3] = { index, nbResults, format };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS, false, results, RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::wifiResetCumulTimings(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS, true, NULL, 0));
-}
-
-int16_t LR11x0::wifiReadCumulTimings(uint32_t* detection, uint32_t* capture, uint32_t* demodulation) {
- uint8_t buff[16] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS, false, buff, sizeof(buff));
-
- // pass the replies
- if(detection) { *detection = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; }
- if(capture) { *capture = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; }
- if(demodulation) { *demodulation = ((uint32_t)(buff[12]) << 24) | ((uint32_t)(buff[13]) << 16) | ((uint32_t)(buff[14]) << 8) | (uint32_t)buff[15]; }
-
- return(state);
-}
-
-int16_t LR11x0::wifiGetNbCountryCodeResults(uint8_t* nbResults) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS, false, buff, sizeof(buff));
-
- // pass the replies
- if(nbResults) { *nbResults = buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::wifiReadCountryCodeResults(uint8_t index, uint8_t nbResults, uint8_t* results) {
- uint8_t reqBuff[2] = { index, nbResults };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS, false, results, nbResults, reqBuff, sizeof(reqBuff)));
-}
-
-int16_t LR11x0::wifiCfgTimestampAPphone(uint32_t timestamp) {
- uint8_t buff[4] = {
- (uint8_t)((timestamp >> 24) & 0xFF), (uint8_t)((timestamp >> 16) & 0xFF),
- (uint8_t)((timestamp >> 8) & 0xFF), (uint8_t)(timestamp & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::wifiReadVersion(uint8_t* major, uint8_t* minor) {
- uint8_t buff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION, false, buff, sizeof(buff));
-
- // pass the replies
- if(major) { *major = buff[0]; }
- if(minor) { *minor = buff[1]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssReadRssi(int8_t* rssi) {
- uint8_t reqBuff[1] = { 0x09 }; // some undocumented magic byte, from the official driver
- uint8_t rplBuff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
- RADIOLIB_ASSERT(state);
- if(rssi) { *rssi = rplBuff[1]; }
- return(state);
-}
-
-int16_t LR11x0::gnssSetConstellationToUse(uint8_t mask) {
- uint8_t buff[1] = { mask };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssReadConstellationToUse(uint8_t* mask) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE, false, buff, sizeof(buff));
-
- // pass the replies
- if(mask) { *mask = buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssSetAlmanacUpdate(uint8_t mask) {
- uint8_t buff[1] = { mask };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssReadAlmanacUpdate(uint8_t* mask) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE, false, buff, sizeof(buff));
-
- // pass the replies
- if(mask) { *mask = buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssSetFreqSearchSpace(uint8_t freq) {
- uint8_t buff[1] = { freq };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssReadFreqSearchSpace(uint8_t* freq) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE, false, buff, sizeof(buff));
- if(freq) { *freq = buff[0]; }
- return(state);
-}
-
-int16_t LR11x0::gnssReadVersion(uint8_t* fw, uint8_t* almanac) {
- uint8_t buff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION, false, buff, sizeof(buff));
-
- // pass the replies
- if(fw) { *fw = buff[0]; }
- if(almanac) { *almanac = buff[1]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssReadSupportedConstellations(uint8_t* mask) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS, false, buff, sizeof(buff));
-
- // pass the replies
- if(mask) { *mask = buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssSetMode(uint8_t mode) {
- uint8_t buff[1] = { mode };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_MODE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssAutonomous(uint32_t gpsTime, uint8_t resMask, uint8_t nbSvMask) {
- uint8_t buff[7] = {
- (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF),
- (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF),
- RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE, resMask, nbSvMask
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssAssisted(uint32_t gpsTime, uint8_t effort, uint8_t resMask, uint8_t nbSvMask) {
- uint8_t buff[7] = {
- (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF),
- (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF),
- effort, resMask, nbSvMask
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ASSISTED, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssSetAssistancePosition(float lat, float lon) {
- uint16_t latRaw = (lat*2048.0f)/90.0f + 0.5f;
- uint16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f;
- uint8_t buff[4] = {
- (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF),
- (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssReadAssistancePosition(float* lat, float* lon) {
- uint8_t buff[4] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION, false, buff, sizeof(buff));
-
- // pass the replies
- if(lat) {
- uint16_t latRaw = ((uint16_t)(buff[0]) << 8) | (uint16_t)(buff[1]);
- *lat = ((float)latRaw*90.0f)/2048.0f;
- }
- if(lon) {
- uint16_t lonRaw = ((uint16_t)(buff[2]) << 8) | (uint16_t)(buff[3]);
- *lon = ((float)lonRaw*180.0f)/2048.0f;
- }
-
- return(state);
-}
-
-int16_t LR11x0::gnssPushSolverMsg(uint8_t* payload, size_t len) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG, true, payload, len));
-}
-
-int16_t LR11x0::gnssPushDmMsg(uint8_t* payload, size_t len) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG, true, payload, len));
-}
-
-int16_t LR11x0::gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, uint8_t* errCode, uint8_t* almUpdMask, uint8_t* freqSpace) {
- // send the command - datasheet here shows extra bytes being sent in the request
- // but doing that fails so treat it like any other read command
- uint8_t buff[9] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS, false, buff, sizeof(buff));
-
- // pass the replies
- if(fwVersion) { *fwVersion = buff[2]; }
- if(almanacCrc) { *almanacCrc = ((uint32_t)(buff[3]) << 24) | ((uint32_t)(buff[4]) << 16) | ((uint32_t)(buff[5]) << 8) | (uint32_t)buff[6]; }
- if(errCode) { *errCode = (buff[7] & 0xF0) >> 4; }
- if(almUpdMask) { *almUpdMask = (buff[7] & 0x0E) >> 1; }
- if(freqSpace) { *freqSpace = ((buff[7] & 0x01) << 1) | ((buff[8] & 0x80) >> 7); }
-
- return(state);
-}
-
-int16_t LR11x0::gnssGetNbSvDetected(uint8_t* nbSv) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED, false, buff, sizeof(buff));
-
- // pass the replies
- if(nbSv) { *nbSv = buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssGetSvDetected(uint8_t* svId, uint8_t* snr, int16_t* doppler, size_t nbSv) {
- // TODO this is arbitrary - is there an actual maximum?
- if(nbSv > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t)) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
-
- // build buffers
- size_t buffLen = nbSv*sizeof(uint32_t);
- #if RADIOLIB_STATIC_ONLY
- uint8_t dataBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* dataBuff = new uint8_t[buffLen];
- #endif
-
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED, false, dataBuff, buffLen);
- if(state == RADIOLIB_ERR_NONE) {
- for(size_t i = 0; i < nbSv; i++) {
- if(svId) { svId[i] = dataBuff[4*i]; }
- if(snr) { snr[i] = dataBuff[4*i + 1]; }
- if(doppler) { doppler[i] = ((uint16_t)(dataBuff[4*i + 2]) << 8) | (uint16_t)dataBuff[4*i + 3]; }
- }
- }
-
- #if !RADIOLIB_STATIC_ONLY
- delete[] dataBuff;
- #endif
- return(state);
-}
-
-int16_t LR11x0::gnssGetConsumption(uint32_t* cpu, uint32_t* radio) {
- uint8_t buff[8] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION, false, buff, sizeof(buff));
-
- // pass the replies
- if(cpu) { *cpu = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; }
- if(radio) { *radio = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssGetResultSize(uint16_t* size) {
- uint8_t buff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE, false, buff, sizeof(buff));
-
- // pass the replies
- if(size) { *size = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssReadResults(uint8_t* result, uint16_t size) {
- RADIOLIB_ASSERT_PTR(result);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS, false, result, size));
-}
-
-int16_t LR11x0::gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc) {
- uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = {
- RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID,
- (uint8_t)((date >> 8) & 0xFF), (uint8_t)(date & 0xFF),
- (uint8_t)((globalCrc >> 24) & 0xFF), (uint8_t)((globalCrc >> 16) & 0xFF),
- (uint8_t)((globalCrc >> 8) & 0xFF), (uint8_t)(globalCrc & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac) {
- uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = { svn };
- memcpy(&buff[1], svnAlmanac, RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE - 1);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssAlmanacReadAddrSize(uint32_t* addr, uint16_t* size) {
- uint8_t buff[6] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE, false, buff, sizeof(buff));
-
- if(addr) { *addr = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; }
- if(size) { *size = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssAlmanacReadSV(uint8_t svId, uint8_t* almanac) {
- uint8_t reqBuff[2] = { svId, 0x01 }; // in theory multiple SV entries can be read at the same time, but we don't need that
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE, false, almanac, 22, reqBuff, sizeof(reqBuff));
- RADIOLIB_ASSERT(state);
- return(state);
-}
-
-int16_t LR11x0::gnssGetNbSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv) {
- uint16_t latRaw = (lat*2048.0f)/90.0f + 0.5f;
- uint16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f;
- uint8_t reqBuff[9] = {
- (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF),
- (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF),
- (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF),
- (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF),
- constellation,
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff)));
-}
-
-int16_t LR11x0::gnssGetSvVisible(uint8_t nbSv, uint8_t** svId, int16_t** doppler, int16_t** dopplerErr) {
- // enforce a maximum of 12 SVs
- if(nbSv > 12) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
-
- uint8_t buff[60] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER, false, buff, sizeof(buff));
- for(uint8_t i = 0; i < nbSv; i++) {
- if(svId && svId[i]) { *svId[i] = buff[i*12]; }
- if(doppler && doppler[i]) { *doppler[i] = ((uint16_t)(buff[i*12 + 1]) << 8) | (uint16_t)buff[i*12 + 2]; }
- if(dopplerErr && dopplerErr[i]) { *dopplerErr[i] = ((uint16_t)(buff[i*12 + 3]) << 8) | (uint16_t)buff[i*12 + 4]; }
- }
-
- return(state);
-}
-
-int16_t LR11x0::gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) {
- uint8_t buff[3] = { effort, resMask, nbSvMax };
- // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts
- return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_SCAN, buff, sizeof(buff), false, false));
-}
-
-int16_t LR11x0::gnssReadLastScanModeLaunched(uint8_t* lastScanMode) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED, false, buff, sizeof(buff));
-
- // pass the replies
- if(lastScanMode) { *lastScanMode = buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssFetchTime(uint8_t effort, uint8_t opt) {
- uint8_t buff[2] = { effort, opt };
- // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts
- return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME, buff, sizeof(buff), false, false));
-}
-
-int16_t LR11x0::gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy) {
- uint8_t buff[12] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_TIME, false, buff, sizeof(buff));
-
- // pass the replies
- if(err) { *err = buff[0]; }
-
- if(time) {
- *time = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4];
- *time += 2UL*1024UL*7UL*24UL*3600UL; // assume WN rollover is at 2, this will fail sometime in 2038
- *time += 315964800UL; // convert to UTC
- }
-
- if(nbUs) {
- *nbUs = ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7];
- *nbUs /= 16;
- }
-
- if(timeAccuracy) {
- *timeAccuracy = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11];
- *timeAccuracy /= 16;
- }
-
- return(state);
-}
-
-int16_t LR11x0::gnssResetTime(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME, true, NULL, 0));
-}
-
-int16_t LR11x0::gnssResetPosition(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION, true, NULL, 0));
-}
-
-int16_t LR11x0::gnssReadWeekNumberRollover(uint8_t* status, uint8_t* rollover) {
- uint8_t buff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER, false, buff, sizeof(buff));
- if(status) { *status = buff[0]; }
- if(rollover) { *rollover = buff[1]; }
- return(state);
-}
-
-int16_t LR11x0::gnssReadDemodStatus(int8_t* status, uint8_t* info) {
- uint8_t buff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS, false, buff, sizeof(buff));
-
- // pass the replies
- if(status) { *status = (int8_t)buff[0]; }
- if(info) { *info = buff[1]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod) {
- uint8_t rplBuff[125] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING, false, rplBuff, 125);
- RADIOLIB_ASSERT(state);
-
- // convert endians
- if(timing) {
- for(size_t i = 0; i < 31; i++) {
- timing[i] = ((uint32_t)rplBuff[i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[1 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[3 + i*sizeof(uint32_t)];
- }
- }
-
- if(constDemod) { *constDemod = rplBuff[124]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssSetTime(uint32_t time, uint16_t accuracy) {
- uint8_t buff[6] = {
- (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF),
- (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF),
- (uint8_t)((accuracy >> 8) & 0xFF), (uint8_t)(accuracy & 0xFF),
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_TIME, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, float* lat, float* lon, uint16_t* accuracy, uint16_t* xtal, float* latFilt, float* lonFilt, uint16_t* accuracyFilt, uint16_t* xtalFilt) {
- uint8_t buff[18] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES, false, buff, sizeof(buff));
-
- // pass the replies
- if(error) { *error = buff[0]; }
- if(nbSvUsed) { *nbSvUsed = buff[1]; }
- if(lat) {
- uint16_t latRaw = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3];
- *lat = ((float)latRaw * 90.0f)/2048.0f;
- }
- if(lon) {
- uint16_t lonRaw = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5];
- *lon = ((float)lonRaw * 180.0f)/2048.0f;
- }
- if(accuracy) { *accuracy = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; }
- if(xtal) { *xtal = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; }
- if(latFilt) {
- uint16_t latRaw = ((uint16_t)(buff[10]) << 8) | (uint16_t)buff[11];
- *latFilt = ((float)latRaw * 90.0f)/2048.0f;
- }
- if(lonFilt) {
- uint16_t lonRaw = ((uint16_t)(buff[12]) << 8) | (uint16_t)buff[13];
- *lonFilt = ((float)lonRaw * 180.0f)/2048.0f;
- }
- if(accuracyFilt) { *accuracyFilt = ((uint16_t)(buff[14]) << 8) | (uint16_t)buff[15]; }
- if(xtalFilt) { *xtalFilt = ((uint16_t)(buff[16]) << 8) | (uint16_t)buff[17]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssReadDelayResetAP(uint32_t* delay) {
- uint8_t buff[3] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP, false, buff, sizeof(buff));
-
- if(delay) { *delay = ((uint32_t)(buff[0]) << 16) | ((uint32_t)(buff[1]) << 8) | (uint32_t)buff[2]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask) {
- uint8_t buff[2] = { effort, bitMask };
- // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts
- return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT, buff, sizeof(buff), false, false));
-}
-
-int16_t LR11x0::gnssReadKeepSyncStatus(uint8_t mask, uint8_t* nbSvVisible, uint32_t* elapsed) {
- uint8_t reqBuff[1] = { mask };
- uint8_t rplBuff[5] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
- RADIOLIB_ASSERT(state);
- if(nbSvVisible) { *nbSvVisible = rplBuff[0]; }
- if(elapsed) { *elapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; }
- return(state);
-}
-
-int16_t LR11x0::gnssReadAlmanacStatus(uint8_t* status) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS, false, status, 53));
-}
-
-int16_t LR11x0::gnssConfigAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t period) {
- uint8_t buff[4] = { bitMask, svType, (uint8_t)((period >> 8) & 0xFF), (uint8_t)(period & 0xFF) };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssReadAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t* period) {
- uint8_t reqBuff[2] = { bitMask, svType };
- uint8_t rplBuff[2] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
- RADIOLIB_ASSERT(state);
-
- if(period) { *period = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssConfigDelayResetAP(uint32_t delay) {
- uint8_t buff[3] = { (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSat) {
- uint8_t reqBuff[1] = { bitMask };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START, false, sv, nbVisSat, reqBuff, sizeof(reqBuff)));
-}
-
-int16_t LR11x0::gnssGetSvSync(uint8_t mask, uint8_t nbSv, uint8_t* syncList) {
- uint8_t reqBuff[2] = { mask, nbSv };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC, false, syncList, nbSv, reqBuff, sizeof(reqBuff)));
-}
-
-int16_t LR11x0::gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed) {
- uint8_t reqBuff[1] = { bitMask };
- uint8_t rplBuff[5] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
- RADIOLIB_ASSERT(state);
-
- if(nbVisSat) { *nbVisSat = rplBuff[0]; }
- if(timeElapsed) { *timeElapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; }
-
- return(state);
-}
-
-int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1) {
- uint8_t reqBuff[1] = { bitMask };
- uint8_t rplBuff[8] = { 0 };
- size_t rplLen = (bitMask & 0x01) ? 8 : 4; // GPS only has the first bit mask
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED, false, rplBuff, rplLen, reqBuff, sizeof(reqBuff));
- RADIOLIB_ASSERT(state);
-
- if(bitMaskActivated0) { *bitMaskActivated0 = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; }
- if(bitMaskActivated1) { *bitMaskActivated1 = ((uint32_t)(rplBuff[4]) << 24) | ((uint32_t)(rplBuff[5]) << 16) | ((uint32_t)(rplBuff[6]) << 8) | (uint32_t)rplBuff[7]; }
-
- return(state);
-}
-
-void LR11x0::gnssAbort() {
- // send the abort signal (single NOP)
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
- // we need to call the most basic overload of the SPI write method otherwise the call will be ambiguous
- uint8_t cmd[2] = { 0, 0 };
- this->mod->SPIwriteStream(cmd, 2, NULL, 0, false, false);
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16;
-
- // wait for at least 2.9 seconds as specified by the user manual
- this->mod->hal->delay(3000);
-}
-
-int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) {
- RADIOLIB_ASSERT_PTR(key);
- uint8_t buff[1 + RADIOLIB_AES128_KEY_SIZE] = { 0 };
- buff[0] = keyId;
- memcpy(&buff[1], key, RADIOLIB_AES128_KEY_SIZE);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY, false, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key) {
- RADIOLIB_ASSERT_PTR(key);
- uint8_t buff[2 + RADIOLIB_AES128_KEY_SIZE] = { 0 };
- buff[0] = srcKeyId;
- buff[1] = dstKeyId;
- memcpy(&buff[2], key, RADIOLIB_AES128_KEY_SIZE);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY, false, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, uint8_t* header, uint8_t* dataIn, size_t len, uint8_t* dataOut) {
- // calculate buffer sizes
- size_t headerLen = 1;
- if(lwVer) {
- headerLen += 11; // LoRaWAN 1.1 header is 11 bytes longer than 1.0
- }
- size_t reqLen = 3*sizeof(uint8_t) + headerLen + len;
- size_t rplLen = sizeof(uint8_t) + len;
-
- // build buffers
- #if RADIOLIB_STATIC_ONLY
- uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* reqBuff = new uint8_t[reqLen];
- uint8_t* rplBuff = new uint8_t[rplLen];
- #endif
-
- // set the request fields
- reqBuff[0] = decKeyId;
- reqBuff[1] = verKeyId;
- reqBuff[2] = lwVer;
- memcpy(&reqBuff[3], header, headerLen);
- memcpy(&reqBuff[3 + headerLen], dataIn, len);
-
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT, false, rplBuff, rplLen, reqBuff, reqLen);
- #if !RADIOLIB_STATIC_ONLY
- delete[] reqBuff;
- #endif
- if(state != RADIOLIB_ERR_NONE) {
- #if !RADIOLIB_STATIC_ONLY
- delete[] rplBuff;
- #endif
- return(state);
- }
-
- // check the crypto engine state
- if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) {
- RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]);
- #if !RADIOLIB_STATIC_ONLY
- delete[] rplBuff;
- #endif
- return(RADIOLIB_ERR_SPI_CMD_FAILED);
- }
-
- // pass the data
- memcpy(dataOut, &rplBuff[1], len);
- #if !RADIOLIB_STATIC_ONLY
- delete[] rplBuff;
- #endif
- return(state);
-}
-
-int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, uint8_t* data, size_t len, uint32_t* mic) {
- size_t reqLen = sizeof(uint8_t) + len;
- #if RADIOLIB_STATIC_ONLY
- uint8_t reqBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* reqBuff = new uint8_t[reqLen];
- #endif
- uint8_t rplBuff[5] = { 0 };
-
- reqBuff[0] = keyId;
- memcpy(&reqBuff[1], data, len);
-
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen);
- #if !RADIOLIB_STATIC_ONLY
- delete[] reqBuff;
- #endif
-
- // check the crypto engine state
- if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) {
- RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]);
- return(RADIOLIB_ERR_SPI_CMD_FAILED);
- }
-
- if(mic) { *mic = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; }
- return(state);
-}
-
-int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, uint8_t* data, size_t len, bool* result) {
- size_t reqLen = sizeof(uint8_t) + sizeof(uint32_t) + len;
- #if RADIOLIB_STATIC_ONLY
- uint8_t reqBuff[sizeof(uint8_t) + sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* reqBuff = new uint8_t[reqLen];
- #endif
- uint8_t rplBuff[1] = { 0 };
-
- reqBuff[0] = keyId;
- reqBuff[1] = (uint8_t)((micExp >> 24) & 0xFF);
- reqBuff[2] = (uint8_t)((micExp >> 16) & 0xFF);
- reqBuff[3] = (uint8_t)((micExp >> 8) & 0xFF);
- reqBuff[4] = (uint8_t)(micExp & 0xFF);
- memcpy(&reqBuff[5], data, len);
-
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen);
- #if !RADIOLIB_STATIC_ONLY
- delete[] reqBuff;
- #endif
-
- // check the crypto engine state
- if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) {
- RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]);
- return(RADIOLIB_ERR_SPI_CMD_FAILED);
- }
-
- if(result) { *result = (rplBuff[0] == RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS); }
- return(state);
-}
-
-int16_t LR11x0::cryptoAesEncrypt01(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) {
- return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01, keyId, dataIn, len, dataOut));
-}
-
-int16_t LR11x0::cryptoAesEncrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) {
- return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT, keyId, dataIn, len, dataOut));
-}
-
-int16_t LR11x0::cryptoAesDecrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) {
- return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT, keyId, dataIn, len, dataOut));
-}
-
-int16_t LR11x0::cryptoStoreToFlash(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH, true, NULL, 0));
-}
-
-int16_t LR11x0::cryptoRestoreFromFlash(void) {
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH, true, NULL, 0));
-}
-
-int16_t LR11x0::cryptoSetParam(uint8_t id, uint32_t value) {
- uint8_t buff[5] = {
- id,
- (uint8_t)((value >> 24) & 0xFF), (uint8_t)((value >> 16) & 0xFF),
- (uint8_t)((value >> 8) & 0xFF), (uint8_t)(value & 0xFF)
- };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::cryptoGetParam(uint8_t id, uint32_t* value) {
- uint8_t reqBuff[1] = { id };
- uint8_t rplBuff[4] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
- RADIOLIB_ASSERT(state);
- if(value) { *value = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; }
- return(state);
-}
-
-int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile) {
- // check maximum size
- if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
- return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile));
-}
-
-int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) {
- uint8_t buff[1] = { 0 };
- int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT, false, buff, sizeof(buff));
-
- // pass the replies
- if(result) { *result = (bool)buff[0]; }
-
- return(state);
-}
-
-int16_t LR11x0::bootEraseFlash(void) {
- // erasing flash takes about 2.5 seconds, temporarily tset SPI timeout to 3 seconds
- RadioLibTime_t timeout = this->mod->spiConfig.timeout;
- this->mod->spiConfig.timeout = 3000;
- int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, NULL, 0, false, false);
- this->mod->spiConfig.timeout = timeout;
- return(state);
-}
-
-int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile) {
- // check maximum size
- if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
- return(RADIOLIB_ERR_SPI_CMD_INVALID);
- }
- return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile));
-}
-
-int16_t LR11x0::bootReboot(bool stay) {
- uint8_t buff[1] = { (uint8_t)stay };
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_REBOOT, true, buff, sizeof(buff)));
-}
-
-int16_t LR11x0::bootGetPin(uint8_t* pin) {
- RADIOLIB_ASSERT_PTR(pin);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN));
-}
-
-int16_t LR11x0::bootGetChipEui(uint8_t* eui) {
- RADIOLIB_ASSERT_PTR(eui);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
-}
-
-int16_t LR11x0::bootGetJoinEui(uint8_t* eui) {
- RADIOLIB_ASSERT_PTR(eui);
- return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
-}
-
-int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) {
- // build buffers - later we need to ensure endians are correct,
- // so there is probably no way to do this without copying buffers and iterating
- size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t);
- #if RADIOLIB_STATIC_ONLY
- uint8_t dataBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* dataBuff = new uint8_t[buffLen];
- #endif
-
- // set the address or offset
- dataBuff[0] = (uint8_t)((addrOffset >> 24) & 0xFF);
- dataBuff[1] = (uint8_t)((addrOffset >> 16) & 0xFF);
- dataBuff[2] = (uint8_t)((addrOffset >> 8) & 0xFF);
- dataBuff[3] = (uint8_t)(addrOffset & 0xFF);
-
- // convert endians
- for(size_t i = 0; i < len; i++) {
- uint32_t bin = 0;
- if(nonvolatile) {
- bin = RADIOLIB_NONVOLATILE_READ_DWORD(data + i);
- } else {
- bin = data[i];
- }
- dataBuff[4 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 24) & 0xFF);
- dataBuff[5 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 16) & 0xFF);
- dataBuff[6 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 8) & 0xFF);
- dataBuff[7 + i*sizeof(uint32_t)] = (uint8_t)(bin & 0xFF);
- }
-
- int16_t state = this->mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false);
- #if !RADIOLIB_STATIC_ONLY
- delete[] dataBuff;
- #endif
- return(state);
-}
-
-int16_t LR11x0::cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) {
- // build buffers
- #if RADIOLIB_STATIC_ONLY
- uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
- #else
- uint8_t* reqBuff = new uint8_t[sizeof(uint8_t) + len];
- uint8_t* rplBuff = new uint8_t[sizeof(uint8_t) + len];
- #endif
-
- // set the request fields
- reqBuff[0] = keyId;
- memcpy(&reqBuff[1], dataIn, len);
-
- int16_t state = this->SPIcommand(cmd, false, rplBuff, sizeof(uint8_t) + len, reqBuff, sizeof(uint8_t) + len);
- #if !RADIOLIB_STATIC_ONLY
- delete[] reqBuff;
- #endif
- if(state != RADIOLIB_ERR_NONE) {
- #if !RADIOLIB_STATIC_ONLY
- delete[] rplBuff;
- #endif
- return(state);
- }
-
- // check the crypto engine state
- if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) {
- RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]);
- return(RADIOLIB_ERR_SPI_CMD_FAILED);
- }
-
- // pass the data
- memcpy(dataOut, &rplBuff[1], len);
- #if !RADIOLIB_STATIC_ONLY
- delete[] rplBuff;
- #endif
- return(state);
-}
-
#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR11x0.h b/lib/RadioLib/src/modules/LR11x0/LR11x0.h
index 42685a9..0a7fee3 100644
--- a/lib/RadioLib/src/modules/LR11x0/LR11x0.h
+++ b/lib/RadioLib/src/modules/LR11x0/LR11x0.h
@@ -7,7 +7,11 @@
#include "../../Module.h"
-#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
+#include "../LR11x0/LR_common.h"
+
+#include "LR11x0_commands.h"
+#include "LR11x0_registers.h"
+#include "LR11x0_types.h"
// LR11X0 physical layer properties
#define RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE 1.0
@@ -15,868 +19,18 @@
#define RADIOLIB_LR11X0_CRYSTAL_FREQ 32.0
#define RADIOLIB_LR11X0_DIV_EXPONENT 25
-// LR11X0 SPI commands
-#define RADIOLIB_LR11X0_CMD_NOP (0x0000)
-#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM (0x0105)
-#define RADIOLIB_LR11X0_CMD_READ_REG_MEM (0x0106)
-#define RADIOLIB_LR11X0_CMD_WRITE_BUFFER (0x0109)
-#define RADIOLIB_LR11X0_CMD_READ_BUFFER (0x010A)
-#define RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER (0x010B)
-#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK (0x010C)
-#define RADIOLIB_LR11X0_CMD_GET_STATUS (0x0100)
-#define RADIOLIB_LR11X0_CMD_GET_VERSION (0x0101)
-#define RADIOLIB_LR11X0_CMD_GET_ERRORS (0x010D)
-#define RADIOLIB_LR11X0_CMD_CLEAR_ERRORS (0x010E)
-#define RADIOLIB_LR11X0_CMD_CALIBRATE (0x010F)
-#define RADIOLIB_LR11X0_CMD_SET_REG_MODE (0x0110)
-#define RADIOLIB_LR11X0_CMD_CALIB_IMAGE (0x0111)
-#define RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH (0x0112)
-#define RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS (0x0113)
-#define RADIOLIB_LR11X0_CMD_CLEAR_IRQ (0x0114)
-#define RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK (0x0116)
-#define RADIOLIB_LR11X0_CMD_SET_TCXO_MODE (0x0117)
-#define RADIOLIB_LR11X0_CMD_REBOOT (0x0118)
-#define RADIOLIB_LR11X0_CMD_GET_VBAT (0x0119)
-#define RADIOLIB_LR11X0_CMD_GET_TEMP (0x011A)
-#define RADIOLIB_LR11X0_CMD_SET_SLEEP (0x011B)
-#define RADIOLIB_LR11X0_CMD_SET_STANDBY (0x011C)
-#define RADIOLIB_LR11X0_CMD_SET_FS (0x011D)
-#define RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER (0x0120)
-#define RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE (0x0121)
-#define RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE (0x0122)
-#define RADIOLIB_LR11X0_CMD_READ_INFO_PAGE (0x0123)
-#define RADIOLIB_LR11X0_CMD_GET_CHIP_EUI (0x0125)
-#define RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI (0x0126)
-#define RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN (0x0127)
-#define RADIOLIB_LR11X0_CMD_ENABLE_SPI_CRC (0x0128)
-#define RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE (0x012A)
-#define RADIOLIB_LR11X0_CMD_RESET_STATS (0x0200)
-#define RADIOLIB_LR11X0_CMD_GET_STATS (0x0201)
-#define RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE (0x0202)
-#define RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS (0x0203)
-#define RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS (0x0204)
-#define RADIOLIB_LR11X0_CMD_GET_RSSI_INST (0x0205)
-#define RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD (0x0206)
-#define RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK (0x0208)
-#define RADIOLIB_LR11X0_CMD_SET_RX (0x0209)
-#define RADIOLIB_LR11X0_CMD_SET_TX (0x020A)
-#define RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY (0x020B)
-#define RADIOLIB_LR11X0_CMD_AUTO_TX_RX (0x020C)
-#define RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS (0x020D)
-#define RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE (0x020E)
-#define RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS (0x020F)
-#define RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS (0x0210)
-#define RADIOLIB_LR11X0_CMD_SET_TX_PARAMS (0x0211)
-#define RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS (0x0212)
-#define RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE (0x0213)
-#define RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE (0x0214)
-#define RADIOLIB_LR11X0_CMD_SET_PA_CONFIG (0x0215)
-#define RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE (0x0217)
-#define RADIOLIB_LR11X0_CMD_SET_CAD (0x0218)
-#define RADIOLIB_LR11X0_CMD_SET_TX_CW (0x0219)
-#define RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE (0x021A)
-#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT (0x021B)
-#define RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR (0x021C)
-#define RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR (0x021D)
-#define RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT (0x021E)
-#define RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY (0x021F)
-#define RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS (0x0224)
-#define RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS (0x0225)
-#define RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED (0x0227)
-#define RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER (0x0228)
-#define RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION (0x0229)
-#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD (0x022B)
-#define RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME (0x022C)
-#define RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD (0x022D)
-#define RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON (0x022E)
-#define RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS (0x0230)
-#define RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND (0x0231)
-#define RADIOLIB_LR11X0_CMD_WIFI_SCAN (0x0300)
-#define RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT (0x0301)
-#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE (0x0302)
-#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT (0x0303)
-#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS (0x0305)
-#define RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS (0x0306)
-#define RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS (0x0307)
-#define RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS (0x0308)
-#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS (0x0309)
-#define RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS (0x030A)
-#define RADIOLIB_LR11X0_CMD_WIFI_CFG_TIMESTAMP_AP_PHONE (0x030B)
-#define RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION (0x0320)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI (0x0222)
-#define RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE (0x0400)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE (0x0401)
-#define RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE (0x0402)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE (0x0403)
-#define RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE (0x0404)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE (0x0405)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION (0x0406)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS (0x0407)
-#define RADIOLIB_LR11X0_CMD_GNSS_SET_MODE (0x0408)
-#define RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS (0x0409)
-#define RADIOLIB_LR11X0_CMD_GNSS_ASSISTED (0x040A)
-#define RADIOLIB_LR11X0_CMD_GNSS_SCAN (0x040B)
-#define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D)
-#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E)
-#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE (0x040F)
-#define RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION (0x0410)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION (0x0411)
-#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG (0x0414)
-#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG (0x0415)
-#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS (0x0416)
-#define RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED (0x0417)
-#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED (0x0418)
-#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION (0x0419)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE (0x041A)
-#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE (0x041F)
-#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER (0x0420)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED (0x0426)
-#define RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME (0x0432)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_TIME (0x0434)
-#define RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME (0x0435)
-#define RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION (0x0437)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER (0x0438)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS (0x0439)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING (0x044A)
-#define RADIOLIB_LR11X0_CMD_GNSS_SET_TIME (0x044B)
-#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP (0x044D)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES (0x044F)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP (0x0453)
-#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT (0x0454)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS (0x0456)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS (0x0457)
-#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD (0x0463)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD (0x0464)
-#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START (0x0466)
-#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC (0x0466)
-#define RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS (0x0469)
-#define RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED (0x0472)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY (0x0502)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY (0x0503)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT (0x0504)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC (0x0505)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC (0x0506)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01 (0x0507)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT (0x0508)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT (0x0509)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH (0x050A)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH (0x050B)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM (0x050D)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM (0x050E)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE (0x050F)
-#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT (0x0510)
-#define RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH (0x8000)
-#define RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED (0x8003)
-#define RADIOLIB_LR11X0_CMD_BOOT_REBOOT (0x8005)
-#define RADIOLIB_LR11X0_CMD_BOOT_GET_PIN (0x800B)
-#define RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI (0x800C)
-#define RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI (0x800D)
-
-// LR11X0 register map
-#define RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT (0x00F20414)
-#define RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX (0x00F30054)
-#define RADIOLIB_LR11X0_REG_LNA_MODE (0x00F3008C)
-// TODO add fix for br 600/1200 bps
-
-// LR11X0 SPI command variables
-
-// RADIOLIB_LR11X0_CMD_GET_STATUS MSB LSB DESCRIPTION
-#define RADIOLIB_LR11X0_STAT_1_CMD_FAIL (0x00UL << 1) // 3 1 command status: last command could not be executed
-#define RADIOLIB_LR11X0_STAT_1_CMD_PERR (0x01UL << 1) // 3 1 processing error
-#define RADIOLIB_LR11X0_STAT_1_CMD_OK (0x02UL << 1) // 3 1 successfully processed
-#define RADIOLIB_LR11X0_STAT_1_CMD_DAT (0x03UL << 1) // 3 1 successfully processed, data is being transmitted
-#define RADIOLIB_LR11X0_STAT_1_IRQ_INACTIVE (0x00UL << 0) // 0 0 interrupt status: inactive
-#define RADIOLIB_LR11X0_STAT_1_IRQ_ACTIVE (0x01UL << 0) // 0 0 at least 1 interrupt active
-#define RADIOLIB_LR11X0_STAT_2_CMD_RST_CLEARED (0x00UL << 4) // 7 4 reset status: cleared
-#define RADIOLIB_LR11X0_STAT_2_CMD_RST_ANALOG (0x01UL << 4) // 7 4 analog (power on, brown-out)
-#define RADIOLIB_LR11X0_STAT_2_CMD_RST_EXTERNAL (0x02UL << 4) // 7 4 NRESET pin
-#define RADIOLIB_LR11X0_STAT_2_CMD_RST_SYSTEM (0x03UL << 4) // 7 4 system
-#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WATCHDOG (0x04UL << 4) // 7 4 watchdog
-#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WAKEUP (0x05UL << 4) // 7 4 NSS toggling wake-up
-#define RADIOLIB_LR11X0_STAT_2_CMD_RST_RTC (0x06UL << 4) // 7 4 realtime clock
-#define RADIOLIB_LR11X0_STAT_2_MODE_SLEEP (0x00UL << 1) // 3 1 chip mode: sleep
-#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_RC (0x01UL << 1) // 3 1 standby with RC oscillator
-#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_OSC (0x02UL << 1) // 3 1 standby with external oscillator
-#define RADIOLIB_LR11X0_STAT_2_MODE_FS (0x03UL << 1) // 3 1 frequency synthesis
-#define RADIOLIB_LR11X0_STAT_2_MODE_RX (0x04UL << 1) // 3 1 receive
-#define RADIOLIB_LR11X0_STAT_2_MODE_TX (0x05UL << 1) // 3 1 transmit
-#define RADIOLIB_LR11X0_STAT_2_MODE_WIFI_GNSS (0x06UL << 1) // 3 1 WiFi or GNSS geolocation
-#define RADIOLIB_LR11X0_STAT_2_BOOT (0x00UL << 0) // 0 0 code executed from: bootloader
-#define RADIOLIB_LR11X0_STAT_2_FLASH (0x01UL << 0) // 0 0 flash
-
-// RADIOLIB_LR11X0_CMD_WRITE_REG_MEM
-#define RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN (256) // 7 0 maximum length of read/write SPI payload in bytes
-
-// RADIOLIB_LR11X0_CMD_GET_VERSION
-#define RADIOLIB_LR11X0_DEVICE_LR1110 (0x01UL << 0) // 7 0 HW device: LR1110
-#define RADIOLIB_LR11X0_DEVICE_LR1120 (0x02UL << 0) // 7 0 LR1120
-#define RADIOLIB_LR11X0_DEVICE_LR1121 (0x03UL << 0) // 7 0 LR1121
-#define RADIOLIB_LR11X0_DEVICE_BOOT (0xDFUL << 0) // 7 0 bootloader mode
-
-// RADIOLIB_LR11X0_CMD_GET_ERRORS
-#define RADIOLIB_LR11X0_ERROR_STAT_LF_RC_CALIB_ERR (0x01UL << 0) // 15 0 error: low frequency RC not calibrated
-#define RADIOLIB_LR11X0_ERROR_STAT_HF_RC_CALIB_ERR (0x01UL << 1) // 15 0 high frequency RC not calibrated
-#define RADIOLIB_LR11X0_ERROR_STAT_ADC_CALIB_ERR (0x01UL << 2) // 15 0 ADC not calibrated
-#define RADIOLIB_LR11X0_ERROR_STAT_PLL_CALIB_ERR (0x01UL << 3) // 15 0 PLL not calibrated
-#define RADIOLIB_LR11X0_ERROR_STAT_IMG_CALIB_ERR (0x01UL << 4) // 15 0 image rejection not calibrated
-#define RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR (0x01UL << 5) // 15 0 high frequency oscillator failed to start
-#define RADIOLIB_LR11X0_ERROR_STAT_LF_XOSC_START_ERR (0x01UL << 6) // 15 0 low frequency oscillator failed to start
-#define RADIOLIB_LR11X0_ERROR_STAT_PLL_LOCK_ERR (0x01UL << 7) // 15 0 PLL failed to lock
-#define RADIOLIB_LR11X0_ERROR_STAT_RX_ADC_OFFSET_ERR (0x01UL << 8) // 15 0 ADC offset not calibrated
-
-// RADIOLIB_LR11X0_CMD_CALIBRATE
-#define RADIOLIB_LR11X0_CALIBRATE_PLL_TX (0x01UL << 5) // 5 5 calibrate: Tx PLL
-#define RADIOLIB_LR11X0_CALIBRATE_IMG (0x01UL << 4) // 4 4 image rejection
-#define RADIOLIB_LR11X0_CALIBRATE_ADC (0x01UL << 3) // 3 3 A/D converter
-#define RADIOLIB_LR11X0_CALIBRATE_PLL (0x01UL << 2) // 2 2 PLL
-#define RADIOLIB_LR11X0_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high frequency RC
-#define RADIOLIB_LR11X0_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 low frequency RC
-#define RADIOLIB_LR11X0_CALIBRATE_ALL (0x3FUL << 0) // 5 0 everything
-#define RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG_MHZ (20.0)
-
-// RADIOLIB_LR11X0_CMD_SET_REG_MODE
-#define RADIOLIB_LR11X0_REG_MODE_LDO (0x00UL << 0) // 0 0 regulator mode: LDO in all modes
-#define RADIOLIB_LR11X0_REG_MODE_DC_DC (0x01UL << 0) // 0 0 DC-DC and LDO
-
-// RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH
-#define RADIOLIB_LR11X0_RFSW_DIO5_ENABLED (0x01UL << 0) // 4 0 RF switch: DIO5 enabled
-#define RADIOLIB_LR11X0_RFSW_DIO5_DISABLED (0x00UL << 0) // 4 0 DIO5 disabled (default)
-#define RADIOLIB_LR11X0_RFSW_DIO6_ENABLED (0x01UL << 1) // 4 0 RF switch: DIO6 enabled
-#define RADIOLIB_LR11X0_RFSW_DIO6_DISABLED (0x00UL << 1) // 4 0 DIO6 disabled (default)
-#define RADIOLIB_LR11X0_RFSW_DIO7_ENABLED (0x01UL << 2) // 4 0 RF switch: DIO7 enabled
-#define RADIOLIB_LR11X0_RFSW_DIO7_DISABLED (0x00UL << 2) // 4 0 DIO7 disabled (default)
-#define RADIOLIB_LR11X0_RFSW_DIO8_ENABLED (0x01UL << 3) // 4 0 RF switch: DIO8 enabled
-#define RADIOLIB_LR11X0_RFSW_DIO8_DISABLED (0x00UL << 3) // 4 0 DIO8 disabled (default)
-#define RADIOLIB_LR11X0_RFSW_DIO10_ENABLED (0x01UL << 4) // 4 0 RF switch: DIO10 enabled
-#define RADIOLIB_LR11X0_RFSW_DIO10_DISABLED (0x00UL << 4) // 4 0 DIO10 disabled (default)
-#define RADIOLIB_LR11X0_DIOx(X) ((X) | RFSWITCH_PIN_FLAG)
-#define RADIOLIB_LR11X0_DIOx_VAL(X) ((X) & ~RFSWITCH_PIN_FLAG)
-#define RADIOLIB_LR11X0_DIO5 (RADIOLIB_LR11X0_DIOx(0))
-#define RADIOLIB_LR11X0_DIO6 (RADIOLIB_LR11X0_DIOx(1))
-#define RADIOLIB_LR11X0_DIO7 (RADIOLIB_LR11X0_DIOx(2))
-#define RADIOLIB_LR11X0_DIO8 (RADIOLIB_LR11X0_DIOx(3))
-#define RADIOLIB_LR11X0_DIO10 (RADIOLIB_LR11X0_DIOx(4))
-
-// RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS
-#define RADIOLIB_LR11X0_IRQ_TX_DONE (0x01UL << 2) // 31 0 interrupt: packet transmitted
-#define RADIOLIB_LR11X0_IRQ_RX_DONE (0x01UL << 3) // 31 0 packet received
-#define RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED (0x01UL << 4) // 31 0 preamble detected
-#define RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID (0x01UL << 5) // 31 0 sync word or LoRa header valid
-#define RADIOLIB_LR11X0_IRQ_HEADER_ERR (0x01UL << 6) // 31 0 LoRa header CRC error
-#define RADIOLIB_LR11X0_IRQ_CRC_ERR (0x01UL << 7) // 31 0 packet CRC error
-#define RADIOLIB_LR11X0_IRQ_CAD_DONE (0x01UL << 8) // 31 0 CAD completed
-#define RADIOLIB_LR11X0_IRQ_CAD_DETECTED (0x01UL << 9) // 31 0 CAD detected
-#define RADIOLIB_LR11X0_IRQ_TIMEOUT (0x01UL << 10) // 31 0 Rx or Tx timeout
-#define RADIOLIB_LR11X0_IRQ_LR_FHSS_HOP (0x01UL << 11) // 31 0 FHSS hop
-#define RADIOLIB_LR11X0_IRQ_GNSS_DONE (0x01UL << 19) // 31 0 GNSS scan finished
-#define RADIOLIB_LR11X0_IRQ_WIFI_DONE (0x01UL << 20) // 31 0 WiFi scan finished
-#define RADIOLIB_LR11X0_IRQ_LBD (0x01UL << 21) // 31 0 low battery detected
-#define RADIOLIB_LR11X0_IRQ_CMD_ERROR (0x01UL << 22) // 31 0 command error
-#define RADIOLIB_LR11X0_IRQ_ERROR (0x01UL << 23) // 31 0 some other error than CMD_ERR
-#define RADIOLIB_LR11X0_IRQ_FSK_LEN_ERROR (0x01UL << 24) // 31 0 FSK packet received with length error
-#define RADIOLIB_LR11X0_IRQ_FSK_ADDR_ERROR (0x01UL << 25) // 31 0 FSK packet received with address error
-#define RADIOLIB_LR11X0_IRQ_LORA_RX_TIMESTAMP (0x01UL << 27) // 31 0 last LoRa symbol was received (timestamp source)
-#define RADIOLIB_LR11X0_IRQ_GNSS_ABORT (0x01UL << 28) // 31 0 GNSS scan aborted
-#define RADIOLIB_LR11X0_IRQ_ALL (0x1BF80FFCUL) // 31 0 all interrupts
-#define RADIOLIB_LR11X0_IRQ_NONE (0x00UL << 0) // 31 0 no interrupts
-
-// RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK
-#define RADIOLIB_LR11X0_LF_CLK_RC (0x00UL << 0) // 1 0 32.768 kHz source: RC oscillator
-#define RADIOLIB_LR11X0_LF_CLK_XOSC (0x01UL << 0) // 1 0 crystal oscillator
-#define RADIOLIB_LR11X0_LF_CLK_EXT (0x02UL << 0) // 1 0 external signal on DIO11
-#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED (0x00UL << 2) // 2 2
-#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_ENABLED (0x01UL << 2) // 2 2
-
-// RADIOLIB_LR11X0_CMD_SET_TCXO_MODE
-#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6 (0x00UL << 0) // 2 0 TCXO supply voltage: 1.6V
-#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7 (0x01UL << 0) // 2 0 1.7V
-#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8 (0x02UL << 0) // 2 0 1.8V
-#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2 (0x03UL << 0) // 2 0 2.2V
-#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4 (0x04UL << 0) // 2 0 2.4V
-#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7 (0x05UL << 0) // 2 0 2.7V
-#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0 (0x06UL << 0) // 2 0 3.0V
-#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3 (0x07UL << 0) // 2 0 3.3V
-
-// RADIOLIB_LR11X0_CMD_SET_SLEEP
-#define RADIOLIB_LR11X0_SLEEP_RETENTION_DISABLED (0x00UL << 0) // 0 0 configuration retention in sleep mode: disabled
-#define RADIOLIB_LR11X0_SLEEP_RETENTION_ENABLED (0x01UL << 0) // 0 0 enabled
-#define RADIOLIB_LR11X0_SLEEP_WAKEUP_DISABLED (0x00UL << 0) // 1 1 automated wakeup: disabled
-#define RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED (0x01UL << 0) // 1 1 enabled
-
-// RADIOLIB_LR11X0_CMD_SET_STANDBY
-#define RADIOLIB_LR11X0_STANDBY_RC (0x00UL << 0) // 7 0 standby mode: RC oscillator
-#define RADIOLIB_LR11X0_STANDBY_XOSC (0x00UL << 0) // 7 0 XTAL/TCXO oscillator
-
-// RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE
-#define RADIOLIB_LR11X0_INFO_PAGE (1)
-
-// RADIOLIB_LR11X0_CMD_GET_CHIP_EUI
-#define RADIOLIB_LR11X0_EUI_LEN (8)
-
-// RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN
-#define RADIOLIB_LR11X0_PIN_LEN (4)
-
-// RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS
-#define RADIOLIB_LR11X0_RX_STATUS_ADDR_ERR (0x01UL << 5) // 7 0 Rx status: address filtering error
-#define RADIOLIB_LR11X0_RX_STATUS_CRC_ERR (0x01UL << 4) // 7 0 CRC error
-#define RADIOLIB_LR11X0_RX_STATUS_LEN_ERR (0x01UL << 3) // 7 0 length filtering error
-#define RADIOLIB_LR11X0_RX_STATUS_ABORTED (0x01UL << 2) // 7 0 packet reception aborted
-#define RADIOLIB_LR11X0_RX_STATUS_PACKET_RECEIVED (0x01UL << 1) // 7 0 packet received
-#define RADIOLIB_LR11X0_RX_STATUS_PACKET_SENT (0x01UL << 0) // 7 0 packet sent
-
-// RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD
-#define RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN (8)
-
-// RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK
-#define RADIOLIB_LR11X0_LORA_PRIVATE_NETWORK (0x00UL << 0) // 7 0 LoRa sync word: private network
-#define RADIOLIB_LR11X0_LORA_PUBLIC_NETWORK (0x01UL << 0) // 7 0 public network
-
-// RADIOLIB_LR11X0_CMD_SET_RX
-#define RADIOLIB_LR11X0_RX_TIMEOUT_NONE (0x000000UL) // 23 0 Rx timeout duration: no timeout (Rx single mode)
-#define RADIOLIB_LR11X0_RX_TIMEOUT_INF (0xFFFFFFUL) // 23 0 infinite (Rx continuous mode)
-
-// RADIOLIB_LR11X0_CMD_SET_TX
-#define RADIOLIB_LR11X0_TX_TIMEOUT_NONE (0x000000UL) // 23 0 disable Tx timeout
-
-// RADIOLIB_LR11X0_CMD_AUTO_TX_RX
-#define RADIOLIB_LR11X0_AUTO_TX_RX_DISABLED (0xFFFFFFUL) // 23 0 disable auto Tx/Rx mode
-#define RADIOLIB_LR11X0_AUTO_TX_RX_SKIP_INT (0x000000UL) // 23 0 skip intermediary mode
-#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_SLEEP (0x00UL << 0) // 1 0 intermediary mode: sleep
-#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_RC (0x01UL << 0) // 1 0 standby with RC
-#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC
-#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis
-#define RADIOLIB_LR11X0_AUTO_TX_RX_TIMEOUT_DISABLED (0x000000UL) // 23 0 disable timeout of the second mode
-
-// RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS
-#define RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC (0x00UL << 0) // 7 0 mode to set after CAD: standby with RC
-#define RADIOLIB_LR11X0_CAD_EXIT_MODE_RX (0x01UL << 0) // 7 0 receive if activity detected
-#define RADIOLIB_LR11X0_CAD_EXIT_MODE_LBT (0x10UL << 0) // 7 0 transmit if no activity detected
-#define RADIOLIB_LR11X0_CAD_PARAM_DEFAULT (0xFFUL << 0) // 7 0 used by the CAD methods to specify default parameter value
-
-// RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE
-#define RADIOLIB_LR11X0_PACKET_TYPE_NONE (0x00UL << 0) // 2 0 packet type: none
-#define RADIOLIB_LR11X0_PACKET_TYPE_GFSK (0x01UL << 0) // 2 0 (G)FSK
-#define RADIOLIB_LR11X0_PACKET_TYPE_LORA (0x02UL << 0) // 2 0 LoRa
-#define RADIOLIB_LR11X0_PACKET_TYPE_SIGFOX (0x03UL << 0) // 2 0 Sigfox
-#define RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS (0x04UL << 0) // 2 0 GMSK/LR-FHSS
-#define RADIOLIB_LR11X0_PACKET_TYPE_RANGING (0x05UL << 0) // 2 0 ranging
-#define RADIOLIB_LR11X0_PACKET_TYPE_BLE (0x06UL << 0) // 2 0 BLE beacon
-
-// RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS
-#define RADIOLIB_LR11X0_LORA_BW_62_5 (0x03UL << 0) // 7 0 LoRa bandwidth: 62.5 kHz
-#define RADIOLIB_LR11X0_LORA_BW_125_0 (0x04UL << 0) // 7 0 125.0 kHz
-#define RADIOLIB_LR11X0_LORA_BW_250_0 (0x05UL << 0) // 7 0 250.0 kHz
-#define RADIOLIB_LR11X0_LORA_BW_500_0 (0x06UL << 0) // 7 0 500.0 kHz
-#define RADIOLIB_LR11X0_LORA_BW_203_125 (0x0DUL << 0) // 7 0 203.0 kHz (2.4GHz only)
-#define RADIOLIB_LR11X0_LORA_BW_406_25 (0x0EUL << 0) // 7 0 406.0 kHz (2.4GHz only)
-#define RADIOLIB_LR11X0_LORA_BW_812_50 (0x0FUL << 0) // 7 0 812.0 kHz (2.4GHz only)
-#define RADIOLIB_LR11X0_LORA_CR_4_5_SHORT (0x01UL << 0) // 7 0 coding rate: 4/5 with short interleaver
-#define RADIOLIB_LR11X0_LORA_CR_4_6_SHORT (0x02UL << 0) // 7 0 4/6 with short interleaver
-#define RADIOLIB_LR11X0_LORA_CR_4_7_SHORT (0x03UL << 0) // 7 0 4/7 with short interleaver
-#define RADIOLIB_LR11X0_LORA_CR_4_8_SHORT (0x04UL << 0) // 7 0 4/8 with short interleaver
-#define RADIOLIB_LR11X0_LORA_CR_4_5_LONG (0x05UL << 0) // 7 0 4/5 with long interleaver
-#define RADIOLIB_LR11X0_LORA_CR_4_6_LONG (0x06UL << 0) // 7 0 4/6 with long interleaver
-#define RADIOLIB_LR11X0_LORA_CR_4_8_LONG (0x07UL << 0) // 7 0 4/8 with long interleaver
-#define RADIOLIB_LR11X0_LORA_LDRO_DISABLED (0x00UL << 0) // 7 0 low data rate optimize: disabled
-#define RADIOLIB_LR11X0_LORA_LDRO_ENABLED (0x01UL << 0) // 7 0 enabled
-#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_DISABLED (0x00UL << 31) // 31 0 divide bit rate value by 256: disabled
-#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_ENABLED (0x01UL << 31) // 31 0 enabled
-#define RADIOLIB_LR11X0_GFSK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none
-#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_3 (0x08UL << 0) // 7 0 Gaussian, BT = 0.3
-#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_5 (0x09UL << 0) // 7 0 Gaussian, BT = 0.5
-#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_7 (0x0AUL << 0) // 7 0 Gaussian, BT = 0.7
-#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 Gaussian, BT = 1.0
-#define RADIOLIB_LR11X0_GFSK_SHAPING_RAISED_COSINE_BT_0_7 (0x16UL << 0) // 7 0 raised cosine, BT = 0.7
-#define RADIOLIB_LR11X0_GFSK_RX_BW_4_8 (0x1FUL << 0) // 7 0 GFSK Rx bandwidth: 4.8 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_5_8 (0x17UL << 0) // 7 0 5.8 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_7_3 (0x0FUL << 0) // 7 0 7.3 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_9_7 (0x1EUL << 0) // 7 0 9.7 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_11_7 (0x16UL << 0) // 7 0 11.7 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_14_6 (0x0EUL << 0) // 7 0 14.6 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_19_5 (0x1DUL << 0) // 7 0 19.5 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_23_4 (0x15UL << 0) // 7 0 23.4 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_29_3 (0x0DUL << 0) // 7 0 29.3 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_39_0 (0x1CUL << 0) // 7 0 39.0 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_46_9 (0x14UL << 0) // 7 0 46.9 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_58_6 (0x0CUL << 0) // 7 0 58.6 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_78_2 (0x1BUL << 0) // 7 0 78.2 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_93_8 (0x13UL << 0) // 7 0 93.8 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_117_3 (0x0BUL << 0) // 7 0 117.3 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_156_2 (0x1AUL << 0) // 7 0 156.2 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_187_2 (0x12UL << 0) // 7 0 187.2 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_234_3 (0x0AUL << 0) // 7 0 234.3 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_312_0 (0x19UL << 0) // 7 0 312.0 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_373_6 (0x11UL << 0) // 7 0 373.6 kHz
-#define RADIOLIB_LR11X0_GFSK_RX_BW_467_0 (0x09UL << 0) // 7 0 467.0 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE (488.28215) // 31 0 LR FHSS bit rate: 488.28215 bps
-#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW (0x8001E848UL) // 31 0 488.28215 bps in raw
-#define RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 shaping filter: Gaussian, BT = 1.0
-#define RADIOLIB_LR11X0_SIGFOX_SHAPING_GAUSSIAN_BT_0_7 (0x16UL << 0) // 7 0 shaping filter: Gaussian, BT = 0.7
-
-// RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS
-#define RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT (0x00UL << 0) // 7 0 LoRa header mode: explicit
-#define RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT (0x01UL << 0) // 7 0 implicit
-#define RADIOLIB_LR11X0_LORA_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length
-#define RADIOLIB_LR11X0_LORA_CRC_ENABLED (0x01UL << 0) // 7 0 CRC: enabled
-#define RADIOLIB_LR11X0_LORA_CRC_DISABLED (0x00UL << 0) // 7 0 disabled
-#define RADIOLIB_LR11X0_LORA_IQ_STANDARD (0x00UL << 0) // 7 0 IQ setup: standard
-#define RADIOLIB_LR11X0_LORA_IQ_INVERTED (0x01UL << 0) // 7 0 inverted
-#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_DISABLED (0x00UL << 0) // 7 0 preamble detector: disabled
-#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_8_BITS (0x04UL << 0) // 7 0 8 bits
-#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS (0x05UL << 0) // 7 0 16 bits
-#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS (0x06UL << 0) // 7 0 24 bits
-#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS (0x07UL << 0) // 7 0 32 bits
-#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled
-#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE (0x01UL << 0) // 7 0 node address
-#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast address
-#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED (0x00UL << 0) // 7 0 packet length: fixed
-#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE (0x01UL << 0) // 7 0 variable
-#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE_SX128X (0x02UL << 0) // 7 0 variable, SX128x 9-bit length encoding
-#define RADIOLIB_LR11X0_GFSK_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length
-#define RADIOLIB_LR11X0_GFSK_CRC_DISABLED (0x01UL << 0) // 7 0 CRC: disabled
-#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE (0x00UL << 0) // 7 0 1-byte
-#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE (0x02UL << 0) // 7 0 2-byte
-#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV (0x04UL << 0) // 7 0 1-byte, inverted
-#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV (0x06UL << 0) // 7 0 2-byte, inverted
-#define RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED (0x00UL << 0) // 7 0 whitening: disabled
-#define RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED (0x01UL << 0) // 7 0 enabled
-
-// RADIOLIB_LR11X0_CMD_SET_TX_PARAMS
-#define RADIOLIB_LR11X0_PA_RAMP_48U (0x02UL << 0) // 7 0 PA ramp time: 48 us
-
-// RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE
-#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC
-#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC
-#define RADIOLIB_LR11X0_FALLBACK_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis
-
-// RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE
-#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_RX (0x00UL << 0) // 0 0 mode in Rx windows: Rx (default)
-#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_CAD (0x01UL << 0) // 0 0 CAD
-#define RADIOLIB_LR11X0_TIMING_STEP (1.0f/32768.0f) // 23 0 timing step fo delays
-
-// RADIOLIB_LR11X0_CMD_SET_PA_CONFIG
-#define RADIOLIB_LR11X0_PA_SEL_LP (0x00UL << 0) // 7 0 PA select: low power PA
-#define RADIOLIB_LR11X0_PA_SEL_HP (0x01UL << 0) // 7 0 high power PA
-#define RADIOLIB_LR11X0_PA_SEL_HF (0x02UL << 0) // 7 0 high frequency PA
-#define RADIOLIB_LR11X0_PA_SUPPLY_INTERNAL (0x00UL << 0) // 7 0 PA power source: internal
-#define RADIOLIB_LR11X0_PA_SUPPLY_VBAT (0x01UL << 0) // 7 0 VBAT (required for >= 14 dBm)
-
-// RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE
-#define RADIOLIB_LR11X0_STOP_ON_SYNC_HEADER (0x00UL << 0) // 0 0 stop timeout on: sync word or header (default)
-#define RADIOLIB_LR11X0_STOP_ON_PREAMBLE (0x01UL << 0) // 0 0 preamble
-
-// RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT
-#define RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE (0) // 7 0 ranging result type: distance
-#define RADIOLIB_LR11X0_RANGING_RESULT_RSSI (1) // 7 0 RSSI
-
-// RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED
-#define RADIOLIB_LR11X0_RX_BOOSTED_ENABLED (0x01UL << 0) // 0 0 Rx boosted mode: enabled
-#define RADIOLIB_LR11X0_RX_BOOSTED_DISABLED (0x00UL << 0) // 0 0 disabled
-
-// RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD
-#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12)
-#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PUBLIC (0x34)
-
-// RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME
-#define RADIOLIB_LR11X0_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6
-#define RADIOLIB_LR11X0_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3
-#define RADIOLIB_LR11X0_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2
-#define RADIOLIB_LR11X0_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3
-#define RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK
-#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC)
-#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC)
-#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled
-#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled
-#define RADIOLIB_LR11X0_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz
-#define RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS (114) // 7 0 LR FHSS packet bit widths: header
-#define RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS (48) // 7 0 payload fragment
-#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS (2) // 7 0 block preamble
-#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS (RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS + RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS)
-
-// RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS
-#define RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED (0x01UL << 4) // 4 4 last header CRC: enabled
-#define RADIOLIB_LR11X0_LAST_HEADER_CRC_DISABLED (0x00UL << 4) // 4 4 disabled
-
-// RADIOLIB_LR11X0_CMD_WIFI_SCAN
-#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_B (0x01UL << 0) // 7 0 Wi-Fi type to scan: 802.11b
-#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_G (0x02UL << 0) // 7 0 802.11g
-#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_N (0x03UL << 0) // 7 0 802.11n
-#define RADIOLIB_LR11X0_WIFI_SCAN_ALL (0x04UL << 0) // 7 0 all (802.11b first)
-#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_ONLY (0x01UL << 0) // 7 0 Wi-Fi acquisition mode: beacon only
-#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_PACKET (0x02UL << 0) // 7 0 beacon and packet
-#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_TRAFFIC (0x03UL << 0) // 7 0 full traffic
-#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON (0x04UL << 0) // 7 0 full beacon
-#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_SSID_BEACON (0x05UL << 0) // 7 0 SSID beacon
-#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED (0x01UL << 0) // 7 0 abort scanning on preamble timeout: enabled
-#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_DISABLED (0x00UL << 0) // 7 0 disabled
-#define RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS (32) // 7 0 maximum possible number of Wi-Fi scan results
-#define RADIOLIB_LR11X0_WIFI_ALL_CHANNELS (0x3FFFUL) // 16 0 scan all channels
-
-// RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS
-#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE (0x01UL << 0) // 7 0 Wi-Fi scan result type: complete
-#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC (0x04UL << 0) // 7 0 basic
-#define RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN (79) // 7 0 maximum possible Wi-Fi scan size
-#define RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN (6) // 7 0 MAC address length in bytes
-#define RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN (32) // 7 0 SSID length in bytes
-
-// RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE
-#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS (0x01UL << 0) // 7 0 GNSS constellation to use: GPS
-#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU (0x01UL << 1) // 7 0 BeiDou
-
-// RADIOLIB_LR11X0_CMD_GNSS_SET_MODE
-#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_SCAN (0x00UL << 0) // 7 0 GNSS scanning mode: single/legacy
-#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_MULTIPLE (0x03UL << 1) // 7 0 multiple/advanced
-
-// RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS
-#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_ENABLED (0x01UL << 0) // 0 0 GNSS results in NAV message: pseudo-range (in single scan mode) or Doppler information (in multiple scan mode)
-#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_DISABLED (0x00UL << 0) // 0 0 not included
-#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_ENABLED (0x01UL << 1) // 1 1 Doppler information
-#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_DISABLED (0x00UL << 1) // 1 1 not included
-#define RADIOLIB_LR11X0_GNSS_NB_SV_ALL (0x00UL << 0) // 7 0 include all detected satellites
-#define RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE (0x00UL << 0) // 7 0 reserved, always 0
-
-// RADIOLIB_LR11X0_CMD_GNSS_ASSISTED
-#define RADIOLIB_LR11X0_GNSS_ASSIST_LOW_POWER (0x00UL << 0) // 7 0 effort mode: low power
-#define RADIOLIB_LR11X0_GNSS_ASSIST_BEST_EFFORT (0x01UL << 0) // 7 0 best effort
-
-// RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS
-#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_NONE (0x00UL << 0) // 7 4 error code: none
-#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_OLD (0x01UL << 0) // 7 4 almanac too old
-#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_CRC (0x02UL << 0) // 7 4 almanac CRC mismatch
-#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_FLASH (0x03UL << 0) // 7 4 flash integrity error
-#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_UPD (0x04UL << 0) // 7 4 almanac update not allowed
-#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_250_HZ (0x00UL << 0) // 8 7 frequency search space: 250 Hz
-#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_500_HZ (0x01UL << 0) // 8 7 500 Hz
-#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_1000_HZ (0x02UL << 0) // 8 7 1000 Hz
-#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_2000_HZ (0x03UL << 0) // 8 7 2000 Hz
-
-// RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE
-#define RADIOLIB_LR11X0_SV_CONSTELLATION_GPS (0x00UL << 0) // 7 0 GNSS constellation: GPS
-#define RADIOLIB_LR11X0_SV_CONSTELLATION_BEIDOU (0x01UL << 0) // 7 0 BeiDou
-
-// RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE
-#define RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID (0x80UL << 0) // 7 0 starting byte of GNSS almanac header
-#define RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE (20)
-
-// RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME
-#define RADIOLIB_LR11X0_GNSS_EFFORT_LOW (0x00UL << 0) // 7 0 GNSS effort mode: low sensitivity
-#define RADIOLIB_LR11X0_GNSS_EFFORT_MID (0x01UL << 0) // 7 0 medium sensitivity
-#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW (0x00UL << 0) // 7 0 time fetch options: ToW only, requires WN to demodulated beforehand
-#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN (0x01UL << 0) // 7 0 ToW and WN
-#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN_ROLL (0x02UL << 0) // 7 0 ToW, WN and rollover
-
-// RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NOT_POSSIBLE (-21) // 7 0 GNSS demodulation status: not possible to demodulate
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SAT_LOST (-20) // 7 0 satellite lost
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALMANAC_DEMOD_ERROR (-19) // 7 0 almanac demodulation error
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOO_LATE (-18) // 7 0 woke up after preamble (demodulation started too late)
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_20_MS_FAIL (-17) // 7 0 20ms real-time clock failed
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WAKE_UP_FAIL (-16) // 7 0 wake up sync failed
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_INVALID (-15) // 7 0 week number not validated
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_ACTIVE_SAT (-14) // 7 0 no active satellite selected in satellite list
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SLEEP_TOO_LONG (-13) // 7 0 sleep time too long
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_INVALID (-12) // 7 0 wrong time-of-week demodulated
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PREAMBLE_INVALID (-11) // 7 0 preamble not validated
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_DISABLED (-10) // 7 0 demodulator disabled
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_EXTR_FAILED (-9) // 7 0 demodulator extraction failed
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE (-8) // 7 0 no bit change found during demodulation start
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE_ADV (-7) // 7 0 no bit change found during advanced scan
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_SAT_FOUND (-6) // 7 0 no satellites found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SYNC_LOST (-5) // 7 0 word sync lost
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_NOT_ENOUGH (-3) // 7 0 parity check fail (not enough)
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_TOO_MANY (-2) // 7 0 parity check fail (too many)
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_PARITY (-1) // 7 0 parity check fail (no parity found)
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_NONE (0) // 7 0 word sync search not started
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_POT (1) // 7 0 potential word sync found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_OK (2) // 7 0 word sync found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND (3) // 7 0 time-of-week found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_FOUND (4) // 7 0 week number and time-of-week found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALM_FOUND_UNSAVED (5) // 7 0 almanac found but not saved
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_HALF_ALM_SAVED (6) // 7 0 half of almanac found and saved
-#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_FULL_ALM_SAVED (7) // 7 0 full almanac found and saved
-#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WORD_SYNC_FOUND (0x01UL << 0) // 7 0 GNSS demodulation info: word synchronization found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_TOW_FOUND (0x01UL << 1) // 7 0 time-of-week found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_DEMODED (0x01UL << 2) // 7 0 week number demodulated
-#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_FOUND (0x01UL << 3) // 7 0 week number found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_1_FOUND (0x01UL << 4) // 7 0 subframe 1 found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_4_FOUND (0x01UL << 5) // 7 0 subframe 4 found
-#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_5_FOUND (0x01UL << 6) // 7 0 subframe 5 found
-
-// RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS
-#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE (0) // 7 0 GPS/BeiDou almanac status: all satellites up-to-date
-#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_OUTDATED (1) // 7 0 at least one satellite needs update
-
-// RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES
-#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NONE (0) // 7 0 internal 2D solver error: no error
-#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_RES_HIGH (1) // 7 0 residue too high
-#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_CONVERGED (2) // 7 0 not converged on solution
-#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_ENOUGH_SV (3) // 7 0 not enough satellites
-#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ILL_MATRIX (4) // 7 0 matrix error (?)
-#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_TIME (5) // 7 0 time error
-#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_PART_OLD (6) // 7 0 part of almanac too old or not available
-#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_INCONSISTENT (7) // 7 0 not consistent with history (?)
-#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_OLD (8) // 7 0 all of almanac too old
-
-// RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY
-#define RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS (0x00UL << 0) // 7 0 crypto engine status: success
-#define RADIOLIB_LR11X0_CRYPTO_STATUS_FAIL_CMAC (0x01UL << 0) // 7 0 MIC check failed
-#define RADIOLIB_LR11X0_CRYPTO_STATUS_INV_KEY_ID (0x03UL << 0) // 7 0 key/parameter source or destination ID error
-#define RADIOLIB_LR11X0_CRYPTO_STATUS_BUF_SIZE (0x05UL << 0) // 7 0 data buffer size invalid
-#define RADIOLIB_LR11X0_CRYPTO_STATUS_ERROR (0x06UL << 0) // 7 0 generic error
-
-// RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT
-#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_0 (0x00UL << 0) // 7 0 LoRaWAN version: 1.0.x
-#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_1 (0x01UL << 0) // 7 0 1.1
-
-// LR11X0 SPI register variables
-
-// RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT
-#define RADIOLIB_LR11X0_SF6_SX126X (0x00UL << 18) // 18 18 SF6 mode: SX126x series
-#define RADIOLIB_LR11X0_SF6_SX127X (0x01UL << 18) // 18 18 SX127x series
-
-// RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX
-#define RADIOLIB_LR11X0_LORA_HIGH_POWER_FIX (0x00UL << 30) // 30 30 fix for errata
-
-// RADIOLIB_LR11X0_REG_LNA_MODE
-#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_N (0x01UL << 4) // 7 4 LNA mode: single-ended RFI_N
-#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_P (0x02UL << 4) // 7 4 single-ended RFI_P
-#define RADIOLIB_LR11X0_LNA_MODE_DIFFERENTIAL (0x03UL << 4) // 7 4 differential (default)
-
-/*!
- \struct LR11x0WifiResult_t
- \brief Structure to save result of passive WiFi scan.
- This result only saves the basic information.
-*/
-struct LR11x0WifiResult_t {
- /*! \brief WiFi (802.11) signal type, 'b', 'n' or 'g' */
- char type;
-
- /*! \brief Data rate ID holding information about modulation and coding rate. See LR11x0 user manual for details. */
- uint8_t dataRateId;
-
- /*! \brief Channel frequency in MHz */
- uint16_t channelFreq;
-
- /*! \brief MAC address origin: from gateway (1), phone (2) or undetermined (3) */
- uint8_t origin;
-
- /*! \brief Whether this signal was sent by an access point (true) or end device (false) */
- bool ap;
-
- /*! \brief RSSI in dBm */
- float rssi;
-
- /*! \brief MAC address */
- uint8_t mac[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN];
-};
-
-/*!
- \struct LR11x0WifiResultFull_t
- \brief Structure to save result of passive WiFi scan.
- This result saves additional information alongside that in LR11x0WifiResult_t.
-*/
-struct LR11x0WifiResultFull_t: public LR11x0WifiResult_t {
- /*! \brief Frame type. See LR11x0 user manual for details. */
- uint8_t frameType;
-
- /*! \brief Frame sub type. See LR11x0 user manual for details. */
- uint8_t frameSubType;
-
- /*! \brief Frame sent from client station to distribution system. */
- bool toDistributionSystem;
-
- /*! \brief Frame sent from distribution system to client station. */
- bool fromDistributionSystem;
-
- /*! \brief See LR11x0 user manual for details. */
- uint16_t phiOffset;
-
- /*! \brief Number of microseconds the AP has been active. */
- uint64_t timestamp;
-
- /*! \brief Beacon period in microseconds. */
- uint32_t periodBeacon;
-};
-
-/*!
- \struct LR11x0WifiResultExtended_t
- \brief Structure to save result of passive WiFi scan.
- This result saves additional information alongside that in LR11x0WifiResultFull_t.
- Only scans performed with RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON acquisition mode
- can yield this result!
-*/
-struct LR11x0WifiResultExtended_t: public LR11x0WifiResultFull_t {
- /*! \brief Data rate. See LR11x0 user manual for details. */
- uint8_t rate;
-
- /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
- uint16_t service;
-
- /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
- uint16_t length;
-
- /*! \brief MAC address 0 */
- uint8_t mac0[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN];
-
- /*! \brief MAC address 2 */
- uint8_t mac2[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN];
-
- /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
- uint16_t seqCtrl;
-
- /*! \brief SSID */
- uint8_t ssid[RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN];
-
- /*! \brief WiFi channel number */
- uint8_t currentChannel;
-
- /*! \brief Two-letter country code (null-terminated string). */
- char countryCode[3];
-
- /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
- uint8_t ioReg;
-
- /*! \brief True if frame check sequences is valid, false otherwise. */
- bool fcsCheckOk;
-};
-
-/*!
- \struct LR11x0VersionInfo_t
- \brief Structure to report information about versions of the LR11x0 hardware and firmware.
-*/
-struct LR11x0VersionInfo_t {
- /*! \brief Hardware revision. */
- uint8_t hardware;
-
- /*! \brief Which device this is - one of RADIOLIB_LR11X0_DEVICE_* macros. */
- uint8_t device;
-
- /*! \brief Major revision of the base firmware. */
- uint8_t fwMajor;
-
- /*! \brief Minor revision of the base firmware. */
- uint8_t fwMinor;
-
- /*! \brief Major revision of the WiFi firmware. */
- uint8_t fwMajorWiFi;
-
- /*! \brief Minor revision of the WiFi firmware. */
- uint8_t fwMinorWiFi;
-
- /*! \brief Revision of the GNSS firmware. */
- uint8_t fwGNSS;
-
- /*! \brief Almanac revision of the GNSS firmware. */
- uint8_t almanacGNSS;
-};
-
-/*!
- \struct LR11x0GnssResult_t
- \brief Structure to report information results of a GNSS scan.
-*/
-struct LR11x0GnssResult_t {
- /*! \brief Demodulator status. One of RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_* */
- int8_t demodStat;
-
- /*! \brief Number of satellites detected during the scan. */
- uint8_t numSatsDet;
-
- /*! \brief Result size, used when passing data to LoRa cloud. */
- uint16_t resSize;
-};
-
-/*!
- \struct LR11x0GnssPosition_t
- \brief Structure to report position from LR11x0 internal solver.
-*/
-struct LR11x0GnssPosition_t {
- /*! \brief Latitude in degrees. */
- float latitude;
-
- /*! \brief Longitude in degrees. */
- float longitude;
-
- /*! \brief Accuracy of this result. */
- uint16_t accuracy;
-
- /*! \brief Number of satellites used to solve this position. */
- uint8_t numSatsUsed;
-};
-
-/*!
- \struct LR11x0GnssSatellite_t
- \brief Structure to save information about a satellite found during GNSS scan.
-*/
-struct LR11x0GnssSatellite_t {
- /*! \brief Satellite vehicle (SV) identifier. */
- uint8_t svId;
-
- /*! \brief C/N0 in dB. */
- uint8_t c_n0;
-
- /*! \brief Doppler shift of the signal in Hz. */
- int16_t doppler;
-};
-
-/*!
- \struct LR11x0GnssAlmanacStatusPart_t
- \brief Structure to save information about one constellation of the GNSS almanac.
-*/
-struct LR11x0GnssAlmanacStatusPart_t {
- int8_t status;
- uint32_t timeUntilSubframe;
- uint8_t numSubframes;
- uint8_t nextSubframe4SvId;
- uint8_t nextSubframe5SvId;
- uint8_t nextSubframeStart;
- uint8_t numUpdateNeeded;
- uint32_t flagsUpdateNeeded[2];
- uint32_t flagsActive[2];
-};
-
-/*!
- \struct LR11x0GnssAlmanacStatus_t
- \brief Structure to save information about the GNSS almanac.
- This is not the actual almanac, just some context information about it.
-*/
-struct LR11x0GnssAlmanacStatus_t {
- /*! \brief GPS part of the almanac */
- LR11x0GnssAlmanacStatusPart_t gps;
-
- /*! \brief BeiDou part of the almanac */
- LR11x0GnssAlmanacStatusPart_t beidou;
-
- /*! \brief Extra flags present for BeiDou only */
- uint32_t beidouSvNoAlmanacFlags[2];
-
- /*! \brief Next almanac ID */
- uint8_t nextAlmanacId;
-
- /*! \brief Timestamp of when almanac status was retrieved - timeUntilSubframe is relative to this value. */
- RadioLibTime_t start;
-};
-
/*!
\class LR11x0
\brief Base class for %LR11x0 series. All derived classes for %LR11x0 (e.g. LR1110 or LR1120) inherit from this base class.
This class should not be instantiated directly from user code, only from its derived classes.
*/
-class LR11x0: public PhysicalLayer {
+class LR11x0: public LRxxxx {
public:
// introduce PhysicalLayer overloads
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
+ using PhysicalLayer::startReceive;
using PhysicalLayer::readData;
/*!
@@ -907,17 +61,13 @@ class LR11x0: public PhysicalLayer {
/*! WiFi scanning mode */
MODE_WIFI,
};
-
- /*!
- \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false.
- */
- bool XTAL;
/*!
\brief Initialization method for LoRa modem.
\param bw LoRa bandwidth in kHz.
\param sf LoRa spreading factor.
- \param cr LoRa coding rate denominator.
+ \param cr LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord 1-byte LoRa sync word.
\param preambleLength LoRa preamble length in symbols
\param tcxoVoltage TCXO reference voltage to be set.
@@ -955,12 +105,6 @@ class LR11x0: public PhysicalLayer {
*/
int16_t beginGNSS(uint8_t constellations = RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS | RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU, float tcxoVoltage = 1.6);
- /*!
- \brief Reset method. Will reset the chip to the default state using RST pin.
- \returns \ref status_codes
- */
- int16_t reset();
-
/*!
\brief Blocking binary transmit method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
@@ -974,11 +118,13 @@ class LR11x0: public PhysicalLayer {
/*!
\brief Blocking binary receive method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
- \param data Binary data to be sent.
- \param len Number of bytes to send.
+ \param data Pointer to array to save the received binary data.
+ \param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+ \param timeout Reception timeout in milliseconds. If set to 0,
+ timeout period will be calculated automatically based on the radio configuration.
\returns \ref status_codes
*/
- int16_t receive(uint8_t* data, size_t len) override;
+ int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override;
/*!
\brief Starts direct mode transmission.
@@ -1013,6 +159,14 @@ class LR11x0: public PhysicalLayer {
*/
int16_t standby() override;
+ /*!
+ \brief Sets the module to standby mode.
+ \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR11X0_STANDBY_RC (13 MHz RC oscillator)
+ or RADIOLIB_LR11X0_STANDBY_XOSC (32 MHz external crystal oscillator).
+ \returns \ref status_codes
+ */
+ int16_t standby(uint8_t mode) override;
+
/*!
\brief Sets the module to standby mode.
\param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR11X0_STANDBY_RC (13 MHz RC oscillator)
@@ -1020,7 +174,7 @@ class LR11x0: public PhysicalLayer {
\param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module.
\returns \ref status_codes
*/
- int16_t standby(uint8_t mode, bool wakeup = true);
+ int16_t standby(uint8_t mode, bool wakeup);
/*!
\brief Sets the module to sleep mode. To wake the device up, call standby().
@@ -1040,49 +194,6 @@ class LR11x0: public PhysicalLayer {
// interrupt methods
- /*!
- \brief Sets interrupt service routine to call when IRQ1 activates.
- \param func ISR to call.
- */
- void setIrqAction(void (*func)(void));
-
- /*!
- \brief Clears interrupt service routine to call when IRQ1 activates.
- */
- void clearIrqAction();
-
- /*!
- \brief Sets interrupt service routine to call when a packet is received.
- \param func ISR to call.
- */
- void setPacketReceivedAction(void (*func)(void)) override;
-
- /*!
- \brief Clears interrupt service routine to call when a packet is received.
- */
- void clearPacketReceivedAction() override;
-
- /*!
- \brief Sets interrupt service routine to call when a packet is sent.
- \param func ISR to call.
- */
- void setPacketSentAction(void (*func)(void)) override;
-
- /*!
- \brief Clears interrupt service routine to call when a packet is sent.
- */
- void clearPacketSentAction() override;
-
- /*!
- \brief Interrupt-driven binary transmit method.
- Overloads for string-based transmissions are implemented in PhysicalLayer.
- \param data Binary data to be sent.
- \param len Number of bytes to send.
- \param addr Address to send the data to. Will only be added if address filtering was enabled.
- \returns \ref status_codes
- */
- int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override;
-
/*!
\brief Clean up after transmission is done.
\returns \ref status_codes
@@ -1097,26 +208,6 @@ class LR11x0: public PhysicalLayer {
*/
int16_t startReceive() override;
- /*!
- \brief Interrupt-driven receive method. IRQ1 will be activated when full packet is received.
- \param timeout Raw timeout value, expressed as multiples of 1/32.768 kHz (approximately 30.52 us).
- Defaults to RADIOLIB_LR11X0_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode),
- set to RADIOLIB_LR11X0_RX_TIMEOUT_NONE for no timeout (Rx single mode).
- If timeout other than infinite is set, signal will be generated on IRQ1.
-
- \param irqFlags Sets the IRQ flags that will trigger IRQ1, defaults to RADIOLIB_LR11X0_IRQ_RX_DONE.
- \param irqMask Only for PhysicalLayer compatibility, not used.
- \param len Only for PhysicalLayer compatibility, not used.
- \returns \ref status_codes
- */
- int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE, uint32_t irqMask = 0, size_t len = 0);
-
- /*!
- \brief Reads the current IRQ status.
- \returns IRQ status bits
- */
- uint32_t getIrqStatus();
-
/*!
\brief Reads data received after calling startReceive method. When the packet length is not known in advance,
getPacketLength method must be called BEFORE calling readData!
@@ -1126,6 +217,12 @@ class LR11x0: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t readData(uint8_t* data, size_t len) override;
+
+ /*!
+ \brief Clean up after reception is done.
+ \returns \ref status_codes
+ */
+ int16_t finishReceive() override;
/*!
\brief Interrupt-driven channel activity detection method. IRQ1 will be activated
@@ -1167,10 +264,12 @@ class LR11x0: public PhysicalLayer {
int16_t setSpreadingFactor(uint8_t sf, bool legacy = false);
/*!
- \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8.
+ \brief Sets LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param cr LoRa coding rate denominator to be set.
\param longInterleave Enable long interleaver when set to true.
- Note that CR 4/7 is not possible with long interleaver enabled!
+ Note that with long interleaver enabled, CR 4/7 is not possible, there are packet length restrictions,
+ and it is not compatible with SX127x radios!
\returns \ref status_codes
*/
int16_t setCodingRate(uint8_t cr, bool longInterleave = false);
@@ -1212,15 +311,6 @@ class LR11x0: public PhysicalLayer {
*/
int16_t setSyncWord(uint8_t* syncWord, size_t len) override;
- /*!
- \brief Sets GFSK sync word in the form of array of up to 8 bytes.
- \param syncWord GFSK sync word to be set.
- \param bitsLen GFSK sync word length in bits. If length is not divisible by 8,
- least significant bits of syncWord will be ignored.
- \returns \ref status_codes
- */
- int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen);
-
/*!
\brief Sets node address. Calling this method will also enable address filtering for node address only.
\param nodeAddr Node address to be set.
@@ -1282,18 +372,22 @@ class LR11x0: public PhysicalLayer {
int16_t setWhitening(bool enabled, uint16_t initial = 0x01FF);
/*!
- \brief Set data.
- \param dr Data rate struct. Interpretation depends on currently active modem (GFSK or LoRa).
+ \brief Set data rate.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t setDataRate(DataRate_t dr) override;
+ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Check the data rate can be configured by this module.
- \param dr Data rate struct. Interpretation depends on currently active modem (GFSK or LoRa).
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t checkDataRate(DataRate_t dr) override;
+ int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Sets preamble length for LoRa or GFSK modem. Allowed values range from 1 to 65535.
@@ -1324,17 +418,26 @@ class LR11x0: public PhysicalLayer {
/*!
\brief Enable/disable inversion of the I and Q signals
- \param enable QI inversion enabled (true) or disabled (false);
+ \param enable IQ inversion enabled (true) or disabled (false);
\returns \ref status_codes
*/
int16_t invertIQ(bool enable) override;
/*!
- \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. Only available for LoRa or GFSK modem.
+ \brief Gets RSSI (Received Signal Strength Indicator) of the last received packet. Only available for LoRa or GFSK modem.
\returns RSSI of the last received packet in dBm.
*/
float getRSSI() override;
+ /*!
+ \brief Gets RSSI (Received Signal Strength Indicator).
+ \param packet Whether to read last packet RSSI, or the current value.
+ \param skipReceive Set to true to skip putting radio in receive mode for instantaneous RSSI measurement.
+ If false, after the RSSI measurement, the radio will be in standby mode.
+ \returns RSSI value in dBm.
+ */
+ float getRSSI(bool packet, bool skipReceive = false);
+
/*!
\brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem.
\returns SNR of the last received packet in dB.
@@ -1357,10 +460,19 @@ class LR11x0: public PhysicalLayer {
/*!
\brief Query modem for the packet length of received payload.
\param update Update received packet length. Will return cached value when set to false.
+ \param offset Pointer to a variable that will hold the receive packet's offset in the RX buffer
\returns Length of last received packet in bytes.
*/
size_t getPacketLength(bool update, uint8_t* offset);
+ /*!
+ \brief Get LoRa header information from last received packet. Only valid in explicit header mode.
+ \param cr Pointer to variable to store the coding rate.
+ \param hasCRC Pointer to variable to store the CRC status.
+ \returns \ref status_codes
+ */
+ int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC);
+
/*!
\brief Get expected time-on-air for a given size of payload
\param len Payload length in bytes.
@@ -1368,13 +480,6 @@ class LR11x0: public PhysicalLayer {
*/
RadioLibTime_t getTimeOnAir(size_t len) override;
- /*!
- \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
- \param timeoutUs Timeout in microseconds to listen for
- \returns Timeout value in a unit that is specific for the used module
- */
- RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override;
-
/*!
\brief Read currently active IRQ flags.
\returns IRQ flags.
@@ -1414,12 +519,6 @@ class LR11x0: public PhysicalLayer {
*/
int16_t explicitHeader();
- /*!
- \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes.
- \returns Effective data rate in bps.
- */
- float getDataRate() const;
-
/*!
\brief Set regulator mode to LDO.
\returns \ref status_codes
@@ -1439,6 +538,25 @@ class LR11x0: public PhysicalLayer {
*/
int16_t setRxBoostedGainMode(bool en);
+ /*!
+ \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA),
+ -17 to 14 dBm (low-power PA) and -18 to 13 dBm (high-frequency PA).
+ This method allows user full control over PA configuration parameters.
+ If you set incorrect PA configuration values, you can fail to reach the
+ desired output power level or damage your device.
+ Unless you can verify the output power, it is strongly advised to use
+ LR1110::setOutputPower(power) or LR1120::setOutputPower(power).
+ \param power Output power to be set in dBm.
+ \param paSel PA selection, low-power, high-power or high-frequency. One of RADIOLIB_LR11X0_PA_SEL_* macros.
+ \param regPaSupply PA power source selection, internal regulator or VBAT. One of RADIOLIB_LR11X0_PA_SUPPLY_* macros.
+ Must be set to RADIOLIB_LR11X0_PA_SUPPLY_VBAT when output power is more than 14 dBm.
+ \param paDutyCycle PA duty cycle.
+ \param paHpSel High-power PA size control.
+ \param rampTime PA power ramping time raw value, one of RADIOLIB_LRXXXX_PA_RAMP_* macros.
+ \returns \ref status_codes
+ */
+ int16_t setOutputPower(int8_t power, uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel, uint8_t rampTime);
+
/*! \copydoc Module::setRfSwitchTable */
void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]);
@@ -1622,20 +740,29 @@ class LR11x0: public PhysicalLayer {
*/
int16_t calibrateImageRejection(float freqMin, float freqMax);
+ /*! \copydoc PhysicalLayer::stageMode */
+ int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override;
+
+ /*! \copydoc PhysicalLayer::launchMode */
+ int16_t launchMode() override;
+
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod() override;
+ // method that applies some magic workaround for specific bitrate, frequency deviation,
+ // receiver bandwidth and carrier frequencies for GFSK (and resets it in all other cases)
+ int16_t workaroundGFSK();
+
// LR11x0 SPI command implementations
- int16_t writeRegMem32(uint32_t addr, uint32_t* data, size_t len);
+ int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len);
int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len);
- int16_t writeBuffer8(uint8_t* data, size_t len);
+ int16_t writeBuffer8(const uint8_t* data, size_t len);
int16_t readBuffer8(uint8_t* data, size_t len, size_t offset);
int16_t clearRxBuffer(void);
int16_t writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data);
- int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq);
int16_t getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor);
int16_t getErrors(uint16_t* err);
int16_t clearErrors(void);
@@ -1644,7 +771,7 @@ class LR11x0: public PhysicalLayer {
int16_t setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg);
int16_t setDioIrqParams(uint32_t irq1, uint32_t irq2);
int16_t setDioIrqParams(uint32_t irq);
- int16_t clearIrq(uint32_t irq);
+ int16_t clearIrqState(uint32_t irq);
int16_t configLfClock(uint8_t setup);
int16_t setTcxoMode(uint8_t tune, uint32_t delay);
int16_t reboot(bool stay);
@@ -1702,11 +829,9 @@ class LR11x0: public PhysicalLayer {
int16_t setRangingParameter(uint8_t symbolNum);
int16_t setRssiCalibration(const int8_t* tune, int16_t gainOffset);
int16_t setLoRaSyncWord(uint8_t sync);
- int16_t lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, uint8_t* payload, size_t len);
int16_t lrFhssSetSyncWord(uint32_t sync);
- int16_t configBleBeacon(uint8_t chan, uint8_t* payload, size_t len);
- int16_t getLoRaRxHeaderInfos(uint8_t* info);
- int16_t bleBeaconSend(uint8_t chan, uint8_t* payload, size_t len);
+ int16_t configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len);
+ int16_t bleBeaconSend(uint8_t chan, const uint8_t* payload, size_t len);
int16_t wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout);
int16_t wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout);
@@ -1744,7 +869,7 @@ class LR11x0: public PhysicalLayer {
int16_t gnssGetResultSize(uint16_t* size);
int16_t gnssReadResults(uint8_t* result, uint16_t size);
int16_t gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc);
- int16_t gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac);
+ int16_t gnssAlmanacFullUpdateSV(uint8_t svn, const uint8_t* svnAlmanac);
int16_t gnssAlmanacReadAddrSize(uint32_t* addr, uint16_t* size);
int16_t gnssAlmanacReadSV(uint8_t svId, uint8_t* almanac);
int16_t gnssGetNbSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv);
@@ -1773,66 +898,40 @@ class LR11x0: public PhysicalLayer {
int16_t gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1);
void gnssAbort();
- int16_t cryptoSetKey(uint8_t keyId, uint8_t* key);
- int16_t cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key);
- int16_t cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, uint8_t* header, uint8_t* dataIn, size_t len, uint8_t* dataOut);
- int16_t cryptoComputeAesCmac(uint8_t keyId, uint8_t* data, size_t len, uint32_t* mic);
- int16_t cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, uint8_t* data, size_t len, bool* result);
- int16_t cryptoAesEncrypt01(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut);
- int16_t cryptoAesEncrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut);
- int16_t cryptoAesDecrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut);
+ int16_t cryptoSetKey(uint8_t keyId, const uint8_t* key);
+ int16_t cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, const uint8_t* key);
+ int16_t cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, const uint8_t* header, const uint8_t* dataIn, size_t len, uint8_t* dataOut);
+ int16_t cryptoComputeAesCmac(uint8_t keyId, const uint8_t* data, size_t len, uint32_t* mic);
+ int16_t cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, const uint8_t* data, size_t len, bool* result);
+ int16_t cryptoAesEncrypt01(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut);
+ int16_t cryptoAesEncrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut);
+ int16_t cryptoAesDecrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut);
int16_t cryptoStoreToFlash(void);
int16_t cryptoRestoreFromFlash(void);
int16_t cryptoSetParam(uint8_t id, uint32_t value);
int16_t cryptoGetParam(uint8_t id, uint32_t* value);
- int16_t cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile);
+ int16_t cryptoCheckEncryptedFirmwareImage(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile);
int16_t cryptoCheckEncryptedFirmwareImageResult(bool* result);
int16_t bootEraseFlash(void);
- int16_t bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile);
+ int16_t bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile);
+ int16_t bootGetHash(uint8_t hash[RADIOLIB_LR11X0_HASH_LEN]);
int16_t bootReboot(bool stay);
int16_t bootGetPin(uint8_t* pin);
int16_t bootGetChipEui(uint8_t* eui);
int16_t bootGetJoinEui(uint8_t* eui);
- int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, uint8_t* out = NULL, size_t outLen = 0);
-
#if !RADIOLIB_GODMODE
protected:
#endif
uint8_t chipType = 0;
- float freqMHz = 0;
#if !RADIOLIB_GODMODE
private:
#endif
- Module* mod;
-
- // cached LoRa parameters
- uint8_t bandwidth = 0, spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0;
- uint16_t preambleLengthLoRa = 0;
- float bandwidthKhz = 0;
- bool ldroAuto = true;
- size_t implicitLen = 0;
- bool invertIQEnabled = false;
-
- // cached GFSK parameters
- uint32_t bitRate = 0, frequencyDev = 0;
- uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0, node = 0;
- uint16_t preambleLengthGFSK = 0;
-
- // cached LR-FHSS parameters
- uint8_t lrFhssCr = 0, lrFhssBw = 0, lrFhssHdrCount = 0, lrFhssGrid = 0;
- uint16_t lrFhssHopSeq = 0;
-
- float dataRateMeasured = 0;
-
uint8_t wifiScanMode = 0;
bool gnss = false;
-
int16_t modSetup(float tcxoVoltage, uint8_t modem);
- static int16_t SPIparseStatus(uint8_t in);
- static int16_t SPIcheckStatus(Module* mod);
bool findChip(uint8_t ver);
int16_t config(uint8_t modem);
int16_t setPacketMode(uint8_t mode, uint8_t len);
@@ -1840,9 +939,8 @@ class LR11x0: public PhysicalLayer {
int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF);
// common methods to avoid some copy-paste
- int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len);
- int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile);
- int16_t cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut);
+ int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, const uint8_t* payload, size_t len);
+ int16_t cryptoCommon(uint16_t cmd, uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut);
};
#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR11x0_commands.cpp b/lib/RadioLib/src/modules/LR11x0/LR11x0_commands.cpp
new file mode 100644
index 0000000..c5dc5fb
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR11x0/LR11x0_commands.cpp
@@ -0,0 +1,744 @@
+#include "LR11x0.h"
+
+#include "../../utils/CRC.h"
+#include "../../utils/Cryptography.h"
+#include "LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR11X0
+
+int16_t LR11x0::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) {
+ // check maximum size
+ if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+ return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false));
+}
+
+int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) {
+ // check maximum size
+ if(len >= (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+
+ // the request contains the address and length
+ uint8_t reqBuff[5] = {
+ (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF),
+ (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
+ (uint8_t)len,
+ };
+
+ // build buffers - later we need to ensure endians are correct,
+ // so there is probably no way to do this without copying buffers and iterating
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)];
+ #endif
+
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff));
+
+ // convert endians
+ if(data && (state == RADIOLIB_ERR_NONE)) {
+ for(size_t i = 0; i < len; i++) {
+ data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)];
+ }
+ }
+
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] rplBuff;
+ #endif
+
+ return(state);
+}
+
+int16_t LR11x0::writeBuffer8(const uint8_t* data, size_t len) {
+ // check maximum size
+ if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, const_cast(data), len));
+}
+
+int16_t LR11x0::readBuffer8(uint8_t* data, size_t len, size_t offset) {
+ // check maximum size
+ if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+
+ // build buffers
+ size_t reqLen = 2*sizeof(uint8_t) + len;
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t reqBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* reqBuff = new uint8_t[reqLen];
+ #endif
+
+ // set the offset and length
+ reqBuff[0] = (uint8_t)offset;
+ reqBuff[1] = (uint8_t)len;
+
+ // send the request
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_BUFFER, false, data, len, reqBuff, reqLen);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] reqBuff;
+ #endif
+ return(state);
+}
+
+int16_t LR11x0::clearRxBuffer(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER, true, NULL, 0));
+}
+
+int16_t LR11x0::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) {
+ uint8_t buff[12] = {
+ (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
+ (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
+ (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor) {
+ uint8_t buff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VERSION, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(hw) { *hw = buff[0]; }
+ if(device) { *device = buff[1]; }
+ if(major) { *major = buff[2]; }
+ if(minor) { *minor = buff[3]; }
+
+ return(state);
+}
+
+int16_t LR11x0::getErrors(uint16_t* err) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_ERRORS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(err) { *err = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+
+ return(state);
+}
+
+int16_t LR11x0::clearErrors(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_ERRORS, true, NULL, 0));
+}
+
+int16_t LR11x0::calibrate(uint8_t params) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIBRATE, true, ¶ms, 1));
+}
+
+int16_t LR11x0::setRegMode(uint8_t mode) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_REG_MODE, true, &mode, 1));
+}
+
+int16_t LR11x0::calibrateImageRejection(float freqMin, float freqMax) {
+ uint8_t buff[2] = {
+ (uint8_t)floor((freqMin - 1.0f) / 4.0f),
+ (uint8_t)ceil((freqMax + 1.0f) / 4.0f)
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIB_IMAGE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg) {
+ uint8_t buff[8] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, txHfCfg, gnssCfg, wifiCfg };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) {
+ uint8_t buff[8] = {
+ (uint8_t)((irq1 >> 24) & 0xFF), (uint8_t)((irq1 >> 16) & 0xFF), (uint8_t)((irq1 >> 8) & 0xFF), (uint8_t)(irq1 & 0xFF),
+ (uint8_t)((irq2 >> 24) & 0xFF), (uint8_t)((irq2 >> 16) & 0xFF), (uint8_t)((irq2 >> 8) & 0xFF), (uint8_t)(irq2 & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setDioIrqParams(uint32_t irq) {
+ return(setDioIrqParams(irq, this->gnss ? 0 : irq));
+}
+
+int16_t LR11x0::clearIrqState(uint32_t irq) {
+ return(this->setU32(RADIOLIB_LR11X0_CMD_CLEAR_IRQ, irq));
+}
+
+int16_t LR11x0::configLfClock(uint8_t setup) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK, true, &setup, 1));
+}
+
+int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) {
+ uint8_t buff[4] = {
+ tune, (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TCXO_MODE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::reboot(bool stay) {
+ uint8_t buff[1] = { (uint8_t)(stay*3) };
+ return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_REBOOT, buff, sizeof(buff), true, false));
+}
+
+int16_t LR11x0::getVbat(float* vbat) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VBAT, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(vbat) { *vbat = (((float)buff[0]/51.0f) - 1.0f)*1.35f; }
+
+ return(state);
+}
+
+int16_t LR11x0::getTemp(float* temp) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_TEMP, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(temp) {
+ uint16_t raw = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1];
+ raw = raw & 0x07FF; //According LR1121 datasheet we need [0..10] bits
+ *temp = 25.0f - (1000.0f/1.7f)*(((float)raw/2047.0f)*1.35f - 0.7295f); //According LR1121 datasheet 1.35
+ }
+
+ return(state);
+}
+
+int16_t LR11x0::setFs(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_FS, true, NULL, 0));
+}
+
+int16_t LR11x0::getRandomNumber(uint32_t* rnd) {
+ uint8_t buff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(rnd) { *rnd = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; }
+
+ return(state);
+}
+
+int16_t LR11x0::eraseInfoPage(void) {
+ // only page 1 can be erased
+ uint8_t buff[1] = { RADIOLIB_LR11X0_INFO_PAGE };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::writeInfoPage(uint16_t addr, const uint32_t* data, size_t len) {
+ // check maximum size
+ if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+
+ // build buffers - later we need to ensure endians are correct,
+ // so there is probably no way to do this without copying buffers and iterating
+ size_t buffLen = sizeof(uint8_t) + sizeof(uint16_t) + len*sizeof(uint32_t);
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t dataBuff[sizeof(uint8_t) + sizeof(uint16_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* dataBuff = new uint8_t[buffLen];
+ #endif
+
+ // set the address
+ dataBuff[0] = RADIOLIB_LR11X0_INFO_PAGE;
+ dataBuff[1] = (uint8_t)((addr >> 8) & 0xFF);
+ dataBuff[2] = (uint8_t)(addr & 0xFF);
+
+ // convert endians
+ for(size_t i = 0; i < len; i++) {
+ dataBuff[3 + i] = (uint8_t)((data[i] >> 24) & 0xFF);
+ dataBuff[4 + i] = (uint8_t)((data[i] >> 16) & 0xFF);
+ dataBuff[5 + i] = (uint8_t)((data[i] >> 8) & 0xFF);
+ dataBuff[6 + i] = (uint8_t)(data[i] & 0xFF);
+ }
+
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE, true, dataBuff, buffLen);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] dataBuff;
+ #endif
+ return(state);
+}
+
+int16_t LR11x0::readInfoPage(uint16_t addr, uint32_t* data, size_t len) {
+ // check maximum size
+ if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+
+ // the request contains the address and length
+ uint8_t reqBuff[4] = {
+ RADIOLIB_LR11X0_INFO_PAGE,
+ (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
+ (uint8_t)len,
+ };
+
+ // build buffers - later we need to ensure endians are correct,
+ // so there is probably no way to do this without copying buffers and iterating
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)];
+ #endif
+
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_INFO_PAGE, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff));
+
+ // convert endians
+ if(data && (state == RADIOLIB_ERR_NONE)) {
+ for(size_t i = 0; i < len; i++) {
+ data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)];
+ }
+ }
+
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] rplBuff;
+ #endif
+
+ return(state);
+}
+
+int16_t LR11x0::getChipEui(uint8_t* eui) {
+ RADIOLIB_ASSERT_PTR(eui);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
+}
+
+int16_t LR11x0::getSemtechJoinEui(uint8_t* eui) {
+ RADIOLIB_ASSERT_PTR(eui);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
+}
+
+int16_t LR11x0::deriveRootKeysAndGetPin(uint8_t* pin) {
+ RADIOLIB_ASSERT_PTR(pin);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN));
+}
+
+int16_t LR11x0::enableSpiCrc(bool en) {
+ // TODO implement this
+ (void)en;
+ // LR11X0 CRC is gen 0xA6 (0x65 but reflected), init 0xFF, input and result reflected
+ /*RadioLibCRCInstance.size = 8;
+ RadioLibCRCInstance.poly = 0xA6;
+ RadioLibCRCInstance.init = 0xFF;
+ RadioLibCRCInstance.out = 0x00;
+ RadioLibCRCInstance.refIn = true;
+ RadioLibCRCInstance.refOut = true;*/
+ return(RADIOLIB_ERR_UNSUPPORTED);
+}
+
+int16_t LR11x0::driveDiosInSleepMode(bool en) {
+ uint8_t buff[1] = { (uint8_t)en };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::resetStats(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_RESET_STATS, true, NULL, 0));
+}
+
+int16_t LR11x0::getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* data1, uint16_t* data2) {
+ uint8_t buff[8] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_STATS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(nbPktReceived) { *nbPktReceived = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(nbPktCrcError) { *nbPktCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; }
+ if(data1) { *data1 = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
+ if(data2) { *data2 = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; }
+
+ return(state);
+}
+
+int16_t LR11x0::getPacketType(uint8_t* type) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(type) { *type = buff[0]; }
+
+ return(state);
+}
+
+int16_t LR11x0::getRxBufferStatus(uint8_t* len, uint8_t* startOffset) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(len) { *len = buff[0]; }
+ if(startOffset) { *startOffset = buff[1]; }
+
+ return(state);
+}
+
+int16_t LR11x0::getPacketStatusLoRa(float* rssiPkt, float* snrPkt, float* signalRssiPkt) {
+ uint8_t buff[3] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(rssiPkt) { *rssiPkt = (float)buff[0] / -2.0f; }
+ if(snrPkt) { *snrPkt = (float)((int8_t)buff[1]) / 4.0f; }
+ if(signalRssiPkt) { *signalRssiPkt = buff[2]; }
+
+ return(state);
+}
+
+int16_t LR11x0::getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rxLen, uint8_t* stat) {
+ uint8_t buff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(rssiSync) { *rssiSync = (float)buff[0] / -2.0f; }
+ if(rssiAvg) { *rssiAvg = (float)buff[1] / -2.0f; }
+ if(rxLen) { *rxLen = buff[2]; }
+ if(stat) { *stat = buff[3]; }
+
+ return(state);
+}
+
+int16_t LR11x0::getRssiInst(float* rssi) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RSSI_INST, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(rssi) { *rssi = (float)buff[0] / -2.0f; }
+
+ return(state);
+}
+
+int16_t LR11x0::setGfskSyncWord(uint8_t* sync) {
+ RADIOLIB_ASSERT_PTR(sync);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, true, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN));
+}
+
+int16_t LR11x0::setLoRaPublicNetwork(bool pub) {
+ uint8_t buff[1] = { (uint8_t)pub };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setRx(uint32_t timeout) {
+ uint8_t buff[3] = {
+ (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setTx(uint32_t timeout) {
+ uint8_t buff[3] = {
+ (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setRfFrequency(uint32_t rfFreq) {
+ return(this->setU32(RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY, rfFreq));
+}
+
+int16_t LR11x0::autoTxRx(uint32_t delay, uint8_t intMode, uint32_t timeout) {
+ uint8_t buff[7] = {
+ (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), intMode,
+ (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_AUTO_TX_RX, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setCadParams(uint8_t symNum, uint8_t detPeak, uint8_t detMin, uint8_t cadExitMode, uint32_t timeout) {
+ uint8_t buff[7] = {
+ symNum, detPeak, detMin, cadExitMode,
+ (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setPacketType(uint8_t type) {
+ uint8_t buff[1] = { type };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
+ // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled
+ if(this->ldroAuto) {
+ float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
+ if(symbolLength >= 16.0f) {
+ this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_ENABLED;
+ } else {
+ this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_DISABLED;
+ }
+ } else {
+ this->ldrOptimize = ldro;
+ }
+
+ uint8_t buff[4] = { sf, bw, cr, this->ldrOptimize };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setModulationParamsGFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) {
+ uint8_t buff[10] = {
+ (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF),
+ (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh, rxBw,
+ (uint8_t)((freqDev >> 24) & 0xFF), (uint8_t)((freqDev >> 16) & 0xFF),
+ (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setModulationParamsLrFhss(uint32_t br, uint8_t sh) {
+ uint8_t buff[5] = {
+ (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF),
+ (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setModulationParamsSigfox(uint32_t br, uint8_t sh) {
+ // same as for LR-FHSS
+ return(this->setModulationParamsLrFhss(br, sh));
+}
+
+int16_t LR11x0::setPacketParamsLoRa(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ) {
+ uint8_t buff[6] = {
+ (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
+ hdrType, payloadLen, crcType, invertIQ
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setPacketParamsGFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t syncWordLen, uint8_t addrCmp, uint8_t packType, uint8_t payloadLen, uint8_t crcType, uint8_t whiten) {
+ uint8_t buff[9] = {
+ (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
+ preambleDetectorLen, syncWordLen, addrCmp, packType, payloadLen, crcType, whiten
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setPacketParamsSigfox(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t bitNum) {
+ uint8_t buff[7] = {
+ payloadLen, (uint8_t)((rampUpDelay >> 8) & 0xFF), (uint8_t)(rampUpDelay & 0xFF),
+ (uint8_t)((rampDownDelay >> 8) & 0xFF), (uint8_t)(rampDownDelay & 0xFF),
+ (uint8_t)((bitNum >> 8) & 0xFF), (uint8_t)(bitNum & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setTxParams(int8_t pwr, uint8_t ramp) {
+ uint8_t buff[2] = { (uint8_t)pwr, ramp };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setPacketAdrs(uint8_t node, uint8_t broadcast) {
+ uint8_t buff[2] = { node, broadcast };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setRxTxFallbackMode(uint8_t mode) {
+ uint8_t buff[1] = { mode };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint8_t mode) {
+ uint8_t buff[7] = {
+ (uint8_t)((rxPeriod >> 16) & 0xFF), (uint8_t)((rxPeriod >> 8) & 0xFF), (uint8_t)(rxPeriod & 0xFF),
+ (uint8_t)((sleepPeriod >> 16) & 0xFF), (uint8_t)((sleepPeriod >> 8) & 0xFF), (uint8_t)(sleepPeriod & 0xFF),
+ mode
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setPaConfig(uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel) {
+ uint8_t buff[4] = { paSel, regPaSupply, paDutyCycle, paHpSel };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PA_CONFIG, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::stopTimeoutOnPreamble(bool stop) {
+ uint8_t buff[1] = { (uint8_t)stop };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setCad(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD, true, NULL, 0));
+}
+
+int16_t LR11x0::setTxCw(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_CW, true, NULL, 0));
+}
+
+int16_t LR11x0::setTxInfinitePreamble(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE, true, NULL, 0));
+}
+
+int16_t LR11x0::setLoRaSynchTimeout(uint8_t symbolNum) {
+ uint8_t buff[1] = { symbolNum };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setRangingAddr(uint32_t addr, uint8_t checkLen) {
+ uint8_t buff[5] = {
+ (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF),
+ (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), checkLen
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setRangingReqAddr(uint32_t addr) {
+ return(this->setU32(RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR, addr));
+}
+
+int16_t LR11x0::getRangingResult(uint8_t type, float* res) {
+ uint8_t reqBuff[1] = { type };
+ uint8_t rplBuff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
+ RADIOLIB_ASSERT(state);
+
+ if(res) {
+ if(type == RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE) {
+ uint32_t raw = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3];
+ *res = ((float)(raw*3e8))/((float)(4096*this->bandwidthKhz*1000));
+ } else {
+ *res = (float)rplBuff[3]/2.0f;
+ }
+ }
+
+ return(state);
+}
+
+int16_t LR11x0::setRangingTxRxDelay(uint32_t delay) {
+ return(this->setU32(RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY, delay));
+}
+
+int16_t LR11x0::setGfskCrcParams(uint32_t init, uint32_t poly) {
+ uint8_t buff[8] = {
+ (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF),
+ (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF),
+ (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF),
+ (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF)
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS, true, buff, sizeof(buff)));
+
+}
+
+int16_t LR11x0::setGfskWhitParams(uint16_t seed) {
+ uint8_t buff[2] = {
+ (uint8_t)((seed >> 8) & 0xFF), (uint8_t)(seed & 0xFF)
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setRangingParameter(uint8_t symbolNum) {
+ // the first byte is reserved
+ uint8_t buff[2] = { 0x00, symbolNum };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setRssiCalibration(const int8_t* tune, int16_t gainOffset) {
+ uint8_t buff[11] = {
+ (uint8_t)((tune[0] & 0x0F) | (uint8_t)(tune[1] & 0x0F) << 4),
+ (uint8_t)((tune[2] & 0x0F) | (uint8_t)(tune[3] & 0x0F) << 4),
+ (uint8_t)((tune[4] & 0x0F) | (uint8_t)(tune[5] & 0x0F) << 4),
+ (uint8_t)((tune[6] & 0x0F) | (uint8_t)(tune[7] & 0x0F) << 4),
+ (uint8_t)((tune[8] & 0x0F) | (uint8_t)(tune[9] & 0x0F) << 4),
+ (uint8_t)((tune[10] & 0x0F) | (uint8_t)(tune[11] & 0x0F) << 4),
+ (uint8_t)((tune[12] & 0x0F) | (uint8_t)(tune[13] & 0x0F) << 4),
+ (uint8_t)((tune[14] & 0x0F) | (uint8_t)(tune[15] & 0x0F) << 4),
+ (uint8_t)((tune[16] & 0x0F) | (uint8_t)(tune[17] & 0x0F) << 4),
+ (uint8_t)(((uint16_t)gainOffset >> 8) & 0xFF), (uint8_t)(gainOffset & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::setLoRaSyncWord(uint8_t sync) {
+ uint8_t buff[1] = { sync };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::lrFhssSetSyncWord(uint32_t sync) {
+ return(this->setU32(RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD, sync));
+}
+
+int16_t LR11x0::configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len) {
+ return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON, chan, payload, len));
+}
+
+int16_t LR11x0::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
+ // check if in explicit header mode
+ if(this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(cr) { *cr = (buff[0] & 0x70) >> 4; }
+ if(hasCRC) { *hasCRC = (buff[0] & RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED) != 0; }
+
+ return(state);
+}
+
+int16_t LR11x0::bleBeaconSend(uint8_t chan, const uint8_t* payload, size_t len) {
+ return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND, chan, payload, len));
+}
+
+int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, const uint8_t* payload, size_t len) {
+ // check maximum size
+ // TODO what is the actual maximum?
+ if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+
+ // build buffers
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t dataBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* dataBuff = new uint8_t[sizeof(uint8_t) + len];
+ #endif
+
+ // set the channel
+ dataBuff[0] = chan;
+ memcpy(&dataBuff[1], payload, len);
+
+ int16_t state = this->SPIcommand(cmd, true, dataBuff, sizeof(uint8_t) + len);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] dataBuff;
+ #endif
+ return(state);
+}
+
+int16_t LR11x0::bootEraseFlash(void) {
+ // erasing flash takes about 2.5 seconds, temporarily tset SPI timeout to 3 seconds
+ RadioLibTime_t timeout = this->mod->spiConfig.timeout;
+ this->mod->spiConfig.timeout = 3000;
+ int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, NULL, 0, false, false);
+ this->mod->spiConfig.timeout = timeout;
+ return(state);
+}
+
+int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile) {
+ // check maximum size
+ if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+ return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile));
+}
+
+int16_t LR11x0::bootGetHash(uint8_t hash[RADIOLIB_LR11X0_HASH_LEN]) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_HASH, false, hash, RADIOLIB_LR11X0_HASH_LEN));
+}
+
+int16_t LR11x0::bootReboot(bool stay) {
+ uint8_t buff[1] = { (uint8_t)stay };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_REBOOT, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::bootGetPin(uint8_t* pin) {
+ RADIOLIB_ASSERT_PTR(pin);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN));
+}
+
+int16_t LR11x0::bootGetChipEui(uint8_t* eui) {
+ RADIOLIB_ASSERT_PTR(eui);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
+}
+
+int16_t LR11x0::bootGetJoinEui(uint8_t* eui) {
+ RADIOLIB_ASSERT_PTR(eui);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR11x0_commands.h b/lib/RadioLib/src/modules/LR11x0/LR11x0_commands.h
new file mode 100644
index 0000000..aa4c22f
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR11x0/LR11x0_commands.h
@@ -0,0 +1,585 @@
+#if !defined(RADIOLIB_LR11X0_COMMANDS_H)
+#define RADIOLIB_LR11X0_COMMANDS_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_LR11X0
+
+// LR11X0 SPI commands
+#define RADIOLIB_LR11X0_CMD_NOP (0x0000)
+#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM (0x0105)
+#define RADIOLIB_LR11X0_CMD_READ_REG_MEM (0x0106)
+#define RADIOLIB_LR11X0_CMD_WRITE_BUFFER (0x0109)
+#define RADIOLIB_LR11X0_CMD_READ_BUFFER (0x010A)
+#define RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER (0x010B)
+#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK (0x010C)
+#define RADIOLIB_LR11X0_CMD_GET_STATUS (0x0100)
+#define RADIOLIB_LR11X0_CMD_GET_VERSION (0x0101)
+#define RADIOLIB_LR11X0_CMD_GET_ERRORS (0x010D)
+#define RADIOLIB_LR11X0_CMD_CLEAR_ERRORS (0x010E)
+#define RADIOLIB_LR11X0_CMD_CALIBRATE (0x010F)
+#define RADIOLIB_LR11X0_CMD_SET_REG_MODE (0x0110)
+#define RADIOLIB_LR11X0_CMD_CALIB_IMAGE (0x0111)
+#define RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH (0x0112)
+#define RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS (0x0113)
+#define RADIOLIB_LR11X0_CMD_CLEAR_IRQ (0x0114)
+#define RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK (0x0116)
+#define RADIOLIB_LR11X0_CMD_SET_TCXO_MODE (0x0117)
+#define RADIOLIB_LR11X0_CMD_REBOOT (0x0118)
+#define RADIOLIB_LR11X0_CMD_GET_VBAT (0x0119)
+#define RADIOLIB_LR11X0_CMD_GET_TEMP (0x011A)
+#define RADIOLIB_LR11X0_CMD_SET_SLEEP (0x011B)
+#define RADIOLIB_LR11X0_CMD_SET_STANDBY (0x011C)
+#define RADIOLIB_LR11X0_CMD_SET_FS (0x011D)
+#define RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER (0x0120)
+#define RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE (0x0121)
+#define RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE (0x0122)
+#define RADIOLIB_LR11X0_CMD_READ_INFO_PAGE (0x0123)
+#define RADIOLIB_LR11X0_CMD_GET_CHIP_EUI (0x0125)
+#define RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI (0x0126)
+#define RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN (0x0127)
+#define RADIOLIB_LR11X0_CMD_ENABLE_SPI_CRC (0x0128)
+#define RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE (0x012A)
+#define RADIOLIB_LR11X0_CMD_RESET_STATS (0x0200)
+#define RADIOLIB_LR11X0_CMD_GET_STATS (0x0201)
+#define RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE (0x0202)
+#define RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS (0x0203)
+#define RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS (0x0204)
+#define RADIOLIB_LR11X0_CMD_GET_RSSI_INST (0x0205)
+#define RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD (0x0206)
+#define RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK (0x0208)
+#define RADIOLIB_LR11X0_CMD_SET_RX (0x0209)
+#define RADIOLIB_LR11X0_CMD_SET_TX (0x020A)
+#define RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY (0x020B)
+#define RADIOLIB_LR11X0_CMD_AUTO_TX_RX (0x020C)
+#define RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS (0x020D)
+#define RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE (0x020E)
+#define RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS (0x020F)
+#define RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS (0x0210)
+#define RADIOLIB_LR11X0_CMD_SET_TX_PARAMS (0x0211)
+#define RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS (0x0212)
+#define RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE (0x0213)
+#define RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE (0x0214)
+#define RADIOLIB_LR11X0_CMD_SET_PA_CONFIG (0x0215)
+#define RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE (0x0217)
+#define RADIOLIB_LR11X0_CMD_SET_CAD (0x0218)
+#define RADIOLIB_LR11X0_CMD_SET_TX_CW (0x0219)
+#define RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE (0x021A)
+#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT (0x021B)
+#define RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR (0x021C)
+#define RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR (0x021D)
+#define RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT (0x021E)
+#define RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY (0x021F)
+#define RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS (0x0224)
+#define RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS (0x0225)
+#define RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED (0x0227)
+#define RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER (0x0228)
+#define RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION (0x0229)
+#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD (0x022B)
+#define RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME (0x022C)
+#define RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD (0x022D)
+#define RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON (0x022E)
+#define RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS (0x0230)
+#define RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND (0x0231)
+#define RADIOLIB_LR11X0_CMD_WIFI_SCAN (0x0300)
+#define RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT (0x0301)
+#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE (0x0302)
+#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT (0x0303)
+#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS (0x0305)
+#define RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS (0x0306)
+#define RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS (0x0307)
+#define RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS (0x0308)
+#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS (0x0309)
+#define RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS (0x030A)
+#define RADIOLIB_LR11X0_CMD_WIFI_CFG_TIMESTAMP_AP_PHONE (0x030B)
+#define RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION (0x0320)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI (0x0222)
+#define RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE (0x0400)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE (0x0401)
+#define RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE (0x0402)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE (0x0403)
+#define RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE (0x0404)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE (0x0405)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION (0x0406)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS (0x0407)
+#define RADIOLIB_LR11X0_CMD_GNSS_SET_MODE (0x0408)
+#define RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS (0x0409)
+#define RADIOLIB_LR11X0_CMD_GNSS_ASSISTED (0x040A)
+#define RADIOLIB_LR11X0_CMD_GNSS_SCAN (0x040B)
+#define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D)
+#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E)
+#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE (0x040F)
+#define RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION (0x0410)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION (0x0411)
+#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG (0x0414)
+#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG (0x0415)
+#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS (0x0416)
+#define RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED (0x0417)
+#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED (0x0418)
+#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION (0x0419)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE (0x041A)
+#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE (0x041F)
+#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER (0x0420)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED (0x0426)
+#define RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME (0x0432)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_TIME (0x0434)
+#define RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME (0x0435)
+#define RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION (0x0437)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER (0x0438)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS (0x0439)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING (0x044A)
+#define RADIOLIB_LR11X0_CMD_GNSS_SET_TIME (0x044B)
+#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP (0x044D)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES (0x044F)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP (0x0453)
+#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT (0x0454)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS (0x0456)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS (0x0457)
+#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD (0x0463)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD (0x0464)
+#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START (0x0466)
+#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC (0x0466)
+#define RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS (0x0469)
+#define RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED (0x0472)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY (0x0502)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY (0x0503)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT (0x0504)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC (0x0505)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC (0x0506)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01 (0x0507)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT (0x0508)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT (0x0509)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH (0x050A)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH (0x050B)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM (0x050D)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM (0x050E)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE (0x050F)
+#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT (0x0510)
+#define RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH (0x8000)
+#define RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED (0x8003)
+#define RADIOLIB_LR11X0_CMD_BOOT_GET_HASH (0x8004)
+#define RADIOLIB_LR11X0_CMD_BOOT_REBOOT (0x8005)
+#define RADIOLIB_LR11X0_CMD_BOOT_GET_PIN (0x800B)
+#define RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI (0x800C)
+#define RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI (0x800D)
+
+// LR11X0 SPI command variables
+
+// RADIOLIB_LR11X0_CMD_GET_STATUS MSB LSB DESCRIPTION
+#define RADIOLIB_LR11X0_STAT_1_CMD_FAIL (0x00UL << 1) // 3 1 command status: last command could not be executed
+#define RADIOLIB_LR11X0_STAT_1_CMD_PERR (0x01UL << 1) // 3 1 processing error
+#define RADIOLIB_LR11X0_STAT_1_CMD_OK (0x02UL << 1) // 3 1 successfully processed
+#define RADIOLIB_LR11X0_STAT_1_CMD_DAT (0x03UL << 1) // 3 1 successfully processed, data is being transmitted
+#define RADIOLIB_LR11X0_STAT_1_IRQ_INACTIVE (0x00UL << 0) // 0 0 interrupt status: inactive
+#define RADIOLIB_LR11X0_STAT_1_IRQ_ACTIVE (0x01UL << 0) // 0 0 at least 1 interrupt active
+#define RADIOLIB_LR11X0_STAT_2_CMD_RST_CLEARED (0x00UL << 4) // 7 4 reset status: cleared
+#define RADIOLIB_LR11X0_STAT_2_CMD_RST_ANALOG (0x01UL << 4) // 7 4 analog (power on, brown-out)
+#define RADIOLIB_LR11X0_STAT_2_CMD_RST_EXTERNAL (0x02UL << 4) // 7 4 NRESET pin
+#define RADIOLIB_LR11X0_STAT_2_CMD_RST_SYSTEM (0x03UL << 4) // 7 4 system
+#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WATCHDOG (0x04UL << 4) // 7 4 watchdog
+#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WAKEUP (0x05UL << 4) // 7 4 NSS toggling wake-up
+#define RADIOLIB_LR11X0_STAT_2_CMD_RST_RTC (0x06UL << 4) // 7 4 realtime clock
+#define RADIOLIB_LR11X0_STAT_2_MODE_SLEEP (0x00UL << 1) // 3 1 chip mode: sleep
+#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_RC (0x01UL << 1) // 3 1 standby with RC oscillator
+#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_OSC (0x02UL << 1) // 3 1 standby with external oscillator
+#define RADIOLIB_LR11X0_STAT_2_MODE_FS (0x03UL << 1) // 3 1 frequency synthesis
+#define RADIOLIB_LR11X0_STAT_2_MODE_RX (0x04UL << 1) // 3 1 receive
+#define RADIOLIB_LR11X0_STAT_2_MODE_TX (0x05UL << 1) // 3 1 transmit
+#define RADIOLIB_LR11X0_STAT_2_MODE_WIFI_GNSS (0x06UL << 1) // 3 1 WiFi or GNSS geolocation
+#define RADIOLIB_LR11X0_STAT_2_BOOT (0x00UL << 0) // 0 0 code executed from: bootloader
+#define RADIOLIB_LR11X0_STAT_2_FLASH (0x01UL << 0) // 0 0 flash
+
+// RADIOLIB_LR11X0_CMD_WRITE_REG_MEM
+#define RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN (256) // 7 0 maximum length of read/write SPI payload in bytes
+
+// RADIOLIB_LR11X0_CMD_GET_VERSION
+#define RADIOLIB_LR11X0_DEVICE_LR1110 (0x01UL << 0) // 7 0 HW device: LR1110
+#define RADIOLIB_LR11X0_DEVICE_LR1120 (0x02UL << 0) // 7 0 LR1120
+#define RADIOLIB_LR11X0_DEVICE_LR1121 (0x03UL << 0) // 7 0 LR1121
+#define RADIOLIB_LR11X0_DEVICE_BOOT (0xDFUL << 0) // 7 0 bootloader mode
+
+// RADIOLIB_LR11X0_CMD_GET_ERRORS
+#define RADIOLIB_LR11X0_ERROR_STAT_LF_RC_CALIB_ERR (0x01UL << 0) // 15 0 error: low frequency RC not calibrated
+#define RADIOLIB_LR11X0_ERROR_STAT_HF_RC_CALIB_ERR (0x01UL << 1) // 15 0 high frequency RC not calibrated
+#define RADIOLIB_LR11X0_ERROR_STAT_ADC_CALIB_ERR (0x01UL << 2) // 15 0 ADC not calibrated
+#define RADIOLIB_LR11X0_ERROR_STAT_PLL_CALIB_ERR (0x01UL << 3) // 15 0 PLL not calibrated
+#define RADIOLIB_LR11X0_ERROR_STAT_IMG_CALIB_ERR (0x01UL << 4) // 15 0 image rejection not calibrated
+#define RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR (0x01UL << 5) // 15 0 high frequency oscillator failed to start
+#define RADIOLIB_LR11X0_ERROR_STAT_LF_XOSC_START_ERR (0x01UL << 6) // 15 0 low frequency oscillator failed to start
+#define RADIOLIB_LR11X0_ERROR_STAT_PLL_LOCK_ERR (0x01UL << 7) // 15 0 PLL failed to lock
+#define RADIOLIB_LR11X0_ERROR_STAT_RX_ADC_OFFSET_ERR (0x01UL << 8) // 15 0 ADC offset not calibrated
+
+// RADIOLIB_LR11X0_CMD_CALIBRATE
+#define RADIOLIB_LR11X0_CALIBRATE_PLL_TX (0x01UL << 5) // 5 5 calibrate: Tx PLL
+#define RADIOLIB_LR11X0_CALIBRATE_IMG (0x01UL << 4) // 4 4 image rejection
+#define RADIOLIB_LR11X0_CALIBRATE_ADC (0x01UL << 3) // 3 3 A/D converter
+#define RADIOLIB_LR11X0_CALIBRATE_PLL (0x01UL << 2) // 2 2 PLL
+#define RADIOLIB_LR11X0_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high frequency RC
+#define RADIOLIB_LR11X0_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 low frequency RC
+#define RADIOLIB_LR11X0_CALIBRATE_ALL (0x3FUL << 0) // 5 0 everything
+#define RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG_MHZ (20.0f)
+
+// RADIOLIB_LR11X0_CMD_SET_REG_MODE
+#define RADIOLIB_LR11X0_REG_MODE_LDO (0x00UL << 0) // 0 0 regulator mode: LDO in all modes
+#define RADIOLIB_LR11X0_REG_MODE_DC_DC (0x01UL << 0) // 0 0 DC-DC and LDO
+
+// RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH
+#define RADIOLIB_LR11X0_RFSW_DIO5_ENABLED (0x01UL << 0) // 4 0 RF switch: DIO5 enabled
+#define RADIOLIB_LR11X0_RFSW_DIO5_DISABLED (0x00UL << 0) // 4 0 DIO5 disabled (default)
+#define RADIOLIB_LR11X0_RFSW_DIO6_ENABLED (0x01UL << 1) // 4 0 RF switch: DIO6 enabled
+#define RADIOLIB_LR11X0_RFSW_DIO6_DISABLED (0x00UL << 1) // 4 0 DIO6 disabled (default)
+#define RADIOLIB_LR11X0_RFSW_DIO7_ENABLED (0x01UL << 2) // 4 0 RF switch: DIO7 enabled
+#define RADIOLIB_LR11X0_RFSW_DIO7_DISABLED (0x00UL << 2) // 4 0 DIO7 disabled (default)
+#define RADIOLIB_LR11X0_RFSW_DIO8_ENABLED (0x01UL << 3) // 4 0 RF switch: DIO8 enabled
+#define RADIOLIB_LR11X0_RFSW_DIO8_DISABLED (0x00UL << 3) // 4 0 DIO8 disabled (default)
+#define RADIOLIB_LR11X0_RFSW_DIO10_ENABLED (0x01UL << 4) // 4 0 RF switch: DIO10 enabled
+#define RADIOLIB_LR11X0_RFSW_DIO10_DISABLED (0x00UL << 4) // 4 0 DIO10 disabled (default)
+#define RADIOLIB_LR11X0_DIO5 (RADIOLIB_LRXXXX_DIOx(0))
+#define RADIOLIB_LR11X0_DIO6 (RADIOLIB_LRXXXX_DIOx(1))
+#define RADIOLIB_LR11X0_DIO7 (RADIOLIB_LRXXXX_DIOx(2))
+#define RADIOLIB_LR11X0_DIO8 (RADIOLIB_LRXXXX_DIOx(3))
+#define RADIOLIB_LR11X0_DIO10 (RADIOLIB_LRXXXX_DIOx(4))
+
+// RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS
+#define RADIOLIB_LR11X0_IRQ_TX_DONE (0x01UL << 2) // 31 0 interrupt: packet transmitted
+#define RADIOLIB_LR11X0_IRQ_RX_DONE (0x01UL << 3) // 31 0 packet received
+#define RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED (0x01UL << 4) // 31 0 preamble detected
+#define RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID (0x01UL << 5) // 31 0 sync word or LoRa header valid
+#define RADIOLIB_LR11X0_IRQ_HEADER_ERR (0x01UL << 6) // 31 0 LoRa header CRC error
+#define RADIOLIB_LR11X0_IRQ_CRC_ERR (0x01UL << 7) // 31 0 packet CRC error
+#define RADIOLIB_LR11X0_IRQ_CAD_DONE (0x01UL << 8) // 31 0 CAD completed
+#define RADIOLIB_LR11X0_IRQ_CAD_DETECTED (0x01UL << 9) // 31 0 CAD detected
+#define RADIOLIB_LR11X0_IRQ_TIMEOUT (0x01UL << 10) // 31 0 Rx or Tx timeout
+#define RADIOLIB_LR11X0_IRQ_LR_FHSS_HOP (0x01UL << 11) // 31 0 FHSS hop
+#define RADIOLIB_LR11X0_IRQ_GNSS_DONE (0x01UL << 19) // 31 0 GNSS scan finished
+#define RADIOLIB_LR11X0_IRQ_WIFI_DONE (0x01UL << 20) // 31 0 WiFi scan finished
+#define RADIOLIB_LR11X0_IRQ_LBD (0x01UL << 21) // 31 0 low battery detected
+#define RADIOLIB_LR11X0_IRQ_CMD_ERROR (0x01UL << 22) // 31 0 command error
+#define RADIOLIB_LR11X0_IRQ_ERROR (0x01UL << 23) // 31 0 some other error than CMD_ERR
+#define RADIOLIB_LR11X0_IRQ_FSK_LEN_ERROR (0x01UL << 24) // 31 0 FSK packet received with length error
+#define RADIOLIB_LR11X0_IRQ_FSK_ADDR_ERROR (0x01UL << 25) // 31 0 FSK packet received with address error
+#define RADIOLIB_LR11X0_IRQ_LORA_RX_TIMESTAMP (0x01UL << 27) // 31 0 last LoRa symbol was received (timestamp source)
+#define RADIOLIB_LR11X0_IRQ_GNSS_ABORT (0x01UL << 28) // 31 0 GNSS scan aborted
+#define RADIOLIB_LR11X0_IRQ_ALL (0x1BF80FFCUL) // 31 0 all interrupts
+#define RADIOLIB_LR11X0_IRQ_NONE (0x00UL << 0) // 31 0 no interrupts
+
+// RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK
+#define RADIOLIB_LR11X0_LF_CLK_RC (0x00UL << 0) // 1 0 32.768 kHz source: RC oscillator
+#define RADIOLIB_LR11X0_LF_CLK_XOSC (0x01UL << 0) // 1 0 crystal oscillator
+#define RADIOLIB_LR11X0_LF_CLK_EXT (0x02UL << 0) // 1 0 external signal on DIO11
+#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED (0x00UL << 2) // 2 2
+#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_ENABLED (0x01UL << 2) // 2 2
+
+// RADIOLIB_LR11X0_CMD_SET_SLEEP
+#define RADIOLIB_LR11X0_SLEEP_RETENTION_DISABLED (0x00UL << 0) // 0 0 configuration retention in sleep mode: disabled
+#define RADIOLIB_LR11X0_SLEEP_RETENTION_ENABLED (0x01UL << 0) // 0 0 enabled
+#define RADIOLIB_LR11X0_SLEEP_WAKEUP_DISABLED (0x00UL << 0) // 1 1 automated wakeup: disabled
+#define RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED (0x01UL << 0) // 1 1 enabled
+
+// RADIOLIB_LR11X0_CMD_SET_STANDBY
+#define RADIOLIB_LR11X0_STANDBY_RC (0x00UL << 0) // 7 0 standby mode: RC oscillator
+#define RADIOLIB_LR11X0_STANDBY_XOSC (0x00UL << 0) // 7 0 XTAL/TCXO oscillator
+
+// RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE
+#define RADIOLIB_LR11X0_INFO_PAGE (1)
+
+// RADIOLIB_LR11X0_CMD_GET_CHIP_EUI
+#define RADIOLIB_LR11X0_EUI_LEN (8)
+
+// RADIOLIB_LR11X0_CMD_GET_HASH
+#define RADIOLIB_LR11X0_HASH_LEN (10)
+
+// RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN
+#define RADIOLIB_LR11X0_PIN_LEN (4)
+
+// RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS
+#define RADIOLIB_LR11X0_RX_STATUS_ADDR_ERR (0x01UL << 5) // 7 0 Rx status: address filtering error
+#define RADIOLIB_LR11X0_RX_STATUS_CRC_ERR (0x01UL << 4) // 7 0 CRC error
+#define RADIOLIB_LR11X0_RX_STATUS_LEN_ERR (0x01UL << 3) // 7 0 length filtering error
+#define RADIOLIB_LR11X0_RX_STATUS_ABORTED (0x01UL << 2) // 7 0 packet reception aborted
+#define RADIOLIB_LR11X0_RX_STATUS_PACKET_RECEIVED (0x01UL << 1) // 7 0 packet received
+#define RADIOLIB_LR11X0_RX_STATUS_PACKET_SENT (0x01UL << 0) // 7 0 packet sent
+
+// RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD
+#define RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN (8)
+
+// RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK
+#define RADIOLIB_LR11X0_LORA_PRIVATE_NETWORK (0x00UL << 0) // 7 0 LoRa sync word: private network
+#define RADIOLIB_LR11X0_LORA_PUBLIC_NETWORK (0x01UL << 0) // 7 0 public network
+
+// RADIOLIB_LR11X0_CMD_SET_RX
+#define RADIOLIB_LR11X0_RX_TIMEOUT_NONE (0x000000UL) // 23 0 Rx timeout duration: no timeout (Rx single mode)
+#define RADIOLIB_LR11X0_RX_TIMEOUT_INF (0xFFFFFFUL) // 23 0 infinite (Rx continuous mode)
+
+// RADIOLIB_LR11X0_CMD_SET_TX
+#define RADIOLIB_LR11X0_TX_TIMEOUT_NONE (0x000000UL) // 23 0 disable Tx timeout
+
+// RADIOLIB_LR11X0_CMD_AUTO_TX_RX
+#define RADIOLIB_LR11X0_AUTO_TX_RX_DISABLED (0xFFFFFFUL) // 23 0 disable auto Tx/Rx mode
+#define RADIOLIB_LR11X0_AUTO_TX_RX_SKIP_INT (0x000000UL) // 23 0 skip intermediary mode
+#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_SLEEP (0x00UL << 0) // 1 0 intermediary mode: sleep
+#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_RC (0x01UL << 0) // 1 0 standby with RC
+#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC
+#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis
+#define RADIOLIB_LR11X0_AUTO_TX_RX_TIMEOUT_DISABLED (0x000000UL) // 23 0 disable timeout of the second mode
+
+// RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS
+#define RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC (0x00UL << 0) // 7 0 mode to set after CAD: standby with RC
+#define RADIOLIB_LR11X0_CAD_EXIT_MODE_RX (0x01UL << 0) // 7 0 receive if activity detected
+#define RADIOLIB_LR11X0_CAD_EXIT_MODE_LBT (0x10UL << 0) // 7 0 transmit if no activity detected
+#define RADIOLIB_LR11X0_CAD_PARAM_DEFAULT (0xFFUL << 0) // 7 0 used by the CAD methods to specify default parameter value
+
+// RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE
+#define RADIOLIB_LR11X0_PACKET_TYPE_NONE (0x00UL << 0) // 2 0 packet type: none
+#define RADIOLIB_LR11X0_PACKET_TYPE_GFSK (0x01UL << 0) // 2 0 (G)FSK
+#define RADIOLIB_LR11X0_PACKET_TYPE_LORA (0x02UL << 0) // 2 0 LoRa
+#define RADIOLIB_LR11X0_PACKET_TYPE_SIGFOX (0x03UL << 0) // 2 0 Sigfox
+#define RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS (0x04UL << 0) // 2 0 GMSK/LR-FHSS
+#define RADIOLIB_LR11X0_PACKET_TYPE_RANGING (0x05UL << 0) // 2 0 ranging
+#define RADIOLIB_LR11X0_PACKET_TYPE_BLE (0x06UL << 0) // 2 0 BLE beacon
+
+// RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS
+#define RADIOLIB_LR11X0_LORA_BW_62_5 (0x03UL << 0) // 7 0 LoRa bandwidth: 62.5 kHz
+#define RADIOLIB_LR11X0_LORA_BW_125_0 (0x04UL << 0) // 7 0 125.0 kHz
+#define RADIOLIB_LR11X0_LORA_BW_250_0 (0x05UL << 0) // 7 0 250.0 kHz
+#define RADIOLIB_LR11X0_LORA_BW_500_0 (0x06UL << 0) // 7 0 500.0 kHz
+#define RADIOLIB_LR11X0_LORA_BW_203_125 (0x0DUL << 0) // 7 0 203.0 kHz (2.4GHz only)
+#define RADIOLIB_LR11X0_LORA_BW_406_25 (0x0EUL << 0) // 7 0 406.0 kHz (2.4GHz only)
+#define RADIOLIB_LR11X0_LORA_BW_812_50 (0x0FUL << 0) // 7 0 812.0 kHz (2.4GHz only)
+#define RADIOLIB_LR11X0_LORA_CR_4_5_SHORT (0x01UL << 0) // 7 0 coding rate: 4/5 with short interleaver
+#define RADIOLIB_LR11X0_LORA_CR_4_6_SHORT (0x02UL << 0) // 7 0 4/6 with short interleaver
+#define RADIOLIB_LR11X0_LORA_CR_4_7_SHORT (0x03UL << 0) // 7 0 4/7 with short interleaver
+#define RADIOLIB_LR11X0_LORA_CR_4_8_SHORT (0x04UL << 0) // 7 0 4/8 with short interleaver
+#define RADIOLIB_LR11X0_LORA_CR_4_5_LONG (0x05UL << 0) // 7 0 4/5 with long interleaver
+#define RADIOLIB_LR11X0_LORA_CR_4_6_LONG (0x06UL << 0) // 7 0 4/6 with long interleaver
+#define RADIOLIB_LR11X0_LORA_CR_4_8_LONG (0x07UL << 0) // 7 0 4/8 with long interleaver
+#define RADIOLIB_LR11X0_LORA_LDRO_DISABLED (0x00UL << 0) // 7 0 low data rate optimize: disabled
+#define RADIOLIB_LR11X0_LORA_LDRO_ENABLED (0x01UL << 0) // 7 0 enabled
+#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_DISABLED (0x00UL << 31) // 31 0 divide bit rate value by 256: disabled
+#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_ENABLED (0x01UL << 31) // 31 0 enabled
+#define RADIOLIB_LR11X0_GFSK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none
+#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_3 (0x08UL << 0) // 7 0 Gaussian, BT = 0.3
+#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_5 (0x09UL << 0) // 7 0 Gaussian, BT = 0.5
+#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_7 (0x0AUL << 0) // 7 0 Gaussian, BT = 0.7
+#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 Gaussian, BT = 1.0
+#define RADIOLIB_LR11X0_GFSK_SHAPING_RAISED_COSINE_BT_0_7 (0x16UL << 0) // 7 0 raised cosine, BT = 0.7
+#define RADIOLIB_LR11X0_GFSK_RX_BW_4_8 (0x1FUL << 0) // 7 0 GFSK Rx bandwidth: 4.8 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_5_8 (0x17UL << 0) // 7 0 5.8 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_7_3 (0x0FUL << 0) // 7 0 7.3 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_9_7 (0x1EUL << 0) // 7 0 9.7 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_11_7 (0x16UL << 0) // 7 0 11.7 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_14_6 (0x0EUL << 0) // 7 0 14.6 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_19_5 (0x1DUL << 0) // 7 0 19.5 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_23_4 (0x15UL << 0) // 7 0 23.4 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_29_3 (0x0DUL << 0) // 7 0 29.3 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_39_0 (0x1CUL << 0) // 7 0 39.0 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_46_9 (0x14UL << 0) // 7 0 46.9 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_58_6 (0x0CUL << 0) // 7 0 58.6 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_78_2 (0x1BUL << 0) // 7 0 78.2 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_93_8 (0x13UL << 0) // 7 0 93.8 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_117_3 (0x0BUL << 0) // 7 0 117.3 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_156_2 (0x1AUL << 0) // 7 0 156.2 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_187_2 (0x12UL << 0) // 7 0 187.2 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_234_3 (0x0AUL << 0) // 7 0 234.3 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_312_0 (0x19UL << 0) // 7 0 312.0 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_373_6 (0x11UL << 0) // 7 0 373.6 kHz
+#define RADIOLIB_LR11X0_GFSK_RX_BW_467_0 (0x09UL << 0) // 7 0 467.0 kHz
+#define RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 shaping filter: Gaussian, BT = 1.0
+#define RADIOLIB_LR11X0_SIGFOX_SHAPING_GAUSSIAN_BT_0_7 (0x16UL << 0) // 7 0 shaping filter: Gaussian, BT = 0.7
+
+// RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS
+#define RADIOLIB_LR11X0_LORA_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length
+#define RADIOLIB_LR11X0_LORA_IQ_STANDARD (0x00UL << 0) // 7 0 IQ setup: standard
+#define RADIOLIB_LR11X0_LORA_IQ_INVERTED (0x01UL << 0) // 7 0 inverted
+#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_DISABLED (0x00UL << 0) // 7 0 preamble detector: disabled
+#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_8_BITS (0x04UL << 0) // 7 0 8 bits
+#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS (0x05UL << 0) // 7 0 16 bits
+#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS (0x06UL << 0) // 7 0 24 bits
+#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS (0x07UL << 0) // 7 0 32 bits
+#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled
+#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE (0x01UL << 0) // 7 0 node address
+#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast address
+#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED (0x00UL << 0) // 7 0 packet length: fixed
+#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE (0x01UL << 0) // 7 0 variable
+#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE_SX128X (0x02UL << 0) // 7 0 variable, SX128x 9-bit length encoding
+#define RADIOLIB_LR11X0_GFSK_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length
+#define RADIOLIB_LR11X0_GFSK_CRC_DISABLED (0x01UL << 0) // 7 0 CRC: disabled
+#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE (0x00UL << 0) // 7 0 1-byte
+#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE (0x02UL << 0) // 7 0 2-byte
+#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV (0x04UL << 0) // 7 0 1-byte, inverted
+#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV (0x06UL << 0) // 7 0 2-byte, inverted
+#define RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED (0x00UL << 0) // 7 0 whitening: disabled
+#define RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED (0x01UL << 0) // 7 0 enabled
+
+// RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE
+#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC
+#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC
+#define RADIOLIB_LR11X0_FALLBACK_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis
+
+// RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE
+#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_RX (0x00UL << 0) // 0 0 mode in Rx windows: Rx (default)
+#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_CAD (0x01UL << 0) // 0 0 CAD
+#define RADIOLIB_LR11X0_TIMING_STEP (1.0f/32768.0f) // 23 0 timing step fo delays
+
+// RADIOLIB_LR11X0_CMD_SET_PA_CONFIG
+#define RADIOLIB_LR11X0_PA_SEL_LP (0x00UL << 0) // 7 0 PA select: low power PA
+#define RADIOLIB_LR11X0_PA_SEL_HP (0x01UL << 0) // 7 0 high power PA
+#define RADIOLIB_LR11X0_PA_SEL_HF (0x02UL << 0) // 7 0 high frequency PA
+#define RADIOLIB_LR11X0_PA_SUPPLY_INTERNAL (0x00UL << 0) // 7 0 PA power source: internal
+#define RADIOLIB_LR11X0_PA_SUPPLY_VBAT (0x01UL << 0) // 7 0 VBAT (required for >= 14 dBm)
+#define RADIOLIB_LR11X0_PA_DC_DEFAULT (0x04UL << 0) // 7 0 PA duty cycle: default value
+#define RADIOLIB_LR11X0_PA_DC_MAX (0x07UL << 0) // 7 0 maximum value
+
+// RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE
+#define RADIOLIB_LR11X0_STOP_ON_SYNC_HEADER (0x00UL << 0) // 0 0 stop timeout on: sync word or header (default)
+#define RADIOLIB_LR11X0_STOP_ON_PREAMBLE (0x01UL << 0) // 0 0 preamble
+
+// RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT
+#define RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE (0) // 7 0 ranging result type: distance
+#define RADIOLIB_LR11X0_RANGING_RESULT_RSSI (1) // 7 0 RSSI
+
+// RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED
+#define RADIOLIB_LR11X0_RX_BOOSTED_ENABLED (0x01UL << 0) // 0 0 Rx boosted mode: enabled
+#define RADIOLIB_LR11X0_RX_BOOSTED_DISABLED (0x00UL << 0) // 0 0 disabled
+
+// RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD
+#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12)
+#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PUBLIC (0x34)
+
+// RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS
+#define RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED (0x01UL << 4) // 4 4 last header CRC: enabled
+#define RADIOLIB_LR11X0_LAST_HEADER_CRC_DISABLED (0x00UL << 4) // 4 4 disabled
+
+// RADIOLIB_LR11X0_CMD_WIFI_SCAN
+#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_B (0x01UL << 0) // 7 0 Wi-Fi type to scan: 802.11b
+#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_G (0x02UL << 0) // 7 0 802.11g
+#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_N (0x03UL << 0) // 7 0 802.11n
+#define RADIOLIB_LR11X0_WIFI_SCAN_ALL (0x04UL << 0) // 7 0 all (802.11b first)
+#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_ONLY (0x01UL << 0) // 7 0 Wi-Fi acquisition mode: beacon only
+#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_PACKET (0x02UL << 0) // 7 0 beacon and packet
+#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_TRAFFIC (0x03UL << 0) // 7 0 full traffic
+#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON (0x04UL << 0) // 7 0 full beacon
+#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_SSID_BEACON (0x05UL << 0) // 7 0 SSID beacon
+#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED (0x01UL << 0) // 7 0 abort scanning on preamble timeout: enabled
+#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_DISABLED (0x00UL << 0) // 7 0 disabled
+#define RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS (32) // 7 0 maximum possible number of Wi-Fi scan results
+#define RADIOLIB_LR11X0_WIFI_ALL_CHANNELS (0x3FFFUL) // 16 0 scan all channels
+
+// RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS
+#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE (0x01UL << 0) // 7 0 Wi-Fi scan result type: complete
+#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC (0x04UL << 0) // 7 0 basic
+#define RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN (79) // 7 0 maximum possible Wi-Fi scan size
+
+// RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE
+#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS (0x01UL << 0) // 7 0 GNSS constellation to use: GPS
+#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU (0x01UL << 1) // 7 0 BeiDou
+
+// RADIOLIB_LR11X0_CMD_GNSS_SET_MODE
+#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_SCAN (0x00UL << 0) // 7 0 GNSS scanning mode: single/legacy
+#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_MULTIPLE (0x03UL << 1) // 7 0 multiple/advanced
+
+// RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS
+#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_ENABLED (0x01UL << 0) // 0 0 GNSS results in NAV message: pseudo-range (in single scan mode) or Doppler information (in multiple scan mode)
+#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_DISABLED (0x00UL << 0) // 0 0 not included
+#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_ENABLED (0x01UL << 1) // 1 1 Doppler information
+#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_DISABLED (0x00UL << 1) // 1 1 not included
+#define RADIOLIB_LR11X0_GNSS_NB_SV_ALL (0x00UL << 0) // 7 0 include all detected satellites
+#define RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE (0x00UL << 0) // 7 0 reserved, always 0
+
+// RADIOLIB_LR11X0_CMD_GNSS_ASSISTED
+#define RADIOLIB_LR11X0_GNSS_ASSIST_LOW_POWER (0x00UL << 0) // 7 0 effort mode: low power
+#define RADIOLIB_LR11X0_GNSS_ASSIST_BEST_EFFORT (0x01UL << 0) // 7 0 best effort
+
+// RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS
+#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_NONE (0x00UL << 0) // 7 4 error code: none
+#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_OLD (0x01UL << 0) // 7 4 almanac too old
+#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_CRC (0x02UL << 0) // 7 4 almanac CRC mismatch
+#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_FLASH (0x03UL << 0) // 7 4 flash integrity error
+#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_UPD (0x04UL << 0) // 7 4 almanac update not allowed
+#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_250_HZ (0x00UL << 0) // 8 7 frequency search space: 250 Hz
+#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_500_HZ (0x01UL << 0) // 8 7 500 Hz
+#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_1000_HZ (0x02UL << 0) // 8 7 1000 Hz
+#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_2000_HZ (0x03UL << 0) // 8 7 2000 Hz
+
+// RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE
+#define RADIOLIB_LR11X0_SV_CONSTELLATION_GPS (0x00UL << 0) // 7 0 GNSS constellation: GPS
+#define RADIOLIB_LR11X0_SV_CONSTELLATION_BEIDOU (0x01UL << 0) // 7 0 BeiDou
+
+// RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE
+#define RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID (0x80UL << 0) // 7 0 starting byte of GNSS almanac header
+#define RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE (20)
+
+// RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME
+#define RADIOLIB_LR11X0_GNSS_EFFORT_LOW (0x00UL << 0) // 7 0 GNSS effort mode: low sensitivity
+#define RADIOLIB_LR11X0_GNSS_EFFORT_MID (0x01UL << 0) // 7 0 medium sensitivity
+#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW (0x00UL << 0) // 7 0 time fetch options: ToW only, requires WN to demodulated beforehand
+#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN (0x01UL << 0) // 7 0 ToW and WN
+#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN_ROLL (0x02UL << 0) // 7 0 ToW, WN and rollover
+
+// RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NOT_POSSIBLE (-21) // 7 0 GNSS demodulation status: not possible to demodulate
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SAT_LOST (-20) // 7 0 satellite lost
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALMANAC_DEMOD_ERROR (-19) // 7 0 almanac demodulation error
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOO_LATE (-18) // 7 0 woke up after preamble (demodulation started too late)
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_20_MS_FAIL (-17) // 7 0 20ms real-time clock failed
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WAKE_UP_FAIL (-16) // 7 0 wake up sync failed
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_INVALID (-15) // 7 0 week number not validated
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_ACTIVE_SAT (-14) // 7 0 no active satellite selected in satellite list
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SLEEP_TOO_LONG (-13) // 7 0 sleep time too long
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_INVALID (-12) // 7 0 wrong time-of-week demodulated
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PREAMBLE_INVALID (-11) // 7 0 preamble not validated
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_DISABLED (-10) // 7 0 demodulator disabled
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_EXTR_FAILED (-9) // 7 0 demodulator extraction failed
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE (-8) // 7 0 no bit change found during demodulation start
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE_ADV (-7) // 7 0 no bit change found during advanced scan
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_SAT_FOUND (-6) // 7 0 no satellites found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SYNC_LOST (-5) // 7 0 word sync lost
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_NOT_ENOUGH (-3) // 7 0 parity check fail (not enough)
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_TOO_MANY (-2) // 7 0 parity check fail (too many)
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_PARITY (-1) // 7 0 parity check fail (no parity found)
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_NONE (0) // 7 0 word sync search not started
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_POT (1) // 7 0 potential word sync found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_OK (2) // 7 0 word sync found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND (3) // 7 0 time-of-week found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_FOUND (4) // 7 0 week number and time-of-week found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALM_FOUND_UNSAVED (5) // 7 0 almanac found but not saved
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_HALF_ALM_SAVED (6) // 7 0 half of almanac found and saved
+#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_FULL_ALM_SAVED (7) // 7 0 full almanac found and saved
+#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WORD_SYNC_FOUND (0x01UL << 0) // 7 0 GNSS demodulation info: word synchronization found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_TOW_FOUND (0x01UL << 1) // 7 0 time-of-week found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_DEMODED (0x01UL << 2) // 7 0 week number demodulated
+#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_FOUND (0x01UL << 3) // 7 0 week number found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_1_FOUND (0x01UL << 4) // 7 0 subframe 1 found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_4_FOUND (0x01UL << 5) // 7 0 subframe 4 found
+#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_5_FOUND (0x01UL << 6) // 7 0 subframe 5 found
+
+// RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS
+#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE (0) // 7 0 GPS/BeiDou almanac status: all satellites up-to-date
+#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_OUTDATED (1) // 7 0 at least one satellite needs update
+
+// RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES
+#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NONE (0) // 7 0 internal 2D solver error: no error
+#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_RES_HIGH (1) // 7 0 residue too high
+#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_CONVERGED (2) // 7 0 not converged on solution
+#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_ENOUGH_SV (3) // 7 0 not enough satellites
+#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ILL_MATRIX (4) // 7 0 matrix error (?)
+#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_TIME (5) // 7 0 time error
+#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_PART_OLD (6) // 7 0 part of almanac too old or not available
+#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_INCONSISTENT (7) // 7 0 not consistent with history (?)
+#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_OLD (8) // 7 0 all of almanac too old
+
+// RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY
+#define RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS (0x00UL << 0) // 7 0 crypto engine status: success
+#define RADIOLIB_LR11X0_CRYPTO_STATUS_FAIL_CMAC (0x01UL << 0) // 7 0 MIC check failed
+#define RADIOLIB_LR11X0_CRYPTO_STATUS_INV_KEY_ID (0x03UL << 0) // 7 0 key/parameter source or destination ID error
+#define RADIOLIB_LR11X0_CRYPTO_STATUS_BUF_SIZE (0x05UL << 0) // 7 0 data buffer size invalid
+#define RADIOLIB_LR11X0_CRYPTO_STATUS_ERROR (0x06UL << 0) // 7 0 generic error
+
+// RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT
+#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_0 (0x00UL << 0) // 7 0 LoRaWAN version: 1.0.x
+#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_1 (0x01UL << 0) // 7 0 1.1
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR11x0_crypto.cpp b/lib/RadioLib/src/modules/LR11x0/LR11x0_crypto.cpp
new file mode 100644
index 0000000..625db10
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR11x0/LR11x0_crypto.cpp
@@ -0,0 +1,233 @@
+#include "LR11x0.h"
+
+#include "../../utils/Cryptography.h"
+#include "LR_common.h"
+
+#include
+
+#if !RADIOLIB_EXCLUDE_LR11X0
+
+int16_t LR11x0::cryptoSetKey(uint8_t keyId, const uint8_t* key) {
+ RADIOLIB_ASSERT_PTR(key);
+ uint8_t buff[1 + RADIOLIB_AES128_KEY_SIZE] = { 0 };
+ buff[0] = keyId;
+ memcpy(&buff[1], key, RADIOLIB_AES128_KEY_SIZE);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY, false, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, const uint8_t* key) {
+ RADIOLIB_ASSERT_PTR(key);
+ uint8_t buff[2 + RADIOLIB_AES128_KEY_SIZE] = { 0 };
+ buff[0] = srcKeyId;
+ buff[1] = dstKeyId;
+ memcpy(&buff[2], key, RADIOLIB_AES128_KEY_SIZE);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY, false, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, const uint8_t* header, const uint8_t* dataIn, size_t len, uint8_t* dataOut) {
+ // calculate buffer sizes
+ size_t headerLen = 1;
+ if(lwVer) {
+ headerLen += 11; // LoRaWAN 1.1 header is 11 bytes longer than 1.0
+ }
+ size_t reqLen = 3*sizeof(uint8_t) + headerLen + len;
+ size_t rplLen = sizeof(uint8_t) + len;
+
+ // build buffers
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* reqBuff = new uint8_t[reqLen];
+ uint8_t* rplBuff = new uint8_t[rplLen];
+ #endif
+
+ // set the request fields
+ reqBuff[0] = decKeyId;
+ reqBuff[1] = verKeyId;
+ reqBuff[2] = lwVer;
+ memcpy(&reqBuff[3], header, headerLen);
+ memcpy(&reqBuff[3 + headerLen], dataIn, len);
+
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT, false, rplBuff, rplLen, reqBuff, reqLen);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] reqBuff;
+ #endif
+ if(state != RADIOLIB_ERR_NONE) {
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] rplBuff;
+ #endif
+ return(state);
+ }
+
+ // check the crypto engine state
+ if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] rplBuff;
+ #endif
+ return(RADIOLIB_ERR_SPI_CMD_FAILED);
+ }
+
+ // pass the data
+ memcpy(dataOut, &rplBuff[1], len);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] rplBuff;
+ #endif
+ return(state);
+}
+
+int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, const uint8_t* data, size_t len, uint32_t* mic) {
+ size_t reqLen = sizeof(uint8_t) + len;
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t reqBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* reqBuff = new uint8_t[reqLen];
+ #endif
+ uint8_t rplBuff[5] = { 0 };
+
+ reqBuff[0] = keyId;
+ memcpy(&reqBuff[1], data, len);
+
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] reqBuff;
+ #endif
+
+ // check the crypto engine state
+ if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]);
+ return(RADIOLIB_ERR_SPI_CMD_FAILED);
+ }
+
+ if(mic) { *mic = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; }
+ return(state);
+}
+
+int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, const uint8_t* data, size_t len, bool* result) {
+ size_t reqLen = sizeof(uint8_t) + sizeof(uint32_t) + len;
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t reqBuff[sizeof(uint8_t) + sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* reqBuff = new uint8_t[reqLen];
+ #endif
+ uint8_t rplBuff[1] = { 0 };
+
+ reqBuff[0] = keyId;
+ reqBuff[1] = (uint8_t)((micExp >> 24) & 0xFF);
+ reqBuff[2] = (uint8_t)((micExp >> 16) & 0xFF);
+ reqBuff[3] = (uint8_t)((micExp >> 8) & 0xFF);
+ reqBuff[4] = (uint8_t)(micExp & 0xFF);
+ memcpy(&reqBuff[5], data, len);
+
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] reqBuff;
+ #endif
+
+ // check the crypto engine state
+ if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]);
+ return(RADIOLIB_ERR_SPI_CMD_FAILED);
+ }
+
+ if(result) { *result = (rplBuff[0] == RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS); }
+ return(state);
+}
+
+int16_t LR11x0::cryptoAesEncrypt01(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) {
+ return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01, keyId, dataIn, len, dataOut));
+}
+
+int16_t LR11x0::cryptoAesEncrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) {
+ return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT, keyId, dataIn, len, dataOut));
+}
+
+int16_t LR11x0::cryptoAesDecrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) {
+ return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT, keyId, dataIn, len, dataOut));
+}
+
+int16_t LR11x0::cryptoStoreToFlash(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH, true, NULL, 0));
+}
+
+int16_t LR11x0::cryptoRestoreFromFlash(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH, true, NULL, 0));
+}
+
+int16_t LR11x0::cryptoSetParam(uint8_t id, uint32_t value) {
+ uint8_t buff[5] = {
+ id,
+ (uint8_t)((value >> 24) & 0xFF), (uint8_t)((value >> 16) & 0xFF),
+ (uint8_t)((value >> 8) & 0xFF), (uint8_t)(value & 0xFF)
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::cryptoGetParam(uint8_t id, uint32_t* value) {
+ uint8_t reqBuff[1] = { id };
+ uint8_t rplBuff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
+ RADIOLIB_ASSERT(state);
+ if(value) { *value = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; }
+ return(state);
+}
+
+int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile) {
+ // check maximum size
+ if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+ return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile));
+}
+
+int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(result) { *result = (bool)buff[0]; }
+
+ return(state);
+}
+
+int16_t LR11x0::cryptoCommon(uint16_t cmd, uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) {
+ // build buffers
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* reqBuff = new uint8_t[sizeof(uint8_t) + len];
+ uint8_t* rplBuff = new uint8_t[sizeof(uint8_t) + len];
+ #endif
+
+ // set the request fields
+ reqBuff[0] = keyId;
+ memcpy(&reqBuff[1], dataIn, len);
+
+ int16_t state = this->SPIcommand(cmd, false, rplBuff, sizeof(uint8_t) + len, reqBuff, sizeof(uint8_t) + len);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] reqBuff;
+ #endif
+ if(state != RADIOLIB_ERR_NONE) {
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] rplBuff;
+ #endif
+ return(state);
+ }
+
+ // check the crypto engine state
+ if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]);
+ return(RADIOLIB_ERR_SPI_CMD_FAILED);
+ }
+
+ // pass the data
+ memcpy(dataOut, &rplBuff[1], len);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] rplBuff;
+ #endif
+ return(state);
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR11x0_gnss.cpp b/lib/RadioLib/src/modules/LR11x0/LR11x0_gnss.cpp
new file mode 100644
index 0000000..2502837
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR11x0/LR11x0_gnss.cpp
@@ -0,0 +1,757 @@
+#include "LR11x0.h"
+
+#include
+
+#if !RADIOLIB_EXCLUDE_LR11X0
+
+int16_t LR11x0::isGnssScanCapable() {
+ // get the version
+ LR11x0VersionInfo_t version;
+ int16_t state = this->getVersionInfo(&version);
+ RADIOLIB_ASSERT(state);
+
+ // check the device firmware version is sufficient
+ uint16_t versionFull = ((uint16_t)version.fwMajor << 8) | (uint16_t)version.fwMinor;
+ state = RADIOLIB_ERR_UNSUPPORTED;
+ if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) {
+ state = RADIOLIB_ERR_NONE;
+ } else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) {
+ state = RADIOLIB_ERR_NONE;
+ }
+ RADIOLIB_ASSERT(state);
+
+ // in debug mode, dump the almanac
+ #if RADIOLIB_DEBUG_PROTOCOL
+ uint32_t addr = 0;
+ uint16_t sz = 0;
+ state = this->gnssAlmanacReadAddrSize(&addr, &sz);
+ RADIOLIB_ASSERT(state);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac@%08x, %d bytes", addr, sz);
+ uint32_t buff[32] = { 0 };
+ while(sz > 0) {
+ size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t);
+ state = this->readRegMem32(addr, buff, len);
+ RADIOLIB_ASSERT(state);
+ RADIOLIB_DEBUG_HEXDUMP(NULL, reinterpret_cast(buff), len*sizeof(uint32_t), addr);
+ addr += len*sizeof(uint32_t);
+ sz -= len*sizeof(uint32_t);
+ }
+
+ uint8_t almanac[22] = { 0 };
+ for(uint8_t i = 0; i < 128; i++) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac[%d]:", i);
+ state = this->gnssAlmanacReadSV(i, almanac);
+ RADIOLIB_ASSERT(state);
+ RADIOLIB_DEBUG_HEXDUMP(NULL, almanac, 22);
+ }
+
+ #endif
+
+ return(state);
+}
+
+int16_t LR11x0::gnssScan(LR11x0GnssResult_t* res) {
+ RADIOLIB_ASSERT_PTR(res);
+
+ // go to standby
+ int16_t state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // set DIO mapping
+ state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT);
+ RADIOLIB_ASSERT(state);
+
+ // set scan mode (single vs multiple)
+ state = this->gnssSetMode(0x03);
+ RADIOLIB_ASSERT(state);
+
+ // set RF switch
+ this->mod->setRfSwitchState(LR11x0::MODE_GNSS);
+
+ // start scan with high effort
+ RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan start");
+ state = this->gnssPerformScan(RADIOLIB_LR11X0_GNSS_EFFORT_MID, 0x3C, 16);
+ RADIOLIB_ASSERT(state);
+
+ // wait for scan finished or timeout
+ // this can take very long if both GPS and BeiDou are enabled
+ RadioLibTime_t softTimeout = 300UL * 1000UL;
+ RadioLibTime_t start = this->mod->hal->millis();
+ while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
+ this->mod->hal->yield();
+ if(this->mod->hal->millis() - start > softTimeout) {
+ this->gnssAbort();
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ");
+ }
+ }
+
+ // restore the switch
+ this->mod->setRfSwitchState(Module::MODE_IDLE);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start));
+
+ // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags
+ uint32_t irq = this->getIrqStatus();
+ this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
+ if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) {
+ return(RADIOLIB_ERR_RX_TIMEOUT);
+ }
+
+ // retrieve the demodulator status
+ uint8_t info = 0;
+ state = this->gnssReadDemodStatus(&res->demodStat, &info);
+ RADIOLIB_ASSERT(state);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Demod status %d, info %02x", (int)res->demodStat, (unsigned int)info);
+
+ // retrieve the number of detected satellites
+ state = this->gnssGetNbSvDetected(&res->numSatsDet);
+ RADIOLIB_ASSERT(state);
+
+ // retrieve the result size
+ state = this->gnssGetResultSize(&res->resSize);
+ RADIOLIB_ASSERT(state);
+
+ // check and return demodulator status
+ if(res->demodStat < RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND) {
+ return(RADIOLIB_ERR_GNSS_DEMOD(res->demodStat));
+ }
+
+ return(state);
+}
+
+int16_t LR11x0::getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat) {
+ RADIOLIB_ASSERT_PTR(stat);
+
+ // save the time the time until subframe is relative to
+ stat->start = this->mod->hal->millis();
+
+ // get the raw data
+ uint8_t raw[53] = { 0 };
+ int16_t state = this->gnssReadAlmanacStatus(raw);
+ RADIOLIB_ASSERT(state);
+
+ // parse the reply
+ stat->gps.status = (int8_t)raw[0];
+ stat->gps.timeUntilSubframe = ((uint32_t)(raw[1]) << 24) | ((uint32_t)(raw[2]) << 16) | ((uint32_t)(raw[3]) << 8) | (uint32_t)raw[4];
+ stat->gps.numSubframes = raw[5];
+ stat->gps.nextSubframe4SvId = raw[6];
+ stat->gps.nextSubframe5SvId = raw[7];
+ stat->gps.nextSubframeStart = raw[8];
+ stat->gps.numUpdateNeeded = raw[9];
+ stat->gps.flagsUpdateNeeded[0] = ((uint32_t)(raw[10]) << 24) | ((uint32_t)(raw[11]) << 16) | ((uint32_t)(raw[12]) << 8) | (uint32_t)raw[13];
+ stat->gps.flagsActive[0] = ((uint32_t)(raw[14]) << 24) | ((uint32_t)(raw[15]) << 16) | ((uint32_t)(raw[16]) << 8) | (uint32_t)raw[17];
+ stat->beidou.status = (int8_t)raw[18];
+ stat->beidou.timeUntilSubframe = ((uint32_t)(raw[19]) << 24) | ((uint32_t)(raw[20]) << 16) | ((uint32_t)(raw[21]) << 8) | (uint32_t)raw[22];
+ stat->beidou.numSubframes = raw[23];
+ stat->beidou.nextSubframe4SvId = raw[24];
+ stat->beidou.nextSubframe5SvId = raw[25];
+ stat->beidou.nextSubframeStart = raw[26];
+ stat->beidou.numUpdateNeeded = raw[27];
+ stat->beidou.flagsUpdateNeeded[0] = ((uint32_t)(raw[28]) << 24) | ((uint32_t)(raw[29]) << 16) | ((uint32_t)(raw[30]) << 8) | (uint32_t)raw[31];
+ stat->beidou.flagsUpdateNeeded[1] = ((uint32_t)(raw[32]) << 24) | ((uint32_t)(raw[33]) << 16) | ((uint32_t)(raw[34]) << 8) | (uint32_t)raw[35];
+ stat->beidou.flagsActive[0] = ((uint32_t)(raw[36]) << 24) | ((uint32_t)(raw[37]) << 16) | ((uint32_t)(raw[38]) << 8) | (uint32_t)raw[39];
+ stat->beidou.flagsActive[1] = ((uint32_t)(raw[40]) << 24) | ((uint32_t)(raw[41]) << 16) | ((uint32_t)(raw[42]) << 8) | (uint32_t)raw[43];
+ stat->beidouSvNoAlmanacFlags[0] = ((uint32_t)(raw[44]) << 24) | ((uint32_t)(raw[45]) << 16) | ((uint32_t)(raw[46]) << 8) | (uint32_t)raw[47];
+ stat->beidouSvNoAlmanacFlags[1] = ((uint32_t)(raw[18]) << 24) | ((uint32_t)(raw[49]) << 16) | ((uint32_t)(raw[50]) << 8) | (uint32_t)raw[51];
+ stat->nextAlmanacId = raw[52];
+
+ return(state);
+}
+
+int16_t LR11x0::gnssDelayUntilSubframe(LR11x0GnssAlmanacStatus_t *stat, uint8_t constellation) {
+ RADIOLIB_ASSERT_PTR(stat);
+
+ // almanac update has to be called at least 1.3 seconds before the subframe
+ // we use 2.3 seconds to be on the safe side
+
+ // calculate absolute times
+ RadioLibTime_t window = stat->start + stat->gps.timeUntilSubframe - 2300;
+ if(constellation == RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU) {
+ window = stat->start + stat->beidou.timeUntilSubframe - 2300;
+ }
+ RadioLibTime_t now = this->mod->hal->millis();
+ if(now > window) {
+ // we missed the window
+ return(RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE);
+ }
+
+ RadioLibTime_t delay = window - now;
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Time until subframe %lu ms", delay);
+ this->mod->hal->delay(delay);
+ return(RADIOLIB_ERR_NONE);
+}
+
+// TODO fix last satellite always out of date
+int16_t LR11x0::updateGnssAlmanac(uint8_t constellation) {
+ int16_t state = this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT);
+ RADIOLIB_ASSERT(state);
+
+ state = this->gnssAlmanacUpdateFromSat(RADIOLIB_LR11X0_GNSS_EFFORT_MID, constellation);
+ RADIOLIB_ASSERT(state);
+
+ // wait for scan finished or timeout, assumes 2 subframes and up to 2.3s pre-roll
+ uint32_t softTimeout = 16UL * 1000UL;
+ uint32_t start = this->mod->hal->millis();
+ while (!this->mod->hal->digitalRead(this->mod->getIrq())) {
+ this->mod->hal->yield();
+ if(this->mod->hal->millis() - start > softTimeout) {
+ this->gnssAbort();
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for almanac update");
+ }
+ }
+
+ RADIOLIB_DEBUG_BASIC_PRINTLN("GPS almanac update done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start));
+
+ // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags
+ uint32_t irq = this->getIrqStatus();
+ this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
+ if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) {
+ state = RADIOLIB_ERR_RX_TIMEOUT;
+ }
+
+ return(state);
+}
+
+int16_t LR11x0::getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered) {
+ RADIOLIB_ASSERT_PTR(pos);
+
+ uint8_t error = 0;
+ int16_t state;
+ if(filtered) {
+ state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, NULL, NULL, NULL, NULL, &pos->latitude, &pos->longitude, &pos->accuracy, NULL);
+ } else {
+ state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, &pos->latitude, &pos->longitude, &pos->accuracy, NULL, NULL, NULL, NULL, NULL);
+ }
+ RADIOLIB_ASSERT(state);
+
+ // check the solver error
+ if(error != 0) {
+ return(RADIOLIB_ERR_GNSS_SOLVER(error));
+ }
+
+ return(state);
+}
+
+int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) {
+ RADIOLIB_ASSERT_PTR(sats);
+ if(numSats >= 32) {
+ return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
+ }
+
+ uint8_t svId[32] = { 0 };
+ uint8_t snr[32] = { 0 };
+ int16_t doppler[32] = { 0 };
+ int16_t state = this->gnssGetSvDetected(svId, snr, doppler, numSats);
+ RADIOLIB_ASSERT(state);
+ for(size_t i = 0; i < numSats; i++) {
+ sats[i].svId = svId[i];
+ sats[i].c_n0 = snr[i] + 31;
+ sats[i].doppler = doppler[i];
+ }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssReadRssi(int8_t* rssi) {
+ uint8_t reqBuff[1] = { 0x09 }; // some undocumented magic byte, from the official driver
+ uint8_t rplBuff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
+ RADIOLIB_ASSERT(state);
+ if(rssi) { *rssi = rplBuff[1]; }
+ return(state);
+}
+
+int16_t LR11x0::gnssSetConstellationToUse(uint8_t mask) {
+ uint8_t buff[1] = { mask };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssReadConstellationToUse(uint8_t* mask) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(mask) { *mask = buff[0]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssSetAlmanacUpdate(uint8_t mask) {
+ uint8_t buff[1] = { mask };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssReadAlmanacUpdate(uint8_t* mask) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(mask) { *mask = buff[0]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssSetFreqSearchSpace(uint8_t freq) {
+ uint8_t buff[1] = { freq };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssReadFreqSearchSpace(uint8_t* freq) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE, false, buff, sizeof(buff));
+ if(freq) { *freq = buff[0]; }
+ return(state);
+}
+
+int16_t LR11x0::gnssReadVersion(uint8_t* fw, uint8_t* almanac) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(fw) { *fw = buff[0]; }
+ if(almanac) { *almanac = buff[1]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssReadSupportedConstellations(uint8_t* mask) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(mask) { *mask = buff[0]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssSetMode(uint8_t mode) {
+ uint8_t buff[1] = { mode };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_MODE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssAutonomous(uint32_t gpsTime, uint8_t resMask, uint8_t nbSvMask) {
+ uint8_t buff[7] = {
+ (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF),
+ (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF),
+ RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE, resMask, nbSvMask
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssAssisted(uint32_t gpsTime, uint8_t effort, uint8_t resMask, uint8_t nbSvMask) {
+ uint8_t buff[7] = {
+ (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF),
+ (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF),
+ effort, resMask, nbSvMask
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ASSISTED, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssSetAssistancePosition(float lat, float lon) {
+ int16_t latRaw = (lat*2048.0f)/90.0f + 0.5f;
+ int16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f;
+ uint8_t buff[4] = {
+ (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF),
+ (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssReadAssistancePosition(float* lat, float* lon) {
+ uint8_t buff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(lat) {
+ int16_t latRaw = ((int16_t)(buff[0]) << 8) | (int16_t)(buff[1]);
+ *lat = ((float)latRaw*90.0f)/2048.0f;
+ }
+ if(lon) {
+ int16_t lonRaw = ((int16_t)(buff[2]) << 8) | (int16_t)(buff[3]);
+ *lon = ((float)lonRaw*180.0f)/2048.0f;
+ }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssPushSolverMsg(uint8_t* payload, size_t len) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG, true, payload, len));
+}
+
+int16_t LR11x0::gnssPushDmMsg(uint8_t* payload, size_t len) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG, true, payload, len));
+}
+
+int16_t LR11x0::gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, uint8_t* errCode, uint8_t* almUpdMask, uint8_t* freqSpace) {
+ // send the command - datasheet here shows extra bytes being sent in the request
+ // but doing that fails so treat it like any other read command
+ uint8_t buff[9] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(fwVersion) { *fwVersion = buff[2]; }
+ if(almanacCrc) { *almanacCrc = ((uint32_t)(buff[3]) << 24) | ((uint32_t)(buff[4]) << 16) | ((uint32_t)(buff[5]) << 8) | (uint32_t)buff[6]; }
+ if(errCode) { *errCode = (buff[7] & 0xF0) >> 4; }
+ if(almUpdMask) { *almUpdMask = (buff[7] & 0x0E) >> 1; }
+ if(freqSpace) { *freqSpace = ((buff[7] & 0x01) << 1) | ((buff[8] & 0x80) >> 7); }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssGetNbSvDetected(uint8_t* nbSv) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(nbSv) { *nbSv = buff[0]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssGetSvDetected(uint8_t* svId, uint8_t* snr, int16_t* doppler, size_t nbSv) {
+ // TODO this is arbitrary - is there an actual maximum?
+ if(nbSv > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t)) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+
+ // build buffers
+ size_t buffLen = nbSv*sizeof(uint32_t);
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t dataBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* dataBuff = new uint8_t[buffLen];
+ #endif
+
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED, false, dataBuff, buffLen);
+ if(state == RADIOLIB_ERR_NONE) {
+ for(size_t i = 0; i < nbSv; i++) {
+ if(svId) { svId[i] = dataBuff[4*i]; }
+ if(snr) { snr[i] = dataBuff[4*i + 1]; }
+ if(doppler) { doppler[i] = ((uint16_t)(dataBuff[4*i + 2]) << 8) | (uint16_t)dataBuff[4*i + 3]; }
+ }
+ }
+
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] dataBuff;
+ #endif
+ return(state);
+}
+
+int16_t LR11x0::gnssGetConsumption(uint32_t* cpu, uint32_t* radio) {
+ uint8_t buff[8] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(cpu) { *cpu = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; }
+ if(radio) { *radio = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssGetResultSize(uint16_t* size) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(size) { *size = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssReadResults(uint8_t* result, uint16_t size) {
+ RADIOLIB_ASSERT_PTR(result);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS, false, result, size));
+}
+
+int16_t LR11x0::gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc) {
+ uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = {
+ RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID,
+ (uint8_t)((date >> 8) & 0xFF), (uint8_t)(date & 0xFF),
+ (uint8_t)((globalCrc >> 24) & 0xFF), (uint8_t)((globalCrc >> 16) & 0xFF),
+ (uint8_t)((globalCrc >> 8) & 0xFF), (uint8_t)(globalCrc & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssAlmanacFullUpdateSV(uint8_t svn, const uint8_t* svnAlmanac) {
+ uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = { svn };
+ memcpy(&buff[1], svnAlmanac, RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE - 1);
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssAlmanacReadAddrSize(uint32_t* addr, uint16_t* size) {
+ uint8_t buff[6] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE, false, buff, sizeof(buff));
+
+ if(addr) { *addr = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; }
+ if(size) { *size = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssAlmanacReadSV(uint8_t svId, uint8_t* almanac) {
+ uint8_t reqBuff[2] = { svId, 0x01 }; // in theory multiple SV entries can be read at the same time, but we don't need that
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE, false, almanac, 22, reqBuff, sizeof(reqBuff));
+ RADIOLIB_ASSERT(state);
+ return(state);
+}
+
+int16_t LR11x0::gnssGetNbSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv) {
+ int16_t latRaw = (lat*2048.0f)/90.0f + 0.5f;
+ int16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f;
+ uint8_t reqBuff[9] = {
+ (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF),
+ (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF),
+ (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF),
+ (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF),
+ constellation,
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff)));
+}
+
+int16_t LR11x0::gnssGetSvVisible(uint8_t nbSv, uint8_t** svId, int16_t** doppler, int16_t** dopplerErr) {
+ // enforce a maximum of 12 SVs
+ if(nbSv > 12) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+
+ uint8_t buff[60] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER, false, buff, sizeof(buff));
+ for(uint8_t i = 0; i < nbSv; i++) {
+ if(svId && svId[i]) { *svId[i] = buff[i*12]; }
+ if(doppler && doppler[i]) { *doppler[i] = ((uint16_t)(buff[i*12 + 1]) << 8) | (uint16_t)buff[i*12 + 2]; }
+ if(dopplerErr && dopplerErr[i]) { *dopplerErr[i] = ((uint16_t)(buff[i*12 + 3]) << 8) | (uint16_t)buff[i*12 + 4]; }
+ }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) {
+ uint8_t buff[3] = { effort, resMask, nbSvMax };
+ // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts
+ return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_SCAN, buff, sizeof(buff), false, false));
+}
+
+int16_t LR11x0::gnssReadLastScanModeLaunched(uint8_t* lastScanMode) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(lastScanMode) { *lastScanMode = buff[0]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssFetchTime(uint8_t effort, uint8_t opt) {
+ uint8_t buff[2] = { effort, opt };
+ // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts
+ return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME, buff, sizeof(buff), false, false));
+}
+
+int16_t LR11x0::gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy) {
+ uint8_t buff[12] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_TIME, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(err) { *err = buff[0]; }
+
+ if(time) {
+ *time = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4];
+ *time += 2UL*1024UL*7UL*24UL*3600UL; // assume WN rollover is at 2, this will fail sometime in 2038
+ *time += 315964800UL; // convert to UTC
+ }
+
+ if(nbUs) {
+ *nbUs = ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7];
+ *nbUs /= 16;
+ }
+
+ if(timeAccuracy) {
+ *timeAccuracy = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11];
+ *timeAccuracy /= 16;
+ }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssResetTime(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME, true, NULL, 0));
+}
+
+int16_t LR11x0::gnssResetPosition(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION, true, NULL, 0));
+}
+
+int16_t LR11x0::gnssReadWeekNumberRollover(uint8_t* status, uint8_t* rollover) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER, false, buff, sizeof(buff));
+ if(status) { *status = buff[0]; }
+ if(rollover) { *rollover = buff[1]; }
+ return(state);
+}
+
+int16_t LR11x0::gnssReadDemodStatus(int8_t* status, uint8_t* info) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(status) { *status = (int8_t)buff[0]; }
+ if(info) { *info = buff[1]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod) {
+ uint8_t rplBuff[125] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING, false, rplBuff, 125);
+ RADIOLIB_ASSERT(state);
+
+ // convert endians
+ if(timing) {
+ for(size_t i = 0; i < 31; i++) {
+ timing[i] = ((uint32_t)rplBuff[i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[1 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[3 + i*sizeof(uint32_t)];
+ }
+ }
+
+ if(constDemod) { *constDemod = rplBuff[124]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssSetTime(uint32_t time, uint16_t accuracy) {
+ uint8_t buff[6] = {
+ (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF),
+ (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF),
+ (uint8_t)((accuracy >> 8) & 0xFF), (uint8_t)(accuracy & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_TIME, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, float* lat, float* lon, uint16_t* accuracy, uint16_t* xtal, float* latFilt, float* lonFilt, uint16_t* accuracyFilt, uint16_t* xtalFilt) {
+ uint8_t buff[18] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(error) { *error = buff[0]; }
+ if(nbSvUsed) { *nbSvUsed = buff[1]; }
+ if(lat) {
+ int16_t latRaw = ((int16_t)(buff[2]) << 8) | (int16_t)buff[3];
+ *lat = ((float)latRaw * 90.0f)/2048.0f;
+ }
+ if(lon) {
+ int16_t lonRaw = ((int16_t)(buff[4]) << 8) | (int16_t)buff[5];
+ *lon = ((float)lonRaw * 180.0f)/2048.0f;
+ }
+ if(accuracy) { *accuracy = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; }
+ if(xtal) { *xtal = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; }
+ if(latFilt) {
+ int16_t latRaw = ((int16_t)(buff[10]) << 8) | (int16_t)buff[11];
+ *latFilt = ((float)latRaw * 90.0f)/2048.0f;
+ }
+ if(lonFilt) {
+ int16_t lonRaw = ((int16_t)(buff[12]) << 8) | (int16_t)buff[13];
+ *lonFilt = ((float)lonRaw * 180.0f)/2048.0f;
+ }
+ if(accuracyFilt) { *accuracyFilt = ((uint16_t)(buff[14]) << 8) | (uint16_t)buff[15]; }
+ if(xtalFilt) { *xtalFilt = ((uint16_t)(buff[16]) << 8) | (uint16_t)buff[17]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssReadDelayResetAP(uint32_t* delay) {
+ uint8_t buff[3] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP, false, buff, sizeof(buff));
+
+ if(delay) { *delay = ((uint32_t)(buff[0]) << 16) | ((uint32_t)(buff[1]) << 8) | (uint32_t)buff[2]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask) {
+ uint8_t buff[2] = { effort, bitMask };
+ // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts
+ return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT, buff, sizeof(buff), false, false));
+}
+
+int16_t LR11x0::gnssReadKeepSyncStatus(uint8_t mask, uint8_t* nbSvVisible, uint32_t* elapsed) {
+ uint8_t reqBuff[1] = { mask };
+ uint8_t rplBuff[5] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
+ RADIOLIB_ASSERT(state);
+ if(nbSvVisible) { *nbSvVisible = rplBuff[0]; }
+ if(elapsed) { *elapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; }
+ return(state);
+}
+
+int16_t LR11x0::gnssReadAlmanacStatus(uint8_t* status) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS, false, status, 53));
+}
+
+int16_t LR11x0::gnssConfigAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t period) {
+ uint8_t buff[4] = { bitMask, svType, (uint8_t)((period >> 8) & 0xFF), (uint8_t)(period & 0xFF) };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssReadAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t* period) {
+ uint8_t reqBuff[2] = { bitMask, svType };
+ uint8_t rplBuff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
+ RADIOLIB_ASSERT(state);
+
+ if(period) { *period = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssConfigDelayResetAP(uint32_t delay) {
+ uint8_t buff[3] = { (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSat) {
+ uint8_t reqBuff[1] = { bitMask };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START, false, sv, nbVisSat, reqBuff, sizeof(reqBuff)));
+}
+
+int16_t LR11x0::gnssGetSvSync(uint8_t mask, uint8_t nbSv, uint8_t* syncList) {
+ uint8_t reqBuff[2] = { mask, nbSv };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC, false, syncList, nbSv, reqBuff, sizeof(reqBuff)));
+}
+
+int16_t LR11x0::gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed) {
+ uint8_t reqBuff[1] = { bitMask };
+ uint8_t rplBuff[5] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
+ RADIOLIB_ASSERT(state);
+
+ if(nbVisSat) { *nbVisSat = rplBuff[0]; }
+ if(timeElapsed) { *timeElapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; }
+
+ return(state);
+}
+
+int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1) {
+ uint8_t reqBuff[1] = { bitMask };
+ uint8_t rplBuff[8] = { 0 };
+ size_t rplLen = (bitMask & 0x01) ? 8 : 4; // GPS only has the first bit mask
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED, false, rplBuff, rplLen, reqBuff, sizeof(reqBuff));
+ RADIOLIB_ASSERT(state);
+
+ if(bitMaskActivated0) { *bitMaskActivated0 = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; }
+ if(bitMaskActivated1) { *bitMaskActivated1 = ((uint32_t)(rplBuff[4]) << 24) | ((uint32_t)(rplBuff[5]) << 16) | ((uint32_t)(rplBuff[6]) << 8) | (uint32_t)rplBuff[7]; }
+
+ return(state);
+}
+
+void LR11x0::gnssAbort() {
+ // send the abort signal (single NOP)
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
+ // we need to call the most basic overload of the SPI write method otherwise the call will be ambiguous
+ const uint8_t cmd[2] = { 0, 0 };
+ this->mod->SPIwriteStream(cmd, 2, NULL, 0, false, false);
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16;
+
+ // wait for at least 2.9 seconds as specified by the user manual
+ this->mod->hal->delay(3000);
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR11x0_registers.h b/lib/RadioLib/src/modules/LR11x0/LR11x0_registers.h
new file mode 100644
index 0000000..6857459
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR11x0/LR11x0_registers.h
@@ -0,0 +1,32 @@
+#if !defined(RADIOLIB_LR11X0_REGISTERS_H)
+#define RADIOLIB_LR11X0_REGISTERS_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_LR11X0
+
+// LR11X0 register map
+#define RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT (0x00F20414)
+#define RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX (0x00F30054)
+#define RADIOLIB_LR11X0_REG_LNA_MODE (0x00F3008C)
+#define RADIOLIB_LR11X0_REG_GFSK_FIX1 (0x00F20344)
+#define RADIOLIB_LR11X0_REG_GFSK_FIX2 (0x00F20348)
+#define RADIOLIB_LR11X0_REG_GFSK_FIX3 (0x00F20244)
+
+// LR11X0 SPI register variables
+
+// RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT
+#define RADIOLIB_LR11X0_SF6_SX126X (0x00UL << 18) // 18 18 SF6 mode: SX126x series
+#define RADIOLIB_LR11X0_SF6_SX127X (0x01UL << 18) // 18 18 SX127x series
+
+// RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX
+#define RADIOLIB_LR11X0_LORA_HIGH_POWER_FIX (0x00UL << 30) // 30 30 fix for errata
+
+// RADIOLIB_LR11X0_REG_LNA_MODE
+#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_N (0x01UL << 4) // 7 4 LNA mode: single-ended RFI_N
+#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_P (0x02UL << 4) // 7 4 single-ended RFI_P
+#define RADIOLIB_LR11X0_LNA_MODE_DIFFERENTIAL (0x03UL << 4) // 7 4 differential (default)
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR11x0_types.h b/lib/RadioLib/src/modules/LR11x0/LR11x0_types.h
new file mode 100644
index 0000000..f30e49f
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR11x0/LR11x0_types.h
@@ -0,0 +1,230 @@
+#if !defined(RADIOLIB_LR11X0_TYPES_H)
+#define RADIOLIB_LR11X0_TYPES_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_LR11X0
+
+// MAC address length in bytes
+#define RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN (6)
+
+// SSID length in bytes
+#define RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN (32)
+
+/*!
+ \struct LR11x0WifiResult_t
+ \brief Structure to save result of passive WiFi scan.
+ This result only saves the basic information.
+*/
+struct LR11x0WifiResult_t {
+ /*! \brief WiFi (802.11) signal type, 'b', 'n' or 'g' */
+ char type;
+
+ /*! \brief Data rate ID holding information about modulation and coding rate. See LR11x0 user manual for details. */
+ uint8_t dataRateId;
+
+ /*! \brief Channel frequency in MHz */
+ uint16_t channelFreq;
+
+ /*! \brief MAC address origin: from gateway (1), phone (2) or undetermined (3) */
+ uint8_t origin;
+
+ /*! \brief Whether this signal was sent by an access point (true) or end device (false) */
+ bool ap;
+
+ /*! \brief RSSI in dBm */
+ float rssi;
+
+ /*! \brief MAC address */
+ uint8_t mac[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN];
+};
+
+/*!
+ \struct LR11x0WifiResultFull_t
+ \brief Structure to save result of passive WiFi scan.
+ This result saves additional information alongside that in LR11x0WifiResult_t.
+*/
+struct LR11x0WifiResultFull_t: public LR11x0WifiResult_t {
+ /*! \brief Frame type. See LR11x0 user manual for details. */
+ uint8_t frameType;
+
+ /*! \brief Frame sub type. See LR11x0 user manual for details. */
+ uint8_t frameSubType;
+
+ /*! \brief Frame sent from client station to distribution system. */
+ bool toDistributionSystem;
+
+ /*! \brief Frame sent from distribution system to client station. */
+ bool fromDistributionSystem;
+
+ /*! \brief See LR11x0 user manual for details. */
+ uint16_t phiOffset;
+
+ /*! \brief Number of microseconds the AP has been active. */
+ uint64_t timestamp;
+
+ /*! \brief Beacon period in microseconds. */
+ uint32_t periodBeacon;
+};
+
+/*!
+ \struct LR11x0WifiResultExtended_t
+ \brief Structure to save result of passive WiFi scan.
+ This result saves additional information alongside that in LR11x0WifiResultFull_t.
+ Only scans performed with RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON acquisition mode
+ can yield this result!
+*/
+struct LR11x0WifiResultExtended_t: public LR11x0WifiResultFull_t {
+ /*! \brief Data rate. See LR11x0 user manual for details. */
+ uint8_t rate;
+
+ /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
+ uint16_t service;
+
+ /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
+ uint16_t length;
+
+ /*! \brief MAC address 0 */
+ uint8_t mac0[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN];
+
+ /*! \brief MAC address 2 */
+ uint8_t mac2[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN];
+
+ /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
+ uint16_t seqCtrl;
+
+ /*! \brief SSID */
+ uint8_t ssid[RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN];
+
+ /*! \brief WiFi channel number */
+ uint8_t currentChannel;
+
+ /*! \brief Two-letter country code (null-terminated string). */
+ char countryCode[3];
+
+ /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
+ uint8_t ioReg;
+
+ /*! \brief True if frame check sequences is valid, false otherwise. */
+ bool fcsCheckOk;
+};
+
+/*!
+ \struct LR11x0VersionInfo_t
+ \brief Structure to report information about versions of the LR11x0 hardware and firmware.
+*/
+struct LR11x0VersionInfo_t {
+ /*! \brief Hardware revision. */
+ uint8_t hardware;
+
+ /*! \brief Which device this is - one of RADIOLIB_LR11X0_DEVICE_* macros. */
+ uint8_t device;
+
+ /*! \brief Major revision of the base firmware. */
+ uint8_t fwMajor;
+
+ /*! \brief Minor revision of the base firmware. */
+ uint8_t fwMinor;
+
+ /*! \brief Major revision of the WiFi firmware. */
+ uint8_t fwMajorWiFi;
+
+ /*! \brief Minor revision of the WiFi firmware. */
+ uint8_t fwMinorWiFi;
+
+ /*! \brief Revision of the GNSS firmware. */
+ uint8_t fwGNSS;
+
+ /*! \brief Almanac revision of the GNSS firmware. */
+ uint8_t almanacGNSS;
+};
+
+/*!
+ \struct LR11x0GnssResult_t
+ \brief Structure to report information results of a GNSS scan.
+*/
+struct LR11x0GnssResult_t {
+ /*! \brief Demodulator status. One of RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_* */
+ int8_t demodStat;
+
+ /*! \brief Number of satellites detected during the scan. */
+ uint8_t numSatsDet;
+
+ /*! \brief Result size, used when passing data to LoRa cloud. */
+ uint16_t resSize;
+};
+
+/*!
+ \struct LR11x0GnssPosition_t
+ \brief Structure to report position from LR11x0 internal solver.
+*/
+struct LR11x0GnssPosition_t {
+ /*! \brief Latitude in degrees. */
+ float latitude;
+
+ /*! \brief Longitude in degrees. */
+ float longitude;
+
+ /*! \brief Accuracy of this result. */
+ uint16_t accuracy;
+
+ /*! \brief Number of satellites used to solve this position. */
+ uint8_t numSatsUsed;
+};
+
+/*!
+ \struct LR11x0GnssSatellite_t
+ \brief Structure to save information about a satellite found during GNSS scan.
+*/
+struct LR11x0GnssSatellite_t {
+ /*! \brief Satellite vehicle (SV) identifier. */
+ uint8_t svId;
+
+ /*! \brief C/N0 in dB. */
+ uint8_t c_n0;
+
+ /*! \brief Doppler shift of the signal in Hz. */
+ int16_t doppler;
+};
+
+/*!
+ \struct LR11x0GnssAlmanacStatusPart_t
+ \brief Structure to save information about one constellation of the GNSS almanac.
+*/
+struct LR11x0GnssAlmanacStatusPart_t {
+ int8_t status;
+ uint32_t timeUntilSubframe;
+ uint8_t numSubframes;
+ uint8_t nextSubframe4SvId;
+ uint8_t nextSubframe5SvId;
+ uint8_t nextSubframeStart;
+ uint8_t numUpdateNeeded;
+ uint32_t flagsUpdateNeeded[2];
+ uint32_t flagsActive[2];
+};
+
+/*!
+ \struct LR11x0GnssAlmanacStatus_t
+ \brief Structure to save information about the GNSS almanac.
+ This is not the actual almanac, just some context information about it.
+*/
+struct LR11x0GnssAlmanacStatus_t {
+ /*! \brief GPS part of the almanac */
+ LR11x0GnssAlmanacStatusPart_t gps;
+
+ /*! \brief BeiDou part of the almanac */
+ LR11x0GnssAlmanacStatusPart_t beidou;
+
+ /*! \brief Extra flags present for BeiDou only */
+ uint32_t beidouSvNoAlmanacFlags[2];
+
+ /*! \brief Next almanac ID */
+ uint8_t nextAlmanacId;
+
+ /*! \brief Timestamp of when almanac status was retrieved - timeUntilSubframe is relative to this value. */
+ RadioLibTime_t start;
+};
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR11x0_wifi.cpp b/lib/RadioLib/src/modules/LR11x0/LR11x0_wifi.cpp
new file mode 100644
index 0000000..34362a3
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR11x0/LR11x0_wifi.cpp
@@ -0,0 +1,267 @@
+#include "LR11x0.h"
+
+#include
+
+#if !RADIOLIB_EXCLUDE_LR11X0
+
+int16_t LR11x0::startWifiScan(char wifiType, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) {
+ // LR1121 cannot do WiFi scanning
+ if(this->chipType == RADIOLIB_LR11X0_DEVICE_LR1121) {
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ uint8_t type;
+ switch(wifiType) {
+ case('b'):
+ type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_B;
+ break;
+ case('g'):
+ type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_G;
+ break;
+ case('n'):
+ type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_N;
+ break;
+ case('*'):
+ type = RADIOLIB_LR11X0_WIFI_SCAN_ALL;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_WIFI_TYPE);
+ }
+
+ // go to standby
+ int16_t state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // reset cumulative timings
+ state = wifiResetCumulTimings();
+ RADIOLIB_ASSERT(state);
+
+ // set DIO mapping
+ state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_WIFI_DONE);
+ RADIOLIB_ASSERT(state);
+
+ // start scan with the maximum number of results and abort on timeout
+ this->wifiScanMode = mode;
+ state = wifiScan(type, chanMask, this->wifiScanMode, RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS, numScans, timeout, RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED);
+ return(state);
+}
+
+void LR11x0::setWiFiScanAction(void (*func)(void)) {
+ this->setIrqAction(func);
+}
+
+void LR11x0::clearWiFiScanAction() {
+ this->clearIrqAction();
+}
+
+int16_t LR11x0::getWifiScanResultsCount(uint8_t* count) {
+ // clear IRQ first, as this is likely to be called right after scan has finished
+ int16_t state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
+ RADIOLIB_ASSERT(state);
+
+ uint8_t buff[1] = { 0 };
+ state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(count) { *count = buff[0]; }
+
+ return(state);
+}
+
+int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, bool brief) {
+ RADIOLIB_ASSERT_PTR(result);
+
+ // read a single result
+ uint8_t format = brief ? RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC : RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE;
+ uint8_t raw[RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN] = { 0 };
+ int16_t state = wifiReadResults(index, 1, format, raw);
+ RADIOLIB_ASSERT(state);
+
+ // parse the information
+ switch(raw[0] & 0x03) {
+ case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_B):
+ result->type = 'b';
+ break;
+ case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_G):
+ result->type = 'g';
+ break;
+ case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_N):
+ result->type = 'n';
+ break;
+ }
+ result->dataRateId = (raw[0] & 0xFC) >> 2;
+ result->channelFreq = 2407 + (raw[1] & 0x0F)*5;
+ result->origin = (raw[1] & 0x30) >> 4;
+ result->ap = (raw[1] & 0x40) != 0;
+ result->rssi = (float)raw[2] / -2.0f;;
+ memcpy(result->mac, &raw[3], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
+
+ if(!brief) {
+ if(this->wifiScanMode == RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON) {
+ LR11x0WifiResultExtended_t* resultExtended = reinterpret_cast(result);
+ resultExtended->rate = raw[3];
+ resultExtended->service = (((uint16_t)raw[4] << 8) | ((uint16_t)raw[5]));
+ resultExtended->length = (((uint16_t)raw[6] << 8) | ((uint16_t)raw[7]));
+ resultExtended->frameType = raw[9] & 0x03;
+ resultExtended->frameSubType = (raw[9] & 0x3C) >> 2;
+ resultExtended->toDistributionSystem = (raw[9] & 0x40) != 0;
+ resultExtended->fromDistributionSystem = (raw[9] & 0x80) != 0;
+ memcpy(resultExtended->mac0, &raw[10], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
+ memcpy(resultExtended->mac, &raw[16], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
+ memcpy(resultExtended->mac2, &raw[22], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
+ resultExtended->timestamp = (((uint64_t)raw[28] << 56) | ((uint64_t)raw[29] << 48)) |
+ (((uint64_t)raw[30] << 40) | ((uint64_t)raw[31] << 32)) |
+ (((uint64_t)raw[32] << 24) | ((uint64_t)raw[33] << 16)) |
+ (((uint64_t)raw[34] << 8) | (uint64_t)raw[35]);
+ resultExtended->periodBeacon = (((uint16_t)raw[36] << 8) | ((uint16_t)raw[37])) * 1024UL;
+ resultExtended->seqCtrl = (((uint16_t)raw[38] << 8) | ((uint16_t)raw[39]));
+ memcpy(resultExtended->ssid, &raw[40], RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN);
+ resultExtended->currentChannel = raw[72];
+ memcpy(resultExtended->countryCode, &raw[73], 2);
+ resultExtended->countryCode[2] = '\0';
+ resultExtended->ioReg = raw[75];
+ resultExtended->fcsCheckOk = (raw[76] != 0);
+ resultExtended->phiOffset = (((uint16_t)raw[77] << 8) | ((uint16_t)raw[78]));
+ return(RADIOLIB_ERR_NONE);
+ }
+
+ LR11x0WifiResultFull_t* resultFull = reinterpret_cast(result);
+ resultFull->frameType = raw[3] & 0x03;
+ resultFull->frameSubType = (raw[3] & 0x3C) >> 2;
+ resultFull->toDistributionSystem = (raw[3] & 0x40) != 0;
+ resultFull->fromDistributionSystem = (raw[3] & 0x80) != 0;
+ memcpy(resultFull->mac, &raw[4], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
+ resultFull->phiOffset = (((uint16_t)raw[10] << 8) | ((uint16_t)raw[11]));
+ resultFull->timestamp = (((uint64_t)raw[12] << 56) | ((uint64_t)raw[13] << 48)) |
+ (((uint64_t)raw[14] << 40) | ((uint64_t)raw[15] << 32)) |
+ (((uint64_t)raw[16] << 24) | ((uint64_t)raw[17] << 16)) |
+ (((uint64_t)raw[18] << 8) | (uint64_t)raw[19]);
+ resultFull->periodBeacon = (((uint16_t)raw[20] << 8) | ((uint16_t)raw[21])) * 1024UL;
+ }
+
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) {
+ RADIOLIB_ASSERT_PTR(count);
+
+ // start scan
+ RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan start");
+ int16_t state = startWifiScan(wifiType, mode, chanMask, numScans, timeout);
+ RADIOLIB_ASSERT(state);
+
+ // wait for scan finished or timeout
+ RadioLibTime_t softTimeout = 30UL * 1000UL;
+ RadioLibTime_t start = this->mod->hal->millis();
+ while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
+ this->mod->hal->yield();
+ if(this->mod->hal->millis() - start > softTimeout) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ");
+ this->standby();
+ return(RADIOLIB_ERR_RX_TIMEOUT);
+ }
+ }
+ RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start));
+
+ // read number of results
+ return(getWifiScanResultsCount(count));
+}
+
+int16_t LR11x0::wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) {
+ uint8_t buff[9] = {
+ type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
+ acqMode, nbMaxRes, nbScanPerChan,
+ (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ abortOnTimeout
+ };
+
+ // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts
+ return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_WIFI_SCAN, buff, sizeof(buff), false, false));
+}
+
+int16_t LR11x0::wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) {
+ uint8_t buff[9] = {
+ type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
+ acqMode, nbMaxRes,
+ (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF),
+ (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::wifiCountryCode(uint16_t mask, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) {
+ uint8_t buff[7] = {
+ (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
+ nbMaxRes, nbScanPerChan,
+ (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ abortOnTimeout
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::wifiCountryCodeTimeLimit(uint16_t mask, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) {
+ uint8_t buff[7] = {
+ (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
+ nbMaxRes,
+ (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF),
+ (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::wifiReadResults(uint8_t index, uint8_t nbResults, uint8_t format, uint8_t* results) {
+ uint8_t buff[3] = { index, nbResults, format };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS, false, results, RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::wifiResetCumulTimings(void) {
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS, true, NULL, 0));
+}
+
+int16_t LR11x0::wifiReadCumulTimings(uint32_t* detection, uint32_t* capture, uint32_t* demodulation) {
+ uint8_t buff[16] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(detection) { *detection = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; }
+ if(capture) { *capture = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; }
+ if(demodulation) { *demodulation = ((uint32_t)(buff[12]) << 24) | ((uint32_t)(buff[13]) << 16) | ((uint32_t)(buff[14]) << 8) | (uint32_t)buff[15]; }
+
+ return(state);
+}
+
+int16_t LR11x0::wifiGetNbCountryCodeResults(uint8_t* nbResults) {
+ uint8_t buff[1] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(nbResults) { *nbResults = buff[0]; }
+
+ return(state);
+}
+
+int16_t LR11x0::wifiReadCountryCodeResults(uint8_t index, uint8_t nbResults, uint8_t* results) {
+ uint8_t reqBuff[2] = { index, nbResults };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS, false, results, nbResults, reqBuff, sizeof(reqBuff)));
+}
+
+int16_t LR11x0::wifiCfgTimestampAPphone(uint32_t timestamp) {
+ uint8_t buff[4] = {
+ (uint8_t)((timestamp >> 24) & 0xFF), (uint8_t)((timestamp >> 16) & 0xFF),
+ (uint8_t)((timestamp >> 8) & 0xFF), (uint8_t)(timestamp & 0xFF)
+ };
+ return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff)));
+}
+
+int16_t LR11x0::wifiReadVersion(uint8_t* major, uint8_t* minor) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION, false, buff, sizeof(buff));
+
+ // pass the replies
+ if(major) { *major = buff[0]; }
+ if(minor) { *minor = buff[1]; }
+
+ return(state);
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR11x0/LR_common.cpp b/lib/RadioLib/src/modules/LR11x0/LR_common.cpp
new file mode 100644
index 0000000..cf70628
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR11x0/LR_common.cpp
@@ -0,0 +1,427 @@
+#include "LR_common.h"
+
+#include
+
+LRxxxx::LRxxxx(Module* mod) : PhysicalLayer() {
+ this->mod = mod;
+ this->XTAL = false;
+ this->mod->spiConfig.stream = true;
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16;
+ this->mod->spiConfig.statusPos = 0;
+ this->mod->spiConfig.parseStatusCb = SPIparseStatus;
+ this->mod->spiConfig.checkStatusCb = SPIcheckStatus;
+}
+
+void LRxxxx::setIrqAction(void (*func)(void)) {
+ this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
+}
+
+void LRxxxx::clearIrqAction() {
+ this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
+}
+
+void LRxxxx::setPacketReceivedAction(void (*func)(void)) {
+ this->setIrqAction(func);
+}
+
+void LRxxxx::clearPacketReceivedAction() {
+ this->clearIrqAction();
+}
+
+void LRxxxx::setPacketSentAction(void (*func)(void)) {
+ this->setIrqAction(func);
+}
+
+void LRxxxx::clearPacketSentAction() {
+ this->clearIrqAction();
+}
+
+uint32_t LRxxxx::getIrqStatus() {
+ // there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes
+ uint8_t buff[6] = { 0 };
+ Module::BitWidth_t statusWidth = mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS];
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
+ mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = statusWidth;
+ uint32_t irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5];
+ return(irq);
+}
+
+RadioLibTime_t LRxxxx::getTimeOnAir(size_t len, ModemType_t modem) {
+ DataRate_t dr = {};
+ PacketConfig_t pc = {};
+ switch(modem) {
+ case ModemType_t::RADIOLIB_MODEM_LORA: {
+ uint8_t cr = this->codingRate;
+ // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values
+ if (cr < 5) {
+ cr = cr + 4;
+ } else if (cr == 7) {
+ cr = cr + 1;
+ }
+
+ dr.lora.spreadingFactor = this->spreadingFactor;
+ dr.lora.bandwidth = this->bandwidthKhz;
+ dr.lora.codingRate = cr;
+
+ pc.lora.preambleLength = this->preambleLengthLoRa;
+ pc.lora.implicitHeader = (this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT);
+ pc.lora.crcEnabled = (this->crcTypeLoRa == RADIOLIB_LRXXXX_LORA_CRC_ENABLED);
+ pc.lora.ldrOptimize = (bool)this->ldrOptimize;
+ break;
+ }
+
+ case ModemType_t::RADIOLIB_MODEM_FSK: {
+ dr.fsk.bitRate = (float)this->bitRate / 1000.0f;
+ dr.fsk.freqDev = (float)this->frequencyDev;
+ pc.fsk.preambleLength = this->preambleLengthGFSK;
+ pc.fsk.syncWordLength = this->syncWordLength;
+ pc.fsk.crcLength = this->crcLenGFSK;
+ break;
+ }
+
+ case ModemType_t::RADIOLIB_MODEM_LRFHSS: {
+ dr.lrFhss.bw = this->lrFhssBw;
+ dr.lrFhss.cr = this->lrFhssCr;
+ dr.lrFhss.narrowGrid = (this->lrFhssGrid == RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC) ? true : false;
+
+ pc.lrFhss.hdrCount = this->lrFhssHdrCount;
+ break;
+ }
+
+ default:
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ return(this->calculateTimeOnAir(modem, dr, pc, len));
+}
+
+RadioLibTime_t LRxxxx::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
+ // check active modem
+ if (modem == ModemType_t::RADIOLIB_MODEM_LORA) {
+ uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << dr.lora.spreadingFactor) / (dr.lora.bandwidth * 10) ;
+ uint8_t sfCoeff1_x4 = 17; // (4.25 * 4)
+ uint8_t sfCoeff2 = 8;
+ if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) {
+ sfCoeff1_x4 = 25; // 6.25 * 4
+ sfCoeff2 = 0;
+ }
+ uint8_t sfDivisor = 4*dr.lora.spreadingFactor;
+ if(pc.lora.ldrOptimize) {
+ sfDivisor = 4*(dr.lora.spreadingFactor - 2);
+ }
+ const int8_t bitsPerCrc = 16;
+ const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20;
+
+ // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8)
+ int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor + sfCoeff2 + N_symbol_header;
+ if(bitCount < 0) {
+ bitCount = 0;
+ }
+ // add (sfDivisor) - 1 to the numerator to give integer CEIL(...)
+ uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor);
+
+ // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit
+ uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4;
+
+ // get time-on-air in us
+ return((symbolLength_us * nSymbol_x4) / 4);
+
+ } else if(modem == ModemType_t::RADIOLIB_MODEM_FSK) {
+ return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f)));
+
+ } else if(modem == ModemType_t::RADIOLIB_MODEM_LRFHSS) {
+ // calculate the number of bits based on coding rate
+ uint16_t N_bits;
+ switch(dr.lrFhss.cr) {
+ case RADIOLIB_LRXXXX_LR_FHSS_CR_5_6:
+ N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4?
+ break;
+ case RADIOLIB_LRXXXX_LR_FHSS_CR_2_3:
+ N_bits = (len * 3) / 2;
+ break;
+ case RADIOLIB_LRXXXX_LR_FHSS_CR_1_2:
+ N_bits = len * 2;
+ break;
+ case RADIOLIB_LRXXXX_LR_FHSS_CR_1_3:
+ N_bits = len * 3;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_CODING_RATE);
+ }
+
+ // calculate number of bits when accounting for unaligned last block
+ uint16_t N_payBits = (N_bits / RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS) * RADIOLIB_LRXXXX_LR_FHSS_BLOCK_BITS;
+ uint16_t N_lastBlockBits = N_bits % RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS;
+ if(N_lastBlockBits) {
+ N_payBits += N_lastBlockBits + 2;
+ }
+
+ // add header bits
+ uint16_t N_totalBits = (RADIOLIB_LRXXXX_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits;
+ return(((uint32_t)N_totalBits * 8 * 1000000UL) / RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE);
+
+ } else {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ return(0);
+}
+
+RadioLibTime_t LRxxxx::calculateRxTimeout(RadioLibTime_t timeoutUs) {
+ // the timeout value is given in units of 30.52 microseconds
+ // the calling function should provide some extra width, as this number of units is truncated to integer
+ RadioLibTime_t timeout = timeoutUs / 30.52;
+ return(timeout);
+}
+
+int16_t LRxxxx::reset() {
+ // run the reset sequence
+ this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput);
+ this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow);
+ this->mod->hal->delay(10);
+ this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh);
+
+ // the typical transition duration should be 273 ms
+ this->mod->hal->delay(300);
+
+ // wait for BUSY to go low
+ RadioLibTime_t start = this->mod->hal->millis();
+ while(this->mod->hal->digitalRead(this->mod->getGpio())) {
+ this->mod->hal->yield();
+ if(this->mod->hal->millis() - start >= 3000) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after reset!");
+ return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
+ }
+ }
+
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t LRxxxx::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) {
+ uint8_t buff[6] = { 0 };
+
+ // the status check command doesn't return status in the same place as other read commands
+ // but only as the first byte (as with any other command), hence LRxxxx::SPIcommand can't be used
+ // it also seems to ignore the actual command, and just sending in bunch of NOPs will work
+ int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
+
+ // pass the replies
+ if(stat1) { *stat1 = buff[0]; }
+ if(stat2) { *stat2 = buff[1]; }
+ if(irq) { *irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; }
+
+ return(state);
+}
+
+int16_t LRxxxx::lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uint8_t grid, uint8_t hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len) {
+ // check maximum size
+ const uint8_t maxLen[4][4] = {
+ { 189, 178, 167, 155, },
+ { 151, 142, 133, 123, },
+ { 112, 105, 99, 92, },
+ { 74, 69, 65, 60, },
+ };
+ if((cr > RADIOLIB_LRXXXX_LR_FHSS_CR_1_3) || ((hdrCount - 1) > (int)sizeof(maxLen[0])) || (len > maxLen[cr][hdrCount - 1])) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+
+ // build buffers
+ size_t buffLen = 9 + len;
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t dataBuff[9 + 190];
+ #else
+ uint8_t* dataBuff = new uint8_t[buffLen];
+ #endif
+
+ // set properties of the packet
+ dataBuff[0] = hdrCount;
+ dataBuff[1] = cr;
+ dataBuff[2] = RADIOLIB_LRXXXX_LR_FHSS_MOD_TYPE_GMSK;
+ dataBuff[3] = grid;
+ dataBuff[4] = hop;
+ dataBuff[5] = bw;
+ dataBuff[6] = (uint8_t)((hopSeq >> 8) & 0x01);
+ dataBuff[7] = (uint8_t)(hopSeq & 0xFF);
+ dataBuff[8] = devOffset;
+ memcpy(&dataBuff[9], payload, len);
+
+ int16_t state = this->SPIcommand(cmd, true, dataBuff, buffLen);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] dataBuff;
+ #endif
+ return(state);
+}
+
+uint8_t LRxxxx::roundRampTime(uint32_t rampTimeUs) {
+ uint8_t regVal;
+
+ // Round up the ramp time to nearest discrete register value
+ if(rampTimeUs <= 2) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_2U;
+ } else if(rampTimeUs <= 4) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_4U;
+ } else if(rampTimeUs <= 8) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_8U;
+ } else if(rampTimeUs <= 16) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_16U;
+ } else if(rampTimeUs <= 32) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_32U;
+ } else if(rampTimeUs <= 48) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_48U;
+ } else if(rampTimeUs <= 64) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_64U;
+ } else if(rampTimeUs <= 80) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_80U;
+ } else if(rampTimeUs <= 96) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_96U;
+ } else if(rampTimeUs <= 112) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_112U;
+ } else if(rampTimeUs <= 128) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_128U;
+ } else if(rampTimeUs <= 144) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_144U;
+ } else if(rampTimeUs <= 160) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_160U;
+ } else if(rampTimeUs <= 176) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_176U;
+ } else if(rampTimeUs <= 192) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_192U;
+ } else if(rampTimeUs <= 208) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_208U;
+ } else if(rampTimeUs <= 240) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_240U;
+ } else if(rampTimeUs <= 272) {
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_272U;
+ } else { // 304
+ regVal = RADIOLIB_LRXXXX_PA_RAMP_304U;
+ }
+
+ return regVal;
+}
+
+int16_t LRxxxx::findRxBw(float rxBw, const uint8_t* lut, size_t lutSize, float rxBwMax, uint8_t* val) {
+ // lookup tables to avoid comparing a whole bunch of floats
+ const uint16_t rxBwAvg[] = {
+ 53, 66, 85, 108, 134, 170, 211, 264,
+ 341, 424, 529, 682, 847, 1058, 1364,
+ 1695, 2116, 2729, 3390, 4233, 5159,
+ 6111, 7179, 9401, 16665, 24440, 28710,
+ };
+
+ // iterate through the table and find whether the user-provided value
+ // is lower than the pre-computed average of the adjacent bandwidth values
+ // if it is, we consider that to be a match even though the actual value is not precise
+ uint16_t rxBwInt = rxBw*10.0f;
+ for(size_t i = 0; i < lutSize; i++) {
+ if(rxBwInt < rxBwAvg[i]) {
+ *val = lut[i];
+ return(RADIOLIB_ERR_NONE);
+ }
+ }
+
+ // if nothing matched up to here, match with the last value
+ if(rxBwInt <= rxBwMax*10) {
+ *val = lut[lutSize - 1];
+ return(RADIOLIB_ERR_NONE);
+ }
+
+ return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
+}
+
+int16_t LRxxxx::setU32(uint16_t cmd, uint32_t u32) {
+ uint8_t buff[] = {
+ (uint8_t)((u32 >> 24) & 0xFF), (uint8_t)((u32 >> 16) & 0xFF),
+ (uint8_t)((u32 >> 8) & 0xFF), (uint8_t)(u32 & 0xFF),
+ };
+ return(this->SPIcommand(cmd, true, buff, sizeof(buff)));
+}
+
+int16_t LRxxxx::SPIparseStatus(uint8_t in) {
+ if((in & 0b00001110) == RADIOLIB_LRXXXX_STAT_1_CMD_PERR) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ } else if((in & 0b00001110) == RADIOLIB_LRXXXX_STAT_1_CMD_FAIL) {
+ return(RADIOLIB_ERR_SPI_CMD_FAILED);
+ } else if((in == 0x00) || (in == 0xFF)) {
+ return(RADIOLIB_ERR_CHIP_NOT_FOUND);
+ }
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t LRxxxx::SPIcheckStatus(Module* mod) {
+ // the status check command doesn't return status in the same place as other read commands,
+ // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used
+ // it also seems to ignore the actual command, and just sending in bunch of NOPs will work
+ uint8_t buff[6] = { 0 };
+ Module::BitWidth_t statusWidth = mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS];
+ mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
+ int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
+ mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = statusWidth;
+ RADIOLIB_ASSERT(state);
+ return(LRxxxx::SPIparseStatus(buff[0]));
+}
+
+int16_t LRxxxx::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) {
+ // build buffers - later we need to ensure endians are correct,
+ // so there is probably no way to do this without copying buffers and iterating
+ size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t);
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t dataBuff[sizeof(uint32_t) + RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* dataBuff = new uint8_t[buffLen];
+ #endif
+
+ // set the address or offset
+ uint8_t* dataBuffPtr = reinterpret_cast(dataBuff);
+ if(this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] >= Module::BITS_32) {
+ // LR2021 has 24-bit address, whereas LR11x0 has 32-bit
+ *(dataBuffPtr++) = (uint8_t)((addrOffset >> 24) & 0xFF);
+ }
+
+ *(dataBuffPtr++) = (uint8_t)((addrOffset >> 16) & 0xFF);
+ *(dataBuffPtr++) = (uint8_t)((addrOffset >> 8) & 0xFF);
+ *(dataBuffPtr++) = (uint8_t)(addrOffset & 0xFF);
+
+ // convert endians
+ for(size_t i = 0; i < len; i++) {
+ uint32_t bin = 0;
+ if(nonvolatile) {
+ uint32_t* ptr = const_cast(data) + i;
+ bin = RADIOLIB_NONVOLATILE_READ_DWORD(ptr);
+ } else {
+ bin = data[i];
+ }
+ *(dataBuffPtr++) = (uint8_t)((bin >> 24) & 0xFF);
+ *(dataBuffPtr++) = (uint8_t)((bin >> 16) & 0xFF);
+ *(dataBuffPtr++) = (uint8_t)((bin >> 8) & 0xFF);
+ *(dataBuffPtr++) = (uint8_t)(bin & 0xFF);
+ }
+
+ int16_t state = this->mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false);
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] dataBuff;
+ #endif
+ return(state);
+}
+
+int16_t LRxxxx::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out, size_t outLen) {
+ int16_t state = RADIOLIB_ERR_UNKNOWN;
+ if(!write) {
+ // the SPI interface of LR11x0 requires two separate transactions for reading
+ // send the 16-bit command
+ state = this->mod->SPIwriteStream(cmd, out, outLen, true, false);
+ RADIOLIB_ASSERT(state);
+
+ // read the result without command
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_0;
+ state = this->mod->SPIreadStream(RADIOLIB_LRXXXX_CMD_NOP, data, len, true, false);
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16;
+
+ } else {
+ // write is just a single transaction
+ state = this->mod->SPIwriteStream(cmd, data, len, true, true);
+
+ }
+
+ return(state);
+}
diff --git a/lib/RadioLib/src/modules/LR11x0/LR_common.h b/lib/RadioLib/src/modules/LR11x0/LR_common.h
new file mode 100644
index 0000000..0cc5634
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR11x0/LR_common.h
@@ -0,0 +1,207 @@
+#if !defined(RADIOLIB_LR_COMMON_H)
+#define RADIOLIB_LR_COMMON_H
+
+#include "../../Module.h"
+#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
+
+#define RADIOLIB_LRXXXX_CMD_NOP (0x0000)
+#define RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN (128) // intentionally limited to the length supported by LR2021
+
+// RADIOLIB_LR11X0_CMD_GET_STATUS
+// RADIOLIB_LR2021_CMD_GET_STATUS MSB LSB DESCRIPTION
+#define RADIOLIB_LRXXXX_STAT_1_CMD_FAIL (0x00UL << 1) // 3 1 command status: last command could not be executed
+#define RADIOLIB_LRXXXX_STAT_1_CMD_PERR (0x01UL << 1) // 3 1 processing error
+#define RADIOLIB_LRXXXX_STAT_1_CMD_OK (0x02UL << 1) // 3 1 successfully processed
+#define RADIOLIB_LRXXXX_STAT_1_CMD_DAT (0x03UL << 1) // 3 1 successfully processed, data is being transmitted
+
+// RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME
+// RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME
+#define RADIOLIB_LRXXXX_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6
+#define RADIOLIB_LRXXXX_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3
+#define RADIOLIB_LRXXXX_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2
+#define RADIOLIB_LRXXXX_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3
+#define RADIOLIB_LRXXXX_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK
+#define RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC)
+#define RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC)
+#define RADIOLIB_LRXXXX_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled
+#define RADIOLIB_LRXXXX_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled
+#define RADIOLIB_LRXXXX_LR_FHSS_HOPPING_TEST_NO_HOP (0x02UL << 0) // 7 0 test mode (packet encoded, no hopping)
+#define RADIOLIB_LRXXXX_LR_FHSS_HOPPING_TEST_PA_RAMP (0x03UL << 0) // 7 0 test mode (PA ramp up, no hopping)
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz
+#define RADIOLIB_LRXXXX_LR_FHSS_HEADER_BITS (114) // 7 0 LR FHSS packet bit widths: header
+#define RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS (48) // 7 0 payload fragment
+#define RADIOLIB_LRXXXX_LR_FHSS_BLOCK_PREAMBLE_BITS (2) // 7 0 block preamble
+#define RADIOLIB_LRXXXX_LR_FHSS_BLOCK_BITS (RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS + RADIOLIB_LRXXXX_LR_FHSS_BLOCK_PREAMBLE_BITS)
+
+// RADIOLIB_LR11X0_CMD_SET_TCXO_MODE
+// RADIOLIB_LR2021_CMD_SET_TCXO_MODE
+#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_6 (0x00UL << 0) // 2 0 TCXO supply voltage: 1.6V
+#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_7 (0x01UL << 0) // 2 0 1.7V
+#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_8 (0x02UL << 0) // 2 0 1.8V
+#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_2 (0x03UL << 0) // 2 0 2.2V
+#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_4 (0x04UL << 0) // 2 0 2.4V
+#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_7 (0x05UL << 0) // 2 0 2.7V
+#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0 (0x06UL << 0) // 2 0 3.0V
+#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3 (0x07UL << 0) // 2 0 3.3V
+
+// RADIOLIB_LR11X0_CMD_SET_TX_PARAMS
+// RADIOLIB_LR2021_CMD_SET_TX_PARAMS
+#define RADIOLIB_LRXXXX_PA_RAMP_2U (0x00UL << 0) // 7 0 PA ramp time: 2 us (LR2021 only)
+#define RADIOLIB_LRXXXX_PA_RAMP_4U (0x01UL << 0) // 7 0 4 us (LR2021 only)
+#define RADIOLIB_LRXXXX_PA_RAMP_8U (0x02UL << 0) // 7 0 8 us (LR2021 only)
+#define RADIOLIB_LRXXXX_PA_RAMP_16U (0x03UL << 0) // 7 0 16 us
+#define RADIOLIB_LRXXXX_PA_RAMP_32U (0x04UL << 0) // 7 0 32 us
+#define RADIOLIB_LRXXXX_PA_RAMP_48U (0x05UL << 0) // 7 0 48 us
+#define RADIOLIB_LRXXXX_PA_RAMP_64U (0x06UL << 0) // 7 0 64 us
+#define RADIOLIB_LRXXXX_PA_RAMP_80U (0x07UL << 0) // 7 0 80 us
+#define RADIOLIB_LRXXXX_PA_RAMP_96U (0x08UL << 0) // 7 0 96 us
+#define RADIOLIB_LRXXXX_PA_RAMP_112U (0x09UL << 0) // 7 0 112 us
+#define RADIOLIB_LRXXXX_PA_RAMP_128U (0x0AUL << 0) // 7 0 128 us
+#define RADIOLIB_LRXXXX_PA_RAMP_144U (0x0BUL << 0) // 7 0 144 us
+#define RADIOLIB_LRXXXX_PA_RAMP_160U (0x0CUL << 0) // 7 0 160 us
+#define RADIOLIB_LRXXXX_PA_RAMP_176U (0x0DUL << 0) // 7 0 176 us
+#define RADIOLIB_LRXXXX_PA_RAMP_192U (0x0EUL << 0) // 7 0 192 us
+#define RADIOLIB_LRXXXX_PA_RAMP_208U (0x0FUL << 0) // 7 0 208 us
+#define RADIOLIB_LRXXXX_PA_RAMP_240U (0x10UL << 0) // 7 0 240 us
+#define RADIOLIB_LRXXXX_PA_RAMP_272U (0x11UL << 0) // 7 0 272 us
+#define RADIOLIB_LRXXXX_PA_RAMP_304U (0x12UL << 0) // 7 0 304 us
+
+// RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH
+// RADIOLIB_LR2021_CMD_SET_DIO_AS_RF_SWITCH
+#define RADIOLIB_LRXXXX_DIOx(X) ((X) | RFSWITCH_PIN_FLAG)
+#define RADIOLIB_LRXXXX_DIOx_VAL(X) ((X) & ~RFSWITCH_PIN_FLAG)
+
+// common configuration values
+#define RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE (488.28215f) // 31 0 LR FHSS bit rate: 488.28215 bps
+#define RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE_RAW (0x8001E848UL) // 31 0 488.28215 bps in raw
+#define RADIOLIB_LRXXXX_LORA_HEADER_EXPLICIT (0x00UL << 0) // 7 0 LoRa header mode: explicit
+#define RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT (0x01UL << 0) // 7 0 implicit
+#define RADIOLIB_LRXXXX_LORA_CRC_ENABLED (0x01UL << 0) // 7 0 CRC: enabled
+#define RADIOLIB_LRXXXX_LORA_CRC_DISABLED (0x00UL << 0) // 7 0 disabled
+
+class LRxxxx: public PhysicalLayer {
+ public:
+ explicit LRxxxx(Module* mod);
+
+ /*!
+ \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false.
+ */
+ bool XTAL;
+
+ /*!
+ \brief Reset method. Will reset the chip to the default state using RST pin.
+ \returns \ref status_codes
+ */
+ int16_t reset();
+
+ /*!
+ \brief Sets interrupt service routine to call when IRQ1 activates.
+ \param func ISR to call.
+ */
+ void setIrqAction(void (*func)(void));
+
+ /*!
+ \brief Clears interrupt service routine to call when IRQ1 activates.
+ */
+ void clearIrqAction();
+
+ /*!
+ \brief Sets interrupt service routine to call when a packet is received.
+ \param func ISR to call.
+ */
+ void setPacketReceivedAction(void (*func)(void)) override;
+
+ /*!
+ \brief Clears interrupt service routine to call when a packet is received.
+ */
+ void clearPacketReceivedAction() override;
+
+ /*!
+ \brief Sets interrupt service routine to call when a packet is sent.
+ \param func ISR to call.
+ */
+ void setPacketSentAction(void (*func)(void)) override;
+
+ /*!
+ \brief Clears interrupt service routine to call when a packet is sent.
+ */
+ void clearPacketSentAction() override;
+
+ /*!
+ \brief Reads the current IRQ status.
+ \returns IRQ status bits
+ */
+ uint32_t getIrqStatus();
+
+ /*!
+ \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size.
+ \param modem Modem type.
+ \param dr Data rate.
+ \param pc Packet config.
+ \param len Payload length in bytes.
+ \returns Expected time-on-air in microseconds.
+ */
+ RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override;
+
+ /*!
+ \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
+ \param timeoutUs Timeout in microseconds to listen for
+ \returns Timeout value in a unit that is specific for the used module
+ */
+ RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override;
+
+ protected:
+ Module* mod;
+
+ float freqMHz = 0;
+ uint32_t rxTimeout = 0;
+
+ // cached LoRa parameters
+ uint8_t bandwidth = 0, spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0;
+ uint16_t preambleLengthLoRa = 0;
+ float bandwidthKhz = 0;
+ bool ldroAuto = true;
+ size_t implicitLen = 0;
+ bool invertIQEnabled = false;
+
+ // cached GFSK parameters
+ uint32_t bitRate = 0, frequencyDev = 0;
+ uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, crcLenGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0, node = 0;
+ uint16_t preambleLengthGFSK = 0;
+
+ // cached LR-FHSS parameters
+ uint8_t lrFhssCr = 0, lrFhssBw = 0, lrFhssHdrCount = 0, lrFhssGrid = 0;
+ uint16_t lrFhssHopSeq = 0;
+
+ // a lot of SPI commands have the same structure and arguments on both LR11xx as well as LR2021
+ // the only difference is the 16-bit command code - however, having everything in this base class
+ // will actually increase the binary size, because of the extra method calls that are needed
+ // for that reason, only the methods that are 100% the same are kept here
+ int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq);
+ int16_t lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uint8_t grid, uint8_t hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len);
+ uint8_t roundRampTime(uint32_t rampTimeUs);
+ int16_t findRxBw(float rxBw, const uint8_t* lut, size_t lutSize, float rxBwMax, uint8_t* val);
+ RadioLibTime_t getTimeOnAir(size_t len, ModemType_t modem);
+
+ // several commands just send unsigned 32-bit number
+ int16_t setU32(uint16_t cmd, uint32_t u32);
+
+ int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile);
+ int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out = NULL, size_t outLen = 0);
+
+ static int16_t SPIparseStatus(uint8_t in);
+ static int16_t SPIcheckStatus(Module* mod);
+
+ private:
+};
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021.cpp b/lib/RadioLib/src/modules/LR2021/LR2021.cpp
new file mode 100644
index 0000000..a7085c5
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021.cpp
@@ -0,0 +1,1055 @@
+#include "LR2021.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+LR2021::LR2021(Module* mod) : LRxxxx(mod) {
+ this->freqStep = RADIOLIB_LR2021_FREQUENCY_STEP_SIZE;
+ this->maxPacketLength = RADIOLIB_LR2021_MAX_PACKET_LENGTH;
+ this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR2021_IRQ_TX_DONE;
+ this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR2021_IRQ_RX_DONE;
+ this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED;
+ this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID;
+ this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID;
+ this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_LR2021_IRQ_LORA_HDR_CRC_ERROR;
+ this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_LR2021_IRQ_CRC_ERROR;
+ this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR2021_IRQ_CAD_DONE;
+ this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR2021_IRQ_CAD_DETECTED;
+ this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR2021_IRQ_TIMEOUT;
+}
+
+int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
+ // set module properties and perform initial setup
+ int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_LORA);
+ RADIOLIB_ASSERT(state);
+
+ // configure publicly accessible settings
+ state = setBandwidth(bw);
+ RADIOLIB_ASSERT(state);
+
+ state = setSpreadingFactor(sf);
+ RADIOLIB_ASSERT(state);
+
+ state = setCodingRate(cr);
+ RADIOLIB_ASSERT(state);
+
+ state = setSyncWord(syncWord);
+ RADIOLIB_ASSERT(state);
+
+ state = setOutputPower(power);
+ RADIOLIB_ASSERT(state);
+
+ state = setPreambleLength(preambleLength);
+ RADIOLIB_ASSERT(state);
+
+ // set publicly accessible settings that are not a part of begin method
+ state = setCRC(2);
+ RADIOLIB_ASSERT(state);
+
+ state = invertIQ(false);
+ return(state);
+}
+
+int16_t LR2021::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
+ this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8;
+ this->frequencyDev = freqDev * 1000.0f;
+
+ // set module properties and perform initial setup
+ int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_GFSK);
+ RADIOLIB_ASSERT(state);
+
+ // configure publicly accessible settings
+ state = setBitRate(br);
+ RADIOLIB_ASSERT(state);
+
+ state = setFrequencyDeviation(freqDev);
+ RADIOLIB_ASSERT(state);
+
+ state = setRxBandwidth(rxBw);
+ RADIOLIB_ASSERT(state);
+
+ state = setOutputPower(power);
+ RADIOLIB_ASSERT(state);
+
+ state = setPreambleLength(preambleLength);
+ RADIOLIB_ASSERT(state);
+
+ // set publicly accessible settings that are not a part of begin method
+ uint8_t sync[] = { 0x12, 0xAD };
+ state = setSyncWord(sync, 2);
+ RADIOLIB_ASSERT(state);
+
+ state = setDataShaping(RADIOLIB_SHAPING_NONE);
+ RADIOLIB_ASSERT(state);
+
+ state = setEncoding(RADIOLIB_ENCODING_NRZ);
+ RADIOLIB_ASSERT(state);
+
+ state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH);
+ RADIOLIB_ASSERT(state);
+
+ state = setCRC(2);
+ return(state);
+}
+
+int16_t LR2021::beginOOK(float freq, float br, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
+ this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8;
+
+ // set module properties and perform initial setup
+ int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_OOK);
+ RADIOLIB_ASSERT(state);
+
+ // configure publicly accessible settings
+ state = setBitRate(br);
+ RADIOLIB_ASSERT(state);
+
+ state = setRxBandwidth(rxBw);
+ RADIOLIB_ASSERT(state);
+
+ state = setOutputPower(power);
+ RADIOLIB_ASSERT(state);
+
+ state = setPreambleLength(preambleLength);
+ RADIOLIB_ASSERT(state);
+
+ // set publicly accessible settings that are not a part of begin method
+ uint8_t sync[] = { 0x12, 0xAD };
+ state = setSyncWord(sync, 2);
+ RADIOLIB_ASSERT(state);
+
+ state = setDataShaping(RADIOLIB_SHAPING_NONE);
+ RADIOLIB_ASSERT(state);
+
+ state = setEncoding(RADIOLIB_ENCODING_NRZ);
+ RADIOLIB_ASSERT(state);
+
+ state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH);
+ RADIOLIB_ASSERT(state);
+
+ state = setCRC(2);
+ return(state);
+}
+
+int16_t LR2021::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage) {
+// set module properties and perform initial setup
+ int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS);
+ RADIOLIB_ASSERT(state);
+
+ // set grid spacing
+ this->lrFhssGrid = narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC;
+
+ // configure publicly accessible settings
+ state = setLrFhssConfig(bw, cr);
+ RADIOLIB_ASSERT(state);
+
+ state = setOutputPower(power);
+ RADIOLIB_ASSERT(state);
+
+ uint8_t syncWord[] = { 0x12, 0xAD, 0x10, 0x1B };
+ state = setSyncWord(syncWord, 4);
+ return(state);
+}
+
+int16_t LR2021::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint16_t preambleLength, uint8_t dataShaping, float tcxoVoltage) {
+ // initialize FLRC modulation variables
+ this->bitRateFlrc = br;
+ this->codingRateFlrc = RADIOLIB_LR2021_FLRC_CR_3_4;
+ this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5;
+
+ // initialize FLRC packet variables
+ this->preambleLengthGFSK = preambleLength;
+ this->crcLenGFSK = 1;
+
+ // set module properties and perform initial setup
+ int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_FLRC);
+ RADIOLIB_ASSERT(state);
+
+ // configure publicly accessible settings
+ state = setFrequency(freq);
+ RADIOLIB_ASSERT(state);
+
+ state = setBitRate(br);
+ RADIOLIB_ASSERT(state);
+
+ state = setCodingRate(cr);
+ RADIOLIB_ASSERT(state);
+
+ state = setOutputPower(pwr);
+ RADIOLIB_ASSERT(state);
+
+ state = setPreambleLength(preambleLength);
+ RADIOLIB_ASSERT(state);
+
+ state = setDataShaping(dataShaping);
+ RADIOLIB_ASSERT(state);
+
+ // set publicly accessible settings that are not a part of begin method
+ uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D};
+ state = setSyncWord(sync, 4);
+ RADIOLIB_ASSERT(state);
+
+ state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH);
+ RADIOLIB_ASSERT(state);
+
+ state = setCRC(2);
+ return(state);
+}
+
+int16_t LR2021::transmit(const uint8_t* data, size_t len, uint8_t addr) {
+ // set mode to standby
+ int16_t state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // check packet length
+ if (this->codingRate > RADIOLIB_LR2021_LORA_CR_4_8) {
+ // Long Interleaver needs at least 8 bytes
+ if(len < 8) {
+ return(RADIOLIB_ERR_PACKET_TOO_SHORT);
+ }
+
+ // Long Interleaver supports up to 253 bytes if CRC is enabled
+ if (this->crcTypeLoRa == RADIOLIB_LR2021_LORA_CRC_ENABLED && (len > RADIOLIB_LR2021_MAX_PACKET_LENGTH - 2)) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+ }
+ if(len > RADIOLIB_LR2021_MAX_PACKET_LENGTH) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+
+ // get currently active modem
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ RadioLibTime_t timeout = getTimeOnAir(len);
+ if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ // calculate timeout (150% of expected time-on-air)
+ timeout = (timeout * 3) / 2;
+
+ } else if((modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) ||
+ (modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) ||
+ (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) ||
+ (modem == RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
+ // calculate timeout (500% of expected time-on-air)
+ timeout = timeout * 5;
+
+ } else {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout);
+
+ // start transmission
+ state = startTransmit(data, len, addr);
+ RADIOLIB_ASSERT(state);
+
+ // wait for packet transmission or timeout
+ RadioLibTime_t start = this->mod->hal->micros();
+ while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
+ this->mod->hal->yield();
+ if(this->mod->hal->micros() - start > timeout) {
+ finishTransmit();
+ return(RADIOLIB_ERR_TX_TIMEOUT);
+ }
+ }
+
+ return(finishTransmit());
+}
+
+int16_t LR2021::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
+ // set mode to standby
+ int16_t state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // calculate timeout based on the configured modem
+ RadioLibTime_t timeoutInternal = timeout;
+ if(!timeoutInternal) {
+ // get currently active modem
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) ||
+ (modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) ||
+ (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) ||
+ (modem == RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
+ // calculate timeout (500 % of expected time-one-air)
+ size_t maxLen = len;
+ if(len == 0) { maxLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH; }
+ timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
+
+ } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
+ // this modem cannot receive
+ return(RADIOLIB_ERR_WRONG_MODEM);
+
+ } else {
+ return(RADIOLIB_ERR_UNKNOWN);
+
+ }
+ }
+
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
+
+ // start reception
+ uint32_t timeoutValue = (uint32_t)(((float)timeoutInternal * 1000.0f) / 30.52f);
+ state = startReceive(timeoutValue);
+ RADIOLIB_ASSERT(state);
+
+ // wait for packet reception or timeout
+ bool softTimeout = false;
+ RadioLibTime_t start = this->mod->hal->millis();
+ while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
+ this->mod->hal->yield();
+ // safety check, the timeout should be done by the radio
+ if(this->mod->hal->millis() - start > timeoutInternal) {
+ softTimeout = true;
+ break;
+ }
+ }
+
+ // if it was a timeout, this will return an error code
+ //! \TODO: [LR2021] taken from SX126x, does this really work?
+ state = standby();
+ if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) {
+ return(state);
+ }
+
+ // check whether this was a timeout or not
+ if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
+ (void)finishReceive();
+ return(RADIOLIB_ERR_RX_TIMEOUT);
+ }
+
+ // read the received data
+ return(readData(data, len));
+}
+
+int16_t LR2021::transmitDirect(uint32_t frf) {
+ // set RF switch (if present)
+ this->mod->setRfSwitchState(Module::MODE_TX);
+
+ // user requested to start transmitting immediately (required for RTTY)
+ int16_t state = RADIOLIB_ERR_NONE;
+ if(frf != 0) {
+ state = setRfFrequency(frf);
+ }
+ RADIOLIB_ASSERT(state);
+
+ // start transmitting
+ return(setTxTestMode(RADIOLIB_LR2021_TX_TEST_MODE_CW));
+}
+
+int16_t LR2021::receiveDirect() {
+ // set RF switch (if present)
+ this->mod->setRfSwitchState(Module::MODE_RX);
+
+ // LR2021 is unable to output received data directly
+ return(RADIOLIB_ERR_UNKNOWN);
+}
+
+int16_t LR2021::scanChannel() {
+ ChannelScanConfig_t cfg = {
+ .cad = {
+ .symNum = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
+ .detPeak = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
+ .detMin = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
+ .exitMode = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
+ .timeout = 0,
+ .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
+ .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
+ },
+ };
+ return(this->scanChannel(cfg));
+}
+
+int16_t LR2021::scanChannel(const ChannelScanConfig_t &config) {
+ // set mode to CAD
+ int state = startChannelScan(config);
+ RADIOLIB_ASSERT(state);
+
+ // wait for channel activity detected or timeout
+ while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
+ this->mod->hal->yield();
+ }
+
+ // check CAD result
+ return(getChannelScanResult());
+}
+
+int16_t LR2021::standby() {
+ return(this->standby(RADIOLIB_LR2021_STANDBY_RC));
+}
+
+int16_t LR2021::standby(uint8_t mode) {
+ return(this->standby(mode, true));
+}
+
+int16_t LR2021::standby(uint8_t mode, bool wakeup) {
+ // set RF switch (if present)
+ this->mod->setRfSwitchState(Module::MODE_IDLE);
+
+ if(wakeup) {
+ // send a NOP command - this pulls the NSS low to exit the sleep mode,
+ // while preventing interference with possible other SPI transactions
+ (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_LR2021_CMD_NOP, NULL, 0, false, false);
+ }
+
+ uint8_t buff[] = { mode };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_STANDBY, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::sleep() {
+ return(this->sleep(true, 0));
+}
+
+int16_t LR2021::sleep(bool retainConfig, uint32_t sleepTime) {
+ // set RF switch (if present)
+ this->mod->setRfSwitchState(Module::MODE_IDLE);
+
+ uint8_t buff[] = { (uint8_t)(retainConfig ? RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED : RADIOLIB_LR2021_SLEEP_RETENTION_DISABLED),
+ (uint8_t)((sleepTime >> 24) & 0xFF), (uint8_t)((sleepTime >> 16) & 0xFF),
+ (uint8_t)((sleepTime >> 8) & 0xFF), (uint8_t)(sleepTime & 0xFF),
+ };
+
+ // in sleep, the busy line will remain high, so we have to use this method to disable waiting for it to go low
+ int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR2021_CMD_SET_SLEEP, buff, sizeof(buff), false, false);
+
+ // wait for the module to safely enter sleep mode
+ this->mod->hal->delay(1);
+
+ return(state);
+}
+
+size_t LR2021::getPacketLength(bool update) {
+ (void)update;
+
+ // in implicit mode, return the cached value
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ (void)getPacketType(&type);
+ if((type == RADIOLIB_LR2021_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT)) {
+ return(this->implicitLen);
+ }
+
+ uint16_t len = 0;
+ (void)getRxPktLength(&len);
+ return((size_t)len);
+}
+
+int16_t LR2021::finishTransmit() {
+ // clear interrupt flags
+ clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
+
+ // set mode to standby to disable transmitter/RF switch
+ return(standby());
+}
+
+int16_t LR2021::startReceive() {
+ return(this->startReceive(RADIOLIB_LR2021_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
+}
+
+int16_t LR2021::readData(uint8_t* data, size_t len) {
+ // check active modem
+ int16_t state = RADIOLIB_ERR_NONE;
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) &&
+ (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK) &&
+ (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC) &&
+ (modem != RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // check integrity CRC
+ uint32_t irq = getIrqStatus();
+ int16_t crcState = RADIOLIB_ERR_NONE;
+ // report CRC mismatch when there's a payload CRC error
+ if(irq & RADIOLIB_LR2021_IRQ_CRC_ERROR) {
+ crcState = RADIOLIB_ERR_CRC_MISMATCH;
+ }
+
+ // for LoRa modem and explicit header mode, check also also header valid flag
+ if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) &&
+ (this->headerType == RADIOLIB_LR2021_LORA_HEADER_EXPLICIT) &&
+ (!(irq & RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID))) {
+ crcState = RADIOLIB_ERR_LORA_HEADER_DAMAGED;
+ }
+
+ // get packet length
+ size_t length = getPacketLength();
+ if((len != 0) && (len < length)) {
+ // user requested less data than we got, only return what was requested
+ length = len;
+ }
+
+ // read packet data
+ state = readRadioRxFifo(data, length);
+ RADIOLIB_ASSERT(state);
+
+ // clear the Rx buffer
+ state = clearRxFifo();
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
+
+ // check if CRC failed - this is done after reading data to give user the option to keep them
+ RADIOLIB_ASSERT(crcState);
+
+ return(state);
+}
+
+int16_t LR2021::finishReceive() {
+ // set mode to standby to disable RF switch
+ int16_t state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ return(clearIrqState(RADIOLIB_LR2021_IRQ_ALL));
+}
+
+int16_t LR2021::startChannelScan() {
+ ChannelScanConfig_t cfg = {
+ .cad = {
+ .symNum = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
+ .detPeak = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
+ .detMin = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
+ .exitMode = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
+ .timeout = 0,
+ .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
+ .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
+ },
+ };
+ return(this->startChannelScan(cfg));
+}
+
+int16_t LR2021::startChannelScan(const ChannelScanConfig_t &config) {
+ // check active modem
+ int16_t state = RADIOLIB_ERR_NONE;
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set mode to standby
+ state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // set RF switch (if present)
+ this->mod->setRfSwitchState(Module::MODE_RX);
+
+ // set DIO pin mapping
+ uint32_t irqFlags = (config.cad.irqFlags == RADIOLIB_IRQ_NOT_SUPPORTED) ? RADIOLIB_LR2021_IRQ_CAD_DETECTED | RADIOLIB_LR2021_IRQ_CAD_DONE : config.cad.irqFlags;
+ state = setDioIrqConfig(this->irqDioNum, getIrqMapped(irqFlags));
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
+ RADIOLIB_ASSERT(state);
+
+ // set mode to CAD
+ return(startCad(config.cad.symNum, config.cad.detPeak, this->fastCad, config.cad.exitMode, config.cad.timeout));
+}
+
+int16_t LR2021::getChannelScanResult() {
+ // check active modem
+ int16_t state = RADIOLIB_ERR_NONE;
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // check CAD result
+ uint32_t cadResult = getIrqStatus();
+ if(cadResult & RADIOLIB_LR2021_IRQ_CAD_DETECTED) {
+ // detected some LoRa activity
+ return(RADIOLIB_LORA_DETECTED);
+ } else if(cadResult & RADIOLIB_LR2021_IRQ_CAD_DONE) {
+ // channel is free
+ return(RADIOLIB_CHANNEL_FREE);
+ }
+
+ return(RADIOLIB_ERR_UNKNOWN);
+}
+
+uint32_t LR2021::getIrqFlags() {
+ return(getIrqStatus());
+}
+
+int16_t LR2021::setIrqFlags(uint32_t irq) {
+ return(this->setDioIrqConfig(this->irqDioNum, irq));
+}
+
+int16_t LR2021::clearIrqFlags(uint32_t irq) {
+ return(this->clearIrqState(irq));
+}
+
+int16_t LR2021::setModem(ModemType_t modem) {
+ switch(modem) {
+ case(ModemType_t::RADIOLIB_MODEM_LORA): {
+ return(this->begin());
+ } break;
+ case(ModemType_t::RADIOLIB_MODEM_FSK): {
+ return(this->beginGFSK());
+ } break;
+ case(ModemType_t::RADIOLIB_MODEM_LRFHSS): {
+ return(this->beginLRFHSS());
+ } break;
+ default:
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+}
+
+Module* LR2021::getMod() {
+ return(this->mod);
+}
+
+int16_t LR2021::modSetup(float freq, float tcxoVoltage, uint8_t modem) {
+ this->mod->init();
+ this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
+ this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
+ this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32;
+ this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32;
+ this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP;
+ this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS;
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_24;
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16;
+
+ // try to find the chip - this will also reset the module at least once
+ if(!this->findChip()) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("No LR2021 found!");
+ this->mod->term();
+ return(RADIOLIB_ERR_CHIP_NOT_FOUND);
+ }
+ RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR2021");
+
+ // set mode to standby
+ int16_t state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // set TCXO control, if requested
+ if(!this->XTAL && tcxoVoltage > 0.0f) {
+ state = setTCXO(tcxoVoltage);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // configure settings not accessible by API
+ state = config(modem);
+ RADIOLIB_ASSERT(state);
+
+ state = setFrequency(freq);
+ return(state);
+}
+
+bool LR2021::findChip(void) {
+ // this is the only version mentioned in datasheet
+ const uint8_t expMajor = 0x01;
+ const uint8_t expMinor = 0x18;
+
+ uint8_t i = 0;
+ bool flagFound = false;
+ uint8_t fwMajor = 0, fwMinor = 0;
+ while((i < 10) && !flagFound) {
+ // reset the module
+ reset();
+
+ // read the version
+ int16_t state = getVersion(&fwMajor, &fwMinor);
+ RADIOLIB_ASSERT(state);
+
+ if((fwMajor == expMajor) && (fwMinor == expMinor)) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR2021");
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)fwMajor, (int)fwMinor);
+ flagFound = true;
+ } else {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("LR2021 not found! (%d of 10 tries) FW version: = %d.%d", (int)fwMajor, (int)fwMinor);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Expected: %d.%d", (int)expMajor, (int)expMinor);
+ this->mod->hal->delay(10);
+ i++;
+ }
+ }
+
+ return(flagFound);
+}
+
+int16_t LR2021::config(uint8_t modem) {
+ // set Rx/Tx fallback mode to STDBY_RC
+ int16_t state = this->setRxTxFallbackMode(RADIOLIB_LR2021_FALLBACK_MODE_STBY_RC);
+ RADIOLIB_ASSERT(state);
+
+ // clear IRQ
+ state = this->clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
+ RADIOLIB_ASSERT(state);
+
+ // Regulator / ramp resolution (datasheet SetRegMode); avoids relying on reset defaults.
+ const uint8_t rampTimes[4] = { 0x00, 0x00, 0x00, 0x00 };
+ state = this->setRegMode((uint8_t)(RADIOLIB_LR2021_REG_MODE_SIMO_NORMAL | RADIOLIB_LR2021_REG_MODE_RAMP_RES_4_US), rampTimes);
+ RADIOLIB_ASSERT(state);
+
+ // validate DIO pin number
+ if((this->irqDioNum < 5) || (this->irqDioNum > 11)) {
+ return(RADIOLIB_ERR_INVALID_DIO_PIN);
+ }
+
+ // set the DIO to IRQ
+ // DIO5 can only be pull up
+ uint8_t pull = this->irqDioNum == 5 ? RADIOLIB_LR2021_DIO_SLEEP_PULL_UP : RADIOLIB_LR2021_DIO_SLEEP_PULL_NONE;
+ state = this->setDioFunction(this->irqDioNum, RADIOLIB_LR2021_DIO_FUNCTION_IRQ, pull);
+ RADIOLIB_ASSERT(state);
+
+ // calibrate all blocks
+ state = this->calibrate(RADIOLIB_LR2021_CALIBRATE_ALL);
+
+ // wait for calibration completion
+ this->mod->hal->delay(5);
+ while(this->mod->hal->digitalRead(this->mod->getGpio())) {
+ this->mod->hal->yield();
+ }
+
+ // if something failed, show the device errors
+ #if RADIOLIB_DEBUG_BASIC
+ if(state != RADIOLIB_ERR_NONE) {
+ uint16_t errors = 0;
+ getErrors(&errors);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
+ }
+ #else
+ RADIOLIB_ASSERT(state);
+ #endif
+
+ // set modem
+ state = this->setPacketType(modem);
+ return(state);
+}
+
+int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, bool fast, uint8_t exitMode, RadioLibTime_t timeout) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // select CAD parameters
+ uint8_t num = symbolNum;
+ if(num == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) {
+ num = 2;
+ }
+
+ // reference values from the datasheet for 2 symbols
+ //! \TODO: [LR2021] allow CAD peak detection autoconfiguration
+ const uint8_t detPeakValues[8] = { 56, 56, 56, 58, 58, 60, 64, 68 };
+ uint8_t peak = detPeak;
+ if(peak == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) {
+ peak = detPeakValues[this->spreadingFactor - 5];
+ }
+
+ // in Fast CAD mode enable acceleration
+ uint8_t pnrDelta = fast ? RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_FAST : RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_STANDARD;
+
+ uint8_t mode = exitMode;
+ if(mode == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) {
+ mode = RADIOLIB_LR2021_CAD_EXIT_MODE_FALLBACK;
+ }
+
+ uint32_t timeout_raw = (float)timeout / 30.52f;
+
+ // set LoRa CAD parameters
+ // preamble only mode is intentionally disabled, as it is unreliable according to the datasheet
+ state = setLoRaCadParams(num, false, pnrDelta, mode, timeout_raw, peak);
+ RADIOLIB_ASSERT(state);
+
+ // start LoraCAD
+ return(setLoRaCad());
+}
+
+RadioLibTime_t LR2021::getTimeOnAir(size_t len) {
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+
+ switch(type) {
+ // basic modems are supported by the LRxxxx base class
+ case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
+ return(LRxxxx::getTimeOnAir(len, ModemType_t::RADIOLIB_MODEM_LORA));
+ case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
+ return(LRxxxx::getTimeOnAir(len, ModemType_t::RADIOLIB_MODEM_FSK));
+ case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
+ return(LRxxxx::getTimeOnAir(len, ModemType_t::RADIOLIB_MODEM_LRFHSS));
+ case(RADIOLIB_LR2021_PACKET_TYPE_FLRC): {
+ //! \todo [LR2021] Add FLRC to the modems supported in ModemType_t
+
+ // calculate the bits of the uncoded part of the packet
+ size_t n_uncoded_bits = (this->preambleLengthGFSK + 1)*4 + 21 + this->syncWordLength*8;
+ if(this->packetType != RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) { n_uncoded_bits+= 16; }
+
+ // calculate bits in the coded part
+ size_t n_coded_bits = len*8;
+ if(this->crcLenGFSK != 0) { n_coded_bits += (this->crcLenGFSK + 1)*8; }
+ if(this->codingRateFlrc <= RADIOLIB_LR2021_FLRC_CR_3_4) { n_coded_bits += 6; }
+ float n_coded_bits_flt = n_coded_bits;
+ switch(this->codingRateFlrc) {
+ case(RADIOLIB_LR2021_FLRC_CR_1_2):
+ n_coded_bits += 6;
+ n_coded_bits_flt = (float)n_coded_bits*2.0f;
+ break;
+ case(RADIOLIB_LR2021_FLRC_CR_3_4):
+ n_coded_bits += 6;
+ n_coded_bits_flt = ((float)n_coded_bits*4.0f)/3.0f;
+ break;
+ case(RADIOLIB_LR2021_FLRC_CR_2_3):
+ n_coded_bits_flt = ((float)n_coded_bits*3.0f)/2.0f;
+ break;
+ }
+ n_coded_bits = n_coded_bits_flt + 0.5f;
+
+ // now calculate the real time on air
+ return((float)(n_uncoded_bits + n_coded_bits) / (float)(this->bitRate / 1000.0f));
+ }
+ }
+
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Called getTimeOnAir() for invalid modem (%02x)!", type);
+ return(0);
+}
+
+int16_t LR2021::getModem(ModemType_t* modem) {
+ RADIOLIB_ASSERT_PTR(modem);
+
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+
+ switch(type) {
+ case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
+ *modem = ModemType_t::RADIOLIB_MODEM_LORA;
+ return(RADIOLIB_ERR_NONE);
+ case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
+ *modem = ModemType_t::RADIOLIB_MODEM_FSK;
+ return(RADIOLIB_ERR_NONE);
+ case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
+ *modem = ModemType_t::RADIOLIB_MODEM_LRFHSS;
+ return(RADIOLIB_ERR_NONE);
+ }
+
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
+ int16_t state;
+
+ switch(mode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ // check active modem
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) &&
+ (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK) &&
+ (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC) &&
+ (modem != RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set the correct Rx path
+ state = setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? this->gainModeHf : this->gainModeLf);
+ RADIOLIB_ASSERT(state);
+
+ // set DIO mapping
+ if(cfg->receive.timeout != RADIOLIB_LR2021_RX_TIMEOUT_INF) {
+ cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
+ }
+ state = setDioIrqConfig(this->irqDioNum, getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
+ RADIOLIB_ASSERT(state);
+
+ // set implicit mode and expected len if applicable
+ if((this->headerType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR2021_PACKET_TYPE_LORA)) {
+ state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // if max(uint32_t) is used, revert to RxContinuous
+ if(cfg->receive.timeout == 0xFFFFFFFF) {
+ cfg->receive.timeout = 0xFFFFFF;
+ }
+ this->rxTimeout = cfg->receive.timeout;
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ // check packet length
+ if(cfg->transmit.len > RADIOLIB_LR2021_MAX_PACKET_LENGTH) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+
+ // maximum packet length is decreased by 1 when address filtering is active
+ //! \todo [LR2021] implement GFSK address filtering
+
+ // set packet Length
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled);
+
+ } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
+
+ } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
+ state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
+
+ } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
+ state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, cfg->transmit.len);
+
+ } else {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ RADIOLIB_ASSERT(state);
+
+ // set DIO mapping
+ state = setDioIrqConfig(this->irqDioNum, RADIOLIB_LR2021_IRQ_TX_DONE | RADIOLIB_LR2021_IRQ_TIMEOUT);
+ RADIOLIB_ASSERT(state);
+
+ if(modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
+ // in LR-FHSS mode, the packet is built by the device
+ //! \todo [LR2021] add configurable LR-FHSS device offset
+ state = LRxxxx::lrFhssBuildFrame(RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME, this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len);
+ RADIOLIB_ASSERT(state);
+
+ } else {
+ // write packet to buffer
+ state = writeRadioTxFifo(cfg->transmit.data, cfg->transmit.len);
+ RADIOLIB_ASSERT(state);
+
+ }
+
+ // clear interrupt flags
+ state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
+ RADIOLIB_ASSERT(state);
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = mode;
+ return(state);
+}
+
+int16_t LR2021::launchMode() {
+ int16_t state;
+ switch(this->stagedMode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ this->mod->setRfSwitchState(Module::MODE_RX);
+ state = setRx(this->rxTimeout);
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ this->mod->setRfSwitchState(Module::MODE_TX);
+ state = setTx(RADIOLIB_LR2021_TX_TIMEOUT_NONE);
+ RADIOLIB_ASSERT(state);
+
+ // wait for BUSY to go low (= PA ramp up done)
+ while(this->mod->hal->digitalRead(this->mod->getGpio())) {
+ this->mod->hal->yield();
+ }
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
+ return(state);
+}
+
+float LR2021::getVoltage(uint8_t bits) {
+ if((bits < 8) || (bits > 13)) {
+ return(0);
+ }
+
+ uint16_t val;
+ if(getVbat(bits, &val) != RADIOLIB_ERR_NONE) {
+ return(0);
+ }
+
+ return((float)val / 1000.0f);
+}
+
+float LR2021::getTemperature(uint8_t source, uint8_t bits) {
+ if((bits < 8) || (bits > 13)) {
+ return(0);
+ }
+
+ float val;
+ if(getTemp(source, bits, &val) != RADIOLIB_ERR_NONE) {
+ return(0);
+ }
+
+ return(val);
+}
+
+float LR2021::getRSSI() {
+ return(this->getRSSI(true));
+}
+
+float LR2021::getRSSI(bool packet, bool skipReceive) {
+ float rssi = 0;
+ int16_t state;
+ if(!packet) {
+ // get instantaneous RSSI value
+ if(!skipReceive) { (void)startReceive(); }
+ state = this->getRssiInst(&rssi);
+ if(!skipReceive) { (void)standby(); }
+ if(state != RADIOLIB_ERR_NONE) { return(0); }
+ return(rssi);
+ }
+
+ // check modem type
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ state = this->getPacketType(&modem);
+ if(state != RADIOLIB_ERR_NONE) { return(0); }
+ if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ state = this->getLoRaPacketStatus(NULL, NULL, NULL, NULL, &rssi, NULL);
+ } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ state = this->getGfskPacketStatus(NULL, &rssi, NULL, NULL, NULL, NULL);
+ } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
+ state = this->getOokPacketStatus(NULL, NULL, &rssi, NULL, NULL, NULL);
+ } else {
+ return(0);
+ }
+
+ if(state != RADIOLIB_ERR_NONE) { return(0); }
+ return(rssi);
+}
+
+float LR2021::getSNR() {
+ float snr;
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = this->getPacketType(&modem);
+ if(state != RADIOLIB_ERR_NONE) { return(0); }
+ if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) { return(0); }
+ state = this->getLoRaPacketStatus(NULL, NULL, NULL, &snr, NULL, NULL);
+ if(state != RADIOLIB_ERR_NONE) { return(0); }
+ return(snr);
+}
+
+uint8_t LR2021::randomByte() {
+ uint32_t num = 0;
+ (void)getRandomNumber(&num);
+ return((uint8_t)num);
+}
+
+int16_t LR2021::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC){
+ return(this->getLoRaPacketStatus(cr, hasCRC, NULL, NULL, NULL, NULL));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021.h b/lib/RadioLib/src/modules/LR2021/LR2021.h
new file mode 100644
index 0000000..b1e8008
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021.h
@@ -0,0 +1,878 @@
+#if !defined(RADIOLIB_LR2021_H)
+#define RADIOLIB_LR2021_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+#include "../../Module.h"
+
+#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
+#include "../LR11x0/LR_common.h"
+#include "LR2021_commands.h"
+#include "LR2021_types.h"
+
+// LR2021 physical layer properties
+#define RADIOLIB_LR2021_FREQUENCY_STEP_SIZE 1.0
+#define RADIOLIB_LR2021_MAX_PACKET_LENGTH 255
+#define RADIOLIB_LR2021_CRYSTAL_FREQ 32.0
+#define RADIOLIB_LR2021_DIV_EXPONENT 25
+
+/*!
+ \class LR2021
+ \brief
+*/
+class LR2021: public LRxxxx {
+ public:
+ // introduce PhysicalLayer overloads
+ using PhysicalLayer::transmit;
+ using PhysicalLayer::receive;
+ using PhysicalLayer::startTransmit;
+ using PhysicalLayer::startReceive;
+ using PhysicalLayer::readData;
+
+ /*!
+ \brief Default constructor.
+ \param mod Instance of Module that will be used to communicate with the radio.
+ */
+ LR2021(Module* mod); // cppcheck-suppress noExplicitConstructor
+
+ /*!
+ \brief Which DIO pin is to be used as the interrupt pin.
+ */
+ uint32_t irqDioNum = 5;
+
+ /*!
+ \brief Determines the type of Lora CAD to perform, either "standard" CAD
+ (same as is implem,ented LR11x0, SX126x and others), or a "fast" CAD if set to true.
+ If there is no signal to be detected, fast CAD should return faster than standard CAD.
+ */
+ bool fastCad = false;
+
+ /*!
+ \brief Custom operation modes for LR2021.
+ Needed because LR2021 has several modems (sub-GHz, 2.4 GHz etc.) in one package
+ */
+ enum OpMode_t {
+ /*! End of table marker, use \ref END_OF_MODE_TABLE constant instead */
+ MODE_END_OF_TABLE = Module::MODE_END_OF_TABLE,
+ /*! Standby/idle mode */
+ MODE_STBY = Module::MODE_IDLE,
+ /*! Receive mode */
+ MODE_RX = Module::MODE_RX,
+ /*! Transmission mode */
+ MODE_TX = Module::MODE_TX,
+ /*! High frequency receive mode */
+ MODE_RX_HF,
+ /*! High frequency transmission mode */
+ MODE_TX_HF,
+ };
+
+ // basic methods
+
+ /*!
+ \brief Initialization method for LoRa modem.
+ \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+ \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz.
+ \param sf LoRa spreading factor. Defaults to 9.
+ \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
+ \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE (0x12).
+ \param power Output power in dBm. Defaults to 10 dBm.
+ \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols.
+ \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
+ If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
+ To use XTAL, either set this value to 0, or set LR2021::XTAL to true.
+ \returns \ref status_codes
+ */
+ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6);
+
+ /*!
+ \brief Initialization method for FSK modem.
+ \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+ \param br FSK bit rate in kbps. Defaults to 4.8 kbps.
+ \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz.
+ \param rxBw Receiver bandwidth in kHz. Defaults to 153.8 kHz.
+ \param power Output power in dBm. Defaults to 10 dBm.
+ \param preambleLength FSK preamble length in bits. Defaults to 16 bits.
+ \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
+ If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
+ To use XTAL, either set this value to 0, or set LR2021::XTAL to true.
+ \returns \ref status_codes
+ */
+ int16_t beginGFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 153.8, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6);
+
+ /*!
+ \brief Initialization method for OOK modem.
+ \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+ \param br OOK bit rate in kbps. Defaults to 4.8 kbps.
+ \param rxBw Receiver bandwidth in kHz. Defaults to 153.8 kHz.
+ \param power Output power in dBm. Defaults to 10 dBm.
+ \param preambleLength OOK preamble length in bits. Defaults to 16 bits.
+ \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
+ If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
+ To use XTAL, either set this value to 0, or set LR2021::XTAL to true.
+ \returns \ref status_codes
+ */
+ int16_t beginOOK(float freq = 434.0, float br = 4.8, float rxBw = 153.8, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6);
+
+ /*!
+ \brief Initialization method for LR-FHSS modem.
+ \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+ \param bw LR-FHSS bandwidth, one of RADIOLIB_LRXXXX_LR_FHSS_BW_* values. Defaults to 722.66 kHz.
+ \param cr LR-FHSS coding rate, one of RADIOLIB_LRXXXX_LR_FHSS_CR_* values. Defaults to 2/3 coding rate.
+ \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid.
+ \param power Output power in dBm. Defaults to 10 dBm.
+ \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
+ If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
+ To use XTAL, either set this value to 0, or set LR2021::XTAL to true.
+ \returns \ref status_codes
+ */
+ int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LRXXXX_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LRXXXX_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6);
+
+ /*!
+ \brief Initialization method for FLRC modem.
+ \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+ \param br FLRC bit rate in kbps. Defaults to 650 kbps.
+ \param cr FLRC coding rate. Defaults to RADIOLIB_LR2021_FLRC_CR_2_3 (coding rate 2/3).
+ \param pwr Output power in dBm. Defaults to 10 dBm.
+ \param preambleLength FLRC preamble length in bits. Defaults to 16 bits.
+ \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5.
+ \returns \ref status_codes
+ */
+ int16_t beginFLRC(float freq = 434.0, uint16_t br = 650, uint8_t cr = RADIOLIB_LR2021_FLRC_CR_2_3, int8_t pwr = 10, uint16_t preambleLength = 16, uint8_t dataShaping = RADIOLIB_SHAPING_0_5, float tcxoVoltage = 1.6);
+
+ /*!
+ \brief Blocking binary transmit method.
+ Overloads for string-based transmissions are implemented in PhysicalLayer.
+ \param data Binary data to be sent.
+ \param len Number of bytes to send.
+ \param addr Address to send the data to. Will only be added if address filtering was enabled.
+ \returns \ref status_codes
+ */
+ int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0) override;
+
+ /*!
+ \brief Blocking binary receive method.
+ Overloads for string-based transmissions are implemented in PhysicalLayer.
+ \param data Pointer to array to save the received binary data.
+ \param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+ \param timeout Reception timeout in milliseconds. If set to 0,
+ timeout period will be calculated automatically based on the radio configuration.
+ \returns \ref status_codes
+ */
+ int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override;
+
+ /*!
+ \brief Starts direct mode transmission.
+ \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY.
+ \returns \ref status_codes
+ */
+ int16_t transmitDirect(uint32_t frf = 0) override;
+
+ /*!
+ \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as LR2021 does not support direct mode reception.
+ Will always return RADIOLIB_ERR_UNKNOWN.
+ \returns \ref status_codes
+ */
+ int16_t receiveDirect() override;
+
+ /*!
+ \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload.
+ \returns \ref status_codes
+ */
+ int16_t scanChannel() override;
+
+ /*!
+ \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload.
+ \param config CAD configuration structure.
+ \returns \ref status_codes
+ */
+ int16_t scanChannel(const ChannelScanConfig_t &config) override;
+
+ /*!
+ \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator).
+ \returns \ref status_codes
+ */
+ int16_t standby() override;
+
+ /*!
+ \brief Sets the module to standby mode.
+ \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR2021_STANDBY_RC (13 MHz RC oscillator)
+ or RADIOLIB_LR2021_STANDBY_XOSC (32 MHz external crystal oscillator).
+ \returns \ref status_codes
+ */
+ int16_t standby(uint8_t mode) override;
+
+ /*!
+ \brief Sets the module to standby mode.
+ \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR2021_STANDBY_RC (13 MHz RC oscillator)
+ or RADIOLIB_LR2021_STANDBY_XOSC (32 MHz external crystal oscillator).
+ \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module.
+ \returns \ref status_codes
+ */
+ int16_t standby(uint8_t mode, bool wakeup);
+
+ /*!
+ \brief Sets the module to sleep mode. To wake the device up, call standby().
+ Overload with warm start enabled for PhysicalLayer compatibility.
+ \returns \ref status_codes
+ */
+ int16_t sleep() override;
+
+ /*!
+ \brief Sets the module to sleep mode. To wake the device up, call standby().
+ \param retainConfig Set to true to retain configuration of the currently active modem ("warm start")
+ or to false to discard current configuration ("cold start"). Defaults to true.
+ \param sleepTime Sleep duration (enables automatic wakeup), in multiples of 30.52 us. Ignored if set to 0.
+ \returns \ref status_codes
+ */
+ int16_t sleep(bool retainConfig, uint32_t sleepTime);
+
+ /*!
+ \brief Query modem for the packet length of received payload.
+ \param update Update received packet length. Will return cached value when set to false.
+ \returns Length of last received packet in bytes.
+ */
+ size_t getPacketLength(bool update = true) override;
+
+ // interrupt methods
+
+ /*!
+ \brief Clean up after transmission is done.
+ \returns \ref status_codes
+ */
+ int16_t finishTransmit() override;
+
+ /*!
+ \brief Interrupt-driven receive method with default parameters.
+ Implemented for compatibility with PhysicalLayer.
+
+ \returns \ref status_codes
+ */
+ int16_t startReceive() override;
+
+ /*!
+ \brief Reads data received after calling startReceive method. When the packet length is not known in advance,
+ getPacketLength method must be called BEFORE calling readData!
+ \param data Pointer to array to save the received binary data.
+ \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically.
+ When more bytes than received are requested, only the number of bytes requested will be returned.
+ \returns \ref status_codes
+ */
+ int16_t readData(uint8_t* data, size_t len) override;
+
+ /*!
+ \brief Clean up after reception is done.
+ \returns \ref status_codes
+ */
+ int16_t finishReceive() override;
+
+ /*!
+ \brief Interrupt-driven channel activity detection method. IRQ1 will be activated
+ when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48.
+ \returns \ref status_codes
+ */
+ int16_t startChannelScan() override;
+
+ /*!
+ \brief Interrupt-driven channel activity detection method. IRQ pin will be activated
+ when LoRa preamble is detected, or upon timeout.
+ \param config CAD configuration structure.
+ \returns \ref status_codes
+ */
+ int16_t startChannelScan(const ChannelScanConfig_t &config) override;
+
+ /*!
+ \brief Read the channel scan result
+ \returns \ref status_codes
+ */
+ int16_t getChannelScanResult() override;
+
+ /*!
+ \brief Read currently active IRQ flags.
+ \returns IRQ flags.
+ */
+ uint32_t getIrqFlags() override;
+
+ /*!
+ \brief Set interrupt on DIO1 to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone).
+ \param irq Module-specific IRQ flags.
+ \returns \ref status_codes
+ */
+ int16_t setIrqFlags(uint32_t irq) override;
+
+ /*!
+ \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone).
+ \param irq Module-specific IRQ flags.
+ \returns \ref status_codes
+ */
+ int16_t clearIrqFlags(uint32_t irq) override;
+
+ /*!
+ \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio
+ using its default parameters.
+ \param modem Modem type to set - FSK, LoRa or LR-FHSS.
+ \returns \ref status_codes
+ */
+ int16_t setModem(ModemType_t modem) override;
+
+ // configuration methods
+
+ /*!
+ \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz,
+ 1900 - 2200 MHz and 2400 - 2500 MHz.
+ Will automatically perform image calibration if the frequency changes by
+ more than RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG MHz.
+ NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency,
+ setOutputPower() must be called in order to set the correct power amplifier!
+ \param freq Carrier frequency to be set in MHz.
+ \returns \ref status_codes
+ */
+ int16_t setFrequency(float freq) override;
+
+ /*!
+ \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz,
+ 1900 - 2200 MHz and 2400 - 2500 MHz.
+ Will automatically perform image calibration if the frequency changes by
+ more than RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG MHz.
+ NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency,
+ setOutputPower() must be called in order to set the correct power amplifier!
+ \param freq Carrier frequency to be set in MHz.
+ \param skipCalibration Skip automated image calibration.
+ \returns \ref status_codes
+ */
+ int16_t setFrequency(float freq, bool skipCalibration);
+
+ /*!
+ \brief Sets output power. Allowed values are in range from -9 to 22 dBm (sub-GHz PA) or -19 to 12 dBm (high-frequency PA).
+ \param power Output power to be set in dBm.
+ \returns \ref status_codes
+ */
+ int16_t setOutputPower(int8_t power) override;
+
+ /*!
+ \brief Sets output power. Allowed values are in range from -9 to 22 dBm (sub-GHz PA) or -19 to 12 dBm (high-frequency PA).
+ \param power Output power to be set in dBm.
+ \param rampTimeUs PA power ramping time in microseconds. Provided value is rounded up to the
+ nearest discrete ramp time supported by the PA.
+ \returns \ref status_codes
+ */
+ int16_t setOutputPower(int8_t power, uint32_t rampTimeUs);
+
+ /*!
+ \brief Check if output power is configurable.
+ This method is needed for compatibility with PhysicalLayer::checkOutputPower.
+ \param power Output power in dBm, PA will be determined automatically.
+ \param clipped Clipped output power value to what is possible within the module's range.
+ \returns \ref status_codes
+ */
+ int16_t checkOutputPower(int8_t power, int8_t* clipped) override;
+
+ /*! \copydoc Module::setRfSwitchTable */
+ void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]);
+
+ /*!
+ \brief Sets LoRa bandwidth. Allowed values are 31.25, 41.67, 62.5, 83.34, 125.0,
+ 101.56, 203.13, 250.0, 406.25, 500.0 kHz, 812.5 kHz and 1000.0 kHz.
+ \param bw LoRa bandwidth to be set in kHz.
+ \returns \ref status_codes
+ */
+ int16_t setBandwidth(float bw);
+
+ /*!
+ \brief Sets LoRa spreading factor. Allowed values range from 5 to 12.
+ \param sf LoRa spreading factor to be set.
+ \param legacy Enable legacy mode for SF6 - this allows to communicate with SX127x at SF6.
+ \returns \ref status_codes
+ */
+ int16_t setSpreadingFactor(uint8_t sf, bool legacy = false);
+
+ /*!
+ \brief Sets LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
+ \param cr LoRa coding rate denominator to be set.
+ \param longInterleave Enable long interleaver when set to true.
+ Note that with long interleaver enabled, CR 4/7 is not possible, there are packet length restrictions,
+ and it is not compatible with SX127x radios!
+ \returns \ref status_codes
+ */
+ int16_t setCodingRate(uint8_t cr, bool longInterleave = false);
+
+ /*!
+ \brief Sets LoRa sync word.
+ \param syncWord LoRa sync word to be set.
+ \returns \ref status_codes
+ */
+ int16_t setSyncWord(uint8_t syncWord);
+
+ /*!
+ \brief Sets preamble length for LoRa or GFSK modem. Allowed values range from 1 to 65535.
+ \param preambleLength Preamble length to be set in symbols (LoRa) or bits (GFSK).
+ \returns \ref status_codes
+ */
+ int16_t setPreambleLength(size_t preambleLength) override;
+
+ /*!
+ \brief Sets TCXO (Temperature Compensated Crystal Oscillator) configuration.
+ \param voltage TCXO reference voltage in volts. Allowed values are 1.6, 1.7, 1.8, 2.2. 2.4, 2.7, 3.0 and 3.3 V.
+ Set to 0 to disable TCXO.
+ NOTE: After setting this parameter to 0, the module will be reset (since there's no other way to disable TCXO).
+ \param delay TCXO timeout in us. Defaults to 1000000 (1 second), because especially on the first startup,
+ this delay may be measured very inaccurately.
+ \returns \ref status_codes
+ */
+ int16_t setTCXO(float voltage, uint32_t delay = 1000000);
+
+ /*!
+ \brief Sets CRC configuration.
+ \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC.
+ \param initial Initial CRC value. GFSK only. Defaults to 0x1D0F (CCITT CRC).
+ \param polynomial Polynomial for CRC calculation. GFSK only. Defaults to 0x1021 (CCITT CRC).
+ \param inverted Invert CRC bytes. GFSK only. Defaults to true (CCITT CRC).
+ \returns \ref status_codes
+ */
+ int16_t setCRC(uint8_t len, uint32_t initial = 0x00001D0FUL, uint32_t polynomial = 0x00001021UL, bool inverted = true);
+
+ /*!
+ \brief Enable/disable inversion of the I and Q signals
+ \param enable IQ inversion enabled (true) or disabled (false);
+ \returns \ref status_codes
+ */
+ int16_t invertIQ(bool enable) override;
+
+ /*!
+ \brief Sets GFSK bit rate. Allowed values range from 0.5 to 2000.0 kbps.
+ \param br FSK bit rate to be set in kbps.
+ \returns \ref status_codes
+ */
+ int16_t setBitRate(float br) override;
+
+ /*!
+ \brief Sets GFSK frequency deviation. Allowed values range from 0.6 to 500.0 kHz.
+ \param freqDev GFSK frequency deviation to be set in kHz.
+ \returns \ref status_codes
+ */
+ int16_t setFrequencyDeviation(float freqDev) override;
+
+ /*!
+ \brief Sets GFSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5,
+ 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz.
+ \param rxBw GFSK receiver bandwidth to be set in kHz.
+ \returns \ref status_codes
+ */
+ int16_t setRxBandwidth(float rxBw);
+
+ /*!
+ \brief Sets GFSK sync word in the form of array of up to 8 bytes.
+ \param syncWord GFSK sync word to be set.
+ \param len GFSK sync word length in bytes.
+ \returns \ref status_codes
+ */
+ int16_t setSyncWord(uint8_t* syncWord, size_t len) override;
+
+ /*!
+ \brief Sets node address. Calling this method will also enable address filtering for node address only.
+ \param nodeAddr Node address to be set.
+ \returns \ref status_codes
+ */
+ int16_t setNodeAddress(uint8_t nodeAddr);
+
+ /*!
+ \brief Sets broadcast address. Calling this method will also enable address
+ filtering for node and broadcast address.
+ \param broadAddr Node address to be set.
+ \returns \ref status_codes
+ */
+ int16_t setBroadcastAddress(uint8_t broadAddr);
+
+ /*!
+ \brief Disables address filtering. Calling this method will also erase previously set addresses.
+ \returns \ref status_codes
+ */
+ int16_t disableAddressFiltering();
+
+ /*!
+ \brief Sets time-bandwidth product of Gaussian filter applied for shaping.
+ Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5, RADIOLIB_SHAPING_0_7 or RADIOLIB_SHAPING_1_0.
+ Set to RADIOLIB_SHAPING_NONE to disable data shaping.
+ \param sh Time-bandwidth product of Gaussian filter to be set.
+ \returns \ref status_codes
+ */
+ int16_t setDataShaping(uint8_t sh) override;
+
+ /*!
+ \brief Sets transmission encoding. Available in GFSK mode only. Serves only as alias for PhysicalLayer compatibility.
+ \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening.
+ \returns \ref status_codes
+ */
+ int16_t setEncoding(uint8_t encoding) override;
+
+ /*!
+ \brief Set modem in fixed packet length mode. Available in GFSK mode only.
+ \param len Packet length.
+ \returns \ref status_codes
+ */
+ int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_LR2021_MAX_PACKET_LENGTH);
+
+ /*!
+ \brief Set modem in variable packet length mode. Available in GFSK mode only.
+ \param maxLen Maximum packet length.
+ \returns \ref status_codes
+ */
+ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH);
+
+ /*!
+ \brief Sets GFSK whitening parameters.
+ \param enabled True = Whitening enabled
+ \param initial Initial value used for the whitening LFSR in GFSK mode.
+ By default set to 0x01FF for compatibility with SX127x and LoRaWAN.
+ \returns \ref status_codes
+ */
+ int16_t setWhitening(bool enabled, uint16_t initial = 0x01FF);
+
+ /*!
+ \brief Set data rate.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS).
+ Defaults to currently active modem if not supplied.
+ \returns \ref status_codes
+ */
+ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
+
+ /*!
+ \brief Check the data rate can be configured by this module.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS).
+ Defaults to currently active modem if not supplied.
+ \returns \ref status_codes
+ */
+ int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
+
+ /*!
+ \brief Sets LR-FHSS configuration.
+ \param bw LR-FHSS bandwidth, one of RADIOLIB_LRXXXX_LR_FHSS_BW_* values.
+ \param cr LR-FHSS coding rate, one of RADIOLIB_LRXXXX_LR_FHSS_CR_* values.
+ \param hdrCount Header packet count, 1 - 4. Defaults to 3.
+ \param hopSeed 9-bit seed number for PRNG generation of the hopping sequence. Defaults to 0x13A.
+ \returns \ref status_codes
+ */
+ int16_t setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount = 3, uint16_t hopSeed = 0x13A);
+
+ /*!
+ \brief Enables or disables Rx Boosted Gain mode (additional Rx gain for increased power consumption).
+ \param level Rx gain boost level. 0 (disabled) to 7 (maximum boost).
+ \returns \ref status_codes
+ */
+ int16_t setRxBoostedGainMode(uint8_t level);
+
+ /*!
+ \brief Get expected time-on-air for a given size of payload
+ \param len Payload length in bytes.
+ \returns Expected time-on-air in microseconds.
+ */
+ RadioLibTime_t getTimeOnAir(size_t len) override;
+
+ /*!
+ \brief Get modem currently in use by the radio.
+ \param modem Pointer to a variable to save the retrieved configuration into.
+ \returns \ref status_codes
+ */
+ int16_t getModem(ModemType_t* modem) override;
+
+ /*! \copydoc PhysicalLayer::stageMode */
+ int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override;
+
+ /*! \copydoc PhysicalLayer::launchMode */
+ int16_t launchMode() override;
+
+ /*!
+ \brief Read the supply voltage on the Vbat pin.
+ \param bits Measurement resolution in bits, 8 to 13.
+ \returns \ref Supply voltage in volts.
+ */
+ float getVoltage(uint8_t bits = 13);
+
+ /*!
+ \brief Read the temperature.
+ \param source Measurement source, one of RADIOLIB_LR2021_TEMP_SOURCE_* macros.
+ \param bits Measurement resolution in bits, 8 to 13.
+ \returns \ref Temperature in degrees Celsius.
+ */
+ float getTemperature(uint8_t source, uint8_t bits = 13);
+
+ /*!
+ \brief Gets received signal strength indicator.
+ Overload with packet mode enabled for PhysicalLayer compatibility.
+ \returns RSSI value in dBm.
+ */
+ float getRSSI() override;
+
+ /*!
+ \brief Gets RSSI (Received Signal Strength Indicator).
+ \param packet Whether to read last packet RSSI, or the current value.
+ NOTE: With OOK modem, the "packet" RSSI value is the received power level of the high bits (digital 1).
+ \param skipReceive Set to true to skip putting radio in receive mode for instantaneous RSSI measurement.
+ If false, after the RSSI measurement, the radio will be in standby mode.
+ \returns RSSI value in dBm.
+ */
+ float getRSSI(bool packet, bool skipReceive = false);
+
+ /*!
+ \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem.
+ \returns SNR of the last received packet in dB.
+ */
+ float getSNR() override;
+
+ /*!
+ \brief Get one truly random byte from RSSI noise.
+ \returns TRNG byte.
+ */
+ uint8_t randomByte() override;
+
+ /*!
+ \brief Set implicit header mode for future reception/transmission.
+ \param len Payload length in bytes.
+ \returns \ref status_codes
+ */
+ int16_t implicitHeader(size_t len);
+
+ /*!
+ \brief Set explicit header mode for future reception/transmission.
+ \returns \ref status_codes
+ */
+ int16_t explicitHeader();
+
+ /*!
+ \brief Set OOK detector properties. The default values are set to allow ADS-B reception.
+ \param pattern Preamble pattern, should end with 01 or 10 (binary).
+ \param len Preamble pattern length in bits.
+ \param repeats Number of preamble repeats, maximum of 31.
+ \param syncRaw Whether the sync word is send raw (unencoded) or encoded. Set to false for encoded sync word.
+ \param rising Whether the start of frame delimiter edge is rising (true) or falling (false).
+ \param sofLen Start-of-frame length in bits.
+ \returns \ref status_codes
+ */
+ int16_t ookDetector(uint16_t pattern = 0x0285, uint8_t len = 16, uint8_t repeats = 0, bool syncRaw = false, bool rising = false, uint8_t sofLen = 0);
+
+ /*!
+ \brief Set OOK detection threshold.
+ \param level Threshold level in dB
+ \returns \ref status_codes
+ */
+ int16_t setOokDetectionThreshold(int16_t level);
+
+ /*!
+ \brief Configure LoRa side detector, which enables to detect mutiple spreading factors and receive one of them.
+ The following limitations apply:
+ * In Rx mode, all side-detector spreading factors must be higher than the primary one (configured via begin or setSpreadingFactor)
+ * For CAD mode, the above condition is inverted - all side-detector spreading factors must be smaller
+ * All packets to be detected must have the same header type (implicit or explicit)
+ * If bandwidth is higher than 500 kHz, at most 2 side detectors are allowed.
+ * If the primary spreading factor is 10, 11 or 12, at most 2 side detectors are allowed.
+ * All spreading factors must be different.
+ * The difference between maximum and minimum spreading factor used must be less than or equal to 4.
+ \param cfg Pointer to an array of side detector configuration structures. Set to null to disable all side detectors.
+ \param numDetectors Number of side detectors to configure. Maximum of 3, set to 0 to to disable all side detectors.
+ \returns \ref status_codes
+ */
+ int16_t setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numDetectors);
+
+ /*!
+ \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 13,
+ where 13 is the highest gain. Set to 0 to enable automatic gain control (recommended).
+ \param gain Gain of receiver LNA (low-noise amplifier) to be set.
+ \returns \ref status_codes
+ */
+ int16_t setGain(uint8_t gain);
+
+ /*!
+ \brief Read status of the last received packet.
+ Each parameter can be set to NULL if the caller is not intending to process it.
+ \param cr Coding rate of the last received packet
+ \param crc Will be set to true if the last packet had a CRC, false otherwise
+ \param packetLen Length of the last received packet in bytes
+ \param snrPacket SNR of the last received packet in dB
+ \param rssiPacket RSSI of the last received packet in dBm
+ \param rssiSignalPacket Estimation of the RSSI of LoRa signal after despreading in dBm
+ \returns \ref status_codes
+ */
+ int16_t getLoRaPacketStatus(uint8_t* cr, bool* crc, uint8_t* packetLen = NULL, float* snrPacket = NULL, float* rssiPacket = NULL, float* rssiSignalPacket = NULL);
+
+ /*!
+ \brief Get LoRa header information from last received packet. Implementation based on getLoRaPacketStatus.
+ \param cr Pointer to variable to store the coding rate.
+ \param hasCRC Pointer to variable to store the CRC status.
+ \returns \ref status_codes
+ */
+ int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC);
+
+#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
+ protected:
+#endif
+ Module* getMod() override;
+
+#if !RADIOLIB_GODMODE
+ protected:
+#endif
+
+#if !RADIOLIB_GODMODE
+ private:
+#endif
+ // flag to determine whether we are in the sub-GHz or 2.4 GHz range
+ // this is needed to automatically detect which PA to use
+ bool highFreq = false;
+ uint8_t gainModeLf = RADIOLIB_LR2021_RX_BOOST_LF;
+ uint8_t gainModeHf = RADIOLIB_LR2021_RX_BOOST_HF;
+
+ // cached FLRC parameters
+ uint16_t bitRateFlrc = 0;
+ uint8_t codingRateFlrc = 0;
+
+ int16_t modSetup(float freq, float tcxoVoltage, uint8_t modem);
+ bool findChip(void);
+ int16_t config(uint8_t modem);
+ int16_t setPacketMode(uint8_t mode, uint8_t len);
+ int16_t startCad(uint8_t symbolNum, uint8_t detPeak, bool fast, uint8_t exitMode, RadioLibTime_t timeout);
+
+ // chip control commands
+ int16_t readRadioRxFifo(uint8_t* data, size_t len);
+ int16_t writeRadioTxFifo(const uint8_t* data, size_t len);
+ int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len);
+ int16_t writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data);
+ int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len);
+ int16_t setFs(void);
+ int16_t setAdditionalRegToRetain(uint8_t slot, uint32_t addr);
+ int16_t setRx(uint32_t timeout);
+ int16_t setTx(uint32_t timeout);
+ int16_t setRxTxFallbackMode(uint8_t mode);
+ int16_t setRxDutyCycle(uint32_t rxMaxTime, uint32_t cycleTime, uint8_t cfg);
+ int16_t autoTxRx(uint32_t delay, uint8_t mode, uint32_t timeout);
+ int16_t getRxPktLength(uint16_t* len);
+ int16_t resetRxStats(void);
+ int16_t setDefaultRxTxTimeout(uint32_t rxTimeout, uint32_t txTimeout);
+ int16_t setRegMode(uint8_t simoUsage, const uint8_t rampTimes[4]);
+ int16_t calibrate(uint8_t blocks);
+ int16_t calibrateFrontEnd(const uint16_t freq[3]);
+ int16_t getVbat(uint8_t resolution, uint16_t* vbat);
+ int16_t getTemp(uint8_t source, uint8_t resolution, float* temp);
+ int16_t setEolConfig(bool enable, uint8_t trim);
+ int16_t getRandomNumber(uint32_t* rnd);
+ int16_t getVersion(uint8_t* major, uint8_t* minor);
+ int16_t clearErrors(void);
+ int16_t getErrors(uint16_t* err);
+ int16_t setDioFunction(uint8_t dio, uint8_t func, uint8_t pullDrive);
+ int16_t setDioRfSwitchConfig(uint8_t dio, uint8_t func);
+ int16_t setDioIrqConfig(uint8_t dio, uint32_t irq);
+ int16_t clearIrqState(uint32_t irq);
+ int16_t getAndClearIrqStatus(uint32_t* irq);
+ int16_t configFifoIrq(uint8_t rxFifoIrq, uint8_t txFifoIrq, uint8_t rxHighThreshold, uint8_t txHighThreshold);
+ int16_t getFifoIrqFlags(uint8_t* rxFifoFlags, uint8_t* txFifoFlags);
+ int16_t clearFifoIrqFlags(uint8_t rxFifoFlags, uint8_t txFifoFlags);
+ int16_t getAndClearFifoIrqFlags(uint8_t* rxFifoFlags, uint8_t* txFifoFlags);
+ int16_t getRxFifoLevel(uint16_t* level);
+ int16_t getTxFifoLevel(uint16_t* level);
+ int16_t clearRxFifo(void);
+ int16_t clearTxFifo(void);
+ int16_t configLfClock(uint8_t cfg);
+ int16_t configClkOutputs(uint8_t scaling);
+ int16_t setTcxoMode(uint8_t tune, uint32_t startTime);
+ int16_t setXoscCpTrim(uint8_t xta, uint8_t xtb, uint8_t startTime);
+
+ // radio frequency front end commands
+ int16_t setRfFrequency(uint32_t rfFreq);
+ int16_t setRxPath(uint8_t rxPath, uint8_t rxBoost);
+ int16_t getRssiInst(float* rssi);
+ int16_t setRssiCalibration(uint8_t rxPath, const uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], const uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]);
+ int16_t setTimestampSource(uint8_t index, uint8_t source);
+ int16_t getTimestampValue(uint8_t index, uint32_t* timestamp);
+ int16_t setCca(uint32_t duration, uint8_t gain);
+ int16_t getCcaResult(float* rssiMin, float* rssiMax, float* rssiAvg);
+ int16_t setCadParams(uint32_t cadTimeout, uint8_t threshold, uint8_t exitMode, uint32_t trxTimeout);
+ int16_t setCad(void);
+ int16_t selPa(uint8_t pa);
+ int16_t setPaConfig(uint8_t pa, uint8_t paLfMode, uint8_t paLfDutyCycle, uint8_t paLfSlices, uint8_t paHfDutyCycle);
+ int16_t setTxParams(int8_t txPower, uint8_t rampTime);
+ /*! \brief SetTxParams first byte as signed half-dBm steps (datasheet / lr20xx `power_half_dbm`). */
+ int16_t setTxParamsHalfDbm(int8_t powerHalfDbm, uint8_t rampTime);
+
+ // modem configuration commands
+ int16_t setPacketType(uint8_t packetType);
+ int16_t getPacketType(uint8_t* packetType);
+
+ // LoRa commands
+ int16_t setLoRaModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro);
+ int16_t setLoRaPacketParams(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ);
+ int16_t setLoRaSynchTimeout(uint8_t numSymbols, bool format);
+ int16_t setLoRaSyncword(uint8_t syncword);
+ int16_t setLoRaSideDetConfig(uint8_t* configs, size_t numSideDets);
+ int16_t setLoRaSideDetSyncword(uint8_t* syncwords, size_t numSideDets);
+ int16_t setLoRaCadParams(uint8_t numSymbols, bool preambleOnly, uint8_t pnrDelta, uint8_t cadExitMode, uint32_t timeout, uint8_t detPeak);
+ int16_t setLoRaCad(void);
+ int16_t getLoRaRxStats(uint16_t* pktRxTotal, uint16_t* pktCrcError, uint16_t* headerCrcError, uint16_t* falseSynch);
+ int16_t setLoRaAddress(uint8_t addrLen, uint8_t addrPos, const uint8_t* addr);
+ int16_t setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, const uint32_t* freqHops, size_t numFreqHops);
+ int16_t setLoRaTxSync(uint8_t function, uint8_t dioNum);
+ int16_t setLoRaSideDetCad(const uint8_t* pnrDelta, const uint8_t* detPeak, size_t numSideDets);
+ int16_t setLoRaHeaderType(uint8_t hdrType, size_t len = RADIOLIB_LR2021_MAX_PACKET_LENGTH);
+
+ // ranging commands
+ int16_t setRangingAddr(uint32_t addr, uint8_t checkLen);
+ int16_t setRangingReqAddr(uint32_t addr);
+ int16_t getRangingResult(uint8_t type, uint32_t* rng1, uint8_t* rssi1, uint32_t* rng2);
+ int16_t getRangingStats(uint16_t* exchangeValid, uint16_t* requestValid, uint16_t* responseDone, uint16_t* timeout, uint16_t* requestDiscarded);
+ int16_t setRangingTxRxDelay(uint32_t delay);
+ int16_t setRangingParams(bool spyMode, uint8_t nbSymbols);
+
+ // GFSK commands
+ int16_t setGfskModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev);
+ int16_t setGfskPacketParams(uint16_t preambleLen, uint8_t preambleDetect, bool longPreamble, bool pldLenBits, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t dcFree);
+ int16_t setGfskWhiteningParams(uint8_t whitenType, uint16_t init);
+ int16_t setGfskCrcParams(uint32_t poly, uint32_t init);
+ int16_t setGfskSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst);
+ int16_t setGfskAddress(uint8_t addrNode, uint8_t addrBroadcast);
+ int16_t getGfskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout);
+ int16_t getGfskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi);
+
+ // OQPSK commands
+ int16_t setOqpskParams(uint8_t mode, uint8_t rxBw, uint8_t payloadLen, uint16_t preambleLen, bool addrFilt, bool fcsManual);
+ int16_t getOqpskRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError);
+ int16_t getOqpskPacketStatus(uint8_t* rxHeader, uint16_t* payloadLen, float* rssiAvg, float* rssiSync, float* lqi);
+ int16_t setOqpskPacketLen(uint8_t len);
+ int16_t setOqpskAddress(const uint8_t longDestAddr[8], uint16_t shortDestAddr, uint16_t panId, uint8_t transId);
+
+ // BPSK commands
+ int16_t setBpskModulationParams(uint32_t bitRate, uint8_t pulseShape, bool diff, uint8_t diffInit);
+ int16_t setBpskPacketParams(uint8_t payloadLen, uint8_t mode, bool sigFoxControlMsg, uint8_t sigFoxRank);
+
+ // FLRC commands
+ int16_t setFlrcModulationParams(uint8_t brBw, uint8_t cr, uint8_t pulseShape);
+ int16_t setFlrcPacketParams(uint8_t agcPreambleLen, uint8_t syncWordLen, uint8_t syncWordTx, uint8_t syncMatch, bool fixedLength, uint8_t crc, uint16_t payloadLen);
+ int16_t getFlrcRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError);
+ int16_t getFlrcPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, uint8_t* syncWordNum);
+ int16_t setFlrcSyncWord(uint8_t syncWordNum, uint32_t syncWord);
+
+ // LR-FHSS commands
+ int16_t lrFhssSetSyncword(uint32_t syncWord);
+ //! \TODO: [LR2021] Implement reading/writing LR-FHSS hopping table
+ //int16_t readLrFhssHoppingTable(LR2021LrFhssHopTableEntry_t* hopTable[40], size_t* hopTableLen);
+ //int16_t writeLrFhssHoppingTable(LR2021LrFhssHopTableEntry_t* hopTable[40], size_t hopTableLen);
+
+ // OOK commands
+ int16_t setOokModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint8_t depth);
+ int16_t setOokPacketParams(uint16_t preambleLen, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t manchester);
+ int16_t setOokCrcParams(uint32_t poly, uint32_t init);
+ int16_t setOokSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst);
+ int16_t setOokAddress(uint8_t addrNode, uint8_t addrBroadcast);
+ int16_t getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError);
+ int16_t getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiHigh, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi);
+ int16_t setOokDetector(uint16_t preamblePattern, uint8_t patternLen, uint8_t patternNumRepeaters, bool syncWordRaw, bool sofDelimiterRising, uint8_t sofDelimiterLen);
+ int16_t setOokWhiteningParams(uint8_t bitIdx, uint16_t poly, uint16_t init);
+
+ // test commands
+ int16_t setTxTestMode(uint8_t mode);
+};
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_chip_control.cpp
new file mode 100644
index 0000000..65183fa
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_chip_control.cpp
@@ -0,0 +1,311 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+int16_t LR2021::readRadioRxFifo(uint8_t* data, size_t len) {
+ // FIFO read is just a single transaction sent without the status code
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
+ int16_t state = this->mod->SPIreadStream(RADIOLIB_LR2021_CMD_READ_RX_FIFO, data, len, true, false);
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16;
+ return(state);
+}
+
+int16_t LR2021::writeRadioTxFifo(const uint8_t* data, size_t len) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_TX_FIFO, true, const_cast(data), len, NULL, 0));
+}
+
+int16_t LR2021::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) {
+ // check maximum size
+ if(len > (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+ return(this->writeCommon(RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32, addr, data, len, false));
+}
+
+int16_t LR2021::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) {
+ uint8_t buff[11] = {
+ (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
+ (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
+ (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_REG_MEM_MASK_32, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::readRegMem32(uint32_t addr, uint32_t* data, size_t len) {
+ // check maximum size
+ if(len > (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
+ return(RADIOLIB_ERR_SPI_CMD_INVALID);
+ }
+
+ // the request contains the address and length
+ uint8_t reqBuff[4] = {
+ (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF),
+ (uint8_t)(addr & 0xFF), (uint8_t)len,
+ };
+
+ // build buffers - later we need to ensure endians are correct,
+ // so there is probably no way to do this without copying buffers and iterating
+ #if RADIOLIB_STATIC_ONLY
+ uint8_t rplBuff[RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN];
+ #else
+ uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)];
+ #endif
+
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_READ_REG_MEM_32, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff));
+
+ // convert endians
+ if(data && (state == RADIOLIB_ERR_NONE)) {
+ for(size_t i = 0; i < len; i++) {
+ data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)];
+ }
+ }
+
+ #if !RADIOLIB_STATIC_ONLY
+ delete[] rplBuff;
+ #endif
+
+ return(state);
+}
+
+int16_t LR2021::setFs(void) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FS, true, NULL, 0));
+}
+
+int16_t LR2021::setAdditionalRegToRetain(uint8_t slot, uint32_t addr) {
+ uint8_t buff[] = {
+ slot, (uint8_t)((addr >> 16) & 0xFF),
+ (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
+ };
+
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_ADDITIONAL_REG_TO_RETAIN, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setRx(uint32_t timeout) {
+ uint8_t buff[] = {
+ (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RX, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setTx(uint32_t timeout) {
+ uint8_t buff[] = {
+ (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TX, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setRxTxFallbackMode(uint8_t mode) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE, true, &mode, sizeof(mode)));
+}
+
+int16_t LR2021::setRxDutyCycle(uint32_t rxMaxTime, uint32_t cycleTime, uint8_t cfg) {
+ uint8_t buff[] = {
+ (uint8_t)((rxMaxTime >> 16) & 0xFF), (uint8_t)((rxMaxTime >> 8) & 0xFF), (uint8_t)(rxMaxTime & 0xFF),
+ (uint8_t)((cycleTime >> 16) & 0xFF), (uint8_t)((cycleTime >> 8) & 0xFF), (uint8_t)(cycleTime & 0xFF),
+ cfg
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RX_DUTY_CYCLE, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::autoTxRx(uint32_t delay, uint8_t mode, uint32_t timeout) {
+ uint8_t buff[] = {
+ (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), mode,
+ (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_AUTO_RX_TX, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getRxPktLength(uint16_t* len) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RX_PKT_LENGTH, false, buff, sizeof(buff));
+ if(len) { *len = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ return(state);
+}
+
+int16_t LR2021::resetRxStats(void) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_RESET_RX_STATS, true, NULL, 0));
+}
+
+int16_t LR2021::setDefaultRxTxTimeout(uint32_t rxTimeout, uint32_t txTimeout) {
+ uint8_t buff[] = {
+ (uint8_t)((rxTimeout >> 16) & 0xFF), (uint8_t)((rxTimeout >> 8) & 0xFF), (uint8_t)(rxTimeout & 0xFF),
+ (uint8_t)((txTimeout >> 16) & 0xFF), (uint8_t)((txTimeout >> 8) & 0xFF), (uint8_t)(txTimeout & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DEFAULT_RX_TX_TIMEOUT, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setRegMode(uint8_t simoUsage, const uint8_t rampTimes[4]) {
+ uint8_t buff[] = { simoUsage,
+ rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RC2RU], rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_TX2RU],
+ rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RU2RC], rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RAMP_DOWN],
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_REG_MODE, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::calibrate(uint8_t blocks) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_CALIBRATE, true, &blocks, sizeof(blocks)));
+}
+
+int16_t LR2021::calibrateFrontEnd(const uint16_t freq[3]) {
+ uint8_t buff[] = {
+ (uint8_t)((freq[0] >> 8) & 0xFF), (uint8_t)(freq[0] & 0xFF),
+ (uint8_t)((freq[1] >> 8) & 0xFF), (uint8_t)(freq[1] & 0xFF),
+ (uint8_t)((freq[2] >> 8) & 0xFF), (uint8_t)(freq[2] & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_CALIB_FRONT_END, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getVbat(uint8_t resolution, uint16_t* vbat) {
+ uint8_t reqBuff[] = { (uint8_t)(RADIOLIB_LR2021_VBAT_FORMAT_MV | ((RADIOLIB_LR2021_MEAS_RESOLUTION_OFFSET + resolution) & 0x07)) };
+ uint8_t rplBuff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_V_BAT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
+ if(vbat) { *vbat = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; }
+ return(state);
+}
+
+int16_t LR2021::getTemp(uint8_t source, uint8_t resolution, float* temp) {
+ uint8_t reqBuff[] = { (uint8_t)((source & 0x30) | RADIOLIB_LR2021_TEMP_FORMAT_DEG_C | ((RADIOLIB_LR2021_MEAS_RESOLUTION_OFFSET + resolution) & 0x07)) };
+ uint8_t rplBuff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_TEMP, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
+ if(temp) {
+ uint16_t raw = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1];
+ *temp = (float)raw/320.0f;
+ }
+ return(state);
+}
+
+int16_t LR2021::setEolConfig(bool enable, uint8_t trim) {
+ uint8_t buff[] = { (uint8_t)((trim & 0x06) | (uint8_t)enable) };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_EOL_CONFIG, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getRandomNumber(uint32_t* rnd) {
+ uint8_t buff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RANDOM_NUMBER, false, buff, sizeof(buff));
+ if(rnd) { *rnd = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; }
+ return(state);
+}
+
+int16_t LR2021::getVersion(uint8_t* major, uint8_t* minor) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_VERSION, false, buff, sizeof(buff));
+ if(major) { *major = buff[0]; }
+ if(minor) { *minor = buff[1]; }
+ return(state);
+}
+
+int16_t LR2021::clearErrors(void) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_ERRORS, true, NULL, 0));
+}
+
+int16_t LR2021::getErrors(uint16_t* err) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_ERRORS, false, buff, sizeof(buff));
+ if(err) { *err = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ return(state);
+}
+
+int16_t LR2021::setDioFunction(uint8_t dio, uint8_t func, uint8_t pullDrive) {
+ uint8_t buff[] = { dio, (uint8_t)((func & 0xF0) | (pullDrive & 0x0F)) };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setDioRfSwitchConfig(uint8_t dio, uint8_t func) {
+ uint8_t buff[] = { dio, func };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DIO_RF_SWITCH_CONFIG, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setDioIrqConfig(uint8_t dio, uint32_t irq) {
+ uint8_t buff[] = { dio,
+ (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF),
+ (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::clearIrqState(uint32_t irq) {
+ return(this->setU32(RADIOLIB_LR2021_CMD_CLEAR_IRQ, irq));
+}
+
+int16_t LR2021::getAndClearIrqStatus(uint32_t* irq) {
+ uint8_t buff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_AND_CLEAR_IRQ_STATUS, false, buff, sizeof(buff));
+ if(irq) { *irq = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) |(uint32_t)buff[3]; }
+ return(state);
+}
+
+int16_t LR2021::configFifoIrq(uint8_t rxFifoIrq, uint8_t txFifoIrq, uint8_t rxHighThreshold, uint8_t txHighThreshold) {
+ uint8_t buff[] = { rxFifoIrq, txFifoIrq, rxHighThreshold, txHighThreshold };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getFifoIrqFlags(uint8_t* rxFifoFlags, uint8_t* txFifoFlags) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FIFO_IRQ_FLAGS, false, buff, sizeof(buff));
+ if(rxFifoFlags) { *rxFifoFlags = buff[0]; }
+ if(txFifoFlags) { *txFifoFlags = buff[1]; }
+ return(state);
+}
+
+int16_t LR2021::clearFifoIrqFlags(uint8_t rxFifoFlags, uint8_t txFifoFlags) {
+ uint8_t buff[] = { rxFifoFlags, txFifoFlags };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_FIFO_IRQ_FLAGS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getAndClearFifoIrqFlags(uint8_t* rxFifoFlags, uint8_t* txFifoFlags) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_AND_CLEAR_FIFO_IRQ_FLAGS, false, buff, sizeof(buff));
+ if(rxFifoFlags) { *rxFifoFlags = buff[0]; }
+ if(txFifoFlags) { *txFifoFlags = buff[1]; }
+ return(state);
+}
+
+int16_t LR2021::getRxFifoLevel(uint16_t* level) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RX_FIFO_LEVEL, false, buff, sizeof(buff));
+ if(level) { *level = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ return(state);
+}
+
+int16_t LR2021::getTxFifoLevel(uint16_t* level) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_TX_FIFO_LEVEL, false, buff, sizeof(buff));
+ if(level) { *level = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ return(state);
+}
+
+int16_t LR2021::clearRxFifo(void) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_RX_FIFO, true, NULL, 0));
+}
+
+int16_t LR2021::clearTxFifo(void) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_TX_FIFO, true, NULL, 0));
+}
+
+int16_t LR2021::configLfClock(uint8_t cfg) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_LF_CLOCK, true, &cfg, sizeof(cfg)));
+}
+
+int16_t LR2021::configClkOutputs(uint8_t scaling) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS, true, &scaling, sizeof(scaling)));
+}
+
+int16_t LR2021::setTcxoMode(uint8_t tune, uint32_t startTime) {
+ uint8_t buff[] = { (uint8_t)(tune & 0x07),
+ (uint8_t)((startTime >> 24) & 0xFF), (uint8_t)((startTime >> 16) & 0xFF),
+ (uint8_t)((startTime >> 8) & 0xFF), (uint8_t)(startTime & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TCXO_MODE, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setXoscCpTrim(uint8_t xta, uint8_t xtb, uint8_t startTime) {
+ uint8_t buff[] = { (uint8_t)(xta & 0x3F), (uint8_t)(xtb & 0x3F), startTime };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_XOSC_CP_TRIM, true, buff, sizeof(buff)));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_cmds_flrc.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_flrc.cpp
new file mode 100644
index 0000000..a773190
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_flrc.cpp
@@ -0,0 +1,61 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+int16_t LR2021::setFlrcModulationParams(uint8_t brBw, uint8_t cr, uint8_t pulseShape) {
+ uint8_t buff[] = { brBw, (uint8_t)((cr << 4) | (pulseShape & 0x0F)) };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FLRC_MODULATION_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setFlrcPacketParams(uint8_t agcPreambleLen, uint8_t syncWordLen, uint8_t syncWordTx, uint8_t syncMatch, bool fixedLength, uint8_t crc, uint16_t payloadLen) {
+ uint8_t buff[] = {
+ (uint8_t)(((agcPreambleLen & 0x0F) << 2) | (syncWordLen / 2)),
+ (uint8_t)(((syncWordTx & 0x03) << 6) | ((syncMatch & 0x07) << 3) | ((uint8_t)fixedLength << 2) | (crc & 0x03)),
+ (uint8_t)((payloadLen >> 8) & 0xFF), (uint8_t)(payloadLen & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FLRC_PACKET_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getFlrcRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError) {
+ uint8_t buff[14] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FLRC_RX_STATS, false, buff, sizeof(buff));
+ if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(packetCrcError) { *packetCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; }
+ if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
+ return(state);
+}
+
+int16_t LR2021::getFlrcPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, uint8_t* syncWordNum) {
+ uint8_t buff[5] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FLRC_PACKET_STATUS, false, buff, sizeof(buff));
+ uint16_t raw;
+ if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(rssiAvg) {
+ raw = (uint16_t)buff[2] << 1;
+ raw |= (buff[4] & 0x04) >> 2;
+ *rssiAvg = (float)raw / -2.0f;
+ }
+ if(rssiSync) {
+ raw = (uint16_t)buff[3] << 1;
+ raw |= (buff[4] & 0x01);
+ *rssiSync = (float)raw / -2.0f;
+ }
+ if(syncWordNum) { *syncWordNum = (buff[4] & 0xF0) >> 4; }
+ return(state);
+}
+
+int16_t LR2021::setFlrcSyncWord(uint8_t syncWordNum, uint32_t syncWord) {
+ uint8_t buff[] = {
+ syncWordNum,
+ (uint8_t)((syncWord >> 24) & 0xFF), (uint8_t)((syncWord >> 16) & 0xFF),
+ (uint8_t)((syncWord >> 8) & 0xFF), (uint8_t)(syncWord & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FLRC_SYNCWORD, true, buff, sizeof(buff)));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_cmds_gfsk.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_gfsk.cpp
new file mode 100644
index 0000000..6aeeec7
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_gfsk.cpp
@@ -0,0 +1,96 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+int16_t LR2021::setGfskModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) {
+ uint8_t buff[] = {
+ (uint8_t)((bitRate >> 24) & 0xFF), (uint8_t)((bitRate >> 16) & 0xFF),
+ (uint8_t)((bitRate >> 8) & 0xFF), (uint8_t)(bitRate & 0xFF),
+ pulseShape, rxBw, (uint8_t)((freqDev >> 16) & 0xFF),
+ (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_MODULATION_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setGfskPacketParams(uint16_t preambleLen, uint8_t preambleDetect, bool longPreamble, bool pldLenBits, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t dcFree) {
+ uint8_t buff[] = {
+ (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), preambleDetect,
+ (uint8_t)(((uint8_t)longPreamble << 5) | ((uint8_t)pldLenBits << 4) | (addrComp << 2) | ((uint8_t)packetFormat & 0x03)),
+ (uint8_t)((payloadLen >> 8) & 0xFF), (uint8_t)(payloadLen & 0xFF),
+ (uint8_t)((crc << 4) | (dcFree << 4)),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_PACKET_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setGfskWhiteningParams(uint8_t whitenType, uint16_t init) {
+ uint8_t buff[] = {
+ (uint8_t)((whitenType << 4) | (uint8_t)((init >> 8) & 0x0F)),
+ (uint8_t)(init & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_WHITENING_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setGfskCrcParams(uint32_t poly, uint32_t init) {
+ uint8_t buff[] = {
+ (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF),
+ (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF),
+ (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF),
+ (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_CRC_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setGfskSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst) {
+ uint8_t buff[9] = { 0 };
+ for(int8_t i = 7; i >= (int8_t) (RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN - syncWordLen); i--) {
+ buff[i] = syncWord[i - (int8_t) (RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN - syncWordLen)];
+ }
+ buff[8] = (uint8_t)msbFirst << 7 | ((syncWordLen*8) & 0x7F);
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_SYNCWORD, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setGfskAddress(uint8_t addrNode, uint8_t addrBroadcast) {
+ uint8_t buff[] = { addrNode, addrBroadcast };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_ADDRESS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getGfskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout) {
+ uint8_t buff[14] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS, false, buff, sizeof(buff));
+ if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(packetCrcError) { *packetCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; }
+ if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
+ if(preambleDet) { *preambleDet = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; }
+ if(syncOk) { *syncOk = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; }
+ if(syncFail) { *syncFail = ((uint16_t)(buff[10]) << 8) | (uint16_t)buff[11]; }
+ if(timeout) { *timeout = ((uint16_t)(buff[12]) << 8) | (uint16_t)buff[13]; }
+ return(state);
+}
+
+int16_t LR2021::getGfskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) {
+ uint8_t buff[6] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_PACKET_STATUS, false, buff, sizeof(buff));
+ uint16_t raw;
+ if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(rssiAvg) {
+ raw = (uint16_t)buff[2] << 1;
+ raw |= (buff[4] & 0x04) >> 2;
+ *rssiAvg = (float)raw / -2.0f;
+ }
+ if(rssiSync) {
+ raw = (uint16_t)buff[3] << 1;
+ raw |= (buff[4] & 0x01);
+ *rssiSync = (float)raw / -2.0f;
+ }
+ if(addrMatchNode) { *addrMatchNode = (buff[4] & 0x10); }
+ if(addrMatchBroadcast) { *addrMatchBroadcast = (buff[4] & 0x20); }
+ if(lqi) { *lqi = buff[5] * 4.0f; }
+ return(state);
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_cmds_lora.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_lora.cpp
new file mode 100644
index 0000000..68f6eaf
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_lora.cpp
@@ -0,0 +1,130 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+int16_t LR2021::setLoRaModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
+ // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled
+ if(this->ldroAuto) {
+ float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
+ if(symbolLength >= 16.0f) {
+ this->ldrOptimize = RADIOLIB_LR2021_LORA_LDRO_ENABLED;
+ } else {
+ this->ldrOptimize = RADIOLIB_LR2021_LORA_LDRO_DISABLED;
+ }
+ } else {
+ this->ldrOptimize = ldro;
+ }
+
+ uint8_t buff[] = { (uint8_t)(((sf & 0x0F) << 4) | (bw & 0x0F)), (uint8_t)(((cr & 0x0F) << 4) | this->ldrOptimize) };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_MODULATION_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setLoRaPacketParams(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ) {
+ uint8_t buff[] = {
+ (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), payloadLen,
+ (uint8_t)(((hdrType & 0x01) << 2) | ((crcType & 0x01) << 1) | (invertIQ & 0x01)),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_PACKET_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setLoRaSynchTimeout(uint8_t numSymbols, bool format) {
+ uint8_t buff[] = { numSymbols, (uint8_t)format };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SYNCH_TIMEOUT, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setLoRaSyncword(uint8_t syncword) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD, true, &syncword, sizeof(syncword)));
+}
+
+int16_t LR2021::setLoRaSideDetConfig(uint8_t* configs, size_t numSideDets) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CONFIG, true, configs, numSideDets));
+}
+
+int16_t LR2021::setLoRaSideDetSyncword(uint8_t* syncwords, size_t numSideDets) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_SYNCWORD, true, syncwords, numSideDets));
+}
+
+int16_t LR2021::setLoRaCadParams(uint8_t numSymbols, bool preambleOnly, uint8_t pnrDelta, uint8_t cadExitMode, uint32_t timeout, uint8_t detPeak) {
+ uint8_t buff[] = {
+ numSymbols, (uint8_t)(((uint8_t)preambleOnly << 4) | (pnrDelta & 0x0F)), cadExitMode,
+ (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
+ (uint8_t)(detPeak & 0x7F)
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_CAD_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setLoRaCad(void) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_CAD, true, NULL, 0));
+}
+
+int16_t LR2021::getLoRaRxStats(uint16_t* pktRxTotal, uint16_t* pktCrcError, uint16_t* headerCrcError, uint16_t* falseSynch) {
+ uint8_t buff[8] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_LORA_RX_STATS, false, buff, sizeof(buff));
+ if(pktRxTotal) { *pktRxTotal = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(pktCrcError) { *pktCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; }
+ if(headerCrcError) { *headerCrcError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
+ if(falseSynch) { *falseSynch = ((uint16_t)(buff[7]) << 8) | (uint16_t)buff[6]; }
+ return(state);
+}
+
+int16_t LR2021::getLoRaPacketStatus(uint8_t* cr, bool* crc, uint8_t* packetLen, float* snrPacket, float* rssiPacket, float* rssiSignalPacket) {
+ uint8_t buff[6] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS, false, buff, sizeof(buff));
+ uint16_t raw;
+ if(crc) { *crc = (buff[0] & 0x10) >> 4; }
+ if(cr) { *cr = buff[0] & 0x0F; }
+ if(packetLen) { *packetLen = buff[1]; }
+ if(snrPacket) { *snrPacket = (float)((int8_t)buff[2]) / 4.0f; }
+ if(rssiPacket) {
+ raw = (uint16_t)buff[3] << 1;
+ raw |= (buff[5] & 0x02) >> 1;
+ *rssiPacket = (float)raw / -2.0f;
+ }
+ if(rssiSignalPacket) {
+ raw = (uint16_t)buff[4] << 1;
+ raw |= buff[5] & 0x01;
+ *rssiSignalPacket = (float)raw / -2.0f;
+ }
+ return(state);
+}
+
+int16_t LR2021::setLoRaAddress(uint8_t addrLen, uint8_t addrPos, const uint8_t* addr) {
+ if(addrLen > 8) { return(RADIOLIB_ERR_UNKNOWN); }
+ uint8_t buff[9] = { (uint8_t)(((addrLen & 0x0F) << 4) | (addrPos & 0x0F)) };
+ memcpy(&buff[1], addr, addrLen);
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_ADDRESS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, const uint32_t* freqHops, size_t numFreqHops) {
+ if(numFreqHops > 40) { return(RADIOLIB_ERR_UNKNOWN); }
+ uint8_t buff[2 + 160] = { (uint8_t)(hopCtrl | ((hopPeriod & 0xF00) >> 8)), (uint8_t)(hopPeriod & 0xFF) };
+ for(uint8_t i = 0; i < numFreqHops; i++) {
+ buff[i + 2] = (freqHops[i] >> 24) & 0xFF;
+ buff[i + 3] = (freqHops[i] >> 16) & 0xFF;
+ buff[i + 4] = (freqHops[i] >> 8) & 0xFF;
+ buff[i + 5] = freqHops[i] & 0xFF;
+ }
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_HOPPING, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setLoRaTxSync(uint8_t function, uint8_t dioNum) {
+ uint8_t buff[] = { (uint8_t)(function | (dioNum & 0x3F)) };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setLoRaSideDetCad(const uint8_t* pnrDelta, const uint8_t* detPeak, size_t numSideDets) {
+ uint8_t buff[6] = { 0 };
+ for(uint8_t i = 0; i < numSideDets; i++) {
+ if(i >= 3) { return(RADIOLIB_ERR_UNKNOWN); }
+ buff[2*i] = pnrDelta[i] & 0x0F;
+ buff[2*i + 1] = detPeak[i] & 0x7F;
+ }
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CAD, true, buff, 2*numSideDets));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_cmds_misc.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_misc.cpp
new file mode 100644
index 0000000..0be29e6
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_misc.cpp
@@ -0,0 +1,35 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+int16_t LR2021::setBpskModulationParams(uint32_t bitRate, uint8_t pulseShape, bool diff, uint8_t diffInit) {
+ uint8_t buff[] = {
+ (uint8_t)((bitRate >> 24) & 0xFF), (uint8_t)((bitRate >> 16) & 0xFF),
+ (uint8_t)((bitRate >> 8) & 0xFF), (uint8_t)(bitRate & 0xFF),
+ (uint8_t)((pulseShape << 4) | ((uint8_t)diff << 2) | (diffInit & 0x03)),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_BPSK_MODULATION_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setBpskPacketParams(uint8_t payloadLen, uint8_t mode, bool sigFoxControlMsg, uint8_t sigFoxRank) {
+ uint8_t buff[] = {
+ payloadLen,
+ (uint8_t)((mode << 4) | ((uint8_t)sigFoxControlMsg << 2) | (sigFoxRank & 0x03)),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_BPSK_PACKET_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::lrFhssSetSyncword(uint32_t syncWord) {
+ return(this->setU32(RADIOLIB_LR2021_CMD_LR_FHSS_SET_SYNCWORD, syncWord));
+}
+
+int16_t LR2021::setTxTestMode(uint8_t mode) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE, true, &mode, sizeof(mode)));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_cmds_ook.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_ook.cpp
new file mode 100644
index 0000000..392a097
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_ook.cpp
@@ -0,0 +1,105 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+int16_t LR2021::setOokModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint8_t depth) {
+ uint8_t buff[] = {
+ (uint8_t)((bitRate >> 24) & 0xFF), (uint8_t)((bitRate >> 16) & 0xFF),
+ (uint8_t)((bitRate >> 8) & 0xFF), (uint8_t)(bitRate & 0xFF),
+ pulseShape, rxBw, depth,
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_MODULATION_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setOokPacketParams(uint16_t preambleLen, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t manchester) {
+ uint8_t buff[] = {
+ (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
+ (uint8_t)((addrComp << 2) | ((uint8_t)packetFormat & 0x03)),
+ (uint8_t)((payloadLen >> 8) & 0xFF), (uint8_t)(payloadLen & 0xFF),
+ (uint8_t)(((crc << 4) & 0xF0) | (manchester & 0x0F)),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setOokCrcParams(uint32_t poly, uint32_t init) {
+ uint8_t buff[] = {
+ (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF),
+ (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF),
+ (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF),
+ (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_CRC_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setOokSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst) {
+ // OOK maximum sync word length is just 32-bits, unlike GFSK
+ if(syncWordLen > RADIOLIB_LR2021_OOK_SYNC_WORD_LEN) {
+ return(RADIOLIB_ERR_INVALID_SYNC_WORD);
+ }
+
+ uint8_t buff[5] = { 0 };
+ for(int8_t i = 3; i >= (int8_t) (RADIOLIB_LR2021_OOK_SYNC_WORD_LEN - syncWordLen); i--) {
+ buff[i] = syncWord[i - (int8_t) (RADIOLIB_LR2021_OOK_SYNC_WORD_LEN - syncWordLen)];
+ }
+ buff[4] = (uint8_t)msbFirst << 7 | ((syncWordLen*8) & 0x7F);
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_SYNCWORD, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setOokAddress(uint8_t addrNode, uint8_t addrBroadcast) {
+ uint8_t buff[] = { addrNode, addrBroadcast };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_ADDRESS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError) {
+ uint8_t buff[6] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OOK_RX_STATS, false, buff, sizeof(buff));
+ if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(crcError) { *crcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; }
+ if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
+ return(state);
+}
+
+int16_t LR2021::getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiHigh, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) {
+ uint8_t buff[6] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OOK_PACKET_STATUS, false, buff, sizeof(buff));
+ uint16_t raw;
+ if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(rssiAvg) {
+ raw = (uint16_t)buff[2] << 1;
+ raw |= (buff[4] & 0x04) >> 2;
+ *rssiAvg = (float)raw / -2.0f;
+ }
+ if(rssiHigh) {
+ raw = (uint16_t)buff[3] << 1;
+ raw |= (buff[4] & 0x01);
+ *rssiHigh = (float)raw / -2.0f;
+ }
+ if(addrMatchNode) { *addrMatchNode = (buff[4] & 0x10); }
+ if(addrMatchBroadcast) { *addrMatchBroadcast = (buff[4] & 0x20); }
+ if(lqi) { *lqi = buff[5] * 4.0f; }
+ return(state);
+}
+
+int16_t LR2021::setOokDetector(uint16_t preamblePattern, uint8_t patternLen, uint8_t patternNumRepeaters, bool syncWordRaw, bool sofDelimiterRising, uint8_t sofDelimiterLen) {
+ uint8_t buff[] = {
+ (uint8_t)((preamblePattern >> 8) & 0xFF), (uint8_t)(preamblePattern & 0xFF),
+ (uint8_t)(patternLen & 0x0F), (uint8_t)(patternNumRepeaters & 0x1F),
+ (uint8_t)(((uint8_t)syncWordRaw << 5) | ((uint8_t)sofDelimiterRising << 4) | (sofDelimiterLen & 0x0F)),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_DETECTOR, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setOokWhiteningParams(uint8_t bitIdx, uint16_t poly, uint16_t init) {
+ uint8_t buff[] = {
+ (uint8_t)((bitIdx << 4) | ((poly >> 8) & 0x0FF)), (uint8_t)(poly & 0xFF),
+ (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_WHITENING_PARAMS, true, buff, sizeof(buff)));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_cmds_oqpsk.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_oqpsk.cpp
new file mode 100644
index 0000000..9090f8c
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_oqpsk.cpp
@@ -0,0 +1,62 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+int16_t LR2021::setOqpskParams(uint8_t mode, uint8_t rxBw, uint8_t payloadLen, uint16_t preambleLen, bool addrFilt, bool fcsManual) {
+ uint8_t buff[] = {
+ mode, rxBw, payloadLen,
+ (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
+ (uint8_t)((uint8_t)addrFilt << 1 | (uint8_t)fcsManual),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getOqpskRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError) {
+ uint8_t buff[6] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OQPSK_RX_STATS, false, buff, sizeof(buff));
+ if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(crcError) { *crcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; }
+ if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
+ return(state);
+}
+
+int16_t LR2021::getOqpskPacketStatus(uint8_t* rxHeader, uint16_t* payloadLen, float* rssiAvg, float* rssiSync, float* lqi) {
+ uint8_t buff[7] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OQPSK_PACKET_STATUS, false, buff, sizeof(buff));
+ if(rxHeader) { *rxHeader = buff[0]; }
+ if(payloadLen) { *payloadLen = ((uint16_t)(buff[1]) << 8) | (uint16_t)buff[2]; }
+ uint16_t raw;
+ if(rssiAvg) {
+ raw = (uint16_t)buff[3] << 1;
+ raw |= (buff[5] & 0x04) >> 2;
+ *rssiAvg = (float)raw / -2.0f;
+ }
+ if(rssiSync) {
+ raw = (uint16_t)buff[4] << 1;
+ raw |= (buff[5] & 0x01);
+ *rssiSync = (float)raw / -2.0f;
+ }
+ if(lqi) { *lqi = buff[6] * 4.0f; }
+ return(state);
+}
+
+int16_t LR2021::setOqpskPacketLen(uint8_t len) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OQPSK_PACKET_LEN, true, &len, sizeof(len)));
+}
+
+int16_t LR2021::setOqpskAddress(const uint8_t longDestAddr[8], uint16_t shortDestAddr, uint16_t panId, uint8_t transId) {
+ uint8_t buff[] = {
+ longDestAddr[7], longDestAddr[6], longDestAddr[5], longDestAddr[4],
+ longDestAddr[3], longDestAddr[2], longDestAddr[1], longDestAddr[0],
+ (uint8_t)((shortDestAddr >> 8) & 0xFF), (uint8_t)(shortDestAddr & 0xFF),
+ (uint8_t)((panId >> 8) & 0xFF), (uint8_t)(panId & 0xFF), transId,
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OQPSK_ADDRESS, true, buff, sizeof(buff)));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_cmds_radio.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_radio.cpp
new file mode 100644
index 0000000..d3aeb0e
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_radio.cpp
@@ -0,0 +1,123 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+int16_t LR2021::setRfFrequency(uint32_t rfFreq) {
+ return(this->setU32(RADIOLIB_LR2021_CMD_SET_RF_FREQUENCY, rfFreq));
+}
+
+int16_t LR2021::setRxPath(uint8_t rxPath, uint8_t rxBoost) {
+ uint8_t buff[] = { (uint8_t)(rxPath & 0x01), (uint8_t)(rxBoost & 0x07) };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RX_PATH, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getRssiInst(float* rssi) {
+ uint8_t buff[2] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RSSI_INST, false, buff, sizeof(buff));
+ if(rssi) {
+ uint16_t raw = ((uint16_t)(buff[0]) << 1) | (uint16_t)((buff[1] >> 7) & 0x01);
+ *rssi = (float)raw/-2.0f;
+ }
+ return(state);
+}
+
+int16_t LR2021::setRssiCalibration(uint8_t rxPath, const uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], const uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]) {
+ uint8_t buff[1 + 3*RADIOLIB_LR2021_GAIN_TABLE_LENGTH] = { 0 };
+ buff[0] = rxPath;
+ for(uint8_t i = 0; i < RADIOLIB_LR2021_GAIN_TABLE_LENGTH; i++) {
+ buff[1 + 3*i] = (uint8_t)((gain[i] & 0x300) >> 8);
+ buff[2 + 3*i] = (uint8_t)(gain[i] & 0xFF);
+ buff[3 + 3*i] = noiseFloor[i];
+ }
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setTimestampSource(uint8_t index, uint8_t source) {
+ uint8_t buff[] = { (uint8_t)(((index & 0x03) << 4) | (source & 0x0F)) };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TIMESTAMP_SOURCE, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getTimestampValue(uint8_t index, uint32_t* timestamp) {
+ uint8_t reqBuff[] = { (uint8_t)(index & 0x03) };
+ uint8_t rplBuff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_TIMESTAMP_VALUE, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
+ if(timestamp) { *timestamp = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; }
+ return(state);
+}
+
+int16_t LR2021::setCca(uint32_t duration, uint8_t gain) {
+ uint8_t buff[] = {
+ (uint8_t)((duration >> 16) & 0xFF), (uint8_t)((duration >> 8) & 0xFF), (uint8_t)(duration & 0xFF), gain,
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_CCA, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getCcaResult(float* rssiMin, float* rssiMax, float* rssiAvg) {
+ uint8_t buff[4] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_CCA_RESULT, false, buff, sizeof(buff));
+ uint16_t raw;
+ if(rssiMin) {
+ raw = ((uint16_t)(buff[0]) << 1) | (uint16_t)((buff[3] >> 2) & 0x01);
+ *rssiMin = (float)raw/-2.0f;
+ }
+ if(rssiMax) {
+ raw = ((uint16_t)(buff[1]) << 1) | (uint16_t)((buff[3] >> 1) & 0x01);
+ *rssiMax = (float)raw/-2.0f;
+ }
+ if(rssiAvg) {
+ raw = ((uint16_t)(buff[2]) << 1) | (uint16_t)((buff[3] >> 0) & 0x01);
+ *rssiAvg = (float)raw/-2.0f;
+ }
+ return(state);
+}
+
+int16_t LR2021::setCadParams(uint32_t cadTimeout, uint8_t threshold, uint8_t exitMode, uint32_t trxTimeout) {
+ uint8_t buff[] = {
+ (uint8_t)((cadTimeout >> 16) & 0xFF), (uint8_t)((cadTimeout >> 8) & 0xFF), (uint8_t)(cadTimeout & 0xFF),
+ threshold, (uint8_t)(exitMode & 0x03),
+ (uint8_t)((trxTimeout >> 16) & 0xFF), (uint8_t)((trxTimeout >> 8) & 0xFF), (uint8_t)(trxTimeout & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_CAD_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setCad(void) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_CAD, true, NULL, 0));
+}
+
+int16_t LR2021::selPa(uint8_t pa) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SEL_PA, true, &pa, sizeof(pa)));
+}
+
+int16_t LR2021::setPaConfig(uint8_t pa, uint8_t paLfMode, uint8_t paLfDutyCycle, uint8_t paLfSlices, uint8_t paHfDutyCycle) {
+ // Matches Semtech lr20xx_radio_common_set_pa_cfg(): 3 payload bytes after opcode.
+ uint8_t buff[] = {
+ (uint8_t)(((pa & 0x01) << 7) | (paLfMode & 0x03)),
+ (uint8_t)(((paLfDutyCycle & 0x0F) << 4) | (paLfSlices & 0x0F)),
+ (uint8_t)(paHfDutyCycle & 0x1F),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_PA_CONFIG, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setTxParamsHalfDbm(int8_t powerHalfDbm, uint8_t rampTime) {
+ uint8_t buff[] = { (uint8_t)powerHalfDbm, rampTime };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TX_PARAMS, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setTxParams(int8_t txPower, uint8_t rampTime) {
+ return(this->setTxParamsHalfDbm((int8_t)(txPower * 2), rampTime));
+}
+
+int16_t LR2021::setPacketType(uint8_t packetType) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_PACKET_TYPE, true, &packetType, sizeof(packetType)));
+}
+
+int16_t LR2021::getPacketType(uint8_t* packetType) {
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_GET_PACKET_TYPE, false, packetType, sizeof(uint8_t)));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_cmds_ranging.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_ranging.cpp
new file mode 100644
index 0000000..7cc4998
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_cmds_ranging.cpp
@@ -0,0 +1,64 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+int16_t LR2021::setRangingAddr(uint32_t addr, uint8_t checkLen) {
+ uint8_t buff[] = {
+ (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF),
+ (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
+ checkLen,
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RANGING_ADDR, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::setRangingReqAddr(uint32_t addr) {
+ uint8_t buff[] = {
+ (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF),
+ (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
+ };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RANGING_REQ_ADDR, true, buff, sizeof(buff)));
+}
+
+int16_t LR2021::getRangingResult(uint8_t type, uint32_t* rng1, uint8_t* rssi1, uint32_t* rng2) {
+ const uint8_t reqBuff[] = { type };
+ uint8_t rplBuff[7] = { 0 };
+
+ //! \TODO: [LR2021] implement AGC gains readout
+ size_t rplLen = (type == RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW) ? 7 : 4;
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, rplLen);
+
+ if(rng1) { *rng1 = ((uint32_t)(rplBuff[0]) << 16) | ((uint32_t)(rplBuff[1]) << 8) | (uint32_t)rplBuff[2]; }
+ if(rssi1) { *rssi1 = rplBuff[3]; }
+ if(rng2 && (type == RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW_EXT)) {
+ *rng2 = ((uint32_t)(rplBuff[4]) << 16) | ((uint32_t)(rplBuff[5]) << 8) | (uint32_t)rplBuff[6];
+ }
+
+ return(state);
+}
+
+int16_t LR2021::getRangingStats(uint16_t* exchangeValid, uint16_t* requestValid, uint16_t* responseDone, uint16_t* timeout, uint16_t* requestDiscarded) {
+ uint8_t buff[10] = { 0 };
+ int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RANGING_STATS, false, buff, sizeof(buff));
+ if(exchangeValid) { *exchangeValid = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
+ if(requestValid) { *requestValid = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; }
+ if(responseDone) { *responseDone = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
+ if(timeout) { *timeout = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; }
+ if(requestDiscarded) { *requestDiscarded = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; }
+ return(state);
+}
+
+int16_t LR2021::setRangingTxRxDelay(uint32_t delay) {
+ return(this->setU32(RADIOLIB_LR2021_CMD_SET_RANGING_TX_RX_DELAY, delay));
+}
+
+int16_t LR2021::setRangingParams(bool spyMode, uint8_t nbSymbols) {
+ uint8_t buff[] = { (uint8_t)(((uint8_t)spyMode << 6) | (nbSymbols & 0x3F)) };
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RANGING_PARAMS, true, buff, sizeof(buff)));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_commands.h b/lib/RadioLib/src/modules/LR2021/LR2021_commands.h
new file mode 100644
index 0000000..c503c79
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_commands.h
@@ -0,0 +1,534 @@
+#if !defined(RADIOLIB_LR2021_COMMANDS_H)
+#define RADIOLIB_LR2021_COMMANDS_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+// LR2021 SPI commands
+#define RADIOLIB_LR2021_CMD_NOP (0x0000)
+#define RADIOLIB_LR2021_CMD_READ_RX_FIFO (0x0001)
+#define RADIOLIB_LR2021_CMD_WRITE_TX_FIFO (0x0002)
+#define RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32 (0x0104)
+#define RADIOLIB_LR2021_CMD_WRITE_REG_MEM_MASK_32 (0x0105)
+#define RADIOLIB_LR2021_CMD_READ_REG_MEM_32 (0x0106)
+#define RADIOLIB_LR2021_CMD_SET_SLEEP (0x0127)
+#define RADIOLIB_LR2021_CMD_SET_STANDBY (0x0128)
+#define RADIOLIB_LR2021_CMD_SET_FS (0x0129)
+#define RADIOLIB_LR2021_CMD_SET_ADDITIONAL_REG_TO_RETAIN (0x012A)
+#define RADIOLIB_LR2021_CMD_SET_RX (0x020C)
+#define RADIOLIB_LR2021_CMD_SET_TX (0x020D)
+#define RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE (0x0206)
+#define RADIOLIB_LR2021_CMD_SET_RX_DUTY_CYCLE (0x0210)
+#define RADIOLIB_LR2021_CMD_SET_AUTO_RX_TX (0x0211)
+#define RADIOLIB_LR2021_CMD_GET_RX_PKT_LENGTH (0x0212)
+#define RADIOLIB_LR2021_CMD_STOP_TIMEOUT_ON_PREAMBLE (0x0209)
+#define RADIOLIB_LR2021_CMD_RESET_RX_STATS (0x020A)
+#define RADIOLIB_LR2021_CMD_SET_DEFAULT_RX_TX_TIMEOUT (0x0215)
+#define RADIOLIB_LR2021_CMD_SET_REG_MODE (0x0121)
+#define RADIOLIB_LR2021_CMD_CALIBRATE (0x0122)
+#define RADIOLIB_LR2021_CMD_CALIB_FRONT_END (0x0123)
+#define RADIOLIB_LR2021_CMD_GET_V_BAT (0x0124)
+#define RADIOLIB_LR2021_CMD_GET_TEMP (0x0125)
+#define RADIOLIB_LR2021_CMD_SET_EOL_CONFIG (0x0130)
+#define RADIOLIB_LR2021_CMD_GET_RANDOM_NUMBER (0x0126)
+#define RADIOLIB_LR2021_CMD_GET_STATUS (0x0100)
+#define RADIOLIB_LR2021_CMD_GET_VERSION (0x0101)
+#define RADIOLIB_LR2021_CMD_CLEAR_ERRORS (0x0111)
+#define RADIOLIB_LR2021_CMD_GET_ERRORS (0x0110)
+#define RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION (0x0112)
+#define RADIOLIB_LR2021_CMD_SET_DIO_RF_SWITCH_CONFIG (0x0113)
+#define RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG (0x0115)
+#define RADIOLIB_LR2021_CMD_CLEAR_IRQ (0x0116)
+#define RADIOLIB_LR2021_CMD_GET_AND_CLEAR_IRQ_STATUS (0x0117)
+#define RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ (0x011A)
+#define RADIOLIB_LR2021_CMD_GET_FIFO_IRQ_FLAGS (0x011B)
+#define RADIOLIB_LR2021_CMD_CLEAR_FIFO_IRQ_FLAGS (0x0114)
+#define RADIOLIB_LR2021_CMD_GET_AND_CLEAR_FIFO_IRQ_FLAGS (0x012E)
+#define RADIOLIB_LR2021_CMD_GET_RX_FIFO_LEVEL (0x011C)
+#define RADIOLIB_LR2021_CMD_GET_TX_FIFO_LEVEL (0x011D)
+#define RADIOLIB_LR2021_CMD_CLEAR_RX_FIFO (0x011E)
+#define RADIOLIB_LR2021_CMD_CLEAR_TX_FIFO (0x011F)
+#define RADIOLIB_LR2021_CMD_CONFIG_LF_CLOCK (0x0118)
+#define RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS (0x0119)
+#define RADIOLIB_LR2021_CMD_SET_TCXO_MODE (0x0120)
+#define RADIOLIB_LR2021_CMD_SET_XOSC_CP_TRIM (0x0131)
+#define RADIOLIB_LR2021_CMD_SET_RF_FREQUENCY (0x0200)
+#define RADIOLIB_LR2021_CMD_SET_RX_PATH (0x0201)
+#define RADIOLIB_LR2021_CMD_GET_RSSI_INST (0x020B)
+#define RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION (0x0205)
+#define RADIOLIB_LR2021_CMD_SET_TIMESTAMP_SOURCE (0x0216)
+#define RADIOLIB_LR2021_CMD_GET_TIMESTAMP_VALUE (0x0217)
+#define RADIOLIB_LR2021_CMD_SET_CCA (0x0218)
+#define RADIOLIB_LR2021_CMD_GET_CCA_RESULT (0x0219)
+#define RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL (0x021A)
+#define RADIOLIB_LR2021_CMD_SET_CAD_PARAMS (0x021B)
+#define RADIOLIB_LR2021_CMD_SET_CAD (0x021C)
+#define RADIOLIB_LR2021_CMD_SEL_PA (0x020F)
+#define RADIOLIB_LR2021_CMD_SET_PA_CONFIG (0x0202)
+#define RADIOLIB_LR2021_CMD_SET_TX_PARAMS (0x0203)
+#define RADIOLIB_LR2021_CMD_SET_PACKET_TYPE (0x0207)
+#define RADIOLIB_LR2021_CMD_GET_PACKET_TYPE (0x0208)
+#define RADIOLIB_LR2021_CMD_SET_LORA_MODULATION_PARAMS (0x0220)
+#define RADIOLIB_LR2021_CMD_SET_LORA_PACKET_PARAMS (0x0221)
+#define RADIOLIB_LR2021_CMD_SET_LORA_SYNCH_TIMEOUT (0x0222)
+#define RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD (0x0223)
+#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CONFIG (0x0224)
+#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_SYNCWORD (0x0225)
+#define RADIOLIB_LR2021_CMD_SET_LORA_CAD_PARAMS (0x0227)
+#define RADIOLIB_LR2021_CMD_SET_LORA_CAD (0x0228)
+#define RADIOLIB_LR2021_CMD_GET_LORA_RX_STATS (0x0229)
+#define RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS (0x022A)
+#define RADIOLIB_LR2021_CMD_SET_LORA_ADDRESS (0x022B)
+#define RADIOLIB_LR2021_CMD_SET_LORA_HOPPING (0x022C)
+#define RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC (0x021D)
+#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CAD (0x021E)
+#define RADIOLIB_LR2021_CMD_SET_RANGING_ADDR (0x0278)
+#define RADIOLIB_LR2021_CMD_SET_RANGING_REQ_ADDR (0x0279)
+#define RADIOLIB_LR2021_CMD_GET_RANGING_RESULT (0x027A)
+#define RADIOLIB_LR2021_CMD_GET_RANGING_STATS (0x027D)
+#define RADIOLIB_LR2021_CMD_SET_RANGING_TX_RX_DELAY (0x027B)
+#define RADIOLIB_LR2021_CMD_SET_RANGING_PARAMS (0x027C)
+#define RADIOLIB_LR2021_CMD_SET_GFSK_MODULATION_PARAMS (0x0240)
+#define RADIOLIB_LR2021_CMD_SET_GFSK_PACKET_PARAMS (0x0241)
+#define RADIOLIB_LR2021_CMD_SET_GFSK_WHITENING_PARAMS (0x0242)
+#define RADIOLIB_LR2021_CMD_SET_GFSK_CRC_PARAMS (0x0243)
+#define RADIOLIB_LR2021_CMD_SET_GFSK_SYNCWORD (0x0244)
+#define RADIOLIB_LR2021_CMD_SET_GFSK_ADDRESS (0x0245)
+#define RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS (0x0246)
+#define RADIOLIB_LR2021_CMD_GET_GFSK_PACKET_STATUS (0x0247)
+#define RADIOLIB_LR2021_CMD_SET_WMBUS_PARAMS (0x026A)
+#define RADIOLIB_LR2021_CMD_GET_WMBUS_RX_STATS (0x026C)
+#define RADIOLIB_LR2021_CMD_GET_WMBUS_PACKET_STATUS (0x026D)
+#define RADIOLIB_LR2021_CMD_SET_WMBUS_FILTERING_ADDRESS (0x026E)
+#define RADIOLIB_LR2021_CMD_SET_WISUN_MODE (0x0270)
+#define RADIOLIB_LR2021_CMD_SET_WISUN_PACKET_PARAMS (0x0271)
+#define RADIOLIB_LR2021_CMD_GET_WISUN_RX_STATS (0x0272)
+#define RADIOLIB_LR2021_CMD_GET_WISUN_PACKET_STATUS (0x0273)
+#define RADIOLIB_LR2021_CMD_SET_WISUN_PACKET_LEN (0x0274)
+#define RADIOLIB_LR2021_CMD_SET_ZWAVE_PARAMS (0x0297)
+#define RADIOLIB_LR2021_CMD_SET_ZWAVE_HOME_ID_FILTERING (0x0298)
+#define RADIOLIB_LR2021_CMD_GET_ZWAVE_RX_STATS (0x0299)
+#define RADIOLIB_LR2021_CMD_GET_ZWAVE_PACKET_STATUS (0x029A)
+#define RADIOLIB_LR2021_CMD_SET_ZWAVE_BEAM_FILTERING (0x029B)
+#define RADIOLIB_LR2021_CMD_SET_ZWAVE_SCAN_CONFIG (0x029C)
+#define RADIOLIB_LR2021_CMD_SET_ZWAVE_SCAN (0x029D)
+#define RADIOLIB_LR2021_CMD_SET_BLE_MODULATION_PARAMS (0x0260)
+#define RADIOLIB_LR2021_CMD_SET_BLE_CHANNEL_PARAMS (0x0261)
+#define RADIOLIB_LR2021_CMD_SET_BLE_PDU_LEN (0x0266)
+#define RADIOLIB_LR2021_CMD_SET_BLE_TX (0x0262)
+#define RADIOLIB_LR2021_CMD_GET_BLE_RX_STATS (0x0264)
+#define RADIOLIB_LR2021_CMD_GET_BLE_PACKET_STATUS (0x0265)
+#define RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS (0x029F)
+#define RADIOLIB_LR2021_CMD_GET_OQPSK_RX_STATS (0x02A0)
+#define RADIOLIB_LR2021_CMD_GET_OQPSK_PACKET_STATUS (0x02A1)
+#define RADIOLIB_LR2021_CMD_SET_OQPSK_PACKET_LEN (0x02A2)
+#define RADIOLIB_LR2021_CMD_SET_OQPSK_ADDRESS (0x02A3)
+#define RADIOLIB_LR2021_CMD_SET_BPSK_MODULATION_PARAMS (0x0250)
+#define RADIOLIB_LR2021_CMD_SET_BPSK_PACKET_PARAMS (0x0251)
+#define RADIOLIB_LR2021_CMD_SET_FLRC_MODULATION_PARAMS (0x0248)
+#define RADIOLIB_LR2021_CMD_SET_FLRC_PACKET_PARAMS (0x0249)
+#define RADIOLIB_LR2021_CMD_GET_FLRC_RX_STATS (0x024A)
+#define RADIOLIB_LR2021_CMD_GET_FLRC_PACKET_STATUS (0x024B)
+#define RADIOLIB_LR2021_CMD_SET_FLRC_SYNCWORD (0x024C)
+#define RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME (0x0256)
+#define RADIOLIB_LR2021_CMD_LR_FHSS_SET_SYNCWORD (0x0257)
+#define RADIOLIB_LR2021_CMD_SET_OOK_MODULATION_PARAMS (0x0281)
+#define RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS (0x0282)
+#define RADIOLIB_LR2021_CMD_SET_OOK_CRC_PARAMS (0x0283)
+#define RADIOLIB_LR2021_CMD_SET_OOK_SYNCWORD (0x0284)
+#define RADIOLIB_LR2021_CMD_SET_OOK_ADDRESS (0x0285)
+#define RADIOLIB_LR2021_CMD_GET_OOK_RX_STATS (0x0286)
+#define RADIOLIB_LR2021_CMD_GET_OOK_PACKET_STATUS (0x0287)
+#define RADIOLIB_LR2021_CMD_SET_OOK_DETECTOR (0x0288)
+#define RADIOLIB_LR2021_CMD_SET_OOK_WHITENING_PARAMS (0x0289)
+#define RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE (0x020E)
+
+// RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG
+#define RADIOLIB_LR2021_IRQ_RX_FIFO (0x01UL << 0) // 31 0 interrupt: Rx FIFO threshold reached
+#define RADIOLIB_LR2021_IRQ_TX_FIFO (0x01UL << 1) // 31 0 Tx FIFO threshold reached
+#define RADIOLIB_LR2021_IRQ_RNG_REQ_VALID (0x01UL << 2) // 31 0 ranging slave received valid request
+#define RADIOLIB_LR2021_IRQ_TX_TIMESTAMP (0x01UL << 3) // 31 0 end of packet Tx timestamp
+#define RADIOLIB_LR2021_IRQ_RX_TIMESTAMP (0x01UL << 4) // 31 0 end of packet Rx timestamp
+#define RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED (0x01UL << 5) // 31 0 preamble detected
+#define RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID (0x01UL << 6) // 31 0 LoRa header received and valid
+#define RADIOLIB_LR2021_IRQ_SYNCWORD_VALID (0x01UL << 6) // 31 0 sync word valid
+#define RADIOLIB_LR2021_IRQ_CAD_DETECTED (0x01UL << 7) // 31 0 channel activity detected
+#define RADIOLIB_LR2021_IRQ_LORA_HDR_TIMESTAMP (0x01UL << 8) // 31 0 LoRa header timestamp
+#define RADIOLIB_LR2021_IRQ_LORA_HDR_CRC_ERROR (0x01UL << 9) // 31 0 LoRa header CRC error
+#define RADIOLIB_LR2021_IRQ_EOL (0x01UL << 10) // 31 0 end of life
+#define RADIOLIB_LR2021_IRQ_PA_OCP_OVP (0x01UL << 11) // 31 0 PA overcurrent/overvoltage triggered
+#define RADIOLIB_LR2021_IRQ_LORA_TX_RX_HOP (0x01UL << 12) // 31 0 LoRa intra-packet hopping
+#define RADIOLIB_LR2021_IRQ_SYNC_FAIL (0x01UL << 13) // 31 0 sync word match detection failed
+#define RADIOLIB_LR2021_IRQ_LORA_SYMBOL_END (0x01UL << 14) // 31 0 symbol end
+#define RADIOLIB_LR2021_IRQ_LORA_TIMESTAMP_STAT (0x01UL << 15) // 31 0 new stats available
+#define RADIOLIB_LR2021_IRQ_ERROR (0x01UL << 16) // 31 0 error other than command error
+#define RADIOLIB_LR2021_IRQ_CMD_ERROR (0x01UL << 17) // 31 0 command error
+#define RADIOLIB_LR2021_IRQ_RX_DONE (0x01UL << 18) // 31 0 packet received
+#define RADIOLIB_LR2021_IRQ_TX_DONE (0x01UL << 19) // 31 0 packet transmitted
+#define RADIOLIB_LR2021_IRQ_CAD_DONE (0x01UL << 20) // 31 0 CAD finished
+#define RADIOLIB_LR2021_IRQ_TIMEOUT (0x01UL << 21) // 31 0 Rx or Tx timeout
+#define RADIOLIB_LR2021_IRQ_CRC_ERROR (0x01UL << 22) // 31 0 CRC error
+#define RADIOLIB_LR2021_IRQ_LEN_ERROR (0x01UL << 23) // 31 0 length error on received packet
+#define RADIOLIB_LR2021_IRQ_ADDR_ERROR (0x01UL << 24) // 31 0 packet with incorrect address received
+#define RADIOLIB_LR2021_IRQ_FHSS (0x01UL << 25) // 31 0 FHSS intra-packet hopping
+#define RADIOLIB_LR2021_IRQ_INTER_PACKET_FREQ (0x01UL << 26) // 31 0 inter packet hopping can load new frequency table
+#define RADIOLIB_LR2021_IRQ_INTER_NEW_PAYLOAD (0x01UL << 27) // 31 0 inter packet hopping can load new payload
+#define RADIOLIB_LR2021_IRQ_RNG_RESP_DONE (0x01UL << 28) // 31 0 slave ranging response sent
+#define RADIOLIB_LR2021_IRQ_RNG_REQ_DIS (0x01UL << 29) // 31 0 ranging request discarded
+#define RADIOLIB_LR2021_IRQ_RNG_EXCH_VALID (0x01UL << 30) // 31 0 master receive valid ranging response
+#define RADIOLIB_LR2021_IRQ_RNG_TIMEOUT (0x01UL << 31) // 31 0 ranging timeout
+#define RADIOLIB_LR2021_IRQ_ALL (0xFFFFFFFFUL) // 31 0 all interrupts
+
+// RADIOLIB_LR2021_CMD_SET_SLEEP
+#define RADIOLIB_LR2021_SLEEP_32K_CLK_DISABLED (0x00UL << 0) // 0 0 32 kHz clock: disabled
+#define RADIOLIB_LR2021_SLEEP_32K_CLK_ENABLED (0x01UL << 0) // 0 0 enabled
+#define RADIOLIB_LR2021_SLEEP_RETENTION_DISABLED (0x00UL << 1) // 1 1 configuration retention in sleep mode: disabled
+#define RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED (0x01UL << 1) // 1 1 enabled
+
+// RADIOLIB_LR2021_CMD_SET_STANDBY
+#define RADIOLIB_LR2021_STANDBY_RC (0x00UL << 0) // 7 0 standby mode: RC oscillator
+#define RADIOLIB_LR2021_STANDBY_XOSC (0x01UL << 0) // 7 0 XOSC oscillator
+
+// RADIOLIB_LR2021_CMD_SET_RX
+#define RADIOLIB_LR2021_RX_TIMEOUT_NONE (0x000000UL) // 23 0 Rx timeout duration: no timeout (Rx single mode)
+#define RADIOLIB_LR2021_RX_TIMEOUT_INF (0xFFFFFFUL) // 23 0 infinite (Rx continuous mode)
+
+// RADIOLIB_LR2021_CMD_SET_TX
+#define RADIOLIB_LR2021_TX_TIMEOUT_NONE (0x000000UL) // 23 0 disable Tx timeout
+
+// RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE
+#define RADIOLIB_LR2021_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC
+#define RADIOLIB_LR2021_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC
+#define RADIOLIB_LR2021_FALLBACK_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis
+
+// RADIOLIB_LR2021_CMD_SET_RX_DUTY_CYCLE
+#define RADIOLIB_LR2021_RX_DUTY_CYCLE_MODE_RX (0x00UL << 0) // 0 0 mode in Rx windows: Rx (default)
+#define RADIOLIB_LR2021_RX_DUTY_CYCLE_MODE_CAD (0x01UL << 0) // 0 0 CAD
+
+// RADIOLIB_LR20210_CMD_AUTO_TX_RX
+#define RADIOLIB_LR2021_AUTO_MODE_NONE (0x00UL << 0) // 1 0 auto rx-tx mode: never enable auto rx-tx
+#define RADIOLIB_LR2021_AUTO_MODE_ALWAYS (0x01UL << 0) // 1 0 auto rx-tx on every RxDone or TxDone event
+#define RADIOLIB_LR2021_AUTO_MODE_OK (0x02UL << 0) // 1 0 auto rx-tx on valid Rx packet only (Tx always)
+#define RADIOLIB_LR2021_AUTO_MODE_CLEAR_DISABLED (0x00UL << 7) // 7 7 automatically disable auto rx-tx on timeout: disabled
+#define RADIOLIB_LR2021_AUTO_MODE_CLEAR_ENABLED (0x01UL << 7) // 7 7 enabled
+
+// RADIOLIB_LR2021_CMD_SET_REG_MODE
+#define RADIOLIB_LR2021_REG_MODE_SIMO_OFF (0x00UL << 0) // 7 0 SIMO mode: disabled
+#define RADIOLIB_LR2021_REG_MODE_SIMO_NORMAL (0x02UL << 0) // 7 0 normal
+#define RADIOLIB_LR2021_REG_MODE_RAMP_RES_2_US (0x00UL << 5) // 6 5 ramp timing resolution: 2 us
+#define RADIOLIB_LR2021_REG_MODE_RAMP_RES_4_US (0x01UL << 5) // 6 5 4 us
+#define RADIOLIB_LR2021_REG_MODE_RAMP_RES_8_US (0x02UL << 5) // 6 5 8 us
+#define RADIOLIB_LR2021_REG_MODE_RAMP_RES_16_US (0x03UL << 5) // 6 5 16 us
+#define RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RC2RU (0)
+#define RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_TX2RU (1)
+#define RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RU2RC (2)
+#define RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RAMP_DOWN (3)
+
+// RADIOLIB_LR2021_CMD_CALIBRATE
+#define RADIOLIB_LR2021_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 blocks to calibrate: low-frequency RC
+#define RADIOLIB_LR2021_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high-frequency RC
+#define RADIOLIB_LR2021_CALIBRATE_PLL (0x01UL << 2) // 2 2 phase-locked loop
+#define RADIOLIB_LR2021_CALIBRATE_AAF (0x01UL << 3) // 3 3 anti-aliasing filter
+#define RADIOLIB_LR2021_CALIBRATE_MU (0x01UL << 5) // 4 4 measurement unit
+#define RADIOLIB_LR2021_CALIBRATE_PA_OFF (0x01UL << 6) // 5 5 power amplifier offset
+#define RADIOLIB_LR2021_CALIBRATE_ALL (0x6FUL << 0) // 7 0 everything
+
+// RADIOLIB_LR2021_CMD_CALIB_FRONT_END
+#define RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH (0x00UL << 15) // 15 15 calibration path: low-frequency
+#define RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH (0x01UL << 15) // 15 15 high-frequency
+#define RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG_MHZ (20.0f)
+#define RADIOLIB_LR2021_LF_CUTOFF_FREQ (1500.0f)
+
+// RADIOLIB_LR2021_CMD_GET_V_BAT
+#define RADIOLIB_LR2021_VBAT_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw
+#define RADIOLIB_LR2021_VBAT_FORMAT_MV (0x01UL << 3) // 3 3 millivolts
+#define RADIOLIB_LR2021_MEAS_RESOLUTION_OFFSET (8)
+
+// RADIOLIB_LR2021_CMD_GET_TEMP
+#define RADIOLIB_LR2021_TEMP_SOURCE_VBE (0x00UL << 4) // 4 4 temperature source: sensor near Vbe junction
+#define RADIOLIB_LR2021_TEMP_SOURCE_XOSC (0x01UL << 4) // 4 4 sensor near XOSC
+#define RADIOLIB_LR2021_TEMP_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw
+#define RADIOLIB_LR2021_TEMP_FORMAT_DEG_C (0x01UL << 3) // 3 3 degrees Celsius
+
+// RADIOLIB_LR2021_CMD_SET_EOL_CONFIG
+#define RADIOLIB_LR2021_EOL_TRIM_1V6 (0x00UL << 1) // 3 1 EoL trigger threshold: 1.60 V
+#define RADIOLIB_LR2021_EOL_TRIM_1V67 (0x01UL << 1) // 3 1 1.67 V
+#define RADIOLIB_LR2021_EOL_TRIM_1V74 (0x02UL << 1) // 3 1 1.74 V
+#define RADIOLIB_LR2021_EOL_TRIM_1V8 (0x03UL << 1) // 3 1 1.80 V
+#define RADIOLIB_LR2021_EOL_TRIM_1V88 (0x04UL << 1) // 3 1 1.88 V (default)
+#define RADIOLIB_LR2021_EOL_TRIM_1V95 (0x05UL << 1) // 3 1 1.95 V
+#define RADIOLIB_LR2021_EOL_TRIM_2V0 (0x06UL << 1) // 3 1 2.00 V
+#define RADIOLIB_LR2021_EOL_TRIM_2V1 (0x07UL << 1) // 3 1 2.10 V
+
+// RADIOLIB_LR2021_CMD_GET_ERRORS
+#define RADIOLIB_LR2021_HF_XOSC_START_ERR (0x01UL << 0) // 15 0 error: high-frequency XOSC failed to start
+#define RADIOLIB_LR2021_LF_XOSC_START_ERR (0x01UL << 1) // 15 0 low-frequency XOSC failed to start
+#define RADIOLIB_LR2021_PLL_LOCK_ERR (0x01UL << 2) // 15 0 PLL failed to lock
+#define RADIOLIB_LR2021_LF_RC_CALIB_ERR (0x01UL << 3) // 15 0 low-frequency RC calibration failed
+#define RADIOLIB_LR2021_HF_RC_CALIB_ERR (0x01UL << 4) // 15 0 high-frequency RC calibration failed
+#define RADIOLIB_LR2021_PLL_CALIB_ERR (0x01UL << 5) // 15 0 PLL calibration failed
+#define RADIOLIB_LR2021_AAF_CALIB_ERR (0x01UL << 6) // 15 0 anti-aliasing filter calibration failed
+#define RADIOLIB_LR2021_IMG_CALIB_ERR (0x01UL << 7) // 15 0 image rejection calibration failed
+#define RADIOLIB_LR2021_CHIP_BUSY_ERR (0x01UL << 8) // 15 0 Tx or Rx could not be processed because chips was busy
+#define RADIOLIB_LR2021_RXFREQ_NO_FE_CAL_ERR (0x01UL << 9) // 15 0 front-end calibration nto available for this Rx frequency
+#define RADIOLIB_LR2021_MEAS_UNIT_ADC_CALIB_ERR (0x01UL << 10) // 15 0 measurement unit ADC calibration failed
+#define RADIOLIB_LR2021_PA_OFFSET_CALIB_ERR (0x01UL << 11) // 15 0 PA offset calibration failed
+#define RADIOLIB_LR2021_PPF_CALIB_ERR (0x01UL << 12) // 15 0 poly-phase filter calibration failed
+#define RADIOLIB_LR2021_SRC_CALIB_ERR (0x01UL << 13) // 15 0 self-reception cancellation calibration failed
+#define RADIOLIB_LR2021_SRC_SATURATION_CALIB_ERR (0x01UL << 14) // 15 0 RSSI saturation during SRC calibration
+#define RADIOLIB_LR2021_SRC_TOLERANCE_CALIB_ERR (0x01UL << 15) // 15 0 self-reception cancellation values out of tolernce
+
+// RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION
+#define RADIOLIB_LR2021_DIO_FUNCTION_NONE (0x00UL << 4) // 7 4 DIO function: none
+#define RADIOLIB_LR2021_DIO_FUNCTION_IRQ (0x01UL << 4) // 7 4 interrupt
+#define RADIOLIB_LR2021_DIO_FUNCTION_RF_SWITCH (0x02UL << 4) // 7 4 RF switch
+#define RADIOLIB_LR2021_DIO_FUNCTION_GPIO_OUTPUT_LOW (0x05UL << 4) // 7 4 low output
+#define RADIOLIB_LR2021_DIO_FUNCTION_GPIO_OUTPUT_HIGH (0x06UL << 4) // 7 4 high output
+#define RADIOLIB_LR2021_DIO_FUNCTION_HF_CLK_OUT (0x07UL << 4) // 7 4 high-frequency clock output
+#define RADIOLIB_LR2021_DIO_FUNCTION_LF_CLK_OUT (0x08UL << 4) // 7 4 low-frequency clock output (DIO7-11 only)
+#define RADIOLIB_LR2021_DIO_FUNCTION_TX_TRIGGER (0x09UL << 4) // 7 4 Tx trigger
+#define RADIOLIB_LR2021_DIO_FUNCTION_RX_TRIGGER (0x0AUL << 4) // 7 4 Rx trigger
+#define RADIOLIB_LR2021_DIO_SLEEP_PULL_NONE (0x00UL << 0) // 3 0 pull up/down in sleep mode: none
+#define RADIOLIB_LR2021_DIO_SLEEP_PULL_DOWN (0x01UL << 0) // 3 0 pull-down
+#define RADIOLIB_LR2021_DIO_SLEEP_PULL_UP (0x02UL << 0) // 3 0 pull-up
+#define RADIOLIB_LR2021_DIO_SLEEP_PULL_AUTO (0x03UL << 0) // 3 0 auto
+
+// RADIOLIB_LR2021_CMD_SET_DIO_RF_SWITCH_CONFIG
+#define RADIOLIB_LR2021_DIO5 (RADIOLIB_LRXXXX_DIOx(0))
+#define RADIOLIB_LR2021_DIO6 (RADIOLIB_LRXXXX_DIOx(1))
+#define RADIOLIB_LR2021_DIO7 (RADIOLIB_LRXXXX_DIOx(2))
+#define RADIOLIB_LR2021_DIO8 (RADIOLIB_LRXXXX_DIOx(3))
+#define RADIOLIB_LR2021_DIO9 (RADIOLIB_LRXXXX_DIOx(4))
+#define RADIOLIB_LR2021_DIO10 (RADIOLIB_LRXXXX_DIOx(5))
+#define RADIOLIB_LR2021_DIO11 (RADIOLIB_LRXXXX_DIOx(6))
+
+// RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ
+#define RADIOLIB_LR2021_FIFO_IRQ_EMPTY (0x01UL << 0) // 7 0 FIFO interrupt on: empty FIFO
+#define RADIOLIB_LR2021_FIFO_IRQ_LOW (0x01UL << 1) // 7 0 level below threshold
+#define RADIOLIB_LR2021_FIFO_IRQ_HIGH (0x01UL << 2) // 7 0 level above threshold
+#define RADIOLIB_LR2021_FIFO_IRQ_FULL (0x01UL << 3) // 7 0 full FIFO
+#define RADIOLIB_LR2021_FIFO_IRQ_OVERFLOW (0x01UL << 4) // 7 0 overflow
+#define RADIOLIB_LR2021_FIFO_IRQ_UNDERFLOW (0x01UL << 5) // 7 0 underflow
+
+// RADIOLIB_LR2021_CMD_CONFIG_LF_CLOCK
+#define RADIOLIB_LR2021_LF_CLOCK_INTERNAL_RC (0x00UL << 0) // 7 0 low-frequency source: internal 32 kHz RC oscillator
+#define RADIOLIB_LR2021_LF_CLOCK_EXTERNAL (0x02UL << 0) // 7 0 external 32.768 kHz signal on DIO11
+
+// RADIOLIB_LR2021_CMD_SET_RX_PATH
+#define RADIOLIB_LR2021_RX_PATH_LF (0x00UL << 0) // 7 0 Rx path: low-frequency
+#define RADIOLIB_LR2021_RX_PATH_HF (0x01UL << 0) // 7 0 high-frequency
+#define RADIOLIB_LR2021_RX_BOOST_LF (0x00UL << 0) // 7 0 Rx boost: low-frequency
+#define RADIOLIB_LR2021_RX_BOOST_HF (0x04UL << 0) // 7 0 high-frequency
+
+// RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION
+#define RADIOLIB_LR2021_RSSI_PATH_LF (0x01UL << 0) // 0 0 Rx path for RSSI: low-frequency
+#define RADIOLIB_LR2021_RSSI_PATH_HF (0x01UL << 1) // 1 1 high-frequency
+#define RADIOLIB_LR2021_GAIN_TABLE_LENGTH (27)
+
+// RADIOLIB_LR2021_CMD_SET_TIMESTAMP_SOURCE
+#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_NONE (0x00UL << 0) // 3 0 timestamp source: none
+#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_TX_DONE (0x01UL << 0) // 3 0 Tx done
+#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_RX_DONE (0x02UL << 0) // 3 0 Rx done
+#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_SYNC (0x03UL << 0) // 3 0 sync
+#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_HEADER (0x04UL << 0) // 3 0 LoRa header
+
+// RADIOLIB_LR2021_CMD_SET_CAD_PARAMS
+#define RADIOLIB_LR2021_CAD_EXIT_MODE_FALLBACK (0x00UL << 0) // 1 0 CAD exit mode: the configured fallback mode
+#define RADIOLIB_LR2021_CAD_EXIT_MODE_TX (0x01UL << 0) // 1 0 Tx
+#define RADIOLIB_LR2021_CAD_EXIT_MODE_RX (0x02UL << 0) // 1 0 Rx
+#define RADIOLIB_LR2021_CAD_PARAM_DEFAULT (0xFFUL << 0) // 7 0 used by the CAD methods to specify default parameter value
+
+// RADIOLIB_LR2021_CMD_SEL_PA
+#define RADIOLIB_LR2021_PA_LOW_POWER (0x00UL << 0) // 1 0 PA to use: low-power
+#define RADIOLIB_LR2021_PA_HIGH_POWER (0x01UL << 0) // 1 0 high-power
+
+// RADIOLIB_LR2021_CMD_SET_PA_CONFIG
+#define RADIOLIB_LR2021_PA_LF_MODE_FSM (0x00UL << 0) // 1 0 PA LF mode: full single-ended mode
+#define RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED (0x06UL << 0) // 7 4 PA LF duty cycle: PA not used (nibble; packed in setPaConfig)
+#define RADIOLIB_LR2021_PA_LF_SLICES_UNUSED (0x07UL << 0) // 3 0 PA LF slices: PA not used
+#define RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED (0x10UL << 0) // 4 0 PA HF duty cycle: PA not used
+
+// RADIOLIB_LR2021_CMD_SET_PACKET_TYPE
+#define RADIOLIB_LR2021_PACKET_TYPE_LORA (0x00UL << 0) // 7 0 packet type: LoRa
+#define RADIOLIB_LR2021_PACKET_TYPE_GFSK (0x02UL << 0) // 7 0 FSK
+#define RADIOLIB_LR2021_PACKET_TYPE_BLE (0x03UL << 0) // 7 0 BLE
+#define RADIOLIB_LR2021_PACKET_TYPE_RTTOF (0x04UL << 0) // 7 0 RTToF
+#define RADIOLIB_LR2021_PACKET_TYPE_FLRC (0x05UL << 0) // 7 0 FLRC
+#define RADIOLIB_LR2021_PACKET_TYPE_BPSK (0x06UL << 0) // 7 0 BPSK
+#define RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS (0x07UL << 0) // 7 0 LR-FHSS
+#define RADIOLIB_LR2021_PACKET_TYPE_WM_BUS (0x08UL << 0) // 7 0 WM-BUS
+#define RADIOLIB_LR2021_PACKET_TYPE_WI_SUN (0x09UL << 0) // 7 0 WI-SUN
+#define RADIOLIB_LR2021_PACKET_TYPE_OOK (0x0AUL << 0) // 7 0 OOK
+#define RADIOLIB_LR2021_PACKET_TYPE_RAW (0x0BUL << 0) // 7 0 RAW
+#define RADIOLIB_LR2021_PACKET_TYPE_Z_WAVE (0x0CUL << 0) // 7 0 Z-WAVE
+#define RADIOLIB_LR2021_PACKET_TYPE_OQPSK (0x0DUL << 0) // 7 0 OQPSK
+#define RADIOLIB_LR2021_PACKET_TYPE_NONE (0xFFUL << 0) // 2 0 none
+
+// RADIOLIB_LR2021_CMD_SET_LORA_MODULATION_PARAMS
+#define RADIOLIB_LR2021_LORA_BW_31 (0x02UL << 0) // 3 0 LoRa bandwidth: 31.25 kHz
+#define RADIOLIB_LR2021_LORA_BW_41 (0x0AUL << 0) // 3 0 41.67 kHz
+#define RADIOLIB_LR2021_LORA_BW_83 (0x0BUL << 0) // 3 0 83.34 kHz
+#define RADIOLIB_LR2021_LORA_BW_62 (0x03UL << 0) // 3 0 62.50 kHz
+#define RADIOLIB_LR2021_LORA_BW_125 (0x04UL << 0) // 3 0 125 kHz
+#define RADIOLIB_LR2021_LORA_BW_250 (0x05UL << 0) // 3 0 250 kHz
+#define RADIOLIB_LR2021_LORA_BW_500 (0x06UL << 0) // 3 0 500 kHz
+#define RADIOLIB_LR2021_LORA_BW_1000 (0x07UL << 0) // 3 0 1000 kHz
+#define RADIOLIB_LR2021_LORA_BW_812 (0x0FUL << 0) // 3 0 812 kHz
+#define RADIOLIB_LR2021_LORA_BW_406 (0x0EUL << 0) // 3 0 406 kHz
+#define RADIOLIB_LR2021_LORA_BW_203 (0x0DUL << 0) // 3 0 203 kHz
+#define RADIOLIB_LR2021_LORA_BW_101 (0x0CUL << 0) // 3 0 101 kHz
+#define RADIOLIB_LR2021_LORA_CR_4_5 (0x01UL << 0) // 3 0 LoRa coding rate: 4/5
+#define RADIOLIB_LR2021_LORA_CR_4_6 (0x02UL << 0) // 3 0 4/6
+#define RADIOLIB_LR2021_LORA_CR_4_7 (0x03UL << 0) // 3 0 4/7
+#define RADIOLIB_LR2021_LORA_CR_4_8 (0x04UL << 0) // 3 0 4/8
+#define RADIOLIB_LR2021_LORA_CR_4_5_LI (0x05UL << 0) // 3 0 4/5 long interleaver
+#define RADIOLIB_LR2021_LORA_CR_4_6_LI (0x06UL << 0) // 3 0 4/6 long interleaver
+#define RADIOLIB_LR2021_LORA_CR_4_7_LI (0x07UL << 0) // 3 0 4/7 long interleaver
+#define RADIOLIB_LR2021_LORA_LDRO_DISABLED (0x00UL << 0) // 1 0 LDRO/PPM configuration: disabled
+#define RADIOLIB_LR2021_LORA_LDRO_ENABLED (0x01UL << 0) // 1 0 enabled
+
+// RADIOLIB_LR2021_CMD_SET_LORA_PACKET_PARAMS
+#define RADIOLIB_LR2021_LORA_HEADER_EXPLICIT (0x00UL << 2) // 2 2 LoRa header mode: explicit
+#define RADIOLIB_LR2021_LORA_HEADER_IMPLICIT (0x01UL << 2) // 2 2 implicit
+#define RADIOLIB_LR2021_LORA_CRC_DISABLED (0x00UL << 1) // 1 1 LoRa CRC: disabled
+#define RADIOLIB_LR2021_LORA_CRC_ENABLED (0x01UL << 1) // 1 1 enabled
+#define RADIOLIB_LR2021_LORA_IQ_STANDARD (0x00UL << 0) // 0 0 LoRa IQ: standard
+#define RADIOLIB_LR2021_LORA_IQ_INVERTED (0x01UL << 0) // 0 0 inverted
+
+// RADIOLIB_LR2021_CMD_SET_LORA_SYNCH_TIMEOUT
+#define RADIOLIB_LR2021_LORA_SYNCH_TIMEOUT_FORMAT_SYMBOLS (0x00UL << 0) // 7 0 LoRa synch timeout format: number of symbols
+#define RADIOLIB_LR2021_LORA_SYNCH_TIMEOUT_FORMAT_MANT_EXP (0x01UL << 0) // 7 0 mantissa-exponent
+
+// RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD
+#define RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE (0x12UL << 0) // 7 0 LoRa sync word: 0x12 (private networks)
+#define RADIOLIB_LR2021_LORA_SYNC_WORD_LORAWAN (0x34UL << 0) // 7 0 0x34 (LoRaWAN reserved)
+
+// RADIOLIB_LR2021_CMD_SET_LORA_CAD_PARAMS
+#define RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_STANDARD (0x00UL << 0) // 7 0 LoRa CAD speed: normal
+#define RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_FAST (0x08UL << 0) // 7 0 fast CAD
+
+// RADIOLIB_LR2021_CMD_SET_LORA_HOPPING
+#define RADIOLIB_LR2021_LORA_HOPPING_DISABLED (0x00UL << 6) // 7 6 LoRa intra-packet hopping: disabled
+#define RADIOLIB_LR2021_LORA_HOPPING_ENABLED (0x01UL << 6) // 7 6 enabled
+
+// RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC
+#define RADIOLIB_LR2021_LORA_TX_SYNC_DISABLED (0x00UL << 6) // 7 6 Tx sync: disabled
+#define RADIOLIB_LR2021_LORA_TX_SYNC_MASTER (0x01UL << 6) // 7 6 master (wait for signal to transmit sync frame)
+#define RADIOLIB_LR2021_LORA_TX_SYNC_SLAVE (0x02UL << 6) // 7 6 slave (output signal on sync frame)
+
+// RADIOLIB_LR2021_CMD_GET_RANGING_RESULT
+#define RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW (0x00UL << 0) // 7 0 ranging result type: raw
+#define RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW_EXT (0x01UL << 0) // 7 0 extended raw
+#define RADIOLIB_LR2021_RANGING_RESULT_TYPE_GAINS (0x02UL << 0) // 7 0 AGC gain steps
+
+// RADIOLIB_LR2021_CMD_SET_GFSK_MODULATION_PARAMS
+#define RADIOLIB_LR2021_GFSK_BPSK_OOK_BITRATE_BPS (0x00UL << 31) // 7 0 bitrate units: bits per second
+#define RADIOLIB_LR2021_GFSK_BPSK_OOK_BITRATE_FRACTIONAL (0x01UL << 31) // 7 0 fractional (1/256 bps)
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_2_0 (0x02UL << 0) // 7 0 Gaussian, BT = 2.0
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_RRC_ROLLOFF_0_4 (0x03UL << 0) // 7 0 Root-Raised-Cosine with 0.4 roll-off
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_3 (0x04UL << 0) // 7 0 Gaussian, BT = 0.3
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5 (0x05UL << 0) // 7 0 Gaussian, BT = 0.5
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_7 (0x06UL << 0) // 7 0 Gaussian, BT = 0.7
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_1_0 (0x07UL << 0) // 7 0 Gaussian, BT = 1.0
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_RRC_ROLLOFF_0_3 (0x08UL << 0) // 7 0 Root-Raised-Cosine with 0.3 roll-off
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_RRC_ROLLOFF_0_5 (0x09UL << 0) // 7 0 Root-Raised-Cosine with 0.5 roll-off
+#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_RRC_ROLLOFF_0_7 (0x0AUL << 0) // 7 0 Root-Raised-Cosine with 0.7 roll-off
+// TODO implement the other bandwidths as well (and figure out a way how to calculate it)
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8 (39) // 7 0 GFSK Rx bandwidth: 4.8 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8 (215) // 7 0 5.8 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4 (87) // 7 0 7.4 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_9_7 (38) // 7 0 9.6 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_12_0 (30) // 7 0 12.0 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_14_9 (86) // 7 0 14.9 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_19_2 (37) // 7 0 19.2 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_23_1 (213) // 7 0 21.3 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_29_8 (85) // 7 0 29.8 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_38_5 (36) // 7 0 38.5 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_46_3 (212) // 7 0 46.3 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_59_5 (84) // 7 0 59.5 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_76_9 (35) // 7 0 76.9 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_92_6 (211) // 7 0 92.6 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_119_0 (83) // 7 0 119.0 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8 (34) // 7 0 153.8 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_185_2 (210) // 7 0 185.2 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_238_1 (82) // 7 0 238.1 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_307_7 (33) // 7 0 307.7 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_370_4 (209) // 7 0 370.4 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_476_2 (81) // 7 0 476.2 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_555_6 (216) // 7 0 555.6 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_666_7 (152) // 7 0 666.7 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_769_2 (24) // 7 0 769.2 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_1111 (200) // 7 0 1111 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_2222 (192) // 7 0 2222 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666 (128) // 7 0 2667 kHz
+#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076 (0) // 7 0 3077 kHz
+
+// RADIOLIB_LR2021_CMD_SET_GFSK_PACKET_PARAMS
+#define RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled
+#define RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE (0x01UL << 0) // 7 0 node only
+#define RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast
+#define RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED (0x00UL << 0) // 7 0 packet format: fixed length
+#define RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_8BIT (0x01UL << 0) // 7 0 variable, 8-bit length
+#define RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_9BIT (0x02UL << 0) // 7 0 variable, 9-bit length (for SX128x compatibility)
+#define RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_15BIT (0x03UL << 0) // 7 0 variable, 15-bit length
+#define RADIOLIB_LR2021_GFSK_OOK_CRC_OFF (0x00UL << 0) // 7 0 CRC: disabled
+#define RADIOLIB_LR2021_GFSK_OOK_CRC8 (0x01UL << 0) // 7 0 1-byte
+#define RADIOLIB_LR2021_GFSK_OOK_CRC16 (0x02UL << 0) // 7 0 2-byte
+#define RADIOLIB_LR2021_GFSK_OOK_CRC24 (0x03UL << 0) // 7 0 3-byte
+#define RADIOLIB_LR2021_GFSK_OOK_CRC32 (0x04UL << 0) // 7 0 4-byte
+#define RADIOLIB_LR2021_GFSK_OOK_CRC8_INV (0x09UL << 0) // 7 0 1-byte, inverted
+#define RADIOLIB_LR2021_GFSK_OOK_CRC16_INV (0x0AUL << 0) // 7 0 2-byte, inverted
+#define RADIOLIB_LR2021_GFSK_OOK_CRC24_INV (0x0BUL << 0) // 7 0 3-byte, inverted
+#define RADIOLIB_LR2021_GFSK_OOK_CRC32_INV (0x0CUL << 0) // 7 0 4-byte, inverted
+
+// RADIOLIB_LR2021_CMD_SET_GFSK_WHITENING_PARAMS
+#define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX (0x00UL << 0) // 7 0 whitening type: compatible with SX126x and LR2021
+#define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX128X (0x01UL << 0) // 7 0 compatible with SX128x
+
+// RADIOLIB_LR2021_CMD_SET_GFSK_SYNCWORD
+#define RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN (8)
+
+// RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS
+#define RADIOLIB_LR2021_OQPSK_TYPE_15_4 (0x00UL << 0) // 7 0 OQPSK type: 802.15.4 PHY, 250 kbps bit rate
+
+// RADIOLIB_LR2021_CMD_SET_BPSK_PACKET_PARAMS
+#define RADIOLIB_LR2021_BPSK_MODE_RAW (0x00UL << 0) // 7 0 encoding mode: raw
+#define RADIOLIB_LR2021_BPSK_MODE_SIGFOX (0x01UL << 0) // 7 0 SigFox PHY
+
+// RADIOLIB_LR2021_CMD_SET_FLRC_MODULATION_PARAMS
+#define RADIOLIB_LR2021_FLRC_BR_2600 (0x00UL << 0) // 7 0 bitrate/bandwidth: 2600 kbps, 2666 kHz
+#define RADIOLIB_LR2021_FLRC_BR_2080 (0x01UL << 0) // 7 0 2080 kbps, 2222 kHz
+#define RADIOLIB_LR2021_FLRC_BR_1300 (0x02UL << 0) // 7 0 1300 kbps, 1333 kHz
+#define RADIOLIB_LR2021_FLRC_BR_1040 (0x03UL << 0) // 7 0 1040 kbps, 1333 kHz
+#define RADIOLIB_LR2021_FLRC_BR_650 (0x04UL << 0) // 7 0 650 kbps, 888 kHz
+#define RADIOLIB_LR2021_FLRC_BR_520 (0x05UL << 0) // 7 0 520 kbps, 769 kHz
+#define RADIOLIB_LR2021_FLRC_BR_325 (0x06UL << 0) // 7 0 325 kbps, 444 kHz
+#define RADIOLIB_LR2021_FLRC_BR_260 (0x07UL << 0) // 7 0 260 kbps, 444 kHz
+#define RADIOLIB_LR2021_FLRC_CR_1_2 (0x00UL << 0) // 7 0 coding rate: 1/2
+#define RADIOLIB_LR2021_FLRC_CR_3_4 (0x01UL << 0) // 7 0 3/4
+#define RADIOLIB_LR2021_FLRC_CR_1_0 (0x02UL << 0) // 7 0 1 (uncoded)
+#define RADIOLIB_LR2021_FLRC_CR_2_3 (0x03UL << 0) // 7 0 2/3
+
+// RADIOLIB_LR2021_CMD_SET_OOK_MODULATION_PARAMS
+#define RADIOLIB_LR2021_OOK_DEPTH_FULL (0x00UL << 0) // 7 0 magnitude depth: limited by the PA
+#define RADIOLIB_LR2021_OOK_DEPTH_20_DB (0x01UL << 0) // 7 0 20 dB maximum
+
+// RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS
+#define RADIOLIB_LR2021_OOK_MANCHESTER_OFF (0x00UL << 0) // 3 0 Manchester encoding: disabled
+#define RADIOLIB_LR2021_OOK_MANCHESTER_ON (0x01UL << 0) // 3 0 enabled
+#define RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV (0x09UL << 0) // 3 0 enabled, inverted
+
+// RADIOLIB_LR2021_CMD_SET_OOK_SYNCWORD
+#define RADIOLIB_LR2021_OOK_SYNC_WORD_LEN (4)
+
+// RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE
+#define RADIOLIB_LR2021_TX_TEST_MODE_NORMAL_TX (0x00UL << 0) // 7 0 Tx test mode: normal
+#define RADIOLIB_LR2021_TX_TEST_MODE_INF_PREAMBLE (0x01UL << 0) // 7 0 infinite preamble
+#define RADIOLIB_LR2021_TX_TEST_MODE_CW (0x02UL << 0) // 7 0 continuous wave
+#define RADIOLIB_LR2021_TX_TEST_MODE_PRBS9 (0x03UL << 0) // 7 0 pseudo-random bits
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_config.cpp b/lib/RadioLib/src/modules/LR2021/LR2021_config.cpp
new file mode 100644
index 0000000..af8a36b
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_config.cpp
@@ -0,0 +1,1197 @@
+#include "LR2021.h"
+
+#include "../LR11x0/LR_common.h"
+#include "LR2021_registers.h"
+
+#include
+#include
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+// maximum number of allowed frontend calibration attempts
+#define RADIOLIB_LR2021_MAX_CAL_ATTEMPTS (10)
+
+// Sub-GHz: below this RF frequency (MHz) use Table 7-17 (490 MHz ref.); at/above use Table 7-16 (915 MHz ref.).
+#define RADIOLIB_LR2021_LF_PA_TABLE_490_MHZ_MAX (700.0f)
+
+// Table 7-16: Optimal Values for 915 MHz Semtech Reference Design (LF PA).
+// Integer targeted dBm 22..10 only: half-dBm rows (e.g. 21.5) need a future API that passes 0.5 dB steps.
+// SetTxParams first byte = `txHalfDbm` (signed half-dBm); matches datasheet TX_PARAM column * 2.
+static const struct {
+ int8_t txHalfDbm;
+ uint8_t paLfDutyCycle;
+ uint8_t paLfSlices;
+} RADIOLIB_LR2021_TABLE_7_16_915_LF[] = {
+ /* 22 */ { 44, 7, 6 },
+ /* 21 */ { 42, 7, 7 },
+ /* 20 */ { 41, 6, 6 },
+ /* 19 */ { 39, 6, 6 },
+ /* 18 */ { 38, 5, 6 },
+ /* 17 */ { 36, 5, 6 },
+ /* 16 */ { 36, 4, 4 },
+ /* 15 */ { 33, 5, 4 },
+ /* 14 */ { 34, 4, 2 },
+ /* 13 */ { 31, 4, 3 },
+ /* 12 */ { 30, 5, 1 },
+ /* 11 */ { 32, 2, 2 },
+ /* 10 */ { 32, 2, 1 },
+};
+
+// `targetedDbm` integer 10..22 only (Table 7-16 rows).
+static void lr2021Table716LfRow(int8_t targetedDbm, int8_t* txHalfDbm, uint8_t* duty, uint8_t* slices) {
+ if(targetedDbm < 10) { targetedDbm = 10; }
+ if(targetedDbm > 22) { targetedDbm = 22; }
+ const auto& e = RADIOLIB_LR2021_TABLE_7_16_915_LF[22 - targetedDbm];
+ *txHalfDbm = e.txHalfDbm;
+ *duty = e.paLfDutyCycle;
+ *slices = e.paLfSlices;
+}
+
+// Table 7-17: Optimal Values for 490 MHz Semtech Reference Design (LF PA). Integer targeted dBm 20..10.
+static const struct {
+ int8_t txHalfDbm;
+ uint8_t paLfDutyCycle;
+ uint8_t paLfSlices;
+} RADIOLIB_LR2021_TABLE_7_17_490_LF[] = {
+ /* 20 */ { 40, 7, 7 },
+ /* 19 */ { 38, 7, 7 },
+ /* 18 */ { 36, 7, 6 },
+ /* 17 */ { 34, 7, 6 },
+ /* 16 */ { 32, 7, 6 },
+ /* 15 */ { 31, 7, 4 },
+ /* 14 */ { 31, 6, 4 },
+ /* 13 */ { 29, 7, 2 },
+ /* 12 */ { 30, 5, 3 },
+ /* 11 */ { 29, 5, 2 },
+ /* 10 */ { 31, 4, 2 },
+};
+
+static void lr2021Table717LfRow(int8_t targetedDbm, int8_t* txHalfDbm, uint8_t* duty, uint8_t* slices) {
+ if(targetedDbm < 10) { targetedDbm = 10; }
+ if(targetedDbm > 20) { targetedDbm = 20; }
+ const auto& e = RADIOLIB_LR2021_TABLE_7_17_490_LF[20 - targetedDbm];
+ *txHalfDbm = e.txHalfDbm;
+ *duty = e.paLfDutyCycle;
+ *slices = e.paLfSlices;
+}
+
+// Table 7-18: Optimal Values for 2445 MHz Semtech Reference Design (HF PA). Integer targeted dBm 0..12.
+static const struct {
+ int8_t txHalfDbm;
+ uint8_t paHfDutyCycle;
+} RADIOLIB_LR2021_TABLE_7_18_2445_HF[] = {
+ /* 12 */ { 24, 16 },
+ /* 11 */ { 24, 26 },
+ /* 10 */ { 24, 30 },
+ /* 9 */ { 22, 30 },
+ /* 8 */ { 21, 31 },
+ /* 7 */ { 18, 30 },
+ /* 6 */ { 16, 30 },
+ /* 5 */ { 15, 31 },
+ /* 4 */ { 10, 25 },
+ /* 3 */ { 8, 25 },
+ /* 2 */ { 7, 28 },
+ /* 1 */ { 6, 30 },
+ /* 0 */ { 4, 30 },
+};
+
+static void lr2021Table718HfRow(int8_t targetedDbm, int8_t* txHalfDbm, uint8_t* hfDuty) {
+ if(targetedDbm < 0) { targetedDbm = 0; }
+ if(targetedDbm > 12) { targetedDbm = 12; }
+ const auto& e = RADIOLIB_LR2021_TABLE_7_18_2445_HF[12 - targetedDbm];
+ *txHalfDbm = e.txHalfDbm;
+ *hfDuty = e.paHfDutyCycle;
+}
+
+int16_t LR2021::setFrequency(float freq) {
+ return(this->setFrequency(freq, false));
+}
+
+int16_t LR2021::setFrequency(float freq, bool skipCalibration) {
+ #if RADIOLIB_CHECK_PARAMS
+ if(!(((freq >= 150.0f) && (freq <= 1090.0f)) ||
+ ((freq >= 1900.0f) && (freq <= 2200.0f)) ||
+ ((freq >= 2400.0f) && (freq <= 2500.0f)))) {
+ return(RADIOLIB_ERR_INVALID_FREQUENCY);
+ }
+ #endif
+
+ // check if we need to recalibrate image
+ int16_t state;
+ if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG_MHZ)) {
+ // calibration can fail if there is a strong interfering source
+ // run it several times until it passes
+ int i = 0;
+ for(; i < RADIOLIB_LR2021_MAX_CAL_ATTEMPTS; i++) {
+ // get the nearest multiple of 4 MHz
+ uint16_t frequencies[3] = { (uint16_t)((freq / 4.0f) + 0.5f), 0, 0 };
+ frequencies[0] |= (freq > RADIOLIB_LR2021_LF_CUTOFF_FREQ) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH;
+ state = calibrateFrontEnd(const_cast(frequencies));
+
+ // if something failed, check the device errors
+ if(state != RADIOLIB_ERR_NONE) {
+ uint16_t errors = 0;
+ getErrors(&errors);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Frontend calibration #%d failed, device errors: 0x%X", i, errors);
+
+ // if this is caused by something else than RSSI saturation, repeating will not help
+ if((errors & RADIOLIB_LR2021_SRC_SATURATION_CALIB_ERR) == 0) {
+ return(state);
+ }
+
+ // wait a little while before the next attempt
+ this->mod->hal->delay(5);
+
+ } else {
+ // calibration passed
+ break;
+ }
+
+ }
+
+ if(i == RADIOLIB_LR2021_MAX_CAL_ATTEMPTS) {
+ return(RADIOLIB_ERR_FRONTEND_CALIBRATION_FAILED);
+ }
+
+ }
+
+ // set frequency
+ state = setRfFrequency((uint32_t)(freq*1000000.0f));
+ RADIOLIB_ASSERT(state);
+ this->freqMHz = freq;
+ this->highFreq = (freq > RADIOLIB_LR2021_LF_CUTOFF_FREQ);
+ return(state);
+}
+
+int16_t LR2021::setOutputPower(int8_t power) {
+ return(this->setOutputPower(power, 48));
+}
+
+int16_t LR2021::setOutputPower(int8_t power, uint32_t rampTimeUs) {
+ int16_t state = this->checkOutputPower(power, NULL);
+ RADIOLIB_ASSERT(state);
+
+ // pa_sel: 0 = LF (Sub-GHz), 1 = HF (1.9–2.5 GHz). Same encoding as lr20xx reference driver.
+ uint8_t paSel = this->highFreq ? (uint8_t)1 : (uint8_t)0;
+ uint8_t paLfMode = RADIOLIB_LR2021_PA_LF_MODE_FSM;
+ uint8_t paLfDutyCycle = RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED;
+ uint8_t paLfSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED;
+ uint8_t paHfDutyCycle = RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED;
+ // TX_PARAM from tables is signed half-dBm (not always 2 * targeted dBm).
+ int8_t lfTxHalfDbm = (int8_t)(power * 2);
+ int8_t hfTxHalfDbm = (int8_t)(power * 2);
+
+ if(this->highFreq) {
+ // HF PA: Table 7-18 (2445 MHz); LF nibbles per Semtech reference (7/6).
+ paLfDutyCycle = (uint8_t)0x07;
+ paLfSlices = (uint8_t)0x06;
+ if(power >= 0) {
+ lr2021Table718HfRow(power, &hfTxHalfDbm, &paHfDutyCycle);
+ } else {
+ lr2021Table718HfRow(0, &hfTxHalfDbm, &paHfDutyCycle);
+ hfTxHalfDbm = (int8_t)(power * 2);
+ }
+ } else if(this->freqMHz < RADIOLIB_LR2021_LF_PA_TABLE_490_MHZ_MAX) {
+ // LF PA: Table 7-17 (490 MHz ref.), max +20 dBm in table; 21–22 use row 20 PA + requested TX half-dBm.
+ if(power > 20) {
+ lr2021Table717LfRow(20, &lfTxHalfDbm, &paLfDutyCycle, &paLfSlices);
+ lfTxHalfDbm = (int8_t)(power * 2);
+ } else if(power >= 10) {
+ lr2021Table717LfRow(power, &lfTxHalfDbm, &paLfDutyCycle, &paLfSlices);
+ } else {
+ lr2021Table717LfRow(10, &lfTxHalfDbm, &paLfDutyCycle, &paLfSlices);
+ lfTxHalfDbm = (int8_t)(power * 2);
+ }
+ } else {
+ // LF PA: Table 7-16 (915 MHz ref.)
+ if(power >= 10) {
+ lr2021Table716LfRow(power, &lfTxHalfDbm, &paLfDutyCycle, &paLfSlices);
+ } else {
+ lr2021Table716LfRow(10, &lfTxHalfDbm, &paLfDutyCycle, &paLfSlices);
+ lfTxHalfDbm = (int8_t)(power * 2);
+ }
+ }
+
+ (void)clearErrors();
+
+ state = setPaConfig(paSel, paLfMode, paLfDutyCycle, paLfSlices, paHfDutyCycle);
+ RADIOLIB_ASSERT(state);
+ #if RADIOLIB_DEBUG_BASIC
+ RADIOLIB_DEBUG_BASIC_PRINTLN("LR2021 PA cfg: hf=%d lf_dc=0x%X lf_sl=0x%X hf_dc=0x%X",
+ (int)this->highFreq, (int)paLfDutyCycle, (int)paLfSlices, (int)paHfDutyCycle);
+ #endif
+
+ state = selPa(paSel);
+ RADIOLIB_ASSERT(state);
+ #if RADIOLIB_DEBUG_BASIC
+ RADIOLIB_DEBUG_BASIC_PRINTLN("LR2021 PA sel: %s", paSel ? "HF" : "LF");
+ #endif
+
+ if(this->highFreq) {
+ state = setTxParamsHalfDbm(hfTxHalfDbm, roundRampTime(rampTimeUs));
+ } else {
+ state = setTxParamsHalfDbm(lfTxHalfDbm, roundRampTime(rampTimeUs));
+ }
+ RADIOLIB_ASSERT(state);
+ #if RADIOLIB_DEBUG_BASIC
+ uint16_t err = 0;
+ if(getErrors(&err) == RADIOLIB_ERR_NONE) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("LR2021 device errors after PA/TX: 0x%X", err);
+ }
+ #endif
+
+ return(state);
+}
+
+int16_t LR2021::checkOutputPower(int8_t power, int8_t* clipped) {
+ if(this->highFreq) {
+ if(clipped) {
+ *clipped = RADIOLIB_MAX(-19, RADIOLIB_MIN(12, power));
+ }
+ RADIOLIB_CHECK_RANGE(power, -19, 12, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
+
+ } else {
+ if(clipped) {
+ *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power));
+ }
+ RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
+
+ }
+
+ return(RADIOLIB_ERR_NONE);
+}
+
+void LR2021::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
+ // find which pins are used
+ // on LR2021, modes are configured per DIO (exact opposite of LR11x0)
+ uint8_t dioConfigs[7] = { 0 };
+ for(size_t i = 0; i < Module::RFSWITCH_MAX_PINS; i++) {
+ // check if this pin is unused
+ if(pins[i] == RADIOLIB_NC) { continue; }
+
+ // only keep DIO pins, there may be some GPIOs in the switch tabke
+ if((pins[i] & RFSWITCH_PIN_FLAG) == 0) { continue; }
+
+ // find modes in which this pin is used
+ uint32_t dioNum = RADIOLIB_LRXXXX_DIOx_VAL(pins[i]);
+ size_t j = 0;
+ while(table[j].mode != LR2021::MODE_END_OF_TABLE) {
+ dioConfigs[dioNum] |= (table[j].values[i] == this->mod->hal->GpioLevelHigh) ? (1UL << (table[j].mode - 1)) : 0;
+ j++;
+ }
+
+ // For DIO = 5, only DIO_SLEEP_PULL_UP is accepted. Otherwise the SetDioFunction returns FAIL.
+ uint8_t pull = dioNum == 0 ? RADIOLIB_LR2021_DIO_SLEEP_PULL_UP : RADIOLIB_LR2021_DIO_SLEEP_PULL_AUTO;
+ // enable RF control for this pin and set the modes in which it is active
+ (void)this->setDioFunction(dioNum + 5, RADIOLIB_LR2021_DIO_FUNCTION_RF_SWITCH, pull);
+ (void)this->setDioRfSwitchConfig(dioNum + 5, dioConfigs[i]);
+ }
+}
+
+int16_t LR2021::setBandwidth(float bw) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // convert to int to avoid bunch of math
+ int bw_div2 = bw / 2 + 0.01f;
+
+ // check allowed bandwidth values
+ switch (bw_div2) {
+ case 15:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_31;
+ break;
+ case 20:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_41;
+ break;
+ case 31:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_62;
+ break;
+ case 41:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_83;
+ break;
+ case 50:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_101;
+ break;
+ case 101:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_203;
+ break;
+ case 62:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_125;
+ break;
+ case 125:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_250;
+ break;
+ case 203:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_406;
+ break;
+ case 250:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_500;
+ break;
+ case 406:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_812;
+ break;
+ case 500:
+ this->bandwidth = RADIOLIB_LR2021_LORA_BW_1000;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_BANDWIDTH);
+ }
+
+ // update modulation parameters
+ this->bandwidthKhz = bw;
+ return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
+}
+
+int16_t LR2021::setSpreadingFactor(uint8_t sf, bool legacy) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
+
+ //! \TODO: [LR2021] enable SF6 legacy mode
+ if(legacy && (sf == 6)) {
+ //this->mod->SPIsetRegValue(RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT, RADIOLIB_LR11X0_SF6_SX127X, 18, 18);
+ }
+
+ // update modulation parameters
+ this->spreadingFactor = sf;
+ return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
+}
+
+int16_t LR2021::setCodingRate(uint8_t cr, bool longInterleave) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+
+ if(longInterleave) {
+ switch(cr) {
+ case 4:
+ this->codingRate = 0;
+ break;
+ case 5:
+ case 6:
+ this->codingRate = cr;
+ break;
+ case 8:
+ this->codingRate = cr - 1;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_CODING_RATE);
+ }
+
+ } else {
+ this->codingRate = cr - 4;
+
+ }
+
+ // update modulation parameters
+ return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
+ if(cr > RADIOLIB_LR2021_FLRC_CR_2_3) {
+ return(RADIOLIB_ERR_INVALID_CODING_RATE);
+ }
+
+ // update modulation parameters
+ this->codingRateFlrc = cr;
+ return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
+
+ }
+
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t LR2021::setSyncWord(uint8_t syncWord) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ return(setLoRaSyncword(syncWord));
+}
+
+int16_t LR2021::setPreambleLength(size_t preambleLength) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ this->preambleLengthLoRa = preambleLength;
+ return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ this->preambleLengthGFSK = preambleLength;
+ this->preambleDetLength = (preambleLength / 8) << 3;
+ return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
+ this->preambleLengthGFSK = preambleLength;
+ this->preambleDetLength = (preambleLength / 8) << 3;
+ return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
+ if((preambleLength % 4) != 0) {
+ return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
+ }
+ this->preambleLengthGFSK = (preambleLength / 4) - 1;
+ return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH));
+
+ }
+
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t LR2021::setTCXO(float voltage, uint32_t delay) {
+ // check if TCXO is enabled at all
+ if(this->XTAL) {
+ return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
+ }
+
+ // set mode to standby
+ standby();
+
+ // check oscillator startup error flag and clear it
+ uint16_t errors = 0;
+ int16_t state = getErrors(&errors);
+ RADIOLIB_ASSERT(state);
+ if(errors & RADIOLIB_LR2021_HF_XOSC_START_ERR) {
+ clearErrors();
+ }
+
+ // check 0 V disable
+ if(fabsf(voltage - 0.0f) <= 0.001f) {
+ setTcxoMode(0, 0);
+ return(reset());
+ }
+
+ // check allowed voltage values
+ uint8_t tune = 0;
+ if(fabsf(voltage - 1.6f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_6;
+ } else if(fabsf(voltage - 1.7f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_7;
+ } else if(fabsf(voltage - 1.8f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_8;
+ } else if(fabsf(voltage - 2.2f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_2;
+ } else if(fabsf(voltage - 2.4f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_4;
+ } else if(fabsf(voltage - 2.7f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_7;
+ } else if(fabsf(voltage - 3.0f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0;
+ } else if(fabsf(voltage - 3.3f) <= 0.001f) {
+ tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3;
+ } else {
+ return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
+ }
+
+ // calculate delay value
+ uint32_t delayValue = (uint32_t)((float)delay / 30.52f);
+ if(delayValue == 0) {
+ delayValue = 1;
+ }
+
+ // enable TCXO control
+ return(setTcxoMode(tune, delayValue));
+}
+
+int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool inverted) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
+ this->crcTypeLoRa = len > 0;
+ return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ if(len > 4) {
+ return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
+ }
+
+ this->crcTypeGFSK = len;
+ if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) {
+ this->crcTypeGFSK += 0x08;
+ }
+
+ state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
+ RADIOLIB_ASSERT(state);
+
+ return(setGfskCrcParams(polynomial, initial));
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
+ if(len > 4) {
+ return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
+ }
+
+ this->crcTypeGFSK = len;
+ if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) {
+ this->crcTypeGFSK += 0x08;
+ }
+
+ state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
+ RADIOLIB_ASSERT(state);
+
+ return(setOokCrcParams(polynomial, initial));
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
+ if((len == 1) || (len > 4)) {
+ return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
+ }
+
+ this->crcLenGFSK = len ? len - 1 : 0;
+ return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH));
+
+ }
+
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t LR2021::invertIQ(bool enable) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ this->invertIQEnabled = enable;
+ return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
+}
+
+int16_t LR2021::setBitRate(float br) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ //! \TODO: [LR2021] implement fractional bit rate configuration
+ this->bitRate = br * 1000.0f;
+ state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
+ return(state);
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
+ RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ //! \TODO: [LR2021] implement fractional bit rate configuration
+ this->bitRate = br * 1000.0f;
+ //! \TODO: [LR2021] implement OOK magnitude depth configuration
+ state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL);
+ return(state);
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
+ if((uint16_t)br == 260) {
+ this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_260;
+ } else if((uint16_t)br == 325) {
+ this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_325;
+ } else if((uint16_t)br == 520) {
+ this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_520;
+ } else if((uint16_t)br == 650) {
+ this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_650;
+ } else if((uint16_t)br == 1040) {
+ this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1040;
+ } else if((uint16_t)br == 1300) {
+ this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1300;
+ } else if((uint16_t)br == 2080) {
+ this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2080;
+ } else if((uint16_t)br == 2600) {
+ this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2600;
+ } else {
+ return(RADIOLIB_ERR_INVALID_BIT_RATE);
+ }
+
+ // it is slightly weird to reuse the GFSK bitrate variable in this way
+ // but if GFSK gets enabled it should get reset anyway ... I think
+ this->bitRate = br;
+
+ // update modulation parameters
+ return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
+ }
+
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t LR2021::setFrequencyDeviation(float freqDev) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set frequency deviation to lowest available setting (required for digimodes)
+ float newFreqDev = freqDev;
+ if(freqDev < 0.6f) {
+ newFreqDev = 0.6f;
+ }
+
+ RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ this->frequencyDev = newFreqDev * 1000.0f;
+ state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
+ return(state);
+}
+
+int16_t LR2021::setRxBandwidth(float rxBw) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(!((type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) ||
+ (type == RADIOLIB_LR2021_PACKET_TYPE_OOK))) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ const uint8_t rxBwLut[] = {
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_9_7,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_12_0,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_14_9,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_19_2,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_23_1,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_29_8,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_38_5,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_46_3,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_59_5,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_76_9,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_92_6,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_119_0,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_185_2,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_238_1,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_307_7,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_370_4,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_476_2,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_555_6,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_666_7,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_769_2,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_1111,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_2222,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666,
+ RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076,
+ };
+
+ state = findRxBw(rxBw, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), 3076.0f, &this->rxBandwidth);
+ RADIOLIB_ASSERT(state);
+
+ // update modulation parameters
+ if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
+ } else {
+ state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL);
+ }
+ return(state);
+}
+
+int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) {
+ if(len > RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN) {
+ return(RADIOLIB_ERR_INVALID_SYNC_WORD);
+ }
+
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+
+ uint32_t sync = 0;
+ switch(type) {
+ case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
+ // default to MSB-first
+ return(setGfskSyncword(const_cast(syncWord), len, true));
+
+ case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
+ // default to MSB-first
+ return(setOokSyncword(const_cast(syncWord), len, true));
+
+ case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
+ // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
+ if(len > 1) {
+ return(RADIOLIB_ERR_INVALID_SYNC_WORD);
+ }
+ return(setSyncWord(syncWord[0]));
+
+ case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
+ // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
+ if(len != sizeof(uint32_t)) {
+ return(RADIOLIB_ERR_INVALID_SYNC_WORD);
+ }
+ memcpy(&sync, syncWord, sizeof(uint32_t));
+ return(lrFhssSetSyncword(sync));
+
+ case(RADIOLIB_LR2021_PACKET_TYPE_FLRC):
+ // FLRC requires 16 or 32-bit sync word
+ if(!((len == 0) || (len == 2) || (len == 4))) {
+ return(RADIOLIB_ERR_INVALID_SYNC_WORD);
+ }
+
+ // update sync word length
+ this->syncWordLength = len;
+ state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH);
+ RADIOLIB_ASSERT(state);
+
+ sync |= (uint32_t)syncWord[0] << 24;
+ sync |= (uint32_t)syncWord[1] << 16;
+ sync |= (uint32_t)syncWord[2] << 8;
+ sync |= (uint32_t)syncWord[3];
+ return(setFlrcSyncWord(1, sync));
+ }
+
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t LR2021::setDataShaping(uint8_t sh) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+
+ // set data shaping
+ switch(sh) {
+ case RADIOLIB_SHAPING_NONE:
+ this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_NONE;
+ break;
+ case RADIOLIB_SHAPING_0_3:
+ this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_3;
+ break;
+ case RADIOLIB_SHAPING_0_5:
+ this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5;
+ break;
+ case RADIOLIB_SHAPING_0_7:
+ this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_7;
+ break;
+ case RADIOLIB_SHAPING_1_0:
+ this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_1_0;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
+ }
+
+ // update modulation parameters
+ if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
+ return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ return(setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
+ return(setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL));
+ }
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t LR2021::setEncoding(uint8_t encoding) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+
+ switch(type) {
+ case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
+ return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING));
+
+ case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
+ switch(encoding) {
+ case(RADIOLIB_ENCODING_NRZ):
+ case(RADIOLIB_ENCODING_WHITENING):
+ return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING));
+
+ case(RADIOLIB_ENCODING_MANCHESTER):
+ state = setWhitening(false);
+ RADIOLIB_ASSERT(state);
+ this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON;
+ return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
+
+ case(RADIOLIB_ENCODING_MANCHESTER_INV):
+ state = setWhitening(false);
+ RADIOLIB_ASSERT(state);
+ this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV;
+ return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
+
+ default:
+ return(RADIOLIB_ERR_INVALID_ENCODING);
+ }
+
+ default:
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ return(state);
+}
+
+int16_t LR2021::fixedPacketLengthMode(uint8_t len) {
+ return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, len));
+}
+
+int16_t LR2021::variablePacketLengthMode(uint8_t maxLen) {
+ return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_8BIT, maxLen));
+}
+
+int16_t LR2021::setWhitening(bool enabled, uint16_t initial) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+
+ switch(type) {
+ case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
+ //! \TODO: [LR2021] Implement SX128x-compatible whitening
+ if(enabled) {
+ state = setGfskWhiteningParams(RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX, initial);
+ RADIOLIB_ASSERT(state);
+ }
+ this->whitening = enabled;
+ return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
+
+ case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
+ this->whitening = enabled;
+ if(enabled) {
+ //! \TODO: [LR2021] Implement configurable index and polynomial
+ state = setOokWhiteningParams(12, 0x01FF, initial);
+ } else {
+ state = setOokWhiteningParams(0, 0, 0);
+ }
+ RADIOLIB_ASSERT(state);
+ return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
+ }
+
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t LR2021::setDataRate(DataRate_t dr, ModemType_t modem ) {
+ // get the current modem
+ ModemType_t currentModem;
+ int16_t state = this->getModem(¤tModem);
+ RADIOLIB_ASSERT(state);
+
+ // switch over if the requested modem is different
+ if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
+ state = this->standby();
+ RADIOLIB_ASSERT(state);
+ state = this->setModem(modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ if(modem == RADIOLIB_MODEM_NONE) {
+ modem = currentModem;
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ // set the bit rate
+ state = this->setBitRate(dr.fsk.bitRate);
+ RADIOLIB_ASSERT(state);
+
+ // set the frequency deviation
+ state = this->setFrequencyDeviation(dr.fsk.freqDev);
+
+ } else if(modem == RADIOLIB_MODEM_LORA) {
+ // set the spreading factor
+ state = this->setSpreadingFactor(dr.lora.spreadingFactor);
+ RADIOLIB_ASSERT(state);
+
+ // set the bandwidth
+ state = this->setBandwidth(dr.lora.bandwidth);
+ RADIOLIB_ASSERT(state);
+
+ // set the coding rate
+ state = this->setCodingRate(dr.lora.codingRate);
+
+ } else if(modem == RADIOLIB_MODEM_LRFHSS) {
+ // set the basic config
+ state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
+ RADIOLIB_ASSERT(state);
+
+ // set hopping grid
+ this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC;
+
+ }
+
+ return(state);
+}
+
+int16_t LR2021::checkDataRate(DataRate_t dr, ModemType_t modem) {
+ int16_t state = RADIOLIB_ERR_UNKNOWN;
+
+ // retrieve modem if not supplied
+ if(modem == RADIOLIB_MODEM_NONE) {
+ state = this->getModem(&modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ return(RADIOLIB_ERR_NONE);
+
+ } else if(modem == RADIOLIB_MODEM_LORA) {
+ RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
+ RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ return(RADIOLIB_ERR_NONE);
+
+ }
+
+ return(state);
+}
+
+int16_t LR2021::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // check and cache all parameters
+ RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE);
+ this->lrFhssCr = cr;
+ RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ this->lrFhssBw = bw;
+ RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE);
+ this->lrFhssHdrCount = hdrCount;
+ RADIOLIB_CHECK_RANGE((int16_t)hopSeed, (int16_t)0x000, (int16_t)0x1FF, RADIOLIB_ERR_INVALID_DATA_SHAPING);
+ this->lrFhssHopSeq = hopSeed;
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t LR2021::setRxBoostedGainMode(uint8_t level) {
+ int16_t state = this->setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? this->gainModeHf : this->gainModeLf);
+ RADIOLIB_ASSERT(state);
+ if(this->highFreq) {
+ this->gainModeHf = level;
+ } else {
+ this->gainModeLf = level;
+ }
+ return(state);
+}
+
+int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ // set requested packet mode
+ state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
+ RADIOLIB_ASSERT(state);
+
+ // update cached value
+ this->packetType = mode;
+ return(state);
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
+ // set requested packet mode
+ state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
+ RADIOLIB_ASSERT(state);
+
+ // update cached value
+ this->packetType = mode;
+ return(state);
+
+ } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
+ state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, mode == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, len);
+ RADIOLIB_ASSERT(state);
+
+ this->packetType = mode;
+ return(state);
+
+ }
+
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t LR2021::setLoRaHeaderType(uint8_t hdrType, size_t len) {
+ uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&modem);
+ RADIOLIB_ASSERT(state);
+ if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set requested packet mode
+ state = setLoRaPacketParams(this->preambleLengthLoRa, hdrType, len, this->crcTypeLoRa, this->invertIQEnabled);
+ RADIOLIB_ASSERT(state);
+
+ // update cached value
+ this->headerType = hdrType;
+ this->implicitLen = len;
+
+ return(state);
+}
+
+int16_t LR2021::implicitHeader(size_t len) {
+ return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_IMPLICIT, len));
+}
+
+int16_t LR2021::explicitHeader() {
+ return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_EXPLICIT));
+}
+
+int16_t LR2021::setNodeAddress(uint8_t nodeAddr) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // enable address filtering (node only)
+ this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE;
+ state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
+ RADIOLIB_ASSERT(state);
+
+ // set node address
+ this->node = nodeAddr;
+ return(setGfskAddress(this->node, 0));
+}
+
+int16_t LR2021::setBroadcastAddress(uint8_t broadAddr) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // enable address filtering (node and broadcast)
+ this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE_BROADCAST;
+ state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
+ RADIOLIB_ASSERT(state);
+
+ // set node and broadcast address
+ return(setGfskAddress(this->node, broadAddr));
+}
+
+int16_t LR2021::disableAddressFiltering() {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // disable address filtering
+ this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED;
+ return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
+}
+
+int16_t LR2021::ookDetector(uint16_t pattern, uint8_t len, uint8_t repeats, bool syncRaw, bool rising, uint8_t sofLen) {
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_OOK) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ return(setOokDetector(pattern, len - 1, repeats, syncRaw, rising, sofLen));
+}
+
+int16_t LR2021::setOokDetectionThreshold(int16_t level) {
+ int16_t levelRaw = 64 + level;
+ return(this->writeRegMemMask32(RADIOLIB_LR2021_REG_OOK_DETECTION_THRESHOLD, (0x7FUL << 20), (uint32_t)levelRaw << 20));
+}
+
+int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numDetectors) {
+ // some basic sanity checks
+ if((cfg == nullptr) || (numDetectors == 0)) {
+ return(RADIOLIB_ERR_NONE);
+ }
+
+ if(numDetectors > 3) {
+ return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
+ }
+
+ // if bandwidth is higher than 500 kHz, at most 2 side detectors are allowed
+ if((this->bandwidthKhz > 500.0f) && (numDetectors > 2)) {
+ return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
+ }
+
+ // if the primary spreading factor is 10, 11 or 12, at most 2 side detectors are allowed
+ if((this->spreadingFactor >= 10) && (numDetectors > 2)) {
+ return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
+ }
+
+ // condition of the primary spreading factor being the smallest/largest is not checked
+ // this is intentional, because it depends on whether the user wants to start Rx or CAD
+
+ uint8_t detectors[3] = { 0 };
+ uint8_t syncWords[3] = { 0 };
+ uint8_t minSf = this->spreadingFactor;
+ for(size_t i = 0; i < numDetectors; i++) {
+ // all side-detector spreading factors must be higher than the primary one
+ //! \todo [LR2021] implement multi-SF for CAD (main SF must be smallest!)
+ if(this->spreadingFactor >= cfg[i].sf) {
+ return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
+ }
+
+ // the difference between maximum and minimum spreading factor used must be less than or equal to 4
+ if(cfg[i].sf - minSf > 4) {
+ return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
+ }
+
+ if(cfg[i].sf < minSf) { minSf = cfg[i].sf; }
+
+ detectors[i] = cfg[i].sf << 4 | cfg[i].ldro << 2 | cfg[i].invertIQ;
+ syncWords[i] = cfg[i].syncWord;
+ }
+
+ // all spreading factors must be different
+ if(numDetectors >= 2) {
+ if(cfg[0].sf == cfg[1].sf) {
+ return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
+ }
+ }
+
+ if(numDetectors == 3) {
+ if((cfg[1].sf == cfg[2].sf) || (cfg[0].sf == cfg[2].sf)) {
+ return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
+ }
+ }
+
+ // check active modem
+ uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
+ int16_t state = getPacketType(&type);
+ RADIOLIB_ASSERT(state);
+ if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ state = setLoRaSideDetConfig(detectors, numDetectors);
+ RADIOLIB_ASSERT(state);
+
+ return(setLoRaSideDetSyncword(syncWords, numDetectors));
+}
+
+int16_t LR2021::setGain(uint8_t gain) {
+ if(gain > 13) {
+ return(RADIOLIB_ERR_INVALID_GAIN);
+ }
+ return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL, true, &gain, sizeof(gain)));
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_registers.h b/lib/RadioLib/src/modules/LR2021/LR2021_registers.h
new file mode 100644
index 0000000..c39a01a
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_registers.h
@@ -0,0 +1,29 @@
+#if !defined(RADIOLIB_LR2021_REGISTERS_H)
+#define RADIOLIB_LR2021_REGISTERS_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+// LR2021 SPI registers
+#define RADIOLIB_LR2021_REG_DCDC_FREQ_LF (0x80004C)
+#define RADIOLIB_LR2021_REG_DCDC_SWITCHER (0xF20024)
+#define RADIOLIB_LR2021_REG_RTTOF_RSSI_POWER_OFFSET (0xF30128)
+#define RADIOLIB_LR2021_REG_RESULT_DEVIATION_CHANNEL_FILTER (0xF3013C)
+#define RADIOLIB_LR2021_REG_RESULT_DEVIATION_DCC (0xF30134)
+#define RADIOLIB_LR2021_REG_RTTOF_RSSI_MAX_GAIN (0xF301A4)
+#define RADIOLIB_LR2021_REG_LORA_MODEM_TXRX_CFG0 (0xF30A14)
+#define RADIOLIB_LR2021_REG_LORA_MODEM_MAIN_TX_CFG1 (0xF30A24)
+#define RADIOLIB_LR2021_REG_LORA_EXT_FREQ_ERR_CTRL (0xF30A2C)
+#define RADIOLIB_LR2021_REG_RTTOF_EXTENDED_STUCK (0xF30B50)
+#define RADIOLIB_LR2021_REG_BLE_PHY_CODED_FREQ_DRIFT (0xF30C28)
+#define RADIOLIB_LR2021_REG_OOK_DETECTION_THRESHOLD (0xF30E14)
+#define RADIOLIB_LR2021_REG_RTTOF_RF_FREQ (0xF40144)
+#define RADIOLIB_LR2021_REG_DCDC_ADC_CTRL (0xF40200)
+#define RADIOLIB_LR2021_REG_OCP_CONTROL_UNLOCK (0xF40338)
+#define RADIOLIB_LR2021_REG_OCP_THRESHOLDS (0xF40300)
+#define RADIOLIB_LR2021_REG_DCDC_RX_PATH (0xF40430)
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/LR2021/LR2021_types.h b/lib/RadioLib/src/modules/LR2021/LR2021_types.h
new file mode 100644
index 0000000..c04aee3
--- /dev/null
+++ b/lib/RadioLib/src/modules/LR2021/LR2021_types.h
@@ -0,0 +1,42 @@
+#if !defined(RADIOLIB_LR2021_TYPES_H)
+#define RADIOLIB_LR2021_TYPES_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_LR2021
+
+/*!
+ \struct LR2021LrFhssHopTableEntry_t
+ \brief Structure to save information about LR-FHSS hopping table entry.
+*/
+struct LR2021LrFhssHopTableEntry_t {
+ bool hoppingEnable;
+ bool convertFreq;
+ uint16_t packetLen;
+ uint8_t numUsedFrequencies;
+ uint8_t numHoppingBlocks;
+ uint32_t freq;
+ uint16_t numSymbols;
+};
+
+/*!
+ \struct LR2021LoRaSideDetector_t
+ \brief Structure to configure multi-SF detection
+*/
+struct LR2021LoRaSideDetector_t {
+ /*! \brief Spreading factor value */
+ uint8_t sf;
+
+ /*! \brief Low datarate optimization enabled for this detector */
+ bool ldro;
+
+ /*! \brief IQ inversion for this detector */
+ bool invertIQ;
+
+ /*! \brief LoRa sync word for this detector */
+ uint8_t syncWord;
+};
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/RF69/RF69.cpp b/lib/RadioLib/src/modules/RF69/RF69.cpp
index f87270b..c47f6d0 100644
--- a/lib/RadioLib/src/modules/RF69/RF69.cpp
+++ b/lib/RadioLib/src/modules/RF69/RF69.cpp
@@ -2,7 +2,9 @@
#include
#if !RADIOLIB_EXCLUDE_RF69
-RF69::RF69(Module* module) : PhysicalLayer(RADIOLIB_RF69_FREQUENCY_STEP_SIZE, RADIOLIB_RF69_MAX_PACKET_LENGTH) {
+RF69::RF69(Module* module) : PhysicalLayer() {
+ this->freqStep = RADIOLIB_RF69_FREQUENCY_STEP_SIZE;
+ this->maxPacketLength = RADIOLIB_RF69_MAX_PACKET_LENGTH;
this->mod = module;
}
@@ -120,9 +122,12 @@ int16_t RF69::transmit(const uint8_t* data, size_t len, uint8_t addr) {
return(finishTransmit());
}
-int16_t RF69::receive(uint8_t* data, size_t len) {
- // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate)
- RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0);
+int16_t RF69::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
+ RadioLibTime_t timeoutInternal = timeout;
+ if(!timeoutInternal) {
+ // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate)
+ timeoutInternal = 500 + (1.0f/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0f);
+ }
// start reception
int16_t state = startReceive();
@@ -133,9 +138,8 @@ int16_t RF69::receive(uint8_t* data, size_t len) {
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
- if(this->mod->hal->millis() - start > timeout) {
- standby();
- clearIRQFlags();
+ if(this->mod->hal->millis() - start > timeoutInternal) {
+ (void)finishReceive();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
}
@@ -219,7 +223,7 @@ int16_t RF69::packetMode() {
return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE, 6, 5));
}
-void RF69::setAESKey(uint8_t* key) {
+void RF69::setAESKey(const uint8_t* key) {
this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_AES_KEY_1, key, 16);
}
@@ -364,7 +368,7 @@ bool RF69::fifoAdd(uint8_t* data, int totalLen, int* remLen) {
bool RF69::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) {
// get pointer to the correct position in data buffer
- uint8_t* dataPtr = (uint8_t*)&data[*rcvLen];
+ uint8_t* dataPtr = const_cast(&data[*rcvLen]);
// check how much data are we still expecting
uint8_t len = RADIOLIB_RF69_FIFO_THRESH - 1;
@@ -419,12 +423,6 @@ int16_t RF69::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
}
this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, const_cast(data), packetLen);
- // this is a hack, but it seems than in Stream mode, Rx FIFO level is getting triggered 1 byte before it should
- // just add a padding byte that can be dropped without consequence
- if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) {
- this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, '/');
- }
-
// enable +20 dBm operation
if(this->power > 17) {
state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_OFF | 0x0F);
@@ -481,12 +479,20 @@ int16_t RF69::readData(uint8_t* data, size_t len) {
// clear internal flag so getPacketLength can return the new packet length
this->packetLengthQueried = false;
- // clear interrupt flags
- clearIRQFlags();
+ finishReceive();
return(RADIOLIB_ERR_NONE);
}
+int16_t RF69::finishReceive() {
+ // set mode to standby to disable RF switch
+ int16_t state = standby();
+
+ // clear interrupt flags
+ clearIRQFlags();
+ return(state);
+}
+
int16_t RF69::setOOK(bool enable) {
// set OOK and if successful, save the new setting
int16_t state = RADIOLIB_ERR_NONE;
@@ -523,9 +529,9 @@ int16_t RF69::setOokPeakThresholdDecrement(uint8_t value) {
int16_t RF69::setFrequency(float freq) {
// check allowed frequency range
- if(!(((freq > 290.0) && (freq < 340.0)) ||
- ((freq > 431.0) && (freq < 510.0)) ||
- ((freq > 862.0) && (freq < 1020.0)))) {
+ if(!(((freq > 290.0f) && (freq < 340.0f)) ||
+ ((freq > 431.0f) && (freq < 510.0f)) ||
+ ((freq > 862.0f) && (freq < 1020.0f)))) {
return(RADIOLIB_ERR_INVALID_FREQUENCY);
}
@@ -559,7 +565,7 @@ int16_t RF69::getFrequency(float *freq) {
int16_t RF69::setBitRate(float br) {
// datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine
- RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(br, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
// check bitrate-bandwidth ratio
if(!(br < 2000 * this->rxBandwidth)) {
@@ -592,8 +598,8 @@ int16_t RF69::setRxBandwidth(float rxBw) {
// calculate exponent and mantissa values for receiver bandwidth
for(int8_t e = 7; e >= 0; e--) {
for(int8_t m = 2; m >= 0; m--) {
- float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + (this->ookEnabled ? 3 : 2))));
- if(fabsf(rxBw - (point / 1000.0)) <= 0.1) {
+ float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0f)/(((4 * m) + 16) * ((uint32_t)1 << (e + (this->ookEnabled ? 3 : 2))));
+ if(fabsf(rxBw - (point / 1000.0f)) <= 0.1f) {
// set Rx bandwidth
state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, (m << 3) | e, 4, 0);
if(state == RADIOLIB_ERR_NONE) {
@@ -610,8 +616,8 @@ int16_t RF69::setRxBandwidth(float rxBw) {
int16_t RF69::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
- if(freqDev < 0.0) {
- newFreqDev = 0.6;
+ if(freqDev < 0.0f) {
+ newFreqDev = 0.6f;
}
// check frequency deviation range
@@ -648,7 +654,7 @@ int16_t RF69::getFrequencyDeviation(float *freqDev) {
// calculate frequency deviation from raw value obtained from register
// Fdev = Fstep * Fdev(13:0) (pag. 20 of datasheet)
- *freqDev = (1000.0 * fdev * RADIOLIB_RF69_CRYSTAL_FREQ) /
+ *freqDev = (1000.0f * fdev * RADIOLIB_RF69_CRYSTAL_FREQ) /
(uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT);
return(RADIOLIB_ERR_NONE);
@@ -692,9 +698,9 @@ int16_t RF69::setOutputPower(int8_t pwr, bool highPower) {
return(state);
}
-int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) {
+int16_t RF69::setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBits) {
// check constraints
- if((maxErrBits > 7) || (len > 8)) {
+ if((maxErrBits > 7) || (len == 0) || (len > 8)) {
return(RADIOLIB_ERR_INVALID_SYNC_WORD);
}
@@ -705,20 +711,19 @@ int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) {
}
}
+ // enable filtering
int16_t state = enableSyncWordFiltering(maxErrBits);
RADIOLIB_ASSERT(state);
+ // set the length
+ state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, (len-1)<<3, 5, 3);
+
// set sync word register
this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len);
-
- if(state == RADIOLIB_ERR_NONE) {
- this->syncWordLength = len;
- }
-
return(state);
}
-int16_t RF69::setPreambleLength(uint8_t preambleLen) {
+int16_t RF69::setPreambleLength(size_t preambleLen) {
// RF69 configures preamble length in bytes
if(preambleLen % 8 != 0) {
return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
@@ -805,7 +810,11 @@ int16_t RF69::variablePacketLengthMode(uint8_t maxLen) {
int16_t RF69::enableSyncWordFiltering(uint8_t maxErrBits) {
// enable sync word recognition
- return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_ON | RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC | (this->syncWordLength - 1) << 3 | maxErrBits, 7, 0));
+ int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_ON | RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC, 7, 6);
+ RADIOLIB_ASSERT(state);
+
+ // set maximum error bits
+ return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, maxErrBits, 2, 0));
}
int16_t RF69::disableSyncWordFiltering() {
@@ -928,9 +937,9 @@ float RF69::getRSSI() {
}
int16_t RF69::setRSSIThreshold(float dbm) {
- RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD);
+ RADIOLIB_CHECK_RANGE(dbm, -127.5f, 0.0f, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD);
- return this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0);
+ return this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0f * dbm), 7, 0);
}
void RF69::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
diff --git a/lib/RadioLib/src/modules/RF69/RF69.h b/lib/RadioLib/src/modules/RF69/RF69.h
index 00ea43b..fa612a9 100644
--- a/lib/RadioLib/src/modules/RF69/RF69.h
+++ b/lib/RadioLib/src/modules/RF69/RF69.h
@@ -12,7 +12,7 @@
// RF69 physical layer properties
#define RADIOLIB_RF69_FREQUENCY_STEP_SIZE 61.03515625
#define RADIOLIB_RF69_MAX_PACKET_LENGTH 64
-#define RADIOLIB_RF69_CRYSTAL_FREQ 32.0
+#define RADIOLIB_RF69_CRYSTAL_FREQ 32.0f
#define RADIOLIB_RF69_DIV_EXPONENT 19
// RF69 register map
@@ -528,11 +528,13 @@ class RF69: public PhysicalLayer {
/*!
\brief Blocking binary receive method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
- \param data Binary data to be sent.
- \param len Number of bytes to send.
+ \param data Pointer to array to save the received binary data.
+ \param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+ \param timeout Reception timeout in milliseconds. If set to 0,
+ timeout period will be calculated automatically based on the radio configuration.
\returns \ref status_codes
*/
- int16_t receive(uint8_t* data, size_t len) override;
+ int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override;
/*!
\brief Sets the module to sleep mode.
@@ -577,7 +579,7 @@ class RF69: public PhysicalLayer {
\brief Sets AES key.
\param key Key to be used for AES encryption. Must be exactly 16 bytes long.
*/
- void setAESKey(uint8_t* key);
+ void setAESKey(const uint8_t* key);
/*!
\brief Enables AES encryption.
@@ -727,6 +729,12 @@ class RF69: public PhysicalLayer {
*/
int16_t readData(uint8_t* data, size_t len) override;
+ /*!
+ \brief Clean up after reception is done.
+ \returns \ref status_codes
+ */
+ int16_t finishReceive() override;
+
// configuration methods
/*!
@@ -789,14 +797,14 @@ class RF69: public PhysicalLayer {
\param len Sync word length in bytes.
\param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0.
*/
- int16_t setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits = 0);
+ int16_t setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBits = 0);
/*!
\brief Sets preamble length.
\param preambleLen Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192.
\returns \ref status_codes
*/
- int16_t setPreambleLength(uint8_t preambleLen);
+ int16_t setPreambleLength(size_t preambleLen) override;
/*!
\brief Sets node address. Calling this method will also enable address filtering for node address only.
@@ -949,7 +957,7 @@ class RF69: public PhysicalLayer {
int16_t setLnaTestBoost(bool value);
/*!
- \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet.
+ \brief Gets RSSI (Received Signal Strength Indicator) of the last received packet.
\returns Last packet RSSI in dBm.
*/
float getRSSI() override;
@@ -999,7 +1007,7 @@ class RF69: public PhysicalLayer {
\param value The value that indicates which function to place on that pin. See chip datasheet for details.
\returns \ref status_codes
*/
- int16_t setDIOMapping(uint32_t pin, uint32_t value) override;
+ int16_t setDIOMapping(uint32_t pin, uint32_t value);
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
@@ -1031,8 +1039,6 @@ class RF69: public PhysicalLayer {
bool promiscuous = false;
- uint8_t syncWordLength = RADIOLIB_RF69_DEFAULT_SW_LEN;
-
bool bitSync = true;
int16_t directMode();
diff --git a/lib/RadioLib/src/modules/SX123x/SX1231.cpp b/lib/RadioLib/src/modules/SX123x/SX1231.cpp
index 11424ee..2b64ff6 100644
--- a/lib/RadioLib/src/modules/SX123x/SX1231.cpp
+++ b/lib/RadioLib/src/modules/SX123x/SX1231.cpp
@@ -17,7 +17,10 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po
bool flagFound = false;
while((i < 10) && !flagFound) {
int16_t version = getChipVersion();
- if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_C)) {
+ if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) ||
+ (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) ||
+ (version == RADIOLIB_SX123X_CHIP_REVISION_2_C) ||
+ (version == RADIOLIB_SX123X_CHIP_REVISION_2_D)) {
flagFound = true;
this->chipRevision = version;
} else {
diff --git a/lib/RadioLib/src/modules/SX123x/SX1231.h b/lib/RadioLib/src/modules/SX123x/SX1231.h
index 6dc3735..6e9b66d 100644
--- a/lib/RadioLib/src/modules/SX123x/SX1231.h
+++ b/lib/RadioLib/src/modules/SX123x/SX1231.h
@@ -11,6 +11,7 @@
#define RADIOLIB_SX123X_CHIP_REVISION_2_A 0x21
#define RADIOLIB_SX123X_CHIP_REVISION_2_B 0x22
#define RADIOLIB_SX123X_CHIP_REVISION_2_C 0x23
+#define RADIOLIB_SX123X_CHIP_REVISION_2_D 0x24
// RADIOLIB_SX1231 specific register map
#define RADIOLIB_SX1231_REG_TEST_OOK 0x6E
@@ -108,7 +109,7 @@ class SX1231: public RF69 {
\param preambleLen Preamble Length in bits. Defaults to 16 bits.
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16);
+ virtual int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16);
#if !RADIOLIB_GODMODE
protected:
diff --git a/lib/RadioLib/src/modules/SX123x/SX1233.cpp b/lib/RadioLib/src/modules/SX123x/SX1233.cpp
index 23eb72c..e414095 100644
--- a/lib/RadioLib/src/modules/SX123x/SX1233.cpp
+++ b/lib/RadioLib/src/modules/SX123x/SX1233.cpp
@@ -18,7 +18,10 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po
bool flagFound = false;
while((i < 10) && !flagFound) {
int16_t version = getChipVersion();
- if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_C)) {
+ if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) ||
+ (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) ||
+ (version == RADIOLIB_SX123X_CHIP_REVISION_2_C) ||
+ (version == RADIOLIB_SX123X_CHIP_REVISION_2_D)) {
flagFound = true;
this->chipRevision = version;
} else {
@@ -93,11 +96,11 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po
int16_t SX1233::setBitRate(float br) {
// check high bit-rate operation
uint8_t pllBandwidth = RADIOLIB_SX1233_PLL_BW_LOW_BIT_RATE;
- if((fabsf(br - 500.0f) < 0.1) || (fabsf(br - 600.0f) < 0.1)) {
+ if((fabsf(br - 500.0f) < 0.1f) || (fabsf(br - 600.0f) < 0.1f)) {
pllBandwidth = RADIOLIB_SX1233_PLL_BW_HIGH_BIT_RATE;
} else {
// datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine
- RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(br, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
}
diff --git a/lib/RadioLib/src/modules/SX123x/SX1233.h b/lib/RadioLib/src/modules/SX123x/SX1233.h
index bf9bb14..2cff2c6 100644
--- a/lib/RadioLib/src/modules/SX123x/SX1233.h
+++ b/lib/RadioLib/src/modules/SX123x/SX1233.h
@@ -38,7 +38,7 @@ class SX1233: public SX1231 {
\param preambleLen Preamble Length in bits. Defaults to 16 bits.
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16);
+ int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16) override;
/*!
\brief Sets bit rate. Allowed values range from 0.5 to 300.0 kbps.
diff --git a/lib/RadioLib/src/modules/SX126x/STM32WLx.cpp b/lib/RadioLib/src/modules/SX126x/STM32WLx.cpp
index e9f4716..d32477a 100644
--- a/lib/RadioLib/src/modules/SX126x/STM32WLx.cpp
+++ b/lib/RadioLib/src/modules/SX126x/STM32WLx.cpp
@@ -45,7 +45,7 @@ int16_t STM32WLx::setOutputPower(int8_t power) {
RADIOLIB_ASSERT(state);
// check the user did not request power output that is not possible
- Module* mod = this->getMod();
+ const Module* mod = this->getMod();
bool hp_supported = mod->findRfSwitchMode(MODE_TX_HP);
bool lp_supported = mod->findRfSwitchMode(MODE_TX_LP);
if((!lp_supported && (power < -9)) || (!hp_supported && (power > 14))) {
diff --git a/lib/RadioLib/src/modules/SX126x/STM32WLx.h b/lib/RadioLib/src/modules/SX126x/STM32WLx.h
index 993791a..317922c 100644
--- a/lib/RadioLib/src/modules/SX126x/STM32WLx.h
+++ b/lib/RadioLib/src/modules/SX126x/STM32WLx.h
@@ -66,12 +66,12 @@ class STM32WLx : public SX1262 {
/*!
\copydoc SX1262::begin
*/
- int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
+ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false) override;
/*!
\copydoc SX1262::beginFSK
*/
- int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
+ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false) override;
// configuration methods
@@ -113,12 +113,12 @@ class STM32WLx : public SX1262 {
\brief Sets interrupt service routine to call when DIO1/2/3 activates.
\param func ISR to call.
*/
- void setDio1Action(void (*func)(void));
+ void setDio1Action(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when DIO1/2/3 activates.
*/
- void clearDio1Action();
+ void clearDio1Action() override;
/*!
\brief Sets interrupt service routine to call when a packet is received.
diff --git a/lib/RadioLib/src/modules/SX126x/SX1262.cpp b/lib/RadioLib/src/modules/SX126x/SX1262.cpp
index 426c2d0..63c221a 100644
--- a/lib/RadioLib/src/modules/SX126x/SX1262.cpp
+++ b/lib/RadioLib/src/modules/SX126x/SX1262.cpp
@@ -3,6 +3,45 @@
#if !RADIOLIB_EXCLUDE_SX126X
+// this is a lookup table for optimized PA configuration
+// it was determined by testing in https://github.com/jgromes/RadioLib/issues/1628
+// see also https://github.com/radiolib-org/power-tests
+static const SX126x::paTableEntry_t paOptTable[32] = {
+ { .paDutyCycle = 2, .hpMax = 2, .paVal = -5 },
+ { .paDutyCycle = 2, .hpMax = 1, .paVal = 0 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 3 },
+ { .paDutyCycle = 1, .hpMax = 2, .paVal = 0 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 6 },
+ { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 },
+ { .paDutyCycle = 2, .hpMax = 2, .paVal = 2 },
+ { .paDutyCycle = 4, .hpMax = 1, .paVal = 6 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 11 },
+ { .paDutyCycle = 2, .hpMax = 1, .paVal = 11 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 14 },
+ { .paDutyCycle = 2, .hpMax = 1, .paVal = 14 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 20 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 22 },
+ { .paDutyCycle = 2, .hpMax = 2, .paVal = 11 },
+ { .paDutyCycle = 3, .hpMax = 1, .paVal = 21 },
+ { .paDutyCycle = 1, .hpMax = 2, .paVal = 17 },
+ { .paDutyCycle = 4, .hpMax = 2, .paVal = 13 },
+ { .paDutyCycle = 1, .hpMax = 2, .paVal = 20 },
+ { .paDutyCycle = 1, .hpMax = 2, .paVal = 22 },
+ { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 },
+ { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 },
+ { .paDutyCycle = 1, .hpMax = 4, .paVal = 19 },
+ { .paDutyCycle = 1, .hpMax = 4, .paVal = 20 },
+ { .paDutyCycle = 3, .hpMax = 3, .paVal = 20 },
+ { .paDutyCycle = 2, .hpMax = 5, .paVal = 19 },
+ { .paDutyCycle = 1, .hpMax = 6, .paVal = 22 },
+ { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 },
+ { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 },
+ { .paDutyCycle = 3, .hpMax = 6, .paVal = 22 },
+ { .paDutyCycle = 4, .hpMax = 6, .paVal = 22 },
+ { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 },
+};
+
+
SX1262::SX1262(Module* mod) : SX126x(mod) {
chipType = RADIOLIB_SX1262_CHIP_TYPE;
}
@@ -49,6 +88,24 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
return(state);
}
+int16_t SX1262::beginBPSK(float freq, float br, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
+ // execute common part
+ int16_t state = SX126x::beginBPSK(br, tcxoVoltage, useRegulatorLDO);
+ RADIOLIB_ASSERT(state);
+
+ // configure publicly accessible settings
+ state = setFrequency(freq);
+ RADIOLIB_ASSERT(state);
+
+ state = SX126x::fixPaClamping();
+ RADIOLIB_ASSERT(state);
+
+ state = setOutputPower(power);
+ RADIOLIB_ASSERT(state);
+
+ return(state);
+}
+
int16_t SX1262::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO);
@@ -72,7 +129,7 @@ int16_t SX1262::setFrequency(float freq) {
}
int16_t SX1262::setFrequency(float freq, bool skipCalibration) {
- RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ RADIOLIB_CHECK_RANGE(freq, 150.0f, 960.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
// check if we need to recalibrate image
if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) {
@@ -85,25 +142,19 @@ int16_t SX1262::setFrequency(float freq, bool skipCalibration) {
}
int16_t SX1262::setOutputPower(int8_t power) {
+ return(setOutputPower(power, true));
+}
+
+int16_t SX1262::setOutputPower(int8_t power, bool optimize) {
// check if power value is configurable
int16_t state = checkOutputPower(power, NULL);
RADIOLIB_ASSERT(state);
- // get current OCP configuration
- uint8_t ocp = 0;
- state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
- RADIOLIB_ASSERT(state);
-
// set PA config
- state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1262);
- RADIOLIB_ASSERT(state);
-
- // set output power with default 200us ramp
- state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U);
- RADIOLIB_ASSERT(state);
-
- // restore OCP configuration
- return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
+ int8_t paVal = optimize ? paOptTable[power + 9].paVal : power;
+ uint8_t paDutyCycle = optimize ? paOptTable[power + 9].paDutyCycle : 0x04;
+ uint8_t hpMax = optimize ? paOptTable[power + 9].hpMax : 0x07;
+ return(SX126x::setOutputPower(paVal, paDutyCycle, hpMax, RADIOLIB_SX126X_PA_CONFIG_SX1262));
}
int16_t SX1262::checkOutputPower(int8_t power, int8_t* clipped) {
diff --git a/lib/RadioLib/src/modules/SX126x/SX1262.h b/lib/RadioLib/src/modules/SX126x/SX1262.h
index a7e0b67..454e00a 100644
--- a/lib/RadioLib/src/modules/SX126x/SX1262.h
+++ b/lib/RadioLib/src/modules/SX126x/SX1262.h
@@ -34,7 +34,8 @@ class SX1262: public SX126x {
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz.
\param sf LoRa spreading factor. Defaults to 9.
- \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7).
+ \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12).
\param power Output power in dBm. Defaults to 10 dBm.
\param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols.
@@ -44,7 +45,7 @@ class SX1262: public SX126x {
\param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
+ virtual int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
/*!
\brief Initialization method for FSK modem.
@@ -60,7 +61,21 @@ class SX1262: public SX126x {
\param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
\returns \ref status_codes
*/
- int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
+ virtual int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
+
+ /*!
+ \brief Initialization method for BPSK modem.
+ NOTE: Proceed with caution! BPSK support in SX126x is epxerimental and poorly documented!
+ \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+ \param br FSK bit rate in kbps. Defaults to 600 bps, only 100 and 600 bps is supported
+ \param power Output power in dBm. Defaults to 10 dBm.
+ \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V.
+ If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
+ To use XTAL, either set this value to 0, or set SX126x::XTAL to true.
+ \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
+ \returns \ref status_codes
+ */
+ virtual int16_t beginBPSK(float freq = 434.0, float br = 0.6, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
/*!
\brief Initialization method for LR-FHSS modem. This modem only supports transmission!
@@ -75,7 +90,7 @@ class SX1262: public SX126x {
\param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
\returns \ref status_codes
*/
- int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
+ virtual int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
// configuration methods
@@ -106,6 +121,14 @@ class SX1262: public SX126x {
*/
virtual int16_t setOutputPower(int8_t power) override;
+ /*!
+ \brief Sets output power. Allowed values are in range from -9 to 22 dBm.
+ \param power Output power to be set in dBm.
+ \param optimize Whether to use power-optimized PA configuration (true) or datasheet default (false).
+ \returns \ref status_codes
+ */
+ int16_t setOutputPower(int8_t power, bool optimize);
+
/*!
\brief Check if output power is configurable.
\param power Output power in dBm.
diff --git a/lib/RadioLib/src/modules/SX126x/SX1268.cpp b/lib/RadioLib/src/modules/SX126x/SX1268.cpp
index 7de82a2..93cd6b3 100644
--- a/lib/RadioLib/src/modules/SX126x/SX1268.cpp
+++ b/lib/RadioLib/src/modules/SX126x/SX1268.cpp
@@ -3,6 +3,44 @@
#if !RADIOLIB_EXCLUDE_SX126X
+// this is a lookup table for optimized PA configuration
+// it was determined by testing in https://github.com/jgromes/RadioLib/issues/1628
+// see also https://github.com/radiolib-org/power-tests
+static const SX126x::paTableEntry_t paOptTable[32] = {
+ { .paDutyCycle = 2, .hpMax = 1, .paVal = -3 },
+ { .paDutyCycle = 2, .hpMax = 1, .paVal = -2 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 0 },
+ { .paDutyCycle = 4, .hpMax = 1, .paVal = -1 },
+ { .paDutyCycle = 2, .hpMax = 1, .paVal = 2 },
+ { .paDutyCycle = 2, .hpMax = 2, .paVal = 0 },
+ { .paDutyCycle = 2, .hpMax = 2, .paVal = 1 },
+ { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 },
+ { .paDutyCycle = 1, .hpMax = 3, .paVal = 3 },
+ { .paDutyCycle = 1, .hpMax = 2, .paVal = 5 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 9 },
+ { .paDutyCycle = 4, .hpMax = 1, .paVal = 8 },
+ { .paDutyCycle = 2, .hpMax = 2, .paVal = 7 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 13 },
+ { .paDutyCycle = 4, .hpMax = 1, .paVal = 11 },
+ { .paDutyCycle = 1, .hpMax = 1, .paVal = 19 },
+ { .paDutyCycle = 2, .hpMax = 1, .paVal = 19 },
+ { .paDutyCycle = 4, .hpMax = 1, .paVal = 17 },
+ { .paDutyCycle = 1, .hpMax = 6, .paVal = 12 },
+ { .paDutyCycle = 1, .hpMax = 2, .paVal = 16 },
+ { .paDutyCycle = 4, .hpMax = 1, .paVal = 22 },
+ { .paDutyCycle = 2, .hpMax = 2, .paVal = 18 },
+ { .paDutyCycle = 1, .hpMax = 2, .paVal = 21 },
+ { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 },
+ { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 },
+ { .paDutyCycle = 2, .hpMax = 3, .paVal = 20 },
+ { .paDutyCycle = 1, .hpMax = 6, .paVal = 20 },
+ { .paDutyCycle = 1, .hpMax = 5, .paVal = 22 },
+ { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 },
+ { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 },
+ { .paDutyCycle = 3, .hpMax = 7, .paVal = 22 },
+ { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 },
+};
+
SX1268::SX1268(Module* mod) : SX126x(mod) {
chipType = RADIOLIB_SX1268_CHIP_TYPE;
}
@@ -49,6 +87,24 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
return(state);
}
+int16_t SX1268::beginBPSK(float freq, float br, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
+ // execute common part
+ int16_t state = SX126x::beginBPSK(br, tcxoVoltage, useRegulatorLDO);
+ RADIOLIB_ASSERT(state);
+
+ // configure publicly accessible settings
+ state = setFrequency(freq);
+ RADIOLIB_ASSERT(state);
+
+ state = SX126x::fixPaClamping();
+ RADIOLIB_ASSERT(state);
+
+ state = setOutputPower(power);
+ RADIOLIB_ASSERT(state);
+
+ return(state);
+}
+
int16_t SX1268::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO);
@@ -73,7 +129,7 @@ int16_t SX1268::setFrequency(float freq) {
/// \todo integers only (all modules - frequency, data rate, bandwidth etc.)
int16_t SX1268::setFrequency(float freq, bool skipCalibration) {
- RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ RADIOLIB_CHECK_RANGE(freq, 410.0f, 810.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
// check if we need to recalibrate image
if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) {
@@ -86,25 +142,19 @@ int16_t SX1268::setFrequency(float freq, bool skipCalibration) {
}
int16_t SX1268::setOutputPower(int8_t power) {
+ return(setOutputPower(power, true));
+}
+
+int16_t SX1268::setOutputPower(int8_t power, bool optimize) {
// check if power value is configurable
int16_t state = checkOutputPower(power, NULL);
RADIOLIB_ASSERT(state);
- // get current OCP configuration
- uint8_t ocp = 0;
- state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
- RADIOLIB_ASSERT(state);
-
// set PA config
- state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1268);
- RADIOLIB_ASSERT(state);
-
- // set output power with default 200us ramp
- state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U);
- RADIOLIB_ASSERT(state);
-
- // restore OCP configuration
- return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
+ int8_t paVal = optimize ? paOptTable[power + 9].paVal : power;
+ uint8_t paDutyCycle = optimize ? paOptTable[power + 9].paDutyCycle : 0x04;
+ uint8_t hpMax = optimize ? paOptTable[power + 9].hpMax : 0x07;
+ return(SX126x::setOutputPower(paVal, paDutyCycle, hpMax, RADIOLIB_SX126X_PA_CONFIG_SX1268));
}
int16_t SX1268::checkOutputPower(int8_t power, int8_t* clipped) {
diff --git a/lib/RadioLib/src/modules/SX126x/SX1268.h b/lib/RadioLib/src/modules/SX126x/SX1268.h
index c34bec8..d97da55 100644
--- a/lib/RadioLib/src/modules/SX126x/SX1268.h
+++ b/lib/RadioLib/src/modules/SX126x/SX1268.h
@@ -33,7 +33,8 @@ class SX1268: public SX126x {
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz.
\param sf LoRa spreading factor. Defaults to 9.
- \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7).
+ \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8.
+ Note that a value of 4 means no coding, is undocumented and not recommended without your own FEC.
\param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12).
\param power Output power in dBm. Defaults to 10 dBm.
\param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols.
@@ -60,7 +61,21 @@ class SX1268: public SX126x {
\returns \ref status_codes
*/
int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
-
+
+ /*!
+ \brief Initialization method for BPSK modem.
+ NOTE: Proceed with caution! BPSK support in SX126x is epxerimental and poorly documented!
+ \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+ \param br FSK bit rate in kbps. Defaults to 600 bps, only 100 and 600 bps is supported.
+ \param power Output power in dBm. Defaults to 10 dBm.
+ \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V.
+ If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
+ To use XTAL, either set this value to 0, or set SX126x::XTAL to true.
+ \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
+ \returns \ref status_codes
+ */
+ virtual int16_t beginBPSK(float freq = 434.0, float br = 0.6, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
+
/*!
\brief Initialization method for LR-FHSS modem. This modem only supports transmission!
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
@@ -104,6 +119,14 @@ class SX1268: public SX126x {
*/
int16_t setOutputPower(int8_t power) override;
+ /*!
+ \brief Sets output power. Allowed values are in range from -9 to 22 dBm.
+ \param power Output power to be set in dBm.
+ \param optimize Whether to use power-optimized PA configuration (true) or datasheet default (false).
+ \returns \ref status_codes
+ */
+ int16_t setOutputPower(int8_t power, bool optimize);
+
/*!
\brief Check if output power is configurable.
\param power Output power in dBm.
diff --git a/lib/RadioLib/src/modules/SX126x/SX126x.cpp b/lib/RadioLib/src/modules/SX126x/SX126x.cpp
index f14e0f8..e4a786f 100644
--- a/lib/RadioLib/src/modules/SX126x/SX126x.cpp
+++ b/lib/RadioLib/src/modules/SX126x/SX126x.cpp
@@ -3,7 +3,9 @@
#include
#if !RADIOLIB_EXCLUDE_SX126X
-SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) {
+SX126x::SX126x(Module* mod) : PhysicalLayer() {
+ this->freqStep = RADIOLIB_SX126X_FREQUENCY_STEP_SIZE;
+ this->maxPacketLength = RADIOLIB_SX126X_MAX_PACKET_LENGTH;
this->mod = mod;
this->XTAL = false;
this->standbyXOSC = false;
@@ -118,6 +120,22 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
return(state);
}
+int16_t SX126x::beginBPSK(float br, float tcxoVoltage, bool useRegulatorLDO) {
+ // set module properties and perform initial setup
+ int16_t state = this->modSetup(tcxoVoltage, useRegulatorLDO, RADIOLIB_SX126X_PACKET_TYPE_BPSK);
+ RADIOLIB_ASSERT(state);
+
+ // configure publicly accessible settings
+ state = setBitRate(br);
+ RADIOLIB_ASSERT(state);
+
+ // set publicly accessible settings that are not a part of begin method
+ state = setDio2AsRfSwitch(true);
+ RADIOLIB_ASSERT(state);
+
+ return(state);
+}
+
int16_t SX126x::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage, bool useRegulatorLDO) {
this->lrFhssGridNonFcc = narrowGrid;
@@ -198,6 +216,17 @@ int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
RADIOLIB_ASSERT(state);
// check packet length
+ if(this->codingRate > RADIOLIB_SX126X_LORA_CR_4_8) {
+ // Long Interleaver needs at least 8 bytes
+ if(len < 8) {
+ return(RADIOLIB_ERR_PACKET_TOO_SHORT);
+ }
+
+ // Long Interleaver supports up to 253 bytes if CRC is enabled
+ if(this->crcTypeLoRa == RADIOLIB_SX126X_LORA_CRC_ON && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 2)) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+ }
if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
@@ -235,51 +264,31 @@ int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
break;
} else {
// handle frequency hop
- this->setLRFHSSHop(this->lrFhssHopNum % 16);
- clearIrqStatus();
+ this->hopLRFHSS();
}
}
}
- // update data rate
- RadioLibTime_t elapsed = this->mod->hal->millis() - start;
- this->dataRateMeasured = (len*8.0)/((float)elapsed/1000.0);
-
return(finishTransmit());
}
-int16_t SX126x::receive(uint8_t* data, size_t len) {
+int16_t SX126x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
- RadioLibTime_t timeout = 0;
-
- // get currently active modem
- uint8_t modem = getPacketType();
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- // calculate timeout (100 LoRa symbols, the default for SX127x series)
- float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
- timeout = (RadioLibTime_t)(symbolLength * 100.0);
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ RadioLibTime_t timeoutInternal = timeout;
+ if(!timeoutInternal) {
// calculate timeout (500 % of expected time-one-air)
size_t maxLen = len;
- if(len == 0) {
- maxLen = 0xFF;
- }
- float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate;
- timeout = (RadioLibTime_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0);
-
- } else {
- return(RADIOLIB_ERR_UNKNOWN);
-
+ if(len == 0) { maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH; }
+ timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
}
- RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
// start reception
- uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0) / 15.625);
+ uint32_t timeoutValue = (uint32_t)(((float)timeoutInternal * 1000.0f) / 15.625f);
state = startReceive(timeoutValue);
RADIOLIB_ASSERT(state);
@@ -289,7 +298,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
// safety check, the timeout should be done by the radio
- if(this->mod->hal->millis() - start > timeout) {
+ if(this->mod->hal->millis() - start > timeoutInternal) {
softTimeout = true;
break;
}
@@ -302,19 +311,11 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
}
// check whether this was a timeout or not
- if((getIrqFlags() & RADIOLIB_SX126X_IRQ_TIMEOUT) || softTimeout) {
- standby();
- fixImplicitTimeout();
- clearIrqStatus();
+ if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
+ (void)finishReceive();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
- // fix timeout in implicit LoRa mode
- if(((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) {
- state = fixImplicitTimeout();
- RADIOLIB_ASSERT(state);
- }
-
// read the received data
return(readData(data, len));
}
@@ -331,8 +332,7 @@ int16_t SX126x::transmitDirect(uint32_t frf) {
RADIOLIB_ASSERT(state);
// direct mode activation intentionally skipped here, as it seems to lead to much worse results
- uint8_t data[] = { RADIOLIB_SX126X_CMD_NOP };
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1));
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0));
}
int16_t SX126x::receiveDirect() {
@@ -438,184 +438,14 @@ int16_t SX126x::scanChannel(const ChannelScanConfig_t &config) {
return(getChannelScanResult());
}
-int16_t SX126x::sleep() {
- return(SX126x::sleep(true));
-}
-
-int16_t SX126x::sleep(bool retainConfig) {
- // set RF switch (if present)
- this->mod->setRfSwitchState(Module::MODE_IDLE);
-
- uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF;
- if(!retainConfig) {
- sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF;
- }
- int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false, false);
-
- // wait for SX126x to safely enter sleep mode
- this->mod->hal->delay(1);
-
- return(state);
-}
-
-int16_t SX126x::standby() {
- return(SX126x::standby(this->standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC : RADIOLIB_SX126X_STANDBY_RC));
-}
-
-int16_t SX126x::standby(uint8_t mode, bool wakeup) {
- // set RF switch (if present)
- this->mod->setRfSwitchState(Module::MODE_IDLE);
-
- if(wakeup) {
- // send a NOP command - this pulls the NSS low to exit the sleep mode,
- // while preventing interference with possible other SPI transactions
- // see https://github.com/jgromes/RadioLib/discussions/1364
- (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX126X_CMD_NOP, NULL, 0, false, false);
+int16_t SX126x::hopLRFHSS() {
+ if(!(this->getIrqFlags() & RADIOLIB_SX126X_IRQ_LR_FHSS_HOP)) {
+ return(RADIOLIB_ERR_TX_TIMEOUT);
}
- uint8_t data[] = { mode };
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1));
-}
-
-void SX126x::setDio1Action(void (*func)(void)) {
- this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
-}
-
-void SX126x::clearDio1Action() {
- this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
-}
-
-void SX126x::setPacketReceivedAction(void (*func)(void)) {
- this->setDio1Action(func);
-}
-
-void SX126x::clearPacketReceivedAction() {
- this->clearDio1Action();
-}
-
-void SX126x::setPacketSentAction(void (*func)(void)) {
- this->setDio1Action(func);
-}
-
-void SX126x::clearPacketSentAction() {
- this->clearDio1Action();
-}
-
-void SX126x::setChannelScanAction(void (*func)(void)) {
- this->setDio1Action(func);
-}
-
-void SX126x::clearChannelScanAction() {
- this->clearDio1Action();
-}
-
-int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
- (void)addr;
-
- // check packet length
- if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) {
- return(RADIOLIB_ERR_PACKET_TOO_LONG);
- }
-
- // maximum packet length is decreased by 1 when address filtering is active
- if((RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) {
- return(RADIOLIB_ERR_PACKET_TOO_LONG);
- }
-
- // set packet Length
- int16_t state = RADIOLIB_ERR_NONE;
- uint8_t modem = getPacketType();
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, this->headerType, this->invertIQEnabled);
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType, len);
-
- } else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
- return(RADIOLIB_ERR_UNKNOWN);
-
- }
+ int16_t state = this->setLRFHSSHop(this->lrFhssHopNum % 16);
RADIOLIB_ASSERT(state);
-
- // set DIO mapping
- if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
- state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE);
- } else {
- state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP, RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP);
- }
- RADIOLIB_ASSERT(state);
-
- // set buffer pointers
- state = setBufferBaseAddress();
- RADIOLIB_ASSERT(state);
-
- // write packet to buffer
- if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
- state = writeBuffer(const_cast(data), len);
-
- } else {
- // first, reset the LR-FHSS state machine
- state = resetLRFHSS();
- RADIOLIB_ASSERT(state);
-
- // skip hopping for the first 4 - lrFhssHdrCount blocks
- for(int i = 0; i < 4 - this->lrFhssHdrCount; ++i ) {
- stepLRFHSS();
- }
-
- // in LR-FHSS mode, we need to build the entire packet manually
- uint8_t frame[RADIOLIB_SX126X_MAX_PACKET_LENGTH] = { 0 };
- size_t frameLen = 0;
- this->lrFhssFrameBitsRem = 0;
- this->lrFhssFrameHopsRem = 0;
- this->lrFhssHopNum = 0;
- state = buildLRFHSSPacket(const_cast(data), len, frame, &frameLen, &this->lrFhssFrameBitsRem, &this->lrFhssFrameHopsRem);
- RADIOLIB_ASSERT(state);
-
- // FIXME check max len for FHSS
- state = writeBuffer(frame, frameLen);
- RADIOLIB_ASSERT(state);
-
- // activate hopping
- uint8_t hopCfg[] = { RADIOLIB_SX126X_HOPPING_ENABLED, (uint8_t)frameLen, (uint8_t)this->lrFhssFrameHopsRem };
- state = writeRegister(RADIOLIB_SX126X_REG_HOPPING_ENABLE, hopCfg, 3);
- RADIOLIB_ASSERT(state);
-
- // write the initial hopping table
- uint8_t initHops = this->lrFhssFrameHopsRem;
- if(initHops > 16) {
- initHops = 16;
- };
- for(size_t i = 0; i < initHops; i++) {
- // set the hop frequency and symbols
- state = this->setLRFHSSHop(i);
- RADIOLIB_ASSERT(state);
- }
-
- }
- RADIOLIB_ASSERT(state);
-
- // clear interrupt flags
- state = clearIrqStatus();
- RADIOLIB_ASSERT(state);
-
- // fix sensitivity
- state = fixSensitivity();
- RADIOLIB_ASSERT(state);
-
- // set RF switch (if present)
- this->mod->setRfSwitchState(this->txMode);
-
- // start transmission
- state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE);
- RADIOLIB_ASSERT(state);
-
- // wait for BUSY to go low (= PA ramp up done)
- while(this->mod->hal->digitalRead(this->mod->getGpio())) {
- this->mod->hal->yield();
- }
-
- return(state);
+ return(clearIrqStatus());
}
int16_t SX126x::finishTransmit() {
@@ -627,27 +457,22 @@ int16_t SX126x::finishTransmit() {
return(standby());
}
-int16_t SX126x::startReceive() {
- return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
-}
-
-int16_t SX126x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) {
- // in implicit header mode, use the provided length if it is nonzero
- // otherwise we trust the user has previously set the payload length manually
- if((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (len != 0)) {
- this->implicitLen = len;
- }
-
- int16_t state = startReceiveCommon(timeout, irqFlags, irqMask);
+int16_t SX126x::finishReceive() {
+ // set mode to standby to disable RF switch
+ int16_t state = standby();
RADIOLIB_ASSERT(state);
- // set RF switch (if present)
- this->mod->setRfSwitchState(Module::MODE_RX);
+ // try to fix timeout error in implicit header mode
+ // check for modem type and header mode is done in fixImplicitTimeout()
+ state = fixImplicitTimeout();
+ RADIOLIB_ASSERT(state);
- // set mode to receive
- state = setRx(timeout);
+ // clear interrupt flags
+ return(clearIrqStatus());
+}
- return(state);
+int16_t SX126x::startReceive() {
+ return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
}
int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) {
@@ -672,7 +497,7 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, R
int16_t state = startReceiveCommon(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask);
RADIOLIB_ASSERT(state);
- uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF),
+ const uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF),
(uint8_t)((sleepPeriodRaw >> 16) & 0xFF), (uint8_t)((sleepPeriodRaw >> 8) & 0xFF), (uint8_t)(sleepPeriodRaw & 0xFF)};
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6));
}
@@ -680,6 +505,16 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, R
int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) {
if(senderPreambleLength == 0) {
senderPreambleLength = this->preambleLengthLoRa;
+ } else if (senderPreambleLength > this->preambleLengthLoRa) {
+ // the unit must be configured to expect a preamble length at least as long as the sender is using
+ return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
+ }
+ if(minSymbols == 0) {
+ if (this->spreadingFactor <= 6) {
+ minSymbols = 12;
+ } else {
+ minSymbols = 8;
+ }
}
// worst case is that the sender starts transmitting when we're just less than minSymbols from going back to sleep.
@@ -733,6 +568,7 @@ int16_t SX126x::startReceiveCommon(uint32_t timeout, RadioLibIrqFlags_t irqFlags
// clear interrupt flags
state = clearIrqStatus();
+ RADIOLIB_ASSERT(state);
// restore original packet length
uint8_t modem = getPacketType();
@@ -847,518 +683,6 @@ int16_t SX126x::getChannelScanResult() {
return(RADIOLIB_ERR_UNKNOWN);
}
-int16_t SX126x::setBandwidth(float bw) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // ensure byte conversion doesn't overflow
- RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
-
- // check allowed bandwidth values
- uint8_t bw_div2 = bw / 2 + 0.01;
- switch (bw_div2) {
- case 3: // 7.8:
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8;
- break;
- case 5: // 10.4:
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_10_4;
- break;
- case 7: // 15.6:
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_15_6;
- break;
- case 10: // 20.8:
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_20_8;
- break;
- case 15: // 31.25:
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_31_25;
- break;
- case 20: // 41.7:
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_41_7;
- break;
- case 31: // 62.5:
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_62_5;
- break;
- case 62: // 125.0:
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_125_0;
- break;
- case 125: // 250.0
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_250_0;
- break;
- case 250: // 500.0
- this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0;
- break;
- default:
- return(RADIOLIB_ERR_INVALID_BANDWIDTH);
- }
-
- // update modulation parameters
- this->bandwidthKhz = bw;
- return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
-}
-
-int16_t SX126x::setSpreadingFactor(uint8_t sf) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
-
- // update modulation parameters
- this->spreadingFactor = sf;
- return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
-}
-
-int16_t SX126x::setCodingRate(uint8_t cr) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
-
- // update modulation parameters
- this->codingRate = cr - 4;
- return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
-}
-
-int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // update register
- uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
- return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2));
-}
-
-int16_t SX126x::setCurrentLimit(float currentLimit) {
- // check allowed range
- if(!((currentLimit >= 0) && (currentLimit <= 140))) {
- return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT);
- }
-
- // calculate raw value
- uint8_t rawLimit = (uint8_t)(currentLimit / 2.5);
-
- // update register
- return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1));
-}
-
-float SX126x::getCurrentLimit() {
- // get the raw value
- uint8_t ocp = 0;
- readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
-
- // return the actual value
- return((float)ocp * 2.5);
-}
-
-int16_t SX126x::setPreambleLength(size_t preambleLength) {
- uint8_t modem = getPacketType();
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- this->preambleLengthLoRa = preambleLength;
- return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- this->preambleLengthFSK = preambleLength;
- // maximum preamble detector length is limited by sync word length
- // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
- uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
- this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
- maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
- maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
- maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
- RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
- return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType));
- }
-
- return(RADIOLIB_ERR_UNKNOWN);
-}
-
-int16_t SX126x::setFrequencyDeviation(float freqDev) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // set frequency deviation to lowest available setting (required for digimodes)
- float newFreqDev = freqDev;
- if(freqDev < 0.0) {
- newFreqDev = 0.6;
- }
-
- RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
-
- // calculate raw frequency deviation value
- uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0));
-
- // check modulation parameters
- this->frequencyDev = freqDevRaw;
-
- // update modulation parameters
- return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
-}
-
-int16_t SX126x::setBitRate(float br) {
- // check active modem
- uint8_t modem = getPacketType();
- if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
- RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
- }
-
- // calculate raw bit rate value
- uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0));
-
- // check modulation parameters
- this->bitRate = brRaw;
-
- // update modulation parameters
- return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
-}
-
-int16_t SX126x::setDataRate(DataRate_t dr) {
- int16_t state = RADIOLIB_ERR_UNKNOWN;
-
- // select interpretation based on active modem
- uint8_t modem = this->getPacketType();
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- // set the bit rate
- state = this->setBitRate(dr.fsk.bitRate);
- RADIOLIB_ASSERT(state);
-
- // set the frequency deviation
- state = this->setFrequencyDeviation(dr.fsk.freqDev);
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- // set the spreading factor
- state = this->setSpreadingFactor(dr.lora.spreadingFactor);
- RADIOLIB_ASSERT(state);
-
- // set the bandwidth
- state = this->setBandwidth(dr.lora.bandwidth);
- RADIOLIB_ASSERT(state);
-
- // set the coding rate
- state = this->setCodingRate(dr.lora.codingRate);
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
- // set the basic config
- state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
- RADIOLIB_ASSERT(state);
-
- // set hopping grid
- this->lrFhssGridNonFcc = dr.lrFhss.narrowGrid ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC;
-
- }
-
- return(state);
-}
-
-int16_t SX126x::checkDataRate(DataRate_t dr) {
- int16_t state = RADIOLIB_ERR_UNKNOWN;
-
- // select interpretation based on active modem
- uint8_t modem = this->getPacketType();
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
- RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
- return(RADIOLIB_ERR_NONE);
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
- RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
- RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
- return(RADIOLIB_ERR_NONE);
-
- }
-
- return(state);
-}
-
-int16_t SX126x::setRxBandwidth(float rxBw) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // check modulation parameters
- /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) {
- return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
- }*/
- this->rxBandwidthKhz = rxBw;
-
- // check allowed receiver bandwidth values
- if(fabsf(rxBw - 4.8) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8;
- } else if(fabsf(rxBw - 5.8) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8;
- } else if(fabsf(rxBw - 7.3) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3;
- } else if(fabsf(rxBw - 9.7) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7;
- } else if(fabsf(rxBw - 11.7) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7;
- } else if(fabsf(rxBw - 14.6) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6;
- } else if(fabsf(rxBw - 19.5) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5;
- } else if(fabsf(rxBw - 23.4) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4;
- } else if(fabsf(rxBw - 29.3) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3;
- } else if(fabsf(rxBw - 39.0) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0;
- } else if(fabsf(rxBw - 46.9) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9;
- } else if(fabsf(rxBw - 58.6) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6;
- } else if(fabsf(rxBw - 78.2) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2;
- } else if(fabsf(rxBw - 93.8) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8;
- } else if(fabsf(rxBw - 117.3) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3;
- } else if(fabsf(rxBw - 156.2) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2;
- } else if(fabsf(rxBw - 187.2) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2;
- } else if(fabsf(rxBw - 234.3) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3;
- } else if(fabsf(rxBw - 312.0) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0;
- } else if(fabsf(rxBw - 373.6) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6;
- } else if(fabsf(rxBw - 467.0) <= 0.001) {
- this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0;
- } else {
- return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
- }
-
- // update modulation parameters
- return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
-}
-
-int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) {
- // update RX gain setting register
- uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING;
- int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1);
- RADIOLIB_ASSERT(state);
-
- // add Rx Gain register to retention memory if requested
- if(persist) {
- // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3
- uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) };
- state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3);
- }
-
- return(state);
-}
-
-int16_t SX126x::setDataShaping(uint8_t sh) {
- // check active modem
- uint8_t modem = getPacketType();
- if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // set data shaping
- switch(sh) {
- case RADIOLIB_SHAPING_NONE:
- this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE;
- break;
- case RADIOLIB_SHAPING_0_3:
- this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3;
- break;
- case RADIOLIB_SHAPING_0_5:
- this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5;
- break;
- case RADIOLIB_SHAPING_0_7:
- this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7;
- break;
- case RADIOLIB_SHAPING_1_0:
- this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1;
- break;
- default:
- return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
- }
-
- // update modulation parameters
- return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
-}
-
-int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) {
- // check active modem
- uint8_t modem = getPacketType();
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- // check sync word Length
- if(len > 8) {
- return(RADIOLIB_ERR_INVALID_SYNC_WORD);
- }
-
- // write sync word
- int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len);
- RADIOLIB_ASSERT(state);
-
- // update packet parameters
- this->syncWordLength = len * 8;
-
- // maximum preamble detector length is limited by sync word length
- // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
- uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
- this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
- maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
- maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
- maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
- RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
- state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
-
- return(state);
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
- if(len > 1) {
- return(RADIOLIB_ERR_INVALID_SYNC_WORD);
- }
- return(setSyncWord(syncWord[0]));
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
- // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
- if(len != sizeof(uint32_t)) {
- return(RADIOLIB_ERR_INVALID_SYNC_WORD);
- }
- memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t));
-
- }
-
- return(RADIOLIB_ERR_WRONG_MODEM);
-}
-
-int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // check sync word Length
- if(bitsLen > 0x40) {
- return(RADIOLIB_ERR_INVALID_SYNC_WORD);
- }
-
- uint8_t bytesLen = bitsLen / 8;
- if ((bitsLen % 8) != 0) {
- bytesLen++;
- }
-
- return(setSyncWord(syncWord, bytesLen));
-}
-
-int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
- // check active modem
- uint8_t modem = getPacketType();
-
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- // update packet parameters
- switch(len) {
- case 0:
- this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF;
- break;
- case 1:
- if(inverted) {
- this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV;
- } else {
- this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE;
- }
- break;
- case 2:
- if(inverted) {
- this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV;
- } else {
- this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE;
- }
- break;
- default:
- return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
- }
-
- int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
- RADIOLIB_ASSERT(state);
-
- // write initial CRC value
- uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
- state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2);
- RADIOLIB_ASSERT(state);
-
- // write CRC polynomial value
- data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
- data[1] = (uint8_t)(polynomial & 0xFF);
- state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
-
- return(state);
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
-
- // update packet parameters
- if(len) {
- this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON;
- } else {
- this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF;
- }
-
- return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
- }
-
- return(RADIOLIB_ERR_UNKNOWN);
-}
-
-int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- int16_t state = RADIOLIB_ERR_NONE;
- if(!enabled) {
- // disable whitening
- this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF;
-
- state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
- RADIOLIB_ASSERT(state);
-
- } else {
- // enable whitening
- this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON;
-
- // write initial whitening value
- // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register"
- uint8_t data[2];
- // first read the actual value and mask 7 MSB which we can not change
- // if different value is written in 7 MSB, the Rx won't even work (tested on HW)
- state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1);
- RADIOLIB_ASSERT(state);
-
- data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01);
- data[1] = (uint8_t)(initial & 0xFF);
- state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2);
- RADIOLIB_ASSERT(state);
-
- state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
- RADIOLIB_ASSERT(state);
- }
- return(state);
-}
-
-float SX126x::getDataRate() const {
- return(this->dataRateMeasured);
-}
-
float SX126x::getRSSI() {
return(this->getRSSI(true));
}
@@ -1373,7 +697,7 @@ float SX126x::getRSSI(bool packet) {
// get instantaneous RSSI value
uint8_t rssiRaw = 0;
this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, &rssiRaw, 1);
- return((float)rssiRaw / (-2.0));
+ return((float)rssiRaw / (-2.0f));
}
}
@@ -1402,11 +726,11 @@ float SX126x::getFrequencyError() {
// read the raw frequency error register values
uint8_t efeRaw[3] = {0};
- int16_t state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR, &efeRaw[0], 1);
+ int16_t state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC, &efeRaw[0], 1);
RADIOLIB_ASSERT(state);
- state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 1, &efeRaw[1], 1);
+ state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC + 1, &efeRaw[1], 1);
RADIOLIB_ASSERT(state);
- state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 2, &efeRaw[2], 1);
+ state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC + 2, &efeRaw[2], 1);
RADIOLIB_ASSERT(state);
uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2];
efe &= 0x0FFFFF;
@@ -1418,9 +742,9 @@ float SX126x::getFrequencyError() {
// frequency error is negative
efe |= (uint32_t) 0xFFF00000;
efe = ~efe + 1;
- error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz) * -1.0;
+ error = 1.55f * (float) efe / (1600.0f / (float) this->bandwidthKhz) * -1.0f;
} else {
- error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz);
+ error = 1.55f * (float) efe / (1600.0f / (float) this->bandwidthKhz);
}
return(error);
@@ -1433,11 +757,12 @@ size_t SX126x::getPacketLength(bool update) {
size_t SX126x::getPacketLength(bool update, uint8_t* offset) {
(void)update;
- // in implicit mode, return the cached value
- if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT)) {
+ // in implicit mode, return the cached value if the offset was not requested
+ if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (!offset)) {
return(this->implicitLen);
}
+ // if offset was requested, or in explicit mode, we always have to perform the SPI transaction
uint8_t rxBufStatus[2] = {0, 0};
this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
@@ -1446,89 +771,164 @@ size_t SX126x::getPacketLength(bool update, uint8_t* offset) {
return((size_t)rxBufStatus[0]);
}
-int16_t SX126x::fixedPacketLengthMode(uint8_t len) {
- return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len));
+int16_t SX126x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
+ int16_t state = RADIOLIB_ERR_NONE;
+
+ // check if in explicit header mode
+ if(this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX126X_REG_LORA_RX_CODING_RATE, 6, 4) >> 4; }
+ if(hasCRC) { *hasCRC = (this->mod->SPIgetRegValue(RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC, 4, 4) != 0); }
+
+ return(state);
}
-int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
- return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
-}
-
-RadioLibTime_t SX126x::getTimeOnAir(size_t len) {
+RadioLibTime_t SX126x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
// everything is in microseconds to allow integer arithmetic
// some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact
- uint8_t modem = getPacketType();
- if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << this->spreadingFactor) / (this->bandwidthKhz * 10) ;
- uint8_t sfCoeff1_x4 = 17; // (4.25 * 4)
- uint8_t sfCoeff2 = 8;
- if(this->spreadingFactor == 5 || this->spreadingFactor == 6) {
- sfCoeff1_x4 = 25; // 6.25 * 4
- sfCoeff2 = 0;
- }
- uint8_t sfDivisor = 4*this->spreadingFactor;
- if(symbolLength_us >= 16000) {
- sfDivisor = 4*(this->spreadingFactor - 2);
- }
- const int8_t bitsPerCrc = 16;
- const int8_t N_symbol_header = this->headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0;
+ switch (modem) {
+ case RADIOLIB_MODEM_LORA: {
+ uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << dr.lora.spreadingFactor) / (dr.lora.bandwidth * 10) ;
+ uint8_t sfCoeff1_x4 = 17; // (4.25 * 4)
+ uint8_t sfCoeff2 = 8;
+ if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) {
+ sfCoeff1_x4 = 25; // 6.25 * 4
+ sfCoeff2 = 0;
+ }
+ uint8_t sfDivisor = 4*dr.lora.spreadingFactor;
+ if(pc.lora.ldrOptimize) {
+ sfDivisor = 4*(dr.lora.spreadingFactor - 2);
+ }
+ const int8_t bitsPerCrc = 16;
+ const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20;
- // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8)
- int16_t bitCount = (int16_t) 8 * len + this->crcTypeLoRa * bitsPerCrc - 4 * this->spreadingFactor + sfCoeff2 + N_symbol_header;
- if(bitCount < 0) {
- bitCount = 0;
+ // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8)
+ int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor + sfCoeff2 + N_symbol_header;
+ if(bitCount < 0) {
+ bitCount = 0;
+ }
+ // add (sfDivisor) - 1 to the numerator to give integer CEIL(...)
+ uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor);
+
+ // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit
+ uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4;
+
+ return((symbolLength_us * nSymbol_x4) / 4);
}
- // add (sfDivisor) - 1 to the numerator to give integer CEIL(...)
- uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor);
-
- // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit
- uint32_t nSymbol_x4 = (this->preambleLengthLoRa + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (this->codingRate + 4) * 4;
-
- return((symbolLength_us * nSymbol_x4) / 4);
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- return(((uint32_t)len * 8 * this->bitRate) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32));
-
- } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
- // calculate the number of bits based on coding rate
- uint16_t N_bits;
- switch(this->lrFhssCr) {
- case RADIOLIB_SX126X_LR_FHSS_CR_5_6:
- N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4?
- break;
- case RADIOLIB_SX126X_LR_FHSS_CR_2_3:
- N_bits = (len * 3) / 2;
- break;
- case RADIOLIB_SX126X_LR_FHSS_CR_1_2:
- N_bits = len * 2;
- break;
- case RADIOLIB_SX126X_LR_FHSS_CR_1_3:
- N_bits = len * 3;
- break;
- default:
- return(RADIOLIB_ERR_INVALID_CODING_RATE);
+ case RADIOLIB_MODEM_FSK: {
+ return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f)));
}
+ case RADIOLIB_MODEM_LRFHSS: {
+ // calculate the number of bits based on coding rate
+ uint16_t N_bits;
+ switch(dr.lrFhss.cr) {
+ case RADIOLIB_SX126X_LR_FHSS_CR_5_6:
+ N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4?
+ break;
+ case RADIOLIB_SX126X_LR_FHSS_CR_2_3:
+ N_bits = (len * 3) / 2;
+ break;
+ case RADIOLIB_SX126X_LR_FHSS_CR_1_2:
+ N_bits = len * 2;
+ break;
+ case RADIOLIB_SX126X_LR_FHSS_CR_1_3:
+ N_bits = len * 3;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_CODING_RATE);
+ }
- // calculate number of bits when accounting for unaligned last block
- uint16_t N_payBits = (N_bits / RADIOLIB_SX126X_LR_FHSS_FRAG_BITS) * RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS;
- uint16_t N_lastBlockBits = N_bits % RADIOLIB_SX126X_LR_FHSS_FRAG_BITS;
- if(N_lastBlockBits) {
- N_payBits += N_lastBlockBits + 2;
+ // calculate number of bits when accounting for unaligned last block
+ uint16_t N_payBits = (N_bits / RADIOLIB_SX126X_LR_FHSS_FRAG_BITS) * RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS;
+ uint16_t N_lastBlockBits = N_bits % RADIOLIB_SX126X_LR_FHSS_FRAG_BITS;
+ if(N_lastBlockBits) {
+ N_payBits += N_lastBlockBits + 2;
+ }
+
+ // add header bits
+ uint16_t N_totalBits = (RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits;
+ return(((uint32_t)N_totalBits * 8 * 1000000UL) / 488.28215f);
}
-
- // add header bits
- uint16_t N_totalBits = (RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount) + N_payBits;
- return(((uint32_t)N_totalBits * 8 * 1000000UL) / 488.28215f);
-
+ default:
+ return(RADIOLIB_ERR_WRONG_MODEM);
}
return(RADIOLIB_ERR_UNKNOWN);
}
+RadioLibTime_t SX126x::getTimeOnAir(size_t len) {
+ uint8_t type = getPacketType();
+ ModemType_t modem = RADIOLIB_MODEM_LORA;
+ DataRate_t dataRate = {};
+ PacketConfig_t packetConfig = {};
+
+ if(type == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ uint8_t cr = this->codingRate;
+ // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values
+ if (cr < 5) {
+ cr = cr + 4;
+ } else if (cr == 7) {
+ cr = cr + 1;
+ }
+
+ dataRate.lora.codingRate = cr;
+ dataRate.lora.spreadingFactor = this->spreadingFactor;
+ dataRate.lora.bandwidth = this->bandwidthKhz;
+
+ packetConfig.lora.preambleLength = this->preambleLengthLoRa;
+ packetConfig.lora.crcEnabled = (bool)this->crcTypeLoRa;
+ packetConfig.lora.implicitHeader = this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT;
+ packetConfig.lora.ldrOptimize = (bool)this->ldrOptimize;
+ } else if(type == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ modem = RADIOLIB_MODEM_FSK;
+
+ dataRate.fsk.bitRate = RADIOLIB_SX126X_CRYSTAL_FREQ * 32.0f * 1000.0f / (float)this->bitRate;
+ dataRate.fsk.freqDev = (float)this->frequencyDev;
+
+ uint8_t crcLen = 0;
+ if(this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_1_BYTE || this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV) {
+ crcLen = 1;
+ } else if(this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_2_BYTE || this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV) {
+ crcLen = 2;
+ }
+
+ packetConfig.fsk.preambleLength = this->preambleLengthFSK;
+ packetConfig.fsk.syncWordLength = this->syncWordLength;
+ packetConfig.fsk.crcLength = crcLen;
+ } else if(type == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
+ modem = RADIOLIB_MODEM_LRFHSS;
+
+ dataRate.lrFhss.bw = this->lrFhssBw;
+ dataRate.lrFhss.cr = this->lrFhssCr;
+ dataRate.lrFhss.narrowGrid = this->lrFhssGridNonFcc;
+
+ packetConfig.lrFhss.hdrCount = this->lrFhssHdrCount;
+ } else if(type == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
+ // BPSK is so experimental it does not have a specific data rate structure
+ // so just reuse FSK
+ modem = RADIOLIB_MODEM_FSK;
+
+ dataRate.fsk.bitRate = RADIOLIB_SX126X_CRYSTAL_FREQ * 32.0f * 1000.0f / (float)this->bitRate;
+ dataRate.fsk.freqDev = 0;
+
+ packetConfig.fsk.preambleLength = 0;
+ packetConfig.fsk.syncWordLength = 0;
+ packetConfig.fsk.crcLength = 0;
+
+ } else {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+
+ }
+
+ return(calculateTimeOnAir(modem, dataRate, packetConfig, len));
+}
+
RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
// the timeout value is given in units of 15.625 microseconds
// the calling function should provide some extra width, as this number of units is truncated to integer
- RadioLibTime_t timeout = timeoutUs / 15.625;
+ RadioLibTime_t timeout = timeoutUs / 15.625f;
return(timeout);
}
@@ -1546,55 +946,6 @@ int16_t SX126x::clearIrqFlags(uint32_t irq) {
return(this->clearIrqStatus(irq));
}
-int16_t SX126x::implicitHeader(size_t len) {
- return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
-}
-
-int16_t SX126x::explicitHeader() {
- return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT));
-}
-
-int16_t SX126x::setRegulatorLDO() {
- return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO));
-}
-
-int16_t SX126x::setRegulatorDCDC() {
- return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC));
-}
-
-int16_t SX126x::setEncoding(uint8_t encoding) {
- return(setWhitening(encoding));
-}
-
-void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
- this->mod->setRfSwitchPins(rxEn, txEn);
-}
-
-void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
- this->mod->setRfSwitchTable(pins, table);
-}
-
-int16_t SX126x::forceLDRO(bool enable) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // update modulation parameters
- this->ldroAuto = false;
- this->ldrOptimize = (uint8_t)enable;
- return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
-}
-
-int16_t SX126x::autoLDRO() {
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- this->ldroAuto = true;
- return(RADIOLIB_ERR_NONE);
-}
-
uint8_t SX126x::randomByte() {
// set some magic registers
this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_ENABLED, 0, 0);
@@ -1624,25 +975,11 @@ uint8_t SX126x::randomByte() {
return(randByte);
}
-int16_t SX126x::invertIQ(bool enable) {
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- if(enable) {
- this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED;
- } else {
- this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
- }
-
- return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
-}
-
int16_t SX126x::getModem(ModemType_t* modem) {
RADIOLIB_ASSERT_PTR(modem);
- uint8_t packetType = getPacketType();
- switch(packetType) {
+ uint8_t type = getPacketType();
+ switch(type) {
case(RADIOLIB_SX126X_PACKET_TYPE_LORA):
*modem = ModemType_t::RADIOLIB_MODEM_LORA;
return(RADIOLIB_ERR_NONE);
@@ -1657,6 +994,165 @@ int16_t SX126x::getModem(ModemType_t* modem) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
+int16_t SX126x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
+ int16_t state;
+
+ switch(mode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ // in implicit header mode, use the provided length if it is nonzero
+ // otherwise we trust the user has previously set the payload length manually
+ if((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (cfg->receive.len != 0)) {
+ this->implicitLen = cfg->receive.len;
+ }
+
+ state = startReceiveCommon(cfg->receive.timeout, cfg->receive.irqFlags, cfg->receive.irqMask);
+ RADIOLIB_ASSERT(state);
+
+ // if max(uint32_t) is used, revert to RxContinuous
+ if(cfg->receive.timeout == 0xFFFFFFFF) {
+ cfg->receive.timeout = 0xFFFFFF;
+ }
+ this->rxTimeout = cfg->receive.timeout;
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ // check packet length
+ if(cfg->transmit.len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+
+ // maximum packet length is decreased by 1 when address filtering is active
+ if((RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) &&
+ (cfg->transmit.len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+
+ // set packet Length
+ state = RADIOLIB_ERR_NONE;
+ uint8_t modem = getPacketType();
+ if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, cfg->transmit.len, this->headerType, this->invertIQEnabled);
+
+ } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType, cfg->transmit.len);
+
+ } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
+ uint16_t rampUp = RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_600_BPS;
+ uint16_t rampDown = RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_600_BPS;
+ if(this->bitRate == 100) {
+ rampUp = RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_100_BPS;
+ rampDown = RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_100_BPS;
+ }
+ state = setPacketParamsBPSK(cfg->transmit.len, rampUp, rampDown, 8*cfg->transmit.len);
+
+ } else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
+ return(RADIOLIB_ERR_UNKNOWN);
+
+ }
+ RADIOLIB_ASSERT(state);
+
+ // set DIO mapping
+ if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
+ state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE);
+ } else {
+ state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP, RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP);
+ }
+ RADIOLIB_ASSERT(state);
+
+ // set buffer pointers
+ state = setBufferBaseAddress();
+ RADIOLIB_ASSERT(state);
+
+ // write packet to buffer
+ if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
+ state = writeBuffer(cfg->transmit.data, cfg->transmit.len);
+
+ } else {
+ // first, reset the LR-FHSS state machine
+ state = resetLRFHSS();
+ RADIOLIB_ASSERT(state);
+
+ // skip hopping for the first 4 - lrFhssHdrCount blocks
+ for(int i = 0; i < 4 - this->lrFhssHdrCount; ++i ) {
+ stepLRFHSS();
+ }
+
+ // in LR-FHSS mode, we need to build the entire packet manually
+ uint8_t frame[RADIOLIB_SX126X_MAX_PACKET_LENGTH] = { 0 };
+ size_t frameLen = 0;
+ this->lrFhssFrameBitsRem = 0;
+ this->lrFhssFrameHopsRem = 0;
+ this->lrFhssHopNum = 0;
+ state = buildLRFHSSPacket(cfg->transmit.data, cfg->transmit.len, frame, &frameLen, &this->lrFhssFrameBitsRem, &this->lrFhssFrameHopsRem);
+ RADIOLIB_ASSERT(state);
+
+ // FIXME check max len for FHSS
+ state = writeBuffer(frame, frameLen);
+ RADIOLIB_ASSERT(state);
+
+ // activate hopping
+ const uint8_t hopCfg[] = { RADIOLIB_SX126X_HOPPING_ENABLED, (uint8_t)frameLen, (uint8_t)this->lrFhssFrameHopsRem };
+ state = writeRegister(RADIOLIB_SX126X_REG_HOPPING_ENABLE, hopCfg, 3);
+ RADIOLIB_ASSERT(state);
+
+ // write the initial hopping table
+ uint8_t initHops = this->lrFhssFrameHopsRem;
+ if(initHops > 16) {
+ initHops = 16;
+ };
+ for(size_t i = 0; i < initHops; i++) {
+ // set the hop frequency and symbols
+ state = this->setLRFHSSHop(i);
+ RADIOLIB_ASSERT(state);
+ }
+
+ }
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ state = clearIrqStatus();
+ RADIOLIB_ASSERT(state);
+
+ // fix sensitivity
+ state = fixSensitivity();
+ RADIOLIB_ASSERT(state);
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = mode;
+ return(state);
+}
+
+int16_t SX126x::launchMode() {
+ int16_t state;
+ switch(this->stagedMode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ this->mod->setRfSwitchState(Module::MODE_RX);
+ state = setRx(this->rxTimeout);
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ this->mod->setRfSwitchState(this->txMode);
+ state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE);
+ RADIOLIB_ASSERT(state);
+
+ // wait for BUSY to go low (= PA ramp up done)
+ while(this->mod->hal->digitalRead(this->mod->getGpio())) {
+ this->mod->hal->yield();
+ }
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
+ return(state);
+}
+
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
void SX126x::setDirectAction(void (*func)(void)) {
setDio1Action(func);
@@ -1687,7 +1183,8 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile)
for(uint32_t i = 0; i < len / sizeof(uint32_t); i++) {
uint32_t bin = 0;
if(nonvolatile) {
- bin = RADIOLIB_NONVOLATILE_READ_DWORD(patch + i);
+ uint32_t* ptr = const_cast(patch) + i;
+ bin = RADIOLIB_NONVOLATILE_READ_DWORD(ptr);
} else {
bin = patch[i];
}
@@ -1726,7 +1223,7 @@ int16_t SX126x::spectralScanStart(uint16_t numSamples, uint8_t window, uint8_t i
RADIOLIB_ASSERT(state);
// now set the actual spectral scan parameters
- uint8_t data[3] = { (uint8_t)((numSamples >> 8) & 0xFF), (uint8_t)(numSamples & 0xFF), interval };
+ const uint8_t data[3] = { (uint8_t)((numSamples >> 8) & 0xFF), (uint8_t)(numSamples & 0xFF), interval };
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS, data, 3));
}
@@ -1754,177 +1251,6 @@ int16_t SX126x::spectralScanGetResult(uint16_t* results) {
return(RADIOLIB_ERR_NONE);
}
-int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
- // check if TCXO is enabled at all
- if(this->XTAL) {
- return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
- }
-
- // set mode to standby
- standby();
-
- // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it
- if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) {
- clearDeviceErrors();
- }
-
- // check 0 V disable
- if(fabsf(voltage - 0.0) <= 0.001) {
- return(reset(true));
- }
-
- // check alowed voltage values
- uint8_t data[4];
- if(fabsf(voltage - 1.6) <= 0.001) {
- data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6;
- } else if(fabsf(voltage - 1.7) <= 0.001) {
- data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7;
- } else if(fabsf(voltage - 1.8) <= 0.001) {
- data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8;
- } else if(fabsf(voltage - 2.2) <= 0.001) {
- data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2;
- } else if(fabsf(voltage - 2.4) <= 0.001) {
- data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4;
- } else if(fabsf(voltage - 2.7) <= 0.001) {
- data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7;
- } else if(fabsf(voltage - 3.0) <= 0.001) {
- data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0;
- } else if(fabsf(voltage - 3.3) <= 0.001) {
- data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3;
- } else {
- return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
- }
-
- // calculate delay
- uint32_t delayValue = (float)delay / 15.625;
- data[1] = (uint8_t)((delayValue >> 16) & 0xFF);
- data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
- data[3] = (uint8_t)(delayValue & 0xFF);
-
- this->tcxoDelay = delay;
-
- // enable TCXO control on DIO3
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
-}
-
-int16_t SX126x::setDio2AsRfSwitch(bool enable) {
- uint8_t data = 0;
- if(enable) {
- data = RADIOLIB_SX126X_DIO2_AS_RF_SWITCH;
- } else {
- data = RADIOLIB_SX126X_DIO2_AS_IRQ;
- }
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
-}
-
-int16_t SX126x::setFs() {
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0));
-}
-
-int16_t SX126x::setTx(uint32_t timeout) {
- uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ;
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3));
-}
-
-int16_t SX126x::setRx(uint32_t timeout) {
- uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) };
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false));
-}
-
-int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) {
- // default CAD parameters are shown in Semtech AN1200.48, page 41.
- const uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30};
-
- // CAD parameters aren't available for SF-6. Just to be safe.
- if(this->spreadingFactor < 7) {
- this->spreadingFactor = 7;
- } else if(this->spreadingFactor > 12) {
- this->spreadingFactor = 12;
- }
-
- // build the packet with default configuration
- uint8_t data[7];
- data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB;
- data[1] = detPeakValues[this->spreadingFactor - 7];
- data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
- data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
- uint32_t timeout_raw = (float)timeout / 15.625f;
- data[4] = (uint8_t)((timeout_raw >> 16) & 0xFF);
- data[5] = (uint8_t)((timeout_raw >> 8) & 0xFF);
- data[6] = (uint8_t)(timeout_raw & 0xFF);
-
- // set user-provided values
- if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
- data[0] = symbolNum;
- }
-
- if(detPeak != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
- data[1] = detPeak;
- }
-
- if(detMin != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
- data[2] = detMin;
- }
-
- if(exitMode != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
- data[3] = exitMode;
- }
-
- // configure parameters
- int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
- RADIOLIB_ASSERT(state);
-
- // start CAD
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0));
-}
-
-int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) {
- uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut };
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4));
-}
-
-int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
- this->mod->SPIwriteRegisterBurst(addr, data, numBytes);
- return(RADIOLIB_ERR_NONE);
-}
-
-int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
- // send the command
- this->mod->SPIreadRegisterBurst(addr, numBytes, data);
-
- // check the status
- int16_t state = this->mod->SPIcheckStream();
- return(state);
-}
-
-int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
- uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset };
- return(this->mod->SPIwriteStream(cmd, 2, data, numBytes));
-}
-
-int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
- uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, offset };
- return(this->mod->SPIreadStream(cmd, 2, data, numBytes));
-}
-
-int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
- uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
- (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF),
- (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF),
- (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)};
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8));
-}
-
-int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) {
- uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) };
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2));
-}
-
-int16_t SX126x::setRfFrequency(uint32_t frf) {
- uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) };
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4));
-}
-
int16_t SX126x::calibrateImage(float freq) {
uint8_t data[2] = { 0, 0 };
@@ -1970,152 +1296,6 @@ int16_t SX126x::calibrateImageRejection(float freqMin, float freqMax) {
return(this->calibrateImage(data));
}
-int16_t SX126x::setPaRampTime(uint8_t rampTime) {
- return(this->setTxParams(this->pwr, rampTime));
-}
-
-int16_t SX126x::calibrateImage(uint8_t* data) {
- int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2);
-
- // if something failed, show the device errors
- #if RADIOLIB_DEBUG_BASIC
- if(state != RADIOLIB_ERR_NONE) {
- // unless mode is forced to standby, device errors will be 0
- standby();
- uint16_t errors = getDeviceErrors();
- RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
- }
- #endif
- return(state);
-}
-
-uint8_t SX126x::getPacketType() {
- uint8_t data = 0xFF;
- this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1);
- return(data);
-}
-
-int16_t SX126x::setTxParams(uint8_t pwr, uint8_t rampTime) {
- uint8_t data[] = { pwr, rampTime };
- int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2);
- if(state == RADIOLIB_ERR_NONE) {
- this->pwr = pwr;
- }
- return(state);
-}
-
-int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // set requested packet mode
- int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len);
- RADIOLIB_ASSERT(state);
-
- // update cached value
- this->packetType = mode;
- return(state);
-}
-
-int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) {
- // check active modem
- if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // set requested packet mode
- int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled);
- RADIOLIB_ASSERT(state);
-
- // update cached value
- this->headerType = hdrType;
- this->implicitLen = len;
-
- return(state);
-}
-
-int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
- // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled
- if(this->ldroAuto) {
- float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
- if(symbolLength >= 16.0) {
- this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON;
- } else {
- this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF;
- }
- } else {
- this->ldrOptimize = ldro;
- }
- // 500/9/8 - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8
- // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7
- uint8_t data[4] = {sf, bw, cr, this->ldrOptimize};
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4));
-}
-
-int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) {
- uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF),
- sh, rxBw,
- (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)};
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8));
-}
-
-int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ) {
- int16_t state = fixInvertedIQ(invertIQ);
- RADIOLIB_ASSERT(state);
- uint8_t data[6] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), hdrType, payloadLen, crcType, invertIQ};
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6));
-}
-
-int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType, uint8_t payloadLen) {
- uint8_t data[9] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
- preambleDetectorLen, syncWordLen, addrCmp,
- packType, payloadLen, crcType, whiten};
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9));
-}
-
-int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
- uint8_t data[2] = {txBaseAddress, rxBaseAddress};
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2));
-}
-
-int16_t SX126x::setRegulatorMode(uint8_t mode) {
- uint8_t data[1] = {mode};
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1));
-}
-
-uint8_t SX126x::getStatus() {
- uint8_t data = 0;
- this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 0);
- return(data);
-}
-
-uint32_t SX126x::getPacketStatus() {
- uint8_t data[3] = {0, 0, 0};
- this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3);
- return((((uint32_t)data[0]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[2]);
-}
-
-uint16_t SX126x::getDeviceErrors() {
- uint8_t data[2] = {0, 0};
- this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2);
- uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) | ((uint16_t)data[1]);
- return(opError);
-}
-
-int16_t SX126x::clearDeviceErrors() {
- uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP};
- return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2));
-}
-
-int16_t SX126x::setFrequencyRaw(float freq) {
- // calculate raw value
- this->freqMHz = freq;
- uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
- return(setRfFrequency(frf));
-}
-
int16_t SX126x::fixSensitivity() {
// fix receiver sensitivity for 500 kHz LoRa
// see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.1 for details
@@ -2126,7 +1306,7 @@ int16_t SX126x::fixSensitivity() {
RADIOLIB_ASSERT(state);
// fix the value for LoRa with 500 kHz bandwidth
- if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabsf(this->bandwidthKhz - 500.0) <= 0.001)) {
+ if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabsf(this->bandwidthKhz - 500.0f) <= 0.001f)) {
sensitivityConfig &= 0xFB;
} else {
sensitivityConfig |= 0x04;
@@ -2158,7 +1338,8 @@ int16_t SX126x::fixImplicitTimeout() {
//check if we're in implicit LoRa mode
if(!((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) {
- return(RADIOLIB_ERR_WRONG_MODEM);
+ // not in the correct mode, nothing to do here
+ return(RADIOLIB_ERR_NONE);
}
// stop RTC counter
@@ -2196,6 +1377,48 @@ int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) {
return(writeRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1));
}
+int16_t SX126x::fixGFSK() {
+ // method that applies some magic workaround for specific bitrate, frequency deviation,
+ // receiver bandwidth and carrier frequencies for GFSK (and resets it in all other cases)
+ // this is not documented in the datasheet, only in Semtech repositories for SX126x and LR11xx
+
+ // first, check we are using GFSK modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ // not in GFSK, nothing to do here
+ return(RADIOLIB_ERR_NONE);
+ }
+
+ // next, decide what to change based on modulation properties
+ int16_t state = RADIOLIB_ERR_UNKNOWN;
+ if(this->bitRate == 1200) {
+ // workaround for 1.2 kbps
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_3, 0x00, 4, 4);
+
+ } else if(this->bitRate == 600) {
+ // workaround for 0.6 kbps
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_1, 0x18, 4, 3);
+ RADIOLIB_ASSERT(state);
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, 0x04, 4, 2);
+ RADIOLIB_ASSERT(state);
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_3, 0x00, 4, 4);
+ RADIOLIB_ASSERT(state);
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_4, 0x50, 6, 4);
+
+ } else {
+ // reset
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_1, 0x08, 4, 3);
+ RADIOLIB_ASSERT(state);
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, 0x00, 4, 2);
+ RADIOLIB_ASSERT(state);
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_3, 0x10, 4, 4);
+ RADIOLIB_ASSERT(state);
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_4, 0x00, 6, 4);
+
+ }
+
+ return(state);
+}
+
Module* SX126x::getMod() {
return(this->mod);
}
@@ -2214,8 +1437,8 @@ int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem)
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS;
this->mod->spiConfig.stream = true;
this->mod->spiConfig.parseStatusCb = SPIparseStatus;
-
- // try to find the SX126x chip
+
+ // find the SX126x chip - this will also reset the module and verify the module
if(!SX126x::findChip(this->chipType)) {
RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!");
this->mod->term();
@@ -2223,22 +1446,37 @@ int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem)
}
RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x");
- // reset the module and verify startup
- int16_t state = reset();
- RADIOLIB_ASSERT(state);
-
- // set mode to standby
- state = standby();
- RADIOLIB_ASSERT(state);
+ int16_t state = RADIOLIB_ERR_NONE;
// set TCXO control, if requested
- if(!this->XTAL && tcxoVoltage > 0.0) {
+ if(!this->XTAL && tcxoVoltage > 0.0f) {
state = setTCXO(tcxoVoltage);
RADIOLIB_ASSERT(state);
}
// configure settings not accessible by API
state = config(modem);
+
+ // if something failed, check the device errors
+ if(state != RADIOLIB_ERR_NONE) {
+ // unless mode is forced to standby, device errors will be 0
+ (void)standby();
+ uint16_t errors = getDeviceErrors();
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Config failed, device errors: 0x%X", errors);
+
+ // SPI command fail and oscillator start error flag indicate incorrectly set oscillator
+ if((state == RADIOLIB_ERR_SPI_CMD_FAILED) && (errors & RADIOLIB_SX126X_XOSC_START_ERR)) {
+ // typically users with XTAL devices will try to call the default begin method
+ // disable TCXO and try to run config again
+ this->XTAL = false;
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Bad oscillator selected, trying XTAL");
+
+ state = setTCXO(0);
+ RADIOLIB_ASSERT(state);
+
+ state = config(modem);
+ }
+ }
RADIOLIB_ASSERT(state);
if (useRegulatorLDO) {
@@ -2249,65 +1487,6 @@ int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem)
return(state);
}
-int16_t SX126x::config(uint8_t modem) {
- // reset buffer base address
- int16_t state = setBufferBaseAddress();
- RADIOLIB_ASSERT(state);
-
- // set modem
- uint8_t data[7];
- data[0] = modem;
- state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1);
- RADIOLIB_ASSERT(state);
-
- // set Rx/Tx fallback mode to STDBY_RC
- data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
- state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
- RADIOLIB_ASSERT(state);
-
- // set some CAD parameters - will be overwritten when calling CAD anyway
- data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
- data[1] = this->spreadingFactor + 13;
- data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
- data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
- data[4] = 0x00;
- data[5] = 0x00;
- data[6] = 0x00;
- state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
- RADIOLIB_ASSERT(state);
-
- // clear IRQ
- state = clearIrqStatus();
- state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE);
- RADIOLIB_ASSERT(state);
-
- // calibrate all blocks
- data[0] = RADIOLIB_SX126X_CALIBRATE_ALL;
- state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false);
- RADIOLIB_ASSERT(state);
-
- // wait for calibration completion
- this->mod->hal->delay(5);
- while(this->mod->hal->digitalRead(this->mod->getGpio())) {
- this->mod->hal->yield();
- }
-
- // check calibration result
- state = this->mod->SPIcheckStream();
-
- // if something failed, show the device errors
- #if RADIOLIB_DEBUG_BASIC
- if(state != RADIOLIB_ERR_NONE) {
- // unless mode is forced to standby, device errors will be 0
- standby();
- uint16_t errors = getDeviceErrors();
- RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
- }
- #endif
-
- return(state);
-}
-
int16_t SX126x::SPIparseStatus(uint8_t in) {
if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) {
return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
@@ -2326,10 +1505,10 @@ bool SX126x::findChip(const char* verStr) {
bool flagFound = false;
while((i < 10) && !flagFound) {
// reset the module
- reset();
+ reset(true);
// read the version string
- char version[16];
+ char version[16] = { 0 };
this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, reinterpret_cast(version));
// check version register
diff --git a/lib/RadioLib/src/modules/SX126x/SX126x.h b/lib/RadioLib/src/modules/SX126x/SX126x.h
index 5fba5a3..984fb92 100644
--- a/lib/RadioLib/src/modules/SX126x/SX126x.h
+++ b/lib/RadioLib/src/modules/SX126x/SX126x.h
@@ -11,453 +11,15 @@
#include "../../utils/FEC.h"
#include "../../utils/CRC.h"
+#include "SX126x_commands.h"
+#include "SX126x_registers.h"
+
// SX126X physical layer properties
#define RADIOLIB_SX126X_FREQUENCY_STEP_SIZE 0.9536743164
#define RADIOLIB_SX126X_MAX_PACKET_LENGTH 255
-#define RADIOLIB_SX126X_CRYSTAL_FREQ 32.0
+#define RADIOLIB_SX126X_CRYSTAL_FREQ 32.0f
#define RADIOLIB_SX126X_DIV_EXPONENT 25
-// SX126X SPI commands
-// operational modes commands
-#define RADIOLIB_SX126X_CMD_NOP 0x00
-#define RADIOLIB_SX126X_CMD_SET_SLEEP 0x84
-#define RADIOLIB_SX126X_CMD_SET_STANDBY 0x80
-#define RADIOLIB_SX126X_CMD_SET_FS 0xC1
-#define RADIOLIB_SX126X_CMD_SET_TX 0x83
-#define RADIOLIB_SX126X_CMD_SET_RX 0x82
-#define RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F
-#define RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE 0x94
-#define RADIOLIB_SX126X_CMD_SET_CAD 0xC5
-#define RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1
-#define RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2
-#define RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE 0x96
-#define RADIOLIB_SX126X_CMD_CALIBRATE 0x89
-#define RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE 0x98
-#define RADIOLIB_SX126X_CMD_SET_PA_CONFIG 0x95
-#define RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93
-
-// register and buffer access commands
-#define RADIOLIB_SX126X_CMD_WRITE_REGISTER 0x0D
-#define RADIOLIB_SX126X_CMD_READ_REGISTER 0x1D
-#define RADIOLIB_SX126X_CMD_WRITE_BUFFER 0x0E
-#define RADIOLIB_SX126X_CMD_READ_BUFFER 0x1E
-
-// DIO and IRQ control
-#define RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08
-#define RADIOLIB_SX126X_CMD_GET_IRQ_STATUS 0x12
-#define RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS 0x02
-#define RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D
-#define RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97
-
-// RF, modulation and packet commands
-#define RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY 0x86
-#define RADIOLIB_SX126X_CMD_SET_PACKET_TYPE 0x8A
-#define RADIOLIB_SX126X_CMD_GET_PACKET_TYPE 0x11
-#define RADIOLIB_SX126X_CMD_SET_TX_PARAMS 0x8E
-#define RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS 0x8B
-#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C
-#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88
-#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F
-#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0
-
-// status commands
-#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0
-#define RADIOLIB_SX126X_CMD_GET_RSSI_INST 0x15
-#define RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS 0x13
-#define RADIOLIB_SX126X_CMD_GET_PACKET_STATUS 0x14
-#define RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS 0x17
-#define RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07
-#define RADIOLIB_SX126X_CMD_GET_STATS 0x10
-#define RADIOLIB_SX126X_CMD_RESET_STATS 0x00
-
-#define RADIOLIB_SX126X_CMD_PRAM_UPDATE 0xD9
-#define RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS 0x9A
-#define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B
-
-// SX126X register map
-#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6
-#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6
-#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6
-#define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320
-#define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385
-#define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386
-#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_HOPPING_BLOCKS 0x0387
-#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(X) (0x0388 + (X)*6)
-#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_LSB(X) (0x0389 + (X)*6)
-#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(X) (0x038A + (X)*6)
-#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_1(X) (0x038B + (X)*6)
-#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_2(X) (0x038C + (X)*6)
-#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6)
-#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT 0x0401
-#define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580
-#define RADIOLIB_SX126X_REG_DIOX_DRIVE_STRENGTH 0x0582
-#define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583
-#define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584
-#define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585
-#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587
-#define RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE 0x0610
-#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680
-#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8
-#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9
-#define RADIOLIB_SX126X_REG_RX_TX_PLD_LEN 0x06BB
-#define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC
-#define RADIOLIB_SX126X_REG_CRC_INITIAL_LSB 0x06BD
-#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE
-#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF
-#define RADIOLIB_SX126X_REG_SYNC_WORD_0 0x06C0
-#define RADIOLIB_SX126X_REG_SYNC_WORD_1 0x06C1
-#define RADIOLIB_SX126X_REG_SYNC_WORD_2 0x06C2
-#define RADIOLIB_SX126X_REG_SYNC_WORD_3 0x06C3
-#define RADIOLIB_SX126X_REG_SYNC_WORD_4 0x06C4
-#define RADIOLIB_SX126X_REG_SYNC_WORD_5 0x06C5
-#define RADIOLIB_SX126X_REG_SYNC_WORD_6 0x06C6
-#define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7
-#define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD
-#define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE
-#define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702
-#define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704
-#define RADIOLIB_SX126X_REG_LORA_SYNC_TIMEOUT 0x0706
-#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736
-#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740
-#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741
-#define RADIOLIB_SX126X_REG_FREQ_ERROR 0x076B
-#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS 0x07CD
-#define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803
-#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819
-#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A
-#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B
-#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C
-#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1
-#define RADIOLIB_SX126X_REG_RF_FREQUENCY_0 0x088B
-#define RADIOLIB_SX126X_REG_RF_FREQUENCY_1 0x088C
-#define RADIOLIB_SX126X_REG_RF_FREQUENCY_2 0x088D
-#define RADIOLIB_SX126X_REG_RF_FREQUENCY_3 0x088E
-#define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B
-#define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC
-#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8
-#define RADIOLIB_SX126X_REG_ANA_LNA 0x08E2
-#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3
-#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_P 0x08E4
-#define RADIOLIB_SX126X_REG_ANA_MIXER 0x08E5
-#define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7
-#define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902
-#define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911
-#define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912
-#define RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL 0x0920
-#define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944
-#define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000
-
-// SX126X SPI command variables
-//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION
-#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default)
-#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained
-#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled
-#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled
-
-//RADIOLIB_SX126X_CMD_SET_STANDBY
-#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator
-#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator
-
-//RADIOLIB_SX126X_CMD_SET_RX
-#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode)
-#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode)
-
-//RADIOLIB_SX126X_CMD_SET_TX
-#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode)
-
-//RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE
-#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default)
-#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection
-
-//RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE
-#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default)
-#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC
-
-//RADIOLIB_SX126X_CMD_CALIBRATE
-#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled
-#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled
-#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled
-#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled
-#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled
-#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled
-#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled
-#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled
-#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled
-#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled
-#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled
-#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled
-#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled
-#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled
-#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks
-
-//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE
-#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B
-#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F
-#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75
-#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81
-#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1
-#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5
-#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7
-#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB
-#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1
-#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9
-#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0)
-
-//RADIOLIB_SX126X_CMD_SET_PA_CONFIG
-#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07
-#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01
-#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00
-
-//RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE
-#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode
-#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator
-#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default)
-
-//RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS
-#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop
-#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout
-#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected
-#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished
-#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received
-#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error
-#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received
-#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected
-#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected
-#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received
-#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed
-#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts
-#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts
-
-//RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL
-#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ
-#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control
-
-//RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL
-#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V
-#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V
-#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V
-#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V
-#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V
-#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V
-#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V
-#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V
-
-//RADIOLIB_SX126X_CMD_SET_PACKET_TYPE
-#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK
-#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa
-#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS
-
-//RADIOLIB_SX126X_CMD_SET_TX_PARAMS
-#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us
-#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us
-#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us
-#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us
-#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us
-#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us
-#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us
-#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us
-
-//RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS
-#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none
-#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3
-#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5
-#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7
-#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1
-#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz
-#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz
-#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz
-#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz
-#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz
-#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz
-#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz
-#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz
-#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz
-#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz
-#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz
-#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz
-#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5
-#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6
-#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7
-#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8
-#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled
-#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled
-
-//RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS
-#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled
-#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits
-#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits
-#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits
-#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits
-#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled
-#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only
-#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast
-#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides)
-#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet)
-#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled
-#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte
-#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte
-#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted
-#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted
-#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled
-#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled
-#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit
-#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit
-#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled
-#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled
-#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard
-#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted
-
-//RADIOLIB_SX126X_CMD_SET_CAD_PARAMS
-#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1
-#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2
-#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4
-#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8
-#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16
-#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode
-#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected
-#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value
-#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter
-
-//RADIOLIB_SX126X_CMD_GET_STATUS
-#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC
-#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC
-#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS
-#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX
-#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX
-#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved
-#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out
-#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command
-#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute
-#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done
-#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed
-
-//RADIOLIB_SX126X_CMD_GET_PACKET_STATUS
-#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error
-#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error
-#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error
-#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error
-#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error
-#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error
-#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received
-#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent
-
-//RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS
-#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed
-#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock
-#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start
-#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed
-#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed
-#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed
-#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed
-#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed
-
-//RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS + RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS
-#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us
-#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us
-#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us
-
-// SX126X SPI register variables
-//RADIOLIB_SX126X_REG_HOPPING_ENABLE
-#define RADIOLIB_SX126X_HOPPING_ENABLED 0b00000001 // 0 0 intra-packet hopping for LR-FHSS: enabled
-#define RADIOLIB_SX126X_HOPPING_DISABLED 0b00000000 // 0 0 (disabled)
-
-//RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB + LSB
-#define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved.
-#define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried.
-
-// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1
-#define RADIOLIB_SX126X_TX_BITBANG_1_DISABLED 0b00000000 // 6 4 Tx bitbang: disabled (default)
-#define RADIOLIB_SX126X_TX_BITBANG_1_ENABLED 0b00010000 // 6 4 enabled
-
-// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0
-#define RADIOLIB_SX126X_TX_BITBANG_0_DISABLED 0b00000000 // 3 0 Tx bitbang: disabled (default)
-#define RADIOLIB_SX126X_TX_BITBANG_0_ENABLED 0b00001100 // 3 0 enabled
-
-// RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE
-#define RADIOLIB_SX126X_DIO1_OUT_DISABLED 0b00000010 // 1 1 DIO1 output: disabled
-#define RADIOLIB_SX126X_DIO1_OUT_ENABLED 0b00000000 // 1 1 enabled
-#define RADIOLIB_SX126X_DIO2_OUT_DISABLED 0b00000100 // 2 2 DIO2 output: disabled
-#define RADIOLIB_SX126X_DIO2_OUT_ENABLED 0b00000000 // 2 2 enabled
-#define RADIOLIB_SX126X_DIO3_OUT_DISABLED 0b00001000 // 3 3 DIO3 output: disabled
-#define RADIOLIB_SX126X_DIO3_OUT_ENABLED 0b00000000 // 3 3 enabled
-
-// RADIOLIB_SX126X_REG_DIOX_IN_ENABLE
-#define RADIOLIB_SX126X_DIO1_IN_DISABLED 0b00000000 // 1 1 DIO1 input: disabled
-#define RADIOLIB_SX126X_DIO1_IN_ENABLED 0b00000010 // 1 1 enabled
-#define RADIOLIB_SX126X_DIO2_IN_DISABLED 0b00000000 // 2 2 DIO2 input: disabled
-#define RADIOLIB_SX126X_DIO2_IN_ENABLED 0b00000100 // 2 2 enabled
-#define RADIOLIB_SX126X_DIO3_IN_DISABLED 0b00000000 // 3 3 DIO3 input: disabled
-#define RADIOLIB_SX126X_DIO3_IN_ENABLED 0b00001000 // 3 3 enabled
-
-// RADIOLIB_SX126X_REG_RX_GAIN
-#define RADIOLIB_SX126X_RX_GAIN_BOOSTED 0x96 // 7 0 Rx gain: boosted
-#define RADIOLIB_SX126X_RX_GAIN_POWER_SAVING 0x94 // 7 0 power saving
-#define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan
-
-// RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE
-#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00000000 // 4 4 patch update: disabled
-#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00010000 // 4 4 enabled
-
-// RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS
-#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none
-#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing
-#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted
-#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed
-
-// RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW
-#define RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window
-
-// RADIOLIB_SX126X_REG_ANA_LNA
-#define RADIOLIB_SX126X_LNA_RNG_DISABLED 0b00000001 // 0 0 random number: disabled
-#define RADIOLIB_SX126X_LNA_RNG_ENABLED 0b00000000 // 0 0 enabled
-
-// RADIOLIB_SX126X_REG_ANA_MIXER
-#define RADIOLIB_SX126X_MIXER_RNG_DISABLED 0b00000001 // 7 7 random number: disabled
-#define RADIOLIB_SX126X_MIXER_RNG_ENABLED 0b00000000 // 7 7 enabled
-
-// size of the spectral scan result
-#define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33)
-
-// LR-FHSS configuration
-#define RADIOLIB_SX126X_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6
-#define RADIOLIB_SX126X_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3
-#define RADIOLIB_SX126X_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2
-#define RADIOLIB_SX126X_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3
-#define RADIOLIB_SX126X_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK
-#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC)
-#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC)
-#define RADIOLIB_SX126X_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled
-#define RADIOLIB_SX126X_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled
-#define RADIOLIB_SX126X_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz
-#define RADIOLIB_SX126X_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz
-#define RADIOLIB_SX126X_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz
-#define RADIOLIB_SX126X_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz
-#define RADIOLIB_SX126X_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz
-#define RADIOLIB_SX126X_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz
-#define RADIOLIB_SX126X_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz
-#define RADIOLIB_SX126X_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz
-#define RADIOLIB_SX126X_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz
-#define RADIOLIB_SX126X_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz
-
// LR-FHSS packet lengths
#define RADIOLIB_SX126X_LR_FHSS_MAX_ENC_SIZE (608)
#define RADIOLIB_SX126X_LR_FHSS_HEADER_BITS (114)
@@ -478,8 +40,20 @@ class SX126x: public PhysicalLayer {
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
+ using PhysicalLayer::startReceive;
using PhysicalLayer::readData;
+ /*!
+ \struct paTableEntry_t
+ \brief This structure is used as entry in the PA lookup table,
+ to optimize PA configuration for minimum power consumption.
+ */
+ struct __attribute__((packed)) paTableEntry_t {
+ uint8_t paDutyCycle: 4;
+ uint8_t hpMax: 4;
+ int8_t paVal;
+ };
+
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
@@ -500,7 +74,8 @@ class SX126x: public PhysicalLayer {
/*!
\brief Initialization method for LoRa modem.
- \param cr LoRa coding rate denominator. Allowed values range from 5 to 8.
+ \param cr LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord 1-byte LoRa sync word.
\param preambleLength LoRa preamble length in symbols. Allowed values range from 1 to 65535.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
@@ -522,6 +97,15 @@ class SX126x: public PhysicalLayer {
*/
int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false);
+ /*!
+ \brief Initialization method for BPSK modem.
+ \param br FSK bit rate in kbps. Only 100 and 600 bps is supported.
+ \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
+ \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
+ \returns \ref status_codes
+ */
+ int16_t beginBPSK(float br, float tcxoVoltage, bool useRegulatorLDO = false);
+
/*!
\brief Initialization method for LR-FHSS modem. This modem only supports transmission!
\param bw LR-FHSS bandwidth, one of RADIOLIB_SX126X_LR_FHSS_BW_* values.
@@ -564,11 +148,13 @@ class SX126x: public PhysicalLayer {
/*!
\brief Blocking binary receive method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
- \param data Binary data to be sent.
- \param len Number of bytes to send.
+ \param data Pointer to array to save the received binary data.
+ \param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+ \param timeout Reception timeout in milliseconds. If set to 0,
+ timeout period will be calculated automatically based on the radio configuration.
\returns \ref status_codes
*/
- int16_t receive(uint8_t* data, size_t len) override;
+ int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override;
/*!
\brief Starts direct mode transmission.
@@ -598,6 +184,22 @@ class SX126x: public PhysicalLayer {
*/
int16_t scanChannel(const ChannelScanConfig_t &config) override;
+ /*!
+ \brief Reset the AGC gain state by performing a warm sleep, recalibration, and
+ image rejection calibration cycle. Re-applies DIO2 RF switch and RX boosted gain
+ settings if previously configured. Leaves the radio in standby mode.
+ \returns \ref status_codes
+ */
+ int16_t resetAGC();
+
+ /*!
+ \brief Perform calibration of the specified blocks.
+ \param params Calibration parameters - bitfield of RADIOLIB_SX126X_CALIBRATE_* values.
+ Use RADIOLIB_SX126X_CALIBRATE_ALL to calibrate all blocks.
+ \returns \ref status_codes
+ */
+ int16_t calibrate(uint8_t params);
+
/*!
\brief Sets the module to sleep mode. To wake the device up, call standby().
Overload with warm start enabled for PhysicalLayer compatibility.
@@ -619,6 +221,14 @@ class SX126x: public PhysicalLayer {
*/
int16_t standby() override;
+ /*!
+ \brief Sets the module to standby mode.
+ \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX126X_STANDBY_RC (13 MHz RC oscillator)
+ or RADIOLIB_SX126X_STANDBY_XOSC (32 MHz external crystal oscillator).
+ \returns \ref status_codes
+ */
+ int16_t standby(uint8_t mode) override;
+
/*!
\brief Sets the module to standby mode.
\param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX126X_STANDBY_RC (13 MHz RC oscillator)
@@ -626,7 +236,14 @@ class SX126x: public PhysicalLayer {
\param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module.
\returns \ref status_codes
*/
- int16_t standby(uint8_t mode, bool wakeup = true);
+ int16_t standby(uint8_t mode, bool wakeup);
+
+ /*!
+ \brief Handle LR-FHSS hop.
+ When using LR-FHSS in interrupt-driven mode, this method MUST be called each time an interrupt is triggered!
+ \returns \ref status_codes
+ */
+ int16_t hopLRFHSS();
// interrupt methods
@@ -634,12 +251,12 @@ class SX126x: public PhysicalLayer {
\brief Sets interrupt service routine to call when DIO1 activates.
\param func ISR to call.
*/
- void setDio1Action(void (*func)(void));
+ virtual void setDio1Action(void (*func)(void));
/*!
\brief Clears interrupt service routine to call when DIO1 activates.
*/
- void clearDio1Action();
+ virtual void clearDio1Action();
/*!
\brief Sets interrupt service routine to call when a packet is received.
@@ -674,21 +291,17 @@ class SX126x: public PhysicalLayer {
*/
void clearChannelScanAction() override;
- /*!
- \brief Interrupt-driven binary transmit method.
- Overloads for string-based transmissions are implemented in PhysicalLayer.
- \param data Binary data to be sent.
- \param len Number of bytes to send.
- \param addr Address to send the data to. Will only be added if address filtering was enabled.
- \returns \ref status_codes
- */
- int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override;
-
/*!
\brief Clean up after transmission is done.
\returns \ref status_codes
*/
int16_t finishTransmit() override;
+
+ /*!
+ \brief Clean up after reception is done.
+ \returns \ref status_codes
+ */
+ int16_t finishReceive() override;
/*!
\brief Interrupt-driven receive method with default parameters.
@@ -698,23 +311,6 @@ class SX126x: public PhysicalLayer {
*/
int16_t startReceive() override;
- /*!
- \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received.
- \param timeout Receive mode type and/or raw timeout value, expressed as multiples of 15.625 us.
- When set to RADIOLIB_SX126X_RX_TIMEOUT_INF, the timeout will be infinite and the device will remain
- in Rx mode until explicitly commanded to stop (Rx continuous mode).
- When set to RADIOLIB_SX126X_RX_TIMEOUT_NONE, there will be no timeout and the device will return
- to standby when a packet is received (Rx single mode).
- For any other value, timeout will be applied and signal will be generated on DIO1 for conditions
- defined by irqFlags and irqMask.
-
- \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error.
- \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done.
- \param len Only for PhysicalLayer compatibility, not used.
- \returns \ref status_codes
- */
- int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0);
-
/*!
\brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen.
Note that this function assumes the unit will take 500us + TCXO_delay to change state.
@@ -733,17 +329,21 @@ class SX126x: public PhysicalLayer {
\brief Calls \ref startReceiveDutyCycle with rxPeriod and sleepPeriod set so the unit shouldn't miss any messages.
\param senderPreambleLength Expected preamble length of the messages to receive.
If set to zero, the currently configured preamble length will be used. Defaults to zero.
+ This value cannot exceed the configured preamble length. If the sender preamble length is variable, set the
+ maximum expected length by calling setPreambleLength(maximumExpectedLength) prior to this method, and use the
+ minimum expected length here.
- \param minSymbols Parameters will be chosen to ensure that the unit will catch at least this many symbols
- of any preamble of the specified length. Defaults to 8.
- According to Semtech, receiver requires 8 symbols to reliably latch a preamble.
- This makes this method redundant when transmitter preamble length is less than 17 (2*minSymbols + 1).
+ \param minSymbols Ensure that the unit will catch at least this many symbols of any preamble of the specified senderPreambleLength.
+ To reliably latch a preamble, the receiver requires 8 symbols for SF7-12 and 12 symbols for SF5-6 (see datasheet section 6.1.1.1, version 1.2).
+ If set to zero, the minimum required symbols will be used. Defaults to 0.
+
+ If senderPreambleLength is less than 2*minSymbols + 1, this method is equivalent to startReceive().
\param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error.
\param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done.
\returns \ref status_codes
*/
- int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK);
+ int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 0, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK);
/*!
\brief Reads data received after calling startReceive method. When the packet length is not known in advance,
@@ -783,21 +383,25 @@ class SX126x: public PhysicalLayer {
\param bw LoRa bandwidth to be set in kHz.
\returns \ref status_codes
*/
- int16_t setBandwidth(float bw);
+ virtual int16_t setBandwidth(float bw);
/*!
\brief Sets LoRa spreading factor. Allowed values range from 5 to 12.
\param sf LoRa spreading factor to be set.
\returns \ref status_codes
*/
- int16_t setSpreadingFactor(uint8_t sf);
+ virtual int16_t setSpreadingFactor(uint8_t sf);
/*!
- \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8.
+ \brief Sets LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param cr LoRa coding rate denominator to be set.
+ \param longInterleave Enable long interleaver when set to true.
+ Note that with long interleaver enabled, CR 4/7 is not possible, there are packet length restrictions,
+ and it is not compatible with SX127x radios.
\returns \ref status_codes
*/
- int16_t setCodingRate(uint8_t cr);
+ int16_t setCodingRate(uint8_t cr, bool longInterleave = false);
/*!
\brief Sets LoRa sync word.
@@ -846,18 +450,22 @@ class SX126x: public PhysicalLayer {
int16_t setBitRate(float br) override;
/*!
- \brief Set data.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \brief Set data rate.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t setDataRate(DataRate_t dr) override;
+ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Check the data rate can be configured by this module.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t checkDataRate(DataRate_t dr) override;
+ int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Sets FSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5,
@@ -899,36 +507,6 @@ class SX126x: public PhysicalLayer {
*/
int16_t setSyncWord(uint8_t* syncWord, size_t len) override;
- /*!
- \brief Sets FSK sync word in the form of array of up to 8 bytes.
- \param syncWord FSK sync word to be set.
- \param bitsLen FSK sync word length in bits. If length is not divisible by 8,
- least significant bits of syncWord will be ignored.
- \returns \ref status_codes
- */
- int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen);
-
- /*!
- \brief Sets node address. Calling this method will also enable address filtering for node address only.
- \param addr Node address to be set.
- \returns \ref status_codes
- */
- int16_t setNodeAddress(uint8_t addr);
-
- /*!
- \brief Sets broadcast address. Calling this method will also enable address
- filtering for node and broadcast address.
- \param broadAddr Node address to be set.
- \returns \ref status_codes
- */
- int16_t setBroadcastAddress(uint8_t broadAddr);
-
- /*!
- \brief Disables address filtering. Calling this method will also erase previously set addresses.
- \returns \ref status_codes
- */
- int16_t disableAddressFiltering();
-
/*!
\brief Sets CRC configuration.
\param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC.
@@ -966,20 +544,14 @@ class SX126x: public PhysicalLayer {
int16_t setDio2AsRfSwitch(bool enable = true);
/*!
- \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes.
- \returns Effective data rate in bps.
- */
- float getDataRate() const;
-
- /*!
- \brief Gets recorded signal strength indicator.
+ \brief Gets received signal strength indicator.
Overload with packet mode enabled for PhysicalLayer compatibility.
\returns RSSI value in dBm.
*/
float getRSSI() override;
/*!
- \brief Gets RSSI (Recorded Signal Strength Indicator).
+ \brief Gets RSSI (Received Signal Strength Indicator).
\param packet Whether to read last packet RSSI, or the current value.
\returns RSSI value in dBm.
*/
@@ -1002,19 +574,27 @@ class SX126x: public PhysicalLayer {
/*!
\brief Query modem for the packet length of received payload.
- \param update Update received packet length. Will return cached value when set to false.
+ \param update Not used for SX126x modules.
\returns Length of last received packet in bytes.
*/
size_t getPacketLength(bool update = true) override;
/*!
\brief Query modem for the packet length of received payload and Rx buffer offset.
- \param update Update received packet length. Will return cached value when set to false.
+ \param update Not used for SX126x modules.
\param offset Pointer to variable to store the Rx buffer offset.
\returns Length of last received packet in bytes.
*/
size_t getPacketLength(bool update, uint8_t* offset);
+ /*!
+ \brief Get LoRa header information from last received packet. Only valid in explicit header mode.
+ \param cr Pointer to variable to store the coding rate.
+ \param hasCRC Pointer to variable to store the CRC status.
+ \returns \ref status_codes
+ */
+ int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC);
+
/*!
\brief Set modem in fixed packet length mode. Available in FSK mode only.
\param len Packet length.
@@ -1029,6 +609,16 @@ class SX126x: public PhysicalLayer {
*/
int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH);
+ /*!
+ \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size.
+ \param modem Modem type.
+ \param dr Data rate.
+ \param pc Packet config.
+ \param len Payload length in bytes.
+ \returns Expected time-on-air in microseconds.
+ */
+ RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override;
+
/*!
\brief Get expected time-on-air for a given size of payload
\param len Payload length in bytes.
@@ -1127,7 +717,7 @@ class SX126x: public PhysicalLayer {
/*!
\brief Enable/disable inversion of the I and Q signals
- \param enable QI inversion enabled (true) or disabled (false);
+ \param enable IQ inversion enabled (true) or disabled (false);
\returns \ref status_codes
*/
int16_t invertIQ(bool enable) override;
@@ -1138,6 +728,12 @@ class SX126x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t getModem(ModemType_t* modem) override;
+
+ /*! \copydoc PhysicalLayer::stageMode */
+ int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override;
+
+ /*! \copydoc PhysicalLayer::launchMode */
+ int16_t launchMode() override;
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
/*!
@@ -1228,6 +824,21 @@ class SX126x: public PhysicalLayer {
*/
int16_t setPaRampTime(uint8_t rampTime);
+ /*!
+ \brief Sets output power. Allowed values are in range from -9 to 22 dBm.
+ This method allows user full control over PA configuration parameters.
+ If you set incorrect PA configuration values, you can fail to reach the
+ desired output power level or damage your device.
+ Unless you can verify the output power, it is strongly advised to use
+ SX1262::setOutputPower(power) or SX1268::setOutputPower(power).
+ \param power Output power to be set in dBm.
+ \param paDutyCycle Raw PA duty cycle value.
+ \param hpMax Raw hpMax value.
+ \param deviceSel Device select. Use either RADIOLIB_SX126X_PA_CONFIG_SX1262 or RADIOLIB_SX126X_PA_CONFIG_SX1268.
+ \returns \ref status_codes
+ */
+ int16_t setOutputPower(int8_t power, uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel);
+
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
@@ -1238,20 +849,22 @@ class SX126x: public PhysicalLayer {
int16_t setTx(uint32_t timeout = 0);
int16_t setRx(uint32_t timeout);
int16_t setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout);
- int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
+ int16_t writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes);
int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
- int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
+ int16_t writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
int16_t readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE);
virtual int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL);
int16_t setRfFrequency(uint32_t frf);
- int16_t calibrateImage(uint8_t* data);
+ int16_t calibrateImage(const uint8_t* data);
uint8_t getPacketType();
int16_t setTxParams(uint8_t power, uint8_t rampTime);
int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro);
int16_t setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev);
+ int16_t setModulationParamsBPSK(uint32_t br, uint8_t sh = RADIOLIB_SX126X_BPSK_PULSE_SHAPE);
int16_t setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ);
int16_t setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLen = 0xFF);
+ int16_t setPacketParamsBPSK(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t payloadLenBits);
int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00);
int16_t setRegulatorMode(uint8_t mode);
uint8_t getStatus();
@@ -1290,13 +903,14 @@ class SX126x: public PhysicalLayer {
uint16_t preambleLengthFSK = 0;
float rxBandwidthKhz = 0;
- float dataRateMeasured = 0;
-
uint32_t tcxoDelay = 0;
uint8_t pwr = 0;
+ bool dio2RfSwitch = false;
+ bool rxBoostedGainMode = false;
size_t implicitLen = 0;
uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
+ uint32_t rxTimeout = 0;
// LR-FHSS stuff - there's a lot of it because all the encoding happens in software
uint8_t lrFhssCr = RADIOLIB_SX126X_LR_FHSS_CR_2_3;
@@ -1326,6 +940,7 @@ class SX126x: public PhysicalLayer {
int16_t fixSensitivity();
int16_t fixImplicitTimeout();
int16_t fixInvertedIQ(uint8_t iqConfig);
+ int16_t fixGFSK();
// LR-FHSS utilities
int16_t buildLRFHSSPacket(const uint8_t* in, size_t in_len, uint8_t* out, size_t* out_len, size_t* out_bits, size_t* out_hops);
diff --git a/lib/RadioLib/src/modules/SX126x/SX126x_LR_FHSS.cpp b/lib/RadioLib/src/modules/SX126x/SX126x_LR_FHSS.cpp
index 0f491f9..42c071a 100644
--- a/lib/RadioLib/src/modules/SX126x/SX126x_LR_FHSS.cpp
+++ b/lib/RadioLib/src/modules/SX126x/SX126x_LR_FHSS.cpp
@@ -87,7 +87,7 @@ int16_t SX126x::buildLRFHSSPacket(const uint8_t* in, size_t in_len, uint8_t* out
// for rates other than the 1/3 base, puncture the code
if(this->lrFhssCr != RADIOLIB_SX126X_LR_FHSS_CR_1_3) {
uint32_t matrix_index = 0;
- uint8_t matrix[15] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 };
+ const uint8_t matrix[15] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 };
uint8_t matrix_len = 0;
switch(this->lrFhssCr) {
case RADIOLIB_SX126X_LR_FHSS_CR_5_6:
@@ -364,7 +364,7 @@ int16_t SX126x::setLRFHSSHop(uint8_t index) {
}
}
- uint8_t frq[4] = { (uint8_t)((freq_raw >> 24) & 0xFF), (uint8_t)((freq_raw >> 16) & 0xFF), (uint8_t)((freq_raw >> 8) & 0xFF), (uint8_t)(freq_raw & 0xFF) };
+ const uint8_t frq[4] = { (uint8_t)((freq_raw >> 24) & 0xFF), (uint8_t)((freq_raw >> 16) & 0xFF), (uint8_t)((freq_raw >> 8) & 0xFF), (uint8_t)(freq_raw & 0xFF) };
int16_t state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(index), frq, sizeof(freq_raw));
RADIOLIB_ASSERT(state);
@@ -380,7 +380,7 @@ int16_t SX126x::setLRFHSSHop(uint8_t index) {
}
// write hop length in symbols
- uint8_t sym[2] = { (uint8_t)((numSymbols >> 8) & 0xFF), (uint8_t)(numSymbols & 0xFF) };
+ const uint8_t sym[2] = { (uint8_t)((numSymbols >> 8) & 0xFF), (uint8_t)(numSymbols & 0xFF) };
state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(index), sym, sizeof(uint16_t));
RADIOLIB_ASSERT(state);
diff --git a/lib/RadioLib/src/modules/SX126x/SX126x_commands.cpp b/lib/RadioLib/src/modules/SX126x/SX126x_commands.cpp
new file mode 100644
index 0000000..f8e1cbd
--- /dev/null
+++ b/lib/RadioLib/src/modules/SX126x/SX126x_commands.cpp
@@ -0,0 +1,311 @@
+#include "SX126x.h"
+
+// this file contains implementation of all commands
+// supported by the SX126x SPI interface
+// in most cases, the names of methods match those in the datasheet
+// however, sometimes slight changes had to be made in order to
+// better fit the RadioLib API
+
+#if !RADIOLIB_EXCLUDE_SX126X
+
+int16_t SX126x::resetAGC() {
+ // warm sleep to power down the analog frontend
+ int16_t state = sleep(true);
+ RADIOLIB_ASSERT(state);
+
+ // wake to RC standby
+ state = standby(RADIOLIB_SX126X_STANDBY_RC, true);
+ RADIOLIB_ASSERT(state);
+
+ // recalibrate all blocks
+ state = calibrate(RADIOLIB_SX126X_CALIBRATE_ALL);
+ RADIOLIB_ASSERT(state);
+
+ // re-calibrate image rejection for the operating frequency
+ state = calibrateImage(this->freqMHz);
+ RADIOLIB_ASSERT(state);
+
+ // re-apply DIO2 RF switch if it was configured
+ if(this->dio2RfSwitch) {
+ state = setDio2AsRfSwitch(true);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // re-apply RX boosted gain if it was configured
+ if(this->rxBoostedGainMode) {
+ state = setRxBoostedGainMode(true);
+ RADIOLIB_ASSERT(state);
+ }
+
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t SX126x::calibrate(uint8_t params) {
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, ¶ms, 1, true, false));
+}
+
+int16_t SX126x::sleep() {
+ return(SX126x::sleep(true));
+}
+
+int16_t SX126x::sleep(bool retainConfig) {
+ // set RF switch (if present)
+ this->mod->setRfSwitchState(Module::MODE_IDLE);
+
+ uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF;
+ if(!retainConfig) {
+ sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF;
+ }
+ int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false, false);
+
+ // wait for SX126x to safely enter sleep mode
+ this->mod->hal->delay(1);
+
+ return(state);
+}
+
+int16_t SX126x::standby() {
+ return(SX126x::standby(this->standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC : RADIOLIB_SX126X_STANDBY_RC, true));
+}
+
+int16_t SX126x::standby(uint8_t mode) {
+ return(SX126x::standby(mode, true));
+}
+
+int16_t SX126x::standby(uint8_t mode, bool wakeup) {
+ // set RF switch (if present)
+ this->mod->setRfSwitchState(Module::MODE_IDLE);
+
+ if(wakeup) {
+ // send a NOP command - this pulls the NSS low to exit the sleep mode,
+ // while preventing interference with possible other SPI transactions
+ // see https://github.com/jgromes/RadioLib/discussions/1364
+ (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX126X_CMD_NOP, NULL, 0, false, false);
+ }
+
+ const uint8_t data[] = { mode };
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1));
+}
+
+int16_t SX126x::setFs() {
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0));
+}
+
+int16_t SX126x::setTx(uint32_t timeout) {
+ const uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ;
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3));
+}
+
+int16_t SX126x::setRx(uint32_t timeout) {
+ const uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) };
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false));
+}
+
+int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) {
+ // default CAD parameters are selected according to recommendations on Semtech DS.SX1261-2.W.APP rev. 1.1, page 92.
+
+ // build the packet with default configuration
+ uint8_t data[7];
+ data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB;
+ data[1] = this->spreadingFactor + 13;
+ data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
+ data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
+ uint32_t timeout_raw = (float)timeout / 15.625f;
+ data[4] = (uint8_t)((timeout_raw >> 16) & 0xFF);
+ data[5] = (uint8_t)((timeout_raw >> 8) & 0xFF);
+ data[6] = (uint8_t)(timeout_raw & 0xFF);
+
+ // set user-provided values
+ if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
+ data[0] = symbolNum;
+ }
+
+ if(detPeak != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
+ data[1] = detPeak;
+ }
+
+ if(detMin != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
+ data[2] = detMin;
+ }
+
+ if(exitMode != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
+ data[3] = exitMode;
+ }
+
+ // configure parameters
+ int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
+ RADIOLIB_ASSERT(state);
+
+ // start CAD
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0));
+}
+
+int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) {
+ const uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut };
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4));
+}
+
+int16_t SX126x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) {
+ this->mod->SPIwriteRegisterBurst(addr, data, numBytes);
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
+ // send the command
+ this->mod->SPIreadRegisterBurst(addr, numBytes, data);
+
+ // check the status
+ int16_t state = this->mod->SPIcheckStream();
+ return(state);
+}
+
+int16_t SX126x::writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset) {
+ const uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset };
+ return(this->mod->SPIwriteStream(cmd, 2, data, numBytes));
+}
+
+int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
+ const uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, offset };
+ return(this->mod->SPIreadStream(cmd, 2, data, numBytes));
+}
+
+int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
+ const uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
+ (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF),
+ (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF),
+ (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)};
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8));
+}
+
+int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) {
+ const uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) };
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2));
+}
+
+int16_t SX126x::setRfFrequency(uint32_t frf) {
+ const uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) };
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4));
+}
+
+int16_t SX126x::calibrateImage(const uint8_t* data) {
+ int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2);
+
+ // if something failed, show the device errors
+ #if RADIOLIB_DEBUG_BASIC
+ if(state != RADIOLIB_ERR_NONE) {
+ // unless mode is forced to standby, device errors will be 0
+ standby();
+ uint16_t errors = getDeviceErrors();
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
+ }
+ #endif
+ return(state);
+}
+
+uint8_t SX126x::getPacketType() {
+ uint8_t data = 0xFF;
+ this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1);
+ return(data);
+}
+
+int16_t SX126x::setTxParams(uint8_t pwr, uint8_t rampTime) {
+ const uint8_t data[] = { pwr, rampTime };
+ int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2);
+ if(state == RADIOLIB_ERR_NONE) {
+ this->pwr = pwr;
+ }
+ return(state);
+}
+
+int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
+ // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled
+ if(this->ldroAuto) {
+ float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
+ if(symbolLength >= 16.0f) {
+ this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON;
+ } else {
+ this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF;
+ }
+ } else {
+ this->ldrOptimize = ldro;
+ }
+ // 500/9/8 - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8
+ // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7
+ const uint8_t data[4] = {sf, bw, cr, this->ldrOptimize};
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4));
+}
+
+int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) {
+ const uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF),
+ sh, rxBw,
+ (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)};
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8));
+}
+
+int16_t SX126x::setModulationParamsBPSK(uint32_t br, uint8_t sh) {
+ const uint8_t data[] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh};
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, sizeof(data)));
+}
+
+int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ) {
+ int16_t state = fixInvertedIQ(invertIQ);
+ RADIOLIB_ASSERT(state);
+ const uint8_t data[6] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), hdrType, payloadLen, crcType, invertIQ};
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6));
+}
+
+int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType, uint8_t payloadLen) {
+ const uint8_t data[9] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
+ preambleDetectorLen, syncWordLen, addrCmp,
+ packType, payloadLen, crcType, whiten};
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9));
+}
+
+int16_t SX126x::setPacketParamsBPSK(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t payloadLenBits) {
+ const uint8_t data[] = { payloadLen,
+ (uint8_t)((rampUpDelay >> 8) & 0xFF), (uint8_t)(rampUpDelay & 0xFF),
+ (uint8_t)((rampDownDelay >> 8) & 0xFF), (uint8_t)(rampDownDelay & 0xFF),
+ (uint8_t)((payloadLenBits >> 8) & 0xFF), (uint8_t)(payloadLenBits & 0xFF)
+ };
+
+ // this one is a bit different, it seems to be split into command transaction and then a register write
+ int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, sizeof(uint8_t));
+ RADIOLIB_ASSERT(state);
+ return(this->writeRegister(RADIOLIB_SX126X_REG_BPSK_PACKET_PARAMS, &data[1], sizeof(data) - sizeof(uint8_t)));
+}
+
+int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
+ const uint8_t data[2] = {txBaseAddress, rxBaseAddress};
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2));
+}
+
+int16_t SX126x::setRegulatorMode(uint8_t mode) {
+ const uint8_t data[1] = {mode};
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1));
+}
+
+uint8_t SX126x::getStatus() {
+ uint8_t data = 0;
+ this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 0);
+ return(data);
+}
+
+uint32_t SX126x::getPacketStatus() {
+ uint8_t data[3] = {0, 0, 0};
+ this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3);
+ return((((uint32_t)data[0]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[2]);
+}
+
+uint16_t SX126x::getDeviceErrors() {
+ uint8_t data[2] = {0, 0};
+ this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2);
+ uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) | ((uint16_t)data[1]);
+ return(opError);
+}
+
+int16_t SX126x::clearDeviceErrors() {
+ const uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP};
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2));
+}
+
+#endif
\ No newline at end of file
diff --git a/lib/RadioLib/src/modules/SX126x/SX126x_commands.h b/lib/RadioLib/src/modules/SX126x/SX126x_commands.h
new file mode 100644
index 0000000..b66124b
--- /dev/null
+++ b/lib/RadioLib/src/modules/SX126x/SX126x_commands.h
@@ -0,0 +1,306 @@
+#if !defined(_RADIOLIB_SX126X_COMMANDS_H)
+#define _RADIOLIB_SX126X_COMMANDS_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_SX126X
+
+// SX126X SPI commands
+// operational modes commands
+#define RADIOLIB_SX126X_CMD_NOP 0x00
+#define RADIOLIB_SX126X_CMD_SET_SLEEP 0x84
+#define RADIOLIB_SX126X_CMD_SET_STANDBY 0x80
+#define RADIOLIB_SX126X_CMD_SET_FS 0xC1
+#define RADIOLIB_SX126X_CMD_SET_TX 0x83
+#define RADIOLIB_SX126X_CMD_SET_RX 0x82
+#define RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F
+#define RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE 0x94
+#define RADIOLIB_SX126X_CMD_SET_CAD 0xC5
+#define RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1
+#define RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2
+#define RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE 0x96
+#define RADIOLIB_SX126X_CMD_CALIBRATE 0x89
+#define RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE 0x98
+#define RADIOLIB_SX126X_CMD_SET_PA_CONFIG 0x95
+#define RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93
+
+// register and buffer access commands
+#define RADIOLIB_SX126X_CMD_WRITE_REGISTER 0x0D
+#define RADIOLIB_SX126X_CMD_READ_REGISTER 0x1D
+#define RADIOLIB_SX126X_CMD_WRITE_BUFFER 0x0E
+#define RADIOLIB_SX126X_CMD_READ_BUFFER 0x1E
+
+// DIO and IRQ control
+#define RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08
+#define RADIOLIB_SX126X_CMD_GET_IRQ_STATUS 0x12
+#define RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS 0x02
+#define RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D
+#define RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97
+
+// RF, modulation and packet commands
+#define RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY 0x86
+#define RADIOLIB_SX126X_CMD_SET_PACKET_TYPE 0x8A
+#define RADIOLIB_SX126X_CMD_GET_PACKET_TYPE 0x11
+#define RADIOLIB_SX126X_CMD_SET_TX_PARAMS 0x8E
+#define RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS 0x8B
+#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C
+#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88
+#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F
+#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0
+
+// status commands
+#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0
+#define RADIOLIB_SX126X_CMD_GET_RSSI_INST 0x15
+#define RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS 0x13
+#define RADIOLIB_SX126X_CMD_GET_PACKET_STATUS 0x14
+#define RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS 0x17
+#define RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07
+#define RADIOLIB_SX126X_CMD_GET_STATS 0x10
+#define RADIOLIB_SX126X_CMD_RESET_STATS 0x00
+
+#define RADIOLIB_SX126X_CMD_PRAM_UPDATE 0xD9
+#define RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS 0x9A
+#define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B
+
+// SX126X SPI command variables
+//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION
+#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default)
+#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained
+#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled
+#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled
+
+//RADIOLIB_SX126X_CMD_SET_STANDBY
+#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator
+#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator
+
+//RADIOLIB_SX126X_CMD_SET_RX
+#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode)
+#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode)
+
+//RADIOLIB_SX126X_CMD_SET_TX
+#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode)
+
+//RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE
+#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default)
+#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection
+
+//RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE
+#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default)
+#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC
+
+//RADIOLIB_SX126X_CMD_CALIBRATE
+#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled
+#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled
+#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled
+#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled
+#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled
+#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled
+#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled
+#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled
+#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled
+#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled
+#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled
+#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled
+#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled
+#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled
+#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks
+
+//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE
+#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B
+#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F
+#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75
+#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81
+#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1
+#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5
+#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7
+#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB
+#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1
+#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9
+#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0f)
+
+//RADIOLIB_SX126X_CMD_SET_PA_CONFIG
+#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07
+#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01
+#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00
+
+//RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE
+#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode
+#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator
+#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default)
+
+//RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS
+#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop
+#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout
+#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected
+#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished
+#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received
+#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error
+#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received
+#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected
+#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected
+#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received
+#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed
+#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts
+#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts
+
+//RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL
+#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ
+#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control
+
+//RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL
+#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V
+#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V
+#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V
+#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V
+#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V
+#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V
+#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V
+#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V
+
+//RADIOLIB_SX126X_CMD_SET_PACKET_TYPE
+#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK
+#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa
+#define RADIOLIB_SX126X_PACKET_TYPE_BPSK 0x02 // 7 0 BPSK
+#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS
+
+//RADIOLIB_SX126X_CMD_SET_TX_PARAMS
+#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us
+#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us
+#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us
+#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us
+#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us
+#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us
+#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us
+#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us
+
+//RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS
+#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none
+#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3
+#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5
+#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7
+#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1
+#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz
+#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz
+#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz
+#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz
+#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz
+#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz
+#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz
+#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz
+#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz
+#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz
+#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz
+#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz
+#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5
+#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6
+#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7
+#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8
+#define RADIOLIB_SX126X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaver
+#define RADIOLIB_SX126X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaver
+#define RADIOLIB_SX126X_LORA_CR_4_8_LI 0x07 // 7 0 4/8, long interleaver
+#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled
+#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled
+#define RADIOLIB_SX126X_BPSK_PULSE_SHAPE 0x16 // 7 0 BSPK pulse shape double OSR, RRC, BT=0.7
+
+//RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS
+#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled
+#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits
+#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits
+#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits
+#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits
+#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled
+#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only
+#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast
+#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides)
+#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet)
+#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled
+#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte
+#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte
+#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted
+#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted
+#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled
+#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled
+#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit
+#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit
+#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled
+#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled
+#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard
+#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted
+#define RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_NONE 0x0000 // 15 0 BPSK ramp-up time optimization: none
+#define RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_100_BPS 0x370F // 15 0 for 100 bps
+#define RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_600_BPS 0x092F // 15 0 for 600 bps
+#define RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_NONE 0x0000 // 15 0 BPSK ramp-down time optimization: none
+#define RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_100_BPS 0x1D70 // 15 0 for 100 bps
+#define RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_600_BPS 0x04E1 // 15 0 for 600 bps
+
+//RADIOLIB_SX126X_CMD_SET_CAD_PARAMS
+#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1
+#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2
+#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4
+#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8
+#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16
+#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode
+#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected
+#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value
+#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter
+
+//RADIOLIB_SX126X_CMD_GET_STATUS
+#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC
+#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC
+#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS
+#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX
+#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX
+#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved
+#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out
+#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command
+#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute
+#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done
+#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed
+
+//RADIOLIB_SX126X_CMD_GET_PACKET_STATUS
+#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error
+#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error
+#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error
+#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error
+#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error
+#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error
+#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received
+#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent
+
+//RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS
+#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed
+#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock
+#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start
+#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed
+#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed
+#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed
+#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed
+#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed
+
+//RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS + RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS
+#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us
+#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us
+#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/SX126x/SX126x_config.cpp b/lib/RadioLib/src/modules/SX126x/SX126x_config.cpp
new file mode 100644
index 0000000..c8b56e6
--- /dev/null
+++ b/lib/RadioLib/src/modules/SX126x/SX126x_config.cpp
@@ -0,0 +1,826 @@
+#include "SX126x.h"
+
+#include
+#include
+
+// this file contains all configuration methods
+// of the SX126x, which let user control the
+// modulation properties, packet configuration etc.
+
+#if !RADIOLIB_EXCLUDE_SX126X
+
+void SX126x::setDio1Action(void (*func)(void)) {
+ this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
+}
+
+void SX126x::clearDio1Action() {
+ this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
+}
+
+void SX126x::setPacketReceivedAction(void (*func)(void)) {
+ this->setDio1Action(func);
+}
+
+void SX126x::clearPacketReceivedAction() {
+ this->clearDio1Action();
+}
+
+void SX126x::setPacketSentAction(void (*func)(void)) {
+ this->setDio1Action(func);
+}
+
+void SX126x::clearPacketSentAction() {
+ this->clearDio1Action();
+}
+
+void SX126x::setChannelScanAction(void (*func)(void)) {
+ this->setDio1Action(func);
+}
+
+void SX126x::clearChannelScanAction() {
+ this->clearDio1Action();
+}
+
+int16_t SX126x::setBandwidth(float bw) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // ensure byte conversion doesn't overflow
+ RADIOLIB_CHECK_RANGE(bw, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+
+ // check allowed bandwidth values
+ uint8_t bw_div2 = bw / 2 + 0.01f;
+ switch (bw_div2) {
+ case 3: // 7.8:
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8;
+ break;
+ case 5: // 10.4:
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_10_4;
+ break;
+ case 7: // 15.6:
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_15_6;
+ break;
+ case 10: // 20.8:
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_20_8;
+ break;
+ case 15: // 31.25:
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_31_25;
+ break;
+ case 20: // 41.7:
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_41_7;
+ break;
+ case 31: // 62.5:
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_62_5;
+ break;
+ case 62: // 125.0:
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_125_0;
+ break;
+ case 125: // 250.0
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_250_0;
+ break;
+ case 250: // 500.0
+ this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_BANDWIDTH);
+ }
+
+ // update modulation parameters
+ this->bandwidthKhz = bw;
+ return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
+}
+
+int16_t SX126x::setSpreadingFactor(uint8_t sf) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
+
+ // update modulation parameters
+ this->spreadingFactor = sf;
+ return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
+}
+
+int16_t SX126x::setCodingRate(uint8_t cr, bool longInterleave) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+
+ if(longInterleave) {
+ switch(cr) {
+ case 4:
+ this->codingRate = 0;
+ break;
+ case 5:
+ case 6:
+ this->codingRate = cr;
+ break;
+ case 8:
+ this->codingRate = cr - 1;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_CODING_RATE);
+ }
+ } else {
+ this->codingRate = cr - 4;
+ }
+
+ // update modulation parameters
+ return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
+}
+
+int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // update register
+ const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
+ return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2));
+}
+
+int16_t SX126x::setCurrentLimit(float currentLimit) {
+ // check allowed range
+ if(!((currentLimit >= 0) && (currentLimit <= 140))) {
+ return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT);
+ }
+
+ // calculate raw value
+ uint8_t rawLimit = (uint8_t)(currentLimit / 2.5f);
+
+ // update register
+ return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1));
+}
+
+float SX126x::getCurrentLimit() {
+ // get the raw value
+ uint8_t ocp = 0;
+ readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
+
+ // return the actual value
+ return((float)ocp * 2.5f);
+}
+
+int16_t SX126x::setPreambleLength(size_t preambleLength) {
+ uint8_t modem = getPacketType();
+ if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ this->preambleLengthLoRa = preambleLength;
+ return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
+ } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ this->preambleLengthFSK = preambleLength;
+ // maximum preamble detector length is limited by sync word length
+ // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
+ uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
+ this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
+ maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
+ maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
+ maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
+ RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
+ return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType));
+ }
+
+ return(RADIOLIB_ERR_UNKNOWN);
+}
+
+int16_t SX126x::setFrequencyDeviation(float freqDev) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set frequency deviation to lowest available setting (required for digimodes)
+ float newFreqDev = freqDev;
+ if(freqDev < 0.0f) {
+ newFreqDev = 0.6f;
+ }
+
+ RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+
+ // calculate raw frequency deviation value
+ uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0f) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f));
+
+ // check modulation parameters
+ this->frequencyDev = freqDevRaw;
+
+ // update modulation parameters
+ return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
+}
+
+int16_t SX126x::setBitRate(float br) {
+ // check active modem
+ uint8_t modem = getPacketType();
+ if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) &&
+ (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) &&
+ (modem != RADIOLIB_SX126X_PACKET_TYPE_BPSK)) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
+ // at the moment only the very specific 488.28125 bps rate is supported
+ RADIOLIB_CHECK_RANGE(br, 0.488f, 0.489f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
+ // this should be just either 100 or 600 bps, not the range
+ // but the BPSK support is so experimental it probably does not matter
+ RADIOLIB_CHECK_RANGE(br, 0.1f, 0.6f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ }
+
+ // calculate raw bit rate value
+ uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f * 32.0f) / (br * 1000.0f));
+
+ // check modulation parameters
+ this->bitRate = brRaw;
+
+ // update modulation parameters
+ int16_t state = RADIOLIB_ERR_UNKNOWN;
+ if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
+ state = setModulationParamsBPSK(this->bitRate);
+ } else {
+ state = setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
+ }
+ RADIOLIB_ASSERT(state);
+
+ // apply workaround or reset it, as needed
+ return(fixGFSK());
+}
+
+int16_t SX126x::setDataRate(DataRate_t dr, ModemType_t modem) {
+ // get the current modem
+ ModemType_t currentModem;
+ int16_t state = this->getModem(¤tModem);
+ RADIOLIB_ASSERT(state);
+
+ // switch over if the requested modem is different
+ if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
+ state = this->standby();
+ RADIOLIB_ASSERT(state);
+ state = this->setModem(modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ if(modem == RADIOLIB_MODEM_NONE) {
+ modem = currentModem;
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ // set the bit rate
+ state = this->setBitRate(dr.fsk.bitRate);
+ RADIOLIB_ASSERT(state);
+
+ // set the frequency deviation
+ state = this->setFrequencyDeviation(dr.fsk.freqDev);
+
+ } else if(modem == RADIOLIB_MODEM_LORA) {
+ // set the spreading factor
+ state = this->setSpreadingFactor(dr.lora.spreadingFactor);
+ RADIOLIB_ASSERT(state);
+
+ // set the bandwidth
+ state = this->setBandwidth(dr.lora.bandwidth);
+ RADIOLIB_ASSERT(state);
+
+ // set the coding rate
+ state = this->setCodingRate(dr.lora.codingRate);
+
+ } else if(modem == RADIOLIB_MODEM_LRFHSS) {
+ // set the basic config
+ state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
+ RADIOLIB_ASSERT(state);
+
+ // set hopping grid
+ this->lrFhssGridNonFcc = dr.lrFhss.narrowGrid ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC;
+
+ }
+
+ return(state);
+}
+
+
+int16_t SX126x::checkDataRate(DataRate_t dr, ModemType_t modem) {
+ int16_t state = RADIOLIB_ERR_UNKNOWN;
+
+ // retrieve modem if not supplied
+ if(modem == RADIOLIB_MODEM_NONE) {
+ state = this->getModem(&modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ return(RADIOLIB_ERR_NONE);
+
+ } else if(modem == RADIOLIB_MODEM_LORA) {
+ RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
+ RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ return(RADIOLIB_ERR_NONE);
+
+ }
+
+ return(state);
+}
+
+int16_t SX126x::setRxBandwidth(float rxBw) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // check modulation parameters
+ /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) {
+ return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
+ }*/
+ this->rxBandwidthKhz = rxBw;
+
+ // check allowed receiver bandwidth values
+ if(fabsf(rxBw - 4.8f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8;
+ } else if(fabsf(rxBw - 5.8f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8;
+ } else if(fabsf(rxBw - 7.3f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3;
+ } else if(fabsf(rxBw - 9.7f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7;
+ } else if(fabsf(rxBw - 11.7f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7;
+ } else if(fabsf(rxBw - 14.6f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6;
+ } else if(fabsf(rxBw - 19.5f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5;
+ } else if(fabsf(rxBw - 23.4f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4;
+ } else if(fabsf(rxBw - 29.3f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3;
+ } else if(fabsf(rxBw - 39.0f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0;
+ } else if(fabsf(rxBw - 46.9f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9;
+ } else if(fabsf(rxBw - 58.6f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6;
+ } else if(fabsf(rxBw - 78.2f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2;
+ } else if(fabsf(rxBw - 93.8f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8;
+ } else if(fabsf(rxBw - 117.3f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3;
+ } else if(fabsf(rxBw - 156.2f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2;
+ } else if(fabsf(rxBw - 187.2f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2;
+ } else if(fabsf(rxBw - 234.3f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3;
+ } else if(fabsf(rxBw - 312.0f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0;
+ } else if(fabsf(rxBw - 373.6f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6;
+ } else if(fabsf(rxBw - 467.0f) <= 0.001f) {
+ this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0;
+ } else {
+ return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
+ }
+
+ // update modulation parameters
+ return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
+}
+
+int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) {
+ this->rxBoostedGainMode = rxbgm;
+
+ // update RX gain setting register
+ uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING;
+ int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1);
+ RADIOLIB_ASSERT(state);
+
+ // add Rx Gain register to retention memory if requested
+ if(persist) {
+ // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3
+ const uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) };
+ state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3);
+ }
+
+ return(state);
+}
+
+int16_t SX126x::setDataShaping(uint8_t sh) {
+ // check active modem
+ uint8_t modem = getPacketType();
+ if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set data shaping
+ switch(sh) {
+ case RADIOLIB_SHAPING_NONE:
+ this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE;
+ break;
+ case RADIOLIB_SHAPING_0_3:
+ this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3;
+ break;
+ case RADIOLIB_SHAPING_0_5:
+ this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5;
+ break;
+ case RADIOLIB_SHAPING_0_7:
+ this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7;
+ break;
+ case RADIOLIB_SHAPING_1_0:
+ this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
+ }
+
+ // update modulation parameters
+ return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
+}
+
+int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) {
+ // check active modem
+ uint8_t modem = getPacketType();
+ if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ // check sync word Length
+ if(len > 8) {
+ return(RADIOLIB_ERR_INVALID_SYNC_WORD);
+ }
+
+ // write sync word
+ int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len);
+ RADIOLIB_ASSERT(state);
+
+ // update packet parameters
+ this->syncWordLength = len * 8;
+
+ // maximum preamble detector length is limited by sync word length
+ // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
+ uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
+ this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
+ maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
+ maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
+ maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
+ RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
+ state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
+
+ return(state);
+
+ } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
+ if(len > 1) {
+ return(RADIOLIB_ERR_INVALID_SYNC_WORD);
+ }
+ return(setSyncWord(syncWord[0]));
+
+ } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
+ // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
+ if(len != sizeof(uint32_t)) {
+ return(RADIOLIB_ERR_INVALID_SYNC_WORD);
+ }
+ memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t));
+
+ }
+
+ return(RADIOLIB_ERR_WRONG_MODEM);
+}
+
+int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
+ // check active modem
+ uint8_t modem = getPacketType();
+
+ if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ // update packet parameters
+ switch(len) {
+ case 0:
+ this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF;
+ break;
+ case 1:
+ if(inverted) {
+ this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV;
+ } else {
+ this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE;
+ }
+ break;
+ case 2:
+ if(inverted) {
+ this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV;
+ } else {
+ this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE;
+ }
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
+ }
+
+ int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
+ RADIOLIB_ASSERT(state);
+
+ // write initial CRC value
+ uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
+ state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2);
+ RADIOLIB_ASSERT(state);
+
+ // write CRC polynomial value
+ data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
+ data[1] = (uint8_t)(polynomial & 0xFF);
+ state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
+
+ return(state);
+
+ } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
+
+ // update packet parameters
+ if(len) {
+ this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON;
+ } else {
+ this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF;
+ }
+
+ return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
+ }
+
+ return(RADIOLIB_ERR_UNKNOWN);
+}
+
+int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ int16_t state = RADIOLIB_ERR_NONE;
+ if(!enabled) {
+ // disable whitening
+ this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF;
+
+ state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
+ RADIOLIB_ASSERT(state);
+
+ } else {
+ // enable whitening
+ this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON;
+
+ // write initial whitening value
+ // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register"
+ uint8_t data[2];
+ // first read the actual value and mask 7 MSB which we can not change
+ // if different value is written in 7 MSB, the Rx won't even work (tested on HW)
+ state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1);
+ RADIOLIB_ASSERT(state);
+
+ data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01);
+ data[1] = (uint8_t)(initial & 0xFF);
+ state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2);
+ RADIOLIB_ASSERT(state);
+
+ state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
+ RADIOLIB_ASSERT(state);
+ }
+ return(state);
+}
+
+int16_t SX126x::fixedPacketLengthMode(uint8_t len) {
+ return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len));
+}
+
+int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
+ return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
+}
+int16_t SX126x::implicitHeader(size_t len) {
+ return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
+}
+
+int16_t SX126x::explicitHeader() {
+ return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT));
+}
+
+int16_t SX126x::setRegulatorLDO() {
+ return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO));
+}
+
+int16_t SX126x::setRegulatorDCDC() {
+ return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC));
+}
+
+int16_t SX126x::setEncoding(uint8_t encoding) {
+ return(setWhitening(encoding));
+}
+
+void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
+ this->mod->setRfSwitchPins(rxEn, txEn);
+}
+
+void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
+ this->mod->setRfSwitchTable(pins, table);
+}
+
+int16_t SX126x::forceLDRO(bool enable) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // update modulation parameters
+ this->ldroAuto = false;
+ this->ldrOptimize = (uint8_t)enable;
+ return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
+}
+
+int16_t SX126x::autoLDRO() {
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ this->ldroAuto = true;
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t SX126x::invertIQ(bool enable) {
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ if(enable) {
+ this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED;
+ } else {
+ this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
+ }
+
+ return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
+}
+
+int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
+ // check if TCXO is enabled at all
+ if(this->XTAL) {
+ return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
+ }
+
+ // set mode to standby
+ standby();
+
+ // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it
+ if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) {
+ clearDeviceErrors();
+ }
+
+ // check 0 V disable
+ if(fabsf(voltage - 0.0f) <= 0.001f) {
+ return(reset(true));
+ }
+
+ // check alowed voltage values
+ uint8_t data[4];
+ if(fabsf(voltage - 1.6f) <= 0.001f) {
+ data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6;
+ } else if(fabsf(voltage - 1.7f) <= 0.001f) {
+ data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7;
+ } else if(fabsf(voltage - 1.8f) <= 0.001f) {
+ data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8;
+ } else if(fabsf(voltage - 2.2f) <= 0.001f) {
+ data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2;
+ } else if(fabsf(voltage - 2.4f) <= 0.001f) {
+ data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4;
+ } else if(fabsf(voltage - 2.7f) <= 0.001f) {
+ data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7;
+ } else if(fabsf(voltage - 3.0f) <= 0.001f) {
+ data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0;
+ } else if(fabsf(voltage - 3.3f) <= 0.001f) {
+ data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3;
+ } else {
+ return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
+ }
+
+ // calculate delay
+ uint32_t delayValue = (float)delay / 15.625f;
+ data[1] = (uint8_t)((delayValue >> 16) & 0xFF);
+ data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
+ data[3] = (uint8_t)(delayValue & 0xFF);
+
+ this->tcxoDelay = delay;
+
+ // enable TCXO control on DIO3
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
+}
+
+int16_t SX126x::setDio2AsRfSwitch(bool enable) {
+ this->dio2RfSwitch = enable;
+ uint8_t data = enable ? RADIOLIB_SX126X_DIO2_AS_RF_SWITCH : RADIOLIB_SX126X_DIO2_AS_IRQ;
+ return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
+}
+
+int16_t SX126x::setPaRampTime(uint8_t rampTime) {
+ return(this->setTxParams(this->pwr, rampTime));
+}
+
+int16_t SX126x::setOutputPower(int8_t power, uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel) {
+ // get current OCP configuration
+ uint8_t ocp = 0;
+ int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
+ RADIOLIB_ASSERT(state);
+
+ // set PA config
+ state = SX126x::setPaConfig(paDutyCycle, deviceSel, hpMax);
+ RADIOLIB_ASSERT(state);
+
+ // set output power with default 200us ramp
+ state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U);
+ RADIOLIB_ASSERT(state);
+
+ // restore OCP configuration
+ return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
+}
+
+int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set requested packet mode
+ int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len);
+ RADIOLIB_ASSERT(state);
+
+ // update cached value
+ this->packetType = mode;
+ return(state);
+}
+
+int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) {
+ // check active modem
+ if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set requested packet mode
+ int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled);
+ RADIOLIB_ASSERT(state);
+
+ // update cached value
+ this->headerType = hdrType;
+ this->implicitLen = len;
+
+ return(state);
+}
+
+int16_t SX126x::setFrequencyRaw(float freq) {
+ // calculate raw value
+ this->freqMHz = freq;
+ uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
+ return(setRfFrequency(frf));
+}
+
+int16_t SX126x::config(uint8_t modem) {
+ // reset buffer base address
+ int16_t state = setBufferBaseAddress();
+ RADIOLIB_ASSERT(state);
+
+ // set modem
+ uint8_t data[7];
+ data[0] = modem;
+ state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1);
+ RADIOLIB_ASSERT(state);
+
+ // set Rx/Tx fallback mode to STDBY_RC
+ data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
+ state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
+ RADIOLIB_ASSERT(state);
+
+ // set some CAD parameters - will be overwritten when calling CAD anyway
+ data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
+ data[1] = this->spreadingFactor + 13;
+ data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
+ data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
+ data[4] = 0x00;
+ data[5] = 0x00;
+ data[6] = 0x00;
+ state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
+ RADIOLIB_ASSERT(state);
+
+ // clear IRQ
+ state = clearIrqStatus();
+ state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE);
+ RADIOLIB_ASSERT(state);
+
+ // calibrate all blocks
+ data[0] = RADIOLIB_SX126X_CALIBRATE_ALL;
+ state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false);
+ RADIOLIB_ASSERT(state);
+
+ // wait for calibration completion
+ this->mod->hal->delay(5);
+ while(this->mod->hal->digitalRead(this->mod->getGpio())) {
+ this->mod->hal->yield();
+ }
+
+ // check calibration result
+ return(this->mod->SPIcheckStream());
+}
+
+#endif
diff --git a/lib/RadioLib/src/modules/SX126x/SX126x_registers.h b/lib/RadioLib/src/modules/SX126x/SX126x_registers.h
new file mode 100644
index 0000000..e1dd762
--- /dev/null
+++ b/lib/RadioLib/src/modules/SX126x/SX126x_registers.h
@@ -0,0 +1,171 @@
+#if !defined(_RADIOLIB_SX126X_REGISTERS_H)
+#define _RADIOLIB_SX126X_REGISTERS_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_SX126X
+
+// SX126X register map
+#define RADIOLIB_SX126X_REG_BPSK_PACKET_PARAMS 0x00F0
+#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6
+#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6
+#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6
+#define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320
+#define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385
+#define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386
+#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_HOPPING_BLOCKS 0x0387
+#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(X) (0x0388 + (X)*6)
+#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_LSB(X) (0x0389 + (X)*6)
+#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(X) (0x038A + (X)*6)
+#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_1(X) (0x038B + (X)*6)
+#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_2(X) (0x038C + (X)*6)
+#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6)
+#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT 0x0401
+#define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580
+#define RADIOLIB_SX126X_REG_DIOX_DRIVE_STRENGTH 0x0582
+#define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583
+#define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584
+#define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585
+#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587
+#define RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE 0x0610
+#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680
+#define RADIOLIB_SX126X_REG_GFSK_FIX_4 0x06AC
+#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8
+#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9
+#define RADIOLIB_SX126X_REG_RX_TX_PLD_LEN 0x06BB
+#define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC
+#define RADIOLIB_SX126X_REG_CRC_INITIAL_LSB 0x06BD
+#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE
+#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF
+#define RADIOLIB_SX126X_REG_SYNC_WORD_0 0x06C0
+#define RADIOLIB_SX126X_REG_SYNC_WORD_1 0x06C1
+#define RADIOLIB_SX126X_REG_SYNC_WORD_2 0x06C2
+#define RADIOLIB_SX126X_REG_SYNC_WORD_3 0x06C3
+#define RADIOLIB_SX126X_REG_SYNC_WORD_4 0x06C4
+#define RADIOLIB_SX126X_REG_SYNC_WORD_5 0x06C5
+#define RADIOLIB_SX126X_REG_SYNC_WORD_6 0x06C6
+#define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7
+#define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD
+#define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE
+#define RADIOLIB_SX126X_REG_GFSK_FIX_1 0x06D1
+#define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702
+#define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704
+#define RADIOLIB_SX126X_REG_LORA_SYNC_TIMEOUT 0x0706
+#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736
+#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740
+#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741
+#define RADIOLIB_SX126X_REG_LORA_RX_CODING_RATE 0x0749
+#define RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC 0x076B
+#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS 0x07CD
+#define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803
+#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819
+#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A
+#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B
+#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C
+#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1
+#define RADIOLIB_SX126X_REG_RF_FREQUENCY_0 0x088B
+#define RADIOLIB_SX126X_REG_RF_FREQUENCY_1 0x088C
+#define RADIOLIB_SX126X_REG_RF_FREQUENCY_2 0x088D
+#define RADIOLIB_SX126X_REG_RF_FREQUENCY_3 0x088E
+#define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B
+#define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC
+#define RADIOLIB_SX126X_REG_GFSK_FIX_3 0x08B8
+#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8
+#define RADIOLIB_SX126X_REG_ANA_LNA 0x08E2
+#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3
+#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_P 0x08E4
+#define RADIOLIB_SX126X_REG_ANA_MIXER 0x08E5
+#define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7
+#define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902
+#define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911
+#define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912
+#define RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL 0x0920
+#define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944
+#define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000
+
+// SX126X SPI register variables
+//RADIOLIB_SX126X_REG_HOPPING_ENABLE MSB LSB DESCRIPTION
+#define RADIOLIB_SX126X_HOPPING_ENABLED 0b00000001 // 0 0 intra-packet hopping for LR-FHSS: enabled
+#define RADIOLIB_SX126X_HOPPING_DISABLED 0b00000000 // 0 0 (disabled)
+
+//RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB + LSB
+#define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved.
+#define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried.
+
+// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1
+#define RADIOLIB_SX126X_TX_BITBANG_1_DISABLED 0b00000000 // 6 4 Tx bitbang: disabled (default)
+#define RADIOLIB_SX126X_TX_BITBANG_1_ENABLED 0b00010000 // 6 4 enabled
+
+// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0
+#define RADIOLIB_SX126X_TX_BITBANG_0_DISABLED 0b00000000 // 3 0 Tx bitbang: disabled (default)
+#define RADIOLIB_SX126X_TX_BITBANG_0_ENABLED 0b00001100 // 3 0 enabled
+
+// RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE
+#define RADIOLIB_SX126X_DIO1_OUT_DISABLED 0b00000010 // 1 1 DIO1 output: disabled
+#define RADIOLIB_SX126X_DIO1_OUT_ENABLED 0b00000000 // 1 1 enabled
+#define RADIOLIB_SX126X_DIO2_OUT_DISABLED 0b00000100 // 2 2 DIO2 output: disabled
+#define RADIOLIB_SX126X_DIO2_OUT_ENABLED 0b00000000 // 2 2 enabled
+#define RADIOLIB_SX126X_DIO3_OUT_DISABLED 0b00001000 // 3 3 DIO3 output: disabled
+#define RADIOLIB_SX126X_DIO3_OUT_ENABLED 0b00000000 // 3 3 enabled
+
+// RADIOLIB_SX126X_REG_DIOX_IN_ENABLE
+#define RADIOLIB_SX126X_DIO1_IN_DISABLED 0b00000000 // 1 1 DIO1 input: disabled
+#define RADIOLIB_SX126X_DIO1_IN_ENABLED 0b00000010 // 1 1 enabled
+#define RADIOLIB_SX126X_DIO2_IN_DISABLED 0b00000000 // 2 2 DIO2 input: disabled
+#define RADIOLIB_SX126X_DIO2_IN_ENABLED 0b00000100 // 2 2 enabled
+#define RADIOLIB_SX126X_DIO3_IN_DISABLED 0b00000000 // 3 3 DIO3 input: disabled
+#define RADIOLIB_SX126X_DIO3_IN_ENABLED 0b00001000 // 3 3 enabled
+
+// RADIOLIB_SX126X_REG_RX_GAIN
+#define RADIOLIB_SX126X_RX_GAIN_BOOSTED 0x96 // 7 0 Rx gain: boosted
+#define RADIOLIB_SX126X_RX_GAIN_POWER_SAVING 0x94 // 7 0 power saving
+#define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan
+
+// RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE
+#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00000000 // 4 4 patch update: disabled
+#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00010000 // 4 4 enabled
+
+// RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS
+#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none
+#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing
+#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted
+#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed
+
+// RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW
+#define RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window
+
+// RADIOLIB_SX126X_REG_ANA_LNA
+#define RADIOLIB_SX126X_LNA_RNG_DISABLED 0b00000001 // 0 0 random number: disabled
+#define RADIOLIB_SX126X_LNA_RNG_ENABLED 0b00000000 // 0 0 enabled
+
+// RADIOLIB_SX126X_REG_ANA_MIXER
+#define RADIOLIB_SX126X_MIXER_RNG_DISABLED 0b00000001 // 7 7 random number: disabled
+#define RADIOLIB_SX126X_MIXER_RNG_ENABLED 0b00000000 // 7 7 enabled
+
+// size of the spectral scan result
+#define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33)
+
+// LR-FHSS configuration
+#define RADIOLIB_SX126X_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6
+#define RADIOLIB_SX126X_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3
+#define RADIOLIB_SX126X_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2
+#define RADIOLIB_SX126X_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3
+#define RADIOLIB_SX126X_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK
+#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC)
+#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC)
+#define RADIOLIB_SX126X_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled
+#define RADIOLIB_SX126X_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled
+#define RADIOLIB_SX126X_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz
+#define RADIOLIB_SX126X_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz
+#define RADIOLIB_SX126X_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz
+#define RADIOLIB_SX126X_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz
+#define RADIOLIB_SX126X_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz
+#define RADIOLIB_SX126X_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz
+#define RADIOLIB_SX126X_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz
+#define RADIOLIB_SX126X_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz
+#define RADIOLIB_SX126X_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz
+#define RADIOLIB_SX126X_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/modules/SX127x/SX1272.cpp b/lib/RadioLib/src/modules/SX127x/SX1272.cpp
index 4b118d6..c4a91c7 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1272.cpp
+++ b/lib/RadioLib/src/modules/SX127x/SX1272.cpp
@@ -83,7 +83,7 @@ void SX1272::reset() {
}
int16_t SX1272::setFrequency(float freq) {
- RADIOLIB_CHECK_RANGE(freq, 860.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ RADIOLIB_CHECK_RANGE(freq, 860.0f, 1020.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
@@ -102,11 +102,11 @@ int16_t SX1272::setBandwidth(float bw) {
uint8_t newBandwidth;
// check allowed bandwidth values
- if(fabsf(bw - 125.0) <= 0.001) {
+ if(fabsf(bw - 125.0f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1272_BW_125_00_KHZ;
- } else if(fabsf(bw - 250.0) <= 0.001) {
+ } else if(fabsf(bw - 250.0f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1272_BW_250_00_KHZ;
- } else if(fabsf(bw - 500.0) <= 0.001) {
+ } else if(fabsf(bw - 500.0f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1272_BW_500_00_KHZ;
} else {
return(RADIOLIB_ERR_INVALID_BANDWIDTH);
@@ -121,9 +121,11 @@ int16_t SX1272::setBandwidth(float bw) {
if(this->ldroAuto) {
float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
Module* mod = this->getMod();
- if(symbolLength >= 16.0) {
+ if(symbolLength >= 16.0f) {
+ this->ldroEnabled = true;
state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
} else {
+ this->ldroEnabled = false;
state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
}
}
@@ -175,7 +177,7 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) {
if(this->ldroAuto) {
float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
Module* mod = this->getMod();
- if(symbolLength >= 16.0) {
+ if(symbolLength >= 16.0f) {
state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
} else {
state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
@@ -195,6 +197,9 @@ int16_t SX1272::setCodingRate(uint8_t cr) {
// check allowed coding rate values
switch(cr) {
+ case 4:
+ newCodingRate = RADIOLIB_SX1272_CR_4_4;
+ break;
case 5:
newCodingRate = RADIOLIB_SX1272_CR_4_5;
break;
@@ -223,12 +228,26 @@ int16_t SX1272::setBitRate(float br) {
return(SX127x::setBitRateCommon(br, RADIOLIB_SX1272_REG_BIT_RATE_FRAC));
}
-int16_t SX1272::setDataRate(DataRate_t dr) {
- int16_t state = RADIOLIB_ERR_UNKNOWN;
+int16_t SX1272::setDataRate(DataRate_t dr, ModemType_t modem) {
+ // get the current modem
+ ModemType_t currentModem;
+ int16_t state = this->getModem(¤tModem);
+ RADIOLIB_ASSERT(state);
- // select interpretation based on active modem
- uint8_t modem = this->getActiveModem();
- if(modem == RADIOLIB_SX127X_FSK_OOK) {
+ // switch over if the requested modem is different
+ if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
+ state = this->standby();
+ RADIOLIB_ASSERT(state);
+ state = this->setModem(modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ if(modem == RADIOLIB_MODEM_NONE) {
+ modem = currentModem;
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
// set the bit rate
state = this->setBitRate(dr.fsk.bitRate);
RADIOLIB_ASSERT(state);
@@ -236,7 +255,7 @@ int16_t SX1272::setDataRate(DataRate_t dr) {
// set the frequency deviation
state = this->setFrequencyDeviation(dr.fsk.freqDev);
- } else if(modem == RADIOLIB_SX127X_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
// set the spreading factor
state = this->setSpreadingFactor(dr.lora.spreadingFactor);
RADIOLIB_ASSERT(state);
@@ -252,22 +271,27 @@ int16_t SX1272::setDataRate(DataRate_t dr) {
return(state);
}
-int16_t SX1272::checkDataRate(DataRate_t dr) {
+int16_t SX1272::checkDataRate(DataRate_t dr, ModemType_t modem) {
int16_t state = RADIOLIB_ERR_UNKNOWN;
- // select interpretation based on active modem
- int16_t modem = getActiveModem();
- if(modem == RADIOLIB_SX127X_FSK_OOK) {
- RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
- if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) {
+ // retrieve modem if not supplied
+ if(modem == RADIOLIB_MODEM_NONE) {
+ state = this->getModem(&modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) {
return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
}
return(RADIOLIB_ERR_NONE);
- } else if(modem == RADIOLIB_SX127X_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
- RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
- RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
return(RADIOLIB_ERR_NONE);
}
@@ -279,8 +303,9 @@ int16_t SX1272::setOutputPower(int8_t power) {
return(this->setOutputPower(power, false));
}
-int16_t SX1272::setOutputPower(int8_t power, bool useRfo) {
+int16_t SX1272::setOutputPower(int8_t power, bool forceRfo) {
// check if power value is configurable
+ bool useRfo = (power < 2) || forceRfo;
int16_t state = checkOutputPower(power, NULL, useRfo);
RADIOLIB_ASSERT(state);
@@ -479,6 +504,7 @@ int16_t SX1272::forceLDRO(bool enable) {
}
this->ldroAuto = false;
+ this->ldroEnabled = enable;
Module* mod = this->getMod();
if(enable) {
return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0));
diff --git a/lib/RadioLib/src/modules/SX127x/SX1272.h b/lib/RadioLib/src/modules/SX127x/SX1272.h
index 337558e..1a0da34 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1272.h
+++ b/lib/RadioLib/src/modules/SX127x/SX1272.h
@@ -31,7 +31,8 @@
#define RADIOLIB_SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz
#define RADIOLIB_SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz
#define RADIOLIB_SX1272_BW_500_00_KHZ 0b10000000 // 7 6 500 kHz
-#define RADIOLIB_SX1272_CR_4_5 0b00001000 // 5 3 error coding rate: 4/5
+#define RADIOLIB_SX1272_CR_4_4 0b00000000 // 5 3 error coding rate: 4/4 (undocumented)
+#define RADIOLIB_SX1272_CR_4_5 0b00001000 // 5 3 4/5
#define RADIOLIB_SX1272_CR_4_6 0b00010000 // 5 3 4/6
#define RADIOLIB_SX1272_CR_4_7 0b00011000 // 5 3 4/7
#define RADIOLIB_SX1272_CR_4_8 0b00100000 // 5 3 4/8
@@ -109,7 +110,8 @@ class SX1272: public SX127x {
\param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
- \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
+ \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
@@ -118,7 +120,7 @@ class SX1272: public SX127x {
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
- int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0);
+ virtual int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0);
/*!
\brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
@@ -160,10 +162,11 @@ class SX1272: public SX127x {
\param sf %LoRa link spreading factor to be set.
\returns \ref status_codes
*/
- int16_t setSpreadingFactor(uint8_t sf);
+ virtual int16_t setSpreadingFactor(uint8_t sf);
/*!
- \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode.
+ \brief Sets %LoRa link coding rate denominator. Allowed values range from 4 to 8. Only available in %LoRa mode.
+ Note that a value of 4 means no coding, is undocumented and not recommended without your own FEC.
\param cr %LoRa link coding rate denominator to be set.
\returns \ref status_codes
*/
@@ -177,18 +180,22 @@ class SX1272: public SX127x {
int16_t setBitRate(float br) override;
/*!
- \brief Set data.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \brief Set data rate.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t setDataRate(DataRate_t dr) override;
+ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Check the data rate can be configured by this module.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t checkDataRate(DataRate_t dr) override;
+ int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin).
@@ -201,10 +208,11 @@ class SX1272: public SX127x {
/*!
\brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin).
\param power Transmission output power in dBm.
- \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output.
+ \param forceRfo Whether to force using the RFO pin for the RF output (true)
+ or to leave the selection up to user (false) based on power output.
\returns \ref status_codes
*/
- int16_t setOutputPower(int8_t power, bool useRfo);
+ int16_t setOutputPower(int8_t power, bool forceRfo);
/*!
\brief Check if output power is configurable.
@@ -250,14 +258,14 @@ class SX1272: public SX127x {
int16_t setDataShapingOOK(uint8_t sh);
/*!
- \brief Gets recorded signal strength indicator.
+ \brief Gets received signal strength indicator.
Overload with packet mode enabled for PhysicalLayer compatibility.
\returns RSSI value in dBm.
*/
float getRSSI() override;
/*!
- \brief Gets recorded signal strength indicator.
+ \brief Gets received signal strength indicator.
\param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK.
\param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode.
\returns RSSI value in dBm.
@@ -317,15 +325,9 @@ class SX1272: public SX127x {
int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
int16_t setCodingRateRaw(uint8_t newCodingRate);
- int16_t configFSK();
+ int16_t configFSK() override;
void errataFix(bool rx) override;
-#if !RADIOLIB_GODMODE
- private:
-#endif
- bool ldroAuto = true;
- bool ldroEnabled = false;
-
};
#endif
diff --git a/lib/RadioLib/src/modules/SX127x/SX1273.cpp b/lib/RadioLib/src/modules/SX127x/SX1273.cpp
index 6a3af96..25bd1de 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1273.cpp
+++ b/lib/RadioLib/src/modules/SX127x/SX1273.cpp
@@ -67,12 +67,26 @@ int16_t SX1273::setSpreadingFactor(uint8_t sf) {
return(state);
}
-int16_t SX1273::setDataRate(DataRate_t dr) {
- int16_t state = RADIOLIB_ERR_UNKNOWN;
+int16_t SX1273::setDataRate(DataRate_t dr, ModemType_t modem) {
+ // get the current modem
+ ModemType_t currentModem;
+ int16_t state = this->getModem(¤tModem);
+ RADIOLIB_ASSERT(state);
- // select interpretation based on active modem
- uint8_t modem = this->getActiveModem();
- if(modem == RADIOLIB_SX127X_FSK_OOK) {
+ // switch over if the requested modem is different
+ if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
+ state = this->standby();
+ RADIOLIB_ASSERT(state);
+ state = this->setModem(modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ if(modem == RADIOLIB_MODEM_NONE) {
+ modem = currentModem;
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
// set the bit rate
state = this->setBitRate(dr.fsk.bitRate);
RADIOLIB_ASSERT(state);
@@ -80,7 +94,7 @@ int16_t SX1273::setDataRate(DataRate_t dr) {
// set the frequency deviation
state = this->setFrequencyDeviation(dr.fsk.freqDev);
- } else if(modem == RADIOLIB_SX127X_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
// set the spreading factor
state = this->setSpreadingFactor(dr.lora.spreadingFactor);
RADIOLIB_ASSERT(state);
@@ -92,22 +106,27 @@ int16_t SX1273::setDataRate(DataRate_t dr) {
return(state);
}
-int16_t SX1273::checkDataRate(DataRate_t dr) {
+int16_t SX1273::checkDataRate(DataRate_t dr, ModemType_t modem) {
int16_t state = RADIOLIB_ERR_UNKNOWN;
- // select interpretation based on active modem
- int16_t modem = getActiveModem();
- if(modem == RADIOLIB_SX127X_FSK_OOK) {
- RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
- if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) {
+ // retrieve modem if not supplied
+ if(modem == RADIOLIB_MODEM_NONE) {
+ state = this->getModem(&modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) {
return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
}
return(RADIOLIB_ERR_NONE);
- } else if(modem == RADIOLIB_SX127X_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
- RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
- RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
return(RADIOLIB_ERR_NONE);
}
diff --git a/lib/RadioLib/src/modules/SX127x/SX1273.h b/lib/RadioLib/src/modules/SX127x/SX1273.h
index 4e9dd1e..24d4bc9 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1273.h
+++ b/lib/RadioLib/src/modules/SX127x/SX1273.h
@@ -29,7 +29,8 @@ class SX1273: public SX1272 {
\param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 9.
- \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
+ \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
@@ -38,7 +39,7 @@ class SX1273: public SX1272 {
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
- int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0);
+ int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0) override;
// configuration methods
@@ -47,21 +48,25 @@ class SX1273: public SX1272 {
\param sf %LoRa link spreading factor to be set.
\returns \ref status_codes
*/
- int16_t setSpreadingFactor(uint8_t sf);
+ int16_t setSpreadingFactor(uint8_t sf) override;
/*!
- \brief Set data.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \brief Set data rate.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t setDataRate(DataRate_t dr) override;
+ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Check the data rate can be configured by this module.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t checkDataRate(DataRate_t dr) override;
+ int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Set modem for the radio to use. Will perform full reset and reconfigure the radio
diff --git a/lib/RadioLib/src/modules/SX127x/SX1276.cpp b/lib/RadioLib/src/modules/SX127x/SX1276.cpp
index 062d11b..9da2d19 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1276.cpp
+++ b/lib/RadioLib/src/modules/SX127x/SX1276.cpp
@@ -7,7 +7,7 @@ SX1276::SX1276(Module* mod) : SX1278(mod) {
int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) {
// execute common part
- uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
+ const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
@@ -39,7 +39,7 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) {
// execute common part
- uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
+ const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK);
RADIOLIB_ASSERT(state);
@@ -69,7 +69,15 @@ int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
}
int16_t SX1276::setFrequency(float freq) {
- RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ // NOTE: The datasheet specifies Band 2 as 410-525 MHz, but the hardware has been
+ // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to
+ // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while
+ // adding a small margin below the 400 MHz practical limit.
+ if(!(((freq >= 137.0f) && (freq <= 175.0f)) ||
+ ((freq >= 395.0f) && (freq <= 525.0f)) ||
+ ((freq >= 862.0f) && (freq <= 1020.0f)))) {
+ return(RADIOLIB_ERR_INVALID_FREQUENCY);
+ }
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
diff --git a/lib/RadioLib/src/modules/SX127x/SX1276.h b/lib/RadioLib/src/modules/SX127x/SX1276.h
index 64dbaa3..402b8cd 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1276.h
+++ b/lib/RadioLib/src/modules/SX127x/SX1276.h
@@ -27,9 +27,10 @@ class SX1276: public SX1278 {
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz.
- \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
+ \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
- \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
+ \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
@@ -38,7 +39,7 @@ class SX1276: public SX1278 {
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0);
+ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0) override;
/*!
\brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
@@ -52,12 +53,12 @@ class SX1276: public SX1278 {
\param enableOOK Use OOK modulation instead of FSK.
\returns \ref status_codes
*/
- int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false);
+ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false) override;
// configuration methods
/*!
- \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz.
+ \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz, 395.0 to 525.0 MHz (datasheet minimum is 410.0 MHz, hardware works lower) and 862.0 to 1020 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
diff --git a/lib/RadioLib/src/modules/SX127x/SX1277.cpp b/lib/RadioLib/src/modules/SX127x/SX1277.cpp
index 59729e8..aae1c78 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1277.cpp
+++ b/lib/RadioLib/src/modules/SX127x/SX1277.cpp
@@ -7,7 +7,7 @@ SX1277::SX1277(Module* mod) : SX1278(mod) {
int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) {
// execute common part
- uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
+ const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
@@ -39,7 +39,7 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) {
// execute common part
- uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
+ const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK);
RADIOLIB_ASSERT(state);
@@ -69,7 +69,15 @@ int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
}
int16_t SX1277::setFrequency(float freq) {
- RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ // NOTE: The datasheet specifies Band 2 as 410-525 MHz, but the hardware has been
+ // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to
+ // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while
+ // adding a small margin below the 400 MHz practical limit.
+ if(!(((freq >= 137.0f) && (freq <= 175.0f)) ||
+ ((freq >= 395.0f) && (freq <= 525.0f)) ||
+ ((freq >= 862.0f) && (freq <= 1020.0f)))) {
+ return(RADIOLIB_ERR_INVALID_FREQUENCY);
+ }
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
@@ -109,12 +117,26 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) {
return(state);
}
-int16_t SX1277::setDataRate(DataRate_t dr) {
- int16_t state = RADIOLIB_ERR_UNKNOWN;
+int16_t SX1277::setDataRate(DataRate_t dr, ModemType_t modem) {
+ // get the current modem
+ ModemType_t currentModem;
+ int16_t state = this->getModem(¤tModem);
+ RADIOLIB_ASSERT(state);
- // select interpretation based on active modem
- uint8_t modem = this->getActiveModem();
- if(modem == RADIOLIB_SX127X_FSK_OOK) {
+ // switch over if the requested modem is different
+ if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
+ state = this->standby();
+ RADIOLIB_ASSERT(state);
+ state = this->setModem(modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ if(modem == RADIOLIB_MODEM_NONE) {
+ modem = currentModem;
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
// set the bit rate
state = this->setBitRate(dr.fsk.bitRate);
RADIOLIB_ASSERT(state);
@@ -122,7 +144,7 @@ int16_t SX1277::setDataRate(DataRate_t dr) {
// set the frequency deviation
state = this->setFrequencyDeviation(dr.fsk.freqDev);
- } else if(modem == RADIOLIB_SX127X_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
// set the spreading factor
state = this->setSpreadingFactor(dr.lora.spreadingFactor);
RADIOLIB_ASSERT(state);
@@ -134,22 +156,27 @@ int16_t SX1277::setDataRate(DataRate_t dr) {
return(state);
}
-int16_t SX1277::checkDataRate(DataRate_t dr) {
+int16_t SX1277::checkDataRate(DataRate_t dr, ModemType_t modem) {
int16_t state = RADIOLIB_ERR_UNKNOWN;
- // select interpretation based on active modem
- int16_t modem = getActiveModem();
- if(modem == RADIOLIB_SX127X_FSK_OOK) {
- RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
- if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) {
+ // retrieve modem if not supplied
+ if(modem == RADIOLIB_MODEM_NONE) {
+ state = this->getModem(&modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) {
return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
}
return(RADIOLIB_ERR_NONE);
- } else if(modem == RADIOLIB_SX127X_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
- RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
- RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
return(RADIOLIB_ERR_NONE);
}
diff --git a/lib/RadioLib/src/modules/SX127x/SX1277.h b/lib/RadioLib/src/modules/SX127x/SX1277.h
index fe068c0..3c0c071 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1277.h
+++ b/lib/RadioLib/src/modules/SX127x/SX1277.h
@@ -27,9 +27,10 @@ class SX1277: public SX1278 {
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz.
- \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
+ \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 9.
- \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
+ \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
@@ -38,7 +39,7 @@ class SX1277: public SX1278 {
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0);
+ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0) override;
/*!
\brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
@@ -52,12 +53,12 @@ class SX1277: public SX1278 {
\param enableOOK Use OOK modulation instead of FSK.
\returns \ref status_codes
*/
- int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false);
+ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false) override;
// configuration methods
/*!
- \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz.
+ \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz, 395.0 to 525.0 MHz (datasheet minimum is 410.0 MHz, hardware works lower) and 862.0 to 1020 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
@@ -68,21 +69,25 @@ class SX1277: public SX1278 {
\param sf %LoRa link spreading factor to be set.
\returns \ref status_codes
*/
- int16_t setSpreadingFactor(uint8_t sf);
+ int16_t setSpreadingFactor(uint8_t sf) override;
/*!
- \brief Set data.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \brief Set data rate.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t setDataRate(DataRate_t dr) override;
+ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Check the data rate can be configured by this module.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t checkDataRate(DataRate_t dr) override;
+ int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Set modem for the radio to use. Will perform full reset and reconfigure the radio
diff --git a/lib/RadioLib/src/modules/SX127x/SX1278.cpp b/lib/RadioLib/src/modules/SX127x/SX1278.cpp
index df76e56..0605620 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1278.cpp
+++ b/lib/RadioLib/src/modules/SX127x/SX1278.cpp
@@ -8,7 +8,7 @@ SX1278::SX1278(Module* mod) : SX127x(mod) {
int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) {
// execute common part
- uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
+ const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
@@ -40,7 +40,7 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) {
// execute common part
- uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
+ const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK);
RADIOLIB_ASSERT(state);
@@ -83,7 +83,14 @@ void SX1278::reset() {
}
int16_t SX1278::setFrequency(float freq) {
- RADIOLIB_CHECK_RANGE(freq, 137.0, 525.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ // NOTE: The datasheet specifies Band 2 as 410-525 MHz, but the hardware has been
+ // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to
+ // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while
+ // adding a small margin below the 400 MHz practical limit.
+ if(!(((freq >= 137.0f) && (freq <= 175.0f)) ||
+ ((freq >= 395.0f) && (freq <= 525.0f)))) {
+ return(RADIOLIB_ERR_INVALID_FREQUENCY);
+ }
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
@@ -102,25 +109,25 @@ int16_t SX1278::setBandwidth(float bw) {
uint8_t newBandwidth;
// check allowed bandwidth values
- if(fabsf(bw - 7.8) <= 0.001) {
+ if(fabsf(bw - 7.8f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_7_80_KHZ;
- } else if(fabsf(bw - 10.4) <= 0.001) {
+ } else if(fabsf(bw - 10.4f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_10_40_KHZ;
- } else if(fabsf(bw - 15.6) <= 0.001) {
+ } else if(fabsf(bw - 15.6f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_15_60_KHZ;
- } else if(fabsf(bw - 20.8) <= 0.001) {
+ } else if(fabsf(bw - 20.8f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_20_80_KHZ;
- } else if(fabsf(bw - 31.25) <= 0.001) {
+ } else if(fabsf(bw - 31.25f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_31_25_KHZ;
- } else if(fabsf(bw - 41.7) <= 0.001) {
+ } else if(fabsf(bw - 41.7f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_41_70_KHZ;
- } else if(fabsf(bw - 62.5) <= 0.001) {
+ } else if(fabsf(bw - 62.5f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_62_50_KHZ;
- } else if(fabsf(bw - 125.0) <= 0.001) {
+ } else if(fabsf(bw - 125.0f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_125_00_KHZ;
- } else if(fabsf(bw - 250.0) <= 0.001) {
+ } else if(fabsf(bw - 250.0f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_250_00_KHZ;
- } else if(fabsf(bw - 500.0) <= 0.001) {
+ } else if(fabsf(bw - 500.0f) <= 0.001f) {
newBandwidth = RADIOLIB_SX1278_BW_500_00_KHZ;
} else {
return(RADIOLIB_ERR_INVALID_BANDWIDTH);
@@ -135,9 +142,11 @@ int16_t SX1278::setBandwidth(float bw) {
if(this->ldroAuto) {
float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
Module* mod = this->getMod();
- if(symbolLength >= 16.0) {
+ if(symbolLength >= 16.0f) {
+ this->ldroEnabled = true;
state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
} else {
+ this->ldroEnabled = false;
state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
}
}
@@ -189,7 +198,7 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) {
if(this->ldroAuto) {
float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
Module* mod = this->getMod();
- if(symbolLength >= 16.0) {
+ if(symbolLength >= 16.0f) {
state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
} else {
state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
@@ -209,6 +218,9 @@ int16_t SX1278::setCodingRate(uint8_t cr) {
// check allowed coding rate values
switch(cr) {
+ case 4:
+ newCodingRate = RADIOLIB_SX1278_CR_4_4;
+ break;
case 5:
newCodingRate = RADIOLIB_SX1278_CR_4_5;
break;
@@ -237,12 +249,26 @@ int16_t SX1278::setBitRate(float br) {
return(SX127x::setBitRateCommon(br, RADIOLIB_SX1278_REG_BIT_RATE_FRAC));
}
-int16_t SX1278::setDataRate(DataRate_t dr) {
- int16_t state = RADIOLIB_ERR_UNKNOWN;
+int16_t SX1278::setDataRate(DataRate_t dr, ModemType_t modem) {
+ // get the current modem
+ ModemType_t currentModem;
+ int16_t state = this->getModem(¤tModem);
+ RADIOLIB_ASSERT(state);
- // select interpretation based on active modem
- uint8_t modem = this->getActiveModem();
- if(modem == RADIOLIB_SX127X_FSK_OOK) {
+ // switch over if the requested modem is different
+ if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
+ state = this->standby();
+ RADIOLIB_ASSERT(state);
+ state = this->setModem(modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ if(modem == RADIOLIB_MODEM_NONE) {
+ modem = currentModem;
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
// set the bit rate
state = this->setBitRate(dr.fsk.bitRate);
RADIOLIB_ASSERT(state);
@@ -250,7 +276,7 @@ int16_t SX1278::setDataRate(DataRate_t dr) {
// set the frequency deviation
state = this->setFrequencyDeviation(dr.fsk.freqDev);
- } else if(modem == RADIOLIB_SX127X_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
// set the spreading factor
state = this->setSpreadingFactor(dr.lora.spreadingFactor);
RADIOLIB_ASSERT(state);
@@ -266,22 +292,27 @@ int16_t SX1278::setDataRate(DataRate_t dr) {
return(state);
}
-int16_t SX1278::checkDataRate(DataRate_t dr) {
+int16_t SX1278::checkDataRate(DataRate_t dr, ModemType_t modem) {
int16_t state = RADIOLIB_ERR_UNKNOWN;
- // select interpretation based on active modem
- int16_t modem = getActiveModem();
- if(modem == RADIOLIB_SX127X_FSK_OOK) {
- RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
- if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) {
+ // retrieve modem if not supplied
+ if(modem == RADIOLIB_MODEM_NONE) {
+ state = this->getModem(&modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) {
return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
}
return(RADIOLIB_ERR_NONE);
- } else if(modem == RADIOLIB_SX127X_LORA) {
+ } else if(modem == RADIOLIB_MODEM_LORA) {
RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
- RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
- RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
return(RADIOLIB_ERR_NONE);
}
@@ -293,8 +324,9 @@ int16_t SX1278::setOutputPower(int8_t power) {
return(this->setOutputPower(power, false));
}
-int16_t SX1278::setOutputPower(int8_t power, bool useRfo) {
+int16_t SX1278::setOutputPower(int8_t power, bool forceRfo) {
// check if power value is configurable
+ bool useRfo = (power < 2) || forceRfo;
int16_t state = checkOutputPower(power, NULL, useRfo);
RADIOLIB_ASSERT(state);
@@ -344,9 +376,9 @@ int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) {
if(useRfo) {
// RFO output
if(clipped) {
- *clipped = RADIOLIB_MAX(-3, RADIOLIB_MIN(15, power));
+ *clipped = RADIOLIB_MAX(-4, RADIOLIB_MIN(15, power));
}
- RADIOLIB_CHECK_RANGE(power, -3, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
+ RADIOLIB_CHECK_RANGE(power, -4, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
} else {
// PA_BOOST output, check high-power operation
if(clipped) {
@@ -476,7 +508,7 @@ float SX1278::getRSSI() {
float SX1278::getRSSI(bool packet, bool skipReceive) {
int16_t offset = -157;
- if(frequency < 868.0) {
+ if(frequency < 868.0f) {
offset = -164;
}
return(SX127x::getRSSI(packet, skipReceive, offset));
@@ -518,6 +550,7 @@ int16_t SX1278::forceLDRO(bool enable) {
Module* mod = this->getMod();
this->ldroAuto = false;
+ this->ldroEnabled = enable;
if(enable) {
return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3));
} else {
@@ -606,11 +639,11 @@ void SX1278::errataFix(bool rx) {
// sensitivity optimization for 500kHz bandwidth
// see SX1276/77/78 Errata, section 2.1 for details
Module* mod = this->getMod();
- if(fabsf(SX127x::bandwidth - 500.0) <= 0.001) {
- if((frequency >= 862.0) && (frequency <= 1020.0)) {
+ if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) {
+ if((frequency >= 862.0f) && (frequency <= 1020.0f)) {
mod->SPIwriteRegister(0x36, 0x02);
mod->SPIwriteRegister(0x3a, 0x64);
- } else if((frequency >= 410.0) && (frequency <= 525.0)) {
+ } else if((frequency >= 410.0f) && (frequency <= 525.0f)) {
mod->SPIwriteRegister(0x36, 0x02);
mod->SPIwriteRegister(0x3a, 0x7F);
}
@@ -622,49 +655,49 @@ void SX1278::errataFix(bool rx) {
// figure out what we need to set
uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 };
float rxFreq = frequency;
- if(fabsf(SX127x::bandwidth - 7.8) <= 0.001) {
+ if(fabsf(SX127x::bandwidth - 7.8f) <= 0.001f) {
fixedRegs[0] = 0b00000000;
fixedRegs[1] = 0x48;
fixedRegs[2] = 0x00;
- rxFreq += 0.00781;
- } else if(fabsf(SX127x::bandwidth - 10.4) <= 0.001) {
+ rxFreq += 0.00781f;
+ } else if(fabsf(SX127x::bandwidth - 10.4f) <= 0.001f) {
fixedRegs[0] = 0b00000000;
fixedRegs[1] = 0x44;
fixedRegs[2] = 0x00;
- rxFreq += 0.01042;
- } else if(fabsf(SX127x::bandwidth - 15.6) <= 0.001) {
+ rxFreq += 0.01042f;
+ } else if(fabsf(SX127x::bandwidth - 15.6f) <= 0.001f) {
fixedRegs[0] = 0b00000000;
fixedRegs[1] = 0x44;
fixedRegs[2] = 0x00;
- rxFreq += 0.01562;
- } else if(fabsf(SX127x::bandwidth - 20.8) <= 0.001) {
+ rxFreq += 0.01562f;
+ } else if(fabsf(SX127x::bandwidth - 20.8f) <= 0.001f) {
fixedRegs[0] = 0b00000000;
fixedRegs[1] = 0x44;
fixedRegs[2] = 0x00;
- rxFreq += 0.02083;
- } else if(fabsf(SX127x::bandwidth - 31.25) <= 0.001) {
+ rxFreq += 0.02083f;
+ } else if(fabsf(SX127x::bandwidth - 31.25f) <= 0.001f) {
fixedRegs[0] = 0b00000000;
fixedRegs[1] = 0x44;
fixedRegs[2] = 0x00;
- rxFreq += 0.03125;
- } else if(fabsf(SX127x::bandwidth - 41.7) <= 0.001) {
+ rxFreq += 0.03125f;
+ } else if(fabsf(SX127x::bandwidth - 41.7f) <= 0.001f) {
fixedRegs[0] = 0b00000000;
fixedRegs[1] = 0x44;
fixedRegs[2] = 0x00;
- rxFreq += 0.04167;
- } else if(fabsf(SX127x::bandwidth - 62.5) <= 0.001) {
+ rxFreq += 0.04167f;
+ } else if(fabsf(SX127x::bandwidth - 62.5f) <= 0.001f) {
fixedRegs[0] = 0b00000000;
fixedRegs[1] = 0x40;
fixedRegs[2] = 0x00;
- } else if(fabsf(SX127x::bandwidth - 125.0) <= 0.001) {
+ } else if(fabsf(SX127x::bandwidth - 125.0f) <= 0.001f) {
fixedRegs[0] = 0b00000000;
fixedRegs[1] = 0x40;
fixedRegs[2] = 0x00;
- } else if(fabsf(SX127x::bandwidth - 250.0) <= 0.001) {
+ } else if(fabsf(SX127x::bandwidth - 250.0f) <= 0.001f) {
fixedRegs[0] = 0b00000000;
fixedRegs[1] = 0x40;
fixedRegs[2] = 0x00;
- } else if(fabsf(SX127x::bandwidth - 500.0) <= 0.001) {
+ } else if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) {
fixedRegs[0] = 0b10000000;
fixedRegs[1] = mod->SPIreadRegister(0x2F);
fixedRegs[2] = mod->SPIreadRegister(0x30);
diff --git a/lib/RadioLib/src/modules/SX127x/SX1278.h b/lib/RadioLib/src/modules/SX127x/SX1278.h
index 1fadf64..600283f 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1278.h
+++ b/lib/RadioLib/src/modules/SX127x/SX1278.h
@@ -49,7 +49,8 @@
#define RADIOLIB_SX1278_BW_125_00_KHZ 0b01110000 // 7 4 125.00 kHz
#define RADIOLIB_SX1278_BW_250_00_KHZ 0b10000000 // 7 4 250.00 kHz
#define RADIOLIB_SX1278_BW_500_00_KHZ 0b10010000 // 7 4 500.00 kHz
-#define RADIOLIB_SX1278_CR_4_5 0b00000010 // 3 1 error coding rate: 4/5
+#define RADIOLIB_SX1278_CR_4_4 0b00000000 // 3 1 error coding rate: 4/4 (undocumented)
+#define RADIOLIB_SX1278_CR_4_5 0b00000010 // 3 1 4/5
#define RADIOLIB_SX1278_CR_4_6 0b00000100 // 3 1 4/6
#define RADIOLIB_SX1278_CR_4_7 0b00000110 // 3 1 4/7
#define RADIOLIB_SX1278_CR_4_8 0b00001000 // 3 1 4/8
@@ -118,9 +119,10 @@ class SX1278: public SX127x {
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz.
- \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
+ \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
- \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
+ \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
@@ -129,7 +131,7 @@ class SX1278: public SX127x {
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0);
+ virtual int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0);
/*!
\brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
@@ -143,7 +145,7 @@ class SX1278: public SX127x {
\param enableOOK Use OOK modulation instead of FSK.
\returns \ref status_codes
*/
- int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false);
+ virtual int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false);
/*!
\brief Reset method. Will reset the chip to the default state using RST pin.
@@ -153,14 +155,14 @@ class SX1278: public SX127x {
// configuration methods
/*!
- \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 525.0 MHz.
+ \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz and 395.0 to 525.0 MHz (datasheet minimum is 410.0 MHz, hardware works lower).
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq) override;
/*!
- \brief Sets %LoRa link bandwidth. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode.
+ \brief Sets %LoRa link bandwidth. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode.
\param bw %LoRa link bandwidth to be set in kHz.
\returns \ref status_codes
*/
@@ -171,10 +173,11 @@ class SX1278: public SX127x {
\param sf %LoRa link spreading factor to be set.
\returns \ref status_codes
*/
- int16_t setSpreadingFactor(uint8_t sf);
+ virtual int16_t setSpreadingFactor(uint8_t sf);
/*!
- \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode.
+ \brief Sets %LoRa link coding rate denominator. Allowed values range from 4 to 8. Only available in %LoRa mode.
+ Note that a value of 4 means no coding, is undocumented and not recommended without your own FEC.
\param cr %LoRa link coding rate denominator to be set.
\returns \ref status_codes
*/
@@ -188,21 +191,25 @@ class SX1278: public SX127x {
int16_t setBitRate(float br) override;
/*!
- \brief Set data.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \brief Set data rate.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t setDataRate(DataRate_t dr) override;
+ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Check the data rate can be configured by this module.
- \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK or LoRa).
+ Defaults to currently active modem if not supplied.
\returns \ref status_codes
*/
- int16_t checkDataRate(DataRate_t dr) override;
+ int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
- \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin).
+ \brief Sets transmission output power. Allowed values range from -4 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin).
High power +20 dBm operation is also supported, on the PA_BOOST pin. Defaults to PA_BOOST.
\param power Transmission output power in dBm.
\returns \ref status_codes
@@ -210,13 +217,14 @@ class SX1278: public SX127x {
int16_t setOutputPower(int8_t power) override;
/*!
- \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin).
+ \brief Sets transmission output power. Allowed values range from -4 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin).
High power +20 dBm operation is also supported, on the PA_BOOST pin.
\param power Transmission output power in dBm.
- \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output.
+ \param forceRfo Whether to force using the RFO pin for the RF output (true)
+ or to leave the selection up to user (false) based on power output.
\returns \ref status_codes
*/
- int16_t setOutputPower(int8_t power, bool useRfo);
+ int16_t setOutputPower(int8_t power, bool forceRfo);
/*!
\brief Check if output power is configurable.
@@ -262,14 +270,14 @@ class SX1278: public SX127x {
int16_t setDataShapingOOK(uint8_t sh);
/*!
- \brief Gets recorded signal strength indicator.
+ \brief Gets received signal strength indicator.
Overload with packet mode enabled for PhysicalLayer compatibility.
\returns RSSI value in dBm.
*/
float getRSSI() override;
/*!
- \brief Gets recorded signal strength indicator.
+ \brief Gets received signal strength indicator.
\param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK.
\param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode.
\returns RSSI value in dBm.
@@ -329,15 +337,9 @@ class SX1278: public SX127x {
int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
int16_t setCodingRateRaw(uint8_t newCodingRate);
- int16_t configFSK();
+ int16_t configFSK() override;
void errataFix(bool rx) override;
-#if !RADIOLIB_GODMODE
- private:
-#endif
- bool ldroAuto = true;
- bool ldroEnabled = false;
-
};
/*!
diff --git a/lib/RadioLib/src/modules/SX127x/SX1279.cpp b/lib/RadioLib/src/modules/SX127x/SX1279.cpp
index a91273f..e356f62 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1279.cpp
+++ b/lib/RadioLib/src/modules/SX127x/SX1279.cpp
@@ -7,7 +7,7 @@ SX1279::SX1279(Module* mod) : SX1278(mod) {
int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) {
// execute common part
- uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
+ const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
@@ -39,7 +39,7 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) {
// execute common part
- uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
+ const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK);
RADIOLIB_ASSERT(state);
@@ -69,7 +69,15 @@ int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
}
int16_t SX1279::setFrequency(float freq) {
- RADIOLIB_CHECK_RANGE(freq, 137.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ // NOTE: The datasheet specifies Band 2 as 410-480 MHz, but the hardware has been
+ // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to
+ // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while
+ // adding a small margin below the 400 MHz practical limit.
+ if(!(((freq >= 137.0f) && (freq <= 160.0f)) ||
+ ((freq >= 395.0f) && (freq <= 480.0f)) ||
+ ((freq >= 779.0f) && (freq <= 960.0f)))) {
+ return(RADIOLIB_ERR_INVALID_FREQUENCY);
+ }
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
diff --git a/lib/RadioLib/src/modules/SX127x/SX1279.h b/lib/RadioLib/src/modules/SX127x/SX1279.h
index 865b1b2..467807f 100644
--- a/lib/RadioLib/src/modules/SX127x/SX1279.h
+++ b/lib/RadioLib/src/modules/SX127x/SX1279.h
@@ -27,9 +27,10 @@ class SX1279: public SX1278 {
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 960.0 MHz.
- \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
+ \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
- \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
+ \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
@@ -38,7 +39,7 @@ class SX1279: public SX1278 {
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0);
+ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0) override;
/*!
\brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
@@ -52,12 +53,12 @@ class SX1279: public SX1278 {
\param enableOOK Use OOK modulation instead of FSK.
\returns \ref status_codes
*/
- int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false);
+ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false) override;
// configuration methods
/*!
- \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 960.0 MHz.
+ \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 160.0 MHz, 395.0 to 480.0 MHz (datasheet minimum is 410.0 MHz, hardware works lower) and 779.0 to 960 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
diff --git a/lib/RadioLib/src/modules/SX127x/SX127x.cpp b/lib/RadioLib/src/modules/SX127x/SX127x.cpp
index 9774b3a..19a3ff9 100644
--- a/lib/RadioLib/src/modules/SX127x/SX127x.cpp
+++ b/lib/RadioLib/src/modules/SX127x/SX127x.cpp
@@ -2,11 +2,13 @@
#include
#if !RADIOLIB_EXCLUDE_SX127X
-SX127x::SX127x(Module* mod) : PhysicalLayer(RADIOLIB_SX127X_FREQUENCY_STEP_SIZE, RADIOLIB_SX127X_MAX_PACKET_LENGTH) {
+SX127x::SX127x(Module* mod) : PhysicalLayer() {
+ this->freqStep = RADIOLIB_SX127X_FREQUENCY_STEP_SIZE;
+ this->maxPacketLength = RADIOLIB_SX127X_MAX_PACKET_LENGTH;
this->mod = mod;
}
-int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength) {
+int16_t SX127x::begin(const uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength) {
// set module properties
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
@@ -63,13 +65,10 @@ int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWo
state = SX127x::invertIQ(false);
RADIOLIB_ASSERT(state);
- // initialize internal variables
- this->dataRate = 0.0;
-
return(state);
}
-int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) {
+int16_t SX127x::beginFSK(const uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) {
// set module properties
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
@@ -202,78 +201,69 @@ int16_t SX127x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
}
}
- // update data rate
- RadioLibTime_t elapsed = this->mod->hal->millis() - start;
- this->dataRate = (len*8.0)/((float)elapsed/1000.0);
-
return(finishTransmit());
}
-int16_t SX127x::receive(uint8_t* data, size_t len) {
+int16_t SX127x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
// set mode to standby
int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
RADIOLIB_ASSERT(state);
- int16_t modem = getActiveModem();
- if(modem == RADIOLIB_SX127X_LORA) {
- // set mode to receive
- state = startReceive(100, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len);
- RADIOLIB_ASSERT(state);
+ // calculate timeout based on the configured modem
+ RadioLibTime_t timeoutInternal = timeout;
+ uint32_t timeoutValue = 0;
+ if(!timeoutInternal) {
+ // calculate timeout (500 % of expected time-one-air)
+ size_t maxLen = len;
+ if(len == 0) { maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH; }
+ timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
- // if no DIO1 is provided, use software timeout (100 LoRa symbols, same as hardware timeout)
- RadioLibTime_t timeout = 0;
- if(this->mod->getGpio() == RADIOLIB_NC) {
- float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
- timeout = (RadioLibTime_t)(symbolLength * 100.0);
- }
+ // convert to symbols
+ float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
+ timeoutValue = (float)timeoutInternal / symbolLength;
+ }
- // wait for packet reception or timeout
- RadioLibTime_t start = this->mod->hal->millis();
- while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
- this->mod->hal->yield();
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
- if(this->mod->getGpio() == RADIOLIB_NC) {
- // no GPIO pin provided, use software timeout
- if(this->mod->hal->millis() - start > timeout) {
- clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
- return(RADIOLIB_ERR_RX_TIMEOUT);
- }
- } else {
- // GPIO provided, use that
- if(this->mod->hal->digitalRead(this->mod->getGpio())) {
- clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
- return(RADIOLIB_ERR_RX_TIMEOUT);
- }
- }
+ // start reception
+ state = startReceive(timeoutValue, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len);
+ RADIOLIB_ASSERT(state);
- }
-
- } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
- // calculate timeout in ms (500 % of expected time-on-air)
- RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000;
-
- // set mode to receive
- state = startReceive(0, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len);
- RADIOLIB_ASSERT(state);
-
- // wait for packet reception or timeout
- RadioLibTime_t start = this->mod->hal->millis();
- while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
- this->mod->hal->yield();
- if(this->mod->hal->millis() - start > timeout) {
- clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
- return(RADIOLIB_ERR_RX_TIMEOUT);
- }
+ // wait for packet reception or timeout
+ bool softTimeout = false;
+ RadioLibTime_t start = this->mod->hal->millis();
+ while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
+ this->mod->hal->yield();
+ // check the blocking timeout
+ if(this->mod->hal->millis() - start > timeoutInternal) {
+ softTimeout = true;
+ break;
}
}
- // read the received data
- state = readData(data, len);
+ // check whether this was a timeout or not
+ if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
+ (void)finishReceive();
+ return(RADIOLIB_ERR_RX_TIMEOUT);
+ }
- return(state);
+ // read the received data
+ return(readData(data, len));
+}
+
+void SX127x::reset() {
+ // should be implemented in derived class
}
int16_t SX127x::scanChannel() {
+ // the configuration is not actually used
+ const ChannelScanConfig_t cfg = { .rssi = { .limit = 0 } };
+ return(scanChannel(cfg));
+}
+
+int16_t SX127x::scanChannel(const ChannelScanConfig_t &config) {
+ (void)config;
+
// start CAD
int16_t state = startChannelScan();
RADIOLIB_ASSERT(state);
@@ -294,7 +284,12 @@ int16_t SX127x::sleep() {
this->mod->setRfSwitchState(Module::MODE_IDLE);
// set mode to sleep
- return(setMode(RADIOLIB_SX127X_SLEEP));
+ int16_t state = setMode(RADIOLIB_SX127X_SLEEP);
+
+ // wait for SX127x to safely enter sleep mode
+ this->mod->hal->delay(1);
+
+ return(state);
}
int16_t SX127x::standby() {
@@ -389,67 +384,6 @@ int16_t SX127x::startReceive() {
return(this->startReceive(0, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
}
-int16_t SX127x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) {
- uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS;
-
- // set mode to standby
- int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
- RADIOLIB_ASSERT(state);
-
- // set DIO pin mapping
- state = this->setIrqFlags(getIrqMapped(irqFlags & irqMask));
- RADIOLIB_ASSERT(state);
-
- int16_t modem = getActiveModem();
- if(modem == RADIOLIB_SX127X_LORA) {
- if(timeout != 0) {
- // for non-zero timeout value, change mode to Rx single and set the timeout
- mode = RADIOLIB_SX127X_RXSINGLE;
- uint8_t msb_sym = (timeout > 0x3FF) ? 0x3 : (uint8_t)(timeout >> 8);
- uint8_t lsb_sym = (timeout > 0x3FF) ? 0xFF : (uint8_t)(timeout & 0xFF);
- state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0);
- state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym);
- RADIOLIB_ASSERT(state);
- }
-
- // in FHSS mode, enable channel change interrupt
- if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
- state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4);
- }
-
- // in implicit header mode, use the provided length if it is nonzero
- // otherwise we trust the user has previously set the payload length manually
- if((this->implicitHdr) && (len != 0)) {
- state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
- this->packetLength = len;
- }
-
- // apply fixes to errata
- RADIOLIB_ERRATA_SX127X(true);
-
- // clear interrupt flags
- clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
-
- // set FIFO pointers
- state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
- state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
- RADIOLIB_ASSERT(state);
-
- } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
- // clear interrupt flags
- clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
-
- // FSK modem does not distinguish between Rx single and continuous
- mode = RADIOLIB_SX127X_RX;
- }
-
- // set RF switch (if present)
- this->mod->setRfSwitchState(Module::MODE_RX);
-
- // set mode to receive
- return(setMode(mode));
-}
-
void SX127x::setDio0Action(void (*func)(void), uint32_t dir) {
this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir);
}
@@ -523,6 +457,11 @@ void SX127x::clearFifoFullAction() {
this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, 0x00, 5, 4);
}
+void SX127x::errataFix(bool rx) {
+ (void)rx;
+ // should be implemented in derived class
+}
+
bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) {
// subtract first (this may be the first time we get to modify the remaining length)
*remLen -= RADIOLIB_SX127X_FIFO_THRESH - 1;
@@ -548,7 +487,7 @@ bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) {
bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) {
// get pointer to the correct position in data buffer
- uint8_t* dataPtr = (uint8_t*)&data[*rcvLen];
+ uint8_t* dataPtr = const_cast(&data[*rcvLen]);
// check how much data are we still expecting
uint8_t len = RADIOLIB_SX127X_FIFO_THRESH - 1;
@@ -568,80 +507,6 @@ bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen)
return(false);
}
-int16_t SX127x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
- // set mode to standby
- int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
-
- int16_t modem = getActiveModem();
- if(modem == RADIOLIB_SX127X_LORA) {
- // check packet length
- if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) {
- return(RADIOLIB_ERR_PACKET_TOO_LONG);
- }
-
- // set DIO mapping
- if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
- this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4);
- } else {
- this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6);
- }
-
- // apply fixes to errata
- RADIOLIB_ERRATA_SX127X(false);
-
- // clear interrupt flags
- clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
-
- // set packet length
- state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
-
- // set FIFO pointers
- state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
- state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
-
- } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
- // clear interrupt flags
- clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
-
- // set DIO mapping
- if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
- this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4);
- } else {
- this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6);
- }
-
- // set packet length - increased by 1 when address filter is enabled
- uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1);
- if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
- if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
- this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len + 1);
- this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, addr);
- } else {
- this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len);
- }
-
- }
-
- }
-
- // write packet to FIFO
- size_t packetLen = len;
- if((modem == RADIOLIB_SX127X_FSK_OOK) && (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) {
- packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1;
- this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
- }
- this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, const_cast(data), packetLen);
-
- // set RF switch (if present)
- this->mod->setRfSwitchState(Module::MODE_TX);
-
- // start transmission
- state |= setMode(RADIOLIB_SX127X_TX);
- RADIOLIB_ASSERT(state);
-
- return(RADIOLIB_ERR_NONE);
-}
-
int16_t SX127x::finishTransmit() {
// wait for at least 1 bit at the lowest possible bit rate before clearing IRQ flags
// not doing this and clearing RADIOLIB_SX127X_FLAG_FIFO_OVERRUN will dump the FIFO,
@@ -711,7 +576,24 @@ int16_t SX127x::readData(uint8_t* data, size_t len) {
return(state);
}
+int16_t SX127x::finishReceive() {
+ // set mode to standby to disable RF switch
+ int16_t state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ return(clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL));
+}
+
int16_t SX127x::startChannelScan() {
+ // the configuration is not actually used
+ const ChannelScanConfig_t cfg = { .rssi = { .limit = 0 } };
+ return(startChannelScan(cfg));
+}
+
+int16_t SX127x::startChannelScan(const ChannelScanConfig_t &config) {
+ (void)config;
+
// check active modem
if(getActiveModem() != RADIOLIB_SX127X_LORA) {
return(RADIOLIB_ERR_WRONG_MODEM);
@@ -844,14 +726,14 @@ float SX127x::getFrequencyError(bool autoCorrect) {
// frequency error is negative
raw |= (uint32_t)0xFFF00000;
raw = ~raw + 1;
- error = (((float)raw * (float)base)/32000000.0) * (this->bandwidth/500.0) * -1.0;
+ error = (((float)raw * (float)base)/32000000.0f) * (this->bandwidth/500.0f) * -1.0f;
} else {
- error = (((float)raw * (float)base)/32000000.0) * (this->bandwidth/500.0);
+ error = (((float)raw * (float)base)/32000000.0f) * (this->bandwidth/500.0f);
}
if(autoCorrect) {
// adjust LoRa modem data rate
- float ppmOffset = 0.95 * (error/32.0);
+ float ppmOffset = 0.95f * (error/32.0f);
this->mod->SPIwriteRegister(0x27, (uint8_t)ppmOffset);
}
@@ -870,9 +752,9 @@ float SX127x::getFrequencyError(bool autoCorrect) {
// frequency error is negative
raw |= (uint32_t)0xFFF00000;
raw = ~raw + 1;
- error = (float)raw * (32000000.0 / (float)(base << 19)) * -1.0;
+ error = (float)raw * (32000000.0f / (float)(base << 19)) * -1.0f;
} else {
- error = (float)raw * (32000000.0 / (float)(base << 19));
+ error = (float)raw * (32000000.0f / (float)(base << 19));
}
return(error);
@@ -894,7 +776,7 @@ float SX127x::getAFCError()
raw |= this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_LSB);
uint32_t base = 1;
- return raw * (32000000.0 / (float)(base << 19));
+ return raw * (32000000.0f / (float)(base << 19));
}
float SX127x::getSNR() {
@@ -908,10 +790,6 @@ float SX127x::getSNR() {
return(rawSNR / 4.0);
}
-float SX127x::getDataRate() const {
- return(this->dataRate);
-}
-
int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) {
// check active modem
if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
@@ -921,9 +799,9 @@ int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) {
// check allowed bit rate
// datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine
if(ookEnabled) {
- RADIOLIB_CHECK_RANGE(br, 0.5, 32.768002, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002
+ RADIOLIB_CHECK_RANGE(br, 0.5f, 32.768002f, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002
} else {
- RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(br, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
}
// set mode to STANDBY
@@ -931,13 +809,13 @@ int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) {
RADIOLIB_ASSERT(state);
// set bit rate
- uint16_t bitRateRaw = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / br;
+ uint16_t bitRateRaw = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0f) / br;
state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRateRaw & 0xFF00) >> 8, 7, 0);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRateRaw & 0x00FF, 7, 0);
// set fractional part of bit rate
if(!ookEnabled) {
- float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / (float)br) - (float)bitRateRaw;
+ float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0f) / br) - (float)bitRateRaw;
uint8_t bitRateFrac = bitRateRem * 16;
state |= this->mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0);
}
@@ -956,15 +834,17 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
- if(freqDev < 0.0) {
- newFreqDev = 0.6;
+ if(freqDev < 0.0f) {
+ newFreqDev = 0.6f;
}
// check frequency deviation range
- if(!((newFreqDev + this->bitRate/2.0 <= 250.0) && (freqDev <= 200.0))) {
+ if(!((newFreqDev + this->bitRate/2.0f <= 250.0f) && (freqDev <= 200.0f))) {
return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
}
+ this->frequencyDev = newFreqDev;
+
// set mode to STANDBY
int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
RADIOLIB_ASSERT(state);
@@ -981,8 +861,8 @@ uint8_t SX127x::calculateBWManExp(float bandwidth)
{
for(uint8_t e = 7; e >= 1; e--) {
for(int8_t m = 2; m >= 0; m--) {
- float point = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2)));
- if(fabsf(bandwidth - ((point / 1000.0) + 0.05)) <= 0.5) {
+ float point = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000000.0f)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2)));
+ if(fabsf(bandwidth - ((point / 1000.0f) + 0.05f)) <= 0.5f) {
return((m << 3) | e);
}
}
@@ -996,7 +876,7 @@ int16_t SX127x::setRxBandwidth(float rxBw) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
- RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 250.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
// set mode to STANDBY
int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
@@ -1012,7 +892,7 @@ int16_t SX127x::setAFCBandwidth(float rxBw) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
- RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 250.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
// set mode to STANDBY
int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
@@ -1237,6 +1117,20 @@ size_t SX127x::getPacketLength(bool update) {
return(this->packetLength);
}
+int16_t SX127x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
+ int16_t state = RADIOLIB_ERR_NONE;
+
+ // check if in explicit header mode
+ if(this->implicitHdr) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_STAT, 7, 5) >> 5; }
+ if(hasCRC) { *hasCRC = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) != 0; }
+
+ return(state);
+}
+
int16_t SX127x::fixedPacketLengthMode(uint8_t len) {
return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_FIXED, len));
}
@@ -1245,75 +1139,115 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) {
return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen));
}
-float SX127x::getNumSymbols(size_t len) {
- // get symbol length in us
- float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
-
+float SX127x::getNumSymbols(size_t len, DataRate_t dr, PacketConfig_t pc) {
// get Low Data Rate optimization flag
- float de = 0;
- if (symbolLength >= 16.0) {
- de = 1;
- }
+ float de = pc.lora.ldrOptimize ? 1.0f : 0.0f;
// get explicit/implicit header enabled flag
- float ih = (float) this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0);
-
+ float ih = (float) pc.lora.implicitHeader;
+
// get CRC enabled flag
- float crc = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2);
+ float crc = (float) pc.lora.crcEnabled;
// get number of preamble symbols
- float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB));
+ float n_pre = (float) pc.lora.preambleLength;
// get number of payload symbols
- float n_pay = 8.0 + RADIOLIB_MAX(ceilf((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0);
+ float n_pay = 8.0f + RADIOLIB_MAX(ceilf((8.0f * (float) len - 4.0f * (float) dr.lora.spreadingFactor + 28.0f + 16.0f * crc - 20.0f * ih) / (4.0f * (float) dr.lora.spreadingFactor - 8.0f * de)) * (float) dr.lora.codingRate, 0.0f);
// add 4.25 symbols for the sync
return(n_pre + n_pay + 4.25f);
}
-RadioLibTime_t SX127x::getTimeOnAir(size_t len) {
- // check active modem
- uint8_t modem = getActiveModem();
- if (modem == RADIOLIB_SX127X_LORA) {
+RadioLibTime_t SX127x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
+ if (modem == RADIOLIB_MODEM_LORA) {
// get symbol length in us
- float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
+ float symbolLength = (float) (uint32_t(1) << dr.lora.spreadingFactor) / (float) dr.lora.bandwidth;
// get number of symbols
- float n_sym = getNumSymbols(len);
+ float n_sym = getNumSymbols(len, dr, pc);
// get time-on-air in us
return ceil((double)symbolLength * (double)n_sym) * 1000;
- } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
- // get number of bits preamble
- float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8;
- // get the number of bits of the sync word
- float n_syncWord = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8;
- // get CRC bits
- float crc = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON) * 16;
-
- if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) {
- // if packet size fixed -> len = fixed packet length
- len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
- } else {
- // if packet variable -> Add 1 extra byte for payload length
- len += 1;
- }
-
+ } else if(modem == RADIOLIB_MODEM_FSK) {
+
// calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec)
- return((uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0)) * 1000000.0));
+ return((uint32_t) ((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (float) (len * 8)) / (dr.fsk.bitRate * 1000.0f)) * 1000000.0f));
+ } else {
+ return(RADIOLIB_ERR_WRONG_MODEM);
}
return(RADIOLIB_ERR_UNKNOWN);
}
+RadioLibTime_t SX127x::getTimeOnAir(size_t len) {
+ uint8_t modem = getActiveModem();
+ DataRate_t dr = {};
+ PacketConfig_t pc = {};
+
+ switch (modem) {
+ case(RADIOLIB_SX127X_LORA): {
+ dr.lora.spreadingFactor = this->spreadingFactor;
+ dr.lora.bandwidth = this->bandwidth;
+ dr.lora.codingRate = this->codingRate;
+
+ // Get number of preamble symbols
+ uint16_t n_pre = ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB));
+
+ pc.lora.preambleLength = n_pre;
+ pc.lora.implicitHeader = this->implicitHdr;
+ pc.lora.crcEnabled = this->crcEnabled;
+ pc.lora.ldrOptimize = this->ldroEnabled;
+
+ return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_LORA, dr, pc, len));
+ }
+ case(RADIOLIB_SX127X_FSK_OOK): {
+ dr.fsk.bitRate = this->bitRate;
+ dr.fsk.freqDev = this->frequencyDev;
+
+ // get number of bits preamble
+ uint16_t n_pre = (uint16_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8;
+ // get the number of bits of the sync word
+ uint8_t n_syncWord = (uint8_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8);
+ // get CRC enabled status
+ bool crcEn = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON);
+
+ pc.fsk.preambleLength = n_pre;
+ pc.fsk.syncWordLength = n_syncWord;
+ pc.fsk.crcLength = (uint8_t)(crcEn * 2);
+
+ if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) {
+ // if packet size fixed -> len = fixed packet length
+ len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
+ } else {
+ // if packet variable -> Add 1 extra byte for payload length
+ len += 1;
+ }
+
+ return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_FSK, dr, pc, len));
+ }
+ default:
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+}
+
RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
- // the timeout is given as the number of symbols
- // the calling function should provide some extra width, as this number of symbols is truncated to integer
- // the order of operators is swapped here to decrease the effects of this truncation error
- float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
- RadioLibTime_t numSymbols = (timeoutUs / symbolLength) / 1000;
- return(numSymbols);
+ RadioLibTime_t timeout = 0;
+ if(getActiveModem() == RADIOLIB_SX127X_LORA) {
+ // for LoRa, the timeout is given as the number of symbols
+ // the calling function should provide some extra width, as this number of symbols is truncated to integer
+ // the order of operators is swapped here to decrease the effects of this truncation error
+ float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
+ timeout = (timeoutUs / symbolLength) / 1000;
+
+ } else {
+ // for FSK, the timeout is in units of 16x bit time
+ timeout = ((float)timeoutUs / ((16.0f * 1000.0f) / this->bitRate));
+
+ }
+
+ return(timeout);
}
uint32_t SX127x::getIrqFlags() {
@@ -1448,9 +1382,9 @@ int16_t SX127x::setCrcFiltering(bool enable) {
}
int16_t SX127x::setRSSIThreshold(float dbm) {
- RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD);
+ RADIOLIB_CHECK_RANGE(dbm, -127.5f, 0.0f, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD);
- return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0);
+ return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0f * dbm), 7, 0);
}
int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) {
@@ -1724,7 +1658,9 @@ int16_t SX127x::setActiveModem(uint8_t modem) {
int16_t state = setMode(RADIOLIB_SX127X_SLEEP);
// set modem
- state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5);
+ // low frequency access (bit 3) automatically resets when switching modem
+ // so we exclude it from the check
+ state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5, 0xF7);
// set mode to STANDBY
state |= setMode(RADIOLIB_SX127X_STANDBY);
@@ -1776,6 +1712,170 @@ int16_t SX127x::getModem(ModemType_t* modem) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
+int16_t SX127x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
+ int16_t state;
+
+ switch(mode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ this->rxMode = RADIOLIB_SX127X_RXCONTINUOUS;
+
+ // set mode to standby
+ state = setMode(RADIOLIB_SX127X_STANDBY);
+ RADIOLIB_ASSERT(state);
+
+ // set DIO pin mapping
+ state = this->setIrqFlags(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
+ RADIOLIB_ASSERT(state);
+
+ int16_t modem = getActiveModem();
+ if(modem == RADIOLIB_SX127X_LORA) {
+ // if max(uint32_t) is used, revert to RxContinuous
+ if(cfg->receive.timeout == 0xFFFFFFFF) {
+ cfg->receive.timeout = 0;
+ }
+ if(cfg->receive.timeout != 0) {
+ // for non-zero timeout value, change mode to Rx single and set the timeout
+ this->rxMode = RADIOLIB_SX127X_RXSINGLE;
+ uint8_t msb_sym = (cfg->receive.timeout > 0x3FF) ? 0x3 : (uint8_t)(cfg->receive.timeout >> 8);
+ uint8_t lsb_sym = (cfg->receive.timeout > 0x3FF) ? 0xFF : (uint8_t)(cfg->receive.timeout & 0xFF);
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0);
+ state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // in FHSS mode, enable channel change interrupt
+ if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4);
+ }
+
+ // in implicit header mode, use the provided length if it is nonzero
+ // otherwise we trust the user has previously set the payload length manually
+ if((this->implicitHdr) && (cfg->receive.len != 0)) {
+ state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->receive.len);
+ this->packetLength = cfg->receive.len;
+ }
+
+ // apply fixes to errata
+ RADIOLIB_ERRATA_SX127X(true);
+
+ // clear interrupt flags
+ clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
+
+ // set FIFO pointers
+ state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
+ state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
+ RADIOLIB_ASSERT(state);
+
+ } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
+ // for non-zero timeout value, emulate timeout
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, cfg->receive.timeout & 0xFF);
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
+
+ // FSK modem does not actually distinguish between Rx single and continuous mode,
+ // Rx single is emulated using timeout
+ this->rxMode = RADIOLIB_SX127X_RX;
+ }
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ // set mode to standby
+ state = setMode(RADIOLIB_SX127X_STANDBY);
+
+ int16_t modem = getActiveModem();
+ if(modem == RADIOLIB_SX127X_LORA) {
+ // check packet length
+ if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+
+ // set DIO mapping
+ if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
+ this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4);
+ } else {
+ this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6);
+ }
+
+ // apply fixes to errata
+ RADIOLIB_ERRATA_SX127X(false);
+
+ // clear interrupt flags
+ clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
+
+ // set packet length
+ state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->transmit.len);
+
+ // set FIFO pointers
+ state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
+ state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
+
+ } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
+ // clear interrupt flags
+ clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
+
+ // set DIO mapping
+ if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
+ this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4);
+ } else {
+ this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6);
+ }
+
+ // set packet length - increased by 1 when address filter is enabled
+ uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1);
+ if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
+ if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
+ this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len + 1);
+ this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.addr);
+ } else {
+ this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len);
+ }
+
+ }
+
+ }
+
+ // write packet to FIFO
+ size_t packetLen = cfg->transmit.len;
+ if((modem == RADIOLIB_SX127X_FSK_OOK) && (cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) {
+ packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1;
+ this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
+ }
+ this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.data, packetLen);
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = mode;
+ return(state);
+}
+
+int16_t SX127x::launchMode() {
+ int16_t state;
+ switch(this->stagedMode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ this->mod->setRfSwitchState(Module::MODE_RX);
+ state = setMode(this->rxMode);
+ RADIOLIB_ASSERT(state);
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ this->mod->setRfSwitchState(Module::MODE_TX);
+ state = setMode(RADIOLIB_SX127X_TX);
+ RADIOLIB_ASSERT(state);
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
+ return(state);
+}
+
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
void SX127x::setDirectAction(void (*func)(void)) {
setDio1Action(func, this->mod->hal->GpioInterruptRising);
@@ -1830,7 +1930,7 @@ float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) {
// spread-spectrum modulation signal can be received below noise floor
// check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value
float lastPacketSNR = SX127x::getSNR();
- if(lastPacketSNR < 0.0) {
+ if(lastPacketSNR < 0.0f) {
lastPacketRSSI += lastPacketSNR;
}
return(lastPacketRSSI);
@@ -1850,7 +1950,7 @@ float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) {
}
// read the value for FSK
- float rssi = (float)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0;
+ float rssi = (float)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0f;
// set mode back to standby
if(!skipReceive) {
@@ -1869,12 +1969,11 @@ int16_t SX127x::setHeaderType(uint8_t headerType, uint8_t bitIndex, size_t len)
}
// set requested packet mode
- Module* mod = this->getMod();
- int16_t state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, bitIndex, bitIndex);
+ int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, bitIndex, bitIndex);
RADIOLIB_ASSERT(state);
// set length to register
- state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
+ state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
RADIOLIB_ASSERT(state);
// update cached value
diff --git a/lib/RadioLib/src/modules/SX127x/SX127x.h b/lib/RadioLib/src/modules/SX127x/SX127x.h
index 593f27e..7eb8a80 100644
--- a/lib/RadioLib/src/modules/SX127x/SX127x.h
+++ b/lib/RadioLib/src/modules/SX127x/SX127x.h
@@ -12,8 +12,8 @@
// SX127x physical layer properties
#define RADIOLIB_SX127X_FREQUENCY_STEP_SIZE 61.03515625
#define RADIOLIB_SX127X_MAX_PACKET_LENGTH 255
-#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64
-#define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0
+#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 // as per datasheet Rev. 7, page 66, the FSK FIFO is just 64 bytes
+#define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0f
#define RADIOLIB_SX127X_DIV_EXPONENT 19
// SX127x series common LoRa registers
@@ -586,6 +586,7 @@ class SX127x: public PhysicalLayer {
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
+ using PhysicalLayer::startReceive;
using PhysicalLayer::readData;
// constructor
@@ -606,12 +607,12 @@ class SX127x: public PhysicalLayer {
\param preambleLength Length of %LoRa transmission preamble in symbols.
\returns \ref status_codes
*/
- int16_t begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength);
+ int16_t begin(const uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength);
/*!
- \brief Reset method. Will reset the chip to the default state using RST pin. Declared pure virtual since SX1272 and SX1278 implementations differ.
+ \brief Reset method. Will reset the chip to the default state using RST pin. Should be implemented in derived class since SX1272 and SX1278 implementations differ.
*/
- virtual void reset() = 0;
+ virtual void reset();
/*!
\brief Initialization method for FSK modem. Will be called with appropriate parameters when calling FSK initialization method from derived class.
@@ -623,7 +624,7 @@ class SX127x: public PhysicalLayer {
\param enableOOK Flag to specify OOK mode. This modulation is similar to FSK.
\returns \ref status_codes
*/
- int16_t beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK);
+ int16_t beginFSK(const uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK);
/*!
\brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem.
@@ -640,9 +641,11 @@ class SX127x: public PhysicalLayer {
For overloads to receive Arduino String, see PhysicalLayer::receive.
\param data Pointer to array to save the received binary data.
\param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+ \param timeout Reception timeout in milliseconds. If set to 0,
+ timeout period will be calculated automatically based on the radio configuration.
\returns \ref status_codes
*/
- int16_t receive(uint8_t* data, size_t len) override;
+ int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override;
/*!
\brief Performs scan for valid %LoRa preamble in the current channel.
@@ -650,6 +653,13 @@ class SX127x: public PhysicalLayer {
*/
int16_t scanChannel() override;
+ /*!
+ \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload.
+ \param config Ignored. Implemented only for PhysicalLayer compatibility.
+ \returns \ref status_codes
+ */
+ int16_t scanChannel(const ChannelScanConfig_t &config) override;
+
/*!
\brief Sets the %LoRa module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode.
%Module will wake up automatically when methods like transmit or receive are called.
@@ -798,15 +808,6 @@ class SX127x: public PhysicalLayer {
*/
bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen);
- /*!
- \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem.
- \param data Binary data that will be transmitted.
- \param len Length of binary data to transmit (in bytes).
- \param addr Node address to transmit the packet to. Only used in FSK mode.
- \returns \ref status_codes
- */
- int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override;
-
/*!
\brief Clean up after transmission is done.
\returns \ref status_codes
@@ -820,19 +821,6 @@ class SX127x: public PhysicalLayer {
*/
int16_t startReceive() override;
- /*!
- \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer.
- \param timeout Receive mode type and/or raw timeout value in symbols.
- When set to 0, the timeout will be infinite and the device will remain
- in Rx mode until explicitly commanded to stop (Rx continuous mode).
- When non-zero (maximum 1023), the device will be set to Rx single mode and timeout will be set.
- \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error.
- \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done.
- \param len Expected length of packet to be received. Required for LoRa spreading factor 6.
- \returns \ref status_codes
- */
- int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0) override;
-
/*!
\brief Reads data that was received after calling startReceive method. When the packet length is not known in advance,
getPacketLength method must be called BEFORE calling readData!
@@ -844,12 +832,26 @@ class SX127x: public PhysicalLayer {
int16_t readData(uint8_t* data, size_t len) override;
/*!
- \brief Interrupt-driven channel activity detection method. DIO0 will be activated when LoRa preamble is detected.
- DIO1 will be activated if there's no preamble detected before timeout.
+ \brief Clean up after reception is done.
+ \returns \ref status_codes
+ */
+ int16_t finishReceive() override;
+
+ /*!
+ \brief Interrupt-driven channel activity detection method. DIO1 will be activated when LoRa preamble is detected.
+ DIO0 will be activated if there's no preamble detected before timeout.
\returns \ref status_codes
*/
int16_t startChannelScan() override;
+ /*!
+ \brief Interrupt-driven channel activity detection method. DIO1 will be activated
+ when LoRa preamble is detected, or upon timeout.
+ \param config Ignored. Implemented only for PhysicalLayer compatibility.
+ \returns \ref status_codes
+ */
+ int16_t startChannelScan(const ChannelScanConfig_t &config) override;
+
/*!
\brief Read the channel scan result.
\returns \ref status_codes
@@ -905,12 +907,6 @@ class SX127x: public PhysicalLayer {
*/
float getSNR() override;
- /*!
- \brief Get data rate of the latest transmitted packet.
- \returns Last packet data rate in bps (bits per second).
- */
- float getDataRate() const;
-
/*!
\brief Sets FSK frequency deviation from carrier frequency. Allowed values depend on bit rate setting and must be lower than 200 kHz. Only available in FSK mode.
\param freqDev Frequency deviation to be set (in kHz).
@@ -1028,6 +1024,14 @@ class SX127x: public PhysicalLayer {
*/
size_t getPacketLength(bool update = true) override;
+ /*!
+ \brief Get LoRa header information from last received packet. Only valid in explicit header mode.
+ \param cr Pointer to variable to store the coding rate.
+ \param hasCRC Pointer to variable to store the CRC status.
+ \returns \ref status_codes
+ */
+ int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC);
+
/*!
\brief Set modem in fixed packet length mode. Available in FSK mode only.
\param len Packet length.
@@ -1045,9 +1049,11 @@ class SX127x: public PhysicalLayer {
/*!
\brief Convert from bytes to LoRa symbols.
\param len Payload length in bytes.
+ \param dr Data rate.
+ \param pc Packet configuration.
\returns The total number of LoRa symbols, including preamble, sync and possible header.
*/
- float getNumSymbols(size_t len);
+ float getNumSymbols(size_t len, DataRate_t dr, PacketConfig_t pc);
/*!
\brief Get expected time-on-air for a given size of payload.
@@ -1056,6 +1062,16 @@ class SX127x: public PhysicalLayer {
*/
RadioLibTime_t getTimeOnAir(size_t len) override;
+ /*!
+ \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size.
+ \param modem Modem type.
+ \param dr Data rate.
+ \param pc Packet config.
+ \param len Payload length in bytes.
+ \returns Expected time-on-air in microseconds.
+ */
+ RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override;
+
/*!
\brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
\param timeoutUs Timeout in microseconds to listen for
@@ -1152,7 +1168,7 @@ class SX127x: public PhysicalLayer {
/*!
\brief Enable/disable inversion of the I and Q signals
- \param enable QI inversion enabled (true) or disabled (false);
+ \param enable IQ inversion enabled (true) or disabled (false);
\returns \ref status_codes
*/
int16_t invertIQ(bool enable) override;
@@ -1163,6 +1179,12 @@ class SX127x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t getModem(ModemType_t* modem) override;
+
+ /*! \copydoc PhysicalLayer::stageMode */
+ int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override;
+
+ /*! \copydoc PhysicalLayer::launchMode */
+ int16_t launchMode() override;
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
/*!
@@ -1208,7 +1230,7 @@ class SX127x: public PhysicalLayer {
\param value The value that indicates which function to place on that pin. See chip datasheet for details.
\returns \ref status_codes
*/
- int16_t setDIOMapping(uint32_t pin, uint32_t value) override;
+ int16_t setDIOMapping(uint32_t pin, uint32_t value);
/*!
\brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it.
@@ -1243,15 +1265,17 @@ class SX127x: public PhysicalLayer {
protected:
#endif
float frequency = 0;
- float bandwidth = 0;
- uint8_t spreadingFactor = 0;
+ float bandwidth = 125;
+ uint8_t spreadingFactor = 9;
size_t packetLength = 0;
uint8_t codingRate = 0;
bool crcEnabled = false;
bool ookEnabled = false;
bool implicitHdr = false;
+ bool ldroAuto = true;
+ bool ldroEnabled = false;
- int16_t configFSK();
+ virtual int16_t configFSK();
int16_t getActiveModem();
int16_t setFrequencyRaw(float newFreq);
int16_t setBitRateCommon(float br, uint8_t fracRegAddr);
@@ -1263,11 +1287,11 @@ class SX127x: public PhysicalLayer {
#endif
Module* mod;
- float bitRate = 0;
+ float bitRate = 0, frequencyDev = 0;
bool crcOn = true; // default value used in FSK mode
- float dataRate = 0;
bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once
uint8_t packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE;
+ uint8_t rxMode = RADIOLIB_SX127X_RXCONTINUOUS;
int16_t config();
int16_t directMode();
@@ -1284,7 +1308,7 @@ class SX127x: public PhysicalLayer {
*/
static uint8_t calculateBWManExp(float bandwidth);
- virtual void errataFix(bool rx) = 0;
+ virtual void errataFix(bool rx); // should be implemented in derived class
};
#endif
diff --git a/lib/RadioLib/src/modules/SX128x/SX1280.cpp b/lib/RadioLib/src/modules/SX128x/SX1280.cpp
index fae3516..fa496e2 100644
--- a/lib/RadioLib/src/modules/SX128x/SX1280.cpp
+++ b/lib/RadioLib/src/modules/SX128x/SX1280.cpp
@@ -3,7 +3,7 @@
#if !RADIOLIB_EXCLUDE_SX128X
SX1280::SX1280(Module* mod) : SX1281(mod) {
-
+ chipType = RADIOLIB_SX1280_CHIP_TYPE;
}
int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) {
@@ -17,23 +17,15 @@ int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) {
while(!mod->hal->digitalRead(mod->getIrq())) {
mod->hal->yield();
if(mod->hal->millis() - start > 10000) {
- clearIrqStatus();
- standby();
+ (void)finishRanging();
return(RADIOLIB_ERR_RANGING_TIMEOUT);
}
}
- // clear interrupt flags
- state = clearIrqStatus();
- RADIOLIB_ASSERT(state);
-
- // set mode to standby
- state = standby();
-
- return(state);
+ return(finishRanging());
}
-int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6]) {
+int16_t SX1280::startRanging(bool master, uint32_t addr, const uint16_t calTable[3][6]) {
// check active modem
uint8_t modem = getPacketType();
if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
@@ -80,7 +72,7 @@ int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6]
}
// set ranging address
- uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
+ const uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
state = writeRegister(addrReg, addrBuff, 4);
RADIOLIB_ASSERT(state);
@@ -116,7 +108,7 @@ int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6]
default:
return(RADIOLIB_ERR_INVALID_BANDWIDTH);
}
- uint8_t calBuff[] = { (uint8_t)((val >> 8) & 0xFF), (uint8_t)(val & 0xFF) };
+ const uint8_t calBuff[] = { (uint8_t)((val >> 8) & 0xFF), (uint8_t)(val & 0xFF) };
state = writeRegister(RADIOLIB_SX128X_REG_RANGING_CALIBRATION_MSB, calBuff, 2);
RADIOLIB_ASSERT(state);
@@ -140,13 +132,42 @@ int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6]
return(state);
}
+int16_t SX1280::finishRanging() {
+ // start by clearing interrupt flags
+ int16_t state = clearIrqStatus();
+ RADIOLIB_ASSERT(state);
+
+ // set mode to standby
+ state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // restore back to LoRa communication
+ // config sets up the bare minimum
+ state = config(RADIOLIB_SX128X_PACKET_TYPE_LORA);
+ RADIOLIB_ASSERT(state);
+
+ // restore modulation and packet parameters and we're done
+ state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa);
+ RADIOLIB_ASSERT(state);
+ return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa));
+}
+
+int32_t SX1280::getRangingResultRaw() {
+ return(getRangingResultCommon(false));
+}
+
float SX1280::getRangingResult() {
+ int32_t raw = getRangingResultCommon(false);
+ return((float)raw * 150.0f / (4.096f * this->bandwidthKhz));
+}
+
+int32_t SX1280::getRangingResultCommon(bool filtered) {
// set mode to standby XOSC
int16_t state = standby(RADIOLIB_SX128X_STANDBY_XOSC);
RADIOLIB_ASSERT(state);
// enable clock
- uint8_t data[4];
+ uint8_t data[3] = { 0 };
state = readRegister(RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1);
RADIOLIB_ASSERT(state);
@@ -154,31 +175,29 @@ float SX1280::getRangingResult() {
state = writeRegister(RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1);
RADIOLIB_ASSERT(state);
- // set result type to filtered
+ // set result type filtered/raw
+ // TODO: at the moment, filtered values do not work and just return huge numbers
+ // the datasheet also isn't exactly clear on how to use the filtering
+ // (when to reset, when are samples added etc.)
state = readRegister(RADIOLIB_SX128X_REG_RANGING_TYPE, data, 1);
RADIOLIB_ASSERT(state);
data[0] &= 0xCF;
- data[0] |= (1 << 4);
+ data[0] |= ((uint8_t)filtered << 4);
state = writeRegister(RADIOLIB_SX128X_REG_RANGING_TYPE, data, 1);
RADIOLIB_ASSERT(state);
// read the register values
- state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MSB, &data[0], 1);
- RADIOLIB_ASSERT(state);
- state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MID, &data[1], 1);
- RADIOLIB_ASSERT(state);
- state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_LSB, &data[2], 1);
+ state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MSB, data, 3);
RADIOLIB_ASSERT(state);
// set mode to standby RC
state = standby();
RADIOLIB_ASSERT(state);
- // calculate the real result
- uint32_t uraw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2];
- int32_t raw = (uraw & ((1UL << 23) - 1)) | (uraw >> 23 << 31);
- return((float)raw * 150.0 / (4.096 * this->bandwidthKhz));
+ // shifting everything by 8 bits more to the left will convert the result to signed number
+ int32_t raw = ((((int32_t)data[0]) << 24) | (((int32_t)data[1]) << 16) | (((int32_t)data[2]) << 8)) >> 8;
+ return(raw);
}
#endif
diff --git a/lib/RadioLib/src/modules/SX128x/SX1280.h b/lib/RadioLib/src/modules/SX128x/SX1280.h
index e06faec..2e2bc04 100644
--- a/lib/RadioLib/src/modules/SX128x/SX1280.h
+++ b/lib/RadioLib/src/modules/SX128x/SX1280.h
@@ -9,6 +9,9 @@
#include "SX128x.h"
#include "SX1281.h"
+// RADIOLIB_SX128X_REG_VERSION_STRING
+#define RADIOLIB_SX1280_CHIP_TYPE "SX1280"
+
/*!
\class SX1280
\brief Derived class for %SX1280 modules.
@@ -37,7 +40,13 @@ class SX1280: public SX1281 {
\param calTable Ranging calibration table - set to NULL to use the default.
\returns \ref status_codes
*/
- int16_t startRanging(bool master, uint32_t addr, uint16_t calTable[3][6] = NULL);
+ int16_t startRanging(bool master, uint32_t addr, const uint16_t calTable[3][6] = NULL);
+
+ /*!
+ \brief Clean up after ranging is done. Will set modem back to LoRa mode.
+ \returns \ref status_codes
+ */
+ int16_t finishRanging();
/*!
\brief Gets ranging result of the last ranging exchange.
@@ -45,10 +54,18 @@ class SX1280: public SX1281 {
*/
float getRangingResult();
+ /*!
+ \brief Gets ranging result of the last ranging exchange.
+ \returns Ranging result in arbitrary raw units. For conversion to meters,
+ see SX1280 datasheet, or use the getRangingResult method.
+ */
+ int32_t getRangingResultRaw();
+
#if !RADIOLIB_GODMODE
private:
#endif
+ int32_t getRangingResultCommon(bool filtered);
};
#endif
diff --git a/lib/RadioLib/src/modules/SX128x/SX1281.cpp b/lib/RadioLib/src/modules/SX128x/SX1281.cpp
index 71e7476..b6bdf77 100644
--- a/lib/RadioLib/src/modules/SX128x/SX1281.cpp
+++ b/lib/RadioLib/src/modules/SX128x/SX1281.cpp
@@ -2,7 +2,7 @@
#if !RADIOLIB_EXCLUDE_SX128X
SX1281::SX1281(Module* mod) : SX128x(mod) {
-
+ chipType = RADIOLIB_SX1281_CHIP_TYPE;
}
#endif
diff --git a/lib/RadioLib/src/modules/SX128x/SX1281.h b/lib/RadioLib/src/modules/SX128x/SX1281.h
index 3d697da..9cdc95e 100644
--- a/lib/RadioLib/src/modules/SX128x/SX1281.h
+++ b/lib/RadioLib/src/modules/SX128x/SX1281.h
@@ -8,6 +8,9 @@
#include "../../Module.h"
#include "SX128x.h"
+// RADIOLIB_SX128X_REG_VERSION_STRING
+#define RADIOLIB_SX1281_CHIP_TYPE "SX1281"
+
/*!
\class SX1281
\brief Derived class for %SX1281 modules.
diff --git a/lib/RadioLib/src/modules/SX128x/SX1282.cpp b/lib/RadioLib/src/modules/SX128x/SX1282.cpp
index d58ba3d..f801d62 100644
--- a/lib/RadioLib/src/modules/SX128x/SX1282.cpp
+++ b/lib/RadioLib/src/modules/SX128x/SX1282.cpp
@@ -3,7 +3,7 @@
/// \todo implement advanced ranging
SX1282::SX1282(Module* mod) : SX1280(mod) {
-
+ chipType = RADIOLIB_SX1282_CHIP_TYPE;
}
#endif
diff --git a/lib/RadioLib/src/modules/SX128x/SX1282.h b/lib/RadioLib/src/modules/SX128x/SX1282.h
index dc51ba9..0b98c94 100644
--- a/lib/RadioLib/src/modules/SX128x/SX1282.h
+++ b/lib/RadioLib/src/modules/SX128x/SX1282.h
@@ -9,6 +9,9 @@
#include "SX128x.h"
#include "SX1280.h"
+// RADIOLIB_SX128X_REG_VERSION_STRING
+#define RADIOLIB_SX1282_CHIP_TYPE "SX1282"
+
/*!
\class SX1282
\brief Derived class for %SX1282 modules.
diff --git a/lib/RadioLib/src/modules/SX128x/SX128x.cpp b/lib/RadioLib/src/modules/SX128x/SX128x.cpp
index 139fac5..966db18 100644
--- a/lib/RadioLib/src/modules/SX128x/SX128x.cpp
+++ b/lib/RadioLib/src/modules/SX128x/SX128x.cpp
@@ -1,8 +1,11 @@
#include "SX128x.h"
#include
+#include
#if !RADIOLIB_EXCLUDE_SX128X
-SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE, RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
+SX128x::SX128x(Module* mod) : PhysicalLayer() {
+ this->freqStep = RADIOLIB_SX128X_FREQUENCY_STEP_SIZE;
+ this->maxPacketLength = RADIOLIB_SX128X_MAX_PACKET_LENGTH;
this->mod = mod;
this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX128X_IRQ_TX_DONE;
this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX128X_IRQ_RX_DONE;
@@ -17,21 +20,6 @@ SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE,
}
int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength) {
- // set module properties
- this->mod->init();
- this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
- this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
- this->mod->spiConfig.statusPos = 1;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
- this->mod->spiConfig.stream = true;
- this->mod->spiConfig.parseStatusCb = SPIparseStatus;
- RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
-
// initialize LoRa modulation variables
this->bandwidthKhz = bw;
this->spreadingFactor = RADIOLIB_SX128X_LORA_SF_9;
@@ -43,16 +31,8 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
this->payloadLen = 0xFF;
this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON;
- // reset the module and verify startup
- int16_t state = reset();
- RADIOLIB_ASSERT(state);
-
- // set mode to standby
- state = standby();
- RADIOLIB_ASSERT(state);
-
- // configure settings not accessible by API
- state = config(RADIOLIB_SX128X_PACKET_TYPE_LORA);
+ // set module properties and perform initial setup
+ int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_LORA);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
@@ -81,21 +61,6 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
}
int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, uint16_t preambleLength) {
- // set module properties
- this->mod->init();
- this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
- this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
- this->mod->spiConfig.statusPos = 1;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
- this->mod->spiConfig.stream = true;
- this->mod->spiConfig.parseStatusCb = SPIparseStatus;
- RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
-
// initialize GFSK modulation variables
this->bitRateKbps = br;
this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
@@ -110,16 +75,8 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, ui
this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE;
this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
- // reset the module and verify startup
- int16_t state = reset();
- RADIOLIB_ASSERT(state);
-
- // set mode to standby
- state = standby();
- RADIOLIB_ASSERT(state);
-
- // configure settings not accessible by API
- state = config(RADIOLIB_SX128X_PACKET_TYPE_GFSK);
+ // set module properties and perform initial setup
+ int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_GFSK);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
@@ -153,21 +110,6 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, ui
}
int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uint8_t dataShaping) {
- // set module properties
- this->mod->init();
- this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
- this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
- this->mod->spiConfig.statusPos = 1;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
- this->mod->spiConfig.stream = true;
- this->mod->spiConfig.parseStatusCb = SPIparseStatus;
- RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
-
// initialize BLE modulation variables
this->bitRateKbps = br;
this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
@@ -179,16 +121,8 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uin
this->crcGFSK = RADIOLIB_SX128X_BLE_CRC_3_BYTE;
this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
- // reset the module and verify startup
- int16_t state = reset();
- RADIOLIB_ASSERT(state);
-
- // set mode to standby
- state = standby();
- RADIOLIB_ASSERT(state);
-
- // configure settings not accessible by API
- state = config(RADIOLIB_SX128X_PACKET_TYPE_BLE);
+ // set module properties and perform initial setup
+ int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_BLE);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
@@ -211,21 +145,6 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uin
}
int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint16_t preambleLength, uint8_t dataShaping) {
- // set module properties
- this->mod->init();
- this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
- this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
- this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
- this->mod->spiConfig.statusPos = 1;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
- this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
- this->mod->spiConfig.stream = true;
- this->mod->spiConfig.parseStatusCb = SPIparseStatus;
- RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
-
// initialize FLRC modulation variables
this->bitRateKbps = br;
this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6;
@@ -239,16 +158,8 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint1
this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE;
this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF;
- // reset the module and verify startup
- int16_t state = reset();
- RADIOLIB_ASSERT(state);
-
- // set mode to standby
- state = standby();
- RADIOLIB_ASSERT(state);
-
- // configure settings not accessible by API
- state = config(RADIOLIB_SX128X_PACKET_TYPE_FLRC);
+ // set module properties and perform initial setup
+ int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_FLRC);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
@@ -313,7 +224,12 @@ int16_t SX128x::reset(bool verify) {
int16_t SX128x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
// check packet length
- if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
+ if(this->codingRateLoRa == RADIOLIB_SX128X_LORA_CR_4_8_LI && this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON) {
+ // Long Interleaver at CR 4/8 supports up to 253 bytes if CRC is enabled
+ if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH - 2) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+ } else if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
@@ -348,7 +264,7 @@ int16_t SX128x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
return(finishTransmit());
}
-int16_t SX128x::receive(uint8_t* data, size_t len) {
+int16_t SX128x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
// check active modem
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
@@ -360,21 +276,26 @@ int16_t SX128x::receive(uint8_t* data, size_t len) {
RADIOLIB_ASSERT(state);
// calculate timeout (1000% of expected time-on-air)
- RadioLibTime_t timeout = getTimeOnAir(len) * 10;
- RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
+ // for most other modules, it is 500%, however, the overall datarates of SX128x are higher
+ // so we use higher value for the default timeout
+ RadioLibTime_t timeoutInternal = timeout;
+ if(!timeoutInternal) {
+ timeoutInternal = getTimeOnAir(len) * 10;
+ }
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", (uint32_t)((timeout + 999) / 1000));
// start reception
- uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625);
+ uint32_t timeoutValue = (uint32_t)((float)timeoutInternal / 15.625f);
state = startReceive(timeoutValue);
RADIOLIB_ASSERT(state);
// wait for packet reception or timeout
bool softTimeout = false;
- RadioLibTime_t start = this->mod->hal->millis();
+ RadioLibTime_t start = this->mod->hal->micros();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
// safety check, the timeout should be done by the radio
- if(this->mod->hal->millis() - start > timeout) {
+ if(this->mod->hal->micros() - start > timeout) {
softTimeout = true;
break;
}
@@ -387,9 +308,8 @@ int16_t SX128x::receive(uint8_t* data, size_t len) {
}
// check whether this was a timeout or not
- if((getIrqStatus() & RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT) || softTimeout) {
- standby();
- clearIrqStatus();
+ if(softTimeout || (getIrqStatus() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
+ (void)finishReceive();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
@@ -461,7 +381,7 @@ int16_t SX128x::sleep(bool retainConfig) {
if(!retainConfig) {
sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH;
}
- int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SAVE_CONTEXT, 0, 1, false, false);
+ int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SAVE_CONTEXT, NULL, 0, false, false);
RADIOLIB_ASSERT(state);
state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false);
@@ -475,6 +395,10 @@ int16_t SX128x::standby() {
return(SX128x::standby(RADIOLIB_SX128X_STANDBY_RC));
}
+int16_t SX128x::standby(uint8_t mode) {
+ return(SX128x::standby(mode, true));
+}
+
int16_t SX128x::standby(uint8_t mode, bool wakeup) {
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_IDLE);
@@ -485,7 +409,7 @@ int16_t SX128x::standby(uint8_t mode, bool wakeup) {
(void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX128X_CMD_NOP, NULL, 0, false, false);
}
- uint8_t data[] = { mode };
+ const uint8_t data[] = { mode };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1));
}
@@ -513,70 +437,6 @@ void SX128x::clearPacketSentAction() {
this->clearDio1Action();
}
-int16_t SX128x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
- // suppress unused variable warning
- (void)addr;
-
- // check packet length
- if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
- return(RADIOLIB_ERR_PACKET_TOO_LONG);
- }
-
- // set packet Length
- int16_t state = RADIOLIB_ERR_NONE;
- uint8_t modem = getPacketType();
- if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
- state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcLoRa, this->invertIQEnabled);
- } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
- state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, len);
- } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
- state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
- } else {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
- RADIOLIB_ASSERT(state);
-
- // update output power
- state = setTxParams(this->power);
- RADIOLIB_ASSERT(state);
-
- // set buffer pointers
- state = setBufferBaseAddress();
- RADIOLIB_ASSERT(state);
-
- // write packet to buffer
- if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
- // first 2 bytes of BLE payload are PDU header
- state = writeBuffer(const_cast(data), len, 2);
- RADIOLIB_ASSERT(state);
- } else {
- state = writeBuffer(const_cast(data), len);
- RADIOLIB_ASSERT(state);
- }
-
- // set DIO mapping
- state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE);
- RADIOLIB_ASSERT(state);
-
- // clear interrupt flags
- state = clearIrqStatus();
- RADIOLIB_ASSERT(state);
-
- // set RF switch (if present)
- this->mod->setRfSwitchState(Module::MODE_TX);
-
- // start transmission
- state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE);
- RADIOLIB_ASSERT(state);
-
- // wait for BUSY to go low (= PA ramp up done)
- while(this->mod->hal->digitalRead(this->mod->getGpio())) {
- this->mod->hal->yield();
- }
-
- return(state);
-}
-
int16_t SX128x::finishTransmit() {
// clear interrupt flags
clearIrqStatus();
@@ -589,49 +449,6 @@ int16_t SX128x::startReceive() {
return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
}
-int16_t SX128x::startReceive(uint16_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) {
- // in implicit header mode, use the provided length if it is nonzero
- // otherwise we trust the user has previously set the payload length manually
- if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (len != 0)) {
- this->payloadLen = len;
- }
-
- // check active modem
- if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
- return(RADIOLIB_ERR_WRONG_MODEM);
- }
-
- // set DIO mapping
- if(timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) {
- irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
- }
-
- int16_t state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqMask));
- RADIOLIB_ASSERT(state);
-
- // set buffer pointers
- state = setBufferBaseAddress();
- RADIOLIB_ASSERT(state);
-
- // clear interrupt flags
- state = clearIrqStatus();
- RADIOLIB_ASSERT(state);
-
- // set implicit mode and expected len if applicable
- if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
- state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
- RADIOLIB_ASSERT(state);
- }
-
- // set RF switch (if present)
- this->mod->setRfSwitchState(Module::MODE_RX);
-
- // set mode to receive
- state = setRx(timeout);
-
- return(state);
-}
-
int16_t SX128x::readData(uint8_t* data, size_t len) {
// check active modem
if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
@@ -671,6 +488,15 @@ int16_t SX128x::readData(uint8_t* data, size_t len) {
return(state);
}
+int16_t SX128x::finishReceive() {
+ // set mode to standby to disable RF switch
+ int16_t state = standby();
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ return(clearIrqStatus());
+}
+
uint32_t SX128x::getIrqFlags() {
return((uint32_t)this->getIrqStatus());
}
@@ -745,7 +571,7 @@ int16_t SX128x::getChannelScanResult() {
}
int16_t SX128x::setFrequency(float freq) {
- RADIOLIB_CHECK_RANGE(freq, 2400.0, 2500.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ RADIOLIB_CHECK_RANGE(freq, 2400.0f, 2500.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
// calculate raw value
uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX128X_DIV_EXPONENT)) / RADIOLIB_SX128X_CRYSTAL_FREQ;
@@ -757,21 +583,21 @@ int16_t SX128x::setBandwidth(float bw) {
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
// check range for LoRa
- RADIOLIB_CHECK_RANGE(bw, 203.125, 1625.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(bw, 203.125f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
} else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
// check range for ranging
- RADIOLIB_CHECK_RANGE(bw, 406.25, 1625.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(bw, 406.25f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
} else {
return(RADIOLIB_ERR_WRONG_MODEM);
}
- if(fabsf(bw - 203.125) <= 0.001) {
+ if(fabsf(bw - 203.125f) <= 0.001f) {
this->bandwidth = RADIOLIB_SX128X_LORA_BW_203_125;
- } else if(fabsf(bw - 406.25) <= 0.001) {
+ } else if(fabsf(bw - 406.25f) <= 0.001f) {
this->bandwidth = RADIOLIB_SX128X_LORA_BW_406_25;
- } else if(fabsf(bw - 812.5) <= 0.001) {
+ } else if(fabsf(bw - 812.5f) <= 0.001f) {
this->bandwidth = RADIOLIB_SX128X_LORA_BW_812_50;
- } else if(fabsf(bw - 1625.0) <= 0.001) {
+ } else if(fabsf(bw - 1625.0f) <= 0.001f) {
this->bandwidth = RADIOLIB_SX128X_LORA_BW_1625_00;
} else {
return(RADIOLIB_ERR_INVALID_BANDWIDTH);
@@ -800,7 +626,7 @@ int16_t SX128x::setSpreadingFactor(uint8_t sf) {
int16_t state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa);
RADIOLIB_ASSERT(state);
- // update mystery register in LoRa mode - SX1280 datasheet v3.0 section 13.4.1
+ // update mystery register in LoRa mode - SX1280 datasheet rev 3.2 section 14.4.1
if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
uint8_t data = 0;
if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_5) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_6)) {
@@ -811,6 +637,15 @@ int16_t SX128x::setSpreadingFactor(uint8_t sf) {
data = 0x32;
}
state = SX128x::writeRegister(RADIOLIB_SX128X_REG_LORA_SF_CONFIG, &data, 1);
+ RADIOLIB_ASSERT(state);
+
+ // this register must also be updated for some reason
+ state = SX128x::readRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1);
+ RADIOLIB_ASSERT(state);
+
+ data |= 0x01;
+ state = SX128x::writeRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1);
+ RADIOLIB_ASSERT(state);
}
return(state);
@@ -822,11 +657,24 @@ int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) {
// LoRa/ranging
if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
- RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
// update modulation parameters
if(longInterleaving && (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
- this->codingRateLoRa = cr;
+ switch(cr) {
+ case 4:
+ this->codingRateLoRa = 0;
+ break;
+ case 5:
+ case 6:
+ this->codingRateLoRa = cr;
+ break;
+ case 8:
+ this->codingRateLoRa = cr - 1;
+ break;
+ default:
+ return(RADIOLIB_ERR_INVALID_CODING_RATE);
+ }
} else {
this->codingRateLoRa = cr - 4;
}
@@ -877,8 +725,7 @@ int16_t SX128x::setModem(ModemType_t modem) {
int16_t SX128x::getModem(ModemType_t* modem) {
RADIOLIB_ASSERT_PTR(modem);
- uint8_t packetType = getPacketType();
- switch(packetType) {
+ switch(getPacketType()) {
case(RADIOLIB_SX128X_PACKET_TYPE_LORA):
*modem = ModemType_t::RADIOLIB_MODEM_LORA;
return(RADIOLIB_ERR_NONE);
@@ -890,11 +737,12 @@ int16_t SX128x::getModem(ModemType_t* modem) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
-int16_t SX128x::setPreambleLength(uint32_t preambleLength) {
+int16_t SX128x::setPreambleLength(size_t preambleLength) {
uint8_t modem = getPacketType();
if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
// LoRa or ranging
- RADIOLIB_CHECK_RANGE(preambleLength, 2, 491520, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
+ // the actual limit is 491520, however, some platforms (notably AVR) limit size_t to 16 bits
+ RADIOLIB_CHECK_RANGE(preambleLength, 2, 65534, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
// check preamble length is even - no point even trying odd numbers
if(preambleLength % 2 != 0) {
@@ -932,17 +780,32 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) {
// update packet parameters
this->preambleLengthGFSK = ((preambleLength / 4) - 1) << 4;
- return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening));
+ return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
}
return(RADIOLIB_ERR_WRONG_MODEM);
}
-int16_t SX128x::setDataRate(DataRate_t dr) {
- // check active modem
- uint8_t modem = getPacketType();
- int16_t state = RADIOLIB_ERR_NONE;
- if (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
+int16_t SX128x::setDataRate(DataRate_t dr, ModemType_t modem) {
+ // get the current modem
+ ModemType_t currentModem;
+ int16_t state = this->getModem(¤tModem);
+ RADIOLIB_ASSERT(state);
+
+ // switch over if the requested modem is different
+ if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
+ state = this->standby();
+ RADIOLIB_ASSERT(state);
+ state = this->setModem(modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ if(modem == RADIOLIB_MODEM_NONE) {
+ modem = currentModem;
+ }
+
+ // select interpretation based on modem
+ if (modem == RADIOLIB_MODEM_LORA) {
state = this->setBandwidth(dr.lora.bandwidth);
RADIOLIB_ASSERT(state);
state = this->setSpreadingFactor(dr.lora.spreadingFactor);
@@ -954,6 +817,32 @@ int16_t SX128x::setDataRate(DataRate_t dr) {
return(state);
}
+int16_t SX128x::checkDataRate(DataRate_t dr, ModemType_t modem) {
+ int16_t state = RADIOLIB_ERR_UNKNOWN;
+
+ // retrieve modem if not supplied
+ if(modem == RADIOLIB_MODEM_NONE) {
+ state = this->getModem(&modem);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // select interpretation based on modem
+ if(modem == RADIOLIB_MODEM_FSK) {
+ RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 125.0f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 62.5f, 1000.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ return(RADIOLIB_ERR_NONE);
+
+ } else if(modem == RADIOLIB_MODEM_LORA) {
+ RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
+ RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 203.0f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
+ return(RADIOLIB_ERR_NONE);
+
+ }
+
+ return(state);
+}
+
int16_t SX128x::setBitRate(float br) {
// check active modem
uint8_t modem = getPacketType();
@@ -1020,26 +909,27 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
- if(freqDev < 0.0) {
- newFreqDev = 62.5;
+ if(freqDev < 0.0f) {
+ newFreqDev = 62.5f;
}
- RADIOLIB_CHECK_RANGE(newFreqDev, 62.5, 1000.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ RADIOLIB_CHECK_RANGE(newFreqDev, 62.5f, 1000.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
// override for the lowest possible frequency deviation - required for some PhysicalLayer protocols
- if(newFreqDev == 0.0) {
+ if(newFreqDev == 0.0f) {
this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35;
this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3;
return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
}
// update modulation parameters
- uint8_t modInd = (uint8_t)((8.0 * (newFreqDev / (float)this->bitRateKbps)) - 1.0);
+ uint8_t modInd = (uint8_t)((8.0f * (newFreqDev / (float)this->bitRateKbps)) - 1.0f);
if(modInd > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) {
return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
}
// update modulation parameters
+ this->frequencyDev = newFreqDev;
this->modIndex = modInd;
return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
}
@@ -1074,7 +964,7 @@ int16_t SX128x::setDataShaping(uint8_t sh) {
}
}
-int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) {
+int16_t SX128x::setSyncWord(uint8_t* sync, size_t len) {
// check active modem
uint8_t modem = getPacketType();
if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
@@ -1102,14 +992,8 @@ int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) {
this->syncWordLen = len;
}
- // reverse sync word byte order
- uint8_t syncWordBuff[] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
- for(uint8_t i = 0; i < len; i++) {
- syncWordBuff[4 - i] = syncWord[i];
- }
-
// update sync word
- int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4, syncWordBuff, 5);
+ int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 + (5 - len), sync, len);
RADIOLIB_ASSERT(state);
// update packet parameters
@@ -1119,7 +1003,7 @@ int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) {
/// \todo add support for multiple sync words
this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
}
- return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening));
+ return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
}
int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
@@ -1129,7 +1013,7 @@ int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
}
// update register
- uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
+ const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
return(writeRegister(RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB, data, 2));
}
@@ -1150,7 +1034,7 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) {
}
}
this->crcGFSK = len << 4;
- state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening);
+ state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType);
RADIOLIB_ASSERT(state);
// set initial CRC value
@@ -1177,7 +1061,7 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) {
RADIOLIB_ASSERT(state);
// set initial CRC value
- uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) };
+ const uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) };
state = writeRegister(RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB, data, 3);
return(state);
@@ -1212,7 +1096,7 @@ int16_t SX128x::setWhitening(bool enabled) {
}
if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
- return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening));
+ return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
}
return(setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening));
}
@@ -1224,7 +1108,7 @@ int16_t SX128x::setAccessAddress(uint32_t addr) {
}
// set the address
- uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
+ const uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
return(SX128x::writeRegister(RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4));
}
@@ -1293,7 +1177,7 @@ float SX128x::getRSSI() {
uint8_t rssiSync = packetStatus[0];
float rssiMeasured = -1.0 * rssiSync/2.0;
float snr = getSNR();
- if(snr <= 0.0) {
+ if(snr <= 0.0f) {
return(rssiMeasured - snr);
} else {
return(rssiMeasured);
@@ -1310,7 +1194,7 @@ float SX128x::getRSSI(bool packet) {
// get instantaneous RSSI value
uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU
this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RSSI_INST, data, 3);
- return ((float)data[0] / (-2.0));
+ return ((float)data[0] / (-2.0f));
} else {
return this->getRSSI();
}
@@ -1332,7 +1216,7 @@ float SX128x::getSNR() {
if(snr < 128) {
return(snr/4.0);
} else {
- return((snr - 256)/4.0);
+ return((snr - 256)/4.0f);
}
}
@@ -1361,9 +1245,9 @@ float SX128x::getFrequencyError() {
// frequency error is negative
efe |= (uint32_t) 0xFFF00000;
efe = ~efe + 1;
- error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz) * -1.0;
+ error = 1.55f * (float) efe / (1600.0f / this->bandwidthKhz) * -1.0f;
} else {
- error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz);
+ error = 1.55f * (float) efe / (1600.0f / this->bandwidthKhz);
}
return(error);
@@ -1389,15 +1273,35 @@ size_t SX128x::getPacketLength(bool update, uint8_t* offset) {
return((size_t)rxBufStatus[0]);
}
-RadioLibTime_t SX128x::getTimeOnAir(size_t len) {
- // check active modem
- uint8_t modem = getPacketType();
- if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
- // calculate number of symbols
- float N_symbol = 0;
- uint8_t sf = this->spreadingFactor >> 4;
- if(this->codingRateLoRa <= RADIOLIB_SX128X_LORA_CR_4_8) {
- // legacy coding rate - nice and simple
+int16_t SX128x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
+ int16_t state = RADIOLIB_ERR_NONE;
+
+ // check if in explicit header mode
+ if(this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_LORA_RX_CODING_RATE, 6, 4) >> 4; }
+ if(hasCRC) { *hasCRC = (this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_FEI_MSB, 4, 4) != 0); }
+
+ return(state);
+}
+
+int16_t SX128x::fixedPacketLengthMode(uint8_t len) {
+ return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED, len));
+}
+
+int16_t SX128x::variablePacketLengthMode(uint8_t maxLen) {
+ return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE, maxLen));
+}
+
+RadioLibTime_t SX128x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
+ switch(modem) {
+ case (ModemType_t::RADIOLIB_MODEM_LORA): {
+ // calculate number of symbols
+ float N_symbol = 0;
+ uint8_t sf = dr.lora.spreadingFactor;
+ float cr = (float)dr.lora.codingRate;
// get SF coefficients
float coeff1 = 0;
@@ -1422,37 +1326,84 @@ RadioLibTime_t SX128x::getTimeOnAir(size_t len) {
// get CRC length
int16_t N_bitCRC = 16;
- if(this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_OFF) {
+ if(!pc.lora.crcEnabled) {
N_bitCRC = 0;
}
// get header length
int16_t N_symbolHeader = 20;
- if(this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) {
+ if(pc.lora.implicitHeader) {
N_symbolHeader = 0;
}
// calculate number of LoRa preamble symbols
- uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4));
+ uint32_t N_symbolPreamble = pc.lora.preambleLength;
// calculate the number of symbols
- N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4);
-
- } else {
- // long interleaving - abandon hope all ye who enter here
- /// \todo implement this mess - SX1280 datasheet v3.0 section 7.4.4.2
+ N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * cr;
+ // get time-on-air in us
+ return(((uint32_t(1) << sf) / dr.lora.bandwidth) * N_symbol * 1000.0f);
}
+ case (ModemType_t::RADIOLIB_MODEM_FSK):
+ return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f)));
- // get time-on-air in us
- return(((uint32_t(1) << sf) / this->bandwidthKhz) * N_symbol * 1000.0);
+ default:
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+}
+RadioLibTime_t SX128x::getTimeOnAir(size_t len) {
+ // check active modem
+ uint8_t modem = getPacketType();
+ DataRate_t dr = {};
+ PacketConfig_t pc = {};
+
+ if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
+ uint8_t sf = this->spreadingFactor >> 4;
+ uint8_t cr = this->codingRateLoRa;
+ // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values
+ if (cr < 5) {
+ cr = cr + 4;
+ } else if (cr == 7) {
+ cr = cr + 1;
+ }
+
+ dr.lora.spreadingFactor = sf;
+ dr.lora.codingRate = cr;
+ dr.lora.bandwidth = this->bandwidthKhz;
+
+ uint16_t preambleLength = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4));
+
+ pc.lora.preambleLength = preambleLength;
+ pc.lora.implicitHeader = this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT;
+ pc.lora.crcEnabled = this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON;
+ pc.lora.ldrOptimize = false;
+
+ return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_LORA, dr, pc, len));
+ } else if (modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
+ dr.fsk.bitRate = (float)this->bitRateKbps;
+ dr.fsk.freqDev = this->frequencyDev;
+
+ pc.fsk.preambleLength = ((uint16_t)this->preambleLengthGFSK >> 2) + 4;
+ pc.fsk.syncWordLength = ((this->syncWordLen >> 1) + 1) * 8;
+ pc.fsk.crcLength = this->crcGFSK >> 4;
+
+ return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_FSK, dr, pc, len));
} else {
- return(((uint32_t)len * 8 * 1000) / this->bitRateKbps);
+ return(RADIOLIB_ERR_WRONG_MODEM);
}
}
+RadioLibTime_t SX128x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
+ // the timeout value is given in units of 15.625 microseconds
+ // the calling function should provide some extra width, as this number of units is truncated to integer
+ RadioLibTime_t timeout = timeoutUs / 15.625f;
+ return(timeout);
+}
+
int16_t SX128x::implicitHeader(size_t len) {
return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_IMPLICIT, len));
}
@@ -1493,6 +1444,132 @@ int16_t SX128x::invertIQ(bool enable) {
return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
}
+int16_t SX128x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
+ int16_t state;
+
+ switch(mode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ // in implicit header mode, use the provided length if it is nonzero
+ // otherwise we trust the user has previously set the payload length manually
+ if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (cfg->receive.len != 0)) {
+ this->payloadLen = cfg->receive.len;
+ }
+
+ // check active modem
+ if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set DIO mapping
+ if(cfg->receive.timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) {
+ cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
+ }
+
+ state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags), getIrqMapped(cfg->receive.irqMask));
+ RADIOLIB_ASSERT(state);
+
+ // set buffer pointers
+ state = setBufferBaseAddress();
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ state = clearIrqStatus();
+ RADIOLIB_ASSERT(state);
+
+ // set implicit mode and expected len if applicable
+ if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
+ state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
+ RADIOLIB_ASSERT(state);
+ }
+ // if max(uint32_t) is used, revert to RxContinuous
+ if(cfg->receive.timeout == 0xFFFFFFFF) {
+ cfg->receive.timeout = 0xFFFF;
+ }
+ this->rxTimeout = cfg->receive.timeout;
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ // check packet length
+ if(cfg->transmit.len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
+ return(RADIOLIB_ERR_PACKET_TOO_LONG);
+ }
+
+ // set packet Length
+ uint8_t modem = getPacketType();
+ if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
+ state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcLoRa, this->invertIQEnabled);
+ } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
+ state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType, cfg->transmit.len);
+ } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
+ state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
+ } else {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+ RADIOLIB_ASSERT(state);
+
+ // update output power
+ state = setTxParams(this->power);
+ RADIOLIB_ASSERT(state);
+
+ // set buffer pointers
+ state = setBufferBaseAddress();
+ RADIOLIB_ASSERT(state);
+
+ // write packet to buffer
+ if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
+ // first 2 bytes of BLE payload are PDU header
+ state = writeBuffer(cfg->transmit.data, cfg->transmit.len, 2);
+ RADIOLIB_ASSERT(state);
+ } else {
+ state = writeBuffer(cfg->transmit.data, cfg->transmit.len);
+ RADIOLIB_ASSERT(state);
+ }
+
+ // set DIO mapping
+ state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE);
+ RADIOLIB_ASSERT(state);
+
+ // clear interrupt flags
+ state = clearIrqStatus();
+ RADIOLIB_ASSERT(state);
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = mode;
+ return(state);
+}
+
+int16_t SX128x::launchMode() {
+ int16_t state;
+ switch(this->stagedMode) {
+ case(RADIOLIB_RADIO_MODE_RX): {
+ this->mod->setRfSwitchState(Module::MODE_RX);
+ state = setRx(this->rxTimeout);
+ RADIOLIB_ASSERT(state);
+ } break;
+
+ case(RADIOLIB_RADIO_MODE_TX): {
+ this->mod->setRfSwitchState(Module::MODE_TX);
+ state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE);
+ RADIOLIB_ASSERT(state);
+
+ // wait for BUSY to go low (= PA ramp up done)
+ while(this->mod->hal->digitalRead(this->mod->getGpio())) {
+ this->mod->hal->yield();
+ }
+ } break;
+
+ default:
+ return(RADIOLIB_ERR_UNSUPPORTED);
+ }
+
+ this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
+ return(state);
+}
+
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
void SX128x::setDirectAction(void (*func)(void)) {
// SX128x is unable to perform direct mode reception
@@ -1511,13 +1588,40 @@ Module* SX128x::getMod() {
return(this->mod);
}
+int16_t SX128x::modSetup(uint8_t modem) {
+ // set module properties
+ this->mod->init();
+ this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
+ this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
+ this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
+ this->mod->spiConfig.statusPos = 1;
+ this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
+ this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
+ this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
+ this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
+ this->mod->spiConfig.stream = true;
+ this->mod->spiConfig.parseStatusCb = SPIparseStatus;
+
+ // find the chip - this will also reset the module and verify the module
+ if(!SX128x::findChip(this->chipType)) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("No SX128x found!");
+ this->mod->term();
+ return(RADIOLIB_ERR_CHIP_NOT_FOUND);
+ }
+ RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
+
+ // configure settings not accessible by API
+ return(config(modem));
+}
+
uint8_t SX128x::getStatus() {
uint8_t data = 0;
this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 0);
return(data);
}
-int16_t SX128x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
+int16_t SX128x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) {
this->mod->SPIwriteRegisterBurst(addr, data, numBytes);
return(RADIOLIB_ERR_NONE);
}
@@ -1531,23 +1635,23 @@ int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
return(state);
}
-int16_t SX128x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
- uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset };
+int16_t SX128x::writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset) {
+ const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset };
return(this->mod->SPIwriteStream(cmd, 2, data, numBytes));
}
int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
- uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, offset };
+ const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, offset };
return(this->mod->SPIreadStream(cmd, 2, data, numBytes));
}
int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) {
- uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
+ const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX, data, 3));
}
int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) {
- uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
+ const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3));
}
@@ -1567,42 +1671,42 @@ uint8_t SX128x::getPacketType() {
}
int16_t SX128x::setRfFrequency(uint32_t frf) {
- uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) };
+ const uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3));
}
int16_t SX128x::setTxParams(uint8_t pwr, uint8_t rampTime) {
- uint8_t data[] = { pwr, rampTime };
+ const uint8_t data[] = { pwr, rampTime };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2));
}
int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
- uint8_t data[] = { txBaseAddress, rxBaseAddress };
+ const uint8_t data[] = { txBaseAddress, rxBaseAddress };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2));
}
int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) {
- uint8_t data[] = { modParam1, modParam2, modParam3 };
+ const uint8_t data[] = { modParam1, modParam2, modParam3 };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3));
}
-int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen, uint8_t hdrType) {
- uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten };
+int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t hdrType, uint8_t payLen) {
+ const uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
}
int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten) {
- uint8_t data[] = { connState, crcLen, bleTest, whiten, 0x00, 0x00, 0x00 };
+ const uint8_t data[] = { connState, crcLen, bleTest, whiten, 0x00, 0x00, 0x00 };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
}
int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ) {
- uint8_t data[] = { preambleLen, hdrType, payLen, crc, invIQ, 0x00, 0x00 };
+ const uint8_t data[] = { preambleLen, hdrType, payLen, crc, invIQ, 0x00, 0x00 };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
}
int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
- uint8_t data[] = { (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
+ const uint8_t data[] = { (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
(uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF),
(uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF),
(uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) };
@@ -1616,20 +1720,36 @@ uint16_t SX128x::getIrqStatus() {
}
int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) {
- uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) };
+ const uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2));
}
int16_t SX128x::setRangingRole(uint8_t role) {
- uint8_t data[] = { role };
+ const uint8_t data[] = { role };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1));
}
int16_t SX128x::setPacketType(uint8_t type) {
- uint8_t data[] = { type };
+ const uint8_t data[] = { type };
return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1));
}
+int16_t SX128x::setPacketMode(uint8_t mode, uint8_t len) {
+ // check active modem
+ uint8_t modem = getPacketType();
+ if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
+ return(RADIOLIB_ERR_WRONG_MODEM);
+ }
+
+ // set requested packet mode
+ int16_t state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, mode, len);
+ RADIOLIB_ASSERT(state);
+
+ // update cached value
+ this->packetType = mode;
+ return(state);
+}
+
int16_t SX128x::setHeaderType(uint8_t hdrType, size_t len) {
// check active modem
uint8_t modem = getPacketType();
@@ -1680,4 +1800,35 @@ int16_t SX128x::SPIparseStatus(uint8_t in) {
return(RADIOLIB_ERR_NONE);
}
+bool SX128x::findChip(const char* verStr) {
+ uint8_t i = 0;
+ bool flagFound = false;
+ while((i < 10) && !flagFound) {
+ // reset the module
+ reset(true);
+
+ // read the version string
+ char version[16] = { 0 };
+ this->mod->SPIreadRegisterBurst(RADIOLIB_SX128X_REG_VERSION_STRING, 16, reinterpret_cast(version));
+
+ // check version register
+ if(strncmp(verStr, version, 6) == 0) {
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX128x: RADIOLIB_SX128X_REG_VERSION_STRING:");
+ RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING);
+ RADIOLIB_DEBUG_BASIC_PRINTLN();
+ flagFound = true;
+ } else {
+ #if RADIOLIB_DEBUG_BASIC
+ RADIOLIB_DEBUG_BASIC_PRINTLN("SX128x not found! (%d of 10 tries) RADIOLIB_SX128X_REG_VERSION_STRING:", i + 1);
+ RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr);
+ #endif
+ this->mod->hal->delay(10);
+ i++;
+ }
+ }
+
+ return(flagFound);
+}
+
#endif
diff --git a/lib/RadioLib/src/modules/SX128x/SX128x.h b/lib/RadioLib/src/modules/SX128x/SX128x.h
index ae1d468..2e968aa 100644
--- a/lib/RadioLib/src/modules/SX128x/SX128x.h
+++ b/lib/RadioLib/src/modules/SX128x/SX128x.h
@@ -12,7 +12,7 @@
// SX128X physical layer properties
#define RADIOLIB_SX128X_FREQUENCY_STEP_SIZE 198.3642578
#define RADIOLIB_SX128X_MAX_PACKET_LENGTH 255
-#define RADIOLIB_SX128X_CRYSTAL_FREQ 52.0
+#define RADIOLIB_SX128X_CRYSTAL_FREQ 52.0f
#define RADIOLIB_SX128X_DIV_EXPONENT 18
// SX128X SPI commands
@@ -57,6 +57,7 @@
#define RADIOLIB_SX128X_CMD_SET_ADVANCED_RANGING 0x9A
// SX128X register map
+#define RADIOLIB_SX128X_REG_VERSION_STRING 0x01F0
#define RADIOLIB_SX128X_REG_GAIN_MODE 0x0891
#define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2 0x0895
#define RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING 0x089E
@@ -84,6 +85,7 @@
#define RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION 0x093C
#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB 0x0944
#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_LSB 0x0945
+#define RADIOLIB_SX128X_REG_LORA_RX_CODING_RATE 0x0950
#define RADIOLIB_SX128X_REG_RANGING_FILTER_RSSI_OFFSET 0x0953
#define RADIOLIB_SX128X_REG_FEI_MSB 0x0954
#define RADIOLIB_SX128X_REG_FEI_MID 0x0955
@@ -252,7 +254,7 @@
#define RADIOLIB_SX128X_LORA_CR_4_8 0x04 // 7 0 4/8
#define RADIOLIB_SX128X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaving
#define RADIOLIB_SX128X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaving
-#define RADIOLIB_SX128X_LORA_CR_4_7_LI 0x07 // 7 0 4/7, long interleaving
+#define RADIOLIB_SX128X_LORA_CR_4_8_LI 0x07 // 7 0 4/8, long interleaving
//RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS
#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF 0x00 // 7 0 GFSK/FLRC sync word used: none
@@ -354,6 +356,7 @@ class SX128x: public PhysicalLayer {
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
+ using PhysicalLayer::startReceive;
using PhysicalLayer::readData;
/*!
@@ -369,7 +372,8 @@ class SX128x: public PhysicalLayer {
\param freq Carrier frequency in MHz. Defaults to 2400.0 MHz.
\param bw LoRa bandwidth in kHz. Defaults to 812.5 kHz.
\param sf LoRa spreading factor. Defaults to 9.
- \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7).
+ \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding,
+ is undocumented and not recommended without your own FEC.
\param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX128X_SYNC_WORD_PRIVATE (0x12).
\param pwr Output power in dBm. Defaults to 10 dBm.
\param preambleLength LoRa preamble length in symbols. Defaults to 12 symbols.
@@ -432,11 +436,13 @@ class SX128x: public PhysicalLayer {
/*!
\brief Blocking binary receive method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
- \param data Binary data to be sent.
- \param len Number of bytes to send.
+ \param data Pointer to array to save the received binary data.
+ \param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+ \param timeout Reception timeout in microseconds. If set to 0,
+ timeout period will be calculated automatically based on the radio configuration.
\returns \ref status_codes
*/
- int16_t receive(uint8_t* data, size_t len) override;
+ int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override;
/*!
\brief Starts direct mode transmission.
@@ -486,6 +492,14 @@ class SX128x: public PhysicalLayer {
*/
int16_t standby() override;
+ /*!
+ \brief Sets the module to standby mode.
+ \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX128X_STANDBY_RC
+ (13 MHz RC oscillator) or RADIOLIB_SX128X_STANDBY_XOSC (52 MHz external crystal oscillator).
+ \returns \ref status_codes
+ */
+ int16_t standby(uint8_t mode) override;
+
/*!
\brief Sets the module to standby mode.
\param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX128X_STANDBY_RC
@@ -493,7 +507,7 @@ class SX128x: public PhysicalLayer {
\param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module.
\returns \ref status_codes
*/
- int16_t standby(uint8_t mode, bool wakeup = false);
+ int16_t standby(uint8_t mode, bool wakeup);
// interrupt methods
@@ -530,16 +544,6 @@ class SX128x: public PhysicalLayer {
*/
void clearPacketSentAction() override;
- /*!
- \brief Interrupt-driven binary transmit method.
- Overloads for string-based transmissions are implemented in PhysicalLayer.
- \param data Binary data to be sent.
- \param len Number of bytes to send.
- \param addr Address to send the data to. Unsupported, compatibility only.
- \returns \ref status_codes
- */
- int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override;
-
/*!
\brief Clean up after transmission is done.
\returns \ref status_codes
@@ -554,20 +558,6 @@ class SX128x: public PhysicalLayer {
*/
int16_t startReceive() override;
- /*!
- \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received.
- \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to
- RADIOLIB_SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode),
- set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode).
- If timeout other than infinite is set, signal will be generated on DIO1.
-
- \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error.
- \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done.
- \param len Only for PhysicalLayer compatibility, not used.
- \returns \ref status_codes
- */
- int16_t startReceive(uint16_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0);
-
/*!
\brief Reads the current IRQ status.
\returns IRQ status bits
@@ -583,6 +573,12 @@ class SX128x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t readData(uint8_t* data, size_t len) override;
+
+ /*!
+ \brief Clean up after reception is done.
+ \returns \ref status_codes
+ */
+ int16_t finishReceive() override;
/*!
\brief Read currently active IRQ flags.
@@ -649,7 +645,8 @@ class SX128x: public PhysicalLayer {
int16_t setSpreadingFactor(uint8_t sf);
/*!
- \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8.
+ \brief Sets LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4
+ means no coding, is undocumented and not recommended without your own FEC.
\param cr LoRa coding rate denominator to be set.
\param longInterleaving Whether to enable long interleaving mode. Not available for coding rate 4/7,
defaults to false.
@@ -692,14 +689,23 @@ class SX128x: public PhysicalLayer {
\param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK/BLE/FLRC).
\returns \ref status_codes
*/
- int16_t setPreambleLength(uint32_t preambleLength);
+ int16_t setPreambleLength(size_t preambleLength) override;
/*!
\brief Set data rate.
\param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa).
\returns \ref status_codes
*/
- int16_t setDataRate(DataRate_t dr) override;
+ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
+
+ /*!
+ \brief Check the data rate can be configured by this module.
+ \param dr Data rate struct.
+ \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS).
+ Defaults to currently active modem if not supplied.
+ \returns \ref status_codes
+ */
+ int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override;
/*!
\brief Sets FSK or FLRC bit rate. Allowed values are 125, 250, 400, 500, 800, 1000,
@@ -727,11 +733,11 @@ class SX128x: public PhysicalLayer {
/*!
\brief Sets FSK/FLRC sync word in the form of array of up to 5 bytes (FSK). For FLRC modem,
the sync word must be exactly 4 bytes long
- \param syncWord Sync word to be set.
+ \param sync Sync word to be set.
\param len Sync word length in bytes.
\returns \ref status_codes
*/
- int16_t setSyncWord(const uint8_t* syncWord, uint8_t len);
+ int16_t setSyncWord(uint8_t* sync, size_t len) override;
/*!
\brief Sets LoRa sync word.
@@ -779,13 +785,13 @@ class SX128x: public PhysicalLayer {
int16_t setGainControl(uint8_t gain = 0);
/*!
- \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet.
+ \brief Gets RSSI (Received Signal Strength Indicator) of the last received packet.
\returns RSSI of the last received packet in dBm.
*/
float getRSSI() override;
/*!
- \brief Gets RSSI (Recorded Signal Strength Indicator).
+ \brief Gets RSSI (Received Signal Strength Indicator).
\param packet Whether to read last packet RSSI, or the current value.
\returns RSSI value in dBm.
*/
@@ -818,6 +824,38 @@ class SX128x: public PhysicalLayer {
*/
size_t getPacketLength(bool update, uint8_t* offset);
+ /*!
+ \brief Get LoRa header information from last received packet. Only valid in explicit header mode.
+ \param cr Pointer to variable to store the coding rate.
+ \param hasCRC Pointer to variable to store the CRC status.
+ \returns \ref status_codes
+ */
+ int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC);
+
+ /*!
+ \brief Set modem in fixed packet length mode. Available in GFSK and FLRC modes only.
+ \param len Packet length.
+ \returns \ref status_codes
+ */
+ int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX128X_MAX_PACKET_LENGTH);
+
+ /*!
+ \brief Set modem in variable packet length mode. Available in GFSK and FLRC modes only.
+ \param maxLen Maximum packet length.
+ \returns \ref status_codes
+ */
+ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX128X_MAX_PACKET_LENGTH);
+
+ /*!
+ \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size.
+ \param modem Modem type.
+ \param dr Data rate.
+ \param pc Packet config.
+ \param len Payload length in bytes.
+ \returns Expected time-on-air in microseconds.
+ */
+ RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override;
+
/*!
\brief Get expected time-on-air for a given size of payload.
\param len Payload length in bytes.
@@ -825,6 +863,13 @@ class SX128x: public PhysicalLayer {
*/
RadioLibTime_t getTimeOnAir(size_t len) override;
+ /*!
+ \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
+ \param timeoutUs Timeout in microseconds to listen for
+ \returns Timeout value in a unit that is specific for the used module
+ */
+ RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override;
+
/*!
\brief Set implicit header mode for future reception/transmission.
\returns \ref status_codes
@@ -859,10 +904,16 @@ class SX128x: public PhysicalLayer {
/*!
\brief Enable/disable inversion of the I and Q signals
- \param enable QI inversion enabled (true) or disabled (false);
+ \param enable IQ inversion enabled (true) or disabled (false);
\returns \ref status_codes
*/
int16_t invertIQ(bool enable) override;
+
+ /*! \copydoc PhysicalLayer::stageMode */
+ int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override;
+
+ /*! \copydoc PhysicalLayer::launchMode */
+ int16_t launchMode() override;
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
/*!
@@ -881,7 +932,10 @@ class SX128x: public PhysicalLayer {
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
+ const char* chipType = NULL;
+
Module* getMod() override;
+ int16_t modSetup(uint8_t modem);
// cached LoRa parameters
float bandwidthKhz = 0;
@@ -890,9 +944,9 @@ class SX128x: public PhysicalLayer {
// SX128x SPI command implementations
uint8_t getStatus();
- int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
+ int16_t writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes);
int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
- int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
+ int16_t writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
int16_t readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
int16_t setTx(uint16_t periodBaseCount = RADIOLIB_SX128X_TX_TIMEOUT_NONE, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US);
int16_t setRx(uint16_t periodBaseCount, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US);
@@ -902,7 +956,7 @@ class SX128x: public PhysicalLayer {
int16_t setTxParams(uint8_t pwr, uint8_t rampTime = RADIOLIB_SX128X_PA_RAMP_10_US);
int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00);
int16_t setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3);
- int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen = 0xFF, uint8_t hdrType = RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE);
+ int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t hdrType, uint8_t payLen = 0xFF);
int16_t setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten);
int16_t setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD);
int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX128X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX128X_IRQ_NONE);
@@ -910,6 +964,9 @@ class SX128x: public PhysicalLayer {
int16_t setRangingRole(uint8_t role);
int16_t setPacketType(uint8_t type);
+ // protected so that it can be accessed from SX1280 class during reinit after ranging is complete
+ int16_t config(uint8_t modem);
+
#if !RADIOLIB_GODMODE
private:
#endif
@@ -920,15 +977,17 @@ class SX128x: public PhysicalLayer {
// common parameters
uint8_t power = 0;
+ uint32_t rxTimeout = 0;
// cached LoRa parameters
uint8_t invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD;
// cached GFSK parameters
- float modIndexReal = 0;
+ float modIndexReal = 0, frequencyDev = 0;
uint16_t bitRateKbps = 0;
uint8_t bitRate = 0, modIndex = 0, shaping = 0;
uint8_t preambleLengthGFSK = 0, syncWordLen = 0, syncWordMatch = 0, crcGFSK = 0, whitening = 0;
+ uint8_t packetType = RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE;
// cached FLRC parameters
uint8_t codingRateFLRC = 0;
@@ -936,7 +995,8 @@ class SX128x: public PhysicalLayer {
// cached BLE parameters
uint8_t connectionState = 0, crcBLE = 0, bleTestPayload = 0;
- int16_t config(uint8_t modem);
+ bool findChip(const char* verStr);
+ int16_t setPacketMode(uint8_t mode, uint8_t len);
int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF);
};
diff --git a/lib/RadioLib/src/modules/Si443x/Si4430.cpp b/lib/RadioLib/src/modules/Si443x/Si4430.cpp
index 7f9ed5f..6470f5e 100644
--- a/lib/RadioLib/src/modules/Si443x/Si4430.cpp
+++ b/lib/RadioLib/src/modules/Si443x/Si4430.cpp
@@ -22,7 +22,7 @@ int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t po
}
int16_t Si4430::setFrequency(float freq) {
- RADIOLIB_CHECK_RANGE(freq, 900.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ RADIOLIB_CHECK_RANGE(freq, 900.0f, 960.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
// set frequency
return(Si443x::setFrequencyRaw(freq));
diff --git a/lib/RadioLib/src/modules/Si443x/Si4430.h b/lib/RadioLib/src/modules/Si443x/Si4430.h
index 2d212e0..e792368 100644
--- a/lib/RadioLib/src/modules/Si443x/Si4430.h
+++ b/lib/RadioLib/src/modules/Si443x/Si4430.h
@@ -35,7 +35,7 @@ class Si4430: public Si4432 {
\param preambleLen Preamble Length in bits. Defaults to 16 bits.
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16);
+ int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16) override;
// configuration methods
diff --git a/lib/RadioLib/src/modules/Si443x/Si4431.h b/lib/RadioLib/src/modules/Si443x/Si4431.h
index a8939ea..9eddc26 100644
--- a/lib/RadioLib/src/modules/Si443x/Si4431.h
+++ b/lib/RadioLib/src/modules/Si443x/Si4431.h
@@ -35,7 +35,7 @@ class Si4431: public Si4432 {
\param preambleLen Preamble Length in bits. Defaults to 16 bits.
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16);
+ int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16) override;
// configuration methods
diff --git a/lib/RadioLib/src/modules/Si443x/Si4432.cpp b/lib/RadioLib/src/modules/Si443x/Si4432.cpp
index 5669086..1725bb4 100644
--- a/lib/RadioLib/src/modules/Si443x/Si4432.cpp
+++ b/lib/RadioLib/src/modules/Si443x/Si4432.cpp
@@ -22,7 +22,7 @@ int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t po
}
int16_t Si4432::setFrequency(float freq) {
- RADIOLIB_CHECK_RANGE(freq, 240.0, 930.0, RADIOLIB_ERR_INVALID_FREQUENCY);
+ RADIOLIB_CHECK_RANGE(freq, 240.0f, 930.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
// set frequency
return(Si443x::setFrequencyRaw(freq));
diff --git a/lib/RadioLib/src/modules/Si443x/Si4432.h b/lib/RadioLib/src/modules/Si443x/Si4432.h
index f3ac066..8bfe310 100644
--- a/lib/RadioLib/src/modules/Si443x/Si4432.h
+++ b/lib/RadioLib/src/modules/Si443x/Si4432.h
@@ -35,7 +35,7 @@ class Si4432: public Si443x {
\param preambleLen Preamble Length in bits. Defaults to 16 bits.
\returns \ref status_codes
*/
- int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16);
+ virtual int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16);
// configuration methods
diff --git a/lib/RadioLib/src/modules/Si443x/Si443x.cpp b/lib/RadioLib/src/modules/Si443x/Si443x.cpp
index 4db2ffc..4d2e866 100644
--- a/lib/RadioLib/src/modules/Si443x/Si443x.cpp
+++ b/lib/RadioLib/src/modules/Si443x/Si443x.cpp
@@ -2,7 +2,9 @@
#include
#if !RADIOLIB_EXCLUDE_SI443X
-Si443x::Si443x(Module* mod) : PhysicalLayer(RADIOLIB_SI443X_FREQUENCY_STEP_SIZE, RADIOLIB_SI443X_MAX_PACKET_LENGTH) {
+Si443x::Si443x(Module* mod) : PhysicalLayer() {
+ this->freqStep = RADIOLIB_SI443X_FREQUENCY_STEP_SIZE;
+ this->maxPacketLength = RADIOLIB_SI443X_MAX_PACKET_LENGTH;
this->mod = mod;
}
@@ -26,7 +28,7 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen)
this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_SOFTWARE_RESET);
// clear POR interrupt
- clearIRQFlags();
+ clearIrqStatus();
// configure settings not accessible by API
int16_t state = config();
@@ -52,10 +54,13 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen)
state = packetMode();
RADIOLIB_ASSERT(state);
- state = setDataShaping(0);
+ state = setDataShaping(RADIOLIB_SHAPING_NONE);
RADIOLIB_ASSERT(state);
- state = setEncoding(0);
+ state = setEncoding(RADIOLIB_ENCODING_NRZ);
+ RADIOLIB_ASSERT(state);
+
+ state = setCRC(true);
RADIOLIB_ASSERT(state);
state = variablePacketLengthMode();
@@ -92,9 +97,12 @@ int16_t Si443x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
return(finishTransmit());
}
-int16_t Si443x::receive(uint8_t* data, size_t len) {
- // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate)
- RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0);
+int16_t Si443x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
+ RadioLibTime_t timeoutInternal = timeout;
+ if(!timeoutInternal) {
+ // calculate timeout (500 ms + 400 full max-length packets at current bit rate)
+ timeoutInternal = 500 + (1.0f/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0f);
+ }
// start reception
int16_t state = startReceive();
@@ -103,9 +111,8 @@ int16_t Si443x::receive(uint8_t* data, size_t len) {
// wait for packet reception or timeout
RadioLibTime_t start = this->mod->hal->millis();
while(this->mod->hal->digitalRead(this->mod->getIrq())) {
- if(this->mod->hal->millis() - start > timeout) {
- standby();
- clearIRQFlags();
+ if(this->mod->hal->millis() - start > timeoutInternal) {
+ (void)finishReceive();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
}
@@ -153,7 +160,7 @@ int16_t Si443x::transmitDirect(uint32_t frf) {
// check high/low band
uint8_t bandSelect = RADIOLIB_SI443X_BAND_SELECT_LOW;
uint8_t freqBand = (newFreq / 10) - 24;
- if(newFreq >= 480.0) {
+ if(newFreq >= 480.0f) {
bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH;
freqBand = (newFreq / 20) - 24;
}
@@ -241,7 +248,7 @@ int16_t Si443x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_CLEAR, 0, 0);
// clear interrupt flags
- clearIRQFlags();
+ clearIrqStatus();
// set packet length
if (this->packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF) {
@@ -269,7 +276,7 @@ int16_t Si443x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
int16_t Si443x::finishTransmit() {
// clear interrupt flags
- clearIRQFlags();
+ clearIrqStatus();
// set mode to standby to disable transmitter/RF switch
return(standby());
@@ -285,13 +292,14 @@ int16_t Si443x::startReceive() {
this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_CLEAR, 1, 1);
// clear interrupt flags
- clearIRQFlags();
+ clearIrqStatus();
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_RX);
// set interrupt mapping
- this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED);
+ uint8_t irq = this->crcEnabled ? (RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED) : RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED;
+ this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, irq);
this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00);
// set mode to receive
@@ -309,8 +317,15 @@ int16_t Si443x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMa
}
int16_t Si443x::readData(uint8_t* data, size_t len) {
- // clear interrupt flags
- clearIRQFlags();
+ // read interrupt flags
+ uint32_t irq = getIrqFlags();
+
+ // check integrity CRC
+ // Si443x does not have the option to keep the data after CRC failed
+ // reading the FIFO will just repeat the first byte (see https://github.com/jgromes/RadioLib/issues/1430)
+ if(irq & RADIOLIB_SI443X_CRC_ERROR_INTERRUPT) {
+ return(RADIOLIB_ERR_CRC_MISMATCH);
+ }
// get packet length
size_t length = getPacketLength();
@@ -332,30 +347,32 @@ int16_t Si443x::readData(uint8_t* data, size_t len) {
// clear internal flag so getPacketLength can return the new packet length
this->packetLengthQueried = false;
- // set mode to standby
+ return(finishReceive());
+}
+
+int16_t Si443x::finishReceive() {
+ // set mode to standby to disable RF switch
int16_t state = standby();
- RADIOLIB_ASSERT(state);
-
+
// clear interrupt flags
- clearIRQFlags();
-
- return(RADIOLIB_ERR_NONE);
+ clearIrqStatus();
+ return(state);
}
int16_t Si443x::setBitRate(float br) {
- RADIOLIB_CHECK_RANGE(br, 0.123, 256.0, RADIOLIB_ERR_INVALID_BIT_RATE);
+ RADIOLIB_CHECK_RANGE(br, 0.123f, 256.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
// check high data rate
uint8_t dataRateMode = RADIOLIB_SI443X_LOW_DATA_RATE_MODE;
uint8_t exp = 21;
- if(br >= 30.0) {
+ if(br >= 30.0f) {
// bit rate above 30 kbps
dataRateMode = RADIOLIB_SI443X_HIGH_DATA_RATE_MODE;
exp = 16;
}
// calculate raw data rate value
- uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0;
+ uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0f;
// update registers
int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5);
@@ -376,14 +393,14 @@ int16_t Si443x::setBitRate(float br) {
int16_t Si443x::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
- if(freqDev < 0.0) {
- newFreqDev = 0.625;
+ if(freqDev < 0.0f) {
+ newFreqDev = 0.625f;
}
- RADIOLIB_CHECK_RANGE(newFreqDev, 0.625, 320.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
+ RADIOLIB_CHECK_RANGE(newFreqDev, 0.625f, 320.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
// calculate raw frequency deviation value
- uint16_t fdev = (uint16_t)(newFreqDev / 0.625);
+ uint16_t fdev = (uint16_t)(newFreqDev / 0.625f);
// update registers
int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2);
@@ -397,7 +414,7 @@ int16_t Si443x::setFrequencyDeviation(float freqDev) {
}
int16_t Si443x::setRxBandwidth(float rxBw) {
- RADIOLIB_CHECK_RANGE(rxBw, 2.6, 620.7, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
+ RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 620.7f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
// decide which approximation to use for decimation rate and filter tap calculation
uint8_t bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_OFF;
@@ -405,84 +422,84 @@ int16_t Si443x::setRxBandwidth(float rxBw) {
uint8_t filterSet = RADIOLIB_SI443X_IF_FILTER_COEFF_SET;
// this is the "well-behaved" section - can be linearly approximated
- if((rxBw >= 2.6) && (rxBw <= 4.5)) {
+ if((rxBw >= 2.6f) && (rxBw <= 4.5f)) {
decRate = 5;
- filterSet = ((rxBw - 2.1429)/0.3250 + 0.5);
- } else if((rxBw > 4.5) && (rxBw <= 8.8)) {
+ filterSet = ((rxBw - 2.1429f)/0.3250f + 0.5f);
+ } else if((rxBw > 4.5f) && (rxBw <= 8.8f)) {
decRate = 4;
- filterSet = ((rxBw - 3.9857)/0.6643 + 0.5);
- } else if((rxBw > 8.8) && (rxBw <= 17.5)) {
+ filterSet = ((rxBw - 3.9857f)/0.6643f + 0.5f);
+ } else if((rxBw > 8.8f) && (rxBw <= 17.5f)) {
decRate = 3;
- filterSet = ((rxBw - 7.6714)/1.3536 + 0.5);
- } else if((rxBw > 17.5) && (rxBw <= 34.7)) {
+ filterSet = ((rxBw - 7.6714f)/1.3536f + 0.5f);
+ } else if((rxBw > 17.5f) && (rxBw <= 34.7f)) {
decRate = 2;
- filterSet = ((rxBw - 15.2000)/2.6893 + 0.5);
- } else if((rxBw > 34.7) && (rxBw <= 69.2)) {
+ filterSet = ((rxBw - 15.2000f)/2.6893f + 0.5f);
+ } else if((rxBw > 34.7f) && (rxBw <= 69.2f)) {
decRate = 1;
- filterSet = ((rxBw - 30.2430)/5.3679 + 0.5);
- } else if((rxBw > 69.2) && (rxBw <= 137.9)) {
+ filterSet = ((rxBw - 30.2430f)/5.3679f + 0.5f);
+ } else if((rxBw > 69.2f) && (rxBw <= 137.9f)) {
decRate = 0;
- filterSet = ((rxBw - 60.286)/10.7000 + 0.5);
+ filterSet = ((rxBw - 60.286f)/10.7000f + 0.5f);
// this is the "Lord help thee who tread 'ere" section - no way to approximate this mess
/// \todo float tolerance equality as macro?
- } else if(fabsf(rxBw - 142.8) <= 0.001) {
+ } else if(fabsf(rxBw - 142.8f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 1;
filterSet = 4;
- } else if(fabsf(rxBw - 167.8) <= 0.001) {
+ } else if(fabsf(rxBw - 167.8f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 1;
filterSet = 5;
- } else if(fabsf(rxBw - 181.1) <= 0.001) {
+ } else if(fabsf(rxBw - 181.1f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 1;
filterSet = 6;
- } else if(fabsf(rxBw - 191.5) <= 0.001) {
+ } else if(fabsf(rxBw - 191.5f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 15;
- } else if(fabsf(rxBw - 225.1) <= 0.001) {
+ } else if(fabsf(rxBw - 225.1f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 1;
- } else if(fabsf(rxBw - 248.8) <= 0.001) {
+ } else if(fabsf(rxBw - 248.8f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 2;
- } else if(fabsf(rxBw - 269.3) <= 0.001) {
+ } else if(fabsf(rxBw - 269.3f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 3;
- } else if(fabsf(rxBw - 284.8) <= 0.001) {
+ } else if(fabsf(rxBw - 284.8f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 4;
- } else if(fabsf(rxBw -335.5) <= 0.001) {
+ } else if(fabsf(rxBw -335.5f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 8;
- } else if(fabsf(rxBw - 391.8) <= 0.001) {
+ } else if(fabsf(rxBw - 391.8f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 9;
- } else if(fabsf(rxBw - 420.2) <= 0.001) {
+ } else if(fabsf(rxBw - 420.2f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 10;
- } else if(fabsf(rxBw - 468.4) <= 0.001) {
+ } else if(fabsf(rxBw - 468.4f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 11;
- } else if(fabsf(rxBw - 518.8) <= 0.001) {
+ } else if(fabsf(rxBw - 518.8f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 12;
- } else if(fabsf(rxBw - 577.0) <= 0.001) {
+ } else if(fabsf(rxBw - 577.0f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 13;
- } else if(fabsf(rxBw - 620.7) <= 0.001) {
+ } else if(fabsf(rxBw - 620.7f) <= 0.001f) {
bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 14;
@@ -520,7 +537,7 @@ int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) {
return(state);
}
-int16_t Si443x::setPreambleLength(uint8_t preambleLen) {
+int16_t Si443x::setPreambleLength(size_t preambleLen) {
// Si443x configures preamble length in 4-bit nibbles
if(preambleLen % 4 != 0) {
return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
@@ -633,6 +650,25 @@ int16_t Si443x::variablePacketLengthMode(uint8_t maxLen) {
return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF, maxLen));
}
+uint32_t Si443x::getIrqFlags() {
+ uint8_t data[] = { 0x00, 0x00 };
+ this->mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, data);
+ return(((uint32_t)(data[0]) << 8) | data[1]);
+}
+
+int16_t Si443x::clearIrqFlags(uint32_t irq) {
+ (void)irq;
+ (void)getIrqFlags();
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t Si443x::setCRC(bool enable, bool mode) {
+ this->crcEnabled = enable;
+ uint8_t crcEn = enable ? RADIOLIB_SI443X_CRC_ON : RADIOLIB_SI443X_CRC_OFF;
+ uint8_t crcCfg = mode ? RADIOLIB_SI443X_CRC_IBM_CRC16 : RADIOLIB_SI443X_CRC_CCITT;
+ return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_DATA_ACCESS_CONTROL, crcEn | crcCfg, 2, 0));
+}
+
Module* Si443x::getMod() {
return(this->mod);
}
@@ -647,7 +683,7 @@ int16_t Si443x::setFrequencyRaw(float newFreq) {
uint8_t freqBand = (newFreq / 10) - 24;
uint8_t afcLimiter = 80;
this->frequency = newFreq;
- if(newFreq >= 480.0) {
+ if(newFreq >= 480.0f) {
bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH;
freqBand = (newFreq / 20) - 24;
afcLimiter = 40;
@@ -705,9 +741,8 @@ bool Si443x::findChip() {
return(flagFound);
}
-void Si443x::clearIRQFlags() {
- uint8_t buff[2];
- this->mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, buff);
+void Si443x::clearIrqStatus() {
+ (void)getIrqFlags();
}
void Si443x::clearFIFO(size_t count) {
@@ -757,17 +792,17 @@ int16_t Si443x::updateClockRecovery() {
ndec = (uint16_t)1 << ndecExp;
} else {
ndecExp *= -1;
- ndec = 1.0/(float)((uint16_t)1 << ndecExp);
+ ndec = 1.0f/(float)((uint16_t)1 << ndecExp);
}
float rxOsr = ((float)(500 * (1 + 2*bypass))) / (ndec * this->bitRate * ((float)(1 + manch)));
uint32_t ncoOff = (this->bitRate * (1 + manch) * ((uint32_t)(1) << (20 + decRate))) / (500 * (1 + 2*bypass));
- uint16_t crGain = 2 + (((float)(65536.0 * (1 + manch)) * this->bitRate) / (rxOsr * (this->frequencyDev / 0.625)));
+ uint16_t crGain = 2 + (((float)(65536.0f * (1 + manch)) * this->bitRate) / (rxOsr * (this->frequencyDev / 0.625f)));
uint16_t rxOsr_fixed = (uint16_t)rxOsr;
// print that whole mess
- RADIOLIB_DEBUG_BASIC_PRINTLN("%X\n%X\n%X", bypass, decRate, manch);
- RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(rxOsr, 2);
- RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, (long unsigned int)ncoOff, (long unsigned int)ncoOff, crGain, crGain);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("%X %X %X", bypass, decRate, manch);
+ RADIOLIB_DEBUG_BASIC_PRINT_FLOAT((double)rxOsr, 2);
+ RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X" RADIOLIB_LINE_FEED "%lu\t%lX" RADIOLIB_LINE_FEED "%d\t%X", rxOsr_fixed, rxOsr_fixed, (long unsigned int)ncoOff, (long unsigned int)ncoOff, crGain, crGain);
// update oversampling ratio
int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5);
diff --git a/lib/RadioLib/src/modules/Si443x/Si443x.h b/lib/RadioLib/src/modules/Si443x/Si443x.h
index c100b04..93bd9c9 100644
--- a/lib/RadioLib/src/modules/Si443x/Si443x.h
+++ b/lib/RadioLib/src/modules/Si443x/Si443x.h
@@ -128,19 +128,19 @@
#define RADIOLIB_SI443X_IDLE 0b00000000 // 1 0 idle
// RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1
-#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow
-#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 // 6 6 Tx FIFO almost full
-#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 // 5 5 Tx FIFO almost empty
-#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 // 4 4 Rx FIFO almost full
-#define RADIOLIB_SI443X_EXTERNAL_INTERRUPT 0b00001000 // 3 3 external interrupt occurred on GPIOx
-#define RADIOLIB_SI443X_PACKET_SENT_INTERRUPT 0b00000100 // 2 2 packet transmission done
-#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 // 1 1 valid packet has been received
-#define RADIOLIB_SI443X_CRC_ERROR_INTERRUPT 0b00000001 // 0 0 CRC failed
+#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 << 8 // 7 7 Tx/Rx FIFO overflow or underflow
+#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 << 8 // 6 6 Tx FIFO almost full
+#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 << 8 // 5 5 Tx FIFO almost empty
+#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 << 8 // 4 4 Rx FIFO almost full
+#define RADIOLIB_SI443X_EXTERNAL_INTERRUPT 0b00001000 << 8 // 3 3 external interrupt occurred on GPIOx
+#define RADIOLIB_SI443X_PACKET_SENT_INTERRUPT 0b00000100 << 8 // 2 2 packet transmission done
+#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 << 8 // 1 1 valid packet has been received
+#define RADIOLIB_SI443X_CRC_ERROR_INTERRUPT 0b00000001 << 8 // 0 0 CRC failed
// RADIOLIB_SI443X_REG_INTERRUPT_STATUS_2
#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_INTERRUPT 0b10000000 // 7 7 sync word has been detected
-#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected
-#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected
+#define RADIOLIB_SI443X_VALID_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected
+#define RADIOLIB_SI443X_INVALID_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected
#define RADIOLIB_SI443X_RSSI_INTERRUPT 0b00010000 // 4 4 RSSI exceeded programmed threshold
#define RADIOLIB_SI443X_WAKEUP_TIMER_INTERRUPT 0b00001000 // 3 3 wake-up timer expired
#define RADIOLIB_SI443X_LOW_BATTERY_INTERRUPT 0b00000100 // 2 2 low battery detected
@@ -159,8 +159,8 @@
// RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2
#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_ENABLED 0b10000000 // 7 7 sync word interrupt enabled
-#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled
-#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled
+#define RADIOLIB_SI443X_VALID_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled
+#define RADIOLIB_SI443X_INVALID_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled
#define RADIOLIB_SI443X_RSSI_ENABLED 0b00010000 // 4 4 RSSI exceeded programmed threshold interrupt enabled
#define RADIOLIB_SI443X_WAKEUP_TIMER_ENABLED 0b00001000 // 3 3 wake-up timer interrupt enabled
#define RADIOLIB_SI443X_LOW_BATTERY_ENABLED 0b00000100 // 2 2 low battery interrupt enabled
@@ -598,9 +598,11 @@ class Si443x: public PhysicalLayer {
For overloads to receive Arduino String, see PhysicalLayer::receive.
\param data Pointer to array to save the received binary data.
\param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+ \param timeout Reception timeout in milliseconds. If set to 0,
+ timeout period will be calculated automatically based on the radio configuration.
\returns \ref status_codes
*/
- int16_t receive(uint8_t* data, size_t len) override;
+ int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override;
/*!
\brief Sets the module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode.
@@ -717,6 +719,12 @@ class Si443x: public PhysicalLayer {
*/
int16_t readData(uint8_t* data, size_t len) override;
+ /*!
+ \brief Clean up after reception is done.
+ \returns \ref status_codes
+ */
+ int16_t finishReceive() override;
+
// configuration methods
/*!
@@ -752,7 +760,7 @@ class Si443x: public PhysicalLayer {
\param preambleLen Preamble length to be set (in bits).
\returns \ref status_codes
*/
- int16_t setPreambleLength(uint8_t preambleLen);
+ int16_t setPreambleLength(size_t preambleLen) override;
/*!
\brief Query modem for the packet length of received payload.
@@ -810,18 +818,39 @@ class Si443x: public PhysicalLayer {
#endif
/*!
- \brief Set modem in fixed packet length mode.
- \param len Packet length.
- \returns \ref status_codes
- */
- int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SI443X_MAX_PACKET_LENGTH);
+ \brief Set modem in fixed packet length mode.
+ \param len Packet length.
+ \returns \ref status_codes
+ */
+ int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SI443X_MAX_PACKET_LENGTH);
/*!
- \brief Set modem in variable packet length mode.
- \param maxLen Maximum packet length.
+ \brief Set modem in variable packet length mode.
+ \param maxLen Maximum packet length.
\returns \ref status_codes
- */
- int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SI443X_MAX_PACKET_LENGTH);
+ */
+ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SI443X_MAX_PACKET_LENGTH);
+
+ /*!
+ \brief Read currently active IRQ flags.
+ \returns IRQ flags.
+ */
+ uint32_t getIrqFlags() override;
+
+ /*!
+ \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone).
+ \param irq Module-specific IRQ flags.
+ \returns \ref status_codes
+ */
+ int16_t clearIrqFlags(uint32_t irq) override;
+
+ /*!
+ \brief Enables/disables CRC of transmitted or received packets.
+ \param enable Enable (true) or disable (false) CRC.
+ \param mode Set CRC mode
+ \returns \ref status_codes
+ */
+ int16_t setCRC(bool enable, bool mode = false);
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
@@ -845,9 +874,10 @@ class Si443x: public PhysicalLayer {
size_t packetLength = 0;
bool packetLengthQueried = false;
uint8_t packetLengthConfig = RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON;
+ bool crcEnabled = false;
bool findChip();
- void clearIRQFlags();
+ void clearIrqStatus();
void clearFIFO(size_t count);
int16_t config();
int16_t updateClockRecovery();
diff --git a/lib/RadioLib/src/modules/nRF24/nRF24.cpp b/lib/RadioLib/src/modules/nRF24/nRF24.cpp
index 0218ddd..10cad0d 100644
--- a/lib/RadioLib/src/modules/nRF24/nRF24.cpp
+++ b/lib/RadioLib/src/modules/nRF24/nRF24.cpp
@@ -2,7 +2,9 @@
#include
#if !RADIOLIB_EXCLUDE_NRF24
-nRF24::nRF24(Module* mod) : PhysicalLayer(RADIOLIB_NRF24_FREQUENCY_STEP_SIZE, RADIOLIB_NRF24_MAX_PACKET_LENGTH) {
+nRF24::nRF24(Module* mod) : PhysicalLayer() {
+ this->freqStep = RADIOLIB_NRF24_FREQUENCY_STEP_SIZE;
+ this->maxPacketLength = RADIOLIB_NRF24_MAX_PACKET_LENGTH;
this->mod = mod;
}
@@ -108,7 +110,13 @@ int16_t nRF24::transmit(const uint8_t* data, size_t len, uint8_t addr) {
return(finishTransmit());
}
-int16_t nRF24::receive(uint8_t* data, size_t len) {
+int16_t nRF24::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
+ RadioLibTime_t timeoutInternal = timeout;
+ if(!timeoutInternal) {
+ // calculate timeout (15 retries * 4ms (max Tx time as per datasheet) + 10 ms)
+ timeoutInternal = ((15 * 4) + 10);
+ }
+
// start reception
int16_t state = startReceive();
RADIOLIB_ASSERT(state);
@@ -118,10 +126,9 @@ int16_t nRF24::receive(uint8_t* data, size_t len) {
while(this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
- // check timeout: 15 retries * 4ms (max Tx time as per datasheet) + 10 ms
- if(this->mod->hal->millis() - start >= ((15 * 4) + 10)) {
- standby();
- clearIRQ();
+ // check timeout
+ if(this->mod->hal->millis() - start >= timeoutInternal) {
+ (void)finishReceive();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
}
@@ -272,10 +279,15 @@ int16_t nRF24::readData(uint8_t* data, size_t len) {
// read packet data
SPIreadRxPayload(data, length);
- // clear interrupt
+ return(finishReceive());
+}
+
+int16_t nRF24::finishReceive() {
+ // clear interrupt flags
clearIRQ();
- return(RADIOLIB_ERR_NONE);
+ // set mode to standby to disable transmitter/RF switch
+ return(standby());
}
int16_t nRF24::setFrequency(float freq) {
@@ -387,7 +399,7 @@ int16_t nRF24::setAddressWidth(uint8_t addrWidth) {
return(state);
}
-int16_t nRF24::setTransmitPipe(uint8_t* addr) {
+int16_t nRF24::setTransmitPipe(const uint8_t* addr) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
@@ -402,7 +414,7 @@ int16_t nRF24::setTransmitPipe(uint8_t* addr) {
return(state);
}
-int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) {
+int16_t nRF24::setReceivePipe(uint8_t pipeNum, const uint8_t* addr) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
@@ -561,6 +573,10 @@ int16_t nRF24::setEncoding(uint8_t encoding) {
return(RADIOLIB_ERR_NONE);
}
+int16_t nRF24::setLNA(bool enable) {
+ return(this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, enable ? RADIOLIB_NRF24_RF_LNA_ON : RADIOLIB_NRF24_RF_LNA_OFF, 0, 0));
+}
+
void nRF24::clearIRQ() {
// clear status bits
this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4);
@@ -610,11 +626,11 @@ void nRF24::SPIreadRxPayload(uint8_t* data, uint8_t numBytes) {
SPItransfer(RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD, false, NULL, data, numBytes);
}
-void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) {
+void nRF24::SPIwriteTxPayload(const uint8_t* data, uint8_t numBytes) {
SPItransfer(RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD, true, data, NULL, numBytes);
}
-void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) {
+void nRF24::SPItransfer(uint8_t cmd, bool write, const uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) {
(void)this->mod->SPItransferStream(&cmd, 1, write, dataOut, dataIn, numBytes, false);
}
diff --git a/lib/RadioLib/src/modules/nRF24/nRF24.h b/lib/RadioLib/src/modules/nRF24/nRF24.h
index 428df70..686a63c 100644
--- a/lib/RadioLib/src/modules/nRF24/nRF24.h
+++ b/lib/RadioLib/src/modules/nRF24/nRF24.h
@@ -123,6 +123,8 @@
#define RADIOLIB_NRF24_RF_PWR_12_DBM 0b00000010 // 2 1 -12 dBm
#define RADIOLIB_NRF24_RF_PWR_6_DBM 0b00000100 // 2 1 -6 dBm
#define RADIOLIB_NRF24_RF_PWR_0_DBM 0b00000110 // 2 1 0 dBm (default)
+#define RADIOLIB_NRF24_RF_LNA_OFF 0b00000000 // 0 0 LNA gain: Off
+#define RADIOLIB_NRF24_RF_LNA_ON 0b00000001 // 0 0 On
// RADIOLIB_NRF24_REG_STATUS
#define RADIOLIB_NRF24_RX_DR 0b01000000 // 6 6 Rx data ready
@@ -241,13 +243,15 @@ class nRF24: public PhysicalLayer {
int16_t transmit(const uint8_t* data, size_t len, uint8_t addr) override;
/*!
- \brief Blocking binary receive method.
- Overloads for string-based transmissions are implemented in PhysicalLayer.
- \param data Binary data to be sent.
- \param len Number of bytes to send.
+ \brief Binary receive method. Will attempt to receive arbitrary binary data up to 64 bytes long.
+ For overloads to receive Arduino String, see PhysicalLayer::receive.
+ \param data Pointer to array to save the received binary data.
+ \param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+ \param timeout Reception timeout in milliseconds. If set to 0,
+ timeout period will be calculated automatically based on the radio configuration.
\returns \ref status_codes
*/
- int16_t receive(uint8_t* data, size_t len) override;
+ int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override;
/*!
\brief Starts direct mode transmission.
@@ -338,6 +342,12 @@ class nRF24: public PhysicalLayer {
*/
int16_t readData(uint8_t* data, size_t len) override;
+ /*!
+ \brief Clean up after reception is done.
+ \returns \ref status_codes
+ */
+ int16_t finishReceive() override;
+
// configuration methods
/*!
@@ -374,7 +384,7 @@ class nRF24: public PhysicalLayer {
\param addr Address to which the next packet shall be transmitted.
\returns \ref status_codes
*/
- int16_t setTransmitPipe(uint8_t* addr);
+ int16_t setTransmitPipe(const uint8_t* addr);
/*!
\brief Sets address of receive pipes 0 or 1. The address width must be the same as the same
@@ -384,7 +394,7 @@ class nRF24: public PhysicalLayer {
\param addr Address from which %nRF24 shall receive new packets on the specified pipe.
\returns \ref status_codes
*/
- int16_t setReceivePipe(uint8_t pipeNum, uint8_t* addr);
+ int16_t setReceivePipe(uint8_t pipeNum, const uint8_t* addr);
/*!
\brief Sets address of receive pipes 2 - 5. The first 2 - 4 address bytes for these pipes
@@ -464,6 +474,14 @@ class nRF24: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t setEncoding(uint8_t encoding) override;
+
+ /*!
+ \brief Enable or disable the low-noise amplifier.
+ Improves receive performance at the cost of increased power consumption.
+ \param enable True to enable.
+ \returns \ref status_codes
+ */
+ int16_t setLNA(bool enable);
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
@@ -471,8 +489,8 @@ class nRF24: public PhysicalLayer {
Module* getMod() override;
void SPIreadRxPayload(uint8_t* data, uint8_t numBytes);
- void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes);
- void SPItransfer(uint8_t cmd, bool write = false, uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0);
+ void SPIwriteTxPayload(const uint8_t* data, uint8_t numBytes);
+ void SPItransfer(uint8_t cmd, bool write = false, const uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0);
#if !RADIOLIB_GODMODE
private:
diff --git a/lib/RadioLib/src/protocols/ADSB/ADSB.cpp b/lib/RadioLib/src/protocols/ADSB/ADSB.cpp
new file mode 100644
index 0000000..7ae5d6e
--- /dev/null
+++ b/lib/RadioLib/src/protocols/ADSB/ADSB.cpp
@@ -0,0 +1,256 @@
+#include "ADSB.h"
+
+#if !RADIOLIB_EXCLUDE_ADSB
+
+#include
+
+ADSBClient::ADSBClient(PhysicalLayer* phy) {
+ phyLayer = phy;
+}
+
+int16_t ADSBClient::begin() {
+ // set what is supported by PHY
+ int16_t state = phyLayer->setFrequency(RADIOLIB_ADSB_CARRIER_FREQUENCY);
+ RADIOLIB_ASSERT(state);
+
+ state = phyLayer->setPreambleLength(16);
+ RADIOLIB_ASSERT(state);
+
+ state = phyLayer->setSyncWord(NULL, 0);
+ RADIOLIB_ASSERT(state);
+
+ state = phyLayer->setEncoding(RADIOLIB_ENCODING_MANCHESTER_INV);
+ return(state);
+}
+
+int16_t ADSBClient::decode(const uint8_t in[RADIOLIB_ADSB_FRAME_LEN_BYTES], ADSBFrame* out) {
+ RADIOLIB_ASSERT_PTR(out);
+
+ // get the basic information
+ out->downlinkFormat = (in[0] & 0xF8) >> 3;
+ out->capability = in[0] & 0x07;
+ for(int i = 0; i < RADIOLIB_ADSB_FRAME_ICAO_LEN_BYTES; i++) {
+ out->icao[i] = in[RADIOLIB_ADSB_FRAME_ICAO_POS + i];
+ }
+
+ // lookup table to avoid a whole bunch of if-else statements
+ const ADSBMessageType msgTypeLut[] = {
+ ADSBMessageType::RESERVED,
+ ADSBMessageType::AIRCRAFT_ID, ADSBMessageType::AIRCRAFT_ID,
+ ADSBMessageType::AIRCRAFT_ID, ADSBMessageType::AIRCRAFT_ID,
+ ADSBMessageType::SURFACE_POS, ADSBMessageType::SURFACE_POS,
+ ADSBMessageType::SURFACE_POS, ADSBMessageType::SURFACE_POS,
+ ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO,
+ ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO,
+ ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO,
+ ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO,
+ ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO,
+ ADSBMessageType::AIRBORNE_VEL,
+ ADSBMessageType::AIRBORNE_POS_ALT_GNSS,
+ ADSBMessageType::AIRBORNE_POS_ALT_GNSS,
+ ADSBMessageType::AIRBORNE_POS_ALT_GNSS,
+ ADSBMessageType::RESERVED, ADSBMessageType::RESERVED,
+ ADSBMessageType::RESERVED, ADSBMessageType::RESERVED, ADSBMessageType::RESERVED,
+ ADSBMessageType::AIRCRAFT_STATUS,
+ ADSBMessageType::TARGET_STATE,
+ ADSBMessageType::RESERVED,
+ ADSBMessageType::AIRCRAFT_OPS_STATUS,
+ };
+
+ // get the message type and then the message itself
+ uint8_t typeCode = (in[RADIOLIB_ADSB_FRAME_MESSAGE_POS] & (0x1F << 3)) >> 3;
+ RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADS-B Type Code = %d", typeCode);
+ out->messageType = msgTypeLut[typeCode];
+ for(int i = 0; i < RADIOLIB_ADSB_FRAME_MESSAGE_LEN_BYTES; i++) {
+ out->message[i] = in[RADIOLIB_ADSB_FRAME_MESSAGE_POS + i];
+ }
+
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t ADSBClient::parseHexId(const ADSBFrame* in, char id[RADIOLIB_ADSB_HEX_ID_LEN]) {
+ RADIOLIB_ASSERT_PTR(in);
+
+ for(int i = 0; i < RADIOLIB_ADSB_HEX_ID_LEN / 2; i++) {
+ snprintf(&id[2*i], 3, "%02X", in->icao[i]);
+ }
+
+ id[RADIOLIB_ADSB_HEX_ID_LEN - 1] = '\0';
+ return(RADIOLIB_ERR_NONE);
+}
+
+int16_t ADSBClient::parseCallsign(const ADSBFrame* in, char callsign[RADIOLIB_ADSB_CALLSIGN_LEN], ADSBAircraftCategory* cat) {
+ RADIOLIB_ASSERT_PTR(in);
+
+ if(in->messageType != ADSBMessageType::AIRCRAFT_ID) {
+ return(RADIOLIB_ERR_ADSB_INVALID_MSG_TYPE);
+ }
+
+ // precomputed bitshifts
+ callsign[0] = (in->message[1] & (0x3F << 2)) >> 2;
+ callsign[1] = ((in->message[1] & (0x03 >> 0)) << 4) | ((in->message[2] & (0x0F << 4)) >> 4);
+ callsign[2] = ((in->message[2] & (0x0F << 0)) << 2) | ((in->message[3] & (0x03 << 6)) >> 6);
+ callsign[3] = in->message[3] & 0x3F;
+ callsign[4] = (in->message[4] & (0x3F << 2)) >> 2;
+ callsign[5] = ((in->message[4] & (0x03 >> 0)) << 4) | ((in->message[5] & (0x0F << 4)) >> 4);
+ callsign[6] = ((in->message[5] & (0x0F << 0)) << 2) | ((in->message[6] & (0x03 << 6)) >> 6);
+ callsign[7] = in->message[6] & 0x3F;
+ callsign[RADIOLIB_ADSB_CALLSIGN_LEN - 1] = '\0';
+
+ // convert to ASCII
+ for(int i = 0; i < RADIOLIB_ADSB_CALLSIGN_LEN - 1; i++) {
+ if((callsign[i] >= 1) && (callsign[i] <= 26)) {
+ callsign[i] += '@';
+ } else if(callsign[i] == 32) {
+ callsign[i] = ' ';
+ } else if(!((callsign[i] >= '0') && (callsign[i] <= '9'))) {
+ callsign[i] = '\0';
+ }
+ }
+
+ // only continue processing if category was requested by user
+ if(!cat) { return(RADIOLIB_ERR_NONE);}
+
+ uint8_t type = (in->message[0] & 0xF8) >> 3;
+ uint8_t category = in->message[0] & 0x03;
+ if(type < 2) {
+ *cat = ADSBAircraftCategory::RESERVED;
+ return(RADIOLIB_ERR_NONE);
+ } else if(category == 0) {
+ *cat = ADSBAircraftCategory::NONE;
+ return(RADIOLIB_ERR_NONE);
+ }
+
+ // lookup table to avoid a whole bunch of if-else statements
+ const ADSBAircraftCategory catLut[] = {
+ ADSBAircraftCategory::SURFACE_EMERGENCY,
+ ADSBAircraftCategory::RESERVED,
+ ADSBAircraftCategory::SURFACE_SERVICE,
+ ADSBAircraftCategory::GROUND_OBSTRUCTION,
+ ADSBAircraftCategory::GROUND_OBSTRUCTION,
+ ADSBAircraftCategory::GROUND_OBSTRUCTION,
+ ADSBAircraftCategory::GROUND_OBSTRUCTION,
+ ADSBAircraftCategory::GLIDER,
+ ADSBAircraftCategory::LIGHTER_THAN_AIR,
+ ADSBAircraftCategory::PARACHUTIST,
+ ADSBAircraftCategory::ULTRALIGHT_PARAGLIDER,
+ ADSBAircraftCategory::RESERVED,
+ ADSBAircraftCategory::UAV,
+ ADSBAircraftCategory::SPACE_VEHICLE,
+ ADSBAircraftCategory::LIGHT,
+ ADSBAircraftCategory::MEDIUM_1,
+ ADSBAircraftCategory::MEDIUM_2,
+ ADSBAircraftCategory::HIGH_VORTEX,
+ ADSBAircraftCategory::HEAVY,
+ ADSBAircraftCategory::HIGH_PERFORMANCE,
+ ADSBAircraftCategory::ROTORCRAFT,
+ };
+
+ // the index is parsed from the type and category
+ // in real world values overflowing the lookup table should not appear,
+ // but better to check anyway
+ size_t index = (type - 2)*7 + (category - 1);
+ if(index >= sizeof(catLut)/sizeof(catLut[0])) {
+ return(RADIOLIB_ERR_ADSB_INVALID_CATEGORY);
+ }
+
+ *cat = catLut[index];
+ return(RADIOLIB_ERR_NONE);
+}
+
+void ADSBClient::setReferencePosition(float lat, float lon) {
+ this->refPos[0] = lat;
+ this->refPos[1] = lon;
+}
+
+// lookup table for longitude zones
+// having this as lookup avoids a whole bunch of floating-point calculations
+static const float lonZoneLut[] = {
+ 87.0000000000000f, 86.5353699751210f, 85.7554162094442f, 84.8916619070209f, 83.9917356298057f,
+ 83.0719944471981f, 82.1395698051061f, 81.1980134927195f, 80.2492321328051f, 79.2942822545693f,
+ 78.3337408292275f, 77.3678946132819f, 76.3968439079447f, 75.4205625665336f, 74.4389341572514f,
+ 73.4517744166787f, 72.4588454472895f, 71.4598647302898f, 70.4545107498760f, 69.4424263114402f,
+ 68.4232202208333f, 67.3964677408467f, 66.3617100838262f, 65.3184530968209f, 64.2661652256744f,
+ 63.2042747938193f, 62.1321665921033f, 61.0491777424635f, 59.9545927669403f, 58.8476377614846f,
+ 57.7274735386611f, 56.5931875620592f, 55.4437844449504f, 54.2781747227290f, 53.0951615279600f,
+ 51.8934246916877f, 50.6715016555384f, 49.4277643925569f, 48.1603912809662f, 46.8673325249875f,
+ 45.5462672266023f, 44.1945495141927f, 42.8091401224356f, 41.3865183226024f, 39.9225668433386f,
+ 38.4124189241226f, 36.8502510759353f, 35.2289959779639f, 33.5399343629848f, 31.7720970768108f,
+ 29.9113568573181f, 27.9389871012190f, 25.8292470705878f, 23.5450448655707f, 21.0293949260285f,
+ 18.1862635707134f, 14.8281743686868f, 10.4704712999685f,
+};
+
+int16_t ADSBClient::parseAirbornePosition(const ADSBFrame* in, int* alt, float* lat, float* lon, bool* altGnss) {
+ RADIOLIB_ASSERT_PTR(in);
+
+ if((in->messageType != ADSBMessageType::AIRBORNE_POS_ALT_BARO) &&
+ (in->messageType != ADSBMessageType::AIRBORNE_POS_ALT_GNSS)) {
+ return(RADIOLIB_ERR_ADSB_INVALID_MSG_TYPE);
+ }
+
+ // parse altitude
+ if(alt) {
+ if(in->messageType == ADSBMessageType::AIRBORNE_POS_ALT_BARO) {
+ // barometric altitude, get the raw value without the Q bit
+ uint16_t altRaw = ((in->message[1] & 0xFE) << 3) | ((in->message[2] & 0xF0) >> 4);
+
+ // now get the step size based on the Q bit and calculate
+ int step = (in->message[1] & 0x01) ? 25 : 100;
+ *alt = step*(int)altRaw - 1000;
+
+ } else {
+ // GNSS altitude, which is just meters
+ *alt = (in->message[1] << 4) | ((in->message[2] & 0xF0) >> 4);
+
+ }
+
+ // pass the source flag, if requested
+ if(altGnss) { *altGnss = (in->messageType == ADSBMessageType::AIRBORNE_POS_ALT_GNSS); }
+ }
+
+ // check if this is an even or odd frame
+ bool odd = in->message[2] & 0x04;
+
+ // always calculate the latitude - it is needed to also calculate longitude
+ uint32_t latRaw = (((uint32_t)(in->message[2] & 0x03)) << 15) | ((uint32_t)in->message[3] << 7) | (uint32_t)((in->message[4] & 0xFE) >> 1);
+ float latCpr = (float)latRaw / (float)(1UL << 17);
+ float latZoneSize = odd ? 360.0f/59.0f : 6.0f;
+ int latZoneIdx = floor(this->refPos[0] / latZoneSize) + floor((fmod(this->refPos[0], latZoneSize) / latZoneSize) - latCpr + 0.5f);
+ float tmpLat = latZoneSize * (latZoneIdx + (float)latCpr);
+ if(lat) { *lat = tmpLat; }
+ RADIOLIB_DEBUG_PROTOCOL_PRINT("latRaw=%d\n", latRaw);
+ RADIOLIB_DEBUG_PROTOCOL_PRINT("latCpr=%f\n", (double)latCpr);
+ RADIOLIB_DEBUG_PROTOCOL_PRINT("latZoneSize=%f\n", (double)latZoneSize);
+ RADIOLIB_DEBUG_PROTOCOL_PRINT("latZoneIdx=%d\n", latZoneIdx);
+
+ // only calculate longitude if the user requested it
+ if(lon) {
+ int lonZone = 1;
+ if(abs(tmpLat) < 87.0f) {
+ for(size_t i = 0; i < sizeof(lonZoneLut)/sizeof(lonZoneLut[0]); i++) {
+ if(abs(tmpLat) >= lonZoneLut[i]) {
+ lonZone = i + 1;
+ break;
+ }
+ }
+ if(lonZone == 1) {
+ lonZone = 59;
+ }
+ }
+ uint32_t lonRaw = (((uint32_t)(in->message[4] & 0x01)) << 16) | ((uint32_t)in->message[5] << 8) | (uint32_t)in->message[6];
+ float lonCpr = (float)lonRaw / (float)(1UL << 17);
+ float lonZoneSize = 360.0f / RADIOLIB_MAX(lonZone - (int)odd, 1);
+ int lonZoneIdx = floor(this->refPos[1] / lonZoneSize) + floor((fmod(this->refPos[1], lonZoneSize) / lonZoneSize) - lonCpr + 0.5f);
+ *lon = lonZoneSize * (lonZoneIdx + (float)lonCpr);
+
+ RADIOLIB_DEBUG_PROTOCOL_PRINT("lonRaw=%d\n", lonRaw);
+ RADIOLIB_DEBUG_PROTOCOL_PRINT("lonCpr=%f\n", (double)lonCpr);
+ RADIOLIB_DEBUG_PROTOCOL_PRINT("lonZone=%d\n", lonZone);
+ RADIOLIB_DEBUG_PROTOCOL_PRINT("lonZoneSize=%f\n", (double)lonZoneSize);
+ RADIOLIB_DEBUG_PROTOCOL_PRINT("lonZoneIdx=%d\n", lonZoneIdx);
+ }
+
+ return(RADIOLIB_ERR_NONE);
+}
+
+#endif
diff --git a/lib/RadioLib/src/protocols/ADSB/ADSB.h b/lib/RadioLib/src/protocols/ADSB/ADSB.h
new file mode 100644
index 0000000..9e91bb6
--- /dev/null
+++ b/lib/RadioLib/src/protocols/ADSB/ADSB.h
@@ -0,0 +1,165 @@
+#if !defined(RADIOLIB_ADSB_H)
+#define RADIOLIB_ADSB_H
+
+#include "../../TypeDef.h"
+
+#if !RADIOLIB_EXCLUDE_ADSB
+
+#include "../PhysicalLayer/PhysicalLayer.h"
+
+#define RADIOLIB_ADSB_CARRIER_FREQUENCY (1090.0f)
+
+// basic ADS-B frame structure
+#define RADIOLIB_ADSB_FRAME_LEN_BYTES (14)
+#define RADIOLIB_ADSB_FRAME_DF_CA_POS (0)
+#define RADIOLIB_ADSB_FRAME_ICAO_LEN_BYTES (3)
+#define RADIOLIB_ADSB_FRAME_ICAO_POS (1)
+#define RADIOLIB_ADSB_FRAME_MESSAGE_LEN_BYTES (7)
+#define RADIOLIB_ADSB_FRAME_MESSAGE_POS (4)
+#define RADIOLIB_ADSB_FRAME_PARITY_INTERROGATOR_LEN_BYTES (3)
+#define RADIOLIB_ADSB_FRAME_PARITY_INTERROGATOR_POS (11)
+
+// length of the ICAO address, including a terminating null
+#define RADIOLIB_ADSB_HEX_ID_LEN (6 + 1)
+
+// length of the callsign, including a terminating null
+#define RADIOLIB_ADSB_CALLSIGN_LEN (8 + 1)
+
+/*!
+ \enum ADSBMessageType
+ \brief ADS-B Message Type
+*/
+enum class ADSBMessageType {
+ AIRCRAFT_ID = 0,
+ SURFACE_POS,
+ AIRBORNE_POS_ALT_BARO,
+ AIRBORNE_VEL,
+ AIRBORNE_POS_ALT_GNSS,
+ AIRCRAFT_STATUS,
+ TARGET_STATE,
+ AIRCRAFT_OPS_STATUS,
+ RESERVED,
+};
+
+/*!
+ \enum ADSBAircraftCategory
+ \brief ADS-B Aircraft category
+*/
+enum class ADSBAircraftCategory {
+ NONE = 0,
+ SURFACE_EMERGENCY,
+ SURFACE_SERVICE,
+ GROUND_OBSTRUCTION,
+ GLIDER,
+ LIGHTER_THAN_AIR,
+ PARACHUTIST,
+ ULTRALIGHT_PARAGLIDER,
+ UAV,
+ SPACE_VEHICLE,
+ LIGHT,
+ MEDIUM_1,
+ MEDIUM_2,
+ HIGH_VORTEX,
+ HEAVY,
+ HIGH_PERFORMANCE,
+ ROTORCRAFT,
+ RESERVED,
+};
+
+/*!
+ \struct ADSBFrame
+ \brief ADS-B Frame structure
+*/
+struct ADSBFrame {
+ public:
+ /*! \brief Downlink format (DF). Received frames should always have DF = 17. */
+ uint8_t downlinkFormat;
+
+ /*! \brief Transponder capability. */
+ uint8_t capability;
+
+ /*! \brief Transponder ICAO address. */
+ uint8_t icao[RADIOLIB_ADSB_FRAME_ICAO_LEN_BYTES];
+
+ /*! \brief Message type. */
+ ADSBMessageType messageType;
+
+ /*! \brief Message buffer, interpretation is dependent on the value of messageType. */
+ uint8_t message[RADIOLIB_ADSB_FRAME_MESSAGE_LEN_BYTES];
+};
+
+/*!
+ \class ADSBClient
+ \brief Client for receiving and decoding ADS-B broadcast.
+*/
+class ADSBClient {
+ public:
+ /*!
+ \brief Default constructor.
+ \param phy Pointer to the wireless module providing PhysicalLayer communication.
+ */
+ explicit ADSBClient(PhysicalLayer* phy);
+
+ /*!
+ \brief Initialization method.
+ \returns \ref status_codes
+ */
+ int16_t begin();
+
+ /*!
+ \brief Frame decoding method, turns raw received binary data into ADS-B frame.
+ \param in Received raw data.
+ \param out Pointer to ADSBFrame where the decoded frame will be saved.
+ \returns \ref status_codes
+ */
+ int16_t decode(const uint8_t in[RADIOLIB_ADSB_FRAME_LEN_BYTES], ADSBFrame* out);
+
+ /*!
+ \brief Method to parse the transponder ICAO address (hex ID).
+ \param in Pointer to ADSBFrame where decoded frame was saved.
+ \param callsign Buffer where the parsed ID will be saved as null-terminated string.
+ \returns \ref status_codes
+ */
+ int16_t parseHexId(const ADSBFrame* in, char id[RADIOLIB_ADSB_HEX_ID_LEN]);
+
+ /*!
+ \brief Method to parse callsign from a received frame.
+ \param in Pointer to ADSBFrame where decoded frame was saved.
+ \param callsign Buffer where the parsed callsign will be saved as null-terminated string.
+ \param cat If set, parsed aircraft category will be saved here.
+ \returns \ref status_codes
+ */
+ int16_t parseCallsign(const ADSBFrame* in, char callsign[RADIOLIB_ADSB_CALLSIGN_LEN], ADSBAircraftCategory* cat = NULL);
+
+ /*!
+ \brief Method to set reference position to be used during airborne position calculation.
+ \param lat Reference latitude in degrees (north positive, south negative).
+ \param lat Reference longitude in degrees (east positive, west negative).
+ */
+ void setReferencePosition(float lat, float lon);
+
+ /*!
+ \brief Parse aircraft position from incoming frame, uasing reference position set by setReferencePosition.
+ The reference position is the "rough area" where the aircraft is located, typically it is the receiver location.
+ Aircraft position will be calcualted accurately only within 180 nautical miles (about 333 km) from the reference position!
+ \param in Pointer to ADSBFrame where decoded frame was saved.
+ \param alt Pointer to variable where the parsed altitude will be saved. Can be set to null to skip altitude calculation.
+ Units are feet for barometric altitude, meters for GNSS altitude.
+ \param lat Pointer to variable where the parsed latitude in degrees will be saved. Can be set to null to skip latitude calculation.
+ \param lon Pointer to variable where the parsed longitude in degrees will be saved. Can be set to null to skip longitude calculation.
+ \param altGnss If set, this variable will be set to true if the altitude source is GNSS, or false if the altitude is barometric.
+ */
+ int16_t parseAirbornePosition(const ADSBFrame* in, int* alt, float* lat, float* lon, bool* altGnss = NULL);
+
+#if !RADIOLIB_GODMODE
+ private:
+#endif
+ PhysicalLayer* phyLayer;
+
+ // reference position
+ float refPos[2] = { 0, 0 };
+};
+
+#endif
+
+#endif
diff --git a/lib/RadioLib/src/protocols/APRS/APRS.cpp b/lib/RadioLib/src/protocols/APRS/APRS.cpp
index c2fb72f..8fa932ad 100644
--- a/lib/RadioLib/src/protocols/APRS/APRS.cpp
+++ b/lib/RadioLib/src/protocols/APRS/APRS.cpp
@@ -14,7 +14,7 @@ APRSClient::APRSClient(PhysicalLayer* phy) {
phyLayer = phy;
}
-int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) {
+int16_t APRSClient::begin(char sym, const char* callsign, uint8_t ssid, bool alt) {
RADIOLIB_CHECK_RANGE(sym, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL);
symbol = sym;
@@ -39,7 +39,7 @@ int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) {
return(RADIOLIB_ERR_NONE);
}
-int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg, char* time) {
+int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, const char* lat, const char* lon, const char* msg, const char* time) {
size_t len = 1 + strlen(lat) + 1 + strlen(lon);
if(msg != NULL) {
len += 1 + strlen(msg);
@@ -50,7 +50,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat
#if !RADIOLIB_STATIC_ONLY
char* info = new char[len + 2];
#else
- char info[RADIOLIB_STATIC_ARRAY_SIZE];
+ char info[RADIOLIB_STATIC_ARRAY_SIZE + 2];
#endif
// build the info field
@@ -84,7 +84,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat
return(state);
}
-int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, uint8_t* telem, size_t telemLen, char* grid, char* status, int32_t alt) {
+int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, const uint8_t* telem, size_t telemLen, const char* grid, const char* status, int32_t alt) {
// sanity checks first
if(((telemLen == 0) && (telem != NULL)) || ((telemLen != 0) && (telem == NULL))) {
return(RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY);
diff --git a/lib/RadioLib/src/protocols/APRS/APRS.h b/lib/RadioLib/src/protocols/APRS/APRS.h
index 44031fd..f496f3b 100644
--- a/lib/RadioLib/src/protocols/APRS/APRS.h
+++ b/lib/RadioLib/src/protocols/APRS/APRS.h
@@ -106,7 +106,7 @@ class APRSClient {
\param alt Whether to use the primary (false) or alternate (true) symbol table. Defaults to primary table.
\returns \ref status_codes
*/
- int16_t begin(char sym, char* callsign = NULL, uint8_t ssid = 0, bool alt = false);
+ int16_t begin(char sym, const char* callsign = NULL, uint8_t ssid = 0, bool alt = false);
/*!
\brief Transmit position.
@@ -118,7 +118,7 @@ class APRSClient {
\param time Position timestamp. Defaults to NULL (no timestamp).
\returns \ref status_codes
*/
- int16_t sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg = NULL, char* time = NULL);
+ int16_t sendPosition(char* destCallsign, uint8_t destSSID, const char* lat, const char* lon, const char* msg = NULL, const char* time = NULL);
/*!
\brief Transmit position using Mic-E encoding.
@@ -133,7 +133,7 @@ class APRSClient {
\param status Status message to send. NULL when not used.
\param alt Altitude to send. RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED when not used.
*/
- int16_t sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, uint8_t* telem = NULL, size_t telemLen = 0, char* grid = NULL, char* status = NULL, int32_t alt = RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED);
+ int16_t sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, const uint8_t* telem = NULL, size_t telemLen = 0, const char* grid = NULL, const char* status = NULL, int32_t alt = RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED);
/*!
\brief Transmit generic APRS frame.
diff --git a/lib/RadioLib/src/protocols/AX25/AX25.cpp b/lib/RadioLib/src/protocols/AX25/AX25.cpp
index 22e1220..ea16083 100644
--- a/lib/RadioLib/src/protocols/AX25/AX25.cpp
+++ b/lib/RadioLib/src/protocols/AX25/AX25.cpp
@@ -14,7 +14,7 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src
}
-AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen) {
+AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const uint8_t* info, uint16_t infoLen) {
// destination callsign/SSID
memcpy(this->destCallsign, destCallsign, strlen(destCallsign));
this->destCallsign[strlen(destCallsign)] = '\0';
@@ -142,7 +142,7 @@ AX25Frame& AX25Frame::operator=(const AX25Frame& frame) {
return(*this);
}
-int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters) {
+int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, const uint8_t* repeaterSSIDs, uint8_t numRepeaters) {
// check number of repeaters
if((numRepeaters < 1) || (numRepeaters > 8)) {
return(RADIOLIB_ERR_INVALID_NUM_REPEATERS);
@@ -263,6 +263,11 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preL
return(phyLayer->startDirect());
}
+void AX25Client::setScrambler(uint32_t poly, uint32_t init) {
+ this->scramblerPoly = poly;
+ this->scramblerInit = init;
+}
+
#if defined(RADIOLIB_BUILD_ARDUINO)
int16_t AX25Client::transmit(String& str, const char* destCallsign, uint8_t destSSID) {
return(transmit(str.c_str(), destCallsign, destSSID));
@@ -307,7 +312,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) {
#if !RADIOLIB_STATIC_ONLY
uint8_t* frameBuff = new uint8_t[frameBuffLen + 2];
#else
- uint8_t frameBuff[RADIOLIB_STATIC_ARRAY_SIZE];
+ uint8_t frameBuff[RADIOLIB_STATIC_ARRAY_SIZE + 2];
#endif
uint8_t* frameBuffPtr = frameBuff;
@@ -390,7 +395,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) {
// worst-case scenario: sequence of 1s, will have 120% of the original length, stuffed frame also includes both flags
uint8_t* stuffedFrameBuff = new uint8_t[preambleLen + 1 + (6*frameBuffLen)/5 + 2];
#else
- uint8_t stuffedFrameBuff[RADIOLIB_STATIC_ARRAY_SIZE];
+ uint8_t stuffedFrameBuff[1 + (6*RADIOLIB_STATIC_ARRAY_SIZE)/5 + 2];
#endif
// initialize buffer to all zeros
@@ -474,6 +479,11 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) {
}
}
+ // do the scrambling
+ if(scramblerPoly) {
+ rlb_scrambler(stuffedFrameBuff, stuffedFrameBuffLen, scramblerPoly, scramblerInit, true);
+ }
+
// transmit
int16_t state = RADIOLIB_ERR_NONE;
#if !RADIOLIB_EXCLUDE_AFSK
diff --git a/lib/RadioLib/src/protocols/AX25/AX25.h b/lib/RadioLib/src/protocols/AX25/AX25.h
index c7678a3..250cf17 100644
--- a/lib/RadioLib/src/protocols/AX25/AX25.h
+++ b/lib/RadioLib/src/protocols/AX25/AX25.h
@@ -185,7 +185,7 @@ class AX25Frame {
\param info Information field, in the form of arbitrary binary buffer.
\param infoLen Number of bytes in the information field.
*/
- AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen);
+ AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const uint8_t* info, uint16_t infoLen);
/*!
\brief Copy constructor.
@@ -211,7 +211,7 @@ class AX25Frame {
\param numRepeaters Number of repeaters, maximum is 8.
\returns \ref status_codes
*/
- int16_t setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters);
+ int16_t setRepeaters(char** repeaterCallsigns, const uint8_t* repeaterSSIDs, uint8_t numRepeaters);
/*!
\brief Method to set receive sequence number.
@@ -281,6 +281,13 @@ class AX25Client {
*/
int16_t begin(const char* srcCallsign, uint8_t srcSSID = 0x00, uint8_t preLen = 8);
+ /*!
+ \brief Set scrambling polynomail and initial value.
+ \param poly Scramling polynomial. Use RADIOLIB_SCRAMBLER_G3RUH_POLY for G3RUH coding.
+ \param poly Initial scrambler value. Use RADIOLIB_SCRAMBLER_G3RUH_INIT for G3RUH coding.
+ */
+ void setScrambler(uint32_t poly, uint32_t init = 0);
+
#if defined(RADIOLIB_BUILD_ARDUINO)
/*!
\brief Transmit unnumbered information (UI) frame.
@@ -324,6 +331,8 @@ class AX25Client {
char sourceCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = { 0 };
uint8_t sourceSSID = 0;
uint16_t preambleLen = 0;
+ uint32_t scramblerInit = 0;
+ uint32_t scramblerPoly = 0;
void getCallsign(char* buff);
uint8_t getSSID();
diff --git a/lib/RadioLib/src/protocols/BellModem/BellModem.cpp b/lib/RadioLib/src/protocols/BellModem/BellModem.cpp
index 30da937..a683393 100644
--- a/lib/RadioLib/src/protocols/BellModem/BellModem.cpp
+++ b/lib/RadioLib/src/protocols/BellModem/BellModem.cpp
@@ -43,7 +43,7 @@ int16_t BellClient::begin(const BellModem_t& modem) {
int16_t BellClient::setModem(const BellModem_t& modem) {
this->modemType = modem;
- this->toneLen = (1000000.0/(float)this->modemType.baudRate)*this->correction;
+ this->toneLen = (1000000.0f/(float)this->modemType.baudRate)*this->correction;
return(RADIOLIB_ERR_NONE);
}
diff --git a/lib/RadioLib/src/protocols/ExternalRadio/ExternalRadio.cpp b/lib/RadioLib/src/protocols/ExternalRadio/ExternalRadio.cpp
index 212f8a1..b597f6f 100644
--- a/lib/RadioLib/src/protocols/ExternalRadio/ExternalRadio.cpp
+++ b/lib/RadioLib/src/protocols/ExternalRadio/ExternalRadio.cpp
@@ -1,20 +1,23 @@
#include "ExternalRadio.h"
#if defined(RADIOLIB_BUILD_ARDUINO)
-ExternalRadio::ExternalRadio(uint32_t pin) : PhysicalLayer(1, 0) {
+ExternalRadio::ExternalRadio(uint32_t pin) : PhysicalLayer() {
+ this->freqStep = 1;
mod = new Module(RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, pin);
mod->hal->pinMode(pin, mod->hal->GpioModeOutput);
this->prevFrf = 0;
}
#endif
-ExternalRadio::ExternalRadio(RadioLibHal *hal, uint32_t pin) : PhysicalLayer(1, 0) {
+ExternalRadio::ExternalRadio(RadioLibHal *hal, uint32_t pin) : PhysicalLayer() {
+ this->freqStep = 1;
mod = new Module(hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, pin);
mod->hal->pinMode(pin, mod->hal->GpioModeOutput);
this->prevFrf = 0;
}
-ExternalRadio::ExternalRadio(const ExternalRadio& ext) : PhysicalLayer(1, 0) {
+ExternalRadio::ExternalRadio(const ExternalRadio& ext) : PhysicalLayer() {
+ this->freqStep = 1;
this->prevFrf = ext.prevFrf;
if(ext.mod) {
this->mod = new Module(ext.mod->hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, ext.mod->getGpio());
@@ -32,9 +35,7 @@ ExternalRadio& ExternalRadio::operator=(const ExternalRadio& ext) {
}
ExternalRadio::~ExternalRadio() {
- if(this->mod) {
- delete this->mod;
- }
+ delete this->mod;
}
Module* ExternalRadio::getMod() {
diff --git a/lib/RadioLib/src/protocols/FSK4/FSK4.cpp b/lib/RadioLib/src/protocols/FSK4/FSK4.cpp
index 7e2d737..b96362e 100644
--- a/lib/RadioLib/src/protocols/FSK4/FSK4.cpp
+++ b/lib/RadioLib/src/protocols/FSK4/FSK4.cpp
@@ -34,7 +34,7 @@ int16_t FSK4Client::begin(float base, uint32_t shift, uint16_t rate) {
}
// calculate 24-bit frequency
- baseFreq = (base * 1000000.0) / phyLayer->getFreqStep();
+ baseFreq = (base * 1000000.0f) / phyLayer->freqStep;
// configure for direct mode
return(phyLayer->startDirect());
@@ -54,7 +54,7 @@ int16_t FSK4Client::setCorrection(int16_t offsets[], float length) {
return(RADIOLIB_ERR_NONE);
}
-size_t FSK4Client::write(uint8_t* buff, size_t len) {
+size_t FSK4Client::write(const uint8_t* buff, size_t len) {
size_t n = 0;
for(size_t i = 0; i < len; i++) {
n += FSK4Client::write(buff[i]);
@@ -109,7 +109,7 @@ int16_t FSK4Client::standby() {
int32_t FSK4Client::getRawShift(int32_t shift) {
// calculate module carrier frequency resolution
- int32_t step = round(phyLayer->getFreqStep());
+ int32_t step = round(phyLayer->freqStep);
// check minimum shift value
if(RADIOLIB_ABS(shift) < step / 2) {
diff --git a/lib/RadioLib/src/protocols/FSK4/FSK4.h b/lib/RadioLib/src/protocols/FSK4/FSK4.h
index 31df410..757e556 100644
--- a/lib/RadioLib/src/protocols/FSK4/FSK4.h
+++ b/lib/RadioLib/src/protocols/FSK4/FSK4.h
@@ -59,7 +59,7 @@ class FSK4Client {
\param len Number of bytes to transmit.
\returns Number of transmitted bytes.
*/
- size_t write(uint8_t* buff, size_t len);
+ size_t write(const uint8_t* buff, size_t len);
/*!
\brief Transmit a single byte.
diff --git a/lib/RadioLib/src/protocols/Hellschreiber/Hellschreiber.cpp b/lib/RadioLib/src/protocols/Hellschreiber/Hellschreiber.cpp
index b79e7a4..5e5d3c2 100644
--- a/lib/RadioLib/src/protocols/Hellschreiber/Hellschreiber.cpp
+++ b/lib/RadioLib/src/protocols/Hellschreiber/Hellschreiber.cpp
@@ -21,10 +21,10 @@ HellClient::HellClient(AFSKClient* audio) {
int16_t HellClient::begin(float base, float rate) {
// calculate 24-bit frequency
baseFreqHz = base;
- baseFreq = (base * 1000000.0) / phyLayer->getFreqStep();
+ baseFreq = (base * 1000000.0f) / phyLayer->freqStep;
// calculate "pixel" duration
- pixelDuration = 1000000.0/rate;
+ pixelDuration = 1000000.0f/rate;
// configure for direct mode
return(phyLayer->startDirect());
@@ -73,7 +73,8 @@ size_t HellClient::write(uint8_t b) {
uint8_t buff[RADIOLIB_HELL_FONT_WIDTH];
buff[0] = 0x00;
for(uint8_t i = 0; i < RADIOLIB_HELL_FONT_WIDTH - 2; i++) {
- buff[i + 1] = RADIOLIB_NONVOLATILE_READ_BYTE(&HellFont[pos][i]);
+ uint8_t* ptr = const_cast(&HellFont[pos][i]);
+ buff[i + 1] = RADIOLIB_NONVOLATILE_READ_BYTE(ptr);
}
buff[RADIOLIB_HELL_FONT_WIDTH - 1] = 0x00;
diff --git a/lib/RadioLib/src/protocols/Hellschreiber/Hellschreiber.h b/lib/RadioLib/src/protocols/Hellschreiber/Hellschreiber.h
index 0c26697..10e6727 100644
--- a/lib/RadioLib/src/protocols/Hellschreiber/Hellschreiber.h
+++ b/lib/RadioLib/src/protocols/Hellschreiber/Hellschreiber.h
@@ -144,9 +144,6 @@ class HellClient: public RadioLibPrint {
uint32_t pixelDuration = 0;
bool invert = false;
- size_t printNumber(unsigned long, uint8_t);
- size_t printFloat(double, uint8_t);
-
int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0);
int16_t standby();
};
diff --git a/lib/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp b/lib/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp
index 07281be..340b581 100644
--- a/lib/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp
+++ b/lib/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp
@@ -9,10 +9,11 @@
LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand) {
this->phyLayer = phy;
this->band = band;
- this->channels[RADIOLIB_LORAWAN_DIR_RX2] = this->band->rx2;
- this->txPowerMax = this->band->powerMax;
this->subBand = subBand;
- memset(this->channelPlan, 0, sizeof(this->channelPlan));
+ memset(this->dynamicChannels, 0, sizeof(this->dynamicChannels));
+ for(int i = 0; i < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; i++) {
+ this->packages[i] = RADIOLIB_LORAWAN_PACKAGE_NONE;
+ }
}
#if defined(RADIOLIB_BUILD_ARDUINO)
@@ -24,16 +25,16 @@ int16_t LoRaWANNode::sendReceive(const String& strUp, uint8_t fPort, String& str
// build a temporary buffer
// LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL
size_t lenDown = 0;
- uint8_t dataDown[251];
+ uint8_t dataDown[RADIOLIB_LORAWAN_MAX_PAYLOAD_SIZE + 1];
- state = this->sendReceive((const uint8_t*)dataUp, strlen(dataUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown);
+ state = this->sendReceive(reinterpret_cast(dataUp), strlen(dataUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown);
- if(state == RADIOLIB_ERR_NONE) {
+ if(state > RADIOLIB_ERR_NONE) {
// add null terminator
dataDown[lenDown] = '\0';
// initialize Arduino String class
- strDown = String((char*)dataDown);
+ strDown = String(reinterpret_cast(dataDown));
}
return(state);
@@ -44,30 +45,29 @@ int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, bool isConfir
// build a temporary buffer
// LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL
size_t lenDown = 0;
- uint8_t dataDown[251];
+ uint8_t dataDown[RADIOLIB_LORAWAN_MAX_PAYLOAD_SIZE + 1];
- return(this->sendReceive((uint8_t*)strUp, strlen(strUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown));
+ return(this->sendReceive(reinterpret_cast(const_cast(strUp)), strlen(strUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown));
}
int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) {
- return(this->sendReceive((uint8_t*)strUp, strlen(strUp), fPort, dataDown, lenDown, isConfirmed, eventUp, eventDown));
+ return(this->sendReceive(reinterpret_cast(const_cast(strUp)), strlen(strUp), fPort, dataDown, lenDown, isConfirmed, eventUp, eventDown));
}
int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) {
// build a temporary buffer
// LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL
size_t lenDown = 0;
- uint8_t dataDown[251];
+ uint8_t dataDown[RADIOLIB_LORAWAN_MAX_PAYLOAD_SIZE + 1];
return(this->sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown));
}
int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) {
- if(!dataUp || !dataDown || !lenDown) {
+ if((lenUp > 0 && !dataUp) || !dataDown || !lenDown) {
return(RADIOLIB_ERR_NULL_POINTER);
}
int16_t state = RADIOLIB_ERR_UNKNOWN;
- Module* mod = this->phyLayer->getMod();
// if after (at) ADR_ACK_LIMIT frames no RekeyConf was received, revert to Join state
if(this->fCntUp == (1UL << this->adrLimitExp)) {
@@ -82,26 +82,62 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP
return(RADIOLIB_ERR_NETWORK_NOT_JOINED);
}
+ Module *mod = this->phyLayer->getMod();
+ RadioLibTime_t tNow = mod->hal->millis();
+ // if scheduled uplink time is in the past, reschedule to now
+ if(this->tUplink < tNow) {
+ this->tUplink = tNow;
+ }
+
+ // if dutycycle is enabled and the time since last uplink + interval has not elapsed, return an error
+ if(this->dutyCycleEnabled) {
+ if(this->tUplinkEnd + (RadioLibTime_t)dutyCycleInterval(this->dutyCycle, this->lastToA) > this->tUplink) {
+ return(RADIOLIB_ERR_UPLINK_UNAVAILABLE);
+ }
+ }
+
+ if(lenUp == 0 && fPort == 0) {
+ this->isMACPayload = true;
+ }
+
// check if the requested payload + fPort are allowed, also given dutycycle
- uint8_t totalLen = lenUp + this->fOptsUpLen;
- state = this->isValidUplink(&totalLen, fPort);
+ state = this->isValidUplink(lenUp + this->fOptsUpLen, fPort);
RADIOLIB_ASSERT(state);
- // in case of TS009, a payload that is too long may have gotten clipped,
- // so recalculate the actual payload length
- // (outside of TS009, a payload that is too long throws an error)
- lenUp = totalLen - this->fOptsUpLen;
+ // clear the MAC downlink buffer as we are going to transmit a new uplink
+ memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
+ this->fOptsDownLen = 0;
// the first 16 bytes are reserved for MIC calculation blocks
size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(lenUp, this->fOptsUpLen);
#if RADIOLIB_STATIC_ONLY
uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE];
+ uint8_t frmPayload[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* uplinkMsg = new uint8_t[uplinkMsgLen];
+ uint8_t* frmPayload = new uint8_t[lenUp + this->fOptsUpLen];
#endif
+
+ uint8_t frmLen = 0;
+
+ // if the payload consists of piggybacked MAC only, move this to the FRMPayload
+ if(this->isMACPayload && lenUp == 0) {
+ memcpy(frmPayload, this->fOptsUp, this->fOptsUpLen);
+ frmLen = this->fOptsUpLen;
+
+ memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
+ this->fOptsUpLen = 0;
+
+ this->isMACPayload = false; // reset for next uplink
+
+ // if there is user payload, move this to the FRMPayload
+ } else {
+ memcpy(frmPayload, dataUp, lenUp);
+ frmLen = lenUp;
+ }
// build the encrypted uplink message
- this->composeUplink(dataUp, lenUp, uplinkMsg, fPort, isConfirmed);
+ this->composeUplink(frmPayload, frmLen, uplinkMsg, fPort, isConfirmed);
// reset Time-on-Air as we are starting new uplink sequence
this->lastToA = 0;
@@ -116,7 +152,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP
// number of additional CAD tries
uint8_t numBackoff = 0;
if(this->backoffMax) {
- numBackoff = this->phyLayer->random(1, this->backoffMax + 1);
+ numBackoff = 1 + rand() % this->backoffMax;
}
do {
@@ -132,23 +168,21 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP
// send it (without the MIC calculation blocks)
state = this->transmitUplink(&this->channels[RADIOLIB_LORAWAN_UPLINK],
&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS],
- (uint8_t)(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS),
- trans > 0);
+ (uint8_t)(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS));
if(state != RADIOLIB_ERR_NONE) {
+ // sometimes, a spurious error can occur even though the uplink was transmitted
+ // therefore, just to be safe, increase frame counter by one for the next uplink
+ this->fCntUp += 1;
+
#if !RADIOLIB_STATIC_ONLY
delete[] uplinkMsg;
+ delete[] frmPayload;
#endif
return(state);
}
- // handle Rx1 and Rx2 windows - returns window > 0 if a downlink is received
- state = receiveCommon(RADIOLIB_LORAWAN_DOWNLINK, this->channels, this->rxDelays, 2, this->rxDelayStart);
-
- // RETRANSMIT_TIMEOUT is 2s +/- 1s (RP v1.0.4)
- // must be present after any confirmed frame, so we force this here
- if(isConfirmed) {
- mod->hal->delay(this->phyLayer->random(1000, 3000));
- }
+ // handle Rx windows - returns window > 0 if a downlink is received
+ state = this->receiveDownlink();
// if an error occured or a downlink was received, stop retransmission
if(state != RADIOLIB_ERR_NONE) {
@@ -156,10 +190,22 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP
}
// if no downlink was received, go on
+ // When an end-device has requested an ACK from the Network but has not yet received it,
+ // it SHALL wait RETRANSMIT_TIMEOUT seconds after RECEIVE_DELAY2 seconds have elapsed
+ // after the end of the previous uplink transmission before sending a new uplink (repetition or new frame).
+ // The RETRANSMIT_TIMEOUT delay is not required between unconfirmed uplinks,
+ // or after the ACK has been successfully demodulated by the end-device.
+ if(isConfirmed) {
+ RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Retransmit timeout");
+ int min = RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS;
+ int max = RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS;
+ this->sleepDelay(min + rand() % (max - min));
+ }
+
} // end of transmission & reception
- // note: if an error occured, it may still be the case that a transmission occured
- // therefore, we act as if a transmission occured before throwing the actual error
+ // note: if an error occurred, it may still be the case that a transmission occurred
+ // therefore, we act as if a transmission occurred before throwing the actual error
// this feels to be the best way to comply to spec
// increase frame counter by one for the next uplink
@@ -179,10 +225,12 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP
eventUp->fCnt = this->fCntUp;
eventUp->fPort = fPort;
eventUp->nbTrans = trans;
+ eventUp->multicast = false;
}
#if !RADIOLIB_STATIC_ONLY
delete[] uplinkMsg;
+ delete[] frmPayload;
#endif
// if a hardware error occurred, return
@@ -202,15 +250,16 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP
LoRaWANNode::clearMacCommands(this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK);
return(rxWindow);
}
-
- // a downlink was received, so we can clear the whole MAC uplink buffer
- memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
- this->fOptsUpLen = 0;
-
- state = this->parseDownlink(dataDown, lenDown, eventDown);
- // return an error code, if any, otherwise return Rx window (which is > 0)
+ state = this->parseDownlink(dataDown, lenDown, rxWindow, eventDown);
RADIOLIB_ASSERT(state);
+
+ // if in Class C, open up RxC window
+ if(this->lwClass == RADIOLIB_LORAWAN_CLASS_C) {
+ this->receiveClassC();
+ }
+
+ // return Rx window (which is > 0)
return(rxWindow);
}
@@ -220,15 +269,13 @@ void LoRaWANNode::clearNonces() {
this->keyCheckSum = 0;
this->devNonce = 0;
this->joinNonce = 0;
- this->isActive = false;
- this->rev = 0;
+ this->sessionStatus = RADIOLIB_LORAWAN_SESSION_NONE;
}
uint8_t* LoRaWANNode::getBufferNonces() {
// set the device credentials
LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL);
LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], this->lwMode);
- LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], this->lwClass);
LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum);
LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], this->keyCheckSum);
@@ -245,18 +292,23 @@ int16_t LoRaWANNode::setBufferNonces(const uint8_t* persistentBuffer) {
return(RADIOLIB_ERR_NONE);
}
+ // // this code can be used in case breaking chances must be caught:
+ // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION];
+ // if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) {
+ // // set default values for variables that are new or something
+ // }
+
int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE);
RADIOLIB_ASSERT(state);
bool isSameKeys = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_CHECKSUM]) == this->keyCheckSum;
bool isSameMode = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_MODE]) == this->lwMode;
- bool isSameClass = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_CLASS]) == this->lwClass;
bool isSamePlan = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_PLAN]) == this->band->bandNum;
// check if Nonces buffer matches the current configuration
- if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) {
+ if(!isSameKeys || !isSameMode || !isSamePlan) {
// if configuration did not match, discard whatever is currently in the buffers and start fresh
- RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (keys: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan);
+ RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (keys: %d, mode: %d, plan: %d)", isSameKeys, isSameMode, isSamePlan);
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Discarding the Nonces buffer:");
RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE);
return(RADIOLIB_ERR_NONCES_DISCARDED);
@@ -268,10 +320,6 @@ int16_t LoRaWANNode::setBufferNonces(const uint8_t* persistentBuffer) {
this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE]);
this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], 3);
- // revert to inactive as long as no session is restored
- this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false;
- this->isActive = false;
-
return(state);
}
@@ -279,8 +327,6 @@ void LoRaWANNode::clearSession() {
memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE);
memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
- this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false;
- this->isActive = false;
// reset all frame counters
this->fCntUp = 0;
@@ -290,74 +336,71 @@ void LoRaWANNode::clearSession() {
this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE;
this->adrFCnt = 0;
- // reset ADR state
+ // reset Tx steps and power limit
this->txPowerSteps = 0;
- this->nbTrans = 1;
+ this->txPowerMax = this->band->powerMax;
// clear CSMA settings
this->csmaEnabled = false;
this->maxChanges = 0;
this->difsSlots = 0;
this->backoffMax = 0;
+
+ // revert to default Class A
+ this->lwClass = RADIOLIB_LORAWAN_CLASS_A;
+
+ // reset all channels
+ memset(this->channels, 0, sizeof(this->channels));
+ memset(this->dynamicChannels, 0, sizeof(this->dynamicChannels));
+
+ // reset the JoinRequest datarate
+ this->channels[RADIOLIB_LORAWAN_UPLINK].dr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED;
+
+ // reset Rx2 channel to default value
+ this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2;
+
+ this->sessionStatus = RADIOLIB_LORAWAN_SESSION_NONE;
}
-void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) {
- this->clearSession();
+void LoRaWANNode::createSession() {
+ // set a seed for the pseudo-rng using a truly random value from radio noise
+ srand(this->phyLayer->random(INT32_MAX));
- // setup JoinRequest uplink/downlink frequencies and datarates
+ // setup default channels
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
- this->selectChannelPlanDyn();
- } else {
- this->selectChannelPlanFix();
- }
-
- uint8_t drUp = RADIOLIB_LORAWAN_DATA_RATE_UNUSED;
-
- // on fixed bands, the first OTAA uplink (JoinRequest) is sent on fixed datarate
- if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && lwMode == RADIOLIB_LORAWAN_MODE_OTAA) {
- // randomly select one of 8 or 9 channels and find corresponding datarate
- uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9;
- uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9
- if(rand <= 8) {
- drUp = this->band->txSpans[0].drJoinRequest; // if one of the first 8 channels, select datarate of span 0
- } else {
- drUp = this->band->txSpans[1].drJoinRequest; // if ninth channel, select datarate of span 1
- }
- } else {
- // on dynamic bands, the first OTAA uplink (JoinRequest) can be any available datarate
- // this is also true for ABP on both dynamic and fixed bands, as there is no JoinRequest
- if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
- uint8_t i = 0;
- for(; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) {
- if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) {
- if(initialDr >= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMin
- && initialDr <= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMax) {
- drUp = initialDr;
- break;
- }
- }
- }
- // if there is no channel that allowed the user-specified datarate, revert to default datarate
- if(i == RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) {
- RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr);
- initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED;
+ for(int num = 0; num < 3; num++) {
+ if(this->band->txFreqs[num].freq) {
+ // copy the channels from the current channel plan
+ this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num];
+ this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num];
}
}
-
- // if there is no (channel that allowed the) user-specified datarate, use a default datarate
- if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
- // use the specified datarate from the first channel (this is always defined)
- drUp = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][0].dr;
- }
}
+ this->enableDefaultChannels();
+ // set default MAC state
uint8_t cOcts[5]; // 5 = maximum downlink payload length
+
+ // set data rate and Tx power
uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR;
uint8_t cLen = 1; // only apply Dr/Tx field
- cOcts[0] = (drUp << 4); // set uplink datarate
- cOcts[0] |= 0; // default to max Tx Power
+
+ // DR and TxPower may have been configured before creating session,
+ // otherwise they are default values (see ::clearSession)
+ uint8_t drUp = this->channels[RADIOLIB_LORAWAN_UPLINK].dr;
+ if(drUp == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
+ if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
+ drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax + 1) / 2;
+ } else { // RADIOLIB_LORAWAN_BAND_FIXED
+ drUp = (this->band->txSpans[0].drMin + this->band->txSpans[0].drMax + 1) / 2;
+ }
+ }
+ uint8_t txSteps = this->txPowerSteps;
+ cOcts[0] = (drUp << 4);
+ cOcts[0] |= txSteps;
(void)execMacCommand(cid, cOcts, cLen);
+ // set maximum dutycycle
cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE;
this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
uint8_t maxDCyclePower = 0;
@@ -372,18 +415,21 @@ void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) {
cOcts[0] = maxDCyclePower;
(void)execMacCommand(cid, cOcts, cLen);
+ // set Rx2 frequency and datarate
cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP;
(void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
cOcts[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4);
- cOcts[0] |= this->channels[RADIOLIB_LORAWAN_DIR_RX2].dr; // may be set by user, otherwise band's default upon initialization
- LoRaWANNode::hton(&cOcts[1], this->channels[RADIOLIB_LORAWAN_DIR_RX2].freq, 3);
+ cOcts[0] |= this->channels[RADIOLIB_LORAWAN_RX2].dr; // user may override the Rx2 datarate
+ LoRaWANNode::hton(&cOcts[1], this->band->rx2.freq, 3);
(void)execMacCommand(cid, cOcts, cLen);
+ // set Rx1 and Rx2 delay
cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP;
(void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
cOcts[0] = (RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS / 1000);
(void)execMacCommand(cid, cOcts, cLen);
+ // set dwelltime and maximum Tx power
cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP;
(void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
cOcts[0] = (this->band->dwellTimeDn > 0 ? 1 : 0) << 5;
@@ -412,17 +458,22 @@ void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) {
cOcts[0] |= maxEIRPRaw;
(void)execMacCommand(cid, cOcts, cLen);
+ // set ADR backoff parameters
cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP;
(void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
cOcts[0] = (RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP << 4);
cOcts[0] |= RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP;
(void)execMacCommand(cid, cOcts, cLen);
+ // set Rejoin parameters
cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP;
(void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
cOcts[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4);
cOcts[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N;
(void)execMacCommand(cid, cOcts, cLen);
+
+ // set up a new session, ready for activation
+ this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVATING;
}
uint8_t* LoRaWANNode::getBufferSession() {
@@ -433,23 +484,19 @@ uint8_t* LoRaWANNode::getBufferSession() {
LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN], this->confFCntDown);
LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFCnt);
LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fCntUp);
-
- // store the enabled channels
- uint64_t chMaskGrp0123 = 0;
- uint32_t chMaskGrp45 = 0;
- this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45);
- LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, chMaskGrp0123);
- LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 9, chMaskGrp45);
-
- // store the available/unused channels
- uint16_t chMask = 0x0000;
- (void)this->getAvailableChannels(&chMask);
- LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], chMask);
-
+ LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS], this->lwClass);
+
// store the current uplink MAC command queue
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], this->fOptsUp, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], &this->fOptsUpLen, 1);
+ // store the channel masks and unused channel flags
+ memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, this->channelMasks, sizeof(this->channelMasks));
+ memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], this->channelFlags, sizeof(this->channelFlags));
+
+ // store the session status
+ LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_STATUS], this->sessionStatus);
+
// generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer
uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2);
LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SIGNATURE], signature);
@@ -478,13 +525,90 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) {
// copy the whole buffer over
memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE);
- //// this code can be used in case breaking chances must be caught:
- // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION];
- // if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) {
- // // set default values for variables that are new or something
- // }
+ // setup the default channels
+ if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
+ for(int num = 0; num < 3; num++) {
+ if(this->band->txFreqs[num].freq) {
+ // copy the channels from the current channel plan
+ this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num];
+ this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num];
+ }
+ }
+ }
+ this->enableDefaultChannels();
- // pull all authentication keys from persistent storage
+ uint8_t cOcts[14] = { 0 }; // see Wiki dev notes for this odd size
+ uint8_t cid;
+ uint8_t cLen;
+
+ // for dynamic bands, the additional channels must be restored per-channel
+ if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
+ // all-zero buffer used for checking if MAC commands are set
+ const uint8_t bufferZeroes[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 };
+
+ // restore the session channels
+ const uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS];
+
+ cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL;
+ (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
+ for(int i = 0; i < RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS; i++) {
+ memcpy(cOcts, startChannelsUp + (i * cLen), cLen);
+ if(memcmp(cOcts, bufferZeroes, cLen) != 0) { // only execute if it is not all zeroes
+ (void)execMacCommand(cid, cOcts, cLen);
+ }
+ }
+
+ const uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS];
+
+ cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL;
+ (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
+ for(int i = 0; i < RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS; i++) {
+ memcpy(cOcts, startChannelsDown + (i * cLen), cLen);
+ if(memcmp(cOcts, bufferZeroes, cLen) != 0) { // only execute if it is not all zeroes
+ (void)execMacCommand(cid, cOcts, cLen);
+ }
+ }
+ }
+
+ // restore the datarate and channels
+ cid = RADIOLIB_LORAWAN_MAC_LINK_ADR;
+ cLen = 14; // only apply Dr/Tx field
+ memcpy(cOcts, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cLen);
+ (void)execMacCommand(cid, cOcts, cLen);
+
+ // always restore the channels, so as to adhere to channel hopping between JoinRequests
+ memcpy(this->channelFlags, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS);
+
+ // restore the session status
+ this->sessionStatus = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_STATUS]);
+
+ // check if the session is active, if not, don't restore anything else
+ if(this->sessionStatus != RADIOLIB_LORAWAN_SESSION_ACTIVE) {
+ return(RADIOLIB_ERR_NETWORK_NOT_JOINED);
+ }
+
+ // restore the rest of the MAC state
+ const uint8_t cids[6] = {
+ RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP,
+ RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP,
+ RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP
+ };
+ const uint16_t locs[6] = {
+ RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE, RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP,
+ RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP, RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP,
+ RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP
+ };
+ for(uint8_t i = 0; i < 6; i++) {
+ (void)this->getMacLen(cids[i], &cLen, RADIOLIB_LORAWAN_DOWNLINK);
+ memcpy(cOcts, &this->bufferSession[locs[i]], cLen);
+ (void)execMacCommand(cids[i], cOcts, cLen);
+ }
+
+ // copy uplink MAC command queue back in place
+ memcpy(this->fOptsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
+ memcpy(&this->fOptsUpLen, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], 1);
+
+ // restore authentication keys
this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]);
memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE);
memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE);
@@ -493,7 +617,7 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) {
// restore session parameters
this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]);
- RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN session: v1.%d", this->rev);
+ this->lwClass = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS]);
this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]);
this->aFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]);
this->nFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]);
@@ -501,82 +625,9 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) {
this->confFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]);
this->adrFCnt = LoRaWANNode::ntoh