mirror of
https://github.com/liberatedsystems/RNode_Firmware_CE.git
synced 2024-10-01 03:15:40 -04:00
Merge branch 'interfaces'
This commit is contained in:
commit
fd688b987d
501
Boards.h
501
Boards.h
@ -13,17 +13,14 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Modem.h"
|
||||
#include "Interfaces.h"
|
||||
|
||||
#ifndef BOARDS_H
|
||||
#define BOARDS_H
|
||||
|
||||
#define PLATFORM_AVR 0x90
|
||||
#define PLATFORM_ESP32 0x80
|
||||
#define PLATFORM_NRF52 0x70
|
||||
|
||||
#define MCU_1284P 0x91
|
||||
#define MCU_2560 0x92
|
||||
#define MCU_ESP32 0x81
|
||||
#define MCU_NRF52 0x71
|
||||
|
||||
@ -47,13 +44,7 @@
|
||||
#define EINK_BW 0x02
|
||||
#define EINK_3C 0x03
|
||||
|
||||
#if defined(__AVR_ATmega1284P__)
|
||||
#define PLATFORM PLATFORM_AVR
|
||||
#define MCU_VARIANT MCU_1284P
|
||||
#elif defined(__AVR_ATmega2560__)
|
||||
#define PLATFORM PLATFORM_AVR
|
||||
#define MCU_VARIANT MCU_2560
|
||||
#elif defined(ESP32)
|
||||
#if defined(ESP32)
|
||||
#define PLATFORM PLATFORM_ESP32
|
||||
#define MCU_VARIANT MCU_ESP32
|
||||
#elif defined(NRF52840_XXAA)
|
||||
@ -64,16 +55,6 @@
|
||||
#error "The firmware cannot be compiled for the selected MCU variant"
|
||||
#endif
|
||||
|
||||
#ifndef MODEM
|
||||
#if BOARD_MODEL == BOARD_RAK4631
|
||||
#define MODEM SX1262
|
||||
#elif BOARD_MODEL == BOARD_GENERIC_NRF52
|
||||
#define MODEM SX1262
|
||||
#else
|
||||
#define MODEM SX1276
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define HAS_DISPLAY false
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE false
|
||||
@ -90,37 +71,7 @@
|
||||
#define HAS_TCXO true
|
||||
#endif
|
||||
|
||||
#if MCU_VARIANT == MCU_1284P
|
||||
const int pin_cs = 4;
|
||||
const int pin_reset = 3;
|
||||
const int pin_dio = 2;
|
||||
const int pin_led_rx = 12;
|
||||
const int pin_led_tx = 13;
|
||||
|
||||
#define BOARD_MODEL BOARD_RNODE
|
||||
#define HAS_EEPROM true
|
||||
#define CONFIG_UART_BUFFER_SIZE 6144
|
||||
#define CONFIG_QUEUE_SIZE 6144
|
||||
#define CONFIG_QUEUE_MAX_LENGTH 200
|
||||
#define EEPROM_SIZE 4096
|
||||
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
|
||||
|
||||
#elif MCU_VARIANT == MCU_2560
|
||||
const int pin_cs = 5;
|
||||
const int pin_reset = 4;
|
||||
const int pin_dio = 2;
|
||||
const int pin_led_rx = 12;
|
||||
const int pin_led_tx = 13;
|
||||
|
||||
#define BOARD_MODEL BOARD_HMBRW
|
||||
#define HAS_EEPROM true
|
||||
#define CONFIG_UART_BUFFER_SIZE 768
|
||||
#define CONFIG_QUEUE_SIZE 5120
|
||||
#define CONFIG_QUEUE_MAX_LENGTH 24
|
||||
#define EEPROM_SIZE 4096
|
||||
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
|
||||
|
||||
#elif MCU_VARIANT == MCU_ESP32
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
|
||||
// Board models for ESP32 based builds are
|
||||
// defined by the build target in the makefile.
|
||||
@ -129,7 +80,7 @@
|
||||
//
|
||||
// #define BOARD_MODEL BOARD_GENERIC_ESP32
|
||||
#define CONFIG_UART_BUFFER_SIZE 6144
|
||||
#define CONFIG_QUEUE_SIZE 6144
|
||||
#define CONFIG_QUEUE_0_SIZE 6144
|
||||
#define CONFIG_QUEUE_MAX_LENGTH 200
|
||||
|
||||
#define EEPROM_SIZE 1024
|
||||
@ -143,11 +94,33 @@
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
const int pin_cs = 4;
|
||||
const int pin_reset = 36;
|
||||
const int pin_dio = 39;
|
||||
#define INTERFACE_COUNT 1
|
||||
const int pin_led_rx = 14;
|
||||
const int pin_led_tx = 32;
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX127X};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX127X
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX127X
|
||||
{
|
||||
4, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
-1, // pin_busy
|
||||
39, // pin_dio
|
||||
36, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_TBEAM
|
||||
#define HAS_DISPLAY true
|
||||
@ -161,32 +134,68 @@
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
#define PMU_IRQ 35
|
||||
const int pin_cs = 18;
|
||||
const int pin_reset = 23;
|
||||
#define INTERFACE_COUNT 1
|
||||
const int pin_led_rx = 2;
|
||||
const int pin_led_tx = 4;
|
||||
|
||||
#if MODEM == SX1262
|
||||
#define HAS_TCXO true
|
||||
#define HAS_BUSY true
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
const int pin_busy = 32;
|
||||
const int pin_dio = 33;
|
||||
const int pin_tcxo_enable = -1;
|
||||
#else
|
||||
const int pin_dio = 26;
|
||||
#endif
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1262
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
true, // HAS_TCXO
|
||||
true // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1262
|
||||
{
|
||||
18, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
32, // pin_busy
|
||||
33, // pin_dio
|
||||
23, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_HUZZAH32
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
const int pin_cs = 4;
|
||||
const int pin_reset = 36;
|
||||
const int pin_dio = 39;
|
||||
#define INTERFACE_COUNT 1
|
||||
const int pin_led_rx = 14;
|
||||
const int pin_led_tx = 32;
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX127X};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX127X
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1262
|
||||
{
|
||||
4, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
-1, // pin_busy
|
||||
39, // pin_dio
|
||||
36, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_LORA32_V1_0
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
@ -194,6 +203,7 @@
|
||||
#define HAS_BLE true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define INTERFACE_COUNT 1
|
||||
const int pin_cs = 18;
|
||||
const int pin_reset = 14;
|
||||
const int pin_dio = 26;
|
||||
@ -205,6 +215,31 @@
|
||||
const int pin_led_tx = 2;
|
||||
#endif
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX1276};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1276
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1276
|
||||
{
|
||||
18, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
-1, // pin_busy
|
||||
26, // pin_dio
|
||||
14, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_LORA32_V2_0
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
@ -212,6 +247,7 @@
|
||||
#define HAS_BLE true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define INTERFACE_COUNT 1
|
||||
const int pin_cs = 18;
|
||||
const int pin_reset = 12;
|
||||
const int pin_dio = 26;
|
||||
@ -223,6 +259,32 @@
|
||||
const int pin_led_tx = 22;
|
||||
#endif
|
||||
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX127X};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX127X
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX127X
|
||||
{
|
||||
18, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
-1, // pin_busy
|
||||
26, // pin_dio
|
||||
14, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_LORA32_V2_1
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
@ -231,11 +293,33 @@
|
||||
#define HAS_PMU true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
const int pin_cs = 18;
|
||||
const int pin_reset = 23;
|
||||
const int pin_dio = 26;
|
||||
#define INTERFACE_COUNT 1
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX127X};
|
||||
#if HAS_TCXO == true
|
||||
const int pin_tcxo_enable = 33;
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX127X
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
true, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX127X
|
||||
{
|
||||
18, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
-1, // pin_busy
|
||||
26, // pin_dio
|
||||
23, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
33 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 15;
|
||||
@ -245,15 +329,40 @@
|
||||
const int pin_led_tx = 25;
|
||||
#endif
|
||||
|
||||
#if HAS_TCXO == false
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX127X
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX127X
|
||||
{
|
||||
18, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
-1, // pin_busy
|
||||
26, // pin_dio
|
||||
23, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#elif BOARD_MODEL == BOARD_HELTEC32_V2
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
const int pin_cs = 18;
|
||||
const int pin_reset = 14;
|
||||
const int pin_dio = 26;
|
||||
#define INTERFACE_COUNT 1
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 36;
|
||||
const int pin_led_tx = 37;
|
||||
@ -262,6 +371,31 @@
|
||||
const int pin_led_tx = 25;
|
||||
#endif
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX127X};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX127X
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX127X
|
||||
{
|
||||
18, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
-1, // pin_busy
|
||||
26, // pin_dio
|
||||
14, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_HELTEC32_V3
|
||||
#define IS_ESP32S3 true
|
||||
#define HAS_DISPLAY true
|
||||
@ -273,6 +407,7 @@
|
||||
#define HAS_SLEEP true
|
||||
#define PIN_WAKEUP GPIO_NUM_0
|
||||
#define WAKEUP_LEVEL 0
|
||||
#define INTERFACE_COUNT 1
|
||||
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
@ -284,20 +419,30 @@
|
||||
const int pin_led_tx = 35;
|
||||
#endif
|
||||
|
||||
#define MODEM SX1262
|
||||
#define HAS_TCXO true
|
||||
const int pin_tcxo_enable = -1;
|
||||
#define HAS_BUSY true
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
|
||||
// Following pins are for the SX1262
|
||||
const int pin_cs = 8;
|
||||
const int pin_busy = 13;
|
||||
const int pin_dio = 14;
|
||||
const int pin_reset = 12;
|
||||
const int pin_mosi = 10;
|
||||
const int pin_miso = 11;
|
||||
const int pin_sclk = 9;
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1262
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
true, // HAS_TCXO
|
||||
true // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1262
|
||||
{
|
||||
8, // pin_ss
|
||||
9, // pin_sclk
|
||||
10, // pin_mosi
|
||||
11, // pin_miso
|
||||
13, // pin_busy
|
||||
14, // pin_dio
|
||||
12, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_RNODE_NG_20
|
||||
#define HAS_DISPLAY true
|
||||
@ -306,6 +451,7 @@
|
||||
#define HAS_NP true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define INTERFACE_COUNT 1
|
||||
const int pin_cs = 18;
|
||||
const int pin_reset = 12;
|
||||
const int pin_dio = 26;
|
||||
@ -320,6 +466,32 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX1276};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1276
|
||||
{
|
||||
false, // DEFAULT_SPI
|
||||
true, // HAS_TCXO
|
||||
true // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const uint8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1276
|
||||
{
|
||||
8, // pin_ss
|
||||
9, // pin_sclk
|
||||
10, // pin_mosi
|
||||
11, // pin_miso
|
||||
13, // pin_busy
|
||||
14, // pin_dio
|
||||
12, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_RNODE_NG_21
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
@ -329,9 +501,7 @@
|
||||
#define HAS_NP true
|
||||
#define HAS_SD false
|
||||
#define HAS_EEPROM true
|
||||
const int pin_cs = 18;
|
||||
const int pin_reset = 23;
|
||||
const int pin_dio = 26;
|
||||
#define INTERFACE_COUNT 1
|
||||
const int pin_np = 12;
|
||||
const int pin_dac = 25;
|
||||
const int pin_adc = 34;
|
||||
@ -349,12 +519,34 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX127X};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX127X
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const uint8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX127X
|
||||
{
|
||||
18, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
-1, // pin_busy
|
||||
26, // pin_dio
|
||||
23, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_RNODE_NG_22
|
||||
#define IS_ESP32S3 true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_TCXO true
|
||||
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
@ -370,19 +562,10 @@
|
||||
#define HAS_SLEEP true
|
||||
#define PIN_WAKEUP GPIO_NUM_0
|
||||
#define WAKEUP_LEVEL 0
|
||||
#define INTERFACE_COUNT 1
|
||||
// #define PIN_DISP_SLEEP 21
|
||||
// #define DISP_SLEEP_LEVEL HIGH
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
const int pin_cs = 7;
|
||||
const int pin_reset = 8;
|
||||
const int pin_sclk = 5;
|
||||
const int pin_mosi = 6;
|
||||
const int pin_miso = 3;
|
||||
const int pin_tcxo_enable = -1;
|
||||
|
||||
const int pin_dio = 33;
|
||||
const int pin_busy = 34;
|
||||
|
||||
const int pin_np = 38;
|
||||
const int pin_dac = 25;
|
||||
@ -402,6 +585,32 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1262
|
||||
{
|
||||
false, // DEFAULT_SPI
|
||||
true, // HAS_TCXO
|
||||
true // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const uint8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1262
|
||||
{
|
||||
7, // pin_ss
|
||||
5, // pin_sclk
|
||||
6, // pin_mosi
|
||||
3, // pin_miso
|
||||
34, // pin_busy
|
||||
33, // pin_dio
|
||||
8, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
#error An unsupported ESP32 board was selected. Cannot compile RNode firmware.
|
||||
#endif
|
||||
@ -410,34 +619,60 @@
|
||||
#if BOARD_MODEL == BOARD_RAK4631
|
||||
#define HAS_EEPROM false
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY EINK_3C
|
||||
#define DISPLAY EINK_BW
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE true
|
||||
#define HAS_CONSOLE false
|
||||
#define HAS_PMU true
|
||||
#define HAS_NP false
|
||||
#define HAS_SD false
|
||||
#define HAS_TCXO true
|
||||
#define HAS_RF_SWITCH_RX_TX true
|
||||
#define HAS_BUSY true
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
#define CONFIG_UART_BUFFER_SIZE 6144
|
||||
#define CONFIG_QUEUE_SIZE 6144
|
||||
#define CONFIG_QUEUE_0_SIZE 6144
|
||||
#define CONFIG_QUEUE_MAX_LENGTH 200
|
||||
#define EEPROM_SIZE 296
|
||||
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
|
||||
#define BLE_MANUFACTURER "RAK Wireless"
|
||||
#define BLE_MODEL "RAK4640"
|
||||
|
||||
// Following pins are for the sx1262
|
||||
const int pin_rxen = 37;
|
||||
const int pin_reset = 38;
|
||||
const int pin_cs = 42;
|
||||
const int pin_sclk = 43;
|
||||
const int pin_mosi = 44;
|
||||
const int pin_miso = 45;
|
||||
const int pin_busy = 46;
|
||||
const int pin_dio = 47;
|
||||
#define INTERFACE_COUNT 1
|
||||
|
||||
// first interface in list is the primary
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1262
|
||||
{
|
||||
false, // DEFAULT_SPI
|
||||
true, // HAS_TCXO
|
||||
true // DIO2_AS_RF_SWITCH
|
||||
}
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1262
|
||||
{
|
||||
42, // pin_ss
|
||||
43, // pin_sclk
|
||||
44, // pin_mosi
|
||||
45, // pin_miso
|
||||
46, // pin_busy
|
||||
47, // pin_dio
|
||||
38, // pin_reset
|
||||
-1, // pin_txen
|
||||
37, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#define INTERFACE_SPI
|
||||
// Required because on RAK4631, non-default SPI pins must be initialised when class is declared.
|
||||
const SPIClass interface_spi[1] = {
|
||||
// SX1262
|
||||
SPIClass(
|
||||
NRF_SPIM2,
|
||||
interface_pins[0][3],
|
||||
interface_pins[0][1],
|
||||
interface_pins[0][2]
|
||||
)
|
||||
};
|
||||
|
||||
const int pin_disp_cs = SS;
|
||||
const int pin_disp_dc = WB_IO1;
|
||||
@ -447,25 +682,15 @@
|
||||
|
||||
const int pin_led_rx = LED_BLUE;
|
||||
const int pin_led_tx = LED_GREEN;
|
||||
const int pin_tcxo_enable = -1;
|
||||
|
||||
#else
|
||||
#error An unsupported nRF board was selected. Cannot compile RNode firmware.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAS_RF_SWITCH_RX_TX
|
||||
const int pin_rxen = -1;
|
||||
const int pin_txen = -1;
|
||||
#ifndef INTERFACE_SPI
|
||||
// Even if custom SPI interfaces are not needed, the array must exist to prevent compilation errors.
|
||||
#define INTERFACE_SPI
|
||||
const SPIClass interface_spi[1];
|
||||
#endif
|
||||
|
||||
#ifndef HAS_BUSY
|
||||
const int pin_busy = -1;
|
||||
#endif
|
||||
|
||||
#ifndef DIO2_AS_RF_SWITCH
|
||||
#define DIO2_AS_RF_SWITCH false
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
89
Config.h
89
Config.h
@ -43,7 +43,7 @@
|
||||
#define M_FRQ_S 27388122
|
||||
#define M_FRQ_R 27388061
|
||||
bool console_active = false;
|
||||
bool modem_installed = false;
|
||||
bool modems_installed = false;
|
||||
|
||||
#define MTU 508
|
||||
#define SINGLE_MTU 255
|
||||
@ -51,13 +51,10 @@
|
||||
#define MIN_L 1
|
||||
#define CMD_L 64
|
||||
|
||||
bool mw_radio_online = false;
|
||||
|
||||
#define eeprom_addr(a) (a+EEPROM_OFFSET)
|
||||
|
||||
#if (MODEM == SX1262 || MODEM == SX1280) && defined(NRF52840_XXAA)
|
||||
SPIClass spiModem(NRF_SPIM2, pin_miso, pin_sclk, pin_mosi);
|
||||
#endif
|
||||
#define PA_OUTPUT_RFO_PIN 0
|
||||
#define PA_OUTPUT_PA_BOOST_PIN 1
|
||||
|
||||
// MCU independent configuration parameters
|
||||
const long serial_baudrate = 115200;
|
||||
@ -66,36 +63,15 @@
|
||||
// packet RSSI register
|
||||
const int rssi_offset = 157;
|
||||
|
||||
// Default LoRa settings
|
||||
const int lora_rx_turnaround_ms = 66;
|
||||
const int lora_post_tx_yield_slots = 6;
|
||||
uint32_t post_tx_yield_timeout = 0;
|
||||
#define LORA_PREAMBLE_SYMBOLS_HW 4
|
||||
#define LORA_PREAMBLE_SYMBOLS_MIN 18
|
||||
#define LORA_PREAMBLE_TARGET_MS 15
|
||||
#define LORA_CAD_SYMBOLS 3
|
||||
int csma_slot_ms = 50;
|
||||
float csma_p_min = 0.1;
|
||||
float csma_p_max = 0.8;
|
||||
uint8_t csma_p = 0;
|
||||
|
||||
int lora_sf = 0;
|
||||
int lora_cr = 5;
|
||||
int lora_txp = 0xFF;
|
||||
uint32_t lora_bw = 0;
|
||||
uint32_t lora_freq = 0;
|
||||
uint32_t lora_bitrate = 0;
|
||||
long lora_preamble_symbols = 6;
|
||||
float lora_symbol_time_ms = 0.0;
|
||||
float lora_symbol_rate = 0.0;
|
||||
float lora_us_per_byte = 0.0;
|
||||
// Default LoRa settings
|
||||
const int lora_rx_turnaround_ms = 66;
|
||||
const int lora_post_tx_yield_slots = 6;
|
||||
#define LORA_CAD_SYMBOLS 3
|
||||
|
||||
// Operational variables
|
||||
bool radio_locked = true;
|
||||
bool radio_online = false;
|
||||
bool community_fw = true;
|
||||
bool hw_ready = false;
|
||||
bool radio_error = false;
|
||||
bool disp_ready = false;
|
||||
bool pmu_ready = false;
|
||||
bool promisc = false;
|
||||
@ -106,7 +82,6 @@
|
||||
uint8_t model = 0x00;
|
||||
uint8_t hwrev = 0x00;
|
||||
|
||||
int current_rssi = -292;
|
||||
int last_rssi = -292;
|
||||
uint8_t last_rssi_raw = 0x00;
|
||||
uint8_t last_snr_raw = 0x80;
|
||||
@ -125,48 +100,8 @@
|
||||
uint32_t stat_rx = 0;
|
||||
uint32_t stat_tx = 0;
|
||||
|
||||
#define STATUS_INTERVAL_MS 3
|
||||
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
#define DCD_SAMPLES 2500
|
||||
#define UTIL_UPDATE_INTERVAL_MS 1000
|
||||
#define UTIL_UPDATE_INTERVAL (UTIL_UPDATE_INTERVAL_MS/STATUS_INTERVAL_MS)
|
||||
#define AIRTIME_LONGTERM 3600
|
||||
#define AIRTIME_LONGTERM_MS (AIRTIME_LONGTERM*1000)
|
||||
#define AIRTIME_BINLEN_MS (STATUS_INTERVAL_MS*DCD_SAMPLES)
|
||||
#define AIRTIME_BINS ((AIRTIME_LONGTERM*1000)/AIRTIME_BINLEN_MS)
|
||||
bool util_samples[DCD_SAMPLES];
|
||||
uint16_t airtime_bins[AIRTIME_BINS];
|
||||
float longterm_bins[AIRTIME_BINS];
|
||||
int dcd_sample = 0;
|
||||
float local_channel_util = 0.0;
|
||||
float total_channel_util = 0.0;
|
||||
float longterm_channel_util = 0.0;
|
||||
float airtime = 0.0;
|
||||
float longterm_airtime = 0.0;
|
||||
#define current_airtime_bin(void) (millis()%AIRTIME_LONGTERM_MS)/AIRTIME_BINLEN_MS
|
||||
#endif
|
||||
float st_airtime_limit = 0.0;
|
||||
float lt_airtime_limit = 0.0;
|
||||
bool airtime_lock = false;
|
||||
|
||||
bool stat_signal_detected = false;
|
||||
bool stat_signal_synced = false;
|
||||
bool stat_rx_ongoing = false;
|
||||
bool dcd = false;
|
||||
bool dcd_led = false;
|
||||
bool dcd_waiting = false;
|
||||
long dcd_wait_until = 0;
|
||||
uint16_t dcd_count = 0;
|
||||
uint16_t dcd_threshold = 2;
|
||||
|
||||
uint32_t status_interval_ms = STATUS_INTERVAL_MS;
|
||||
uint32_t last_status_update = 0;
|
||||
uint32_t last_dcd = 0;
|
||||
|
||||
// Status flags
|
||||
const uint8_t SIG_DETECT = 0x01;
|
||||
const uint8_t SIG_SYNCED = 0x02;
|
||||
const uint8_t RX_ONGOING = 0x04;
|
||||
unsigned long last_tx = 0;
|
||||
unsigned long last_rx = 0;
|
||||
|
||||
// Power management
|
||||
#define BATTERY_STATE_DISCHARGING 0x01
|
||||
@ -192,4 +127,10 @@
|
||||
#define START_FROM_BROWNOUT 0x03
|
||||
#define START_FROM_JTAG 0x04
|
||||
|
||||
// Subinterfaces
|
||||
// select interface 0 by default
|
||||
uint8_t interface = 0;
|
||||
RadioInterface* selected_radio;
|
||||
RadioInterface* interface_obj[INTERFACE_COUNT];
|
||||
RadioInterface* interface_obj_sorted[INTERFACE_COUNT];
|
||||
#endif
|
||||
|
237
Display.h
237
Display.h
@ -41,18 +41,18 @@ void busyCallback(const void* p) {
|
||||
|
||||
#include "Fonts/Org_01.h"
|
||||
#if BOARD_MODEL == BOARD_RNODE_NG_20 || BOARD_MODEL == BOARD_LORA32_V2_0
|
||||
#if BOARD_TYPE == OLED
|
||||
#if DISPLAY == OLED
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
#endif
|
||||
#elif BOARD_MODEL == BOARD_TBEAM
|
||||
#if BOARD_TYPE == OLED
|
||||
#if DISPLAY == OLED
|
||||
#define DISP_RST 13
|
||||
#define DISP_ADDR 0x3C
|
||||
#define DISP_CUSTOM_ADDR true
|
||||
#endif
|
||||
#elif BOARD_MODEL == BOARD_HELTEC32_V2 || BOARD_MODEL == BOARD_LORA32_V1_0
|
||||
#if BOARD_TYPE == OLED
|
||||
#if DISPLAY == OLED
|
||||
#define DISP_RST 16
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 15
|
||||
@ -64,12 +64,12 @@ void busyCallback(const void* p) {
|
||||
#define SCL_OLED 18
|
||||
#define SDA_OLED 17
|
||||
#elif BOARD_MODEL == BOARD_RNODE_NG_21
|
||||
#if BOARD_TYPE == OLED
|
||||
#if DISPLAY == OLED
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
#endif
|
||||
#elif BOARD_MODEL == BOARD_RNODE_NG_22
|
||||
#if BOARD_TYPE == OLED
|
||||
#if DISPLAY == OLED
|
||||
#define DISP_RST 21
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 17
|
||||
@ -130,10 +130,23 @@ unsigned char fb[512];
|
||||
uint32_t last_disp_update = 0;
|
||||
int disp_update_interval = 1000/disp_target_fps;
|
||||
uint32_t last_page_flip = 0;
|
||||
uint32_t last_interface_page_flip = 0;
|
||||
int page_interval = 4000;
|
||||
bool device_signatures_ok();
|
||||
bool device_firmware_ok();
|
||||
|
||||
bool stat_area_initialised = false;
|
||||
bool radio_online = false;
|
||||
|
||||
#define START_PAGE 0
|
||||
const uint8_t pages = 3;
|
||||
uint8_t disp_page = START_PAGE;
|
||||
uint8_t interface_page = START_PAGE;
|
||||
|
||||
uint8_t online_interface_list[INTERFACE_COUNT] = {0};
|
||||
|
||||
uint8_t online_interfaces = 0;
|
||||
|
||||
#if DISPLAY == OLED
|
||||
#define WATERFALL_SIZE 46
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
@ -142,8 +155,8 @@ bool device_firmware_ok();
|
||||
// add more eink compatible boards here
|
||||
#endif
|
||||
|
||||
int waterfall[WATERFALL_SIZE];
|
||||
int waterfall_head = 0;
|
||||
int waterfall[INTERFACE_COUNT][WATERFALL_SIZE] = {0};
|
||||
int waterfall_head[INTERFACE_COUNT] = {0};
|
||||
|
||||
int p_ad_x = 0;
|
||||
int p_ad_y = 0;
|
||||
@ -175,8 +188,8 @@ void update_area_positions() {
|
||||
uint8_t display_contrast = 0x00;
|
||||
#if DISPLAY == OLED
|
||||
void set_contrast(Adafruit_SSD1306 *display, uint8_t contrast) {
|
||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
||||
display.ssd1306_command(contrast);
|
||||
display->ssd1306_command(SSD1306_SETCONTRAST);
|
||||
display->ssd1306_command(contrast);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -286,9 +299,6 @@ bool display_init() {
|
||||
#endif
|
||||
|
||||
update_area_positions();
|
||||
for (int i = 0; i < WATERFALL_SIZE; i++) {
|
||||
waterfall[i] = 0;
|
||||
}
|
||||
|
||||
last_page_flip = millis();
|
||||
|
||||
@ -359,34 +369,63 @@ void draw_bt_icon(int px, int py) {
|
||||
}
|
||||
}
|
||||
|
||||
void draw_lora_icon(int px, int py) {
|
||||
void draw_lora_icon(RadioInterface* radio, int px, int py) {
|
||||
// todo: make display show other interfaces
|
||||
if (radio_online) {
|
||||
#if DISPLAY == OLED
|
||||
stat_area.drawBitmap(px, py, bm_rf+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
stat_area.drawBitmap(px, py, bm_rf+1*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
#endif
|
||||
} else {
|
||||
#if DISPLAY == OLED
|
||||
stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
stat_area.drawBitmap(px, py, bm_rf+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
#endif
|
||||
}
|
||||
#if DISPLAY == OLED
|
||||
if (online_interface_list[interface_page] == radio->getIndex()) {
|
||||
stat_area.drawBitmap(px - 1, py-1, bm_dot_sqr, 18, 19, SSD1306_WHITE, SSD1306_BLACK);
|
||||
|
||||
// redraw stat area on next refresh
|
||||
stat_area_initialised = false;
|
||||
}
|
||||
if (radio->getRadioOnline()) {
|
||||
stat_area.drawBitmap(px, py, bm_rf+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
} else {
|
||||
stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
}
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
if (online_interface_list[interface_page] == radio->getIndex()) {
|
||||
stat_area.drawBitmap(px - 2, py - 2, bm_dot_sqr, 34, 36, GxEPD_WHITE, GxEPD_BLACK);
|
||||
|
||||
// redraw stat area on next refresh
|
||||
stat_area_initialised = false;
|
||||
}
|
||||
if (radio->getRadioOnline()) {
|
||||
stat_area.drawBitmap(px, py, bm_rf+1*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
} else {
|
||||
stat_area.drawBitmap(px, py, bm_rf+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if DISPLAY == OLED
|
||||
stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
stat_area.drawBitmap(px, py, bm_rf+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void draw_mw_icon(int px, int py) {
|
||||
if (mw_radio_online) {
|
||||
#if DISPLAY == OLED
|
||||
stat_area.drawBitmap(px, py, bm_rf+3*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
stat_area.drawBitmap(px, py, bm_rf+3*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
#endif
|
||||
if (INTERFACE_COUNT >= 2) {
|
||||
if (interface_obj[1]->getRadioOnline()) {
|
||||
#if DISPLAY == OLED
|
||||
stat_area.drawBitmap(px, py, bm_rf+3*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
stat_area.drawBitmap(px, py, bm_rf+3*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
#endif
|
||||
} else {
|
||||
#if DISPLAY == OLED
|
||||
stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
stat_area.drawBitmap(px, py, bm_rf+2*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
#if DISPLAY == OLED
|
||||
stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
stat_area.drawBitmap(px, py, bm_rf+2*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
stat_area.drawBitmap(px, py, bm_rf+2*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -479,7 +518,7 @@ void draw_battery_bars(int px, int py) {
|
||||
void draw_quality_bars(int px, int py) {
|
||||
signed char t_snr = (signed int)last_snr_raw;
|
||||
int snr_int = (int)t_snr;
|
||||
float snr_min = Q_SNR_MIN_BASE-(int)lora_sf*Q_SNR_STEP;
|
||||
float snr_min = Q_SNR_MIN_BASE-(int)interface_obj[interface_page]->getSpreadingFactor()*Q_SNR_STEP;
|
||||
float snr_span = (Q_SNR_MAX-snr_min);
|
||||
float snr = ((int)snr_int) * 0.25;
|
||||
float quality = ((snr-snr_min)/(snr_span))*100;
|
||||
@ -593,13 +632,13 @@ void draw_signal_bars(int px, int py) {
|
||||
#define WF_PIXEL_WIDTH 22
|
||||
#endif
|
||||
void draw_waterfall(int px, int py) {
|
||||
int rssi_val = current_rssi;
|
||||
int rssi_val = interface_obj[interface_page]->currentRssi();
|
||||
if (rssi_val < WF_RSSI_MIN) rssi_val = WF_RSSI_MIN;
|
||||
if (rssi_val > WF_RSSI_MAX) rssi_val = WF_RSSI_MAX;
|
||||
int rssi_normalised = ((rssi_val - WF_RSSI_MIN)*(1.0/WF_RSSI_SPAN))*WF_PIXEL_WIDTH;
|
||||
|
||||
waterfall[waterfall_head++] = rssi_normalised;
|
||||
if (waterfall_head >= WATERFALL_SIZE) waterfall_head = 0;
|
||||
waterfall[interface_page][waterfall_head[interface_page]++] = rssi_normalised;
|
||||
if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0;
|
||||
|
||||
#if DISPLAY == OLED
|
||||
stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, SSD1306_BLACK);
|
||||
@ -607,8 +646,8 @@ void draw_waterfall(int px, int py) {
|
||||
stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, GxEPD_BLACK);
|
||||
#endif
|
||||
for (int i = 0; i < WATERFALL_SIZE; i++){
|
||||
int wi = (waterfall_head+i)%WATERFALL_SIZE;
|
||||
int ws = waterfall[wi];
|
||||
int wi = (waterfall_head[interface_page]+i)%WATERFALL_SIZE;
|
||||
int ws = waterfall[interface_page][wi];
|
||||
if (ws > 0) {
|
||||
#if DISPLAY == OLED
|
||||
stat_area.drawLine(px, py+i, px+ws-1, py+i, SSD1306_WHITE);
|
||||
@ -619,7 +658,6 @@ void draw_waterfall(int px, int py) {
|
||||
}
|
||||
}
|
||||
|
||||
bool stat_area_initialised = false;
|
||||
void draw_stat_area() {
|
||||
if (device_init_done) {
|
||||
if (!stat_area_initialised) {
|
||||
@ -631,19 +669,69 @@ void draw_stat_area() {
|
||||
stat_area_initialised = true;
|
||||
}
|
||||
|
||||
if (millis()-last_interface_page_flip >= page_interval) {
|
||||
int online_interfaces_check = 0;
|
||||
|
||||
// todo, is there a more efficient way of doing this?
|
||||
for (int i = 0; i < INTERFACE_COUNT; i++) {
|
||||
if (interface_obj[i]->getRadioOnline()) {
|
||||
online_interfaces_check++;
|
||||
}
|
||||
}
|
||||
|
||||
if (online_interfaces != online_interfaces_check) {
|
||||
online_interfaces = online_interfaces_check;
|
||||
}
|
||||
|
||||
// cap at two for now, as only two boxes to symbolise interfaces
|
||||
// available on display
|
||||
if (online_interfaces > 2) {
|
||||
online_interfaces = 2;
|
||||
}
|
||||
|
||||
uint8_t index = 0;
|
||||
|
||||
for (int i = 0; i < INTERFACE_COUNT; i++) {
|
||||
if (interface_obj[i]->getRadioOnline()) {
|
||||
online_interface_list[index] = i;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (online_interfaces > 0) {
|
||||
interface_page = (++interface_page%online_interfaces);
|
||||
}
|
||||
last_interface_page_flip = millis();
|
||||
}
|
||||
|
||||
#if DISPLAY == OLED
|
||||
draw_cable_icon(3, 8);
|
||||
draw_bt_icon(3, 30);
|
||||
draw_lora_icon(45, 8);
|
||||
draw_mw_icon(45, 30);
|
||||
draw_lora_icon(interface_obj[0], 45, 8);
|
||||
|
||||
// todo, expand support to show more than two interfaces on screen
|
||||
if (INTERFACE_COUNT > 1) {
|
||||
draw_lora_icon(interface_obj[1], 45, 30);
|
||||
}
|
||||
draw_battery_bars(4, 58);
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
draw_cable_icon(6, 18);
|
||||
draw_bt_icon(6, 60);
|
||||
draw_lora_icon(86, 18);
|
||||
draw_mw_icon(86, 60);
|
||||
draw_lora_icon(interface_obj[0], 86, 18);
|
||||
|
||||
// todo, expand support to show more than two interfaces on screen
|
||||
if (INTERFACE_COUNT > 1) {
|
||||
draw_lora_icon(interface_obj[1], 86, 60);
|
||||
}
|
||||
draw_battery_bars(8, 113);
|
||||
#endif
|
||||
radio_online = false;
|
||||
for (int i = 0; i < INTERFACE_COUNT; i++) {
|
||||
if (interface_obj[i]->getRadioOnline()) {
|
||||
radio_online = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (radio_online) {
|
||||
#if DISPLAY == OLED
|
||||
draw_quality_bars(28, 56);
|
||||
@ -701,9 +789,6 @@ void update_stat_area() {
|
||||
}
|
||||
}
|
||||
|
||||
#define START_PAGE 0
|
||||
const uint8_t pages = 3;
|
||||
uint8_t disp_page = START_PAGE;
|
||||
void draw_disp_area() {
|
||||
if (!device_init_done || firmware_update_mode) {
|
||||
uint8_t p_by = 37;
|
||||
@ -726,6 +811,7 @@ void draw_disp_area() {
|
||||
if (!disp_ext_fb or bt_ssp_pin != 0) {
|
||||
if (radio_online && display_diagnostics) {
|
||||
#if DISPLAY == OLED
|
||||
selected_radio = interface_obj[online_interface_list[interface_page]];
|
||||
disp_area.fillRect(0,8,disp_area.width(),37, SSD1306_BLACK); disp_area.fillRect(0,37,disp_area.width(),27, SSD1306_WHITE);
|
||||
disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(SSD1306_WHITE);
|
||||
|
||||
@ -734,26 +820,26 @@ void draw_disp_area() {
|
||||
disp_area.setCursor(14, 13);
|
||||
disp_area.print("@");
|
||||
disp_area.setCursor(21, 13);
|
||||
disp_area.printf("%.1fKbps", (float)lora_bitrate/1000.0);
|
||||
disp_area.printf("%.1fKbps", (float)(selected_radio->getBitrate())/1000.0);
|
||||
|
||||
disp_area.setCursor(2, 23-1);
|
||||
disp_area.print("Airtime:");
|
||||
|
||||
disp_area.setCursor(11, 33-1);
|
||||
if (total_channel_util < 0.099) {
|
||||
disp_area.printf("%.1f%%", airtime*100.0);
|
||||
if (selected_radio->getTotalChannelUtil() < 0.099) {
|
||||
disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0);
|
||||
} else {
|
||||
disp_area.printf("%.0f%%", airtime*100.0);
|
||||
disp_area.printf("%.0f%%", selected_radio->getAirtime()*100.0);
|
||||
}
|
||||
|
||||
disp_area.drawBitmap(2, 26-1, bm_hg_low, 5, 9, SSD1306_WHITE, SSD1306_BLACK);
|
||||
|
||||
disp_area.setCursor(32+11, 33-1);
|
||||
|
||||
if (longterm_channel_util < 0.099) {
|
||||
disp_area.printf("%.1f%%", longterm_airtime*100.0);
|
||||
if (selected_radio->getLongtermChannelUtil() < 0.099) {
|
||||
disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0);
|
||||
} else {
|
||||
disp_area.printf("%.0f%%", longterm_airtime*100.0);
|
||||
disp_area.printf("%.0f%%", selected_radio->getLongtermAirtime()*100.0);
|
||||
}
|
||||
disp_area.drawBitmap(32+2, 26-1, bm_hg_high, 5, 9, SSD1306_WHITE, SSD1306_BLACK);
|
||||
|
||||
@ -765,22 +851,23 @@ void draw_disp_area() {
|
||||
disp_area.print("Load:");
|
||||
|
||||
disp_area.setCursor(11, 57);
|
||||
if (total_channel_util < 0.099) {
|
||||
disp_area.printf("%.1f%%", total_channel_util*100.0);
|
||||
if (selected_radio->getTotalChannelUtil() < 0.099) {
|
||||
disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0);
|
||||
} else {
|
||||
disp_area.printf("%.0f%%", total_channel_util*100.0);
|
||||
disp_area.printf("%.0f%%", selected_radio->getTotalChannelUtil()*100.0);
|
||||
}
|
||||
disp_area.drawBitmap(2, 50, bm_hg_low, 5, 9, SSD1306_BLACK, SSD1306_WHITE);
|
||||
|
||||
disp_area.setCursor(32+11, 57);
|
||||
if (longterm_channel_util < 0.099) {
|
||||
disp_area.printf("%.1f%%", longterm_channel_util*100.0);
|
||||
if (selected_radio->getLongtermChannelUtil() < 0.099) {
|
||||
disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0);
|
||||
} else {
|
||||
disp_area.printf("%.0f%%", longterm_channel_util*100.0);
|
||||
disp_area.printf("%.0f%%", selected_radio->getLongtermChannelUtil()*100.0);
|
||||
}
|
||||
disp_area.drawBitmap(32+2, 50, bm_hg_high, 5, 9, SSD1306_BLACK, SSD1306_WHITE);
|
||||
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
selected_radio = interface_obj[online_interface_list[interface_page]];
|
||||
disp_area.fillRect(0,12,disp_area.width(),57, GxEPD_BLACK); disp_area.fillRect(0,69,disp_area.width(),56, GxEPD_WHITE);
|
||||
disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(GxEPD_WHITE);
|
||||
disp_area.setTextSize(2); // scale text 2x
|
||||
@ -790,25 +877,25 @@ void draw_disp_area() {
|
||||
disp_area.setCursor(14*2, 22);
|
||||
disp_area.print("@");
|
||||
disp_area.setCursor(21*2, 22);
|
||||
disp_area.printf("%.1fKbps", (float)lora_bitrate/1000.0);
|
||||
disp_area.printf("%.1fKbps", (float)(selected_radio->getBitrate())/1000.0);
|
||||
|
||||
disp_area.setCursor(2, 36);
|
||||
disp_area.print("Airtime:");
|
||||
|
||||
disp_area.setCursor(7+12, 53);
|
||||
if (total_channel_util < 0.099) {
|
||||
disp_area.printf("%.1f%%", airtime*100.0);
|
||||
if (selected_radio->getTotalChannelUtil() < 0.099) {
|
||||
disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0);
|
||||
} else {
|
||||
disp_area.printf("%.0f%%", airtime*100.0);
|
||||
disp_area.printf("%.0f%%", selected_radio->getAirtime()*100.0);
|
||||
}
|
||||
|
||||
disp_area.drawBitmap(2, 41, bm_hg_low, 10, 18, GxEPD_WHITE, GxEPD_BLACK);
|
||||
|
||||
disp_area.setCursor(64+17, 53);
|
||||
if (longterm_channel_util < 0.099) {
|
||||
disp_area.printf("%.1f%%", longterm_airtime*100.0);
|
||||
if (selected_radio->getLongtermChannelUtil() < 0.099) {
|
||||
disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0);
|
||||
} else {
|
||||
disp_area.printf("%.0f%%", longterm_airtime*100.0);
|
||||
disp_area.printf("%.0f%%", selected_radio->getLongtermAirtime()*100.0);
|
||||
}
|
||||
disp_area.drawBitmap(64, 41, bm_hg_high, 10, 18, GxEPD_WHITE, GxEPD_BLACK);
|
||||
|
||||
@ -820,18 +907,18 @@ void draw_disp_area() {
|
||||
disp_area.print("Load:");
|
||||
|
||||
disp_area.setCursor(7+12, 110);
|
||||
if (total_channel_util < 0.099) {
|
||||
disp_area.printf("%.1f%%", total_channel_util*100.0);
|
||||
if (selected_radio->getTotalChannelUtil() < 0.099) {
|
||||
disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0);
|
||||
} else {
|
||||
disp_area.printf("%.0f%%", total_channel_util*100.0);
|
||||
disp_area.printf("%.0f%%", selected_radio->getTotalChannelUtil()*100.0);
|
||||
}
|
||||
disp_area.drawBitmap(2, 98, bm_hg_low, 10, 18, GxEPD_BLACK, GxEPD_WHITE);
|
||||
|
||||
disp_area.setCursor(64+17, 110);
|
||||
if (longterm_channel_util < 0.099) {
|
||||
disp_area.printf("%.1f%%", longterm_channel_util*100.0);
|
||||
if (selected_radio->getLongtermChannelUtil() < 0.099) {
|
||||
disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0);
|
||||
} else {
|
||||
disp_area.printf("%.0f%%", longterm_channel_util*100.0);
|
||||
disp_area.printf("%.0f%%", selected_radio->getLongtermChannelUtil()*100.0);
|
||||
}
|
||||
disp_area.drawBitmap(64, 98, bm_hg_high, 10, 18, GxEPD_BLACK, GxEPD_WHITE);
|
||||
#endif
|
||||
@ -852,7 +939,7 @@ void draw_disp_area() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!hw_ready || radio_error || !device_firmware_ok()) {
|
||||
if (!hw_ready || !device_firmware_ok()) {
|
||||
if (!device_firmware_ok()) {
|
||||
#if DISPLAY == OLED
|
||||
disp_area.drawBitmap(0, 37, bm_fw_corrupt, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK);
|
||||
@ -860,7 +947,7 @@ void draw_disp_area() {
|
||||
disp_area.drawBitmap(0, 71, bm_fw_corrupt, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK);
|
||||
#endif
|
||||
} else {
|
||||
if (!modem_installed) {
|
||||
if (!modems_installed) {
|
||||
#if DISPLAY == OLED
|
||||
disp_area.drawBitmap(0, 37, bm_no_radio, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK);
|
||||
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
|
||||
|
@ -10,6 +10,11 @@ This entry should include, at a minimum, the following:
|
||||
* whether the modem has a busy pin
|
||||
* RX and TX leds (preferably LEDs of different colours)
|
||||
|
||||
# Check this area...
|
||||
see https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.h#L39
|
||||
Effectively, there are multiple SPI buses we can map to pins on these
|
||||
devices (including the hardware SPI bus)
|
||||
|
||||
An example of a minimal entry can be seen below:
|
||||
```
|
||||
#elif BOARD_MODEL == BOARD_MY_WICKED_BOARD
|
||||
|
31
Framing.h
31
Framing.h
@ -22,7 +22,6 @@
|
||||
#define TFESC 0xDD
|
||||
|
||||
#define CMD_UNKNOWN 0xFE
|
||||
#define CMD_DATA 0x00
|
||||
#define CMD_FREQUENCY 0x01
|
||||
#define CMD_BANDWIDTH 0x02
|
||||
#define CMD_TXPOWER 0x03
|
||||
@ -75,6 +74,34 @@
|
||||
#define CMD_RESET 0x55
|
||||
#define CMD_RESET_BYTE 0xF8
|
||||
|
||||
#define CMD_INTERFACES 0x64
|
||||
|
||||
#define CMD_INT0_DATA 0x00
|
||||
#define CMD_INT1_DATA 0x10
|
||||
#define CMD_INT2_DATA 0x20
|
||||
#define CMD_INT3_DATA 0x70
|
||||
#define CMD_INT4_DATA 0x80
|
||||
#define CMD_INT5_DATA 0x90
|
||||
#define CMD_INT6_DATA 0xA0
|
||||
#define CMD_INT7_DATA 0xB0
|
||||
#define CMD_INT8_DATA 0xC0
|
||||
#define CMD_INT9_DATA 0xD0
|
||||
#define CMD_INT10_DATA 0xE0
|
||||
#define CMD_INT11_DATA 0xF0
|
||||
|
||||
#define CMD_SEL_INT0 0x1E
|
||||
#define CMD_SEL_INT1 0x1F
|
||||
#define CMD_SEL_INT2 0x2F
|
||||
#define CMD_SEL_INT3 0x7F
|
||||
#define CMD_SEL_INT4 0x8F
|
||||
#define CMD_SEL_INT5 0x9F
|
||||
#define CMD_SEL_INT6 0xAF
|
||||
#define CMD_SEL_INT7 0xBF
|
||||
#define CMD_SEL_INT8 0xCF
|
||||
#define CMD_SEL_INT9 0xDF
|
||||
#define CMD_SEL_INT10 0xEF
|
||||
#define CMD_SEL_INT11 0xFF
|
||||
|
||||
#define DETECT_REQ 0x73
|
||||
#define DETECT_RESP 0x46
|
||||
|
||||
@ -98,4 +125,4 @@
|
||||
bool ESCAPE = false;
|
||||
uint8_t command = CMD_UNKNOWN;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
22
Graphics.h
22
Graphics.h
@ -401,6 +401,13 @@ const unsigned char bm_n_uh [] PROGMEM = {
|
||||
0xe7, 0xe7
|
||||
};
|
||||
|
||||
const unsigned char bm_dot_sqr [] PROGMEM = {
|
||||
0xaa, 0xd5, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00,
|
||||
0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00,
|
||||
0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0xaa, 0xd5, 0x40
|
||||
};
|
||||
|
||||
#elif DISP_H == 122
|
||||
// use 122px wide graphics
|
||||
|
||||
@ -1688,6 +1695,21 @@ const unsigned char bm_n_uh [] PROGMEM = {
|
||||
0xfc, 0x00, 0xfc, 0x00 // 9
|
||||
};
|
||||
|
||||
const unsigned char bm_dot_sqr [] PROGMEM = {
|
||||
0xee, 0xee, 0xdd, 0xdd, 0xc0, 0xee, 0xee, 0xdd, 0xdd, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00,
|
||||
0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00,
|
||||
0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
|
||||
0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0,
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00,
|
||||
0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
|
||||
0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xee, 0xee, 0xdd, 0xdd, 0xc0, 0xee,
|
||||
0xee, 0xdd, 0xdd, 0xc0
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
7
Interfaces.h
Normal file
7
Interfaces.h
Normal file
@ -0,0 +1,7 @@
|
||||
#define SX127X 0x00
|
||||
#define SX1276 0x01
|
||||
#define SX1278 0x02
|
||||
#define SX126X 0x10
|
||||
#define SX1262 0x11
|
||||
#define SX128X 0x20
|
||||
#define SX1280 0x21
|
11
Makefile
11
Makefile
@ -13,7 +13,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
ESP_IDF_VER = 2.0.15
|
||||
ESP_IDF_VER = 2.0.17
|
||||
|
||||
all: release
|
||||
|
||||
@ -30,7 +30,7 @@ prep-avr:
|
||||
|
||||
prep-esp32:
|
||||
arduino-cli core update-index --config-file arduino-cli.yaml
|
||||
arduino-cli core install esp32:esp32 --config-file arduino-cli.yaml
|
||||
arduino-cli core install esp32:esp32@2.0.17 --config-file arduino-cli.yaml
|
||||
arduino-cli lib install "Adafruit SSD1306"
|
||||
arduino-cli lib install "XPowersLib"
|
||||
arduino-cli lib install "Crypto"
|
||||
@ -207,16 +207,11 @@ upload-rak4631:
|
||||
|
||||
release: release-all
|
||||
|
||||
release-all: console-site spiffs-image release-rnode release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 release-heltec32_v2 release-heltec32_v3 release-heltec32_v2_extled release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-hashes
|
||||
release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 release-heltec32_v2 release-heltec32_v3 release-heltec32_v2_extled release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-hashes
|
||||
|
||||
release-hashes:
|
||||
python ./release_hashes.py > ./Release/release.json
|
||||
|
||||
release-rnode:
|
||||
arduino-cli compile --fqbn unsignedio:avr:rnode -e
|
||||
cp build/unsignedio.avr.rnode/RNode_Firmware_CE.ino.hex Release/rnode_firmware.hex
|
||||
rm -r build
|
||||
|
||||
release-tbeam:
|
||||
arduino-cli compile --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam.boot_app0
|
||||
|
4
Modem.h
4
Modem.h
@ -1,4 +0,0 @@
|
||||
#define SX1276 0x01
|
||||
#define SX1278 0x02
|
||||
#define SX1262 0x03
|
||||
#define SX1280 0x04
|
File diff suppressed because it is too large
Load Diff
666
Radio.h
Normal file
666
Radio.h
Normal file
@ -0,0 +1,666 @@
|
||||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// Modifications and additions copyright 2023 by Mark Qvist & Jacob Eva
|
||||
// Obviously still under the MIT license.
|
||||
|
||||
#ifndef RADIO_H
|
||||
#define RADIO_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "Interfaces.h"
|
||||
#include "Boards.h"
|
||||
|
||||
#define MAX_PKT_LENGTH 255
|
||||
|
||||
// TX
|
||||
#define PA_OUTPUT_RFO_PIN 0
|
||||
#define PA_OUTPUT_PA_BOOST_PIN 1
|
||||
|
||||
// DCD
|
||||
#define STATUS_INTERVAL_MS 3
|
||||
#define DCD_SAMPLES 2500
|
||||
#define UTIL_UPDATE_INTERVAL_MS 1000
|
||||
#define UTIL_UPDATE_INTERVAL (UTIL_UPDATE_INTERVAL_MS/STATUS_INTERVAL_MS)
|
||||
#define AIRTIME_LONGTERM 3600
|
||||
#define AIRTIME_LONGTERM_MS (AIRTIME_LONGTERM*1000)
|
||||
#define AIRTIME_BINLEN_MS (STATUS_INTERVAL_MS*DCD_SAMPLES)
|
||||
#define AIRTIME_BINS ((AIRTIME_LONGTERM*1000)/AIRTIME_BINLEN_MS)
|
||||
#define current_airtime_bin(void) (millis()%AIRTIME_LONGTERM_MS)/AIRTIME_BINLEN_MS
|
||||
#define DCD_THRESHOLD 2
|
||||
#define DCD_LED_STEP_D 3
|
||||
#define LORA_PREAMBLE_SYMBOLS_HW 4
|
||||
#define LORA_PREAMBLE_SYMBOLS_MIN 18
|
||||
#define LORA_PREAMBLE_TARGET_MS 15
|
||||
#define LORA_PREAMBLE_FAST_TARGET_MS 1
|
||||
#define LORA_FAST_BITRATE_THRESHOLD 40000
|
||||
|
||||
#define RSSI_OFFSET 157
|
||||
|
||||
#define PHY_HEADER_LORA_SYMBOLS 8
|
||||
|
||||
#define _e 2.71828183
|
||||
#define _S 10.0
|
||||
|
||||
// Status flags
|
||||
const uint8_t SIG_DETECT = 0x01;
|
||||
const uint8_t SIG_SYNCED = 0x02;
|
||||
const uint8_t RX_ONGOING = 0x04;
|
||||
|
||||
// forward declare Utilities.h LED functions
|
||||
void led_rx_on();
|
||||
|
||||
void led_rx_off();
|
||||
void led_indicate_airtime_lock();
|
||||
|
||||
#if PLATFORM == PLATFORM_ESP32
|
||||
// get update_lock for ESP32
|
||||
extern portMUX_TYPE update_lock;
|
||||
#endif
|
||||
|
||||
class RadioInterface : public Stream {
|
||||
public:
|
||||
// todo: in the future define _spiModem and _spiSettings from here for inheritence by child classes
|
||||
RadioInterface(uint8_t index) : _index(index), _radio_locked(false),
|
||||
_radio_online(false), _st_airtime_limit(0.0), _lt_airtime_limit(0.0),
|
||||
_airtime_lock(false), _airtime(0.0), _longterm_airtime(0.0),
|
||||
_local_channel_util(0.0), _total_channel_util(0.0),
|
||||
_longterm_channel_util(0.0), _last_status_update(0),
|
||||
_stat_signal_detected(false), _stat_signal_synced(false),_stat_rx_ongoing(false), _last_dcd(0),
|
||||
_dcd_count(0), _dcd(false), _dcd_led(false),
|
||||
_dcd_waiting(false), _dcd_wait_until(0), _dcd_sample(0),
|
||||
_post_tx_yield_timeout(0), _csma_slot_ms(50), _csma_p_min(0.1),
|
||||
_csma_p_max(0.8), _preambleLength(6), _lora_symbol_time_ms(0.0),
|
||||
_lora_symbol_rate(0.0), _lora_us_per_byte(0.0), _bitrate(0),
|
||||
_packet{0}, _onReceive(NULL) {};
|
||||
virtual int begin() = 0;
|
||||
virtual void end() = 0;
|
||||
|
||||
virtual int beginPacket(int implicitHeader = false) = 0;
|
||||
virtual int endPacket() = 0;
|
||||
|
||||
virtual int packetRssi() = 0;
|
||||
virtual int currentRssi() = 0;
|
||||
virtual uint8_t packetRssiRaw() = 0;
|
||||
virtual uint8_t currentRssiRaw() = 0;
|
||||
virtual uint8_t packetSnrRaw() = 0;
|
||||
virtual float packetSnr() = 0;
|
||||
virtual long packetFrequencyError() = 0;
|
||||
|
||||
// from Print
|
||||
virtual size_t write(uint8_t byte) = 0;
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
|
||||
|
||||
// from Stream
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
|
||||
virtual void onReceive(void(*callback)(uint8_t, int)) = 0;
|
||||
|
||||
virtual void receive(int size = 0) = 0;
|
||||
virtual void standby() = 0;
|
||||
virtual void sleep() = 0;
|
||||
|
||||
virtual bool preInit() = 0;
|
||||
virtual uint8_t getTxPower() = 0;
|
||||
virtual void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN) = 0;
|
||||
virtual uint32_t getFrequency() = 0;
|
||||
virtual void setFrequency(uint32_t frequency) = 0;
|
||||
virtual void setSpreadingFactor(int sf) = 0;
|
||||
virtual uint8_t getSpreadingFactor() = 0;
|
||||
virtual uint32_t getSignalBandwidth() = 0;
|
||||
virtual void setSignalBandwidth(uint32_t sbw) = 0;
|
||||
virtual void setCodingRate4(int denominator) = 0;
|
||||
virtual uint8_t getCodingRate4() = 0;
|
||||
virtual void setPreambleLength(long length) = 0;
|
||||
virtual uint8_t modemStatus() = 0;
|
||||
virtual void enableCrc() = 0;
|
||||
virtual void disableCrc() = 0;
|
||||
virtual void enableTCXO() = 0;
|
||||
virtual void disableTCXO() = 0;
|
||||
|
||||
virtual byte random() = 0;
|
||||
|
||||
virtual void setSPIFrequency(uint32_t frequency) = 0;
|
||||
|
||||
virtual void updateBitrate() = 0;
|
||||
virtual void handleDio0Rise() = 0;
|
||||
virtual void clearIRQStatus() = 0;
|
||||
uint32_t getBitrate() { return _bitrate; };
|
||||
uint8_t getIndex() { return _index; };
|
||||
void setRadioLock(bool lock) { _radio_locked = lock; };
|
||||
bool getRadioLock() { return _radio_locked; };
|
||||
void setRadioOnline(bool online) { _radio_online = online; };
|
||||
bool getRadioOnline() { return _radio_online; };
|
||||
void setSTALock(float at) { _st_airtime_limit = at; };
|
||||
float getSTALock() { return _st_airtime_limit; };
|
||||
void setLTALock(float at) { _lt_airtime_limit = at; };
|
||||
float getLTALock() { return _lt_airtime_limit; };
|
||||
bool calculateALock() {
|
||||
_airtime_lock = false;
|
||||
if (_st_airtime_limit != 0.0 && _airtime >= _st_airtime_limit) {
|
||||
_airtime_lock = true;
|
||||
}
|
||||
if (_lt_airtime_limit != 0.0 && _longterm_airtime >= _lt_airtime_limit) {
|
||||
_airtime_lock = true;
|
||||
}
|
||||
return _airtime_lock;
|
||||
};
|
||||
void updateAirtime() {
|
||||
uint16_t cb = current_airtime_bin();
|
||||
uint16_t pb = cb-1; if (cb-1 < 0) { pb = AIRTIME_BINS-1; }
|
||||
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
|
||||
_airtime_bins[nb] = 0;
|
||||
_airtime = (float)(_airtime_bins[cb]+_airtime_bins[pb])/(2.0*AIRTIME_BINLEN_MS);
|
||||
|
||||
uint32_t longterm_airtime_sum = 0;
|
||||
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) {
|
||||
longterm_airtime_sum += _airtime_bins[bin];
|
||||
}
|
||||
_longterm_airtime = (float)longterm_airtime_sum/(float)AIRTIME_LONGTERM_MS;
|
||||
|
||||
float longterm_channel_util_sum = 0.0;
|
||||
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) {
|
||||
longterm_channel_util_sum += _longterm_bins[bin];
|
||||
}
|
||||
_longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS;
|
||||
|
||||
updateCSMAp();
|
||||
|
||||
//kiss_indicate_channel_stats(); // todo: enable me!
|
||||
};
|
||||
void addAirtime(uint16_t written) {
|
||||
float packet_cost_ms = 0.0;
|
||||
float payload_cost_ms = ((float)written * _lora_us_per_byte)/1000.0;
|
||||
packet_cost_ms += payload_cost_ms;
|
||||
packet_cost_ms += (_preambleLength+4.25)*_lora_symbol_time_ms;
|
||||
packet_cost_ms += PHY_HEADER_LORA_SYMBOLS * _lora_symbol_time_ms;
|
||||
uint16_t cb = current_airtime_bin();
|
||||
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
|
||||
_airtime_bins[cb] += packet_cost_ms;
|
||||
_airtime_bins[nb] = 0;
|
||||
};
|
||||
void checkModemStatus() {
|
||||
if (millis()-_last_status_update >= STATUS_INTERVAL_MS) {
|
||||
updateModemStatus();
|
||||
|
||||
_util_samples[_dcd_sample] = _dcd;
|
||||
_dcd_sample = (_dcd_sample+1)%DCD_SAMPLES;
|
||||
if (_dcd_sample % UTIL_UPDATE_INTERVAL == 0) {
|
||||
int util_count = 0;
|
||||
for (int ui = 0; ui < DCD_SAMPLES; ui++) {
|
||||
if (_util_samples[ui]) util_count++;
|
||||
}
|
||||
_local_channel_util = (float)util_count / (float)DCD_SAMPLES;
|
||||
_total_channel_util = _local_channel_util + _airtime;
|
||||
if (_total_channel_util > 1.0) _total_channel_util = 1.0;
|
||||
|
||||
int16_t cb = current_airtime_bin();
|
||||
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
|
||||
if (_total_channel_util > _longterm_bins[cb]) _longterm_bins[cb] = _total_channel_util;
|
||||
_longterm_bins[nb] = 0.0;
|
||||
|
||||
updateAirtime();
|
||||
}
|
||||
}
|
||||
};
|
||||
void updateModemStatus() {
|
||||
#if PLATFORM == PLATFORM_ESP32
|
||||
portENTER_CRITICAL(&update_lock);
|
||||
#elif PLATFORM == PLATFORM_NRF52
|
||||
portENTER_CRITICAL();
|
||||
#endif
|
||||
|
||||
uint8_t status = modemStatus();
|
||||
|
||||
_last_status_update = millis();
|
||||
|
||||
#if PLATFORM == PLATFORM_ESP32
|
||||
portEXIT_CRITICAL(&update_lock);
|
||||
#elif PLATFORM == PLATFORM_NRF52
|
||||
portEXIT_CRITICAL();
|
||||
#endif
|
||||
|
||||
if ((status & SIG_DETECT) == SIG_DETECT) { _stat_signal_detected = true; } else { _stat_signal_detected = false; }
|
||||
if ((status & SIG_SYNCED) == SIG_SYNCED) { _stat_signal_synced = true; } else { _stat_signal_synced = false; }
|
||||
if ((status & RX_ONGOING) == RX_ONGOING) { _stat_rx_ongoing = true; } else { _stat_rx_ongoing = false; }
|
||||
|
||||
// if (stat_signal_detected || stat_signal_synced || stat_rx_ongoing) {
|
||||
if (_stat_signal_detected || _stat_signal_synced) {
|
||||
if (_stat_rx_ongoing) {
|
||||
if (_dcd_count < DCD_THRESHOLD) {
|
||||
_dcd_count++;
|
||||
} else {
|
||||
_last_dcd = _last_status_update;
|
||||
_dcd_led = true;
|
||||
_dcd = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_dcd_count == 0) {
|
||||
_dcd_led = false;
|
||||
} else if (_dcd_count > DCD_LED_STEP_D) {
|
||||
_dcd_count -= DCD_LED_STEP_D;
|
||||
} else {
|
||||
_dcd_count = 0;
|
||||
}
|
||||
|
||||
if (_last_status_update > _last_dcd+_csma_slot_ms) {
|
||||
_dcd = false;
|
||||
_dcd_led = false;
|
||||
_dcd_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_dcd_led) {
|
||||
led_rx_on();
|
||||
} else {
|
||||
if (_airtime_lock) {
|
||||
led_indicate_airtime_lock();
|
||||
} else {
|
||||
led_rx_off();
|
||||
}
|
||||
}
|
||||
};
|
||||
void setPostTxYieldTimeout(uint32_t timeout) { _post_tx_yield_timeout = timeout; };
|
||||
uint32_t getPostTxYieldTimeout() { return _post_tx_yield_timeout; };
|
||||
void setDCD(bool dcd) { _dcd = dcd; };
|
||||
bool getDCD() { return _dcd; };
|
||||
void setDCDWaiting(bool dcd_waiting) { _dcd_waiting = dcd_waiting; };
|
||||
bool getDCDWaiting() { return _dcd_waiting; };
|
||||
void setDCDWaitUntil(uint32_t dcd_wait_until) { _dcd_wait_until = dcd_wait_until; };
|
||||
bool getDCDWaitUntil() { return _dcd_wait_until; };
|
||||
float getAirtime() { return _airtime; };
|
||||
float getLongtermAirtime() { return _longterm_airtime; };
|
||||
float getTotalChannelUtil() { return _total_channel_util; };
|
||||
float getLongtermChannelUtil() { return _longterm_channel_util; };
|
||||
float CSMASlope(float u) { return (pow(_e,_S*u-_S/2.0))/(pow(_e,_S*u-_S/2.0)+1.0); };
|
||||
void updateCSMAp() {
|
||||
_csma_p = (uint8_t)((1.0-(_csma_p_min+(_csma_p_max-_csma_p_min)*CSMASlope(_airtime)))*255.0);
|
||||
};
|
||||
uint8_t getCSMAp() { return _csma_p; };
|
||||
void setCSMASlotMS(int slot_size) { _csma_slot_ms = slot_size; };
|
||||
int getCSMASlotMS() { return _csma_slot_ms; };
|
||||
float getSymbolTime() { return _lora_symbol_time_ms; };
|
||||
float getSymbolRate() { return _lora_symbol_rate; };
|
||||
long getPreambleLength() { return _preambleLength; };
|
||||
protected:
|
||||
virtual void explicitHeaderMode() = 0;
|
||||
virtual void implicitHeaderMode() = 0;
|
||||
|
||||
uint8_t _index;
|
||||
bool _radio_locked;
|
||||
bool _radio_online;
|
||||
float _st_airtime_limit;
|
||||
float _lt_airtime_limit;
|
||||
bool _airtime_lock;
|
||||
uint16_t _airtime_bins[AIRTIME_BINS] = {0};
|
||||
uint16_t _longterm_bins[AIRTIME_BINS] = {0};
|
||||
float _airtime;
|
||||
float _longterm_airtime;
|
||||
float _local_channel_util;
|
||||
float _total_channel_util;
|
||||
float _longterm_channel_util;
|
||||
uint32_t _last_status_update;
|
||||
bool _stat_signal_detected;
|
||||
bool _stat_signal_synced;
|
||||
bool _stat_rx_ongoing;
|
||||
uint32_t _last_dcd;
|
||||
uint16_t _dcd_count;
|
||||
bool _dcd;
|
||||
bool _dcd_led;
|
||||
bool _dcd_waiting;
|
||||
long _dcd_wait_until;
|
||||
bool _util_samples[DCD_SAMPLES] = {false};
|
||||
int _dcd_sample;
|
||||
uint32_t _post_tx_yield_timeout;
|
||||
uint8_t _csma_p;
|
||||
int _csma_slot_ms;
|
||||
float _csma_p_min;
|
||||
float _csma_p_max;
|
||||
long _preambleLength;
|
||||
float _lora_symbol_time_ms;
|
||||
float _lora_symbol_rate;
|
||||
float _lora_us_per_byte;
|
||||
uint32_t _bitrate;
|
||||
uint8_t _packet[255];
|
||||
void (*_onReceive)(uint8_t, int);
|
||||
};
|
||||
|
||||
class sx126x : public RadioInterface {
|
||||
public:
|
||||
sx126x(uint8_t index, SPIClass spi, bool tcxo, bool dio2_as_rf_switch, int ss, int sclk, int mosi, int miso, int reset, int
|
||||
dio0, int busy, int rxen);
|
||||
|
||||
int begin();
|
||||
void end();
|
||||
|
||||
int beginPacket(int implicitHeader = false);
|
||||
int endPacket();
|
||||
|
||||
int packetRssi();
|
||||
int currentRssi();
|
||||
uint8_t packetRssiRaw();
|
||||
uint8_t currentRssiRaw();
|
||||
uint8_t packetSnrRaw();
|
||||
float packetSnr();
|
||||
long packetFrequencyError();
|
||||
|
||||
// from Print
|
||||
size_t write(uint8_t byte);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
// from Stream
|
||||
int available();
|
||||
int read();
|
||||
int peek();
|
||||
void flush();
|
||||
|
||||
void onReceive(void(*callback)(uint8_t, int));
|
||||
|
||||
void receive(int size = 0);
|
||||
void standby();
|
||||
void sleep();
|
||||
|
||||
bool preInit();
|
||||
uint8_t getTxPower();
|
||||
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
||||
uint32_t getFrequency();
|
||||
void setFrequency(uint32_t frequency);
|
||||
void setSpreadingFactor(int sf);
|
||||
uint8_t getSpreadingFactor();
|
||||
uint32_t getSignalBandwidth();
|
||||
void setSignalBandwidth(uint32_t sbw);
|
||||
void setCodingRate4(int denominator);
|
||||
uint8_t getCodingRate4();
|
||||
void setPreambleLength(long length);
|
||||
uint8_t modemStatus();
|
||||
void enableCrc();
|
||||
void disableCrc();
|
||||
void enableTCXO();
|
||||
void disableTCXO();
|
||||
|
||||
|
||||
byte random();
|
||||
|
||||
void setSPIFrequency(uint32_t frequency);
|
||||
|
||||
void dumpRegisters(Stream& out);
|
||||
|
||||
void updateBitrate();
|
||||
|
||||
void handleDio0Rise();
|
||||
private:
|
||||
void writeBuffer(const uint8_t* buffer, size_t size);
|
||||
void readBuffer(uint8_t* buffer, size_t size);
|
||||
void loraMode();
|
||||
void rxAntEnable();
|
||||
void setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc);
|
||||
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro);
|
||||
void setSyncWord(uint16_t sw);
|
||||
void waitOnBusy();
|
||||
void executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
||||
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
||||
void explicitHeaderMode();
|
||||
void implicitHeaderMode();
|
||||
|
||||
|
||||
uint8_t readRegister(uint16_t address);
|
||||
void writeRegister(uint16_t address, uint8_t value);
|
||||
uint8_t singleTransfer(uint8_t opcode, uint16_t address, uint8_t value);
|
||||
|
||||
static void onDio0Rise();
|
||||
|
||||
void handleLowDataRate();
|
||||
void optimizeModemSensitivity();
|
||||
|
||||
void reset(void);
|
||||
void calibrate(void);
|
||||
void calibrate_image(uint32_t frequency);
|
||||
void clearIRQStatus();
|
||||
|
||||
private:
|
||||
SPISettings _spiSettings;
|
||||
SPIClass _spiModem;
|
||||
int _ss;
|
||||
int _sclk;
|
||||
int _mosi;
|
||||
int _miso;
|
||||
int _reset;
|
||||
int _dio0;
|
||||
int _rxen;
|
||||
int _busy;
|
||||
uint32_t _frequency;
|
||||
int _txp;
|
||||
uint8_t _sf;
|
||||
uint8_t _bw;
|
||||
uint8_t _cr;
|
||||
uint8_t _ldro;
|
||||
int _packetIndex;
|
||||
int _implicitHeaderMode;
|
||||
int _payloadLength;
|
||||
int _crcMode;
|
||||
int _fifo_tx_addr_ptr;
|
||||
int _fifo_rx_addr_ptr;
|
||||
bool _preinit_done;
|
||||
uint8_t _index;
|
||||
bool _tcxo;
|
||||
bool _dio2_as_rf_switch;
|
||||
};
|
||||
|
||||
class sx127x : public RadioInterface {
|
||||
public:
|
||||
sx127x(uint8_t index, SPIClass spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy);
|
||||
|
||||
int begin();
|
||||
void end();
|
||||
|
||||
int beginPacket(int implicitHeader = false);
|
||||
int endPacket();
|
||||
|
||||
int packetRssi();
|
||||
int currentRssi();
|
||||
uint8_t packetRssiRaw();
|
||||
uint8_t currentRssiRaw();
|
||||
uint8_t packetSnrRaw();
|
||||
float packetSnr();
|
||||
long packetFrequencyError();
|
||||
|
||||
// from Print
|
||||
size_t write(uint8_t byte);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
// from Stream
|
||||
int available();
|
||||
int read();
|
||||
int peek();
|
||||
void flush();
|
||||
|
||||
void onReceive(void(*callback)(uint8_t, int));
|
||||
|
||||
void receive(int size = 0);
|
||||
void standby();
|
||||
void sleep();
|
||||
|
||||
bool preInit();
|
||||
uint8_t getTxPower();
|
||||
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
||||
uint32_t getFrequency();
|
||||
void setFrequency(uint32_t frequency);
|
||||
void setSpreadingFactor(int sf);
|
||||
uint8_t getSpreadingFactor();
|
||||
uint32_t getSignalBandwidth();
|
||||
void setSignalBandwidth(uint32_t sbw);
|
||||
void setCodingRate4(int denominator);
|
||||
uint8_t getCodingRate4();
|
||||
void setPreambleLength(long length);
|
||||
uint8_t modemStatus();
|
||||
void enableCrc();
|
||||
void disableCrc();
|
||||
void enableTCXO();
|
||||
void disableTCXO();
|
||||
|
||||
byte random();
|
||||
|
||||
void setSPIFrequency(uint32_t frequency);
|
||||
|
||||
void updateBitrate();
|
||||
|
||||
void handleDio0Rise();
|
||||
void clearIRQStatus();
|
||||
private:
|
||||
void setSyncWord(uint8_t sw);
|
||||
void explicitHeaderMode();
|
||||
void implicitHeaderMode();
|
||||
|
||||
|
||||
uint8_t readRegister(uint8_t address);
|
||||
void writeRegister(uint8_t address, uint8_t value);
|
||||
uint8_t singleTransfer(uint8_t address, uint8_t value);
|
||||
|
||||
static void onDio0Rise();
|
||||
|
||||
void handleLowDataRate();
|
||||
void optimizeModemSensitivity();
|
||||
|
||||
private:
|
||||
SPISettings _spiSettings;
|
||||
SPIClass _spiModem;
|
||||
int _ss;
|
||||
int _sclk;
|
||||
int _mosi;
|
||||
int _miso;
|
||||
int _reset;
|
||||
int _dio0;
|
||||
int _busy;
|
||||
uint32_t _frequency;
|
||||
int _packetIndex;
|
||||
int _implicitHeaderMode;
|
||||
bool _preinit_done;
|
||||
uint8_t _index;
|
||||
uint8_t _sf;
|
||||
uint8_t _cr;
|
||||
};
|
||||
|
||||
class sx128x : public RadioInterface {
|
||||
public:
|
||||
sx128x(uint8_t index, SPIClass spi, bool tcxo, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy, int rxen, int txen);
|
||||
|
||||
int begin();
|
||||
void end();
|
||||
|
||||
int beginPacket(int implicitHeader = false);
|
||||
int endPacket();
|
||||
|
||||
int packetRssi();
|
||||
int currentRssi();
|
||||
uint8_t packetRssiRaw();
|
||||
uint8_t currentRssiRaw();
|
||||
uint8_t packetSnrRaw();
|
||||
float packetSnr();
|
||||
long packetFrequencyError();
|
||||
|
||||
// from Print
|
||||
size_t write(uint8_t byte);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
// from Stream
|
||||
int available();
|
||||
int read();
|
||||
int peek();
|
||||
void flush();
|
||||
|
||||
void onReceive(void(*callback)(uint8_t, int));
|
||||
|
||||
void receive(int size = 0);
|
||||
void standby();
|
||||
void sleep();
|
||||
|
||||
bool preInit();
|
||||
uint8_t getTxPower();
|
||||
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
||||
uint32_t getFrequency();
|
||||
void setFrequency(uint32_t frequency);
|
||||
void setSpreadingFactor(int sf);
|
||||
uint8_t getSpreadingFactor();
|
||||
uint32_t getSignalBandwidth();
|
||||
void setSignalBandwidth(uint32_t sbw);
|
||||
void setCodingRate4(int denominator);
|
||||
uint8_t getCodingRate4();
|
||||
void setPreambleLength(long length);
|
||||
uint8_t modemStatus();
|
||||
void enableCrc();
|
||||
void disableCrc();
|
||||
void enableTCXO();
|
||||
void disableTCXO();
|
||||
|
||||
byte random();
|
||||
|
||||
void setSPIFrequency(uint32_t frequency);
|
||||
|
||||
void dumpRegisters(Stream& out);
|
||||
|
||||
void updateBitrate();
|
||||
|
||||
void handleDio0Rise();
|
||||
|
||||
void clearIRQStatus();
|
||||
private:
|
||||
void writeBuffer(const uint8_t* buffer, size_t size);
|
||||
void readBuffer(uint8_t* buffer, size_t size);
|
||||
void txAntEnable();
|
||||
void rxAntEnable();
|
||||
void loraMode();
|
||||
void waitOnBusy();
|
||||
void executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
||||
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
||||
void setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc);
|
||||
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr);
|
||||
void setSyncWord(int sw);
|
||||
void explicitHeaderMode();
|
||||
void implicitHeaderMode();
|
||||
|
||||
|
||||
uint8_t readRegister(uint16_t address);
|
||||
void writeRegister(uint16_t address, uint8_t value);
|
||||
uint8_t singleTransfer(uint8_t opcode, uint16_t address, uint8_t value);
|
||||
|
||||
static void onDio0Rise();
|
||||
|
||||
void handleLowDataRate();
|
||||
void optimizeModemSensitivity();
|
||||
|
||||
private:
|
||||
SPISettings _spiSettings;
|
||||
SPIClass _spiModem;
|
||||
int _ss;
|
||||
int _sclk;
|
||||
int _mosi;
|
||||
int _miso;
|
||||
int _reset;
|
||||
int _dio0;
|
||||
int _rxen;
|
||||
int _txen;
|
||||
int _busy;
|
||||
int _modem;
|
||||
uint32_t _frequency;
|
||||
int _txp;
|
||||
uint8_t _sf;
|
||||
uint8_t _bw;
|
||||
uint8_t _cr;
|
||||
int _packetIndex;
|
||||
int _implicitHeaderMode;
|
||||
int _payloadLength;
|
||||
int _crcMode;
|
||||
int _fifo_tx_addr_ptr;
|
||||
int _fifo_rx_addr_ptr;
|
||||
bool _preinit_done;
|
||||
int _rxPacketLength;
|
||||
uint8_t _index;
|
||||
bool _tcxo;
|
||||
};
|
||||
#endif
|
624
Utilities.h
624
Utilities.h
@ -13,8 +13,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Radio.h"
|
||||
#include "Config.h"
|
||||
|
||||
// Included for sorting
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#if HAS_EEPROM
|
||||
#include <EEPROM.h>
|
||||
#elif PLATFORM == PLATFORM_NRF52
|
||||
@ -28,17 +33,6 @@
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#if MODEM == SX1262
|
||||
#include "sx126x.h"
|
||||
sx126x *LoRa = &sx126x_modem;
|
||||
#elif MODEM == SX1276 || MODEM == SX1278
|
||||
#include "sx127x.h"
|
||||
sx127x *LoRa = &sx127x_modem;
|
||||
#elif MODEM == SX1280
|
||||
#include "sx128x.h"
|
||||
sx128x *LoRa = &sx128x_modem;
|
||||
#endif
|
||||
|
||||
#include "ROM.h"
|
||||
#include "Framing.h"
|
||||
#include "MD5.h"
|
||||
@ -81,20 +75,9 @@ uint8_t eeprom_read(uint32_t mapped_addr);
|
||||
#define ISR_VECT
|
||||
#endif
|
||||
|
||||
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
|
||||
#include <avr/wdt.h>
|
||||
#include <util/atomic.h>
|
||||
#endif
|
||||
|
||||
uint8_t boot_vector = 0x00;
|
||||
|
||||
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
|
||||
uint8_t OPTIBOOT_MCUSR __attribute__ ((section(".noinit")));
|
||||
void resetFlagsInit(void) __attribute__ ((naked)) __attribute__ ((used)) __attribute__ ((section (".init0")));
|
||||
void resetFlagsInit(void) {
|
||||
__asm__ __volatile__ ("sts %0, r2\n" : "=m" (OPTIBOOT_MCUSR) :);
|
||||
}
|
||||
#elif MCU_VARIANT == MCU_ESP32
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
// TODO: Get ESP32 boot flags
|
||||
#elif MCU_VARIANT == MCU_NRF52
|
||||
// TODO: Get NRF52 boot flags
|
||||
@ -138,12 +121,7 @@ uint8_t boot_vector = 0x00;
|
||||
void boot_seq() { }
|
||||
#endif
|
||||
|
||||
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
|
||||
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
|
||||
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
|
||||
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
|
||||
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
|
||||
#elif MCU_VARIANT == MCU_ESP32
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
#if HAS_NP == true
|
||||
void led_rx_on() { npset(0, 0, 0xFF); }
|
||||
void led_rx_off() { npset(0, 0, 0); }
|
||||
@ -236,12 +214,7 @@ uint8_t boot_vector = 0x00;
|
||||
#endif
|
||||
|
||||
void hard_reset(void) {
|
||||
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
|
||||
wdt_enable(WDTO_15MS);
|
||||
while(true) {
|
||||
led_tx_on(); led_rx_off();
|
||||
}
|
||||
#elif MCU_VARIANT == MCU_ESP32
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
ESP.restart();
|
||||
#elif MCU_VARIANT == MCU_NRF52
|
||||
NVIC_SystemReset();
|
||||
@ -332,20 +305,7 @@ void led_indicate_warning(int cycles) {
|
||||
}
|
||||
|
||||
// LED Indication: Info
|
||||
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
|
||||
void led_indicate_info(int cycles) {
|
||||
bool forever = (cycles == 0) ? true : false;
|
||||
cycles = forever ? 1 : cycles;
|
||||
while(cycles > 0) {
|
||||
led_rx_off();
|
||||
delay(100);
|
||||
led_rx_on();
|
||||
delay(100);
|
||||
if (!forever) cycles--;
|
||||
}
|
||||
led_rx_off();
|
||||
}
|
||||
#elif MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
#if HAS_NP == true
|
||||
void led_indicate_info(int cycles) {
|
||||
bool forever = (cycles == 0) ? true : false;
|
||||
@ -403,12 +363,7 @@ void led_indicate_warning(int cycles) {
|
||||
|
||||
|
||||
unsigned long led_standby_ticks = 0;
|
||||
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
|
||||
uint8_t led_standby_min = 1;
|
||||
uint8_t led_standby_max = 40;
|
||||
unsigned long led_standby_wait = 11000;
|
||||
|
||||
#elif MCU_VARIANT == MCU_ESP32
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
|
||||
#if HAS_NP == true
|
||||
int led_standby_lng = 100;
|
||||
@ -451,23 +406,7 @@ unsigned long led_standby_ticks = 0;
|
||||
unsigned long led_standby_value = led_standby_min;
|
||||
int8_t led_standby_direction = 0;
|
||||
|
||||
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
|
||||
void led_indicate_standby() {
|
||||
led_standby_ticks++;
|
||||
if (led_standby_ticks > led_standby_wait) {
|
||||
led_standby_ticks = 0;
|
||||
if (led_standby_value <= led_standby_min) {
|
||||
led_standby_direction = 1;
|
||||
} else if (led_standby_value >= led_standby_max) {
|
||||
led_standby_direction = -1;
|
||||
}
|
||||
led_standby_value += led_standby_direction;
|
||||
analogWrite(pin_led_rx, led_standby_value);
|
||||
led_tx_off();
|
||||
}
|
||||
}
|
||||
|
||||
#elif MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
#if HAS_NP == true
|
||||
void led_indicate_standby() {
|
||||
led_standby_ticks++;
|
||||
@ -560,22 +499,7 @@ int8_t led_standby_direction = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
|
||||
void led_indicate_not_ready() {
|
||||
led_standby_ticks++;
|
||||
if (led_standby_ticks > led_standby_wait) {
|
||||
led_standby_ticks = 0;
|
||||
if (led_standby_value <= led_standby_min) {
|
||||
led_standby_direction = 1;
|
||||
} else if (led_standby_value >= led_standby_max) {
|
||||
led_standby_direction = -1;
|
||||
}
|
||||
led_standby_value += led_standby_direction;
|
||||
analogWrite(pin_led_tx, led_standby_value);
|
||||
led_rx_off();
|
||||
}
|
||||
}
|
||||
#elif MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
#if HAS_NP == true
|
||||
void led_indicate_not_ready() {
|
||||
led_standby_ticks++;
|
||||
@ -636,6 +560,18 @@ int8_t led_standby_direction = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
bool interface_bitrate_cmp(RadioInterface* p, RadioInterface* q) {
|
||||
long p_bitrate = p->getBitrate();
|
||||
long q_bitrate = q->getBitrate();
|
||||
return p_bitrate > q_bitrate;
|
||||
}
|
||||
|
||||
// Sort interfaces in descending order according to bitrate.
|
||||
void sort_interfaces() {
|
||||
std::sort(std::begin(interface_obj_sorted), std::end(interface_obj_sorted), interface_bitrate_cmp);
|
||||
}
|
||||
|
||||
void serial_write(uint8_t byte) {
|
||||
#if HAS_BLUETOOTH || HAS_BLE == true
|
||||
if (bt_state != BT_STATE_CONNECTED) {
|
||||
@ -668,31 +604,33 @@ void kiss_indicate_error(uint8_t error_code) {
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_radiostate() {
|
||||
void kiss_indicate_radiostate(RadioInterface* radio) {
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_RADIO_STATE);
|
||||
serial_write(radio_online);
|
||||
serial_write(radio->getRadioOnline());
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_stat_rx() {
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_STAT_RX);
|
||||
escaped_serial_write(stat_rx>>24);
|
||||
escaped_serial_write(stat_rx>>16);
|
||||
escaped_serial_write(stat_rx>>8);
|
||||
escaped_serial_write(stat_rx);
|
||||
serial_write(FEND);
|
||||
// todo, implement
|
||||
//serial_write(FEND);
|
||||
//serial_write(CMD_STAT_RX);
|
||||
//escaped_serial_write(stat_rx>>24);
|
||||
//escaped_serial_write(stat_rx>>16);
|
||||
//escaped_serial_write(stat_rx>>8);
|
||||
//escaped_serial_write(stat_rx);
|
||||
//serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_stat_tx() {
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_STAT_TX);
|
||||
escaped_serial_write(stat_tx>>24);
|
||||
escaped_serial_write(stat_tx>>16);
|
||||
escaped_serial_write(stat_tx>>8);
|
||||
escaped_serial_write(stat_tx);
|
||||
serial_write(FEND);
|
||||
// todo, implement
|
||||
//serial_write(FEND);
|
||||
//serial_write(CMD_STAT_TX);
|
||||
//escaped_serial_write(stat_tx>>24);
|
||||
//escaped_serial_write(stat_tx>>16);
|
||||
//escaped_serial_write(stat_tx>>8);
|
||||
//escaped_serial_write(stat_tx);
|
||||
//serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_stat_rssi() {
|
||||
@ -710,24 +648,24 @@ void kiss_indicate_stat_snr() {
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_radio_lock() {
|
||||
void kiss_indicate_radio_lock(RadioInterface* radio) {
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_RADIO_LOCK);
|
||||
serial_write(radio_locked);
|
||||
serial_write(radio->getRadioLock());
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_spreadingfactor() {
|
||||
void kiss_indicate_spreadingfactor(RadioInterface* radio) {
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_SF);
|
||||
serial_write((uint8_t)lora_sf);
|
||||
serial_write(radio->getSpreadingFactor());
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_codingrate() {
|
||||
void kiss_indicate_codingrate(RadioInterface* radio) {
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_CR);
|
||||
serial_write((uint8_t)lora_cr);
|
||||
serial_write(radio->getCodingRate4());
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
@ -738,35 +676,47 @@ void kiss_indicate_implicit_length() {
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_txpower() {
|
||||
void kiss_indicate_txpower(RadioInterface* radio) {
|
||||
uint8_t txp = radio->getTxPower();
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_TXPOWER);
|
||||
serial_write((uint8_t)lora_txp);
|
||||
serial_write(txp);
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_bandwidth() {
|
||||
void kiss_indicate_bandwidth(RadioInterface* radio) {
|
||||
uint32_t bw = radio->getSignalBandwidth();
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_BANDWIDTH);
|
||||
escaped_serial_write(lora_bw>>24);
|
||||
escaped_serial_write(lora_bw>>16);
|
||||
escaped_serial_write(lora_bw>>8);
|
||||
escaped_serial_write(lora_bw);
|
||||
escaped_serial_write(bw>>24);
|
||||
escaped_serial_write(bw>>16);
|
||||
escaped_serial_write(bw>>8);
|
||||
escaped_serial_write(bw);
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_frequency() {
|
||||
void kiss_indicate_frequency(RadioInterface* radio) {
|
||||
uint32_t freq = radio->getFrequency();
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_FREQUENCY);
|
||||
escaped_serial_write(lora_freq>>24);
|
||||
escaped_serial_write(lora_freq>>16);
|
||||
escaped_serial_write(lora_freq>>8);
|
||||
escaped_serial_write(lora_freq);
|
||||
escaped_serial_write(freq>>24);
|
||||
escaped_serial_write(freq>>16);
|
||||
escaped_serial_write(freq>>8);
|
||||
escaped_serial_write(freq);
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_st_alock() {
|
||||
uint16_t at = (uint16_t)(st_airtime_limit*100*100);
|
||||
void kiss_indicate_interface(int index) {
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_INTERFACES);
|
||||
// print the index to the interface and the interface type
|
||||
serial_write(index);
|
||||
serial_write(interfaces[index]);
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_st_alock(RadioInterface* radio) {
|
||||
uint16_t at = (uint16_t)(radio->getSTALock()*100*100);
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_ST_ALOCK);
|
||||
escaped_serial_write(at>>8);
|
||||
@ -774,8 +724,8 @@ void kiss_indicate_st_alock() {
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_lt_alock() {
|
||||
uint16_t at = (uint16_t)(lt_airtime_limit*100*100);
|
||||
void kiss_indicate_lt_alock(RadioInterface* radio) {
|
||||
uint16_t at = (uint16_t)(radio->getLTALock()*100*100);
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_LT_ALOCK);
|
||||
escaped_serial_write(at>>8);
|
||||
@ -783,47 +733,43 @@ void kiss_indicate_lt_alock() {
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_channel_stats() {
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
uint16_t ats = (uint16_t)(airtime*100*100);
|
||||
uint16_t atl = (uint16_t)(longterm_airtime*100*100);
|
||||
uint16_t cls = (uint16_t)(total_channel_util*100*100);
|
||||
uint16_t cll = (uint16_t)(longterm_channel_util*100*100);
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_STAT_CHTM);
|
||||
escaped_serial_write(ats>>8);
|
||||
escaped_serial_write(ats);
|
||||
escaped_serial_write(atl>>8);
|
||||
escaped_serial_write(atl);
|
||||
escaped_serial_write(cls>>8);
|
||||
escaped_serial_write(cls);
|
||||
escaped_serial_write(cll>>8);
|
||||
escaped_serial_write(cll);
|
||||
serial_write(FEND);
|
||||
#endif
|
||||
void kiss_indicate_channel_stats(RadioInterface* radio) {
|
||||
uint16_t ats = (uint16_t)(radio->getAirtime()*100*100);
|
||||
uint16_t atl = (uint16_t)(radio->getLongtermAirtime()*100*100);
|
||||
uint16_t cls = (uint16_t)(radio->getTotalChannelUtil()*100*100);
|
||||
uint16_t cll = (uint16_t)(radio->getLongtermChannelUtil()*100*100);
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_STAT_CHTM);
|
||||
escaped_serial_write(ats>>8);
|
||||
escaped_serial_write(ats);
|
||||
escaped_serial_write(atl>>8);
|
||||
escaped_serial_write(atl);
|
||||
escaped_serial_write(cls>>8);
|
||||
escaped_serial_write(cls);
|
||||
escaped_serial_write(cll>>8);
|
||||
escaped_serial_write(cll);
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_phy_stats() {
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
uint16_t lst = (uint16_t)(lora_symbol_time_ms*1000);
|
||||
uint16_t lsr = (uint16_t)(lora_symbol_rate);
|
||||
uint16_t prs = (uint16_t)(lora_preamble_symbols+4);
|
||||
uint16_t prt = (uint16_t)((lora_preamble_symbols+4)*lora_symbol_time_ms);
|
||||
uint16_t cst = (uint16_t)(csma_slot_ms);
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_STAT_PHYPRM);
|
||||
escaped_serial_write(lst>>8);
|
||||
escaped_serial_write(lst);
|
||||
escaped_serial_write(lsr>>8);
|
||||
escaped_serial_write(lsr);
|
||||
escaped_serial_write(prs>>8);
|
||||
escaped_serial_write(prs);
|
||||
escaped_serial_write(prt>>8);
|
||||
escaped_serial_write(prt);
|
||||
escaped_serial_write(cst>>8);
|
||||
escaped_serial_write(cst);
|
||||
serial_write(FEND);
|
||||
#endif
|
||||
void kiss_indicate_phy_stats(RadioInterface* radio) {
|
||||
uint16_t lst = (uint16_t)(radio->getSymbolTime()*1000);
|
||||
uint16_t lsr = (uint16_t)(radio->getSymbolRate());
|
||||
uint16_t prs = (uint16_t)(radio->getPreambleLength()+4);
|
||||
uint16_t prt = (uint16_t)((radio->getPreambleLength()+4)*radio->getSymbolTime());
|
||||
uint16_t cst = (uint16_t)(radio->getCSMASlotMS());
|
||||
serial_write(FEND);
|
||||
serial_write(CMD_STAT_PHYPRM);
|
||||
escaped_serial_write(lst>>8);
|
||||
escaped_serial_write(lst);
|
||||
escaped_serial_write(lsr>>8);
|
||||
escaped_serial_write(lsr);
|
||||
escaped_serial_write(prs>>8);
|
||||
escaped_serial_write(prs);
|
||||
escaped_serial_write(prt>>8);
|
||||
escaped_serial_write(prt);
|
||||
escaped_serial_write(cst>>8);
|
||||
escaped_serial_write(cst);
|
||||
serial_write(FEND);
|
||||
}
|
||||
|
||||
void kiss_indicate_battery() {
|
||||
@ -1009,43 +955,6 @@ inline uint8_t packetSequence(uint8_t header) {
|
||||
return header >> 4;
|
||||
}
|
||||
|
||||
void setPreamble() {
|
||||
if (radio_online) LoRa->setPreambleLength(lora_preamble_symbols);
|
||||
kiss_indicate_phy_stats();
|
||||
}
|
||||
|
||||
void updateBitrate() {
|
||||
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
if (radio_online) {
|
||||
lora_symbol_rate = (float)lora_bw/(float)(pow(2, lora_sf));
|
||||
lora_symbol_time_ms = (1.0/lora_symbol_rate)*1000.0;
|
||||
lora_bitrate = (uint32_t)(lora_sf * ( (4.0/(float)lora_cr) / ((float)(pow(2, lora_sf))/((float)lora_bw/1000.0)) ) * 1000.0);
|
||||
lora_us_per_byte = 1000000.0/((float)lora_bitrate/8.0);
|
||||
// csma_slot_ms = lora_symbol_time_ms*10;
|
||||
float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
|
||||
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) {
|
||||
target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
|
||||
} else {
|
||||
target_preamble_symbols = ceil(target_preamble_symbols);
|
||||
}
|
||||
lora_preamble_symbols = (long)target_preamble_symbols;
|
||||
setPreamble();
|
||||
} else {
|
||||
lora_bitrate = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void setSpreadingFactor() {
|
||||
if (radio_online) LoRa->setSpreadingFactor(lora_sf);
|
||||
updateBitrate();
|
||||
}
|
||||
|
||||
void setCodingRate() {
|
||||
if (radio_online) LoRa->setCodingRate4(lora_cr);
|
||||
updateBitrate();
|
||||
}
|
||||
|
||||
void set_implicit_length(uint8_t len) {
|
||||
implicit_l = len;
|
||||
if (implicit_l != 0) {
|
||||
@ -1055,76 +964,181 @@ void set_implicit_length(uint8_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
int getTxPower() {
|
||||
uint8_t txp = LoRa->getTxPower();
|
||||
return (int)txp;
|
||||
void setTXPower(RadioInterface* radio, int txp) {
|
||||
if (model == MODEL_11) {
|
||||
if (interfaces[radio->getIndex()] == SX128X) {
|
||||
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
} else {
|
||||
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
||||
}
|
||||
}
|
||||
if (model == MODEL_12) {
|
||||
if (interfaces[radio->getIndex()] == SX128X) {
|
||||
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
} else {
|
||||
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
||||
}
|
||||
}
|
||||
|
||||
if (model == MODEL_A1) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A2) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A3) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
||||
if (model == MODEL_A4) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
||||
if (model == MODEL_A6) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A7) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
|
||||
if (model == MODEL_B3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_B4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_B8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_B9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
|
||||
if (model == MODEL_C4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_C9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
|
||||
if (model == MODEL_E4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_E9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_E3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_E8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
|
||||
if (model == MODEL_FE) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_FF) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
||||
}
|
||||
|
||||
void setTXPower() {
|
||||
if (radio_online) {
|
||||
if (model == MODEL_A1) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A2) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A3) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
|
||||
if (model == MODEL_A4) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
|
||||
if (model == MODEL_A6) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A7) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_A9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
|
||||
if (model == MODEL_B3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_B4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_B8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_B9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
|
||||
if (model == MODEL_C4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_C9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
|
||||
if (model == MODEL_E4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_E9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_E3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_E8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
|
||||
if (model == MODEL_FE) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
|
||||
if (model == MODEL_FF) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void getBandwidth() {
|
||||
if (radio_online) {
|
||||
lora_bw = LoRa->getSignalBandwidth();
|
||||
}
|
||||
updateBitrate();
|
||||
}
|
||||
|
||||
void setBandwidth() {
|
||||
if (radio_online) {
|
||||
LoRa->setSignalBandwidth(lora_bw);
|
||||
getBandwidth();
|
||||
}
|
||||
}
|
||||
|
||||
void getFrequency() {
|
||||
if (radio_online) {
|
||||
lora_freq = LoRa->getFrequency();
|
||||
}
|
||||
}
|
||||
|
||||
void setFrequency() {
|
||||
if (radio_online) {
|
||||
LoRa->setFrequency(lora_freq);
|
||||
getFrequency();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getRandom() {
|
||||
if (radio_online) {
|
||||
return LoRa->random();
|
||||
uint8_t getRandom(RadioInterface* radio) {
|
||||
if (radio->getRadioOnline()) {
|
||||
return radio->random();
|
||||
} else {
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getInterfaceIndex(uint8_t byte) {
|
||||
switch (byte) {
|
||||
case CMD_INT0_DATA:
|
||||
case CMD_SEL_INT0:
|
||||
return 0;
|
||||
case CMD_INT1_DATA:
|
||||
case CMD_SEL_INT1:
|
||||
return 1;
|
||||
case CMD_INT2_DATA:
|
||||
case CMD_SEL_INT2:
|
||||
return 2;
|
||||
case CMD_INT3_DATA:
|
||||
case CMD_SEL_INT3:
|
||||
return 3;
|
||||
case CMD_INT4_DATA:
|
||||
case CMD_SEL_INT4:
|
||||
return 4;
|
||||
case CMD_INT5_DATA:
|
||||
case CMD_SEL_INT5:
|
||||
return 5;
|
||||
case CMD_INT6_DATA:
|
||||
case CMD_SEL_INT6:
|
||||
return 6;
|
||||
case CMD_INT7_DATA:
|
||||
case CMD_SEL_INT7:
|
||||
return 7;
|
||||
case CMD_INT8_DATA:
|
||||
case CMD_SEL_INT8:
|
||||
return 8;
|
||||
case CMD_INT9_DATA:
|
||||
case CMD_SEL_INT9:
|
||||
return 9;
|
||||
case CMD_INT10_DATA:
|
||||
case CMD_SEL_INT10:
|
||||
return 10;
|
||||
case CMD_INT11_DATA:
|
||||
case CMD_SEL_INT11:
|
||||
return 11;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getInterfaceCommandByte(uint8_t index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return CMD_INT0_DATA;
|
||||
case 1:
|
||||
return CMD_INT1_DATA;
|
||||
case 2:
|
||||
return CMD_INT2_DATA;
|
||||
case 3:
|
||||
return CMD_INT3_DATA;
|
||||
case 4:
|
||||
return CMD_INT4_DATA;
|
||||
case 5:
|
||||
return CMD_INT5_DATA;
|
||||
case 6:
|
||||
return CMD_INT6_DATA;
|
||||
case 7:
|
||||
return CMD_INT7_DATA;
|
||||
case 8:
|
||||
return CMD_INT8_DATA;
|
||||
case 9:
|
||||
return CMD_INT9_DATA;
|
||||
case 10:
|
||||
return CMD_INT10_DATA;
|
||||
case 11:
|
||||
return CMD_INT11_DATA;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getQueueSize(uint8_t index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return CONFIG_QUEUE_0_SIZE;
|
||||
#if INTERFACE_COUNT > 1
|
||||
case 1:
|
||||
return CONFIG_QUEUE_1_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 2
|
||||
case 2:
|
||||
return CONFIG_QUEUE_2_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 3
|
||||
case 3:
|
||||
return CONFIG_QUEUE_3_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 4
|
||||
case 4:
|
||||
return CONFIG_QUEUE_4_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 5
|
||||
case 5:
|
||||
return CONFIG_QUEUE_5_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 6
|
||||
case 6:
|
||||
return CONFIG_QUEUE_6_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 7
|
||||
case 7:
|
||||
return CONFIG_QUEUE_7_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 8
|
||||
case 8:
|
||||
return CONFIG_QUEUE_8_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 9
|
||||
case 9:
|
||||
return CONFIG_QUEUE_9_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 10
|
||||
case 10:
|
||||
return CONFIG_QUEUE_10_SIZE;
|
||||
#endif
|
||||
#if INTERFACE_COUNT > 11
|
||||
case 11:
|
||||
return CONFIG_QUEUE_11_SIZE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void promisc_enable() {
|
||||
promisc = true;
|
||||
}
|
||||
@ -1228,9 +1242,7 @@ void eeprom_flush() {
|
||||
#endif
|
||||
|
||||
void eeprom_update(int mapped_addr, uint8_t byte) {
|
||||
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
|
||||
EEPROM.update(mapped_addr, byte);
|
||||
#elif MCU_VARIANT == MCU_ESP32
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
if (EEPROM.read(mapped_addr) != byte) {
|
||||
EEPROM.write(mapped_addr, byte);
|
||||
EEPROM.commit();
|
||||
@ -1297,9 +1309,7 @@ bool eeprom_product_valid() {
|
||||
uint8_t rval = eeprom_read(eeprom_addr(ADDR_PRODUCT));
|
||||
#endif
|
||||
|
||||
#if PLATFORM == PLATFORM_AVR
|
||||
if (rval == PRODUCT_RNODE || rval == PRODUCT_HMBRW) {
|
||||
#elif PLATFORM == PLATFORM_ESP32
|
||||
#if PLATFORM == PLATFORM_ESP32
|
||||
if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3) {
|
||||
#elif PLATFORM == PLATFORM_NRF52
|
||||
if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW) {
|
||||
@ -1434,39 +1444,51 @@ bool eeprom_have_conf() {
|
||||
}
|
||||
}
|
||||
|
||||
void eeprom_conf_load() {
|
||||
void eeprom_conf_load(RadioInterface* radio) {
|
||||
if (eeprom_have_conf()) {
|
||||
if (!(radio->getRadioOnline())) {
|
||||
#if HAS_EEPROM
|
||||
lora_sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF));
|
||||
lora_cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR));
|
||||
lora_txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP));
|
||||
lora_freq = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x03);
|
||||
lora_bw = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x03);
|
||||
uint8_t sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF));
|
||||
uint8_t cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR));
|
||||
uint8_t txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP));
|
||||
uint32_t freq = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x03);
|
||||
uint32_t bw = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x03);
|
||||
#elif MCU_VARIANT == MCU_NRF52
|
||||
lora_sf = eeprom_read(eeprom_addr(ADDR_CONF_SF));
|
||||
lora_cr = eeprom_read(eeprom_addr(ADDR_CONF_CR));
|
||||
lora_txp = eeprom_read(eeprom_addr(ADDR_CONF_TXP));
|
||||
lora_freq = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x03);
|
||||
lora_bw = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x03);
|
||||
uint8_t sf = eeprom_read(eeprom_addr(ADDR_CONF_SF));
|
||||
uint8_t cr = eeprom_read(eeprom_addr(ADDR_CONF_CR));
|
||||
uint8_t txp = eeprom_read(eeprom_addr(ADDR_CONF_TXP));
|
||||
uint32_t freq = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x03);
|
||||
uint32_t bw = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x03);
|
||||
#endif
|
||||
radio->setSpreadingFactor(sf);
|
||||
radio->setCodingRate4(cr);
|
||||
setTXPower(radio, txp);
|
||||
radio->setFrequency(freq);
|
||||
radio->setSignalBandwidth(bw);
|
||||
radio->updateBitrate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eeprom_conf_save() {
|
||||
if (hw_ready && radio_online) {
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_SF), lora_sf);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_CR), lora_cr);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_TXP), lora_txp);
|
||||
void eeprom_conf_save(RadioInterface* radio) {
|
||||
if (hw_ready && radio->getRadioOnline()) {
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_SF), radio->getSpreadingFactor());
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_CR), radio->getCodingRate4());
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_TXP), radio->getTxPower());
|
||||
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, lora_bw>>24);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x01, lora_bw>>16);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x02, lora_bw>>8);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x03, lora_bw);
|
||||
uint32_t bw = radio->getSignalBandwidth();
|
||||
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x00, lora_freq>>24);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x01, lora_freq>>16);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x02, lora_freq>>8);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x03, lora_freq);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, bw>>24);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x01, bw>>16);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x02, bw>>8);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x03, bw);
|
||||
|
||||
uint32_t freq = radio->getFrequency();
|
||||
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x00, freq>>24);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x01, freq>>16);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x02, freq>>8);
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x03, freq);
|
||||
|
||||
eeprom_update(eeprom_addr(ADDR_CONF_OK), CONF_OK_BYTE);
|
||||
led_indicate_info(10);
|
||||
@ -1484,18 +1506,6 @@ void unlock_rom() {
|
||||
eeprom_erase();
|
||||
}
|
||||
|
||||
void init_channel_stats() {
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
for (uint16_t ai = 0; ai < DCD_SAMPLES; ai++) { util_samples[ai] = false; }
|
||||
for (uint16_t ai = 0; ai < AIRTIME_BINS; ai++) { airtime_bins[ai] = 0; }
|
||||
for (uint16_t ai = 0; ai < AIRTIME_BINS; ai++) { longterm_bins[ai] = 0.0; }
|
||||
local_channel_util = 0.0;
|
||||
total_channel_util = 0.0;
|
||||
airtime = 0.0;
|
||||
longterm_airtime = 0.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct FIFOBuffer
|
||||
{
|
||||
unsigned char *begin;
|
||||
|
@ -1,5 +1,5 @@
|
||||
board_manager:
|
||||
additional_urls:
|
||||
- https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
|
||||
- https://liberatedsystems.co.uk/rnode-firmware-ce/esp-custom-package.json
|
||||
- https://raw.githubusercontent.com/RAKwireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless_index.json
|
||||
- http://unsigned.io/arduino/package_unsignedio_UnsignedBoards_index.json
|
||||
|
987
sx126x.cpp
987
sx126x.cpp
@ -1,987 +0,0 @@
|
||||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva
|
||||
// Obviously still under the MIT license.
|
||||
|
||||
#include "Boards.h"
|
||||
|
||||
#if MODEM == SX1262
|
||||
#include "sx126x.h"
|
||||
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
#if MCU_VARIANT == MCU_ESP32 and !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#include "soc/rtc_wdt.h"
|
||||
#endif
|
||||
#define ISR_VECT IRAM_ATTR
|
||||
#else
|
||||
#define ISR_VECT
|
||||
#endif
|
||||
|
||||
#define OP_RF_FREQ_6X 0x86
|
||||
#define OP_SLEEP_6X 0x84
|
||||
#define OP_STANDBY_6X 0x80
|
||||
#define OP_TX_6X 0x83
|
||||
#define OP_RX_6X 0x82
|
||||
#define OP_PA_CONFIG_6X 0x95
|
||||
#define OP_SET_IRQ_FLAGS_6X 0x08 // also provides info such as
|
||||
// preamble detection, etc for
|
||||
// knowing when it's safe to switch
|
||||
// antenna modes
|
||||
#define OP_CLEAR_IRQ_STATUS_6X 0x02
|
||||
#define OP_GET_IRQ_STATUS_6X 0x12
|
||||
#define OP_RX_BUFFER_STATUS_6X 0x13
|
||||
#define OP_PACKET_STATUS_6X 0x14 // get snr & rssi of last packet
|
||||
#define OP_CURRENT_RSSI_6X 0x15
|
||||
#define OP_MODULATION_PARAMS_6X 0x8B // bw, sf, cr, etc.
|
||||
#define OP_PACKET_PARAMS_6X 0x8C // crc, preamble, payload length, etc.
|
||||
#define OP_STATUS_6X 0xC0
|
||||
#define OP_TX_PARAMS_6X 0x8E // set dbm, etc
|
||||
#define OP_PACKET_TYPE_6X 0x8A
|
||||
#define OP_BUFFER_BASE_ADDR_6X 0x8F
|
||||
#define OP_READ_REGISTER_6X 0x1D
|
||||
#define OP_WRITE_REGISTER_6X 0x0D
|
||||
#define OP_DIO3_TCXO_CTRL_6X 0x97
|
||||
#define OP_DIO2_RF_CTRL_6X 0x9D
|
||||
#define OP_CAD_PARAMS 0x88
|
||||
#define OP_CALIBRATE_6X 0x89
|
||||
#define OP_RX_TX_FALLBACK_MODE_6X 0x93
|
||||
#define OP_REGULATOR_MODE_6X 0x96
|
||||
#define OP_CALIBRATE_IMAGE_6X 0x98
|
||||
|
||||
#define MASK_CALIBRATE_ALL 0x7f
|
||||
|
||||
#define IRQ_TX_DONE_MASK_6X 0x01
|
||||
#define IRQ_RX_DONE_MASK_6X 0x02
|
||||
#define IRQ_HEADER_DET_MASK_6X 0x10
|
||||
#define IRQ_PREAMBLE_DET_MASK_6X 0x04
|
||||
#define IRQ_PAYLOAD_CRC_ERROR_MASK_6X 0x40
|
||||
#define IRQ_ALL_MASK_6X 0b0100001111111111
|
||||
|
||||
#define MODE_LONG_RANGE_MODE_6X 0x01
|
||||
|
||||
#define OP_FIFO_WRITE_6X 0x0E
|
||||
#define OP_FIFO_READ_6X 0x1E
|
||||
#define REG_OCP_6X 0x08E7
|
||||
#define REG_LNA_6X 0x08AC // no agc in sx1262
|
||||
#define REG_SYNC_WORD_MSB_6X 0x0740
|
||||
#define REG_SYNC_WORD_LSB_6X 0x0741
|
||||
#define REG_PAYLOAD_LENGTH_6X 0x0702 // https://github.com/beegee-tokyo/SX126x-Arduino/blob/master/src/radio/sx126x/sx126x.h#L98
|
||||
#define REG_RANDOM_GEN_6X 0x0819
|
||||
|
||||
#define MODE_TCXO_3_3V_6X 0x07
|
||||
#define MODE_TCXO_3_0V_6X 0x06
|
||||
#define MODE_TCXO_2_7V_6X 0x06
|
||||
#define MODE_TCXO_2_4V_6X 0x06
|
||||
#define MODE_TCXO_2_2V_6X 0x03
|
||||
#define MODE_TCXO_1_8V_6X 0x02
|
||||
#define MODE_TCXO_1_7V_6X 0x01
|
||||
#define MODE_TCXO_1_6V_6X 0x00
|
||||
|
||||
#define MODE_STDBY_RC_6X 0x00
|
||||
#define MODE_STDBY_XOSC_6X 0x01
|
||||
#define MODE_FALLBACK_STDBY_RC_6X 0x20
|
||||
#define MODE_IMPLICIT_HEADER 0x01
|
||||
#define MODE_EXPLICIT_HEADER 0x00
|
||||
|
||||
#define SYNC_WORD_6X 0x1424
|
||||
|
||||
#define XTAL_FREQ_6X (double)32000000
|
||||
#define FREQ_DIV_6X (double)pow(2.0, 25.0)
|
||||
#define FREQ_STEP_6X (double)(XTAL_FREQ_6X / FREQ_DIV_6X)
|
||||
|
||||
#if defined(NRF52840_XXAA)
|
||||
extern SPIClass spiModem;
|
||||
#define SPI spiModem
|
||||
#endif
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
||||
#define MAX_PKT_LENGTH 255
|
||||
|
||||
sx126x::sx126x() :
|
||||
_spiSettings(8E6, MSBFIRST, SPI_MODE0),
|
||||
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _busy(LORA_DEFAULT_BUSY_PIN), _rxen(LORA_DEFAULT_RXEN_PIN),
|
||||
_frequency(0),
|
||||
_txp(0),
|
||||
_sf(0x07),
|
||||
_bw(0x04),
|
||||
_cr(0x01),
|
||||
_ldro(0x00),
|
||||
_packetIndex(0),
|
||||
_preambleLength(18),
|
||||
_implicitHeaderMode(0),
|
||||
_payloadLength(255),
|
||||
_crcMode(1),
|
||||
_fifo_tx_addr_ptr(0),
|
||||
_fifo_rx_addr_ptr(0),
|
||||
_packet({0}),
|
||||
_preinit_done(false),
|
||||
_onReceive(NULL)
|
||||
{
|
||||
// overide Stream timeout value
|
||||
setTimeout(0);
|
||||
}
|
||||
|
||||
bool sx126x::preInit() {
|
||||
pinMode(_ss, OUTPUT);
|
||||
digitalWrite(_ss, HIGH);
|
||||
|
||||
#if BOARD_MODEL == BOARD_RNODE_NG_22 || BOARD_MODEL == BOARD_HELTEC32_V3
|
||||
SPI.begin(pin_sclk, pin_miso, pin_mosi, pin_cs);
|
||||
#else
|
||||
SPI.begin();
|
||||
#endif
|
||||
|
||||
// check version (retry for up to 2 seconds)
|
||||
// TODO: Actually read version registers, not syncwords
|
||||
long start = millis();
|
||||
uint8_t syncmsb;
|
||||
uint8_t synclsb;
|
||||
while (((millis() - start) < 2000) && (millis() >= start)) {
|
||||
syncmsb = readRegister(REG_SYNC_WORD_MSB_6X);
|
||||
synclsb = readRegister(REG_SYNC_WORD_LSB_6X);
|
||||
if ( uint16_t(syncmsb << 8 | synclsb) == 0x1424 || uint16_t(syncmsb << 8 | synclsb) == 0x4434) {
|
||||
break;
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
if ( uint16_t(syncmsb << 8 | synclsb) != 0x1424 && uint16_t(syncmsb << 8 | synclsb) != 0x4434) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_preinit_done = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t ISR_VECT sx126x::readRegister(uint16_t address)
|
||||
{
|
||||
return singleTransfer(OP_READ_REGISTER_6X, address, 0x00);
|
||||
}
|
||||
|
||||
void sx126x::writeRegister(uint16_t address, uint8_t value)
|
||||
{
|
||||
singleTransfer(OP_WRITE_REGISTER_6X, address, value);
|
||||
}
|
||||
|
||||
uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_t value)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
uint8_t response;
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(opcode);
|
||||
SPI.transfer((address & 0xFF00) >> 8);
|
||||
SPI.transfer(address & 0x00FF);
|
||||
if (opcode == OP_READ_REGISTER_6X) {
|
||||
SPI.transfer(0x00);
|
||||
}
|
||||
response = SPI.transfer(value);
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void sx126x::rxAntEnable()
|
||||
{
|
||||
if (_rxen != -1) {
|
||||
digitalWrite(_rxen, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::loraMode() {
|
||||
// enable lora mode on the SX1262 chip
|
||||
uint8_t mode = MODE_LONG_RANGE_MODE_6X;
|
||||
executeOpcode(OP_PACKET_TYPE_6X, &mode, 1);
|
||||
}
|
||||
|
||||
void sx126x::waitOnBusy() {
|
||||
unsigned long time = millis();
|
||||
if (_busy != -1) {
|
||||
while (digitalRead(_busy) == HIGH)
|
||||
{
|
||||
if (millis() >= (time + 100)) {
|
||||
break;
|
||||
}
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(opcode);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
SPI.transfer(buffer[i]);
|
||||
}
|
||||
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
}
|
||||
|
||||
void sx126x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(opcode);
|
||||
SPI.transfer(0x00);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
buffer[i] = SPI.transfer(0x00);
|
||||
}
|
||||
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
}
|
||||
|
||||
void sx126x::writeBuffer(const uint8_t* buffer, size_t size)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(OP_FIFO_WRITE_6X);
|
||||
SPI.transfer(_fifo_tx_addr_ptr);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
SPI.transfer(buffer[i]);
|
||||
_fifo_tx_addr_ptr++;
|
||||
}
|
||||
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
}
|
||||
|
||||
void sx126x::readBuffer(uint8_t* buffer, size_t size)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(OP_FIFO_READ_6X);
|
||||
SPI.transfer(_fifo_rx_addr_ptr);
|
||||
SPI.transfer(0x00);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
buffer[i] = SPI.transfer(0x00);
|
||||
}
|
||||
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
}
|
||||
|
||||
void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) {
|
||||
// because there is no access to these registers on the sx1262, we have
|
||||
// to set all these parameters at once or not at all.
|
||||
uint8_t buf[8];
|
||||
|
||||
buf[0] = sf;
|
||||
buf[1] = bw;
|
||||
buf[2] = cr;
|
||||
// low data rate toggle
|
||||
buf[3] = ldro;
|
||||
// unused params in LoRa mode
|
||||
buf[4] = 0x00;
|
||||
buf[5] = 0x00;
|
||||
buf[6] = 0x00;
|
||||
buf[7] = 0x00;
|
||||
|
||||
executeOpcode(OP_MODULATION_PARAMS_6X, buf, 8);
|
||||
}
|
||||
|
||||
void sx126x::setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
|
||||
// because there is no access to these registers on the sx1262, we have
|
||||
// to set all these parameters at once or not at all.
|
||||
uint8_t buf[9];
|
||||
|
||||
buf[0] = uint8_t((preamble & 0xFF00) >> 8);
|
||||
buf[1] = uint8_t((preamble & 0x00FF));
|
||||
buf[2] = headermode;
|
||||
buf[3] = length;
|
||||
buf[4] = crc;
|
||||
// standard IQ setting (no inversion)
|
||||
buf[5] = 0x00;
|
||||
// unused params
|
||||
buf[6] = 0x00;
|
||||
buf[7] = 0x00;
|
||||
buf[8] = 0x00;
|
||||
|
||||
executeOpcode(OP_PACKET_PARAMS_6X, buf, 9);
|
||||
}
|
||||
|
||||
void sx126x::reset(void) {
|
||||
if (_reset != -1) {
|
||||
pinMode(_reset, OUTPUT);
|
||||
|
||||
// perform reset
|
||||
digitalWrite(_reset, LOW);
|
||||
delay(10);
|
||||
digitalWrite(_reset, HIGH);
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::calibrate(void) {
|
||||
// Put in STDBY_RC mode before calibration
|
||||
uint8_t mode_byte = MODE_STDBY_RC_6X;
|
||||
executeOpcode(OP_STANDBY_6X, &mode_byte, 1);
|
||||
|
||||
// calibrate RC64k, RC13M, PLL, ADC and image
|
||||
uint8_t calibrate = MASK_CALIBRATE_ALL;
|
||||
executeOpcode(OP_CALIBRATE_6X, &calibrate, 1);
|
||||
|
||||
delay(5);
|
||||
waitOnBusy();
|
||||
}
|
||||
|
||||
void sx126x::calibrate_image(long frequency) {
|
||||
uint8_t image_freq[2] = {0};
|
||||
|
||||
if (frequency >= 430E6 && frequency <= 440E6) {
|
||||
image_freq[0] = 0x6B;
|
||||
image_freq[1] = 0x6F;
|
||||
}
|
||||
else if (frequency >= 470E6 && frequency <= 510E6) {
|
||||
image_freq[0] = 0x75;
|
||||
image_freq[1] = 0x81;
|
||||
}
|
||||
else if (frequency >= 779E6 && frequency <= 787E6) {
|
||||
image_freq[0] = 0xC1;
|
||||
image_freq[1] = 0xC5;
|
||||
}
|
||||
else if (frequency >= 863E6 && frequency <= 870E6) {
|
||||
image_freq[0] = 0xD7;
|
||||
image_freq[1] = 0xDB;
|
||||
}
|
||||
else if (frequency >= 902E6 && frequency <= 928E6) {
|
||||
image_freq[0] = 0xE1;
|
||||
image_freq[1] = 0xE9;
|
||||
}
|
||||
|
||||
executeOpcode(OP_CALIBRATE_IMAGE_6X, image_freq, 2);
|
||||
waitOnBusy();
|
||||
}
|
||||
|
||||
int sx126x::begin(long frequency)
|
||||
{
|
||||
reset();
|
||||
|
||||
if (_busy != -1) {
|
||||
pinMode(_busy, INPUT);
|
||||
}
|
||||
|
||||
if (!_preinit_done) {
|
||||
if (!preInit()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_rxen != -1) {
|
||||
pinMode(_rxen, OUTPUT);
|
||||
}
|
||||
|
||||
calibrate();
|
||||
calibrate_image(frequency);
|
||||
|
||||
enableTCXO();
|
||||
|
||||
loraMode();
|
||||
standby();
|
||||
|
||||
// Set sync word
|
||||
setSyncWord(SYNC_WORD_6X);
|
||||
|
||||
#if DIO2_AS_RF_SWITCH
|
||||
// enable dio2 rf switch
|
||||
uint8_t byte = 0x01;
|
||||
executeOpcode(OP_DIO2_RF_CTRL_6X, &byte, 1);
|
||||
#endif
|
||||
|
||||
rxAntEnable();
|
||||
|
||||
setFrequency(frequency);
|
||||
|
||||
// set output power to 2 dBm
|
||||
setTxPower(2);
|
||||
enableCrc();
|
||||
|
||||
// set LNA boost
|
||||
writeRegister(REG_LNA_6X, 0x96);
|
||||
|
||||
// set base addresses
|
||||
uint8_t basebuf[2] = {0};
|
||||
executeOpcode(OP_BUFFER_BASE_ADDR_6X, basebuf, 2);
|
||||
|
||||
setModulationParams(_sf, _bw, _cr, _ldro);
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void sx126x::end()
|
||||
{
|
||||
// put in sleep mode
|
||||
sleep();
|
||||
|
||||
// stop SPI
|
||||
SPI.end();
|
||||
|
||||
_preinit_done = false;
|
||||
}
|
||||
|
||||
int sx126x::beginPacket(int implicitHeader)
|
||||
{
|
||||
standby();
|
||||
|
||||
if (implicitHeader) {
|
||||
implicitHeaderMode();
|
||||
} else {
|
||||
explicitHeaderMode();
|
||||
}
|
||||
|
||||
_payloadLength = 0;
|
||||
_fifo_tx_addr_ptr = 0;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sx126x::endPacket()
|
||||
{
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
// put in single TX mode
|
||||
uint8_t timeout[3] = {0};
|
||||
executeOpcode(OP_TX_6X, timeout, 3);
|
||||
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = 0x00;
|
||||
buf[1] = 0x00;
|
||||
|
||||
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
|
||||
|
||||
// wait for TX done
|
||||
while ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0) {
|
||||
buf[0] = 0x00;
|
||||
buf[1] = 0x00;
|
||||
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
|
||||
yield();
|
||||
}
|
||||
|
||||
// clear IRQ's
|
||||
|
||||
uint8_t mask[2];
|
||||
mask[0] = 0x00;
|
||||
mask[1] = IRQ_TX_DONE_MASK_6X;
|
||||
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, mask, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t sx126x::modemStatus() {
|
||||
// imitate the register status from the sx1276 / 78
|
||||
uint8_t buf[2] = {0};
|
||||
|
||||
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
|
||||
uint8_t clearbuf[2] = {0};
|
||||
uint8_t byte = 0x00;
|
||||
|
||||
if ((buf[1] & IRQ_PREAMBLE_DET_MASK_6X) != 0) {
|
||||
byte = byte | 0x01 | 0x04;
|
||||
// clear register after reading
|
||||
clearbuf[1] = IRQ_PREAMBLE_DET_MASK_6X;
|
||||
}
|
||||
|
||||
if ((buf[1] & IRQ_HEADER_DET_MASK_6X) != 0) {
|
||||
byte = byte | 0x02 | 0x04;
|
||||
}
|
||||
|
||||
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2);
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
|
||||
uint8_t sx126x::currentRssiRaw() {
|
||||
uint8_t byte = 0;
|
||||
executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1);
|
||||
return byte;
|
||||
}
|
||||
|
||||
int ISR_VECT sx126x::currentRssi() {
|
||||
uint8_t byte = 0;
|
||||
executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1);
|
||||
int rssi = -(int(byte)) / 2;
|
||||
return rssi;
|
||||
}
|
||||
|
||||
uint8_t sx126x::packetRssiRaw() {
|
||||
uint8_t buf[3] = {0};
|
||||
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
|
||||
return buf[2];
|
||||
}
|
||||
|
||||
int ISR_VECT sx126x::packetRssi() {
|
||||
// may need more calculations here
|
||||
uint8_t buf[3] = {0};
|
||||
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
|
||||
int pkt_rssi = -buf[0] / 2;
|
||||
return pkt_rssi;
|
||||
}
|
||||
|
||||
uint8_t ISR_VECT sx126x::packetSnrRaw() {
|
||||
uint8_t buf[3] = {0};
|
||||
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
|
||||
return buf[1];
|
||||
}
|
||||
|
||||
float ISR_VECT sx126x::packetSnr() {
|
||||
uint8_t buf[3] = {0};
|
||||
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
|
||||
return float(buf[1]) * 0.25;
|
||||
}
|
||||
|
||||
long sx126x::packetFrequencyError()
|
||||
{
|
||||
// todo: implement this, no idea how to check it on the sx1262
|
||||
const float fError = 0.0;
|
||||
return static_cast<long>(fError);
|
||||
}
|
||||
|
||||
size_t sx126x::write(uint8_t byte)
|
||||
{
|
||||
return write(&byte, sizeof(byte));
|
||||
}
|
||||
|
||||
size_t sx126x::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
if ((_payloadLength + size) > MAX_PKT_LENGTH) {
|
||||
size = MAX_PKT_LENGTH - _payloadLength;
|
||||
}
|
||||
|
||||
// write data
|
||||
writeBuffer(buffer, size);
|
||||
_payloadLength = _payloadLength + size;
|
||||
return size;
|
||||
}
|
||||
|
||||
int ISR_VECT sx126x::available()
|
||||
{
|
||||
uint8_t buf[2] = {0};
|
||||
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, buf, 2);
|
||||
return buf[0] - _packetIndex;
|
||||
}
|
||||
|
||||
int ISR_VECT sx126x::read()
|
||||
{
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if received new packet
|
||||
if (_packetIndex == 0) {
|
||||
uint8_t rxbuf[2] = {0};
|
||||
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
|
||||
int size = rxbuf[0];
|
||||
_fifo_rx_addr_ptr = rxbuf[1];
|
||||
|
||||
readBuffer(_packet, size);
|
||||
}
|
||||
|
||||
uint8_t byte = _packet[_packetIndex];
|
||||
_packetIndex++;
|
||||
return byte;
|
||||
}
|
||||
|
||||
int sx126x::peek()
|
||||
{
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if received new packet
|
||||
if (_packetIndex == 0) {
|
||||
uint8_t rxbuf[2] = {0};
|
||||
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
|
||||
int size = rxbuf[0];
|
||||
_fifo_rx_addr_ptr = rxbuf[1];
|
||||
|
||||
readBuffer(_packet, size);
|
||||
}
|
||||
|
||||
uint8_t b = _packet[_packetIndex];
|
||||
return b;
|
||||
}
|
||||
|
||||
void sx126x::flush()
|
||||
{
|
||||
}
|
||||
|
||||
void sx126x::onReceive(void(*callback)(int))
|
||||
{
|
||||
_onReceive = callback;
|
||||
|
||||
if (callback) {
|
||||
pinMode(_dio0, INPUT);
|
||||
|
||||
// set preamble and header detection irqs, plus dio0 mask
|
||||
uint8_t buf[8];
|
||||
|
||||
// set irq masks, enable all
|
||||
buf[0] = 0xFF;
|
||||
buf[1] = 0xFF;
|
||||
|
||||
// set dio0 masks
|
||||
buf[2] = 0x00;
|
||||
buf[3] = IRQ_RX_DONE_MASK_6X;
|
||||
|
||||
// set dio1 masks
|
||||
buf[4] = 0x00;
|
||||
buf[5] = 0x00;
|
||||
|
||||
// set dio2 masks
|
||||
buf[6] = 0x00;
|
||||
buf[7] = 0x00;
|
||||
|
||||
executeOpcode(OP_SET_IRQ_FLAGS_6X, buf, 8);
|
||||
#ifdef SPI_HAS_NOTUSINGINTERRUPT
|
||||
SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
|
||||
#endif
|
||||
attachInterrupt(digitalPinToInterrupt(_dio0), sx126x::onDio0Rise, RISING);
|
||||
} else {
|
||||
detachInterrupt(digitalPinToInterrupt(_dio0));
|
||||
#ifdef SPI_HAS_NOTUSINGINTERRUPT
|
||||
SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::receive(int size)
|
||||
{
|
||||
if (size > 0) {
|
||||
implicitHeaderMode();
|
||||
|
||||
// tell radio payload length
|
||||
_payloadLength = size;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
} else {
|
||||
explicitHeaderMode();
|
||||
}
|
||||
|
||||
if (_rxen != -1) {
|
||||
rxAntEnable();
|
||||
}
|
||||
|
||||
uint8_t mode[3] = {0xFF, 0xFF, 0xFF}; // continuous mode
|
||||
executeOpcode(OP_RX_6X, mode, 3);
|
||||
}
|
||||
|
||||
void sx126x::standby()
|
||||
{
|
||||
// STDBY_XOSC
|
||||
uint8_t byte = MODE_STDBY_XOSC_6X;
|
||||
// STDBY_RC
|
||||
// uint8_t byte = MODE_STDBY_RC_6X;
|
||||
executeOpcode(OP_STANDBY_6X, &byte, 1);
|
||||
}
|
||||
|
||||
void sx126x::sleep()
|
||||
{
|
||||
uint8_t byte = 0x00;
|
||||
executeOpcode(OP_SLEEP_6X, &byte, 1);
|
||||
}
|
||||
|
||||
void sx126x::enableTCXO() {
|
||||
#if HAS_TCXO
|
||||
#if BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_HELTEC32_V3
|
||||
uint8_t buf[4] = {MODE_TCXO_3_3V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_TBEAM
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_RNODE_NG_22
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#endif
|
||||
executeOpcode(OP_DIO3_TCXO_CTRL_6X, buf, 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: Once enabled, SX1262 needs a complete reset to disable TCXO
|
||||
void sx126x::disableTCXO() { }
|
||||
|
||||
void sx126x::setTxPower(int level, int outputPin) {
|
||||
// currently no low power mode for SX1262 implemented, assuming PA boost
|
||||
|
||||
// WORKAROUND - Better Resistance of the SX1262 Tx to Antenna Mismatch, see DS_SX1261-2_V1.2 datasheet chapter 15.2
|
||||
// RegTxClampConfig = @address 0x08D8
|
||||
writeRegister(0x08D8, readRegister(0x08D8) | (0x0F << 1));
|
||||
|
||||
uint8_t pa_buf[4];
|
||||
|
||||
pa_buf[0] = 0x04; // PADutyCycle needs to be 0x04 to achieve 22dBm output, but can be lowered for better efficiency at lower outputs
|
||||
pa_buf[1] = 0x07; // HPMax at 0x07 is maximum supported for SX1262
|
||||
pa_buf[2] = 0x00; // DeviceSel 0x00 for SX1262 (0x01 for SX1261)
|
||||
pa_buf[3] = 0x01; // PALut always 0x01 (reserved according to datasheet)
|
||||
|
||||
executeOpcode(OP_PA_CONFIG_6X, pa_buf, 4); // set pa_config for high power
|
||||
|
||||
if (level > 22) { level = 22; }
|
||||
else if (level < -9) { level = -9; }
|
||||
|
||||
writeRegister(REG_OCP_6X, 0x38); // 160mA limit, overcurrent protection
|
||||
|
||||
uint8_t tx_buf[2];
|
||||
|
||||
tx_buf[0] = level;
|
||||
tx_buf[1] = 0x02; // PA ramping time - 40 microseconds
|
||||
|
||||
executeOpcode(OP_TX_PARAMS_6X, tx_buf, 2);
|
||||
|
||||
_txp = level;
|
||||
}
|
||||
|
||||
uint8_t sx126x::getTxPower() {
|
||||
return _txp;
|
||||
}
|
||||
|
||||
void sx126x::setFrequency(long frequency) {
|
||||
_frequency = frequency;
|
||||
|
||||
uint8_t buf[4];
|
||||
|
||||
uint32_t freq = (uint32_t)((double)frequency / (double)FREQ_STEP_6X);
|
||||
|
||||
buf[0] = ((freq >> 24) & 0xFF);
|
||||
buf[1] = ((freq >> 16) & 0xFF);
|
||||
buf[2] = ((freq >> 8) & 0xFF);
|
||||
buf[3] = (freq & 0xFF);
|
||||
|
||||
executeOpcode(OP_RF_FREQ_6X, buf, 4);
|
||||
}
|
||||
|
||||
uint32_t sx126x::getFrequency() {
|
||||
// we can't read the frequency on the sx1262 / 80
|
||||
uint32_t frequency = _frequency;
|
||||
|
||||
return frequency;
|
||||
}
|
||||
|
||||
void sx126x::setSpreadingFactor(int sf)
|
||||
{
|
||||
if (sf < 5) {
|
||||
sf = 5;
|
||||
} else if (sf > 12) {
|
||||
sf = 12;
|
||||
}
|
||||
|
||||
_sf = sf;
|
||||
|
||||
handleLowDataRate();
|
||||
setModulationParams(sf, _bw, _cr, _ldro);
|
||||
}
|
||||
|
||||
long sx126x::getSignalBandwidth()
|
||||
{
|
||||
int bw = _bw;
|
||||
switch (bw) {
|
||||
case 0x00: return 7.8E3;
|
||||
case 0x01: return 15.6E3;
|
||||
case 0x02: return 31.25E3;
|
||||
case 0x03: return 62.5E3;
|
||||
case 0x04: return 125E3;
|
||||
case 0x05: return 250E3;
|
||||
case 0x06: return 500E3;
|
||||
case 0x08: return 10.4E3;
|
||||
case 0x09: return 20.8E3;
|
||||
case 0x0A: return 41.7E3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sx126x::handleLowDataRate(){
|
||||
if ( long( (1<<_sf) / (getSignalBandwidth()/1000)) > 16) {
|
||||
_ldro = 0x01;
|
||||
} else {
|
||||
_ldro = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::optimizeModemSensitivity(){
|
||||
// todo: check if there's anything the sx1262 can do here
|
||||
}
|
||||
|
||||
void sx126x::setSignalBandwidth(long sbw)
|
||||
{
|
||||
if (sbw <= 7.8E3) {
|
||||
_bw = 0x00;
|
||||
} else if (sbw <= 10.4E3) {
|
||||
_bw = 0x08;
|
||||
} else if (sbw <= 15.6E3) {
|
||||
_bw = 0x01;
|
||||
} else if (sbw <= 20.8E3) {
|
||||
_bw = 0x09;
|
||||
} else if (sbw <= 31.25E3) {
|
||||
_bw = 0x02;
|
||||
} else if (sbw <= 41.7E3) {
|
||||
_bw = 0x0A;
|
||||
} else if (sbw <= 62.5E3) {
|
||||
_bw = 0x03;
|
||||
} else if (sbw <= 125E3) {
|
||||
_bw = 0x04;
|
||||
} else if (sbw <= 250E3) {
|
||||
_bw = 0x05;
|
||||
} else /*if (sbw <= 250E3)*/ {
|
||||
_bw = 0x06;
|
||||
}
|
||||
|
||||
handleLowDataRate();
|
||||
setModulationParams(_sf, _bw, _cr, _ldro);
|
||||
|
||||
optimizeModemSensitivity();
|
||||
}
|
||||
|
||||
void sx126x::setCodingRate4(int denominator)
|
||||
{
|
||||
if (denominator < 5) {
|
||||
denominator = 5;
|
||||
} else if (denominator > 8) {
|
||||
denominator = 8;
|
||||
}
|
||||
|
||||
int cr = denominator - 4;
|
||||
|
||||
_cr = cr;
|
||||
|
||||
setModulationParams(_sf, _bw, cr, _ldro);
|
||||
}
|
||||
|
||||
void sx126x::setPreambleLength(long length)
|
||||
{
|
||||
_preambleLength = length;
|
||||
setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
void sx126x::setSyncWord(uint16_t sw)
|
||||
{
|
||||
// TODO: Fix
|
||||
// writeRegister(REG_SYNC_WORD_MSB_6X, (sw & 0xFF00) >> 8);
|
||||
// writeRegister(REG_SYNC_WORD_LSB_6X, sw & 0x00FF);
|
||||
writeRegister(REG_SYNC_WORD_MSB_6X, 0x14);
|
||||
writeRegister(REG_SYNC_WORD_LSB_6X, 0x24);
|
||||
}
|
||||
|
||||
void sx126x::enableCrc()
|
||||
{
|
||||
_crcMode = 1;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
void sx126x::disableCrc()
|
||||
{
|
||||
_crcMode = 0;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
byte sx126x::random()
|
||||
{
|
||||
return readRegister(REG_RANDOM_GEN_6X);
|
||||
}
|
||||
|
||||
void sx126x::setPins(int ss, int reset, int dio0, int busy, int rxen)
|
||||
{
|
||||
_ss = ss;
|
||||
_reset = reset;
|
||||
_dio0 = dio0;
|
||||
_busy = busy;
|
||||
_rxen = rxen;
|
||||
}
|
||||
|
||||
void sx126x::setSPIFrequency(uint32_t frequency)
|
||||
{
|
||||
_spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0);
|
||||
}
|
||||
|
||||
void sx126x::dumpRegisters(Stream& out)
|
||||
{
|
||||
for (int i = 0; i < 128; i++) {
|
||||
out.print("0x");
|
||||
out.print(i, HEX);
|
||||
out.print(": 0x");
|
||||
out.println(readRegister(i), HEX);
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::explicitHeaderMode()
|
||||
{
|
||||
_implicitHeaderMode = 0;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
void sx126x::implicitHeaderMode()
|
||||
{
|
||||
_implicitHeaderMode = 1;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
|
||||
void ISR_VECT sx126x::handleDio0Rise()
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = 0x00;
|
||||
buf[1] = 0x00;
|
||||
|
||||
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
|
||||
|
||||
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, buf, 2);
|
||||
|
||||
if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_6X) == 0) {
|
||||
// received a packet
|
||||
_packetIndex = 0;
|
||||
|
||||
// read packet length
|
||||
uint8_t rxbuf[2] = {0};
|
||||
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
|
||||
int packetLength = rxbuf[0];
|
||||
|
||||
if (_onReceive) {
|
||||
_onReceive(packetLength);
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// Serial.println("CRCE");
|
||||
// Serial.println(buf[0]);
|
||||
// Serial.println(buf[1]);
|
||||
// }
|
||||
}
|
||||
|
||||
void ISR_VECT sx126x::onDio0Rise()
|
||||
{
|
||||
sx126x_modem.handleDio0Rise();
|
||||
}
|
||||
|
||||
sx126x sx126x_modem;
|
||||
|
||||
#endif
|
146
sx126x.h
146
sx126x.h
@ -1,146 +0,0 @@
|
||||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// Modifications and additions copyright 2023 by Mark Qvist
|
||||
// Obviously still under the MIT license.
|
||||
|
||||
#ifndef SX126X_H
|
||||
#define SX126X_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "Modem.h"
|
||||
|
||||
#define LORA_DEFAULT_SS_PIN 10
|
||||
#define LORA_DEFAULT_RESET_PIN 9
|
||||
#define LORA_DEFAULT_DIO0_PIN 2
|
||||
#define LORA_DEFAULT_RXEN_PIN -1
|
||||
#define LORA_DEFAULT_TXEN_PIN -1
|
||||
#define LORA_DEFAULT_BUSY_PIN -1
|
||||
|
||||
#define PA_OUTPUT_RFO_PIN 0
|
||||
#define PA_OUTPUT_PA_BOOST_PIN 1
|
||||
|
||||
#define RSSI_OFFSET 157
|
||||
|
||||
class sx126x : public Stream {
|
||||
public:
|
||||
sx126x();
|
||||
|
||||
int begin(long frequency);
|
||||
void end();
|
||||
|
||||
int beginPacket(int implicitHeader = false);
|
||||
int endPacket();
|
||||
|
||||
int parsePacket(int size = 0);
|
||||
int packetRssi();
|
||||
int currentRssi();
|
||||
uint8_t packetRssiRaw();
|
||||
uint8_t currentRssiRaw();
|
||||
uint8_t packetSnrRaw();
|
||||
float packetSnr();
|
||||
long packetFrequencyError();
|
||||
|
||||
// from Print
|
||||
virtual size_t write(uint8_t byte);
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
// from Stream
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual int peek();
|
||||
virtual void flush();
|
||||
|
||||
void onReceive(void(*callback)(int));
|
||||
|
||||
void receive(int size = 0);
|
||||
void standby();
|
||||
void sleep();
|
||||
|
||||
bool preInit();
|
||||
uint8_t getTxPower();
|
||||
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
||||
uint32_t getFrequency();
|
||||
void setFrequency(long frequency);
|
||||
void setSpreadingFactor(int sf);
|
||||
long getSignalBandwidth();
|
||||
void setSignalBandwidth(long sbw);
|
||||
void setCodingRate4(int denominator);
|
||||
void setPreambleLength(long length);
|
||||
void setSyncWord(uint16_t sw);
|
||||
uint8_t modemStatus();
|
||||
void enableCrc();
|
||||
void disableCrc();
|
||||
void enableTCXO();
|
||||
void disableTCXO();
|
||||
|
||||
void rxAntEnable();
|
||||
void loraMode();
|
||||
void waitOnBusy();
|
||||
void executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
||||
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
||||
void writeBuffer(const uint8_t* buffer, size_t size);
|
||||
void readBuffer(uint8_t* buffer, size_t size);
|
||||
void setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc);
|
||||
|
||||
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro);
|
||||
|
||||
// deprecated
|
||||
void crc() { enableCrc(); }
|
||||
void noCrc() { disableCrc(); }
|
||||
|
||||
byte random();
|
||||
|
||||
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN, int busy = LORA_DEFAULT_BUSY_PIN, int rxen = LORA_DEFAULT_RXEN_PIN);
|
||||
void setSPIFrequency(uint32_t frequency);
|
||||
|
||||
void dumpRegisters(Stream& out);
|
||||
|
||||
private:
|
||||
void explicitHeaderMode();
|
||||
void implicitHeaderMode();
|
||||
|
||||
void handleDio0Rise();
|
||||
|
||||
uint8_t readRegister(uint16_t address);
|
||||
void writeRegister(uint16_t address, uint8_t value);
|
||||
uint8_t singleTransfer(uint8_t opcode, uint16_t address, uint8_t value);
|
||||
|
||||
static void onDio0Rise();
|
||||
|
||||
void handleLowDataRate();
|
||||
void optimizeModemSensitivity();
|
||||
|
||||
void reset(void);
|
||||
void calibrate(void);
|
||||
void calibrate_image(long frequency);
|
||||
|
||||
private:
|
||||
SPISettings _spiSettings;
|
||||
int _ss;
|
||||
int _reset;
|
||||
int _dio0;
|
||||
int _rxen;
|
||||
int _busy;
|
||||
long _frequency;
|
||||
int _txp;
|
||||
uint8_t _sf;
|
||||
uint8_t _bw;
|
||||
uint8_t _cr;
|
||||
uint8_t _ldro;
|
||||
int _packetIndex;
|
||||
int _preambleLength;
|
||||
int _implicitHeaderMode;
|
||||
int _payloadLength;
|
||||
int _crcMode;
|
||||
int _fifo_tx_addr_ptr;
|
||||
int _fifo_rx_addr_ptr;
|
||||
uint8_t _packet[255];
|
||||
bool _preinit_done;
|
||||
void (*_onReceive)(int);
|
||||
};
|
||||
|
||||
extern sx126x sx126x_modem;
|
||||
|
||||
#endif
|
498
sx127x.cpp
498
sx127x.cpp
@ -1,498 +0,0 @@
|
||||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// Modifications and additions copyright 2023 by Mark Qvist
|
||||
// Obviously still under the MIT license.
|
||||
|
||||
#include "Boards.h"
|
||||
|
||||
#if MODEM == SX1276
|
||||
#include "sx127x.h"
|
||||
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
#if MCU_VARIANT == MCU_ESP32 and !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#include "soc/rtc_wdt.h"
|
||||
#endif
|
||||
#define ISR_VECT IRAM_ATTR
|
||||
#else
|
||||
#define ISR_VECT
|
||||
#endif
|
||||
|
||||
// Registers
|
||||
#define REG_FIFO_7X 0x00
|
||||
#define REG_OP_MODE_7X 0x01
|
||||
#define REG_FRF_MSB_7X 0x06
|
||||
#define REG_FRF_MID_7X 0x07
|
||||
#define REG_FRF_LSB_7X 0x08
|
||||
#define REG_PA_CONFIG_7X 0x09
|
||||
#define REG_OCP_7X 0x0b
|
||||
#define REG_LNA_7X 0x0c
|
||||
#define REG_FIFO_ADDR_PTR_7X 0x0d
|
||||
#define REG_FIFO_TX_BASE_ADDR_7X 0x0e
|
||||
#define REG_FIFO_RX_BASE_ADDR_7X 0x0f
|
||||
#define REG_FIFO_RX_CURRENT_ADDR_7X 0x10
|
||||
#define REG_IRQ_FLAGS_7X 0x12
|
||||
#define REG_RX_NB_BYTES_7X 0x13
|
||||
#define REG_MODEM_STAT_7X 0x18
|
||||
#define REG_PKT_SNR_VALUE_7X 0x19
|
||||
#define REG_PKT_RSSI_VALUE_7X 0x1a
|
||||
#define REG_RSSI_VALUE_7X 0x1b
|
||||
#define REG_MODEM_CONFIG_1_7X 0x1d
|
||||
#define REG_MODEM_CONFIG_2_7X 0x1e
|
||||
#define REG_PREAMBLE_MSB_7X 0x20
|
||||
#define REG_PREAMBLE_LSB_7X 0x21
|
||||
#define REG_PAYLOAD_LENGTH_7X 0x22
|
||||
#define REG_MODEM_CONFIG_3_7X 0x26
|
||||
#define REG_FREQ_ERROR_MSB_7X 0x28
|
||||
#define REG_FREQ_ERROR_MID_7X 0x29
|
||||
#define REG_FREQ_ERROR_LSB_7X 0x2a
|
||||
#define REG_RSSI_WIDEBAND_7X 0x2c
|
||||
#define REG_DETECTION_OPTIMIZE_7X 0x31
|
||||
#define REG_HIGH_BW_OPTIMIZE_1_7X 0x36
|
||||
#define REG_DETECTION_THRESHOLD_7X 0x37
|
||||
#define REG_SYNC_WORD_7X 0x39
|
||||
#define REG_HIGH_BW_OPTIMIZE_2_7X 0x3a
|
||||
#define REG_DIO_MAPPING_1_7X 0x40
|
||||
#define REG_VERSION_7X 0x42
|
||||
#define REG_TCXO_7X 0x4b
|
||||
#define REG_PA_DAC_7X 0x4d
|
||||
|
||||
// Modes
|
||||
#define MODE_LONG_RANGE_MODE_7X 0x80
|
||||
#define MODE_SLEEP_7X 0x00
|
||||
#define MODE_STDBY_7X 0x01
|
||||
#define MODE_TX_7X 0x03
|
||||
#define MODE_RX_CONTINUOUS_7X 0x05
|
||||
#define MODE_RX_SINGLE_7X 0x06
|
||||
|
||||
// PA config
|
||||
#define PA_BOOST_7X 0x80
|
||||
|
||||
// IRQ masks
|
||||
#define IRQ_TX_DONE_MASK_7X 0x08
|
||||
#define IRQ_RX_DONE_MASK_7X 0x40
|
||||
#define IRQ_PAYLOAD_CRC_ERROR_MASK_7X 0x20
|
||||
|
||||
#define SYNC_WORD_7X 0x12
|
||||
#define MAX_PKT_LENGTH 255
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
||||
sx127x::sx127x() :
|
||||
_spiSettings(8E6, MSBFIRST, SPI_MODE0),
|
||||
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN),
|
||||
_frequency(0),
|
||||
_packetIndex(0),
|
||||
_preinit_done(false),
|
||||
_onReceive(NULL) { setTimeout(0); }
|
||||
|
||||
void sx127x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); }
|
||||
void sx127x::setPins(int ss, int reset, int dio0, int busy) { _ss = ss; _reset = reset; _dio0 = dio0; _busy = busy; }
|
||||
uint8_t ISR_VECT sx127x::readRegister(uint8_t address) { return singleTransfer(address & 0x7f, 0x00); }
|
||||
void sx127x::writeRegister(uint8_t address, uint8_t value) { singleTransfer(address | 0x80, value); }
|
||||
void sx127x::standby() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_STDBY_7X); }
|
||||
void sx127x::sleep() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_SLEEP_7X); }
|
||||
uint8_t sx127x::modemStatus() { return readRegister(REG_MODEM_STAT_7X); }
|
||||
void sx127x::setSyncWord(uint8_t sw) { writeRegister(REG_SYNC_WORD_7X, sw); }
|
||||
void sx127x::enableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) | 0x04); }
|
||||
void sx127x::disableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) & 0xfb); }
|
||||
void sx127x::enableTCXO() { uint8_t tcxo_reg = readRegister(REG_TCXO_7X); writeRegister(REG_TCXO_7X, tcxo_reg | 0x10); }
|
||||
void sx127x::disableTCXO() { uint8_t tcxo_reg = readRegister(REG_TCXO_7X); writeRegister(REG_TCXO_7X, tcxo_reg & 0xEF); }
|
||||
void sx127x::explicitHeaderMode() { _implicitHeaderMode = 0; writeRegister(REG_MODEM_CONFIG_1_7X, readRegister(REG_MODEM_CONFIG_1_7X) & 0xfe); }
|
||||
void sx127x::implicitHeaderMode() { _implicitHeaderMode = 1; writeRegister(REG_MODEM_CONFIG_1_7X, readRegister(REG_MODEM_CONFIG_1_7X) | 0x01); }
|
||||
byte sx127x::random() { return readRegister(REG_RSSI_WIDEBAND_7X); }
|
||||
void sx127x::flush() { }
|
||||
|
||||
bool sx127x::preInit() {
|
||||
pinMode(_ss, OUTPUT);
|
||||
digitalWrite(_ss, HIGH);
|
||||
SPI.begin();
|
||||
|
||||
// Check modem version
|
||||
uint8_t version;
|
||||
long start = millis();
|
||||
while (((millis() - start) < 500) && (millis() >= start)) {
|
||||
version = readRegister(REG_VERSION_7X);
|
||||
if (version == 0x12) { break; }
|
||||
delay(100);
|
||||
}
|
||||
|
||||
if (version != 0x12) { return false; }
|
||||
|
||||
_preinit_done = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t ISR_VECT sx127x::singleTransfer(uint8_t address, uint8_t value) {
|
||||
uint8_t response;
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(address);
|
||||
response = SPI.transfer(value);
|
||||
SPI.endTransaction();
|
||||
digitalWrite(_ss, HIGH);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
int sx127x::begin(long frequency) {
|
||||
if (_reset != -1) {
|
||||
pinMode(_reset, OUTPUT);
|
||||
|
||||
// Perform reset
|
||||
digitalWrite(_reset, LOW);
|
||||
delay(10);
|
||||
digitalWrite(_reset, HIGH);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
if (_busy != -1) { pinMode(_busy, INPUT); }
|
||||
|
||||
if (!_preinit_done) {
|
||||
if (!preInit()) { return false; }
|
||||
}
|
||||
|
||||
sleep();
|
||||
setFrequency(frequency);
|
||||
|
||||
// set base addresses
|
||||
writeRegister(REG_FIFO_TX_BASE_ADDR_7X, 0);
|
||||
writeRegister(REG_FIFO_RX_BASE_ADDR_7X, 0);
|
||||
|
||||
// set LNA boost and auto AGC
|
||||
writeRegister(REG_LNA_7X, readRegister(REG_LNA_7X) | 0x03);
|
||||
writeRegister(REG_MODEM_CONFIG_3_7X, 0x04);
|
||||
|
||||
setSyncWord(SYNC_WORD_7X);
|
||||
enableCrc();
|
||||
setTxPower(2);
|
||||
|
||||
standby();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void sx127x::end() {
|
||||
sleep();
|
||||
SPI.end();
|
||||
_preinit_done = false;
|
||||
}
|
||||
|
||||
int sx127x::beginPacket(int implicitHeader) {
|
||||
standby();
|
||||
|
||||
if (implicitHeader) {
|
||||
implicitHeaderMode();
|
||||
} else {
|
||||
explicitHeaderMode();
|
||||
}
|
||||
|
||||
// Reset FIFO address and payload length
|
||||
writeRegister(REG_FIFO_ADDR_PTR_7X, 0);
|
||||
writeRegister(REG_PAYLOAD_LENGTH_7X, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sx127x::endPacket() {
|
||||
// Enter TX mode
|
||||
writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_TX_7X);
|
||||
|
||||
// Wait for TX completion
|
||||
while ((readRegister(REG_IRQ_FLAGS_7X) & IRQ_TX_DONE_MASK_7X) == 0) {
|
||||
yield();
|
||||
}
|
||||
|
||||
// Clear TX complete IRQ
|
||||
writeRegister(REG_IRQ_FLAGS_7X, IRQ_TX_DONE_MASK_7X);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t sx127x::currentRssiRaw() {
|
||||
uint8_t rssi = readRegister(REG_RSSI_VALUE_7X);
|
||||
return rssi;
|
||||
}
|
||||
|
||||
int ISR_VECT sx127x::currentRssi() {
|
||||
int rssi = (int)readRegister(REG_RSSI_VALUE_7X) - RSSI_OFFSET;
|
||||
if (_frequency < 820E6) rssi -= 7;
|
||||
return rssi;
|
||||
}
|
||||
|
||||
uint8_t sx127x::packetRssiRaw() {
|
||||
uint8_t pkt_rssi_value = readRegister(REG_PKT_RSSI_VALUE_7X);
|
||||
return pkt_rssi_value;
|
||||
}
|
||||
|
||||
int ISR_VECT sx127x::packetRssi() {
|
||||
int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET;
|
||||
int pkt_snr = packetSnr();
|
||||
|
||||
if (_frequency < 820E6) pkt_rssi -= 7;
|
||||
|
||||
if (pkt_snr < 0) {
|
||||
pkt_rssi += pkt_snr;
|
||||
} else {
|
||||
// Slope correction is (16/15)*pkt_rssi,
|
||||
// this estimation looses one floating point
|
||||
// operation, and should be precise enough.
|
||||
pkt_rssi = (int)(1.066 * pkt_rssi);
|
||||
}
|
||||
return pkt_rssi;
|
||||
}
|
||||
|
||||
uint8_t ISR_VECT sx127x::packetSnrRaw() {
|
||||
return readRegister(REG_PKT_SNR_VALUE_7X);
|
||||
}
|
||||
|
||||
float ISR_VECT sx127x::packetSnr() {
|
||||
return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25;
|
||||
}
|
||||
|
||||
long sx127x::packetFrequencyError() {
|
||||
int32_t freqError = 0;
|
||||
freqError = static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MSB_7X) & B111);
|
||||
freqError <<= 8L;
|
||||
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MID_7X));
|
||||
freqError <<= 8L;
|
||||
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_LSB_7X));
|
||||
|
||||
if (readRegister(REG_FREQ_ERROR_MSB_7X) & B1000) { // Sign bit is on
|
||||
freqError -= 524288; // B1000'0000'0000'0000'0000
|
||||
}
|
||||
|
||||
const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14)
|
||||
const float fError = ((static_cast<float>(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f);
|
||||
|
||||
return static_cast<long>(fError);
|
||||
}
|
||||
|
||||
size_t sx127x::write(uint8_t byte) { return write(&byte, sizeof(byte)); }
|
||||
|
||||
size_t sx127x::write(const uint8_t *buffer, size_t size) {
|
||||
int currentLength = readRegister(REG_PAYLOAD_LENGTH_7X);
|
||||
if ((currentLength + size) > MAX_PKT_LENGTH) {
|
||||
size = MAX_PKT_LENGTH - currentLength;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
writeRegister(REG_FIFO_7X, buffer[i]);
|
||||
}
|
||||
|
||||
writeRegister(REG_PAYLOAD_LENGTH_7X, currentLength + size);
|
||||
return size;
|
||||
}
|
||||
|
||||
int ISR_VECT sx127x::available() { return (readRegister(REG_RX_NB_BYTES_7X) - _packetIndex); }
|
||||
|
||||
int ISR_VECT sx127x::read() {
|
||||
if (!available()) { return -1; }
|
||||
_packetIndex++;
|
||||
return readRegister(REG_FIFO_7X);
|
||||
}
|
||||
|
||||
int sx127x::peek() {
|
||||
if (!available()) { return -1; }
|
||||
|
||||
// Remember current FIFO address, read, and then reset address
|
||||
int currentAddress = readRegister(REG_FIFO_ADDR_PTR_7X);
|
||||
uint8_t b = readRegister(REG_FIFO_7X);
|
||||
writeRegister(REG_FIFO_ADDR_PTR_7X, currentAddress);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void sx127x::onReceive(void(*callback)(int)) {
|
||||
_onReceive = callback;
|
||||
|
||||
if (callback) {
|
||||
pinMode(_dio0, INPUT);
|
||||
writeRegister(REG_DIO_MAPPING_1_7X, 0x00);
|
||||
|
||||
#ifdef SPI_HAS_NOTUSINGINTERRUPT
|
||||
SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
|
||||
#endif
|
||||
|
||||
attachInterrupt(digitalPinToInterrupt(_dio0), sx127x::onDio0Rise, RISING);
|
||||
|
||||
} else {
|
||||
detachInterrupt(digitalPinToInterrupt(_dio0));
|
||||
|
||||
#ifdef SPI_HAS_NOTUSINGINTERRUPT
|
||||
SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void sx127x::receive(int size) {
|
||||
if (size > 0) {
|
||||
implicitHeaderMode();
|
||||
writeRegister(REG_PAYLOAD_LENGTH_7X, size & 0xff);
|
||||
} else { explicitHeaderMode(); }
|
||||
|
||||
writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_RX_CONTINUOUS_7X);
|
||||
}
|
||||
|
||||
void sx127x::setTxPower(int level, int outputPin) {
|
||||
// Setup according to RFO or PA_BOOST output pin
|
||||
if (PA_OUTPUT_RFO_PIN == outputPin) {
|
||||
if (level < 0) { level = 0; }
|
||||
else if (level > 14) { level = 14; }
|
||||
|
||||
writeRegister(REG_PA_DAC_7X, 0x84);
|
||||
writeRegister(REG_PA_CONFIG_7X, 0x70 | level);
|
||||
|
||||
} else {
|
||||
if (level < 2) { level = 2; }
|
||||
else if (level > 17) { level = 17; }
|
||||
|
||||
writeRegister(REG_PA_DAC_7X, 0x84);
|
||||
writeRegister(REG_PA_CONFIG_7X, PA_BOOST_7X | (level - 2));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sx127x::getTxPower() { byte txp = readRegister(REG_PA_CONFIG_7X); return txp; }
|
||||
|
||||
void sx127x::setFrequency(unsigned long frequency) {
|
||||
_frequency = frequency;
|
||||
uint32_t frf = ((uint64_t)frequency << 19) / 32000000;
|
||||
|
||||
writeRegister(REG_FRF_MSB_7X, (uint8_t)(frf >> 16));
|
||||
writeRegister(REG_FRF_MID_7X, (uint8_t)(frf >> 8));
|
||||
writeRegister(REG_FRF_LSB_7X, (uint8_t)(frf >> 0));
|
||||
|
||||
optimizeModemSensitivity();
|
||||
}
|
||||
|
||||
uint32_t sx127x::getFrequency() {
|
||||
uint8_t msb = readRegister(REG_FRF_MSB_7X);
|
||||
uint8_t mid = readRegister(REG_FRF_MID_7X);
|
||||
uint8_t lsb = readRegister(REG_FRF_LSB_7X);
|
||||
|
||||
uint32_t frf = ((uint32_t)msb << 16) | ((uint32_t)mid << 8) | (uint32_t)lsb;
|
||||
uint64_t frm = (uint64_t)frf*32000000;
|
||||
uint32_t frequency = (frm >> 19);
|
||||
|
||||
return frequency;
|
||||
}
|
||||
|
||||
void sx127x::setSpreadingFactor(int sf) {
|
||||
if (sf < 6) { sf = 6; }
|
||||
else if (sf > 12) { sf = 12; }
|
||||
|
||||
if (sf == 6) {
|
||||
writeRegister(REG_DETECTION_OPTIMIZE_7X, 0xc5);
|
||||
writeRegister(REG_DETECTION_THRESHOLD_7X, 0x0c);
|
||||
} else {
|
||||
writeRegister(REG_DETECTION_OPTIMIZE_7X, 0xc3);
|
||||
writeRegister(REG_DETECTION_THRESHOLD_7X, 0x0a);
|
||||
}
|
||||
|
||||
writeRegister(REG_MODEM_CONFIG_2_7X, (readRegister(REG_MODEM_CONFIG_2_7X) & 0x0f) | ((sf << 4) & 0xf0));
|
||||
handleLowDataRate();
|
||||
}
|
||||
|
||||
long sx127x::getSignalBandwidth() {
|
||||
byte bw = (readRegister(REG_MODEM_CONFIG_1_7X) >> 4);
|
||||
switch (bw) {
|
||||
case 0: return 7.8E3;
|
||||
case 1: return 10.4E3;
|
||||
case 2: return 15.6E3;
|
||||
case 3: return 20.8E3;
|
||||
case 4: return 31.25E3;
|
||||
case 5: return 41.7E3;
|
||||
case 6: return 62.5E3;
|
||||
case 7: return 125E3;
|
||||
case 8: return 250E3;
|
||||
case 9: return 500E3; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sx127x::setSignalBandwidth(long sbw) {
|
||||
int bw;
|
||||
if (sbw <= 7.8E3) {
|
||||
bw = 0;
|
||||
} else if (sbw <= 10.4E3) {
|
||||
bw = 1;
|
||||
} else if (sbw <= 15.6E3) {
|
||||
bw = 2;
|
||||
} else if (sbw <= 20.8E3) {
|
||||
bw = 3;
|
||||
} else if (sbw <= 31.25E3) {
|
||||
bw = 4;
|
||||
} else if (sbw <= 41.7E3) {
|
||||
bw = 5;
|
||||
} else if (sbw <= 62.5E3) {
|
||||
bw = 6;
|
||||
} else if (sbw <= 125E3) {
|
||||
bw = 7;
|
||||
} else if (sbw <= 250E3) {
|
||||
bw = 8;
|
||||
} else /*if (sbw <= 250E3)*/ {
|
||||
bw = 9;
|
||||
}
|
||||
|
||||
writeRegister(REG_MODEM_CONFIG_1_7X, (readRegister(REG_MODEM_CONFIG_1_7X) & 0x0f) | (bw << 4));
|
||||
handleLowDataRate();
|
||||
optimizeModemSensitivity();
|
||||
}
|
||||
|
||||
void sx127x::setCodingRate4(int denominator) {
|
||||
if (denominator < 5) { denominator = 5; }
|
||||
else if (denominator > 8) { denominator = 8; }
|
||||
int cr = denominator - 4;
|
||||
writeRegister(REG_MODEM_CONFIG_1_7X, (readRegister(REG_MODEM_CONFIG_1_7X) & 0xf1) | (cr << 1));
|
||||
}
|
||||
|
||||
void sx127x::setPreambleLength(long length) {
|
||||
writeRegister(REG_PREAMBLE_MSB_7X, (uint8_t)(length >> 8));
|
||||
writeRegister(REG_PREAMBLE_LSB_7X, (uint8_t)(length >> 0));
|
||||
}
|
||||
|
||||
void sx127x::handleLowDataRate() {
|
||||
int sf = (readRegister(REG_MODEM_CONFIG_2_7X) >> 4);
|
||||
if ( long( (1<<sf) / (getSignalBandwidth()/1000)) > 16) {
|
||||
// Set auto AGC and LowDataRateOptimize
|
||||
writeRegister(REG_MODEM_CONFIG_3_7X, (1<<3)|(1<<2));
|
||||
} else {
|
||||
// Only set auto AGC
|
||||
writeRegister(REG_MODEM_CONFIG_3_7X, (1<<2));
|
||||
}
|
||||
}
|
||||
|
||||
void sx127x::optimizeModemSensitivity() {
|
||||
byte bw = (readRegister(REG_MODEM_CONFIG_1_7X) >> 4);
|
||||
uint32_t freq = getFrequency();
|
||||
|
||||
if (bw == 9 && (410E6 <= freq) && (freq <= 525E6)) {
|
||||
writeRegister(REG_HIGH_BW_OPTIMIZE_1_7X, 0x02);
|
||||
writeRegister(REG_HIGH_BW_OPTIMIZE_2_7X, 0x7f);
|
||||
} else if (bw == 9 && (820E6 <= freq) && (freq <= 1020E6)) {
|
||||
writeRegister(REG_HIGH_BW_OPTIMIZE_1_7X, 0x02);
|
||||
writeRegister(REG_HIGH_BW_OPTIMIZE_2_7X, 0x64);
|
||||
} else {
|
||||
writeRegister(REG_HIGH_BW_OPTIMIZE_1_7X, 0x03);
|
||||
}
|
||||
}
|
||||
|
||||
void ISR_VECT sx127x::handleDio0Rise() {
|
||||
int irqFlags = readRegister(REG_IRQ_FLAGS_7X);
|
||||
|
||||
// Clear IRQs
|
||||
writeRegister(REG_IRQ_FLAGS_7X, irqFlags);
|
||||
if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK_7X) == 0) {
|
||||
_packetIndex = 0;
|
||||
int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH_7X) : readRegister(REG_RX_NB_BYTES_7X);
|
||||
writeRegister(REG_FIFO_ADDR_PTR_7X, readRegister(REG_FIFO_RX_CURRENT_ADDR_7X));
|
||||
if (_onReceive) { _onReceive(packetLength); }
|
||||
writeRegister(REG_FIFO_ADDR_PTR_7X, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ISR_VECT sx127x::onDio0Rise() { sx127x_modem.handleDio0Rise(); }
|
||||
|
||||
sx127x sx127x_modem;
|
||||
|
||||
#endif
|
111
sx127x.h
111
sx127x.h
@ -1,111 +0,0 @@
|
||||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// Modifications and additions copyright 2023 by Mark Qvist
|
||||
// Obviously still under the MIT license.
|
||||
|
||||
#ifndef SX1276_H
|
||||
#define SX1276_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "Modem.h"
|
||||
|
||||
#define LORA_DEFAULT_SS_PIN 10
|
||||
#define LORA_DEFAULT_RESET_PIN 9
|
||||
#define LORA_DEFAULT_DIO0_PIN 2
|
||||
#define LORA_DEFAULT_BUSY_PIN -1
|
||||
|
||||
#define PA_OUTPUT_RFO_PIN 0
|
||||
#define PA_OUTPUT_PA_BOOST_PIN 1
|
||||
|
||||
#define RSSI_OFFSET 157
|
||||
|
||||
class sx127x : public Stream {
|
||||
public:
|
||||
sx127x();
|
||||
|
||||
int begin(long frequency);
|
||||
void end();
|
||||
|
||||
int beginPacket(int implicitHeader = false);
|
||||
int endPacket();
|
||||
|
||||
int parsePacket(int size = 0);
|
||||
int packetRssi();
|
||||
int currentRssi();
|
||||
uint8_t packetRssiRaw();
|
||||
uint8_t currentRssiRaw();
|
||||
uint8_t packetSnrRaw();
|
||||
float packetSnr();
|
||||
long packetFrequencyError();
|
||||
|
||||
// from Print
|
||||
virtual size_t write(uint8_t byte);
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
// from Stream
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual int peek();
|
||||
virtual void flush();
|
||||
|
||||
void onReceive(void(*callback)(int));
|
||||
|
||||
void receive(int size = 0);
|
||||
void standby();
|
||||
void sleep();
|
||||
|
||||
bool preInit();
|
||||
uint8_t getTxPower();
|
||||
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
||||
uint32_t getFrequency();
|
||||
void setFrequency(unsigned long frequency);
|
||||
void setSpreadingFactor(int sf);
|
||||
long getSignalBandwidth();
|
||||
void setSignalBandwidth(long sbw);
|
||||
void setCodingRate4(int denominator);
|
||||
void setPreambleLength(long length);
|
||||
void setSyncWord(uint8_t sw);
|
||||
uint8_t modemStatus();
|
||||
void enableCrc();
|
||||
void disableCrc();
|
||||
void enableTCXO();
|
||||
void disableTCXO();
|
||||
|
||||
byte random();
|
||||
|
||||
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN, int busy = LORA_DEFAULT_BUSY_PIN);
|
||||
void setSPIFrequency(uint32_t frequency);
|
||||
|
||||
private:
|
||||
void explicitHeaderMode();
|
||||
void implicitHeaderMode();
|
||||
|
||||
void handleDio0Rise();
|
||||
|
||||
uint8_t readRegister(uint8_t address);
|
||||
void writeRegister(uint8_t address, uint8_t value);
|
||||
uint8_t singleTransfer(uint8_t address, uint8_t value);
|
||||
|
||||
static void onDio0Rise();
|
||||
|
||||
void handleLowDataRate();
|
||||
void optimizeModemSensitivity();
|
||||
|
||||
private:
|
||||
SPISettings _spiSettings;
|
||||
int _ss;
|
||||
int _reset;
|
||||
int _dio0;
|
||||
int _busy;
|
||||
long _frequency;
|
||||
int _packetIndex;
|
||||
int _implicitHeaderMode;
|
||||
bool _preinit_done;
|
||||
void (*_onReceive)(int);
|
||||
};
|
||||
|
||||
extern sx127x sx127x_modem;
|
||||
|
||||
#endif
|
889
sx128x.cpp
889
sx128x.cpp
@ -1,889 +0,0 @@
|
||||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva
|
||||
// Obviously still under the MIT license.
|
||||
|
||||
#include "sx128x.h"
|
||||
#include "Boards.h"
|
||||
|
||||
#define MCU_1284P 0x91
|
||||
#define MCU_2560 0x92
|
||||
#define MCU_ESP32 0x81
|
||||
#define MCU_NRF52 0x71
|
||||
#if defined(__AVR_ATmega1284P__)
|
||||
#define PLATFORM PLATFORM_AVR
|
||||
#define MCU_VARIANT MCU_1284P
|
||||
#elif defined(__AVR_ATmega2560__)
|
||||
#define PLATFORM PLATFORM_AVR
|
||||
#define MCU_VARIANT MCU_2560
|
||||
#elif defined(ESP32)
|
||||
#define PLATFORM PLATFORM_ESP32
|
||||
#define MCU_VARIANT MCU_ESP32
|
||||
#elif defined(NRF52840_XXAA)
|
||||
#define PLATFORM PLATFORM_NRF52
|
||||
#define MCU_VARIANT MCU_NRF52
|
||||
#endif
|
||||
|
||||
#ifndef MCU_VARIANT
|
||||
#error No MCU variant defined, cannot compile
|
||||
#endif
|
||||
|
||||
#if MCU_VARIANT == MCU_ESP32
|
||||
#if MCU_VARIANT == MCU_ESP32 and !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#include "soc/rtc_wdt.h"
|
||||
#endif
|
||||
#define ISR_VECT IRAM_ATTR
|
||||
#else
|
||||
#define ISR_VECT
|
||||
#endif
|
||||
|
||||
#define OP_RF_FREQ_8X 0x86
|
||||
#define OP_SLEEP_8X 0x84
|
||||
#define OP_STANDBY_8X 0x80
|
||||
#define OP_TX_8X 0x83
|
||||
#define OP_RX_8X 0x82
|
||||
#define OP_SET_IRQ_FLAGS_8X 0x8D // also provides info such as
|
||||
// preamble detection, etc for
|
||||
// knowing when it's safe to switch
|
||||
// antenna modes
|
||||
#define OP_CLEAR_IRQ_STATUS_8X 0x97
|
||||
#define OP_GET_IRQ_STATUS_8X 0x15
|
||||
#define OP_RX_BUFFER_STATUS_8X 0x17
|
||||
#define OP_PACKET_STATUS_8X 0x1D // get snr & rssi of last packet
|
||||
#define OP_CURRENT_RSSI_8X 0x1F
|
||||
#define OP_MODULATION_PARAMS_8X 0x8B // bw, sf, cr, etc.
|
||||
#define OP_PACKET_PARAMS_8X 0x8C // crc, preamble, payload length, etc.
|
||||
#define OP_STATUS_8X 0xC0
|
||||
#define OP_TX_PARAMS_8X 0x8E // set dbm, etc
|
||||
#define OP_PACKET_TYPE_8X 0x8A
|
||||
#define OP_BUFFER_BASE_ADDR_8X 0x8F
|
||||
#define OP_READ_REGISTER_8X 0x19
|
||||
#define OP_WRITE_REGISTER_8X 0x18
|
||||
#define IRQ_TX_DONE_MASK_8X 0x01
|
||||
#define IRQ_RX_DONE_MASK_8X 0x02
|
||||
#define IRQ_HEADER_DET_MASK_8X 0x10
|
||||
#define IRQ_HEADER_ERROR_MASK_8X 0x20
|
||||
#define IRQ_PAYLOAD_CRC_ERROR_MASK_8X 0x40
|
||||
|
||||
#define MODE_LONG_RANGE_MODE_8X 0x01
|
||||
|
||||
#define OP_FIFO_WRITE_8X 0x1A
|
||||
#define OP_FIFO_READ_8X 0x1B
|
||||
#define IRQ_PREAMBLE_DET_MASK_8X 0x80
|
||||
|
||||
#define REG_PACKET_SIZE 0x901
|
||||
#define REG_FIRM_VER_MSB 0x154
|
||||
#define REG_FIRM_VER_LSB 0x153
|
||||
|
||||
#define XTAL_FREQ_8X (double)52000000
|
||||
#define FREQ_DIV_8X (double)pow(2.0, 18.0)
|
||||
#define FREQ_STEP_8X (double)(XTAL_FREQ_8X / FREQ_DIV_8X)
|
||||
|
||||
#if defined(NRF52840_XXAA)
|
||||
extern SPIClass spiModem;
|
||||
#define SPI spiModem
|
||||
#endif
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
||||
#define MAX_PKT_LENGTH 255
|
||||
|
||||
sx128x::sx128x() :
|
||||
_spiSettings(8E6, MSBFIRST, SPI_MODE0),
|
||||
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _rxen(LORA_DEFAULT_RXEN_PIN), _busy(LORA_DEFAULT_BUSY_PIN),
|
||||
_frequency(0),
|
||||
_txp(0),
|
||||
_sf(0x50),
|
||||
_bw(0x34),
|
||||
_cr(0x01),
|
||||
_packetIndex(0),
|
||||
_preambleLength(18),
|
||||
_implicitHeaderMode(0),
|
||||
_payloadLength(255),
|
||||
_crcMode(0),
|
||||
_fifo_tx_addr_ptr(0),
|
||||
_fifo_rx_addr_ptr(0),
|
||||
_packet({0}),
|
||||
_rxPacketLength(0),
|
||||
_preinit_done(false),
|
||||
_onReceive(NULL)
|
||||
{
|
||||
// overide Stream timeout value
|
||||
setTimeout(0);
|
||||
}
|
||||
|
||||
bool sx128x::preInit() {
|
||||
// setup pins
|
||||
pinMode(_ss, OUTPUT);
|
||||
// set SS high
|
||||
digitalWrite(_ss, HIGH);
|
||||
|
||||
SPI.begin();
|
||||
|
||||
// check version (retry for up to 2 seconds)
|
||||
long start = millis();
|
||||
|
||||
uint8_t version_msb;
|
||||
uint8_t version_lsb;
|
||||
|
||||
while (((millis() - start) < 2000) && (millis() >= start)) {
|
||||
|
||||
version_msb = readRegister(REG_FIRM_VER_MSB);
|
||||
version_lsb = readRegister(REG_FIRM_VER_LSB);
|
||||
|
||||
if ((version_msb == 0xB7 && version_lsb == 0xA9) || (version_msb == 0xB5 && version_lsb == 0xA9)) {
|
||||
break;
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
if ((version_msb != 0xB7 || version_lsb != 0xA9) && (version_msb != 0xB5 || version_lsb != 0xA9)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_preinit_done = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t ISR_VECT sx128x::readRegister(uint16_t address)
|
||||
{
|
||||
return singleTransfer(OP_READ_REGISTER_8X, address, 0x00);
|
||||
}
|
||||
|
||||
void sx128x::writeRegister(uint16_t address, uint8_t value)
|
||||
{
|
||||
singleTransfer(OP_WRITE_REGISTER_8X, address, value);
|
||||
}
|
||||
|
||||
uint8_t ISR_VECT sx128x::singleTransfer(uint8_t opcode, uint16_t address, uint8_t value)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
uint8_t response;
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(opcode);
|
||||
SPI.transfer((address & 0xFF00) >> 8);
|
||||
SPI.transfer(address & 0x00FF);
|
||||
if (opcode == OP_READ_REGISTER_8X) {
|
||||
SPI.transfer(0x00);
|
||||
}
|
||||
response = SPI.transfer(value);
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void sx128x::rxAntEnable()
|
||||
{
|
||||
if (_txen != -1) {
|
||||
digitalWrite(_txen, LOW);
|
||||
}
|
||||
if (_rxen != -1) {
|
||||
digitalWrite(_rxen, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
void sx128x::txAntEnable()
|
||||
{
|
||||
if (_txen != -1) {
|
||||
digitalWrite(_txen, HIGH);
|
||||
}
|
||||
if (_rxen != -1) {
|
||||
digitalWrite(_rxen, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void sx128x::loraMode() {
|
||||
// enable lora mode on the SX1262 chip
|
||||
uint8_t mode = MODE_LONG_RANGE_MODE_8X;
|
||||
executeOpcode(OP_PACKET_TYPE_8X, &mode, 1);
|
||||
}
|
||||
|
||||
void sx128x::waitOnBusy() {
|
||||
unsigned long time = millis();
|
||||
if (_busy != -1) {
|
||||
while (digitalRead(_busy) == HIGH)
|
||||
{
|
||||
if (millis() >= (time + 100)) {
|
||||
break;
|
||||
}
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sx128x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(opcode);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
SPI.transfer(buffer[i]);
|
||||
}
|
||||
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
}
|
||||
|
||||
void sx128x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(opcode);
|
||||
SPI.transfer(0x00);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
buffer[i] = SPI.transfer(0x00);
|
||||
}
|
||||
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
}
|
||||
|
||||
void sx128x::writeBuffer(const uint8_t* buffer, size_t size)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(OP_FIFO_WRITE_8X);
|
||||
SPI.transfer(_fifo_tx_addr_ptr);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
SPI.transfer(buffer[i]);
|
||||
_fifo_tx_addr_ptr++;
|
||||
}
|
||||
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
}
|
||||
|
||||
void sx128x::readBuffer(uint8_t* buffer, size_t size)
|
||||
{
|
||||
waitOnBusy();
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
SPI.beginTransaction(_spiSettings);
|
||||
SPI.transfer(OP_FIFO_READ_8X);
|
||||
SPI.transfer(_fifo_rx_addr_ptr);
|
||||
SPI.transfer(0x00);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
buffer[i] = SPI.transfer(0x00);
|
||||
}
|
||||
|
||||
SPI.endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
}
|
||||
|
||||
void sx128x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr) {
|
||||
// because there is no access to these registers on the sx1280, we have
|
||||
// to set all these parameters at once or not at all.
|
||||
uint8_t buf[3];
|
||||
|
||||
buf[0] = sf;
|
||||
buf[1] = bw;
|
||||
buf[2] = cr;
|
||||
executeOpcode(OP_MODULATION_PARAMS_8X, buf, 3);
|
||||
|
||||
if (sf <= 6) {
|
||||
writeRegister(0x925, 0x1E);
|
||||
} else if (sf <= 8) {
|
||||
writeRegister(0x925, 0x37);
|
||||
} else if (sf >= 9) {
|
||||
writeRegister(0x925, 0x32);
|
||||
}
|
||||
writeRegister(0x093C, 0x1);
|
||||
}
|
||||
|
||||
void sx128x::setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
|
||||
// because there is no access to these registers on the sx1280, we have
|
||||
// to set all these parameters at once or not at all.
|
||||
uint8_t buf[7];
|
||||
|
||||
// calculate exponent and mantissa values for modem
|
||||
uint8_t e = 1;
|
||||
uint8_t m = 1;
|
||||
uint32_t preamblelen;
|
||||
|
||||
for (e <= 15; e++;) {
|
||||
for (m <= 15; m++;) {
|
||||
preamblelen = m * (uint32_t(1) << e);
|
||||
if (preamblelen >= preamble) break;
|
||||
}
|
||||
if (preamblelen >= preamble) break;
|
||||
}
|
||||
|
||||
buf[0] = (e << 4) | m;
|
||||
buf[1] = headermode;
|
||||
buf[2] = length;
|
||||
buf[3] = crc;
|
||||
// standard IQ setting (no inversion)
|
||||
buf[4] = 0x40;
|
||||
// unused params
|
||||
buf[5] = 0x00;
|
||||
buf[6] = 0x00;
|
||||
|
||||
executeOpcode(OP_PACKET_PARAMS_8X, buf, 7);
|
||||
}
|
||||
|
||||
int sx128x::begin(unsigned long frequency)
|
||||
{
|
||||
if (_reset != -1) {
|
||||
pinMode(_reset, OUTPUT);
|
||||
|
||||
// perform reset
|
||||
digitalWrite(_reset, LOW);
|
||||
delay(10);
|
||||
digitalWrite(_reset, HIGH);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
if (_rxen != -1) {
|
||||
pinMode(_rxen, OUTPUT);
|
||||
}
|
||||
|
||||
if (_txen != -1) {
|
||||
pinMode(_txen, OUTPUT);
|
||||
}
|
||||
|
||||
if (_busy != -1) {
|
||||
pinMode(_busy, INPUT);
|
||||
}
|
||||
|
||||
if (!_preinit_done) {
|
||||
if (!preInit()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
idle();
|
||||
loraMode();
|
||||
rxAntEnable();
|
||||
|
||||
setFrequency(frequency);
|
||||
|
||||
// set LNA boost
|
||||
// todo: implement this
|
||||
//writeRegister(REG_LNA, 0x96);
|
||||
|
||||
setModulationParams(_sf, _bw, _cr);
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
// set output power to 2 dBm
|
||||
setTxPower(2);
|
||||
|
||||
// set base addresses
|
||||
uint8_t basebuf[2] = {0};
|
||||
executeOpcode(OP_BUFFER_BASE_ADDR_8X, basebuf, 2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void sx128x::end()
|
||||
{
|
||||
// put in sleep mode
|
||||
sleep();
|
||||
|
||||
// stop SPI
|
||||
SPI.end();
|
||||
|
||||
_preinit_done = false;
|
||||
}
|
||||
|
||||
int sx128x::beginPacket(int implicitHeader)
|
||||
{
|
||||
// put in standby mode
|
||||
idle();
|
||||
|
||||
if (implicitHeader) {
|
||||
implicitHeaderMode();
|
||||
} else {
|
||||
explicitHeaderMode();
|
||||
}
|
||||
|
||||
_payloadLength = 0;
|
||||
_fifo_tx_addr_ptr = 0;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sx128x::endPacket()
|
||||
{
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
txAntEnable();
|
||||
|
||||
// put in single TX mode
|
||||
uint8_t timeout[3] = {0};
|
||||
executeOpcode(OP_TX_8X, timeout, 3);
|
||||
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = 0x00;
|
||||
buf[1] = 0x00;
|
||||
|
||||
executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
|
||||
|
||||
// wait for TX done
|
||||
while ((buf[1] & IRQ_TX_DONE_MASK_8X) == 0) {
|
||||
buf[0] = 0x00;
|
||||
buf[1] = 0x00;
|
||||
executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
|
||||
yield();
|
||||
}
|
||||
|
||||
// clear IRQ's
|
||||
|
||||
uint8_t mask[2];
|
||||
mask[0] = 0x00;
|
||||
mask[1] = IRQ_TX_DONE_MASK_8X;
|
||||
executeOpcode(OP_CLEAR_IRQ_STATUS_8X, mask, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t sx128x::modemStatus() {
|
||||
// imitate the register status from the sx1276 / 78
|
||||
uint8_t buf[2] = {0};
|
||||
|
||||
executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
|
||||
|
||||
uint8_t clearbuf[2] = {0};
|
||||
|
||||
uint8_t byte = 0x00;
|
||||
|
||||
if ((buf[0] & IRQ_PREAMBLE_DET_MASK_8X) != 0) {
|
||||
byte = byte | 0x01 | 0x04;
|
||||
// clear register after reading
|
||||
clearbuf[0] = 0xFF;
|
||||
}
|
||||
|
||||
if ((buf[1] & IRQ_HEADER_DET_MASK_8X) != 0) {
|
||||
byte = byte | 0x02 | 0x04;
|
||||
// clear register after reading
|
||||
clearbuf[1] = 0xFF;
|
||||
}
|
||||
|
||||
executeOpcode(OP_CLEAR_IRQ_STATUS_8X, clearbuf, 2);
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
|
||||
uint8_t sx128x::currentRssiRaw() {
|
||||
uint8_t byte = 0;
|
||||
executeOpcodeRead(OP_CURRENT_RSSI_8X, &byte, 1);
|
||||
return byte;
|
||||
}
|
||||
|
||||
int ISR_VECT sx128x::currentRssi() {
|
||||
uint8_t byte = 0;
|
||||
executeOpcodeRead(OP_CURRENT_RSSI_8X, &byte, 1);
|
||||
int rssi = -byte / 2;
|
||||
return rssi;
|
||||
}
|
||||
|
||||
uint8_t sx128x::packetRssiRaw() {
|
||||
uint8_t buf[5] = {0};
|
||||
executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5);
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
int ISR_VECT sx128x::packetRssi() {
|
||||
// may need more calculations here
|
||||
uint8_t buf[5] = {0};
|
||||
executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5);
|
||||
int pkt_rssi = -buf[0] / 2;
|
||||
return pkt_rssi;
|
||||
}
|
||||
|
||||
uint8_t ISR_VECT sx128x::packetSnrRaw() {
|
||||
uint8_t buf[5] = {0};
|
||||
executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5);
|
||||
return buf[1];
|
||||
}
|
||||
|
||||
float ISR_VECT sx128x::packetSnr() {
|
||||
uint8_t buf[5] = {0};
|
||||
executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 3);
|
||||
return float(buf[1]) * 0.25;
|
||||
}
|
||||
|
||||
long sx128x::packetFrequencyError()
|
||||
{
|
||||
int32_t freqError = 0;
|
||||
// todo: implement this, page 120 of sx1280 datasheet
|
||||
const float fError = 0.0;
|
||||
return static_cast<long>(fError);
|
||||
}
|
||||
|
||||
size_t sx128x::write(uint8_t byte)
|
||||
{
|
||||
return write(&byte, sizeof(byte));
|
||||
}
|
||||
|
||||
size_t sx128x::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
if ((_payloadLength + size) > MAX_PKT_LENGTH) {
|
||||
size = MAX_PKT_LENGTH - _payloadLength;
|
||||
}
|
||||
|
||||
// write data
|
||||
writeBuffer(buffer, size);
|
||||
_payloadLength = _payloadLength + size;
|
||||
return size;
|
||||
}
|
||||
|
||||
int ISR_VECT sx128x::available()
|
||||
{
|
||||
return _rxPacketLength - _packetIndex;
|
||||
}
|
||||
|
||||
int ISR_VECT sx128x::read()
|
||||
{
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t byte = _packet[_packetIndex];
|
||||
_packetIndex++;
|
||||
return byte;
|
||||
}
|
||||
|
||||
int sx128x::peek()
|
||||
{
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t b = _packet[_packetIndex];
|
||||
return b;
|
||||
}
|
||||
|
||||
void sx128x::flush()
|
||||
{
|
||||
}
|
||||
|
||||
void sx128x::onReceive(void(*callback)(int))
|
||||
{
|
||||
_onReceive = callback;
|
||||
|
||||
if (callback) {
|
||||
pinMode(_dio0, INPUT);
|
||||
|
||||
// set preamble and header detection irqs, plus dio0 mask
|
||||
uint8_t buf[8];
|
||||
|
||||
// set irq masks, enable all
|
||||
buf[0] = 0xFF;
|
||||
buf[1] = 0xFF;
|
||||
|
||||
// set dio0 masks
|
||||
buf[2] = 0x00;
|
||||
buf[3] = IRQ_RX_DONE_MASK_8X;
|
||||
|
||||
// set dio1 masks
|
||||
buf[4] = 0x00;
|
||||
buf[5] = 0x00;
|
||||
|
||||
// set dio2 masks
|
||||
buf[6] = 0x00;
|
||||
buf[7] = 0x00;
|
||||
|
||||
executeOpcode(OP_SET_IRQ_FLAGS_8X, buf, 8);
|
||||
//#ifdef SPI_HAS_NOTUSINGINTERRUPT
|
||||
// SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
|
||||
//#endif
|
||||
attachInterrupt(digitalPinToInterrupt(_dio0), sx128x::onDio0Rise, RISING);
|
||||
} else {
|
||||
detachInterrupt(digitalPinToInterrupt(_dio0));
|
||||
//#ifdef SPI_HAS_NOTUSINGINTERRUPT
|
||||
// SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0));
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
|
||||
void sx128x::receive(int size)
|
||||
{
|
||||
if (size > 0) {
|
||||
implicitHeaderMode();
|
||||
|
||||
// tell radio payload length
|
||||
_rxPacketLength = size;
|
||||
//_payloadLength = size;
|
||||
//setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
} else {
|
||||
explicitHeaderMode();
|
||||
}
|
||||
|
||||
rxAntEnable();
|
||||
|
||||
uint8_t mode[3] = {0xFF, 0xFF, 0xFF}; // continuous mode
|
||||
executeOpcode(OP_RX_8X, mode, 3);
|
||||
}
|
||||
|
||||
void sx128x::idle()
|
||||
{
|
||||
#if HAS_TCXO
|
||||
// STDBY_XOSC
|
||||
uint8_t byte = 0x01;
|
||||
#else
|
||||
// STDBY_RC
|
||||
uint8_t byte = 0x00;
|
||||
#endif
|
||||
executeOpcode(OP_STANDBY_8X, &byte, 1);
|
||||
}
|
||||
|
||||
void sx128x::sleep()
|
||||
{
|
||||
uint8_t byte = 0x00;
|
||||
executeOpcode(OP_SLEEP_8X, &byte, 1);
|
||||
}
|
||||
|
||||
void sx128x::enableTCXO() {
|
||||
// todo: need to check how to implement on sx1280
|
||||
}
|
||||
|
||||
void sx128x::disableTCXO() {
|
||||
// todo: need to check how to implement on sx1280
|
||||
}
|
||||
|
||||
void sx128x::setTxPower(int level, int outputPin) {
|
||||
if (level > 13) {
|
||||
level = 13;
|
||||
} else if (level < -18) {
|
||||
level = -18;
|
||||
}
|
||||
|
||||
_txp = level;
|
||||
|
||||
level = level + 18;
|
||||
|
||||
uint8_t tx_buf[2];
|
||||
|
||||
tx_buf[0] = level;
|
||||
tx_buf[1] = 0xE0; // ramping time - 20 microseconds
|
||||
|
||||
executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2);
|
||||
}
|
||||
|
||||
uint8_t sx128x::getTxPower() {
|
||||
return _txp;
|
||||
}
|
||||
|
||||
void sx128x::setFrequency(unsigned long frequency) {
|
||||
_frequency = frequency;
|
||||
|
||||
uint8_t buf[3];
|
||||
|
||||
uint32_t freq = (uint32_t)((double)frequency / (double)FREQ_STEP_8X);
|
||||
|
||||
buf[0] = ((freq >> 16) & 0xFF);
|
||||
buf[1] = ((freq >> 8) & 0xFF);
|
||||
buf[2] = (freq & 0xFF);
|
||||
|
||||
executeOpcode(OP_RF_FREQ_8X, buf, 3);
|
||||
}
|
||||
|
||||
uint32_t sx128x::getFrequency() {
|
||||
// we can't read the frequency on the sx1280
|
||||
uint32_t frequency = _frequency;
|
||||
|
||||
return frequency;
|
||||
}
|
||||
|
||||
void sx128x::setSpreadingFactor(int sf)
|
||||
{
|
||||
if (sf < 5) {
|
||||
sf = 5;
|
||||
} else if (sf > 12) {
|
||||
sf = 12;
|
||||
}
|
||||
|
||||
_sf = sf << 4;
|
||||
|
||||
setModulationParams(sf << 4, _bw, _cr);
|
||||
handleLowDataRate();
|
||||
}
|
||||
|
||||
long sx128x::getSignalBandwidth()
|
||||
{
|
||||
int bw = _bw;
|
||||
switch (bw) {
|
||||
case 0x34: return 203.125E3;
|
||||
case 0x26: return 406.25E3;
|
||||
case 0x18: return 812.5E3;
|
||||
case 0x0A: return 1625E3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sx128x::handleLowDataRate(){
|
||||
// todo: do i need this??
|
||||
}
|
||||
|
||||
void sx128x::optimizeModemSensitivity(){
|
||||
// todo: check if there's anything the sx1280 can do here
|
||||
}
|
||||
|
||||
void sx128x::setSignalBandwidth(long sbw)
|
||||
{
|
||||
if (sbw <= 203.125E3) {
|
||||
_bw = 0x34;
|
||||
} else if (sbw <= 406.25E3) {
|
||||
_bw = 0x26;
|
||||
} else if (sbw <= 812.5E3) {
|
||||
_bw = 0x18;
|
||||
} else {
|
||||
_bw = 0x0A;
|
||||
}
|
||||
|
||||
setModulationParams(_sf, _bw, _cr);
|
||||
|
||||
handleLowDataRate();
|
||||
optimizeModemSensitivity();
|
||||
}
|
||||
|
||||
void sx128x::setCodingRate4(int denominator)
|
||||
{
|
||||
if (denominator < 5) {
|
||||
denominator = 5;
|
||||
} else if (denominator > 8) {
|
||||
denominator = 8;
|
||||
}
|
||||
|
||||
_cr = denominator - 4;
|
||||
|
||||
// todo: add support for new interleaving scheme, see page 117 of sx1280
|
||||
// datasheet
|
||||
|
||||
// update cr values for sx1280's use
|
||||
|
||||
setModulationParams(_sf, _bw, _cr);
|
||||
}
|
||||
|
||||
void sx128x::setPreambleLength(long length)
|
||||
{
|
||||
_preambleLength = length;
|
||||
setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
void sx128x::setSyncWord(int sw)
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
|
||||
void sx128x::enableCrc()
|
||||
{
|
||||
_crcMode = 0x20;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
void sx128x::disableCrc()
|
||||
{
|
||||
_crcMode = 0;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
byte sx128x::random()
|
||||
{
|
||||
// todo: implement
|
||||
}
|
||||
|
||||
void sx128x::setPins(int ss, int reset, int dio0, int busy, int rxen, int txen)
|
||||
{
|
||||
_ss = ss;
|
||||
_reset = reset;
|
||||
_dio0 = dio0;
|
||||
_busy = busy;
|
||||
_rxen = rxen;
|
||||
_txen = txen;
|
||||
}
|
||||
|
||||
void sx128x::setSPIFrequency(uint32_t frequency)
|
||||
{
|
||||
_spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0);
|
||||
}
|
||||
|
||||
void sx128x::dumpRegisters(Stream& out)
|
||||
{
|
||||
for (int i = 0; i < 128; i++) {
|
||||
out.print("0x");
|
||||
out.print(i, HEX);
|
||||
out.print(": 0x");
|
||||
out.println(readRegister(i), HEX);
|
||||
}
|
||||
}
|
||||
|
||||
void sx128x::explicitHeaderMode()
|
||||
{
|
||||
_implicitHeaderMode = 0;
|
||||
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
void sx128x::implicitHeaderMode()
|
||||
{
|
||||
_implicitHeaderMode = 0x80;
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
}
|
||||
|
||||
|
||||
void ISR_VECT sx128x::handleDio0Rise()
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = 0x00;
|
||||
buf[1] = 0x00;
|
||||
|
||||
executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
|
||||
|
||||
executeOpcode(OP_CLEAR_IRQ_STATUS_8X, buf, 2);
|
||||
|
||||
if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_8X) == 0) {
|
||||
// received a packet
|
||||
_packetIndex = 0;
|
||||
|
||||
uint8_t rxbuf[2] = {0};
|
||||
executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2);
|
||||
_rxPacketLength = rxbuf[0];
|
||||
_fifo_rx_addr_ptr = rxbuf[1];
|
||||
readBuffer(_packet, _rxPacketLength);
|
||||
|
||||
if (_onReceive) {
|
||||
_onReceive(_rxPacketLength);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ISR_VECT sx128x::onDio0Rise()
|
||||
{
|
||||
sx128x_modem.handleDio0Rise();
|
||||
}
|
||||
|
||||
sx128x sx128x_modem;
|
144
sx128x.h
144
sx128x.h
@ -1,144 +0,0 @@
|
||||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// Modifications and additions copyright 2023 by Mark Qvist
|
||||
// Obviously still under the MIT license.
|
||||
|
||||
#ifndef SX128X_H
|
||||
#define SX128X_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "Modem.h"
|
||||
|
||||
#define LORA_DEFAULT_SS_PIN 10
|
||||
#define LORA_DEFAULT_RESET_PIN 9
|
||||
#define LORA_DEFAULT_DIO0_PIN 2
|
||||
#define LORA_DEFAULT_RXEN_PIN -1
|
||||
#define LORA_DEFAULT_TXEN_PIN -1
|
||||
#define LORA_DEFAULT_BUSY_PIN -1
|
||||
|
||||
#define PA_OUTPUT_RFO_PIN 0
|
||||
#define PA_OUTPUT_PA_BOOST_PIN 1
|
||||
|
||||
#define RSSI_OFFSET 157
|
||||
|
||||
class sx128x : public Stream {
|
||||
public:
|
||||
sx128x();
|
||||
|
||||
int begin(unsigned long frequency);
|
||||
void end();
|
||||
|
||||
int beginPacket(int implicitHeader = false);
|
||||
int endPacket();
|
||||
|
||||
int parsePacket(int size = 0);
|
||||
int packetRssi();
|
||||
int currentRssi();
|
||||
uint8_t packetRssiRaw();
|
||||
uint8_t currentRssiRaw();
|
||||
uint8_t packetSnrRaw();
|
||||
float packetSnr();
|
||||
long packetFrequencyError();
|
||||
|
||||
// from Print
|
||||
virtual size_t write(uint8_t byte);
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
// from Stream
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual int peek();
|
||||
virtual void flush();
|
||||
|
||||
void onReceive(void(*callback)(int));
|
||||
|
||||
void receive(int size = 0);
|
||||
void idle();
|
||||
void sleep();
|
||||
|
||||
bool preInit();
|
||||
uint8_t getTxPower();
|
||||
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
||||
uint32_t getFrequency();
|
||||
void setFrequency(unsigned long frequency);
|
||||
void setSpreadingFactor(int sf);
|
||||
long getSignalBandwidth();
|
||||
void setSignalBandwidth(long sbw);
|
||||
void setCodingRate4(int denominator);
|
||||
void setPreambleLength(long length);
|
||||
void setSyncWord(int sw);
|
||||
uint8_t modemStatus();
|
||||
void enableCrc();
|
||||
void disableCrc();
|
||||
void enableTCXO();
|
||||
void disableTCXO();
|
||||
|
||||
void txAntEnable();
|
||||
void rxAntEnable();
|
||||
void loraMode();
|
||||
void waitOnBusy();
|
||||
void executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
||||
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
||||
void writeBuffer(const uint8_t* buffer, size_t size);
|
||||
void readBuffer(uint8_t* buffer, size_t size);
|
||||
void setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc);
|
||||
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr);
|
||||
|
||||
// deprecated
|
||||
void crc() { enableCrc(); }
|
||||
void noCrc() { disableCrc(); }
|
||||
|
||||
byte random();
|
||||
|
||||
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN, int busy = LORA_DEFAULT_BUSY_PIN, int rxen = LORA_DEFAULT_RXEN_PIN, int txen = LORA_DEFAULT_TXEN_PIN);
|
||||
void setSPIFrequency(uint32_t frequency);
|
||||
|
||||
void dumpRegisters(Stream& out);
|
||||
|
||||
private:
|
||||
void explicitHeaderMode();
|
||||
void implicitHeaderMode();
|
||||
|
||||
void handleDio0Rise();
|
||||
|
||||
uint8_t readRegister(uint16_t address);
|
||||
void writeRegister(uint16_t address, uint8_t value);
|
||||
uint8_t singleTransfer(uint8_t opcode, uint16_t address, uint8_t value);
|
||||
|
||||
static void onDio0Rise();
|
||||
|
||||
void handleLowDataRate();
|
||||
void optimizeModemSensitivity();
|
||||
|
||||
private:
|
||||
SPISettings _spiSettings;
|
||||
int _ss;
|
||||
int _reset;
|
||||
int _dio0;
|
||||
int _rxen;
|
||||
int _txen;
|
||||
int _busy;
|
||||
int _modem;
|
||||
unsigned long _frequency;
|
||||
int _txp;
|
||||
uint8_t _sf;
|
||||
uint8_t _bw;
|
||||
uint8_t _cr;
|
||||
int _packetIndex;
|
||||
uint32_t _preambleLength;
|
||||
int _implicitHeaderMode;
|
||||
int _payloadLength;
|
||||
int _crcMode;
|
||||
int _fifo_tx_addr_ptr;
|
||||
int _fifo_rx_addr_ptr;
|
||||
uint8_t _packet[256];
|
||||
bool _preinit_done;
|
||||
int _rxPacketLength;
|
||||
void (*_onReceive)(int);
|
||||
};
|
||||
|
||||
extern sx128x sx128x_modem;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user