Add multiple interface support
This commit is contained in:
		
							parent
							
								
									ebdec7f3e0
								
							
						
					
					
						commit
						3f8d012457
					
				
							
								
								
									
										494
									
								
								Boards.h
									
									
									
									
									
								
							
							
						
						
									
										494
									
								
								Boards.h
									
									
									
									
									
								
							| @ -13,17 +13,14 @@ | |||||||
| // You should have received a copy of the GNU General Public License
 | // You should have received a copy of the GNU General Public License
 | ||||||
| // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | ||||||
| 
 | 
 | ||||||
| #include "Modem.h" | #include "Interfaces.h" | ||||||
| 
 | 
 | ||||||
| #ifndef BOARDS_H | #ifndef BOARDS_H | ||||||
|   #define BOARDS_H |   #define BOARDS_H | ||||||
| 
 | 
 | ||||||
|   #define PLATFORM_AVR        0x90 |  | ||||||
|   #define PLATFORM_ESP32      0x80 |   #define PLATFORM_ESP32      0x80 | ||||||
|   #define PLATFORM_NRF52      0x70 |   #define PLATFORM_NRF52      0x70 | ||||||
| 
 | 
 | ||||||
|   #define MCU_1284P           0x91 |  | ||||||
|   #define MCU_2560            0x92 |  | ||||||
|   #define MCU_ESP32           0x81 |   #define MCU_ESP32           0x81 | ||||||
|   #define MCU_NRF52           0x71 |   #define MCU_NRF52           0x71 | ||||||
| 
 | 
 | ||||||
| @ -47,13 +44,7 @@ | |||||||
|   #define EINK_BW 0x02 |   #define EINK_BW 0x02 | ||||||
|   #define EINK_3C 0x03 |   #define EINK_3C 0x03 | ||||||
| 
 | 
 | ||||||
|   #if defined(__AVR_ATmega1284P__) |   #if defined(ESP32) | ||||||
|     #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 PLATFORM PLATFORM_ESP32 | ||||||
|     #define MCU_VARIANT MCU_ESP32 |     #define MCU_VARIANT MCU_ESP32 | ||||||
|   #elif defined(NRF52840_XXAA) |   #elif defined(NRF52840_XXAA) | ||||||
| @ -64,16 +55,6 @@ | |||||||
|       #error "The firmware cannot be compiled for the selected MCU variant" |       #error "The firmware cannot be compiled for the selected MCU variant" | ||||||
|   #endif |   #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_DISPLAY false | ||||||
|   #define HAS_BLUETOOTH false |   #define HAS_BLUETOOTH false | ||||||
|   #define HAS_BLE false |   #define HAS_BLE false | ||||||
| @ -90,37 +71,7 @@ | |||||||
|       #define HAS_TCXO true |       #define HAS_TCXO true | ||||||
|   #endif |   #endif | ||||||
| 
 | 
 | ||||||
|   #if MCU_VARIANT == MCU_1284P |   #if MCU_VARIANT == MCU_ESP32 | ||||||
|     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 |  | ||||||
| 
 | 
 | ||||||
|     // Board models for ESP32 based builds are
 |     // Board models for ESP32 based builds are
 | ||||||
|     // defined by the build target in the makefile.
 |     // defined by the build target in the makefile.
 | ||||||
| @ -143,11 +94,33 @@ | |||||||
|       #define HAS_BLUETOOTH true |       #define HAS_BLUETOOTH true | ||||||
|       #define HAS_CONSOLE true |       #define HAS_CONSOLE true | ||||||
|       #define HAS_EEPROM true |       #define HAS_EEPROM true | ||||||
|       const int pin_cs = 4; |       #define INTERFACE_COUNT 1 | ||||||
|       const int pin_reset = 36; |  | ||||||
|       const int pin_dio = 39; |  | ||||||
|       const int pin_led_rx = 14; |       const int pin_led_rx = 14; | ||||||
|       const int pin_led_tx = 32; |       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 |     #elif BOARD_MODEL == BOARD_TBEAM | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
| @ -161,32 +134,70 @@ | |||||||
|       #define I2C_SDA 21 |       #define I2C_SDA 21 | ||||||
|       #define I2C_SCL 22 |       #define I2C_SCL 22 | ||||||
|       #define PMU_IRQ 35 |       #define PMU_IRQ 35 | ||||||
|       const int pin_cs = 18; |  | ||||||
|       const int pin_reset = 23; |  | ||||||
|       const int pin_led_rx = 2; |       const int pin_led_rx = 2; | ||||||
|       const int pin_led_tx = 4; |       const int pin_led_tx = 4; | ||||||
| 
 | 
 | ||||||
|       #if MODEM == SX1262 |       #define INTERFACE_COUNT 1 | ||||||
|         #define HAS_TCXO true | 
 | ||||||
|         #define HAS_BUSY true |       const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; | ||||||
|         #define DIO2_AS_RF_SWITCH true |       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||||
|         const int pin_busy = 32; |                     // SX1262
 | ||||||
|         const int pin_dio = 33; |           { | ||||||
|         const int pin_tcxo_enable = -1; |               true, // DEFAULT_SPI
 | ||||||
|       #else |               true, // HAS_TCXO
 | ||||||
|         const int pin_dio = 26; |               true  // DIO2_AS_RF_SWITCH
 | ||||||
|       #endif |           },  | ||||||
|  |       }; | ||||||
|  |       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 |     #elif BOARD_MODEL == BOARD_HUZZAH32 | ||||||
|       #define HAS_BLUETOOTH true |       #define HAS_BLUETOOTH true | ||||||
|       #define HAS_CONSOLE true |       #define HAS_CONSOLE true | ||||||
|       #define HAS_EEPROM true |       #define HAS_EEPROM true | ||||||
|       const int pin_cs = 4; |  | ||||||
|       const int pin_reset = 36; |  | ||||||
|       const int pin_dio = 39; |  | ||||||
|       const int pin_led_rx = 14; |       const int pin_led_rx = 14; | ||||||
|       const int pin_led_tx = 32; |       const int pin_led_tx = 32; | ||||||
| 
 | 
 | ||||||
|  |       #define INTERFACE_COUNT 1 | ||||||
|  | 
 | ||||||
|  |       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 |     #elif BOARD_MODEL == BOARD_LORA32_V1_0 | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
|       #define DISPLAY OLED |       #define DISPLAY OLED | ||||||
| @ -205,6 +216,33 @@ | |||||||
|         const int pin_led_tx = 2; |         const int pin_led_tx = 2; | ||||||
|       #endif |       #endif | ||||||
| 
 | 
 | ||||||
|  |       #define INTERFACE_COUNT 1 | ||||||
|  | 
 | ||||||
|  |       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 |     #elif BOARD_MODEL == BOARD_LORA32_V2_0 | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
|       #define DISPLAY OLED |       #define DISPLAY OLED | ||||||
| @ -223,6 +261,33 @@ | |||||||
|         const int pin_led_tx = 22; |         const int pin_led_tx = 22; | ||||||
|       #endif |       #endif | ||||||
| 
 | 
 | ||||||
|  |       #define INTERFACE_COUNT 1 | ||||||
|  | 
 | ||||||
|  |       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 |     #elif BOARD_MODEL == BOARD_LORA32_V2_1 | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
|       #define DISPLAY OLED |       #define DISPLAY OLED | ||||||
| @ -231,11 +296,30 @@ | |||||||
|       #define HAS_PMU true |       #define HAS_PMU true | ||||||
|       #define HAS_CONSOLE true |       #define HAS_CONSOLE true | ||||||
|       #define HAS_EEPROM true |       #define HAS_EEPROM true | ||||||
|       const int pin_cs = 18; |  | ||||||
|       const int pin_reset = 23; |  | ||||||
|       const int pin_dio = 26; |  | ||||||
|       #if HAS_TCXO == true |       #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 |       #endif | ||||||
|       #if defined(EXTERNAL_LEDS) |       #if defined(EXTERNAL_LEDS) | ||||||
|         const int pin_led_rx = 15; |         const int pin_led_rx = 15; | ||||||
| @ -245,15 +329,43 @@ | |||||||
|         const int pin_led_tx = 25; |         const int pin_led_tx = 25; | ||||||
|       #endif |       #endif | ||||||
| 
 | 
 | ||||||
|  |       #define INTERFACE_COUNT 1 | ||||||
|  | 
 | ||||||
|  |       const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; | ||||||
|  | 
 | ||||||
