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
 | ||||
| // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| #include "Modem.h" | ||||
| #include "Interfaces.h" | ||||
| 
 | ||||
| #ifndef BOARDS_H | ||||
|   #define BOARDS_H | ||||
| 
 | ||||
|   #define PLATFORM_AVR        0x90 | ||||
|   #define PLATFORM_ESP32      0x80 | ||||
|   #define PLATFORM_NRF52      0x70 | ||||
| 
 | ||||
|   #define MCU_1284P           0x91 | ||||
|   #define MCU_2560            0x92 | ||||
|   #define MCU_ESP32           0x81 | ||||
|   #define MCU_NRF52           0x71 | ||||
| 
 | ||||
| @ -47,13 +44,7 @@ | ||||
|   #define EINK_BW 0x02 | ||||
|   #define EINK_3C 0x03 | ||||
| 
 | ||||
|   #if defined(__AVR_ATmega1284P__) | ||||
|     #define PLATFORM PLATFORM_AVR | ||||
|     #define MCU_VARIANT MCU_1284P | ||||
|   #elif defined(__AVR_ATmega2560__) | ||||
|     #define PLATFORM PLATFORM_AVR | ||||
|     #define MCU_VARIANT MCU_2560 | ||||
|   #elif defined(ESP32) | ||||
|   #if defined(ESP32) | ||||
|     #define PLATFORM PLATFORM_ESP32 | ||||
|     #define MCU_VARIANT MCU_ESP32 | ||||
|   #elif defined(NRF52840_XXAA) | ||||
| @ -64,16 +55,6 @@ | ||||
|       #error "The firmware cannot be compiled for the selected MCU variant" | ||||
|   #endif | ||||
| 
 | ||||
|   #ifndef MODEM | ||||
|     #if BOARD_MODEL == BOARD_RAK4631 | ||||
|       #define MODEM SX1262 | ||||
|     #elif BOARD_MODEL == BOARD_GENERIC_NRF52 | ||||
|       #define MODEM SX1262 | ||||
|     #else | ||||
|       #define MODEM SX1276 | ||||
|     #endif | ||||
|   #endif | ||||
| 
 | ||||
|   #define HAS_DISPLAY false | ||||
|   #define HAS_BLUETOOTH false | ||||
|   #define HAS_BLE false | ||||
| @ -90,37 +71,7 @@ | ||||
|       #define HAS_TCXO true | ||||
|   #endif | ||||
| 
 | ||||
|   #if MCU_VARIANT == MCU_1284P | ||||
|     const int pin_cs = 4; | ||||
|     const int pin_reset = 3; | ||||
|     const int pin_dio = 2; | ||||
|     const int pin_led_rx = 12; | ||||
|     const int pin_led_tx = 13; | ||||
| 
 | ||||
|     #define BOARD_MODEL BOARD_RNODE | ||||
|     #define HAS_EEPROM true | ||||
|     #define CONFIG_UART_BUFFER_SIZE 6144 | ||||
|     #define CONFIG_QUEUE_SIZE 6144 | ||||
|     #define CONFIG_QUEUE_MAX_LENGTH 200 | ||||
|     #define EEPROM_SIZE 4096 | ||||
|     #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED | ||||
|    | ||||
|   #elif MCU_VARIANT == MCU_2560 | ||||
|     const int pin_cs = 5; | ||||
|     const int pin_reset = 4; | ||||
|     const int pin_dio = 2; | ||||
|     const int pin_led_rx = 12; | ||||
|     const int pin_led_tx = 13; | ||||
| 
 | ||||
|     #define BOARD_MODEL BOARD_HMBRW | ||||
|     #define HAS_EEPROM true | ||||
|     #define CONFIG_UART_BUFFER_SIZE 768 | ||||
|     #define CONFIG_QUEUE_SIZE 5120 | ||||
|     #define CONFIG_QUEUE_MAX_LENGTH 24 | ||||
|     #define EEPROM_SIZE 4096 | ||||
|     #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED | ||||
| 
 | ||||
|   #elif MCU_VARIANT == MCU_ESP32 | ||||
|   #if MCU_VARIANT == MCU_ESP32 | ||||
| 
 | ||||
|     // Board models for ESP32 based builds are
 | ||||
|     // defined by the build target in the makefile.
 | ||||
| @ -143,11 +94,33 @@ | ||||
|       #define HAS_BLUETOOTH true | ||||
|       #define HAS_CONSOLE true | ||||
|       #define HAS_EEPROM true | ||||
|       const int pin_cs = 4; | ||||
|       const int pin_reset = 36; | ||||
|       const int pin_dio = 39; | ||||
|       #define INTERFACE_COUNT 1 | ||||
|       const int pin_led_rx = 14; | ||||
|       const int pin_led_tx = 32; | ||||
|       const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; | ||||
|       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||
|                     // SX127X
 | ||||
|           { | ||||
|               true, // DEFAULT_SPI
 | ||||
|               false, // HAS_TCXO
 | ||||
|               false  // DIO2_AS_RF_SWITCH
 | ||||
|           },  | ||||
|       }; | ||||
|       const int8_t interface_pins[INTERFACE_COUNT][10] = {  | ||||
|                   // SX127X
 | ||||
|           { | ||||
|               4, // pin_ss
 | ||||
|               -1, // pin_sclk
 | ||||
|               -1, // pin_mosi
 | ||||
|               -1, // pin_miso
 | ||||
|               -1, // pin_busy
 | ||||
|               39, // pin_dio
 | ||||
|               36, // pin_reset
 | ||||
|               -1, // pin_txen
 | ||||
|               -1, // pin_rxen
 | ||||
|               -1  // pin_tcxo_enable
 | ||||
|           } | ||||
|       }; | ||||
| 
 | ||||
|     #elif BOARD_MODEL == BOARD_TBEAM | ||||
|       #define HAS_DISPLAY true | ||||
| @ -161,32 +134,70 @@ | ||||
|       #define I2C_SDA 21 | ||||
|       #define I2C_SCL 22 | ||||
|       #define PMU_IRQ 35 | ||||
|       const int pin_cs = 18; | ||||
|       const int pin_reset = 23; | ||||
|       const int pin_led_rx = 2; | ||||
|       const int pin_led_tx = 4; | ||||
| 
 | ||||
|       #if MODEM == SX1262 | ||||
|         #define HAS_TCXO true | ||||
|         #define HAS_BUSY true | ||||
|         #define DIO2_AS_RF_SWITCH true | ||||
|         const int pin_busy = 32; | ||||
|         const int pin_dio = 33; | ||||
|         const int pin_tcxo_enable = -1; | ||||
|       #else | ||||
|         const int pin_dio = 26; | ||||
|       #endif | ||||
|       #define INTERFACE_COUNT 1 | ||||
| 
 | ||||
|       const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; | ||||
|       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||
|                     // SX1262
 | ||||
|           { | ||||
|               true, // DEFAULT_SPI
 | ||||
|               true, // HAS_TCXO
 | ||||
|               true  // DIO2_AS_RF_SWITCH
 | ||||
|           },  | ||||
|       }; | ||||
|       const int8_t interface_pins[INTERFACE_COUNT][10] = {  | ||||
|                   // SX1262
 | ||||
|           { | ||||
|               18, // pin_ss
 | ||||
|               -1, // pin_sclk
 | ||||
|               -1, // pin_mosi
 | ||||
|               -1, // pin_miso
 | ||||
|               32, // pin_busy
 | ||||
|               33, // pin_dio
 | ||||
|               23, // pin_reset
 | ||||
|               -1, // pin_txen
 | ||||
|               -1, // pin_rxen
 | ||||
|               -1  // pin_tcxo_enable
 | ||||
|           } | ||||
|       }; | ||||
| 
 | ||||
|     #elif BOARD_MODEL == BOARD_HUZZAH32 | ||||
|       #define HAS_BLUETOOTH true | ||||
|       #define HAS_CONSOLE true | ||||
|       #define HAS_EEPROM true | ||||
|       const int pin_cs = 4; | ||||
|       const int pin_reset = 36; | ||||
|       const int pin_dio = 39; | ||||
|       const int pin_led_rx = 14; | ||||
|       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 | ||||
|       #define HAS_DISPLAY true | ||||
|       #define DISPLAY OLED | ||||
| @ -205,6 +216,33 @@ | ||||
|         const int pin_led_tx = 2; | ||||
|       #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 | ||||
|       #define HAS_DISPLAY true | ||||
|       #define DISPLAY OLED | ||||
| @ -223,6 +261,33 @@ | ||||
|         const int pin_led_tx = 22; | ||||
|       #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 | ||||
|       #define HAS_DISPLAY true | ||||
|       #define DISPLAY OLED | ||||
| @ -231,11 +296,30 @@ | ||||
|       #define HAS_PMU true | ||||
|       #define HAS_CONSOLE true | ||||
|       #define HAS_EEPROM true | ||||
|       const int pin_cs = 18; | ||||
|       const int pin_reset = 23; | ||||
|       const int pin_dio = 26; | ||||
|       #if HAS_TCXO == true | ||||
|         const int pin_tcxo_enable = 33; | ||||
|         const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||
|                         // SX127X
 | ||||
|               { | ||||
|                   true, // DEFAULT_SPI
 | ||||
|                   true, // HAS_TCXO
 | ||||
|                   false  // DIO2_AS_RF_SWITCH
 | ||||
|               },  | ||||
|         }; | ||||
|       const int8_t interface_pins[INTERFACE_COUNT][10] = {  | ||||
|                   // SX127X
 | ||||
|           { | ||||
|               18, // pin_ss
 | ||||
|               -1, // pin_sclk
 | ||||
|               -1, // pin_mosi
 | ||||
|               -1, // pin_miso
 | ||||
|               -1, // pin_busy
 | ||||
|               26, // pin_dio
 | ||||
|               23, // pin_reset
 | ||||
|               -1, // pin_txen
 | ||||
|               -1, // pin_rxen
 | ||||
|               33  // pin_tcxo_enable
 | ||||
|           } | ||||
|       }; | ||||
|       #endif | ||||
|       #if defined(EXTERNAL_LEDS) | ||||
|         const int pin_led_rx = 15; | ||||
| @ -245,15 +329,43 @@ | ||||
|         const int pin_led_tx = 25; | ||||
|       #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 | ||||
|       #define HAS_DISPLAY true | ||||
|       #define DISPLAY OLED | ||||
|       #define HAS_BLUETOOTH true | ||||
|       #define HAS_CONSOLE true | ||||
|       #define HAS_EEPROM true | ||||
|       const int pin_cs = 18; | ||||
|       const int pin_reset = 14; | ||||
|       const int pin_dio = 26; | ||||
|       #if defined(EXTERNAL_LEDS) | ||||
|         const int pin_led_rx = 36; | ||||
|         const int pin_led_tx = 37; | ||||
| @ -262,6 +374,33 @@ | ||||
|         const int pin_led_tx = 25; | ||||
|       #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 | ||||
|       #define IS_ESP32S3 true | ||||
|       #define HAS_DISPLAY true | ||||
| @ -273,6 +412,7 @@ | ||||
|       #define HAS_SLEEP true | ||||
|       #define PIN_WAKEUP GPIO_NUM_0 | ||||
|       #define WAKEUP_LEVEL 0 | ||||
|       #define INTERFACE_COUNT 1 | ||||
| 
 | ||||
|       const int pin_btn_usr1 = 0; | ||||
| 
 | ||||
| @ -284,20 +424,30 @@ | ||||
|         const int pin_led_tx = 35; | ||||
|       #endif | ||||
| 
 | ||||
|       #define MODEM SX1262 | ||||
|       #define HAS_TCXO true | ||||
|       const int pin_tcxo_enable = -1; | ||||
|       #define HAS_BUSY true | ||||
|       #define DIO2_AS_RF_SWITCH true | ||||
| 
 | ||||
|       // Following pins are for the SX1262
 | ||||
|       const int pin_cs = 8; | ||||
|       const int pin_busy = 13; | ||||
|       const int pin_dio = 14; | ||||
|       const int pin_reset = 12; | ||||
|       const int pin_mosi = 10; | ||||
|       const int pin_miso = 11; | ||||
|       const int pin_sclk = 9; | ||||
|       const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; | ||||
|       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||
|                     // SX1262
 | ||||
|           { | ||||
|               false, // DEFAULT_SPI
 | ||||
|               true, // HAS_TCXO
 | ||||
|               true  // DIO2_AS_RF_SWITCH
 | ||||
|           },  | ||||
|       }; | ||||
|       const uint8_t interface_pins[INTERFACE_COUNT][10] = {  | ||||
|                   // SX1262
 | ||||
|           { | ||||
|               8, // pin_ss
 | ||||
|               9, // pin_sclk
 | ||||
|               10, // pin_mosi
 | ||||
|               11, // pin_miso
 | ||||
|               13, // pin_busy
 | ||||
|               14, // pin_dio
 | ||||
|               12, // pin_reset
 | ||||
|               -1, // pin_txen
 | ||||
|               -1, // pin_rxen
 | ||||
|               -1  // pin_tcxo_enable
 | ||||
|           } | ||||
|       }; | ||||
| 
 | ||||
|     #elif BOARD_MODEL == BOARD_RNODE_NG_20 | ||||
|       #define HAS_DISPLAY true | ||||
| @ -320,6 +470,31 @@ | ||||
|         #endif | ||||
|       #endif | ||||
| 
 | ||||
|       const uint8_t interfaces[INTERFACE_COUNT] = {SX1276}; | ||||
|       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||
|                     // SX1276
 | ||||
|           { | ||||
|               false, // DEFAULT_SPI
 | ||||
|               true, // HAS_TCXO
 | ||||
|               true  // DIO2_AS_RF_SWITCH
 | ||||
|           },  | ||||
|       }; | ||||
|       const uint8_t interface_pins[INTERFACE_COUNT][10] = {  | ||||
|                   // SX1276
 | ||||
|           { | ||||
|               8, // pin_ss
 | ||||
|               9, // pin_sclk
 | ||||
|               10, // pin_mosi
 | ||||
|               11, // pin_miso
 | ||||
|               13, // pin_busy
 | ||||
|               14, // pin_dio
 | ||||
|               12, // pin_reset
 | ||||
|               -1, // pin_txen
 | ||||
|               -1, // pin_rxen
 | ||||
|               -1  // pin_tcxo_enable
 | ||||
|           } | ||||
|       }; | ||||
| 
 | ||||
|     #elif BOARD_MODEL == BOARD_RNODE_NG_21 | ||||
|       #define HAS_DISPLAY true | ||||
|       #define DISPLAY OLED | ||||
| @ -329,9 +504,6 @@ | ||||
|       #define HAS_NP true | ||||
|       #define HAS_SD false | ||||
|       #define HAS_EEPROM true | ||||
|       const int pin_cs = 18; | ||||
|       const int pin_reset = 23; | ||||
|       const int pin_dio = 26; | ||||
|       const int pin_np = 12; | ||||
|       const int pin_dac = 25; | ||||
|       const int pin_adc = 34; | ||||
| @ -349,12 +521,34 @@ | ||||
|         #endif | ||||
|       #endif | ||||
| 
 | ||||
|       const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; | ||||
|       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||
|                     // SX127X
 | ||||
|           { | ||||
|               true, // DEFAULT_SPI
 | ||||
|               false, // HAS_TCXO
 | ||||
|               false  // DIO2_AS_RF_SWITCH
 | ||||
|           },  | ||||
|       }; | ||||
|       const uint8_t interface_pins[INTERFACE_COUNT][10] = {  | ||||
|                   // SX127X
 | ||||
|           { | ||||
|               18, // pin_ss
 | ||||
|               -1, // pin_sclk
 | ||||
|               -1, // pin_mosi
 | ||||
|               -1, // pin_miso
 | ||||
|               -1, // pin_busy
 | ||||
|               26, // pin_dio
 | ||||
|               23, // pin_reset
 | ||||
|               -1, // pin_txen
 | ||||
|               -1, // pin_rxen
 | ||||
|               -1  // pin_tcxo_enable
 | ||||
|           } | ||||
|       }; | ||||
| 
 | ||||
|     #elif BOARD_MODEL == BOARD_RNODE_NG_22 | ||||
|       #define IS_ESP32S3 true | ||||
|       #define MODEM SX1262 | ||||
|       #define DIO2_AS_RF_SWITCH true | ||||
|       #define HAS_BUSY true | ||||
|       #define HAS_TCXO true | ||||
| 
 | ||||
|       #define HAS_DISPLAY true | ||||
|       #define DISPLAY OLED | ||||
| @ -374,16 +568,6 @@ | ||||
|       // #define DISP_SLEEP_LEVEL HIGH
 | ||||
|       const int pin_btn_usr1 = 0; | ||||
|        | ||||
|       const int pin_cs = 7; | ||||
|       const int pin_reset = 8; | ||||
|       const int pin_sclk = 5; | ||||
|       const int pin_mosi = 6; | ||||
|       const int pin_miso = 3; | ||||
|       const int pin_tcxo_enable = -1; | ||||
| 
 | ||||
|       const int pin_dio = 33; | ||||
|       const int pin_busy = 34; | ||||
|        | ||||
|       const int pin_np = 38; | ||||
|       const int pin_dac = 25; | ||||
|       const int pin_adc = 1; | ||||
| @ -402,6 +586,31 @@ | ||||
|         #endif | ||||
|       #endif | ||||
| 
 | ||||
|       const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; | ||||
|       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||
|                     // SX1262
 | ||||
|           { | ||||
|               false, // DEFAULT_SPI
 | ||||
|               true, // HAS_TCXO
 | ||||
|               true  // DIO2_AS_RF_SWITCH
 | ||||
|           },  | ||||
|       }; | ||||
|       const uint8_t interface_pins[INTERFACE_COUNT][10] = {  | ||||
|                   // SX1262
 | ||||
|           { | ||||
|                7, // pin_ss
 | ||||
|                5, // pin_sclk
 | ||||
|                6, // pin_mosi
 | ||||
|                3, // pin_miso
 | ||||
|               34, // pin_busy
 | ||||
|               33, // pin_dio
 | ||||
|                8, // pin_reset
 | ||||
|               -1, // pin_txen
 | ||||
|               -1, // pin_rxen
 | ||||
|               -1  // pin_tcxo_enable
 | ||||
|           } | ||||
|       }; | ||||
| 
 | ||||
|     #else | ||||
|       #error An unsupported ESP32 board was selected. Cannot compile RNode firmware. | ||||
|     #endif | ||||
| @ -410,17 +619,14 @@ | ||||
|     #if BOARD_MODEL == BOARD_RAK4631 | ||||
|       #define HAS_EEPROM false | ||||
|       #define HAS_DISPLAY true | ||||
|       #define DISPLAY EINK_3C | ||||
|       #define DISPLAY EINK_BW | ||||
|       #define HAS_BLUETOOTH false | ||||
|       #define HAS_BLE true | ||||
|       #define HAS_CONSOLE false | ||||
|       #define HAS_PMU true | ||||
|       #define HAS_NP false | ||||
|       #define HAS_SD false | ||||
|       #define HAS_TCXO true | ||||
|       #define HAS_RF_SWITCH_RX_TX true | ||||
|       #define HAS_BUSY true | ||||
|       #define DIO2_AS_RF_SWITCH true | ||||
|       #define CONFIG_UART_BUFFER_SIZE 6144 | ||||
|       #define CONFIG_QUEUE_SIZE 6144 | ||||
|       #define CONFIG_QUEUE_MAX_LENGTH 200 | ||||
| @ -429,15 +635,45 @@ | ||||
|       #define BLE_MANUFACTURER "RAK Wireless" | ||||
|       #define BLE_MODEL "RAK4640" | ||||
| 
 | ||||
|       // Following pins are for the sx1262
 | ||||
|       const int pin_rxen = 37; | ||||
|       const int pin_reset = 38; | ||||
|       const int pin_cs = 42; | ||||
|       const int pin_sclk = 43; | ||||
|       const int pin_mosi = 44; | ||||
|       const int pin_miso = 45; | ||||
|       const int pin_busy = 46; | ||||
|       const int pin_dio = 47; | ||||
|       #define INTERFACE_COUNT 1 | ||||
| 
 | ||||