|  |       #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 |     #elif BOARD_MODEL == BOARD_HELTEC32_V2 | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
|       #define DISPLAY OLED |       #define DISPLAY OLED | ||||||
|       #define HAS_BLUETOOTH true |       #define HAS_BLUETOOTH true | ||||||
|       #define HAS_CONSOLE true |       #define HAS_CONSOLE true | ||||||
|       #define HAS_EEPROM true |       #define HAS_EEPROM true | ||||||
|       const int pin_cs = 18; |  | ||||||
|       const int pin_reset = 14; |  | ||||||
|       const int pin_dio = 26; |  | ||||||
|       #if defined(EXTERNAL_LEDS) |       #if defined(EXTERNAL_LEDS) | ||||||
|         const int pin_led_rx = 36; |         const int pin_led_rx = 36; | ||||||
|         const int pin_led_tx = 37; |         const int pin_led_tx = 37; | ||||||
| @ -262,6 +374,33 @@ | |||||||
|         const int pin_led_tx = 25; |         const int pin_led_tx = 25; | ||||||
|       #endif |       #endif | ||||||
| 
 | 
 | ||||||
|  |       #define INTERFACE_COUNT 1 | ||||||
|  | 
 | ||||||
|  |       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 |     #elif BOARD_MODEL == BOARD_HELTEC32_V3 | ||||||
|       #define IS_ESP32S3 true |       #define IS_ESP32S3 true | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
| @ -273,6 +412,7 @@ | |||||||
|       #define HAS_SLEEP true |       #define HAS_SLEEP true | ||||||
|       #define PIN_WAKEUP GPIO_NUM_0 |       #define PIN_WAKEUP GPIO_NUM_0 | ||||||
|       #define WAKEUP_LEVEL 0 |       #define WAKEUP_LEVEL 0 | ||||||
|  |       #define INTERFACE_COUNT 1 | ||||||
| 
 | 
 | ||||||
|       const int pin_btn_usr1 = 0; |       const int pin_btn_usr1 = 0; | ||||||
| 
 | 
 | ||||||
| @ -284,20 +424,30 @@ | |||||||
|         const int pin_led_tx = 35; |         const int pin_led_tx = 35; | ||||||
|       #endif |       #endif | ||||||
| 
 | 
 | ||||||
|       #define MODEM SX1262 |       const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; | ||||||
|       #define HAS_TCXO true |       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||||
|       const int pin_tcxo_enable = -1; |                     // SX1262
 | ||||||
|       #define HAS_BUSY true |           { | ||||||
|       #define DIO2_AS_RF_SWITCH true |               false, // DEFAULT_SPI
 | ||||||
| 
 |               true, // HAS_TCXO
 | ||||||
|       // Following pins are for the SX1262
 |               true  // DIO2_AS_RF_SWITCH
 | ||||||