|       // first interface in list is the primary
 | ||||
|       const uint8_t interfaces[INTERFACE_COUNT] = {SX126X}; | ||||
|       const bool interface_cfg[INTERFACE_COUNT][3] = {  | ||||
|                     // SX1262
 | ||||
|           { | ||||
|               false, // DEFAULT_SPI
 | ||||
|               true, // HAS_TCXO
 | ||||
|               true  // DIO2_AS_RF_SWITCH
 | ||||
|           } | ||||
|       }; | ||||
|       const 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_dc = WB_IO1; | ||||
| @ -447,25 +683,15 @@ | ||||
| 
 | ||||
|       const int pin_led_rx = LED_BLUE; | ||||
|       const int pin_led_tx = LED_GREEN; | ||||
|       const int pin_tcxo_enable = -1; | ||||
| 
 | ||||
|     #else | ||||
|       #error An unsupported nRF board was selected. Cannot compile RNode firmware. | ||||
|     #endif | ||||
| 
 | ||||
|   #endif | ||||
| 
 | ||||
|   #ifndef HAS_RF_SWITCH_RX_TX | ||||
|     const int pin_rxen = -1; | ||||
|     const int pin_txen = -1; | ||||
|   #ifndef INTERFACE_SPI | ||||
|     // Even if custom SPI interfaces are not needed, the array must exist to prevent compilation errors.
 | ||||
|     #define INTERFACE_SPI | ||||
|     const SPIClass interface_spi[1]; | ||||
|   #endif | ||||
| 
 | ||||
|   #ifndef HAS_BUSY | ||||
|     const int pin_busy = -1; | ||||
|   #endif | ||||
| 
 | ||||
|   #ifndef DIO2_AS_RF_SWITCH | ||||
|     #define DIO2_AS_RF_SWITCH false | ||||
|   #endif | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										82
									
								
								Config.h
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								Config.h
									
									
									
									
									
								
							| @ -43,7 +43,7 @@ | ||||
| 	#define M_FRQ_S 27388122 | ||||
| 	#define M_FRQ_R 27388061 | ||||
| 	bool console_active = false; | ||||
| 	bool modem_installed = false; | ||||
| 	bool modems_installed = false; | ||||
| 
 | ||||
| 	#define MTU   	   508 | ||||
| 	#define SINGLE_MTU 255 | ||||
| @ -51,13 +51,10 @@ | ||||
| 	#define MIN_L	   1 | ||||
| 	#define CMD_L      64 | ||||
| 
 | ||||
|     bool mw_radio_online = false; | ||||
| 
 | ||||
| 	#define eeprom_addr(a) (a+EEPROM_OFFSET) | ||||
| 
 | ||||
|     #if (MODEM == SX1262 || MODEM == SX1280) && defined(NRF52840_XXAA) | ||||
|         SPIClass spiModem(NRF_SPIM2, pin_miso, pin_sclk, pin_mosi); | ||||
|     #endif | ||||
|     #define PA_OUTPUT_RFO_PIN      0 | ||||
|     #define PA_OUTPUT_PA_BOOST_PIN 1 | ||||
| 
 | ||||
| 	// MCU independent configuration parameters
 | ||||
| 	const long serial_baudrate  = 115200; | ||||
| @ -66,36 +63,15 @@ | ||||
| 	// packet RSSI register
 | ||||
| 	const int  rssi_offset = 157; | ||||
| 
 | ||||
| 
 | ||||
|     // Default LoRa settings
 | ||||
|     const int lora_rx_turnaround_ms = 66; | ||||
|     const int lora_post_tx_yield_slots = 6; | ||||
| 	uint32_t post_tx_yield_timeout = 0; | ||||
| 	#define LORA_PREAMBLE_SYMBOLS_HW  4 | ||||
| 	#define LORA_PREAMBLE_SYMBOLS_MIN 18 | ||||
| 	#define LORA_PREAMBLE_TARGET_MS   15 | ||||
|     #define LORA_CAD_SYMBOLS 3 | ||||
| 	int csma_slot_ms = 50; | ||||
| 	float csma_p_min = 0.1; | ||||
| 	float csma_p_max = 0.8; | ||||
| 	uint8_t csma_p = 0; | ||||
| 
 | ||||
| 	int  lora_sf   	           = 0; | ||||
| 	int  lora_cr               = 5; | ||||
| 	int  lora_txp              = 0xFF; | ||||
| 	uint32_t lora_bw           = 0; | ||||
| 	uint32_t lora_freq         = 0; | ||||
| 	uint32_t lora_bitrate      = 0; | ||||
| 	long lora_preamble_symbols = 6; | ||||
| 	float lora_symbol_time_ms  = 0.0; | ||||
| 	float lora_symbol_rate     = 0.0; | ||||
| 	float lora_us_per_byte     = 0.0; | ||||
| 
 | ||||
| 	// Operational variables
 | ||||
| 	bool radio_locked  = true; | ||||
| 	bool radio_online  = false; | ||||
| 	bool community_fw  = true; | ||||
| 	bool hw_ready      = false; | ||||
| 	bool radio_error   = false; | ||||
| 	bool disp_ready    = false; | ||||
| 	bool pmu_ready     = false; | ||||
| 	bool promisc       = false; | ||||
| @ -106,7 +82,6 @@ | ||||
| 	uint8_t model     = 0x00; | ||||
| 	uint8_t hwrev     = 0x00; | ||||
| 
 | ||||
|     int     current_rssi    = -292; | ||||
| 	int		last_rssi		= -292; | ||||
| 	uint8_t last_rssi_raw   = 0x00; | ||||
| 	uint8_t last_snr_raw	= 0x80; | ||||
| @ -125,49 +100,6 @@ | ||||
| 	uint32_t stat_rx		= 0; | ||||
| 	uint32_t stat_tx		= 0; | ||||
| 
 | ||||
| 	#define STATUS_INTERVAL_MS 3 | ||||
| 	#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||
| 	  #define DCD_SAMPLES 2500 | ||||
| 		#define UTIL_UPDATE_INTERVAL_MS 1000 | ||||
| 		#define UTIL_UPDATE_INTERVAL (UTIL_UPDATE_INTERVAL_MS/STATUS_INTERVAL_MS) | ||||
| 		#define AIRTIME_LONGTERM 3600 | ||||
| 		#define AIRTIME_LONGTERM_MS (AIRTIME_LONGTERM*1000) | ||||
| 		#define AIRTIME_BINLEN_MS (STATUS_INTERVAL_MS*DCD_SAMPLES) | ||||
| 		#define AIRTIME_BINS ((AIRTIME_LONGTERM*1000)/AIRTIME_BINLEN_MS) | ||||
| 		bool util_samples[DCD_SAMPLES]; | ||||
| 		uint16_t airtime_bins[AIRTIME_BINS]; | ||||
| 		float longterm_bins[AIRTIME_BINS]; | ||||
| 		int dcd_sample = 0; | ||||
| 		float local_channel_util = 0.0; | ||||
| 		float total_channel_util = 0.0; | ||||
| 		float longterm_channel_util = 0.0; | ||||
| 		float airtime = 0.0; | ||||
| 		float longterm_airtime = 0.0; | ||||
| 		#define current_airtime_bin(void) (millis()%AIRTIME_LONGTERM_MS)/AIRTIME_BINLEN_MS | ||||
| 	#endif | ||||
| 	float st_airtime_limit = 0.0; | ||||
| 	float lt_airtime_limit = 0.0; | ||||
| 	bool airtime_lock = false; | ||||
| 
 | ||||
| 	bool stat_signal_detected   = false; | ||||
| 	bool stat_signal_synced     = false; | ||||
| 	bool stat_rx_ongoing        = false; | ||||
| 	bool dcd                    = false; | ||||
| 	bool dcd_led                = false; | ||||
| 	bool dcd_waiting            = false; | ||||
| 	long dcd_wait_until         = 0; | ||||
| 	uint16_t dcd_count          = 0; | ||||
| 	uint16_t dcd_threshold      = 2; | ||||
| 
 | ||||
| 	uint32_t status_interval_ms = STATUS_INTERVAL_MS; | ||||
| 	uint32_t last_status_update = 0; | ||||
| 	uint32_t last_dcd = 0; | ||||
| 
 | ||||
| 	// Status flags
 | ||||
| 	const uint8_t SIG_DETECT = 0x01; | ||||
| 	const uint8_t SIG_SYNCED = 0x02; | ||||
| 	const uint8_t RX_ONGOING = 0x04; | ||||
| 
 | ||||
|     // Power management
 | ||||
|     #define BATTERY_STATE_DISCHARGING 0x01 | ||||
|     #define BATTERY_STATE_CHARGING 0x02 | ||||
| @ -192,4 +124,10 @@ | ||||
| 	#define START_FROM_BROWNOUT 0x03 | ||||
| 	#define START_FROM_JTAG 0x04 | ||||
| 
 | ||||
|     // Subinterfaces
 | ||||
|     // select interface 0 by default
 | ||||
|     uint8_t interface = 0; | ||||
|     RadioInterface* selected_radio; | ||||
|     RadioInterface* interface_obj[INTERFACE_COUNT]; | ||||
|     RadioInterface* interface_obj_sorted[INTERFACE_COUNT]; | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										165
									
								
								Display.h
									
									
									
									
									
								
							
							
						
						
									
										165
									
								
								Display.h
									
									
									
									
									
								
							| @ -130,10 +130,19 @@ unsigned char fb[512]; | ||||
| uint32_t last_disp_update = 0; | ||||
| int disp_update_interval = 1000/disp_target_fps; | ||||
| uint32_t last_page_flip = 0; | ||||
| uint32_t last_interface_page_flip = 0; | ||||
| int page_interval = 4000; | ||||
| bool device_signatures_ok(); | ||||
| bool device_firmware_ok(); | ||||
| 
 | ||||
| bool stat_area_initialised = false; | ||||
| bool radio_online = false; | ||||
| 
 | ||||
| #define START_PAGE 0 | ||||
| const uint8_t pages = 3; | ||||
| uint8_t disp_page = START_PAGE; | ||||
| uint8_t interface_page = START_PAGE; | ||||
| 
 | ||||
| #if DISPLAY == OLED | ||||
| #define WATERFALL_SIZE 46 | ||||
| #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||
| @ -142,8 +151,8 @@ bool device_firmware_ok(); | ||||
| // add more eink compatible boards here
 | ||||
| #endif | ||||
| 
 | ||||
| int waterfall[WATERFALL_SIZE]; | ||||
| int waterfall_head = 0; | ||||
| int waterfall[INTERFACE_COUNT][WATERFALL_SIZE] = {0}; | ||||
| int waterfall_head[INTERFACE_COUNT] = {0}; | ||||
| 
 | ||||
| int p_ad_x = 0; | ||||
| int p_ad_y = 0; | ||||
| @ -286,9 +295,6 @@ bool display_init() { | ||||
|       #endif | ||||
| 
 | ||||
|       update_area_positions(); | ||||
|       for (int i = 0; i < WATERFALL_SIZE; i++) { | ||||
|         waterfall[i] = 0; | ||||
|       } | ||||
| 
 | ||||
|       last_page_flip = millis(); | ||||
| 
 | ||||
| @ -359,12 +365,33 @@ void draw_bt_icon(int px, int py) { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void draw_lora_icon(int px, int py) { | ||||
| void draw_lora_icon(RadioInterface* radio, int px, int py) { | ||||
|   // todo: make display show other interfaces
 | ||||
|   if (radio_online) { | ||||
|         #if DISPLAY == OLED | ||||
|         stat_area.drawBitmap(px, py, bm_rf+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); | ||||
|                 if (interface_page == radio->getIndex()) { | ||||
|                     stat_area.drawBitmap(px - 2, py - 2, bm_dot_sqr, 18, 18, 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*32, 16, 16, GxEPD_WHITE, GxEPD_BLACK); | ||||
|                   } else { | ||||
|                 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 | ||||
| @ -376,7 +403,8 @@ void draw_lora_icon(int px, int py) { | ||||
| } | ||||
| 
 | ||||
| void draw_mw_icon(int px, int py) { | ||||
|   if (mw_radio_online) { | ||||
|   if (INTERFACE_COUNT >= 2) { | ||||
|       if (interface_obj[1]->getRadioOnline()) { | ||||
|         #if DISPLAY == OLED | ||||
|             stat_area.drawBitmap(px, py, bm_rf+3*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); | ||||
|         #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||
| @ -389,6 +417,13 @@ void draw_mw_icon(int px, int py) { | ||||
|             stat_area.drawBitmap(px, py, bm_rf+2*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); | ||||
|         #endif | ||||
|       } | ||||
|   } else { | ||||
|     #if DISPLAY == OLED | ||||
|       stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); | ||||
|     #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 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| uint8_t charge_tick = 0; | ||||
| @ -479,7 +514,7 @@ void draw_battery_bars(int px, int py) { | ||||
| void draw_quality_bars(int px, int py) { | ||||
|   signed char t_snr = (signed int)last_snr_raw; | ||||
|   int snr_int = (int)t_snr; | ||||
|   float snr_min = Q_SNR_MIN_BASE-(int)lora_sf*Q_SNR_STEP; | ||||
|   float snr_min = Q_SNR_MIN_BASE-(int)interface_obj[interface_page]->getSpreadingFactor()*Q_SNR_STEP; | ||||
|   float snr_span = (Q_SNR_MAX-snr_min); | ||||
|   float snr = ((int)snr_int) * 0.25; | ||||
|   float quality = ((snr-snr_min)/(snr_span))*100; | ||||
| @ -593,13 +628,13 @@ void draw_signal_bars(int px, int py) { | ||||
| #define WF_PIXEL_WIDTH 22 | ||||
| #endif | ||||
| void draw_waterfall(int px, int py) { | ||||
|   int rssi_val = current_rssi; | ||||
|   int rssi_val = interface_obj[interface_page]->currentRssi(); | ||||
|   if (rssi_val < WF_RSSI_MIN) rssi_val = WF_RSSI_MIN; | ||||
|   if (rssi_val > WF_RSSI_MAX) rssi_val = WF_RSSI_MAX; | ||||
|   int rssi_normalised = ((rssi_val - WF_RSSI_MIN)*(1.0/WF_RSSI_SPAN))*WF_PIXEL_WIDTH; | ||||
| 
 | ||||
|   waterfall[waterfall_head++] = rssi_normalised; | ||||
|   if (waterfall_head >= WATERFALL_SIZE) waterfall_head = 0; | ||||
|   waterfall[interface_page][waterfall_head[interface_page]++] = rssi_normalised; | ||||
|   if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0; | ||||
| 
 | ||||
|   #if DISPLAY == OLED | ||||
|   stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, SSD1306_BLACK); | ||||
| @ -607,8 +642,8 @@ void draw_waterfall(int px, int py) { | ||||
|   stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, GxEPD_BLACK); | ||||
|   #endif | ||||
|   for (int i = 0; i < WATERFALL_SIZE; i++){ | ||||
|     int wi = (waterfall_head+i)%WATERFALL_SIZE; | ||||
|     int ws = waterfall[wi]; | ||||
|     int wi = (waterfall_head[interface_page]+i)%WATERFALL_SIZE; | ||||
|     int ws = waterfall[interface_page][wi]; | ||||
|     if (ws > 0) { | ||||
|       #if DISPLAY == OLED | ||||
|         stat_area.drawLine(px, py+i, px+ws-1, py+i, SSD1306_WHITE); | ||||
| @ -619,7 +654,6 @@ void draw_waterfall(int px, int py) { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool stat_area_initialised = false; | ||||
| void draw_stat_area() { | ||||
|   if (device_init_done) { | ||||
|     if (!stat_area_initialised) { | ||||
| @ -631,19 +665,51 @@ void draw_stat_area() { | ||||
|       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 | ||||
|     draw_cable_icon(3, 8); | ||||
|     draw_bt_icon(3, 30); | ||||
|     draw_lora_icon(45, 8); | ||||
|     draw_mw_icon(45, 30); | ||||
|     draw_lora_icon(interface_obj[0], 45, 8); | ||||
| 
 | ||||
|     // todo, expand support to show more than two interfaces on screen
 | ||||
|     if (INTERFACE_COUNT > 1) { | ||||
|         draw_lora_icon(interface_obj[1], 45, 30); | ||||
|     } | ||||
|     draw_battery_bars(4, 58); | ||||
|     #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||
|     draw_cable_icon(6, 18); | ||||
|     draw_bt_icon(6, 60); | ||||
|     draw_lora_icon(86, 18); | ||||
|     draw_mw_icon(86, 60); | ||||
|     draw_lora_icon(interface_obj[0], 86, 18); | ||||
| 
 | ||||
|     // todo, expand support to show more than two interfaces on screen
 | ||||
|     if (INTERFACE_COUNT > 1) { | ||||
|         draw_lora_icon(interface_obj[1], 86, 60); | ||||
|     } | ||||
|     draw_battery_bars(8, 113); | ||||
|     #endif | ||||
|     radio_online = false; | ||||
|     for (int i = 0; i < INTERFACE_COUNT; i++) { | ||||
|         if (interface_obj[i]->getRadioOnline()) { | ||||
|             radio_online = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if (radio_online) { | ||||
|       #if DISPLAY == OLED | ||||
|       draw_quality_bars(28, 56); | ||||
| @ -701,9 +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() { | ||||
|   if (!device_init_done || firmware_update_mode) { | ||||
|     uint8_t p_by = 37; | ||||
| @ -726,6 +789,7 @@ void draw_disp_area() { | ||||
|     if (!disp_ext_fb or bt_ssp_pin != 0) { | ||||
|       if (radio_online && display_diagnostics) { | ||||
|         #if DISPLAY == OLED | ||||
|           selected_radio = interface_obj[interface_page]; | ||||
|           disp_area.fillRect(0,8,disp_area.width(),37, SSD1306_BLACK); disp_area.fillRect(0,37,disp_area.width(),27, SSD1306_WHITE); | ||||
|           disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(SSD1306_WHITE); | ||||
| 
 | ||||
| @ -734,26 +798,26 @@ void draw_disp_area() { | ||||
|           disp_area.setCursor(14, 13); | ||||
|           disp_area.print("@"); | ||||
|           disp_area.setCursor(21, 13); | ||||
|           disp_area.printf("%.1fKbps", (float)lora_bitrate/1000.0); | ||||
|           disp_area.printf("%.1fKbps", (float)(selected_radio->getBitrate())/1000.0); | ||||
| 
 | ||||
|           disp_area.setCursor(2, 23-1); | ||||
|           disp_area.print("Airtime:"); | ||||
| 
 | ||||
|           disp_area.setCursor(11, 33-1); | ||||
|           if (total_channel_util < 0.099) { | ||||
|             disp_area.printf("%.1f%%", airtime*100.0); | ||||
|           if (selected_radio->getTotalChannelUtil() < 0.099) { | ||||
|             disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0); | ||||
|           } else { | ||||
|             disp_area.printf("%.0f%%", airtime*100.0); | ||||
|             disp_area.printf("%.0f%%", selected_radio->getAirtime()*100.0); | ||||
|           } | ||||
| 
 | ||||
|           disp_area.drawBitmap(2, 26-1, bm_hg_low, 5, 9, SSD1306_WHITE, SSD1306_BLACK); | ||||
| 
 | ||||
|           disp_area.setCursor(32+11, 33-1); | ||||
| 
 | ||||
|           if (longterm_channel_util < 0.099) { | ||||
|             disp_area.printf("%.1f%%", longterm_airtime*100.0); | ||||
|           if (selected_radio->getLongtermChannelUtil() < 0.099) { | ||||
|             disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0); | ||||
|           } else { | ||||
|             disp_area.printf("%.0f%%", longterm_airtime*100.0); | ||||
|             disp_area.printf("%.0f%%", selected_radio->getLongtermAirtime()*100.0); | ||||
|           } | ||||
|           disp_area.drawBitmap(32+2, 26-1, bm_hg_high, 5, 9, SSD1306_WHITE, SSD1306_BLACK); | ||||
| 
 | ||||
| @ -765,22 +829,23 @@ void draw_disp_area() { | ||||
|           disp_area.print("Load:"); | ||||
| 
 | ||||
|           disp_area.setCursor(11, 57); | ||||
|           if (total_channel_util < 0.099) { | ||||
|             disp_area.printf("%.1f%%", total_channel_util*100.0); | ||||
|           if (selected_radio->getTotalChannelUtil() < 0.099) { | ||||
|             disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0); | ||||
|           } else { | ||||
|             disp_area.printf("%.0f%%", total_channel_util*100.0); | ||||
|             disp_area.printf("%.0f%%", selected_radio->getTotalChannelUtil()*100.0); | ||||
|           } | ||||
|           disp_area.drawBitmap(2, 50, bm_hg_low, 5, 9, SSD1306_BLACK, SSD1306_WHITE); | ||||
|          | ||||
|           disp_area.setCursor(32+11, 57); | ||||
|           if (longterm_channel_util < 0.099) { | ||||
|             disp_area.printf("%.1f%%", longterm_channel_util*100.0); | ||||
|           if (selected_radio->getLongtermChannelUtil() < 0.099) { | ||||
|             disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0); | ||||
|           } else { | ||||
|             disp_area.printf("%.0f%%", longterm_channel_util*100.0); | ||||
|             disp_area.printf("%.0f%%", selected_radio->getLongtermChannelUtil()*100.0); | ||||
|           } | ||||
|           disp_area.drawBitmap(32+2, 50, bm_hg_high, 5, 9, SSD1306_BLACK, SSD1306_WHITE); | ||||
| 
 | ||||
|         #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||
|           selected_radio = interface_obj[interface_page]; | ||||
|           disp_area.fillRect(0,12,disp_area.width(),57, GxEPD_BLACK); disp_area.fillRect(0,69,disp_area.width(),56, GxEPD_WHITE); | ||||
|           disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(GxEPD_WHITE); | ||||
|           disp_area.setTextSize(2); // scale text 2x
 | ||||
| @ -790,25 +855,25 @@ void draw_disp_area() { | ||||
|           disp_area.setCursor(14*2, 22); | ||||
|           disp_area.print("@"); | ||||
|           disp_area.setCursor(21*2, 22); | ||||
|           disp_area.printf("%.1fKbps", (float)lora_bitrate/1000.0); | ||||
|           disp_area.printf("%.1fKbps", (float)(selected_radio->getBitrate())/1000.0); | ||||
| 
 | ||||
|           disp_area.setCursor(2, 36); | ||||
|           disp_area.print("Airtime:"); | ||||
| 
 | ||||
|           disp_area.setCursor(7+12, 53); | ||||
|           if (total_channel_util < 0.099) { | ||||
|             disp_area.printf("%.1f%%", airtime*100.0); | ||||
|           if (selected_radio->getTotalChannelUtil() < 0.099) { | ||||
|             disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0); | ||||
|           } else { | ||||
|             disp_area.printf("%.0f%%", airtime*100.0); | ||||
|             disp_area.printf("%.0f%%", selected_radio->getAirtime()*100.0); | ||||
|           } | ||||
| 
 | ||||
|           disp_area.drawBitmap(2, 41, bm_hg_low, 10, 18, GxEPD_WHITE, GxEPD_BLACK); | ||||
| 
 | ||||
|           disp_area.setCursor(64+17, 53); | ||||
|           if (longterm_channel_util < 0.099) { | ||||
|             disp_area.printf("%.1f%%", longterm_airtime*100.0); | ||||
|           if (selected_radio->getLongtermChannelUtil() < 0.099) { | ||||
|             disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0); | ||||
|           } else { | ||||
|             disp_area.printf("%.0f%%", longterm_airtime*100.0); | ||||
|             disp_area.printf("%.0f%%", selected_radio->getLongtermAirtime()*100.0); | ||||
|           } | ||||
|           disp_area.drawBitmap(64, 41, bm_hg_high, 10, 18, GxEPD_WHITE, GxEPD_BLACK); | ||||
| 
 | ||||
| @ -820,18 +885,18 @@ void draw_disp_area() { | ||||
|           disp_area.print("Load:"); | ||||
|          | ||||
|           disp_area.setCursor(7+12, 110); | ||||
|           if (total_channel_util < 0.099) { | ||||
|             disp_area.printf("%.1f%%", total_channel_util*100.0); | ||||
|           if (selected_radio->getTotalChannelUtil() < 0.099) { | ||||
|             disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0); | ||||
|           } else { | ||||
|             disp_area.printf("%.0f%%", total_channel_util*100.0); | ||||
|             disp_area.printf("%.0f%%", selected_radio->getTotalChannelUtil()*100.0); | ||||
|           } | ||||
|           disp_area.drawBitmap(2, 98, bm_hg_low, 10, 18, GxEPD_BLACK, GxEPD_WHITE); | ||||
| 
 | ||||
|           disp_area.setCursor(64+17, 110); | ||||
|           if (longterm_channel_util < 0.099) { | ||||
|             disp_area.printf("%.1f%%", longterm_channel_util*100.0); | ||||
|           if (selected_radio->getLongtermChannelUtil() < 0.099) { | ||||
|             disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0); | ||||
|           } else { | ||||
|             disp_area.printf("%.0f%%", longterm_channel_util*100.0); | ||||
|             disp_area.printf("%.0f%%", selected_radio->getLongtermChannelUtil()*100.0); | ||||
|           } | ||||
|           disp_area.drawBitmap(64, 98, bm_hg_high, 10, 18, GxEPD_BLACK, GxEPD_WHITE); | ||||
|         #endif | ||||
| @ -852,7 +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 DISPLAY == OLED | ||||
|             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); | ||||
|           #endif | ||||
|         } else { | ||||
|           if (!modem_installed) { | ||||
|           if (!modems_installed) { | ||||
|             #if DISPLAY == OLED | ||||
|               disp_area.drawBitmap(0, 37, bm_no_radio, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); | ||||
|             #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) | ||||
|  | ||||
| @ -10,6 +10,11 @@ This entry should include, at a minimum, the following: | ||||
| * whether the modem has a busy pin | ||||
| * RX and TX leds (preferably LEDs of different colours) | ||||
| 
 | ||||
| # Check this area... | ||||
| see https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.h#L39 | ||||
| Effectively, there are multiple SPI buses we can map to pins on these | ||||
| devices (including the hardware SPI bus) | ||||
| 
 | ||||
| An example of a minimal entry can be seen below: | ||||
| ``` | ||||
| #elif BOARD_MODEL == BOARD_MY_WICKED_BOARD | ||||
|  | ||||
							
								
								
									
										29
									
								
								Framing.h
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								Framing.h
									
									
									
									
									
								
							| @ -22,7 +22,6 @@ | ||||
|   #define TFESC           0xDD | ||||
| 
 | ||||
|   #define CMD_UNKNOWN     0xFE | ||||
|   #define CMD_DATA        0x00 | ||||
|   #define CMD_FREQUENCY   0x01 | ||||
|   #define CMD_BANDWIDTH   0x02 | ||||
|   #define CMD_TXPOWER     0x03 | ||||
| @ -75,6 +74,34 @@ | ||||
|   #define CMD_RESET       0x55 | ||||
|   #define CMD_RESET_BYTE  0xF8 | ||||
| 
 | ||||
|   #define CMD_INTERFACES  0x64 | ||||
| 
 | ||||
|   #define CMD_INT0_DATA   0x00 | ||||
|   #define CMD_INT1_DATA   0x10 | ||||
|   #define CMD_INT2_DATA   0x20 | ||||
|   #define CMD_INT3_DATA   0x70 | ||||
|   #define CMD_INT4_DATA   0x80 | ||||
|   #define CMD_INT5_DATA   0x90 | ||||
|   #define CMD_INT6_DATA   0xA0 | ||||
|   #define CMD_INT7_DATA   0xB0 | ||||
|   #define CMD_INT8_DATA   0xC0 | ||||
|   #define CMD_INT9_DATA   0xD0 | ||||
|   #define CMD_INT10_DATA  0xE0 | ||||
|   #define CMD_INT11_DATA  0xF0 | ||||
| 
 | ||||
|   #define CMD_SEL_INT0    0x1E | ||||
|   #define CMD_SEL_INT1    0x1F | ||||
|   #define CMD_SEL_INT2    0x2F | ||||
|   #define CMD_SEL_INT3    0x7F | ||||
|   #define CMD_SEL_INT4    0x8F | ||||
|   #define CMD_SEL_INT5    0x9F | ||||
|   #define CMD_SEL_INT6    0xAF | ||||
|   #define CMD_SEL_INT7    0xBF | ||||
|   #define CMD_SEL_INT8    0xCF | ||||
|   #define CMD_SEL_INT9    0xDF | ||||
|   #define CMD_SEL_INT10   0xEF | ||||
|   #define CMD_SEL_INT11   0xFF | ||||
| 
 | ||||
|   #define DETECT_REQ      0x73 | ||||
|   #define DETECT_RESP     0x46 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										22
									
								
								Graphics.h
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								Graphics.h
									
									
									
									
									
								
							| @ -401,6 +401,13 @@ const unsigned char bm_n_uh [] PROGMEM = { | ||||
|    0xe7, 0xe7 | ||||
| }; | ||||
| 
 | ||||
| const unsigned char bm_dot_sqr [] PROGMEM = { | ||||
| 	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 | ||||
| // use 122px wide graphics
 | ||||
| 
 | ||||
| @ -1688,6 +1695,21 @@ const unsigned char bm_n_uh [] PROGMEM = { | ||||
| 	0xfc, 0x00, 0xfc, 0x00 // 9
 | ||||
| }; | ||||
| 
 | ||||
| const unsigned char bm_dot_sqr [] PROGMEM = { | ||||
| 	0xee, 0xee, 0xdd, 0xdd, 0xc0, 0xee, 0xee, 0xdd, 0xdd, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00,  | ||||
| 	0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00,  | ||||
| 	0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00,  | ||||
| 	0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,  | ||||
| 	0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,  | ||||
| 	0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0,  | ||||
| 	0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00,  | ||||
| 	0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,  | ||||
| 	0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,  | ||||
| 	0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0,  | ||||
| 	0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xee, 0xee, 0xdd, 0xdd, 0xc0, 0xee,  | ||||
| 	0xee, 0xdd, 0xdd, 0xc0 | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										7
									
								
								Interfaces.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Interfaces.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #define SX127X 0x00 | ||||
| #define SX1276 0x01 | ||||
| #define SX1278 0x02 | ||||
| #define SX126X 0x10 | ||||
| #define SX1262 0x11 | ||||
| #define SX128X 0x20 | ||||
| #define SX1280 0x21 | ||||
							
								
								
									
										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 | ||||
							
								
								
									
										513
									
								
								Utilities.h
									
									
									
									
									
								
							
							
						
						
									
										513
									
								
								Utilities.h
									
									
									
									
									
								
							| @ -13,8 +13,13 @@ | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| #include "Radio.h" | ||||
| #include "Config.h" | ||||
| 
 | ||||
| // Included for sorting
 | ||||
| #include <algorithm> | ||||
| #include <iterator> | ||||
| 
 | ||||
| #if HAS_EEPROM  | ||||
|     #include <EEPROM.h> | ||||
| #elif PLATFORM == PLATFORM_NRF52 | ||||
| @ -28,17 +33,6 @@ | ||||
| #endif | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| #if MODEM == SX1262 | ||||
| #include "sx126x.h" | ||||
| sx126x *LoRa = &sx126x_modem; | ||||
| #elif MODEM == SX1276 || MODEM == SX1278 | ||||
| #include "sx127x.h" | ||||
| sx127x *LoRa = &sx127x_modem; | ||||
| #elif MODEM == SX1280 | ||||
| #include "sx128x.h" | ||||
| sx128x *LoRa = &sx128x_modem; | ||||
| #endif | ||||
| 
 | ||||
| #include "ROM.h" | ||||
| #include "Framing.h" | ||||
| #include "MD5.h" | ||||
| @ -81,20 +75,9 @@ uint8_t eeprom_read(uint32_t mapped_addr); | ||||
|   #define ISR_VECT | ||||
| #endif | ||||
| 
 | ||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | ||||
| 	#include <avr/wdt.h> | ||||
| 	#include <util/atomic.h> | ||||
| #endif | ||||
| 
 | ||||
| uint8_t boot_vector = 0x00; | ||||
| 
 | ||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | ||||
| 	uint8_t OPTIBOOT_MCUSR __attribute__ ((section(".noinit"))); | ||||
| 	void resetFlagsInit(void) __attribute__ ((naked)) __attribute__ ((used)) __attribute__ ((section (".init0"))); | ||||
| 	void resetFlagsInit(void) { | ||||
| 	    __asm__ __volatile__ ("sts %0, r2\n" : "=m" (OPTIBOOT_MCUSR) :); | ||||
| 	} | ||||
| #elif MCU_VARIANT == MCU_ESP32 | ||||
| #if MCU_VARIANT == MCU_ESP32 | ||||
| 	// TODO: Get ESP32 boot flags
 | ||||
| #elif MCU_VARIANT == MCU_NRF52 | ||||
| 	// TODO: Get NRF52 boot flags
 | ||||
| @ -138,12 +121,7 @@ uint8_t boot_vector = 0x00; | ||||
|   void boot_seq() { } | ||||
| #endif | ||||
| 
 | ||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | ||||
| 	void led_rx_on()  { digitalWrite(pin_led_rx, HIGH); } | ||||
| 	void led_rx_off() {	digitalWrite(pin_led_rx, LOW); } | ||||
| 	void led_tx_on()  { digitalWrite(pin_led_tx, HIGH); } | ||||
| 	void led_tx_off() { digitalWrite(pin_led_tx, LOW); } | ||||
| #elif MCU_VARIANT == MCU_ESP32 | ||||
| #if MCU_VARIANT == MCU_ESP32 | ||||
| 	#if HAS_NP == true | ||||
| 		void led_rx_on()  { npset(0, 0, 0xFF); } | ||||
| 		void led_rx_off() {	npset(0, 0, 0); } | ||||
| @ -236,12 +214,7 @@ uint8_t boot_vector = 0x00; | ||||
| #endif | ||||
| 
 | ||||
| void hard_reset(void) { | ||||
| 	#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | ||||
| 		wdt_enable(WDTO_15MS); | ||||
| 		while(true) { | ||||
| 			led_tx_on(); led_rx_off(); | ||||
| 		} | ||||
| 	#elif MCU_VARIANT == MCU_ESP32 | ||||
| 	#if MCU_VARIANT == MCU_ESP32 | ||||
| 		ESP.restart(); | ||||
| 	#elif MCU_VARIANT == MCU_NRF52 | ||||
|         NVIC_SystemReset(); | ||||
| @ -332,20 +305,7 @@ void led_indicate_warning(int cycles) { | ||||
| } | ||||
| 
 | ||||
| // LED Indication: Info
 | ||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | ||||
| 	void led_indicate_info(int cycles) { | ||||
| 		bool forever = (cycles == 0) ? true : false; | ||||
| 		cycles = forever ? 1 : cycles; | ||||
| 		while(cycles > 0) { | ||||
| 	    led_rx_off(); | ||||
| 	    delay(100); | ||||
| 	    led_rx_on(); | ||||
| 	    delay(100); | ||||
| 	    if (!forever) cycles--; | ||||
| 	  } | ||||
| 	  led_rx_off(); | ||||
| 	} | ||||
| #elif MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||
| #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||
| 	#if HAS_NP == true | ||||
| 		void led_indicate_info(int cycles) { | ||||
| 			bool forever = (cycles == 0) ? true : false; | ||||
| @ -403,12 +363,7 @@ void led_indicate_warning(int cycles) { | ||||
| 
 | ||||
| 
 | ||||
| unsigned long led_standby_ticks = 0; | ||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | ||||
| 	uint8_t led_standby_min = 1; | ||||
| 	uint8_t led_standby_max = 40; | ||||
| 	unsigned long led_standby_wait = 11000; | ||||
| 
 | ||||
| #elif MCU_VARIANT == MCU_ESP32 | ||||
| #if MCU_VARIANT == MCU_ESP32 | ||||
| 
 | ||||
| 	#if HAS_NP == true | ||||
| 		int led_standby_lng = 100; | ||||
| @ -451,23 +406,7 @@ unsigned long led_standby_ticks = 0; | ||||
| unsigned long led_standby_value = led_standby_min; | ||||
| int8_t  led_standby_direction = 0; | ||||
| 
 | ||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | ||||
| 	void led_indicate_standby() { | ||||
| 		led_standby_ticks++; | ||||
| 		if (led_standby_ticks > led_standby_wait) { | ||||
| 			led_standby_ticks = 0; | ||||
| 			if (led_standby_value <= led_standby_min) { | ||||
| 				led_standby_direction = 1; | ||||
| 			} else if (led_standby_value >= led_standby_max) { | ||||
| 				led_standby_direction = -1; | ||||
| 			} | ||||
| 			led_standby_value += led_standby_direction; | ||||
| 			analogWrite(pin_led_rx, led_standby_value); | ||||
| 			led_tx_off(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| #elif MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||
| #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||
| 	#if HAS_NP == true | ||||
| 		void led_indicate_standby() { | ||||
| 			led_standby_ticks++; | ||||
| @ -560,22 +499,7 @@ int8_t  led_standby_direction = 0; | ||||
|   #endif | ||||
| #endif | ||||
| 
 | ||||
| #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | ||||
| 	void led_indicate_not_ready() { | ||||
| 		led_standby_ticks++; | ||||
| 		if (led_standby_ticks > led_standby_wait) { | ||||
| 			led_standby_ticks = 0; | ||||
| 			if (led_standby_value <= led_standby_min) { | ||||
| 				led_standby_direction = 1; | ||||
| 			} else if (led_standby_value >= led_standby_max) { | ||||
| 				led_standby_direction = -1; | ||||
| 			} | ||||
| 			led_standby_value += led_standby_direction; | ||||
| 			analogWrite(pin_led_tx, led_standby_value); | ||||
| 			led_rx_off(); | ||||
| 		} | ||||
| 	} | ||||
| #elif MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||
| #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||
| 	#if HAS_NP == true | ||||
|     void led_indicate_not_ready() { | ||||
|     	led_standby_ticks++; | ||||
| @ -636,6 +560,18 @@ int8_t  led_standby_direction = 0; | ||||
| 	#endif | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| bool interface_bitrate_cmp(RadioInterface* p, RadioInterface* q) { | ||||
|     long p_bitrate = p->getBitrate(); | ||||
|     long q_bitrate = q->getBitrate(); | ||||
|     return p_bitrate > q_bitrate; | ||||
| } | ||||
| 
 | ||||
| // Sort interfaces in descending order according to bitrate.
 | ||||
| void sort_interfaces() { | ||||
|     std::sort(std::begin(interface_obj_sorted), std::end(interface_obj_sorted), interface_bitrate_cmp); | ||||
| } | ||||
| 
 | ||||
| void serial_write(uint8_t byte) { | ||||
| 	#if HAS_BLUETOOTH || HAS_BLE == true | ||||
| 		if (bt_state != BT_STATE_CONNECTED) { | ||||
| @ -668,31 +604,33 @@ void kiss_indicate_error(uint8_t error_code) { | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_radiostate() { | ||||
| void kiss_indicate_radiostate(RadioInterface* radio) { | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_RADIO_STATE); | ||||
| 	serial_write(radio_online); | ||||
| 	serial_write(radio->getRadioOnline()); | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_stat_rx() { | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_STAT_RX); | ||||
| 	escaped_serial_write(stat_rx>>24); | ||||
| 	escaped_serial_write(stat_rx>>16); | ||||
| 	escaped_serial_write(stat_rx>>8); | ||||
| 	escaped_serial_write(stat_rx); | ||||
| 	serial_write(FEND); | ||||
|     // todo, implement
 | ||||
| 	//serial_write(FEND);
 | ||||
| 	//serial_write(CMD_STAT_RX);
 | ||||
| 	//escaped_serial_write(stat_rx>>24);
 | ||||
| 	//escaped_serial_write(stat_rx>>16);
 | ||||
| 	//escaped_serial_write(stat_rx>>8);
 | ||||
| 	//escaped_serial_write(stat_rx);
 | ||||
| 	//serial_write(FEND);
 | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_stat_tx() { | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_STAT_TX); | ||||
| 	escaped_serial_write(stat_tx>>24); | ||||
| 	escaped_serial_write(stat_tx>>16); | ||||
| 	escaped_serial_write(stat_tx>>8); | ||||
| 	escaped_serial_write(stat_tx); | ||||
| 	serial_write(FEND); | ||||
|     // todo, implement
 | ||||
| 	//serial_write(FEND);
 | ||||
| 	//serial_write(CMD_STAT_TX);
 | ||||
| 	//escaped_serial_write(stat_tx>>24);
 | ||||
| 	//escaped_serial_write(stat_tx>>16);
 | ||||
| 	//escaped_serial_write(stat_tx>>8);
 | ||||
| 	//escaped_serial_write(stat_tx);
 | ||||
| 	//serial_write(FEND);
 | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_stat_rssi() { | ||||
| @ -710,24 +648,24 @@ void kiss_indicate_stat_snr() { | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_radio_lock() { | ||||
| void kiss_indicate_radio_lock(RadioInterface* radio) { | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_RADIO_LOCK); | ||||
| 	serial_write(radio_locked); | ||||
| 	serial_write(radio->getRadioLock()); | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_spreadingfactor() { | ||||
| void kiss_indicate_spreadingfactor(RadioInterface* radio) { | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_SF); | ||||
| 	serial_write((uint8_t)lora_sf); | ||||
| 	serial_write(radio->getSpreadingFactor()); | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_codingrate() { | ||||
| void kiss_indicate_codingrate(RadioInterface* radio) { | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_CR); | ||||
| 	serial_write((uint8_t)lora_cr); | ||||
| 	serial_write(radio->getCodingRate4()); | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| @ -738,35 +676,47 @@ void kiss_indicate_implicit_length() { | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_txpower() { | ||||
| void kiss_indicate_txpower(RadioInterface* radio) { | ||||
|     uint8_t txp = radio->getTxPower(); | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_TXPOWER); | ||||
| 	serial_write((uint8_t)lora_txp); | ||||
| 	serial_write(txp); | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_bandwidth() { | ||||
| void kiss_indicate_bandwidth(RadioInterface* radio) { | ||||
|     uint32_t bw = radio->getSignalBandwidth(); | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_BANDWIDTH); | ||||
| 	escaped_serial_write(lora_bw>>24); | ||||
| 	escaped_serial_write(lora_bw>>16); | ||||
| 	escaped_serial_write(lora_bw>>8); | ||||
| 	escaped_serial_write(lora_bw); | ||||
| 	escaped_serial_write(bw>>24); | ||||
| 	escaped_serial_write(bw>>16); | ||||
| 	escaped_serial_write(bw>>8); | ||||
| 	escaped_serial_write(bw); | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_frequency() { | ||||
| void kiss_indicate_frequency(RadioInterface* radio) { | ||||
|     uint32_t freq = radio->getFrequency(); | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_FREQUENCY); | ||||
| 	escaped_serial_write(lora_freq>>24); | ||||
| 	escaped_serial_write(lora_freq>>16); | ||||
| 	escaped_serial_write(lora_freq>>8); | ||||
| 	escaped_serial_write(lora_freq); | ||||
| 	escaped_serial_write(freq>>24); | ||||
| 	escaped_serial_write(freq>>16); | ||||
| 	escaped_serial_write(freq>>8); | ||||
| 	escaped_serial_write(freq); | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_st_alock() { | ||||
| 	uint16_t at = (uint16_t)(st_airtime_limit*100*100); | ||||
| void kiss_indicate_interface(int index) { | ||||
|     serial_write(FEND); | ||||
|     serial_write(CMD_INTERFACES); | ||||
|     // print the index to the interface and the interface type
 | ||||
|     serial_write(index); | ||||
|     serial_write(interfaces[index]); | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_st_alock(RadioInterface* radio) { | ||||
| 	uint16_t at = (uint16_t)(radio->getSTALock()*100*100); | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_ST_ALOCK); | ||||
| 	escaped_serial_write(at>>8); | ||||
| @ -774,8 +724,8 @@ void kiss_indicate_st_alock() { | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_lt_alock() { | ||||
| 	uint16_t at = (uint16_t)(lt_airtime_limit*100*100); | ||||
| void kiss_indicate_lt_alock(RadioInterface* radio) { | ||||
| 	uint16_t at = (uint16_t)(radio->getLTALock()*100*100); | ||||
| 	serial_write(FEND); | ||||
| 	serial_write(CMD_LT_ALOCK); | ||||
| 	escaped_serial_write(at>>8); | ||||
| @ -783,12 +733,11 @@ void kiss_indicate_lt_alock() { | ||||
| 	serial_write(FEND); | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_channel_stats() { | ||||
| 	#if MCU_VARIANT == MCU_ESP32 | ||||
| 		uint16_t ats = (uint16_t)(airtime*100*100); | ||||
| 		uint16_t atl = (uint16_t)(longterm_airtime*100*100); | ||||
| 		uint16_t cls = (uint16_t)(total_channel_util*100*100); | ||||
| 		uint16_t cll = (uint16_t)(longterm_channel_util*100*100); | ||||
| void kiss_indicate_channel_stats(RadioInterface* radio) { | ||||
|     uint16_t ats = (uint16_t)(radio->getAirtime()*100*100); | ||||
|     uint16_t atl = (uint16_t)(radio->getLongtermAirtime()*100*100); | ||||
|     uint16_t cls = (uint16_t)(radio->getTotalChannelUtil()*100*100); | ||||
|     uint16_t cll = (uint16_t)(radio->getLongtermChannelUtil()*100*100); | ||||
|     serial_write(FEND); | ||||
|     serial_write(CMD_STAT_CHTM); | ||||
|     escaped_serial_write(ats>>8); | ||||
| @ -800,16 +749,14 @@ void kiss_indicate_channel_stats() { | ||||
|     escaped_serial_write(cll>>8); | ||||
|     escaped_serial_write(cll); | ||||
|     serial_write(FEND); | ||||
| 	#endif | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_phy_stats() { | ||||
| 	#if MCU_VARIANT == MCU_ESP32 | ||||
| 		uint16_t lst = (uint16_t)(lora_symbol_time_ms*1000); | ||||
| 		uint16_t lsr = (uint16_t)(lora_symbol_rate); | ||||
| 		uint16_t prs = (uint16_t)(lora_preamble_symbols+4); | ||||
| 		uint16_t prt = (uint16_t)((lora_preamble_symbols+4)*lora_symbol_time_ms); | ||||
| 		uint16_t cst = (uint16_t)(csma_slot_ms); | ||||
| void kiss_indicate_phy_stats(RadioInterface* radio) { | ||||
|     uint16_t lst = (uint16_t)(radio->getSymbolTime()*1000); | ||||
|     uint16_t lsr = (uint16_t)(radio->getSymbolRate()); | ||||
|     uint16_t prs = (uint16_t)(radio->getPreambleLength()+4); | ||||
|     uint16_t prt = (uint16_t)((radio->getPreambleLength()+4)*radio->getSymbolTime()); | ||||
|     uint16_t cst = (uint16_t)(radio->getCSMASlotMS()); | ||||
|     serial_write(FEND); | ||||
|     serial_write(CMD_STAT_PHYPRM); | ||||
|     escaped_serial_write(lst>>8); | ||||
| @ -823,7 +770,6 @@ void kiss_indicate_phy_stats() { | ||||
|     escaped_serial_write(cst>>8); | ||||
|     escaped_serial_write(cst); | ||||
|     serial_write(FEND); | ||||
| 	#endif | ||||
| } | ||||
| 
 | ||||
| void kiss_indicate_battery() { | ||||
| @ -1009,43 +955,6 @@ inline uint8_t packetSequence(uint8_t header) { | ||||
| 	return header >> 4; | ||||
| } | ||||
| 
 | ||||
| void setPreamble() { | ||||
| 	if (radio_online) LoRa->setPreambleLength(lora_preamble_symbols); | ||||
| 	kiss_indicate_phy_stats(); | ||||
| } | ||||
| 
 | ||||
| void updateBitrate() { | ||||
| 	#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 | ||||
| 		if (radio_online) { | ||||
| 			lora_symbol_rate = (float)lora_bw/(float)(pow(2, lora_sf)); | ||||
| 			lora_symbol_time_ms = (1.0/lora_symbol_rate)*1000.0; | ||||
| 			lora_bitrate = (uint32_t)(lora_sf * ( (4.0/(float)lora_cr) / ((float)(pow(2, lora_sf))/((float)lora_bw/1000.0)) ) * 1000.0); | ||||
| 			lora_us_per_byte = 1000000.0/((float)lora_bitrate/8.0); | ||||
| 			// csma_slot_ms = lora_symbol_time_ms*10;
 | ||||
| 			float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; | ||||
| 			if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { | ||||
| 				target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; | ||||
| 			} else { | ||||
| 				target_preamble_symbols = ceil(target_preamble_symbols); | ||||
| 			} | ||||
| 			lora_preamble_symbols = (long)target_preamble_symbols; | ||||
| 			setPreamble(); | ||||
| 		} else { | ||||
| 			lora_bitrate = 0; | ||||
| 		} | ||||
| 	#endif | ||||
| } | ||||
| 
 | ||||
| void setSpreadingFactor() { | ||||
| 	if (radio_online) LoRa->setSpreadingFactor(lora_sf); | ||||
| 	updateBitrate(); | ||||
| } | ||||
| 
 | ||||
| void setCodingRate() { | ||||
| 	if (radio_online) LoRa->setCodingRate4(lora_cr); | ||||
| 	updateBitrate(); | ||||
| } | ||||
| 
 | ||||
| void set_implicit_length(uint8_t len) { | ||||
| 	implicit_l = len; | ||||
| 	if (implicit_l != 0) { | ||||
| @ -1055,76 +964,118 @@ void set_implicit_length(uint8_t len) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int getTxPower() { | ||||
| 	uint8_t txp = LoRa->getTxPower(); | ||||
| 	return (int)txp; | ||||
| void setTXPower(RadioInterface* radio, int txp) { | ||||
|     if (model == MODEL_11) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); | ||||
|     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() { | ||||
| 	if (radio_online) { | ||||
| 		if (model == MODEL_A1) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_A2) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_A3) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN); | ||||
| 		if (model == MODEL_A4) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN); | ||||
| 		if (model == MODEL_A6) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_A7) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_A8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_A9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 
 | ||||
| 		if (model == MODEL_B3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_B4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_B8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_B9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 
 | ||||
| 		if (model == MODEL_C4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_C9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 
 | ||||
| 		if (model == MODEL_E4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_E9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_E3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_E8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 
 | ||||
| 		if (model == MODEL_FE) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); | ||||
| 		if (model == MODEL_FF) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void getBandwidth() { | ||||
| 	if (radio_online) { | ||||
| 			lora_bw = LoRa->getSignalBandwidth(); | ||||
| 	} | ||||
| 	updateBitrate(); | ||||
| } | ||||
| 
 | ||||
| void setBandwidth() { | ||||
| 	if (radio_online) { | ||||
| 		LoRa->setSignalBandwidth(lora_bw); | ||||
| 		getBandwidth(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void getFrequency() { | ||||
| 	if (radio_online) { | ||||
| 		lora_freq = LoRa->getFrequency(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void setFrequency() { | ||||
| 	if (radio_online) { | ||||
| 		LoRa->setFrequency(lora_freq); | ||||
| 		getFrequency(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| uint8_t getRandom() { | ||||
| 	if (radio_online) { | ||||
| 		return LoRa->random(); | ||||
| uint8_t getRandom(RadioInterface* radio) { | ||||
| 	if (radio->getRadioOnline()) { | ||||
| 		return radio->random(); | ||||
| 	} else { | ||||
| 		return 0x00; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| uint8_t getInterfaceIndex(uint8_t byte) { | ||||
|     switch (byte) { | ||||
|         case CMD_INT0_DATA: | ||||
|         case CMD_SEL_INT0: | ||||
|             return 0; | ||||
|         case CMD_INT1_DATA: | ||||
|         case CMD_SEL_INT1: | ||||
|             return 1; | ||||
|         case CMD_INT2_DATA: | ||||
|         case CMD_SEL_INT2: | ||||
|             return 2; | ||||
|         case CMD_INT3_DATA: | ||||
|         case CMD_SEL_INT3: | ||||
|             return 3; | ||||
|         case CMD_INT4_DATA: | ||||
|         case CMD_SEL_INT4: | ||||
|             return 4; | ||||
|         case CMD_INT5_DATA: | ||||
|         case CMD_SEL_INT5: | ||||
|             return 5; | ||||
|         case CMD_INT6_DATA: | ||||
|         case CMD_SEL_INT6: | ||||
|             return 6; | ||||
|         case CMD_INT7_DATA: | ||||
|         case CMD_SEL_INT7: | ||||
|             return 7; | ||||
|         case CMD_INT8_DATA: | ||||
|         case CMD_SEL_INT8: | ||||
|             return 8; | ||||
|         case CMD_INT9_DATA: | ||||
|         case CMD_SEL_INT9: | ||||
|             return 9; | ||||
|         case CMD_INT10_DATA: | ||||
|         case CMD_SEL_INT10: | ||||
|             return 10; | ||||
|         case CMD_INT11_DATA: | ||||
|         case CMD_SEL_INT11: | ||||
|             return 11; | ||||
|         default: | ||||
|             return 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint8_t getInterfaceCommandByte(uint8_t index) { | ||||
|     switch (index) { | ||||
|         case 0: | ||||
|             return CMD_INT0_DATA; | ||||
|         case 1: | ||||
|             return CMD_INT1_DATA; | ||||
|         case 2: | ||||
|             return CMD_INT2_DATA; | ||||
|         case 3: | ||||
|             return CMD_INT3_DATA; | ||||
|         case 4: | ||||
|             return CMD_INT4_DATA; | ||||
|         case 5: | ||||
|             return CMD_INT5_DATA; | ||||
|         case 6: | ||||
|             return CMD_INT6_DATA; | ||||
|         case 7: | ||||
|             return CMD_INT7_DATA; | ||||
|         case 8: | ||||
|             return CMD_INT8_DATA; | ||||
|         case 9: | ||||
|             return CMD_INT9_DATA; | ||||
|         case 10: | ||||
|             return CMD_INT10_DATA; | ||||
|         case 11: | ||||
|             return CMD_INT11_DATA; | ||||
|         default: | ||||
|             return 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void promisc_enable() { | ||||
| 	promisc = true; | ||||
| } | ||||
| @ -1228,9 +1179,7 @@ void eeprom_flush() { | ||||
| #endif | ||||
| 
 | ||||
| void eeprom_update(int mapped_addr, uint8_t byte) { | ||||
| 	#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 | ||||
| 		EEPROM.update(mapped_addr, byte); | ||||
| 	#elif MCU_VARIANT == MCU_ESP32 | ||||
| 	#if MCU_VARIANT == MCU_ESP32 | ||||
| 		if (EEPROM.read(mapped_addr) != byte) { | ||||
| 			EEPROM.write(mapped_addr, byte); | ||||
| 			EEPROM.commit(); | ||||
| @ -1297,9 +1246,7 @@ bool eeprom_product_valid() { | ||||
| 	    uint8_t rval = eeprom_read(eeprom_addr(ADDR_PRODUCT)); | ||||
|     #endif | ||||
| 
 | ||||
| 	#if PLATFORM == PLATFORM_AVR | ||||
| 	if (rval == PRODUCT_RNODE || rval == PRODUCT_HMBRW) { | ||||
| 	#elif PLATFORM == PLATFORM_ESP32 | ||||
| 	#if PLATFORM == PLATFORM_ESP32 | ||||
| 	if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3) { | ||||
| 	#elif PLATFORM == PLATFORM_NRF52 | ||||
| 	if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW) { | ||||
| @ -1434,39 +1381,51 @@ bool eeprom_have_conf() { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void eeprom_conf_load() { | ||||
| void eeprom_conf_load(RadioInterface* radio) { | ||||
| 	if (eeprom_have_conf()) { | ||||
|         if (!(radio->getRadioOnline())) { | ||||
|         #if HAS_EEPROM | ||||
|             lora_sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF)); | ||||
|             lora_cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR)); | ||||
|             lora_txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP)); | ||||
|             lora_freq = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x03); | ||||
|             lora_bw = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x03); | ||||
|             uint8_t sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF)); | ||||
|             uint8_t cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR)); | ||||
|             uint8_t txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP)); | ||||
|             uint32_t freq = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x03); | ||||
|             uint32_t bw = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x03); | ||||
|         #elif MCU_VARIANT == MCU_NRF52 | ||||
|             lora_sf = eeprom_read(eeprom_addr(ADDR_CONF_SF)); | ||||
|             lora_cr = eeprom_read(eeprom_addr(ADDR_CONF_CR)); | ||||
|             lora_txp = eeprom_read(eeprom_addr(ADDR_CONF_TXP)); | ||||
|             lora_freq = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x03); | ||||
|             lora_bw = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x03); | ||||
|             uint8_t sf = eeprom_read(eeprom_addr(ADDR_CONF_SF)); | ||||
|             uint8_t cr = eeprom_read(eeprom_addr(ADDR_CONF_CR)); | ||||
|             uint8_t txp = eeprom_read(eeprom_addr(ADDR_CONF_TXP)); | ||||
|             uint32_t freq = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x03); | ||||
|             uint32_t bw = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x03); | ||||
|         #endif | ||||
|             radio->setSpreadingFactor(sf); | ||||
|             radio->setCodingRate4(cr); | ||||
|             setTXPower(radio, txp); | ||||
|             radio->setFrequency(freq); | ||||
|             radio->setSignalBandwidth(bw); | ||||
|             radio->updateBitrate(); | ||||
|         } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void eeprom_conf_save() { | ||||
| 	if (hw_ready && radio_online) { | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_SF), lora_sf); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_CR), lora_cr); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_TXP), lora_txp); | ||||
| void eeprom_conf_save(RadioInterface* radio) { | ||||
| 	if (hw_ready && radio->getRadioOnline()) { | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_SF), radio->getSpreadingFactor()); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_CR), radio->getCodingRate4()); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_TXP), radio->getTxPower()); | ||||
| 
 | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, lora_bw>>24); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x01, lora_bw>>16); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x02, lora_bw>>8); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x03, lora_bw); | ||||
|         uint32_t bw = radio->getSignalBandwidth(); | ||||
| 
 | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x00, lora_freq>>24); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x01, lora_freq>>16); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x02, lora_freq>>8); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x03, lora_freq); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, bw>>24); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x01, bw>>16); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x02, bw>>8); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x03, bw); | ||||
| 
 | ||||
|         uint32_t freq = radio->getFrequency(); | ||||
| 
 | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x00, freq>>24); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x01, freq>>16); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x02, freq>>8); | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x03, freq); | ||||
| 
 | ||||
| 		eeprom_update(eeprom_addr(ADDR_CONF_OK), CONF_OK_BYTE); | ||||
| 		led_indicate_info(10); | ||||
| @ -1484,18 +1443,6 @@ void unlock_rom() { | ||||
| 	eeprom_erase(); | ||||
| } | ||||
| 
 | ||||
| void init_channel_stats() { | ||||
| 	#if MCU_VARIANT == MCU_ESP32 | ||||
| 		for (uint16_t ai = 0; ai < DCD_SAMPLES; ai++) { util_samples[ai] = false; } | ||||
| 		for (uint16_t ai = 0; ai < AIRTIME_BINS; ai++) { airtime_bins[ai] = 0; } | ||||
| 		for (uint16_t ai = 0; ai < AIRTIME_BINS; ai++) { longterm_bins[ai] = 0.0; } | ||||
| 		local_channel_util = 0.0; | ||||
| 		total_channel_util = 0.0; | ||||
| 		airtime = 0.0; | ||||
| 		longterm_airtime = 0.0; | ||||
| 	#endif | ||||
| } | ||||
| 
 | ||||
| typedef struct FIFOBuffer | ||||
| { | ||||
|   unsigned char *begin; | ||||
|  | ||||
							
								
								
									
										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