|       const int pin_cs = 8; |           },  | ||||||
|       const int pin_busy = 13; |       }; | ||||||
|       const int pin_dio = 14; |       const uint8_t interface_pins[INTERFACE_COUNT][10] = {  | ||||||
|       const int pin_reset = 12; |                   // SX1262
 | ||||||
|       const int pin_mosi = 10; |           { | ||||||
|       const int pin_miso = 11; |               8, // pin_ss
 | ||||||
|       const int pin_sclk = 9; |               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 |     #elif BOARD_MODEL == BOARD_RNODE_NG_20 | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
| @ -320,6 +470,31 @@ | |||||||
|         #endif |         #endif | ||||||
|       #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 |     #elif BOARD_MODEL == BOARD_RNODE_NG_21 | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
|       #define DISPLAY OLED |       #define DISPLAY OLED | ||||||
| @ -329,9 +504,6 @@ | |||||||
|       #define HAS_NP true |       #define HAS_NP true | ||||||
|       #define HAS_SD false |       #define HAS_SD false | ||||||
|       #define HAS_EEPROM true |       #define HAS_EEPROM true | ||||||
|       const int pin_cs = 18; |  | ||||||
|       const int pin_reset = 23; |  | ||||||
|       const int pin_dio = 26; |  | ||||||
|       const int pin_np = 12; |       const int pin_np = 12; | ||||||
|       const int pin_dac = 25; |       const int pin_dac = 25; | ||||||
|       const int pin_adc = 34; |       const int pin_adc = 34; | ||||||
| @ -349,12 +521,34 @@ | |||||||
|         #endif |         #endif | ||||||
|       #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 |     #elif BOARD_MODEL == BOARD_RNODE_NG_22 | ||||||
|       #define IS_ESP32S3 true |       #define IS_ESP32S3 true | ||||||
|       #define MODEM SX1262 |       #define MODEM SX1262 | ||||||
|       #define DIO2_AS_RF_SWITCH true |  | ||||||
|       #define HAS_BUSY true |  | ||||||
|       #define HAS_TCXO true |  | ||||||
| 
 | 
 | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
|       #define DISPLAY OLED |       #define DISPLAY OLED | ||||||
| @ -373,16 +567,6 @@ | |||||||
|       // #define PIN_DISP_SLEEP 21
 |       // #define PIN_DISP_SLEEP 21
 | ||||||
|       // #define DISP_SLEEP_LEVEL HIGH
 |       // #define DISP_SLEEP_LEVEL HIGH
 | ||||||
|       const int pin_btn_usr1 = 0; |       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_np = 38; | ||||||
|       const int pin_dac = 25; |       const int pin_dac = 25; | ||||||
| @ -402,6 +586,31 @@ | |||||||
|         #endif |         #endif | ||||||
|       #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 |     #else | ||||||
|       #error An unsupported ESP32 board was selected. Cannot compile RNode firmware. |       #error An unsupported ESP32 board was selected. Cannot compile RNode firmware. | ||||||
|     #endif |     #endif | ||||||
| @ -410,17 +619,14 @@ | |||||||
|     #if BOARD_MODEL == BOARD_RAK4631 |     #if BOARD_MODEL == BOARD_RAK4631 | ||||||
|       #define HAS_EEPROM false |       #define HAS_EEPROM false | ||||||
|       #define HAS_DISPLAY true |       #define HAS_DISPLAY true | ||||||
|       #define DISPLAY EINK_3C |       #define DISPLAY EINK_BW | ||||||
|       #define HAS_BLUETOOTH false |       #define HAS_BLUETOOTH false | ||||||
|       #define HAS_BLE true |       #define HAS_BLE true | ||||||
|       #define HAS_CONSOLE false |       #define HAS_CONSOLE false | ||||||
|       #define HAS_PMU true |       #define HAS_PMU true | ||||||
|       #define HAS_NP false |       #define HAS_NP false | ||||||
|       #define HAS_SD false |       #define HAS_SD false | ||||||
|       #define HAS_TCXO true |  | ||||||
|       #define HAS_RF_SWITCH_RX_TX 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_UART_BUFFER_SIZE 6144 | ||||||
|       #define CONFIG_QUEUE_SIZE 6144 |       #define CONFIG_QUEUE_SIZE 6144 | ||||||
|       #define CONFIG_QUEUE_MAX_LENGTH 200 |       #define CONFIG_QUEUE_MAX_LENGTH 200 | ||||||
| @ -429,15 +635,45 @@ | |||||||
|       #define BLE_MANUFACTURER "RAK Wireless" |       #define BLE_MANUFACTURER "RAK Wireless" | ||||||
|       #define BLE_MODEL "RAK4640" |       #define BLE_MODEL "RAK4640" | ||||||
| 
 | 
 | ||||||
|       // Following pins are for the sx1262
 |       #define INTERFACE_COUNT 1 | ||||||
|       const int pin_rxen = 37; | 
 | ||||||
|       const int pin_reset = 38; |       // first interface in list is the primary
 | ||||||
|       const int pin_cs = 42; |       const uint8_t interfaces[INTERFACE_COUNT] = {SX126X}; | ||||||
|       const int pin_sclk = 43; |       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||||
|       const int pin_mosi = 44; |                     // SX1262
 | ||||||
|       const int pin_miso = 45; |           { | ||||||
|       const int pin_busy = 46; |               false, // DEFAULT_SPI
 | ||||||
|       const int pin_dio = 47; |               true, // HAS_TCXO
 | ||||||
|  |               true  // DIO2_AS_RF_SWITCH
 | ||||||
|  |           } | ||||||
|  |       }; | ||||||
|  |       const uint8_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_cs = SS; | ||||||
|       const int pin_disp_dc = WB_IO1; |       const int pin_disp_dc = WB_IO1; | ||||||
| @ -447,25 +683,15 @@ | |||||||
| 
 | 
 | ||||||
|       const int pin_led_rx = LED_BLUE; |       const int pin_led_rx = LED_BLUE; | ||||||
|       const int pin_led_tx = LED_GREEN; |       const int pin_led_tx = LED_GREEN; | ||||||
|       const int pin_tcxo_enable = -1; |  | ||||||
| 
 | 
 | ||||||
|     #else |     #else | ||||||
|       #error An unsupported nRF board was selected. Cannot compile RNode firmware. |       #error An unsupported nRF board was selected. Cannot compile RNode firmware. | ||||||
|     #endif |     #endif | ||||||
| 
 | 
 | ||||||
|   #endif |   #endif | ||||||
| 
 |   #ifndef INTERFACE_SPI | ||||||
|   #ifndef HAS_RF_SWITCH_RX_TX |     // Even if custom SPI interfaces are not needed, the array must exist to prevent compilation errors.
 | ||||||
|     const int pin_rxen = -1; |     #define INTERFACE_SPI | ||||||
|     const int pin_txen = -1; |     const SPIClass interface_spi[1]; | ||||||
|   #endif |   #endif | ||||||
| 
 |  | ||||||
|   #ifndef HAS_BUSY |  | ||||||
|     const int pin_busy = -1; |  | ||||||
|   #endif |  | ||||||
| 
 |  | ||||||
|   #ifndef DIO2_AS_RF_SWITCH |  | ||||||
|     #define DIO2_AS_RF_SWITCH false |  | ||||||
|   #endif |  | ||||||
| 
 |  | ||||||
| #endif | #endif | ||||||
|  | |||||||
							
								
								
									
										88
									
								
								Config.h
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								Config.h
									
									
									
									
									
								
							| @ -43,7 +43,7 @@ | |||||||
| 	#define M_FRQ_S 27388122 | 	#define M_FRQ_S 27388122 | ||||||
| 	#define M_FRQ_R 27388061 | 	#define M_FRQ_R 27388061 | ||||||
| 	bool console_active = false; | 	bool console_active = false; | ||||||
| 	bool modem_installed = false; | 	bool modems_installed = false; | ||||||
| 
 | 
 | ||||||
| 	#define MTU   	   508 | 	#define MTU   	   508 | ||||||
| 	#define SINGLE_MTU 255 | 	#define SINGLE_MTU 255 | ||||||
| @ -51,13 +51,10 @@ | |||||||
| 	#define MIN_L	   1 | 	#define MIN_L	   1 | ||||||
| 	#define CMD_L      64 | 	#define CMD_L      64 | ||||||
| 
 | 
 | ||||||
|     bool mw_radio_online = false; |  | ||||||
| 
 |  | ||||||
| 	#define eeprom_addr(a) (a+EEPROM_OFFSET) | 	#define eeprom_addr(a) (a+EEPROM_OFFSET) | ||||||
| 
 | 
 | ||||||
|     #if (MODEM == SX1262 || MODEM == SX1280) && defined(NRF52840_XXAA) |     #define PA_OUTPUT_RFO_PIN      0 | ||||||
|         SPIClass spiModem(NRF_SPIM2, pin_miso, pin_sclk, pin_mosi); |     #define PA_OUTPUT_PA_BOOST_PIN 1 | ||||||
|     #endif |  | ||||||
| 
 | 
 | ||||||
| 	// MCU independent configuration parameters
 | 	// MCU independent configuration parameters
 | ||||||
| 	const long serial_baudrate  = 115200; | 	const long serial_baudrate  = 115200; | ||||||
| @ -66,36 +63,15 @@ | |||||||
| 	// packet RSSI register
 | 	// packet RSSI register
 | ||||||
| 	const int  rssi_offset = 157; | 	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; |     // Default LoRa settings
 | ||||||
| 	int  lora_cr               = 5; |     const int lora_rx_turnaround_ms = 66; | ||||||
| 	int  lora_txp              = 0xFF; |     const int lora_post_tx_yield_slots = 6; | ||||||
| 	uint32_t lora_bw           = 0; |     #define LORA_CAD_SYMBOLS 3 | ||||||
| 	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; |  | ||||||
| 
 | 
 | ||||||
| 	// Operational variables
 | 	// Operational variables
 | ||||||
| 	bool radio_locked  = true; |  | ||||||
| 	bool radio_online  = false; |  | ||||||
| 	bool community_fw  = true; | 	bool community_fw  = true; | ||||||
| 	bool hw_ready      = false; | 	bool hw_ready      = false; | ||||||
| 	bool radio_error   = false; |  | ||||||
| 	bool disp_ready    = false; | 	bool disp_ready    = false; | ||||||
| 	bool pmu_ready     = false; | 	bool pmu_ready     = false; | ||||||
| 	bool promisc       = false; | 	bool promisc       = false; | ||||||
| @ -106,7 +82,6 @@ | |||||||
| 	uint8_t model     = 0x00; | 	uint8_t model     = 0x00; | ||||||
| 	uint8_t hwrev     = 0x00; | 	uint8_t hwrev     = 0x00; | ||||||
| 
 | 
 | ||||||
|     int     current_rssi    = -292; |  | ||||||
| 	int		last_rssi		= -292; | 	int		last_rssi		= -292; | ||||||
| 	uint8_t last_rssi_raw   = 0x00; | 	uint8_t last_rssi_raw   = 0x00; | ||||||
| 	uint8_t last_snr_raw	= 0x80; | 	uint8_t last_snr_raw	= 0x80; | ||||||
| @ -125,49 +100,6 @@ | |||||||
| 	uint32_t stat_rx		= 0; | 	uint32_t stat_rx		= 0; | ||||||
| 	uint32_t stat_tx		= 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; |  | ||||||
| 
 |  | ||||||
|     // Power management
 |     // Power management
 | ||||||
|     #define BATTERY_STATE_DISCHARGING 0x01 |     #define BATTERY_STATE_DISCHARGING 0x01 | ||||||
|     #define BATTERY_STATE_CHARGING 0x02 |     #define BATTERY_STATE_CHARGING 0x02 | ||||||
| @ -192,4 +124,10 @@ | |||||||
| 	#define START_FROM_BROWNOUT 0x03 | 	#define START_FROM_BROWNOUT 0x03 | ||||||
| 	#define START_FROM_JTAG 0x04 | 	#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 | #endif | ||||||
|  | |||||||
							
								
								
									
										201
									
								
								Display.h
									
									
									
									
									
								
							
							
						
						
									
										201
									
								
								Display.h
									
									
									
									
									
								
							| @ -130,10 +130,19 @@ unsigned char fb[512]; | |||||||
| uint32_t last_disp_update = 0; | uint32_t last_disp_update = 0; | ||||||
| int disp_update_interval = 1000/disp_target_fps; | int disp_update_interval = 1000/disp_target_fps; | ||||||
| uint32_t last_page_flip = 0; | uint32_t last_page_flip = 0; | ||||||
|  | uint32_t last_interface_page_flip = 0; | ||||||
| int page_interval = 4000; | int page_interval = 4000; | ||||||
| bool device_signatures_ok(); | bool device_signatures_ok(); | ||||||
| bool device_firmware_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; | ||||||
|  | 
 | ||||||
| #if DISPLAY == OLED | #if DISPLAY == OLED | ||||||
| #define WATERFALL_SIZE 46 | #define WATERFALL_SIZE 46 | ||||||
| #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||||
| @ -142,8 +151,8 @@ bool device_firmware_ok(); | |||||||
| // add more eink compatible boards here
 | // add more eink compatible boards here
 | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| int waterfall[WATERFALL_SIZE]; | int waterfall[INTERFACE_COUNT][WATERFALL_SIZE] = {0}; | ||||||
| int waterfall_head = 0; | int waterfall_head[INTERFACE_COUNT] = {0}; | ||||||
| 
 | 
 | ||||||
| int p_ad_x = 0; | int p_ad_x = 0; | ||||||
| int p_ad_y = 0; | int p_ad_y = 0; | ||||||
| @ -286,9 +295,6 @@ bool display_init() { | |||||||
|       #endif |       #endif | ||||||
| 
 | 
 | ||||||
|       update_area_positions(); |       update_area_positions(); | ||||||
|       for (int i = 0; i < WATERFALL_SIZE; i++) { |  | ||||||
|         waterfall[i] = 0; |  | ||||||
|       } |  | ||||||
| 
 | 
 | ||||||
|       last_page_flip = millis(); |       last_page_flip = millis(); | ||||||
| 
 | 
 | ||||||
| @ -359,34 +365,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 (radio_online) { | ||||||
|     #if DISPLAY == OLED |         #if DISPLAY == OLED | ||||||
|         stat_area.drawBitmap(px, py, bm_rf+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); |                 if (interface_page == radio->getIndex()) { | ||||||
|     #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) |                     stat_area.drawBitmap(px - 2, py - 2, bm_dot_sqr, 18, 18, GxEPD_WHITE, GxEPD_BLACK); | ||||||
|         stat_area.drawBitmap(px, py, bm_rf+1*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); | 
 | ||||||
|     #endif |                     // redraw stat area on next refresh
 | ||||||
|   } else { |                     stat_area_initialised = false; | ||||||
|     #if DISPLAY == OLED |                 } | ||||||
|         stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); |                   if (radio->getRadioOnline()) { | ||||||
|     #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) |                 stat_area.drawBitmap(px, py, bm_rf+1*32, 16, 16, GxEPD_WHITE, GxEPD_BLACK); | ||||||
|         stat_area.drawBitmap(px, py, bm_rf+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); |                   } else { | ||||||
|     #endif |                 stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, GxEPD_WHITE, GxEPD_BLACK); | ||||||
|   } |                   } | ||||||
|  |         #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||||
|  |                 if (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) { | void draw_mw_icon(int px, int py) { | ||||||
|   if (mw_radio_online) { |   if (INTERFACE_COUNT >= 2) { | ||||||
|     #if DISPLAY == OLED |       if (interface_obj[1]->getRadioOnline()) { | ||||||
|         stat_area.drawBitmap(px, py, bm_rf+3*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); |         #if DISPLAY == OLED | ||||||
|     #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) |             stat_area.drawBitmap(px, py, bm_rf+3*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); | ||||||
|         stat_area.drawBitmap(px, py, bm_rf+3*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); |         #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||||
|     #endif |             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 { |   } else { | ||||||
|     #if DISPLAY == OLED |     #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) |     #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 |     #endif | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -479,7 +514,7 @@ void draw_battery_bars(int px, int py) { | |||||||
| void draw_quality_bars(int px, int py) { | void draw_quality_bars(int px, int py) { | ||||||
|   signed char t_snr = (signed int)last_snr_raw; |   signed char t_snr = (signed int)last_snr_raw; | ||||||
|   int snr_int = (int)t_snr; |   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_span = (Q_SNR_MAX-snr_min); | ||||||
|   float snr = ((int)snr_int) * 0.25; |   float snr = ((int)snr_int) * 0.25; | ||||||
|   float quality = ((snr-snr_min)/(snr_span))*100; |   float quality = ((snr-snr_min)/(snr_span))*100; | ||||||
| @ -593,13 +628,13 @@ void draw_signal_bars(int px, int py) { | |||||||
| #define WF_PIXEL_WIDTH 22 | #define WF_PIXEL_WIDTH 22 | ||||||
| #endif | #endif | ||||||
| void draw_waterfall(int px, int py) { | 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_MIN) rssi_val = WF_RSSI_MIN; | ||||||
|   if (rssi_val > WF_RSSI_MAX) rssi_val = WF_RSSI_MAX; |   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; |   int rssi_normalised = ((rssi_val - WF_RSSI_MIN)*(1.0/WF_RSSI_SPAN))*WF_PIXEL_WIDTH; | ||||||
| 
 | 
 | ||||||
|   waterfall[waterfall_head++] = rssi_normalised; |   waterfall[interface_page][waterfall_head[interface_page]++] = rssi_normalised; | ||||||
|   if (waterfall_head >= WATERFALL_SIZE) waterfall_head = 0; |   if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0; | ||||||
| 
 | 
 | ||||||
|   #if DISPLAY == OLED |   #if DISPLAY == OLED | ||||||
|   stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, SSD1306_BLACK); |   stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, SSD1306_BLACK); | ||||||
| @ -607,8 +642,8 @@ void draw_waterfall(int px, int py) { | |||||||
|   stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, GxEPD_BLACK); |   stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, GxEPD_BLACK); | ||||||
|   #endif |   #endif | ||||||
|   for (int i = 0; i < WATERFALL_SIZE; i++){ |   for (int i = 0; i < WATERFALL_SIZE; i++){ | ||||||
|     int wi = (waterfall_head+i)%WATERFALL_SIZE; |     int wi = (waterfall_head[interface_page]+i)%WATERFALL_SIZE; | ||||||
|     int ws = waterfall[wi]; |     int ws = waterfall[interface_page][wi]; | ||||||
|     if (ws > 0) { |     if (ws > 0) { | ||||||
|       #if DISPLAY == OLED |       #if DISPLAY == OLED | ||||||
|         stat_area.drawLine(px, py+i, px+ws-1, py+i, SSD1306_WHITE); |         stat_area.drawLine(px, py+i, px+ws-1, py+i, SSD1306_WHITE); | ||||||
| @ -619,7 +654,6 @@ void draw_waterfall(int px, int py) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool stat_area_initialised = false; |  | ||||||
| void draw_stat_area() { | void draw_stat_area() { | ||||||
|   if (device_init_done) { |   if (device_init_done) { | ||||||
|     if (!stat_area_initialised) { |     if (!stat_area_initialised) { | ||||||
| @ -631,19 +665,51 @@ void draw_stat_area() { | |||||||
|       stat_area_initialised = true; |       stat_area_initialised = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (millis()-last_interface_page_flip >= page_interval) { | ||||||
|  |       int online_interfaces = 0; | ||||||
|  |       for (int i = 0; i < INTERFACE_COUNT; i++) { | ||||||
|  |           if (interface_obj[i]->getRadioOnline()) { | ||||||
|  |               online_interfaces++; | ||||||
|  |           } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // cap at two for now, as only two boxes to symbolise interfaces
 | ||||||
|  |       // available on display
 | ||||||
|  |       if (online_interfaces > 2) { | ||||||
|  |           online_interfaces = 2; | ||||||
|  |       } | ||||||
|  |       interface_page = (++interface_page%online_interfaces); | ||||||
|  |       last_interface_page_flip = millis(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     #if DISPLAY == OLED |     #if DISPLAY == OLED | ||||||
|     draw_cable_icon(3, 8); |     draw_cable_icon(3, 8); | ||||||
|     draw_bt_icon(3, 30); |     draw_bt_icon(3, 30); | ||||||
|     draw_lora_icon(45, 8); |     draw_lora_icon(interface_obj[0], 45, 8); | ||||||
|     draw_mw_icon(45, 30); | 
 | ||||||
|  |     // 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); |     draw_battery_bars(4, 58); | ||||||
|     #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) |     #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||||
|     draw_cable_icon(6, 18); |     draw_cable_icon(6, 18); | ||||||
|     draw_bt_icon(6, 60); |     draw_bt_icon(6, 60); | ||||||
|     draw_lora_icon(86, 18); |     draw_lora_icon(interface_obj[0], 86, 18); | ||||||
|     draw_mw_icon(86, 60); | 
 | ||||||
|  |     // 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); |     draw_battery_bars(8, 113); | ||||||
|     #endif |     #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 (radio_online) { | ||||||
|       #if DISPLAY == OLED |       #if DISPLAY == OLED | ||||||
|       draw_quality_bars(28, 56); |       draw_quality_bars(28, 56); | ||||||
| @ -701,9 +767,6 @@ void update_stat_area() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define START_PAGE 0 |  | ||||||
| const uint8_t pages = 3; |  | ||||||
| uint8_t disp_page = START_PAGE; |  | ||||||
| void draw_disp_area() { | void draw_disp_area() { | ||||||
|   if (!device_init_done || firmware_update_mode) { |   if (!device_init_done || firmware_update_mode) { | ||||||
|     uint8_t p_by = 37; |     uint8_t p_by = 37; | ||||||
| @ -726,6 +789,7 @@ void draw_disp_area() { | |||||||
|     if (!disp_ext_fb or bt_ssp_pin != 0) { |     if (!disp_ext_fb or bt_ssp_pin != 0) { | ||||||
|       if (radio_online && display_diagnostics) { |       if (radio_online && display_diagnostics) { | ||||||
|         #if DISPLAY == OLED |         #if DISPLAY == OLED | ||||||
|  |           selected_radio = interface_obj[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.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); |           disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(SSD1306_WHITE); | ||||||
| 
 | 
 | ||||||
| @ -734,26 +798,26 @@ void draw_disp_area() { | |||||||
|           disp_area.setCursor(14, 13); |           disp_area.setCursor(14, 13); | ||||||
|           disp_area.print("@"); |           disp_area.print("@"); | ||||||
|           disp_area.setCursor(21, 13); |           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.setCursor(2, 23-1); | ||||||
|           disp_area.print("Airtime:"); |           disp_area.print("Airtime:"); | ||||||
| 
 | 
 | ||||||
|           disp_area.setCursor(11, 33-1); |           disp_area.setCursor(11, 33-1); | ||||||
|           if (total_channel_util < 0.099) { |           if (selected_radio->getTotalChannelUtil() < 0.099) { | ||||||
|             disp_area.printf("%.1f%%", airtime*100.0); |             disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0); | ||||||
|           } else { |           } 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.drawBitmap(2, 26-1, bm_hg_low, 5, 9, SSD1306_WHITE, SSD1306_BLACK); | ||||||
| 
 | 
 | ||||||
|           disp_area.setCursor(32+11, 33-1); |           disp_area.setCursor(32+11, 33-1); | ||||||
| 
 | 
 | ||||||
|           if (longterm_channel_util < 0.099) { |           if (selected_radio->getLongtermChannelUtil() < 0.099) { | ||||||
|             disp_area.printf("%.1f%%", longterm_airtime*100.0); |             disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0); | ||||||
|           } else { |           } 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); |           disp_area.drawBitmap(32+2, 26-1, bm_hg_high, 5, 9, SSD1306_WHITE, SSD1306_BLACK); | ||||||
| 
 | 
 | ||||||
| @ -765,22 +829,23 @@ void draw_disp_area() { | |||||||
|           disp_area.print("Load:"); |           disp_area.print("Load:"); | ||||||
| 
 | 
 | ||||||
|           disp_area.setCursor(11, 57); |           disp_area.setCursor(11, 57); | ||||||
|           if (total_channel_util < 0.099) { |           if (selected_radio->getTotalChannelUtil() < 0.099) { | ||||||
|             disp_area.printf("%.1f%%", total_channel_util*100.0); |             disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0); | ||||||
|           } else { |           } 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.drawBitmap(2, 50, bm_hg_low, 5, 9, SSD1306_BLACK, SSD1306_WHITE); | ||||||
|          |          | ||||||
|           disp_area.setCursor(32+11, 57); |           disp_area.setCursor(32+11, 57); | ||||||
|           if (longterm_channel_util < 0.099) { |           if (selected_radio->getLongtermChannelUtil() < 0.099) { | ||||||
|             disp_area.printf("%.1f%%", longterm_channel_util*100.0); |             disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0); | ||||||
|           } else { |           } 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); |           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) |         #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||||
|  |           selected_radio = interface_obj[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.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.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(GxEPD_WHITE); | ||||||
|           disp_area.setTextSize(2); // scale text 2x
 |           disp_area.setTextSize(2); // scale text 2x
 | ||||||
| @ -790,25 +855,25 @@ void draw_disp_area() { | |||||||
|           disp_area.setCursor(14*2, 22); |           disp_area.setCursor(14*2, 22); | ||||||
|           disp_area.print("@"); |           disp_area.print("@"); | ||||||
|           disp_area.setCursor(21*2, 22); |           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.setCursor(2, 36); | ||||||
|           disp_area.print("Airtime:"); |           disp_area.print("Airtime:"); | ||||||
| 
 | 
 | ||||||
|           disp_area.setCursor(7+12, 53); |           disp_area.setCursor(7+12, 53); | ||||||
|           if (total_channel_util < 0.099) { |           if (selected_radio->getTotalChannelUtil() < 0.099) { | ||||||
|             disp_area.printf("%.1f%%", airtime*100.0); |             disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0); | ||||||
|           } else { |           } 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.drawBitmap(2, 41, bm_hg_low, 10, 18, GxEPD_WHITE, GxEPD_BLACK); | ||||||
| 
 | 
 | ||||||
|           disp_area.setCursor(64+17, 53); |           disp_area.setCursor(64+17, 53); | ||||||
|           if (longterm_channel_util < 0.099) { |           if (selected_radio->getLongtermChannelUtil() < 0.099) { | ||||||
|             disp_area.printf("%.1f%%", longterm_airtime*100.0); |             disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0); | ||||||
|           } else { |           } 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); |           disp_area.drawBitmap(64, 41, bm_hg_high, 10, 18, GxEPD_WHITE, GxEPD_BLACK); | ||||||
| 
 | 
 | ||||||
| @ -820,18 +885,18 @@ void draw_disp_area() { | |||||||
|           disp_area.print("Load:"); |           disp_area.print("Load:"); | ||||||
|          |          | ||||||
|           disp_area.setCursor(7+12, 110); |           disp_area.setCursor(7+12, 110); | ||||||
|           if (total_channel_util < 0.099) { |           if (selected_radio->getTotalChannelUtil() < 0.099) { | ||||||
|             disp_area.printf("%.1f%%", total_channel_util*100.0); |             disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0); | ||||||
|           } else { |           } 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.drawBitmap(2, 98, bm_hg_low, 10, 18, GxEPD_BLACK, GxEPD_WHITE); | ||||||
| 
 | 
 | ||||||
|           disp_area.setCursor(64+17, 110); |           disp_area.setCursor(64+17, 110); | ||||||
|           if (longterm_channel_util < 0.099) { |           if (selected_radio->getLongtermChannelUtil() < 0.099) { | ||||||
|             disp_area.printf("%.1f%%", longterm_channel_util*100.0); |             disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0); | ||||||
|           } else { |           } 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); |           disp_area.drawBitmap(64, 98, bm_hg_high, 10, 18, GxEPD_BLACK, GxEPD_WHITE); | ||||||
|         #endif |         #endif | ||||||
| @ -852,7 +917,7 @@ void draw_disp_area() { | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       if (!hw_ready || radio_error || !device_firmware_ok()) { |       if (!hw_ready || !device_firmware_ok()) { | ||||||
|         if (!device_firmware_ok()) { |         if (!device_firmware_ok()) { | ||||||
|           #if DISPLAY == OLED |           #if DISPLAY == OLED | ||||||
|             disp_area.drawBitmap(0, 37, bm_fw_corrupt, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); |             disp_area.drawBitmap(0, 37, bm_fw_corrupt, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); | ||||||
| @ -860,7 +925,7 @@ void draw_disp_area() { | |||||||
|             disp_area.drawBitmap(0, 71, bm_fw_corrupt, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); |             disp_area.drawBitmap(0, 71, bm_fw_corrupt, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); | ||||||
|           #endif |           #endif | ||||||
|         } else { |         } else { | ||||||
|           if (!modem_installed) { |           if (!modems_installed) { | ||||||
|             #if DISPLAY == OLED |             #if DISPLAY == OLED | ||||||
|               disp_area.drawBitmap(0, 37, bm_no_radio, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); |               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) |             #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 | * whether the modem has a busy pin | ||||||
| * RX and TX leds (preferably LEDs of different colours) | * 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: | An example of a minimal entry can be seen below: | ||||||
| ``` | ``` | ||||||
| #elif BOARD_MODEL == BOARD_MY_WICKED_BOARD | #elif BOARD_MODEL == BOARD_MY_WICKED_BOARD | ||||||
|  | |||||||
							
								
								
									
										31
									
								
								Framing.h
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								Framing.h
									
									
									
									
									
								
							| @ -22,7 +22,6 @@ | |||||||
|   #define TFESC           0xDD |   #define TFESC           0xDD | ||||||
| 
 | 
 | ||||||
|   #define CMD_UNKNOWN     0xFE |   #define CMD_UNKNOWN     0xFE | ||||||
|   #define CMD_DATA        0x00 |  | ||||||
|   #define CMD_FREQUENCY   0x01 |   #define CMD_FREQUENCY   0x01 | ||||||
|   #define CMD_BANDWIDTH   0x02 |   #define CMD_BANDWIDTH   0x02 | ||||||
|   #define CMD_TXPOWER     0x03 |   #define CMD_TXPOWER     0x03 | ||||||
| @ -75,6 +74,34 @@ | |||||||
|   #define CMD_RESET       0x55 |   #define CMD_RESET       0x55 | ||||||
|   #define CMD_RESET_BYTE  0xF8 |   #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_REQ      0x73 | ||||||
|   #define DETECT_RESP     0x46 |   #define DETECT_RESP     0x46 | ||||||
| 
 | 
 | ||||||
| @ -98,4 +125,4 @@ | |||||||
|   bool ESCAPE = false; |   bool ESCAPE = false; | ||||||
|   uint8_t command = CMD_UNKNOWN; |   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 |    0xe7, 0xe7 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | const unsigned char bm_dot_sqr [] PROGMEM = { | ||||||
|  | 	0xdb, 0x36, 0xc0, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x80, 0x00, 0x40, 0x00,  | ||||||
|  | 	0x00, 0x00, 0x80, 0x00, 0x40, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,  | ||||||
|  | 	0x40, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00,  | ||||||
|  | 	0x80, 0x00, 0x40, 0xdb, 0x36, 0xc0 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| #elif DISP_H == 122 | #elif DISP_H == 122 | ||||||
| // use 122px wide graphics
 | // use 122px wide graphics
 | ||||||
| 
 | 
 | ||||||
| @ -1688,6 +1695,21 @@ const unsigned char bm_n_uh [] PROGMEM = { | |||||||
| 	0xfc, 0x00, 0xfc, 0x00 // 9
 | 	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 | #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 | ||||||
							
								
								
									
										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
											
										
									
								
							
							
								
								
									
										656
									
								
								Radio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										656
									
								
								Radio.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,656 @@ | |||||||
|  | // 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" | ||||||
|  | 
 | ||||||
|  | // 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 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), _last_dcd(0), | ||||||
|  |     _stat_rx_ongoing(false), _stat_signal_detected(false), | ||||||
|  |     _stat_signal_synced(false), _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), | ||||||
|  |     _onReceive(NULL) {}; | ||||||
|  |     virtual int begin(); | ||||||
|  |     virtual void end(); | ||||||
|  | 
 | ||||||
|  |     virtual int beginPacket(int implicitHeader = false); | ||||||
|  |     virtual int endPacket(); | ||||||
|  | 
 | ||||||
|  |     virtual int packetRssi(); | ||||||
|  |     virtual int currentRssi(); | ||||||
|  |     virtual uint8_t packetRssiRaw(); | ||||||
|  |     virtual uint8_t currentRssiRaw(); | ||||||
|  |     virtual uint8_t packetSnrRaw(); | ||||||
|  |     virtual float packetSnr(); | ||||||
|  |     virtual 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(); | ||||||
|  | 
 | ||||||
|  |     virtual void onReceive(void(*callback)(uint8_t, int)); | ||||||
|  | 
 | ||||||
|  |     virtual void receive(int size = 0); | ||||||
|  |     virtual void standby(); | ||||||
|  |     virtual void sleep(); | ||||||
|  | 
 | ||||||
|  |     virtual bool preInit(); | ||||||
|  |     virtual uint8_t getTxPower(); | ||||||
|  |     virtual void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); | ||||||
|  |     virtual uint32_t getFrequency(); | ||||||
|  |     virtual void setFrequency(uint32_t frequency); | ||||||
|  |     virtual void setSpreadingFactor(int sf); | ||||||
|  |     virtual uint8_t getSpreadingFactor(); | ||||||
|  |     virtual uint32_t getSignalBandwidth(); | ||||||
|  |     virtual void setSignalBandwidth(uint32_t sbw); | ||||||
|  |     virtual void setCodingRate4(int denominator); | ||||||
|  |     virtual uint8_t getCodingRate4(); | ||||||
|  |     virtual void setPreambleLength(long length); | ||||||
|  |     virtual uint8_t modemStatus(); | ||||||
|  |     virtual void enableCrc(); | ||||||
|  |     virtual void disableCrc(); | ||||||
|  |     virtual void enableTCXO(); | ||||||
|  |     virtual void disableTCXO(); | ||||||
|  | 
 | ||||||
|  |     virtual byte random(); | ||||||
|  | 
 | ||||||
|  |     virtual void setSPIFrequency(uint32_t frequency); | ||||||
|  | 
 | ||||||
|  |     virtual void updateBitrate(); | ||||||
|  |     virtual void handleDio0Rise(); | ||||||
|  |     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(); | ||||||
|  |     virtual void implicitHeaderMode(); | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     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); | ||||||
|  | 
 | ||||||
|  | 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; | ||||||
|  |   uint8_t _packet[255]; | ||||||
|  |   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(); | ||||||
|  | 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(); | ||||||
|  | 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; | ||||||
|  |   uint8_t _packet[255]; | ||||||
|  |   bool _preinit_done; | ||||||
|  |   int _rxPacketLength; | ||||||
|  |   uint8_t _index; | ||||||
|  |   bool _tcxo; | ||||||
|  | }; | ||||||
|  | #endif | ||||||
							
								
								
									
										561
									
								
								Utilities.h
									
									
									
									
									
								
							
							
						
						
									
										561
									
								
								Utilities.h
									
									
									
									
									
								
							| @ -13,8 +13,13 @@ | |||||||
| // You should have received a copy of the GNU General Public License
 | // You should have received a copy of the GNU General Public License
 | ||||||
| // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | ||||||
| 
 | 
 | ||||||
|  | #include "Radio.h" | ||||||
| #include "Config.h" | #include "Config.h" | ||||||
| 
 | 
 | ||||||
|  | // Included for sorting
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <iterator> | ||||||
|  | 
 | ||||||
| #if HAS_EEPROM  | #if HAS_EEPROM  | ||||||
|     #include <EEPROM.h> |     #include <EEPROM.h> | ||||||
| #elif PLATFORM == PLATFORM_NRF52 | #elif PLATFORM == PLATFORM_NRF52 | ||||||
| @ -28,17 +33,6 @@ | |||||||
| #endif | #endif | ||||||
| #include <stddef.h> | #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 "ROM.h" | ||||||
| #include "Framing.h" | #include "Framing.h" | ||||||
| #include "MD5.h" | #include "MD5.h" | ||||||
| @ -81,20 +75,9 @@ uint8_t eeprom_read(uint32_t mapped_addr); | |||||||
|   #define ISR_VECT |   #define ISR_VECT | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 |  | ||||||
| 	#include <avr/wdt.h> |  | ||||||
| 	#include <util/atomic.h> |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| uint8_t boot_vector = 0x00; | uint8_t boot_vector = 0x00; | ||||||
| 
 | 
 | ||||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | #if MCU_VARIANT == MCU_ESP32 | ||||||
| 	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 |  | ||||||
| 	// TODO: Get ESP32 boot flags
 | 	// TODO: Get ESP32 boot flags
 | ||||||
| #elif MCU_VARIANT == MCU_NRF52 | #elif MCU_VARIANT == MCU_NRF52 | ||||||
| 	// TODO: Get NRF52 boot flags
 | 	// TODO: Get NRF52 boot flags
 | ||||||
| @ -138,12 +121,7 @@ uint8_t boot_vector = 0x00; | |||||||
|   void boot_seq() { } |   void boot_seq() { } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | #if MCU_VARIANT == MCU_ESP32 | ||||||
| 	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 HAS_NP == true | 	#if HAS_NP == true | ||||||
| 		void led_rx_on()  { npset(0, 0, 0xFF); } | 		void led_rx_on()  { npset(0, 0, 0xFF); } | ||||||
| 		void led_rx_off() {	npset(0, 0, 0); } | 		void led_rx_off() {	npset(0, 0, 0); } | ||||||
| @ -236,12 +214,7 @@ uint8_t boot_vector = 0x00; | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| void hard_reset(void) { | void hard_reset(void) { | ||||||
| 	#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | 	#if MCU_VARIANT == MCU_ESP32 | ||||||
| 		wdt_enable(WDTO_15MS); |  | ||||||
| 		while(true) { |  | ||||||
| 			led_tx_on(); led_rx_off(); |  | ||||||
| 		} |  | ||||||
| 	#elif MCU_VARIANT == MCU_ESP32 |  | ||||||
| 		ESP.restart(); | 		ESP.restart(); | ||||||
| 	#elif MCU_VARIANT == MCU_NRF52 | 	#elif MCU_VARIANT == MCU_NRF52 | ||||||
|         NVIC_SystemReset(); |         NVIC_SystemReset(); | ||||||
| @ -332,20 +305,7 @@ void led_indicate_warning(int cycles) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // LED Indication: Info
 | // LED Indication: Info
 | ||||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||||
| 	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 HAS_NP == true | 	#if HAS_NP == true | ||||||
| 		void led_indicate_info(int cycles) { | 		void led_indicate_info(int cycles) { | ||||||
| 			bool forever = (cycles == 0) ? true : false; | 			bool forever = (cycles == 0) ? true : false; | ||||||
| @ -403,12 +363,7 @@ void led_indicate_warning(int cycles) { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| unsigned long led_standby_ticks = 0; | unsigned long led_standby_ticks = 0; | ||||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | #if MCU_VARIANT == MCU_ESP32 | ||||||
| 	uint8_t led_standby_min = 1; |  | ||||||
| 	uint8_t led_standby_max = 40; |  | ||||||
| 	unsigned long led_standby_wait = 11000; |  | ||||||
| 
 |  | ||||||
| #elif MCU_VARIANT == MCU_ESP32 |  | ||||||
| 
 | 
 | ||||||
| 	#if HAS_NP == true | 	#if HAS_NP == true | ||||||
| 		int led_standby_lng = 100; | 		int led_standby_lng = 100; | ||||||
| @ -451,23 +406,7 @@ unsigned long led_standby_ticks = 0; | |||||||
| unsigned long led_standby_value = led_standby_min; | unsigned long led_standby_value = led_standby_min; | ||||||
| int8_t  led_standby_direction = 0; | int8_t  led_standby_direction = 0; | ||||||
| 
 | 
 | ||||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||||
| 	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 HAS_NP == true | 	#if HAS_NP == true | ||||||
| 		void led_indicate_standby() { | 		void led_indicate_standby() { | ||||||
| 			led_standby_ticks++; | 			led_standby_ticks++; | ||||||
| @ -560,22 +499,7 @@ int8_t  led_standby_direction = 0; | |||||||
|   #endif |   #endif | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||||
| 	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 HAS_NP == true | 	#if HAS_NP == true | ||||||
|     void led_indicate_not_ready() { |     void led_indicate_not_ready() { | ||||||
|     	led_standby_ticks++; |     	led_standby_ticks++; | ||||||
| @ -636,6 +560,18 @@ int8_t  led_standby_direction = 0; | |||||||
| 	#endif | 	#endif | ||||||
| #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) { | void serial_write(uint8_t byte) { | ||||||
| 	#if HAS_BLUETOOTH || HAS_BLE == true | 	#if HAS_BLUETOOTH || HAS_BLE == true | ||||||
| 		if (bt_state != BT_STATE_CONNECTED) { | 		if (bt_state != BT_STATE_CONNECTED) { | ||||||
| @ -668,31 +604,33 @@ void kiss_indicate_error(uint8_t error_code) { | |||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_radiostate() { | void kiss_indicate_radiostate(RadioInterface* radio) { | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| 	serial_write(CMD_RADIO_STATE); | 	serial_write(CMD_RADIO_STATE); | ||||||
| 	serial_write(radio_online); | 	serial_write(radio->getRadioOnline()); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_stat_rx() { | void kiss_indicate_stat_rx() { | ||||||
| 	serial_write(FEND); |     // todo, implement
 | ||||||
| 	serial_write(CMD_STAT_RX); | 	//serial_write(FEND);
 | ||||||
| 	escaped_serial_write(stat_rx>>24); | 	//serial_write(CMD_STAT_RX);
 | ||||||
| 	escaped_serial_write(stat_rx>>16); | 	//escaped_serial_write(stat_rx>>24);
 | ||||||
| 	escaped_serial_write(stat_rx>>8); | 	//escaped_serial_write(stat_rx>>16);
 | ||||||
| 	escaped_serial_write(stat_rx); | 	//escaped_serial_write(stat_rx>>8);
 | ||||||
| 	serial_write(FEND); | 	//escaped_serial_write(stat_rx);
 | ||||||
|  | 	//serial_write(FEND);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_stat_tx() { | void kiss_indicate_stat_tx() { | ||||||
| 	serial_write(FEND); |     // todo, implement
 | ||||||
| 	serial_write(CMD_STAT_TX); | 	//serial_write(FEND);
 | ||||||
| 	escaped_serial_write(stat_tx>>24); | 	//serial_write(CMD_STAT_TX);
 | ||||||
| 	escaped_serial_write(stat_tx>>16); | 	//escaped_serial_write(stat_tx>>24);
 | ||||||
| 	escaped_serial_write(stat_tx>>8); | 	//escaped_serial_write(stat_tx>>16);
 | ||||||
| 	escaped_serial_write(stat_tx); | 	//escaped_serial_write(stat_tx>>8);
 | ||||||
| 	serial_write(FEND); | 	//escaped_serial_write(stat_tx);
 | ||||||
|  | 	//serial_write(FEND);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_stat_rssi() { | void kiss_indicate_stat_rssi() { | ||||||
| @ -710,24 +648,24 @@ void kiss_indicate_stat_snr() { | |||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_radio_lock() { | void kiss_indicate_radio_lock(RadioInterface* radio) { | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| 	serial_write(CMD_RADIO_LOCK); | 	serial_write(CMD_RADIO_LOCK); | ||||||
| 	serial_write(radio_locked); | 	serial_write(radio->getRadioLock()); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_spreadingfactor() { | void kiss_indicate_spreadingfactor(RadioInterface* radio) { | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| 	serial_write(CMD_SF); | 	serial_write(CMD_SF); | ||||||
| 	serial_write((uint8_t)lora_sf); | 	serial_write(radio->getSpreadingFactor()); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_codingrate() { | void kiss_indicate_codingrate(RadioInterface* radio) { | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| 	serial_write(CMD_CR); | 	serial_write(CMD_CR); | ||||||
| 	serial_write((uint8_t)lora_cr); | 	serial_write(radio->getCodingRate4()); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -738,35 +676,47 @@ void kiss_indicate_implicit_length() { | |||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_txpower() { | void kiss_indicate_txpower(RadioInterface* radio) { | ||||||
|  |     uint8_t txp = radio->getTxPower(); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| 	serial_write(CMD_TXPOWER); | 	serial_write(CMD_TXPOWER); | ||||||
| 	serial_write((uint8_t)lora_txp); | 	serial_write(txp); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_bandwidth() { | void kiss_indicate_bandwidth(RadioInterface* radio) { | ||||||
|  |     uint32_t bw = radio->getSignalBandwidth(); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| 	serial_write(CMD_BANDWIDTH); | 	serial_write(CMD_BANDWIDTH); | ||||||
| 	escaped_serial_write(lora_bw>>24); | 	escaped_serial_write(bw>>24); | ||||||
| 	escaped_serial_write(lora_bw>>16); | 	escaped_serial_write(bw>>16); | ||||||
| 	escaped_serial_write(lora_bw>>8); | 	escaped_serial_write(bw>>8); | ||||||
| 	escaped_serial_write(lora_bw); | 	escaped_serial_write(bw); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_frequency() { | void kiss_indicate_frequency(RadioInterface* radio) { | ||||||
|  |     uint32_t freq = radio->getFrequency(); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| 	serial_write(CMD_FREQUENCY); | 	serial_write(CMD_FREQUENCY); | ||||||
| 	escaped_serial_write(lora_freq>>24); | 	escaped_serial_write(freq>>24); | ||||||
| 	escaped_serial_write(lora_freq>>16); | 	escaped_serial_write(freq>>16); | ||||||
| 	escaped_serial_write(lora_freq>>8); | 	escaped_serial_write(freq>>8); | ||||||
| 	escaped_serial_write(lora_freq); | 	escaped_serial_write(freq); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_st_alock() { | void kiss_indicate_interface(int index) { | ||||||
| 	uint16_t at = (uint16_t)(st_airtime_limit*100*100); |     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(FEND); | ||||||
| 	serial_write(CMD_ST_ALOCK); | 	serial_write(CMD_ST_ALOCK); | ||||||
| 	escaped_serial_write(at>>8); | 	escaped_serial_write(at>>8); | ||||||
| @ -774,8 +724,8 @@ void kiss_indicate_st_alock() { | |||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_lt_alock() { | void kiss_indicate_lt_alock(RadioInterface* radio) { | ||||||
| 	uint16_t at = (uint16_t)(lt_airtime_limit*100*100); | 	uint16_t at = (uint16_t)(radio->getLTALock()*100*100); | ||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| 	serial_write(CMD_LT_ALOCK); | 	serial_write(CMD_LT_ALOCK); | ||||||
| 	escaped_serial_write(at>>8); | 	escaped_serial_write(at>>8); | ||||||
| @ -783,47 +733,43 @@ void kiss_indicate_lt_alock() { | |||||||
| 	serial_write(FEND); | 	serial_write(FEND); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_channel_stats() { | void kiss_indicate_channel_stats(RadioInterface* radio) { | ||||||
| 	#if MCU_VARIANT == MCU_ESP32 |     uint16_t ats = (uint16_t)(radio->getAirtime()*100*100); | ||||||
| 		uint16_t ats = (uint16_t)(airtime*100*100); |     uint16_t atl = (uint16_t)(radio->getLongtermAirtime()*100*100); | ||||||
| 		uint16_t atl = (uint16_t)(longterm_airtime*100*100); |     uint16_t cls = (uint16_t)(radio->getTotalChannelUtil()*100*100); | ||||||
| 		uint16_t cls = (uint16_t)(total_channel_util*100*100); |     uint16_t cll = (uint16_t)(radio->getLongtermChannelUtil()*100*100); | ||||||
| 		uint16_t cll = (uint16_t)(longterm_channel_util*100*100); |     serial_write(FEND); | ||||||
| 		serial_write(FEND); |     serial_write(CMD_STAT_CHTM); | ||||||
| 		serial_write(CMD_STAT_CHTM); |     escaped_serial_write(ats>>8); | ||||||
| 		escaped_serial_write(ats>>8); |     escaped_serial_write(ats); | ||||||
| 		escaped_serial_write(ats); |     escaped_serial_write(atl>>8); | ||||||
| 		escaped_serial_write(atl>>8); |     escaped_serial_write(atl); | ||||||
| 		escaped_serial_write(atl); |     escaped_serial_write(cls>>8); | ||||||
| 		escaped_serial_write(cls>>8); |     escaped_serial_write(cls); | ||||||
| 		escaped_serial_write(cls); |     escaped_serial_write(cll>>8); | ||||||
| 		escaped_serial_write(cll>>8); |     escaped_serial_write(cll); | ||||||
| 		escaped_serial_write(cll); |     serial_write(FEND); | ||||||
| 		serial_write(FEND); |  | ||||||
| 	#endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_phy_stats() { | void kiss_indicate_phy_stats(RadioInterface* radio) { | ||||||
| 	#if MCU_VARIANT == MCU_ESP32 |     uint16_t lst = (uint16_t)(radio->getSymbolTime()*1000); | ||||||
| 		uint16_t lst = (uint16_t)(lora_symbol_time_ms*1000); |     uint16_t lsr = (uint16_t)(radio->getSymbolRate()); | ||||||
| 		uint16_t lsr = (uint16_t)(lora_symbol_rate); |     uint16_t prs = (uint16_t)(radio->getPreambleLength()+4); | ||||||
| 		uint16_t prs = (uint16_t)(lora_preamble_symbols+4); |     uint16_t prt = (uint16_t)((radio->getPreambleLength()+4)*radio->getSymbolTime()); | ||||||
| 		uint16_t prt = (uint16_t)((lora_preamble_symbols+4)*lora_symbol_time_ms); |     uint16_t cst = (uint16_t)(radio->getCSMASlotMS()); | ||||||
| 		uint16_t cst = (uint16_t)(csma_slot_ms); |     serial_write(FEND); | ||||||
| 		serial_write(FEND); |     serial_write(CMD_STAT_PHYPRM); | ||||||
| 		serial_write(CMD_STAT_PHYPRM); |     escaped_serial_write(lst>>8); | ||||||
| 		escaped_serial_write(lst>>8); |     escaped_serial_write(lst); | ||||||
| 		escaped_serial_write(lst); |     escaped_serial_write(lsr>>8); | ||||||
| 		escaped_serial_write(lsr>>8); |     escaped_serial_write(lsr); | ||||||
| 		escaped_serial_write(lsr); |     escaped_serial_write(prs>>8); | ||||||
| 		escaped_serial_write(prs>>8); |     escaped_serial_write(prs); | ||||||
| 		escaped_serial_write(prs); |     escaped_serial_write(prt>>8); | ||||||
| 		escaped_serial_write(prt>>8); |     escaped_serial_write(prt); | ||||||
| 		escaped_serial_write(prt); |     escaped_serial_write(cst>>8); | ||||||
| 		escaped_serial_write(cst>>8); |     escaped_serial_write(cst); | ||||||
| 		escaped_serial_write(cst); |     serial_write(FEND); | ||||||
| 		serial_write(FEND); |  | ||||||
| 	#endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kiss_indicate_battery() { | void kiss_indicate_battery() { | ||||||
| @ -1009,43 +955,6 @@ inline uint8_t packetSequence(uint8_t header) { | |||||||
| 	return header >> 4; | 	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) { | void set_implicit_length(uint8_t len) { | ||||||
| 	implicit_l = len; | 	implicit_l = len; | ||||||
| 	if (implicit_l != 0) { | 	if (implicit_l != 0) { | ||||||
| @ -1055,76 +964,118 @@ void set_implicit_length(uint8_t len) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int getTxPower() { | void setTXPower(RadioInterface* radio, int txp) { | ||||||
| 	uint8_t txp = LoRa->getTxPower(); |     if (model == MODEL_11) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); | ||||||
| 	return (int)txp; |     if (model == MODEL_12) 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() { | uint8_t getRandom(RadioInterface* radio) { | ||||||
| 	if (radio_online) { | 	if (radio->getRadioOnline()) { | ||||||
| 		if (model == MODEL_A1) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | 		return radio->random(); | ||||||
| 		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(); |  | ||||||
| 	} else { | 	} else { | ||||||
| 		return 0x00; | 		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; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void promisc_enable() { | void promisc_enable() { | ||||||
| 	promisc = true; | 	promisc = true; | ||||||
| } | } | ||||||
| @ -1228,9 +1179,7 @@ void eeprom_flush() { | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| void eeprom_update(int mapped_addr, uint8_t byte) { | void eeprom_update(int mapped_addr, uint8_t byte) { | ||||||
| 	#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | 	#if MCU_VARIANT == MCU_ESP32 | ||||||
| 		EEPROM.update(mapped_addr, byte); |  | ||||||
| 	#elif MCU_VARIANT == MCU_ESP32 |  | ||||||
| 		if (EEPROM.read(mapped_addr) != byte) { | 		if (EEPROM.read(mapped_addr) != byte) { | ||||||
| 			EEPROM.write(mapped_addr, byte); | 			EEPROM.write(mapped_addr, byte); | ||||||
| 			EEPROM.commit(); | 			EEPROM.commit(); | ||||||
| @ -1297,9 +1246,7 @@ bool eeprom_product_valid() { | |||||||
| 	    uint8_t rval = eeprom_read(eeprom_addr(ADDR_PRODUCT)); | 	    uint8_t rval = eeprom_read(eeprom_addr(ADDR_PRODUCT)); | ||||||
|     #endif |     #endif | ||||||
| 
 | 
 | ||||||
| 	#if PLATFORM == PLATFORM_AVR | 	#if PLATFORM == PLATFORM_ESP32 | ||||||
| 	if (rval == PRODUCT_RNODE || rval == PRODUCT_HMBRW) { |  | ||||||
| 	#elif 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) { | 	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 | 	#elif PLATFORM == PLATFORM_NRF52 | ||||||
| 	if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW) { | 	if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW) { | ||||||
| @ -1434,39 +1381,51 @@ bool eeprom_have_conf() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void eeprom_conf_load() { | void eeprom_conf_load(RadioInterface* radio) { | ||||||
| 	if (eeprom_have_conf()) { | 	if (eeprom_have_conf()) { | ||||||
|  |         if (!(radio->getRadioOnline())) { | ||||||
|         #if HAS_EEPROM |         #if HAS_EEPROM | ||||||
|             lora_sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF)); |             uint8_t sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF)); | ||||||
|             lora_cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR)); |             uint8_t cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR)); | ||||||
|             lora_txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP)); |             uint8_t 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); |             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); | ||||||
|             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); |             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 |         #elif MCU_VARIANT == MCU_NRF52 | ||||||
|             lora_sf = eeprom_read(eeprom_addr(ADDR_CONF_SF)); |             uint8_t sf = eeprom_read(eeprom_addr(ADDR_CONF_SF)); | ||||||
|             lora_cr = eeprom_read(eeprom_addr(ADDR_CONF_CR)); |             uint8_t cr = eeprom_read(eeprom_addr(ADDR_CONF_CR)); | ||||||
|             lora_txp = eeprom_read(eeprom_addr(ADDR_CONF_TXP)); |             uint8_t 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); |             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); | ||||||
|             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); |             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 |         #endif | ||||||
|  |             radio->setSpreadingFactor(sf); | ||||||
|  |             radio->setCodingRate4(cr); | ||||||
|  |             setTXPower(radio, txp); | ||||||
|  |             radio->setFrequency(freq); | ||||||
|  |             radio->setSignalBandwidth(bw); | ||||||
|  |             radio->updateBitrate(); | ||||||
|  |         } | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void eeprom_conf_save() { | void eeprom_conf_save(RadioInterface* radio) { | ||||||
| 	if (hw_ready && radio_online) { | 	if (hw_ready && radio->getRadioOnline()) { | ||||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_SF), lora_sf); | 		eeprom_update(eeprom_addr(ADDR_CONF_SF), radio->getSpreadingFactor()); | ||||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_CR), lora_cr); | 		eeprom_update(eeprom_addr(ADDR_CONF_CR), radio->getCodingRate4()); | ||||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_TXP), lora_txp); | 		eeprom_update(eeprom_addr(ADDR_CONF_TXP), radio->getTxPower()); | ||||||
| 
 | 
 | ||||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, lora_bw>>24); |         uint32_t bw = radio->getSignalBandwidth(); | ||||||
| 		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); |  | ||||||
| 
 | 
 | ||||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x00, lora_freq>>24); | 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, bw>>24); | ||||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x01, lora_freq>>16); | 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x01, bw>>16); | ||||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x02, lora_freq>>8); | 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x02, bw>>8); | ||||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x03, lora_freq); | 		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); | 		eeprom_update(eeprom_addr(ADDR_CONF_OK), CONF_OK_BYTE); | ||||||
| 		led_indicate_info(10); | 		led_indicate_info(10); | ||||||
| @ -1484,18 +1443,6 @@ void unlock_rom() { | |||||||
| 	eeprom_erase(); | 	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 | typedef struct FIFOBuffer | ||||||
| { | { | ||||||
|   unsigned char *begin; |   unsigned char *begin; | ||||||
|  | |||||||
							
								
								
									
										985
									
								
								sx126x.cpp
									
									
									
									
									
								
							
							
						
						
									
										985
									
								
								sx126x.cpp
									
									
									
									
									
								
							| @ -1,985 +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(); |  | ||||||
|     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 |  | ||||||
							
								
								
									
										147
									
								
								sx126x.h
									
									
									
									
									
								
							
							
						
						
									
										147
									
								
								sx126x.h
									
									
									
									
									
								
							| @ -1,147 +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 "Interfaces.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  11 |  | ||||||
| 
 |  | ||||||
| #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); |  | ||||||
|   bool _tcxo; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| 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 |  | ||||||
							
								
								
									
										887
									
								
								sx128x.cpp
									
									
									
									
									
								
							
							
						
						
									
										887
									
								
								sx128x.cpp
									
									
									
									
									
								
							| @ -1,887 +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(); |  | ||||||
|     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 "Interfaces.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  11 |  | ||||||
| 
 |  | ||||||
| #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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user