2024-10-12 18:04:19 +01:00
// Copyright (C) 2024, Mark Qvist
2023-01-14 00:11:02 +01:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2018-12-01 19:31:51 +01:00
# include <Arduino.h>
2018-04-05 18:10:42 +02:00
# include <SPI.h>
2019-01-01 15:52:48 +01:00
# include "Utilities.h"
2018-04-05 18:10:42 +02:00
2024-09-12 10:57:16 -04:00
# if MCU_VARIANT == MCU_NRF52
# define INTERFACE_SPI
2024-10-16 21:24:18 +01:00
# if BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL
2024-08-06 17:37:47 +01:00
// Required because on RAK4631, non-default SPI pins must be initialised when class is declared.
SPIClass interface_spi [ 1 ] = {
// SX1262
SPIClass (
NRF_SPIM2 ,
interface_pins [ 0 ] [ 3 ] ,
interface_pins [ 0 ] [ 1 ] ,
interface_pins [ 0 ] [ 2 ]
)
} ;
2024-09-12 10:57:16 -04:00
# elif BOARD_MODEL == BOARD_TECHO
SPIClass interface_spi [ 1 ] = {
// SX1262
SPIClass (
NRF_SPIM3 ,
interface_pins [ 0 ] [ 3 ] ,
interface_pins [ 0 ] [ 1 ] ,
interface_pins [ 0 ] [ 2 ]
)
} ;
# endif
2024-08-06 17:37:47 +01:00
# endif
# ifndef INTERFACE_SPI
// INTERFACE_SPI is only required on NRF52 platforms, as the SPI pins are set in the class constructor and not by a setter method.
// Even if custom SPI interfaces are not needed, the array must exist to prevent compilation errors.
# define INTERFACE_SPI
SPIClass interface_spi [ 1 ] ;
2024-07-04 13:57:51 +01:00
# endif
2020-05-28 22:18:19 +02:00
FIFOBuffer serialFIFO ;
2020-06-01 12:43:59 +02:00
uint8_t serialBuffer [ CONFIG_UART_BUFFER_SIZE + 1 ] ;
2020-05-28 22:18:19 +02:00
2024-07-03 11:06:52 +01:00
uint16_t packet_starts_buf [ ( CONFIG_QUEUE_MAX_LENGTH ) + 1 ] ;
2020-05-28 22:18:19 +02:00
2024-07-03 11:06:52 +01:00
uint16_t packet_lengths_buf [ ( CONFIG_QUEUE_MAX_LENGTH ) + 1 ] ;
2020-05-28 22:18:19 +02:00
2024-06-10 13:05:21 +01:00
FIFOBuffer16 packet_starts [ INTERFACE_COUNT ] ;
FIFOBuffer16 packet_lengths [ INTERFACE_COUNT ] ;
2020-05-28 22:18:19 +02:00
2024-06-10 13:05:21 +01:00
volatile uint8_t queue_height [ INTERFACE_COUNT ] = { 0 } ;
volatile uint16_t queued_bytes [ INTERFACE_COUNT ] = { 0 } ;
volatile uint16_t queue_cursor [ INTERFACE_COUNT ] = { 0 } ;
volatile uint16_t current_packet_start [ INTERFACE_COUNT ] = { 0 } ;
2020-05-29 14:58:10 +02:00
volatile bool serial_buffering = false ;
2024-04-23 00:52:57 +02:00
# if HAS_BLUETOOTH || HAS_BLE == true
2022-10-30 14:52:22 +01:00
bool bt_init_ran = false ;
# endif
2020-05-29 14:58:10 +02:00
2023-01-06 22:29:23 +01:00
# if HAS_CONSOLE
# include "Console.h"
# endif
2024-10-12 18:04:19 +01:00
# define MODEM_QUEUE_SIZE 4*INTERFACE_COUNT
typedef struct {
size_t len ;
int rssi ;
int snr_raw ;
uint8_t interface ;
2024-10-15 17:34:16 +01:00
uint8_t data [ ] ;
2024-10-12 18:04:19 +01:00
} modem_packet_t ;
static xQueueHandle modem_packet_queue = NULL ;
2020-05-29 14:58:10 +02:00
char sbuf [ 128 ] ;
2020-05-28 22:18:19 +02:00
2024-07-03 11:06:52 +01:00
uint8_t * packet_queue [ INTERFACE_COUNT ] ;
2022-01-10 22:14:30 +01:00
2018-04-05 18:10:42 +02:00
void setup ( ) {
2022-01-09 23:40:30 +01:00
# if MCU_VARIANT == MCU_ESP32
2022-11-02 19:02:22 +01:00
boot_seq ( ) ;
2022-01-09 23:40:30 +01:00
EEPROM . begin ( EEPROM_SIZE ) ;
2022-01-11 02:54:32 +01:00
Serial . setRxBufferSize ( CONFIG_UART_BUFFER_SIZE ) ;
2024-10-12 18:04:19 +01:00
# if BOARD_MODEL == BOARD_TDECK
pinMode ( pin_poweron , OUTPUT ) ;
digitalWrite ( pin_poweron , HIGH ) ;
pinMode ( SD_CS , OUTPUT ) ;
pinMode ( DISPLAY_CS , OUTPUT ) ;
digitalWrite ( SD_CS , HIGH ) ;
digitalWrite ( DISPLAY_CS , HIGH ) ;
pinMode ( DISPLAY_BL_PIN , OUTPUT ) ;
# endif
2022-01-09 23:40:30 +01:00
2025-02-03 17:25:02 +00:00
# elif MCU_VARIANT == MCU_NRF52
2025-01-15 18:38:14 +01:00
# if BOARD_MODEL == BOARD_TECHO
2025-01-15 21:20:43 +01:00
delay ( 200 ) ;
2025-01-15 18:38:14 +01:00
pinMode ( PIN_VEXT_EN , OUTPUT ) ;
digitalWrite ( PIN_VEXT_EN , HIGH ) ;
2025-01-15 21:20:43 +01:00
pinMode ( pin_btn_usr1 , INPUT_PULLUP ) ;
pinMode ( pin_btn_touch , INPUT_PULLUP ) ;
pinMode ( PIN_LED_RED , OUTPUT ) ;
pinMode ( PIN_LED_GREEN , OUTPUT ) ;
pinMode ( PIN_LED_BLUE , OUTPUT ) ;
delay ( 200 ) ;
2025-01-15 18:38:14 +01:00
# endif
2025-01-15 21:20:43 +01:00
if ( ! eeprom_begin ( ) ) { Serial . write ( " EEPROM initialisation failed. \r \n " ) ; }
2024-01-21 15:12:20 +00:00
# endif
2024-03-30 15:11:24 +01:00
// Seed the PRNG for CSMA R-value selection
# if MCU_VARIANT == MCU_ESP32
// On ESP32, get the seed value from the
// hardware RNG
int seed_val = ( int ) esp_random ( ) ;
# else
// Otherwise, get a pseudo-random seed
// value from an unconnected analog pin
int seed_val = analogRead ( 0 ) ;
# endif
randomSeed ( seed_val ) ;
2018-04-05 18:10:42 +02:00
// Initialise serial communication
2020-05-28 22:18:19 +02:00
memset ( serialBuffer , 0 , sizeof ( serialBuffer ) ) ;
2020-06-01 12:43:59 +02:00
fifo_init ( & serialFIFO , serialBuffer , CONFIG_UART_BUFFER_SIZE ) ;
2020-05-28 22:18:19 +02:00
2018-04-05 18:10:42 +02:00
Serial . begin ( serial_baudrate ) ;
2024-05-18 10:26:10 +02:00
2024-10-12 18:04:19 +01:00
# if HAS_NP
led_init ( ) ;
# endif
2025-02-03 17:25:02 +00:00
# if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_OPENCOM_XL
2024-05-13 22:25:24 +01:00
// Some boards need to wait until the hardware UART is set up before booting
2024-10-11 19:58:36 +01:00
// the full firmware. In the case of the RAK4631/TECHO, the line below will wait
2024-05-13 22:25:24 +01:00
// until a serial connection is actually established with a master. Thus, it
// is disabled on this platform.
2024-05-18 01:07:38 +02:00
while ( ! Serial ) ;
2024-05-13 22:25:24 +01:00
# endif
2018-04-05 18:10:42 +02:00
// Configure input and output pins
2024-05-02 01:20:33 +02:00
# if HAS_INPUT
input_init ( ) ;
# endif
2022-12-04 20:00:21 +01:00
# if HAS_NP == false
pinMode ( pin_led_rx , OUTPUT ) ;
pinMode ( pin_led_tx , OUTPUT ) ;
# endif
2018-04-05 18:10:42 +02:00
2024-06-10 13:05:21 +01:00
for ( int i = 0 ; i < INTERFACE_COUNT ; i + + ) {
if ( interface_pins [ i ] [ 9 ] ! = - 1 ) {
pinMode ( interface_pins [ i ] [ 9 ] , OUTPUT ) ;
digitalWrite ( interface_pins [ i ] [ 9 ] , HIGH ) ;
2024-01-21 14:23:28 +00:00
}
2024-06-10 13:05:21 +01:00
}
2024-01-19 00:10:24 +01:00
2018-06-27 10:22:44 +02:00
// Initialise buffers
2018-04-05 18:10:42 +02:00
memset ( pbuf , 0 , sizeof ( pbuf ) ) ;
2022-11-01 21:11:41 +01:00
memset ( cmdbuf , 0 , sizeof ( cmdbuf ) ) ;
2018-06-27 10:22:44 +02:00
2020-06-01 12:43:59 +02:00
memset ( packet_starts_buf , 0 , sizeof ( packet_starts_buf ) ) ;
memset ( packet_lengths_buf , 0 , sizeof ( packet_starts_buf ) ) ;
2024-06-10 13:05:21 +01:00
2024-10-12 18:04:19 +01:00
memset ( seq , 0xFF , sizeof ( seq ) ) ;
2024-10-22 18:02:46 +01:00
memset ( read_len , 0 , sizeof ( read_len ) ) ;
2024-10-12 18:04:19 +01:00
modem_packet_queue = xQueueCreate ( MODEM_QUEUE_SIZE , sizeof ( modem_packet_t * ) ) ;
2024-06-10 13:05:21 +01:00
for ( int i = 0 ; i < INTERFACE_COUNT ; i + + ) {
2024-09-10 22:39:49 +01:00
fifo16_init ( & packet_starts [ i ] , packet_starts_buf , CONFIG_QUEUE_MAX_LENGTH + 1 ) ;
fifo16_init ( & packet_lengths [ i ] , packet_lengths_buf , CONFIG_QUEUE_MAX_LENGTH + 1 ) ;
2024-08-21 17:54:38 +01:00
packet_queue [ i ] = ( uint8_t * ) malloc ( getQueueSize ( i ) + 1 ) ;
2024-06-10 13:05:21 +01:00
}
2024-09-04 17:37:09 +01:00
memset ( packet_rdy_interfaces_buf , 0 , sizeof ( packet_rdy_interfaces_buf ) ) ;
fifo_init ( & packet_rdy_interfaces , packet_rdy_interfaces_buf , MAX_INTERFACES ) ;
2024-10-12 18:04:19 +01:00
// add call to init_channel_stats here? \todo
2024-06-10 13:05:21 +01:00
// Create and configure interface objects
for ( uint8_t i = 0 ; i < INTERFACE_COUNT ; i + + ) {
switch ( interfaces [ i ] ) {
case SX1262 :
{
sx126x * obj ;
// if default spi enabled
if ( interface_cfg [ i ] [ 0 ] ) {
2024-08-06 17:37:47 +01:00
obj = new sx126x ( i , & SPI , interface_cfg [ i ] [ 1 ] ,
2024-06-10 13:05:21 +01:00
interface_cfg [ i ] [ 2 ] , interface_pins [ i ] [ 0 ] , interface_pins [ i ] [ 1 ] ,
interface_pins [ i ] [ 2 ] , interface_pins [ i ] [ 3 ] , interface_pins [ i ] [ 6 ] ,
interface_pins [ i ] [ 5 ] , interface_pins [ i ] [ 4 ] , interface_pins [ i ] [ 8 ] ) ;
}
else {
2024-08-06 17:37:47 +01:00
obj = new sx126x ( i , & interface_spi [ i ] , interface_cfg [ i ] [ 1 ] ,
2024-06-10 13:05:21 +01:00
interface_cfg [ i ] [ 2 ] , interface_pins [ i ] [ 0 ] , interface_pins [ i ] [ 1 ] ,
interface_pins [ i ] [ 2 ] , interface_pins [ i ] [ 3 ] , interface_pins [ i ] [ 6 ] ,
interface_pins [ i ] [ 5 ] , interface_pins [ i ] [ 4 ] , interface_pins [ i ] [ 8 ] ) ;
}
interface_obj [ i ] = obj ;
interface_obj_sorted [ i ] = obj ;
break ;
2023-02-18 12:14:15 +01:00
}
2024-06-10 13:05:21 +01:00
case SX1276 :
case SX1278 :
{
sx127x * obj ;
// if default spi enabled
if ( interface_cfg [ i ] [ 0 ] ) {
2024-08-06 17:37:47 +01:00
obj = new sx127x ( i , & SPI , interface_pins [ i ] [ 0 ] ,
2024-06-10 13:05:21 +01:00
interface_pins [ i ] [ 1 ] , interface_pins [ i ] [ 2 ] , interface_pins [ i ] [ 3 ] ,
interface_pins [ i ] [ 6 ] , interface_pins [ i ] [ 5 ] , interface_pins [ i ] [ 4 ] ) ;
}
else {
2024-08-06 17:37:47 +01:00
obj = new sx127x ( i , & interface_spi [ i ] , interface_pins [ i ] [ 0 ] ,
2024-06-10 13:05:21 +01:00
interface_pins [ i ] [ 1 ] , interface_pins [ i ] [ 2 ] , interface_pins [ i ] [ 3 ] ,
interface_pins [ i ] [ 6 ] , interface_pins [ i ] [ 5 ] , interface_pins [ i ] [ 4 ] ) ;
}
interface_obj [ i ] = obj ;
interface_obj_sorted [ i ] = obj ;
break ;
}
case SX1280 :
{
sx128x * obj ;
// if default spi enabled
if ( interface_cfg [ i ] [ 0 ] ) {
2024-08-06 17:37:47 +01:00
obj = new sx128x ( i , & SPI , interface_cfg [ i ] [ 1 ] ,
2024-06-10 13:05:21 +01:00
interface_pins [ i ] [ 0 ] , interface_pins [ i ] [ 1 ] , interface_pins [ i ] [ 2 ] ,
interface_pins [ i ] [ 3 ] , interface_pins [ i ] [ 6 ] , interface_pins [ i ] [ 5 ] ,
interface_pins [ i ] [ 4 ] , interface_pins [ i ] [ 8 ] , interface_pins [ i ] [ 7 ] ) ;
}
else {
2024-08-06 17:37:47 +01:00
obj = new sx128x ( i , & interface_spi [ i ] , interface_cfg [ i ] [ 1 ] ,
2024-06-10 13:05:21 +01:00
interface_pins [ i ] [ 0 ] , interface_pins [ i ] [ 1 ] , interface_pins [ i ] [ 2 ] ,
interface_pins [ i ] [ 3 ] , interface_pins [ i ] [ 6 ] , interface_pins [ i ] [ 5 ] ,
interface_pins [ i ] [ 4 ] , interface_pins [ i ] [ 8 ] , interface_pins [ i ] [ 7 ] ) ;
}
interface_obj [ i ] = obj ;
interface_obj_sorted [ i ] = obj ;
break ;
}
default :
break ;
2023-02-18 12:14:15 +01:00
}
2024-06-10 13:05:21 +01:00
}
2025-02-03 17:25:02 +00:00
# if BOARD_MODEL == BOARD_T3S3 && BOARD_VARIANT == MODEL_AC
// Fix weird radio not found bug on T3S3 SX1280
delay ( 300 ) ;
interface_obj [ 0 ] - > reset ( ) ;
delay ( 100 ) ;
# endif
2024-06-10 13:05:21 +01:00
// Check installed transceiver chip(s) and probe boot parameters. If any of
// the configured modems cannot be initialised, do not boot
for ( int i = 0 ; i < INTERFACE_COUNT ; i + + ) {
switch ( interfaces [ i ] ) {
case SX1262 :
case SX1276 :
case SX1278 :
case SX1280 :
selected_radio = interface_obj [ i ] ;
break ;
default :
modems_installed = false ;
break ;
}
if ( selected_radio - > preInit ( ) ) {
modems_installed = true ;
2025-02-03 17:25:02 +00:00
# if HAS_INPUT
// Skip quick-reset console activation
# else
uint32_t lfr = selected_radio - > getFrequency ( ) ;
if ( lfr = = 0 ) {
// Normal boot
} else if ( lfr = = M_FRQ_R ) {
// Quick reboot
# if HAS_CONSOLE
if ( rtc_get_reset_reason ( 0 ) = = POWERON_RESET ) {
console_active = true ;
}
# endif
} else {
// Unknown boot
2024-06-10 13:05:21 +01:00
}
2025-02-03 17:25:02 +00:00
selected_radio - > setFrequency ( M_FRQ_S ) ;
2024-10-07 20:45:12 +02:00
# endif
2024-06-10 13:05:21 +01:00
} else {
modems_installed = false ;
}
if ( ! modems_installed ) {
break ;
}
2023-01-07 16:35:07 +01:00
}
2018-06-20 08:45:11 +02:00
2022-11-02 19:02:22 +01:00
# if HAS_DISPLAY
2024-05-05 17:15:55 +01:00
# if HAS_EEPROM
2023-05-03 14:05:49 +02:00
if ( EEPROM . read ( eeprom_addr ( ADDR_CONF_DSET ) ) ! = CONF_OK_BYTE ) {
2024-05-05 17:15:55 +01:00
# elif MCU_VARIANT == MCU_NRF52
if ( eeprom_read ( eeprom_addr ( ADDR_CONF_DSET ) ) ! = CONF_OK_BYTE ) {
# endif
2023-05-03 14:05:49 +02:00
eeprom_update ( eeprom_addr ( ADDR_CONF_DSET ) , CONF_OK_BYTE ) ;
2025-01-16 11:15:31 +01:00
# if BOARD_MODEL == BOARD_TECHO
eeprom_update ( eeprom_addr ( ADDR_CONF_DINT ) , 0x03 ) ;
# else
eeprom_update ( eeprom_addr ( ADDR_CONF_DINT ) , 0xFF ) ;
# endif
2023-05-03 14:05:49 +02:00
}
2025-02-03 17:25:02 +00:00
# if BOARD_MODEL == BOARD_OPENCOM_XL && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
// On this board it isn't possible to run the main loop whilst the
// display is updating as the SPI pins are shared between the display and
// secondary modem. Because running the main loop causes a lockup, we
// just run the serial poll loop instead.
display_add_callback ( process_serial ) ;
# elif DISPLAY == EINK_BW || DISPLAY == EINK_3C
2025-01-15 18:38:14 +01:00
display_add_callback ( work_while_waiting ) ;
2024-05-20 20:14:16 +01:00
# endif
2025-01-15 18:38:14 +01:00
2024-09-29 02:33:02 +02:00
display_unblank ( ) ;
2022-11-02 19:02:22 +01:00
disp_ready = display_init ( ) ;
2025-02-04 15:33:15 +00:00
if ( disp_ready ) update_display ( ) ;
2022-11-02 19:02:22 +01:00
# endif
2022-10-29 00:53:39 +02:00
# if HAS_PMU == true
pmu_ready = init_pmu ( ) ;
2022-01-21 20:43:29 +01:00
# endif
2024-04-23 00:52:57 +02:00
# if HAS_BLUETOOTH || HAS_BLE == true
2022-11-02 19:02:22 +01:00
bt_init ( ) ;
bt_init_ran = true ;
# endif
2022-01-09 23:40:30 +01:00
2023-01-06 22:29:23 +01:00
if ( console_active ) {
2023-01-11 09:42:11 +01:00
# if HAS_CONSOLE
console_start ( ) ;
# else
kiss_indicate_reset ( ) ;
# endif
2023-01-07 16:35:07 +01:00
} else {
kiss_indicate_reset ( ) ;
2023-01-06 22:29:23 +01:00
}
2022-10-29 00:53:39 +02:00
2025-02-03 17:25:02 +00:00
for ( int i = 0 ; i < INTERFACE_COUNT ; i + + ) {
selected_radio = interface_obj [ i ] ;
if ( interfaces [ i ] = = SX1280 ) {
selected_radio - > setAvdInterference ( false ) ;
}
if ( selected_radio - > getAvdInterference ( ) ) {
# if HAS_EEPROM
uint8_t ia_conf = EEPROM . read ( eeprom_addr ( ADDR_CONF_DIA ) ) ;
if ( ia_conf = = 0x00 ) { selected_radio - > setAvdInterference ( true ) ; }
else { selected_radio - > setAvdInterference ( false ) ; }
# elif MCU_VARIANT == MCU_NRF52
uint8_t ia_conf = eeprom_read ( eeprom_addr ( ADDR_CONF_DIA ) ) ;
if ( ia_conf = = 0x00 ) { selected_radio - > setAvdInterference ( true ) ; }
else { selected_radio - > setAvdInterference ( false ) ; }
# endif
}
}
2025-01-09 17:58:46 +01:00
2022-10-29 16:44:49 +02:00
// Validate board health, EEPROM and config
2022-11-01 21:11:41 +01:00
validate_status ( ) ;
2018-04-05 18:10:42 +02:00
}
2024-06-10 13:05:21 +01:00
void lora_receive ( RadioInterface * radio ) {
2021-03-12 18:48:50 +01:00
if ( ! implicit ) {
2024-06-10 13:05:21 +01:00
radio - > receive ( ) ;
2021-03-12 18:48:50 +01:00
} else {
2024-06-10 13:05:21 +01:00
radio - > receive ( implicit_l ) ;
2021-03-12 18:48:50 +01:00
}
}
2024-06-10 13:05:21 +01:00
inline void kiss_write_packet ( int index ) {
2025-01-09 21:26:58 +00:00
// Print index of interface the packet came from
2022-10-30 18:35:53 +01:00
serial_write ( FEND ) ;
2025-01-09 21:26:58 +00:00
serial_write ( CMD_SEL_INT ) ;
serial_write ( index ) ;
serial_write ( FEND ) ;
serial_write ( FEND ) ;
serial_write ( CMD_DATA ) ;
2024-06-10 13:05:21 +01:00
2024-10-22 18:02:46 +01:00
for ( uint16_t i = 0 ; i < read_len [ index ] ; i + + ) {
2024-10-12 18:04:19 +01:00
# if MCU_VARIANT == MCU_NRF52
portENTER_CRITICAL ( ) ;
uint8_t byte = pbuf [ i ] ;
portEXIT_CRITICAL ( ) ;
# else
uint8_t byte = pbuf [ i ] ;
# endif
2022-10-30 18:35:53 +01:00
if ( byte = = FEND ) { serial_write ( FESC ) ; byte = TFEND ; }
if ( byte = = FESC ) { serial_write ( FESC ) ; byte = TFESC ; }
serial_write ( byte ) ;
2018-04-05 18:10:42 +02:00
}
2024-10-12 18:04:19 +01:00
2022-10-30 18:35:53 +01:00
serial_write ( FEND ) ;
2024-10-22 18:02:46 +01:00
read_len [ index ] = 0 ;
2024-10-12 18:04:19 +01:00
# if MCU_VARIANT == MCU_ESP32 && HAS_BLE
bt_flush ( ) ;
# endif
2018-04-05 18:10:42 +02:00
}
2024-06-10 13:05:21 +01:00
inline void getPacketData ( RadioInterface * radio , uint16_t len ) {
2024-10-22 18:02:46 +01:00
uint8_t index = radio - > getIndex ( ) ;
2024-10-12 18:04:19 +01:00
# if MCU_VARIANT != MCU_NRF52
2024-10-22 18:02:46 +01:00
while ( len - - & & read_len [ index ] < MTU ) {
pbuf [ read_len [ index ] + + ] = radio - > read ( ) ;
2024-10-12 18:04:19 +01:00
}
# else
BaseType_t int_mask = taskENTER_CRITICAL_FROM_ISR ( ) ;
2024-10-22 18:02:46 +01:00
while ( len - - & & read_len [ index ] < MTU ) {
pbuf [ read_len [ index ] + + ] = radio - > read ( ) ;
2024-10-12 18:04:19 +01:00
}
taskEXIT_CRITICAL_FROM_ISR ( int_mask ) ;
# endif
}
2024-10-15 17:34:16 +01:00
inline bool queue_packet ( RadioInterface * radio , uint8_t index ) {
2024-10-12 18:04:19 +01:00
// Allocate packet struct, but abort if there
// is not enough memory available.
2024-10-22 18:02:46 +01:00
modem_packet_t * modem_packet = ( modem_packet_t * ) malloc ( sizeof ( modem_packet_t ) + read_len [ index ] ) ;
2024-10-12 18:04:19 +01:00
if ( ! modem_packet ) { memory_low = true ; return false ; }
// Get packet RSSI and SNR
modem_packet - > snr_raw = radio - > packetSnrRaw ( ) ;
// Pass raw SNR to get RSSI as SX127X driver requires it for calculations
modem_packet - > rssi = radio - > packetRssi ( modem_packet - > snr_raw ) ;
modem_packet - > interface = index ;
// Send packet to event queue, but free the
// allocated memory again if the queue is
// unable to receive the packet.
2024-10-22 18:02:46 +01:00
modem_packet - > len = read_len [ index ] ;
memcpy ( modem_packet - > data , pbuf , read_len [ index ] ) ;
2024-10-12 18:04:19 +01:00
if ( ! modem_packet_queue | | xQueueSendFromISR ( modem_packet_queue , & modem_packet , NULL ) ! = pdPASS ) {
free ( modem_packet ) ;
2024-10-15 17:34:16 +01:00
return false ;
2024-10-12 18:04:19 +01:00
}
2024-10-15 17:34:16 +01:00
return true ;
2022-01-11 02:54:32 +01:00
}
2022-01-10 22:14:30 +01:00
2024-10-12 18:04:19 +01:00
void ISR_VECT receive_callback ( uint8_t index , int packet_size ) {
selected_radio = interface_obj [ index ] ;
2024-09-10 22:39:15 +01:00
bool ready = false ;
2024-10-12 18:04:19 +01:00
BaseType_t int_mask ;
2022-01-14 21:12:33 +01:00
if ( ! promisc ) {
// The standard operating mode allows large
// packets with a payload up to 500 bytes,
// by combining two raw LoRa packets.
// We read the 1-byte header and extract
// packet sequence number and split flags
2024-09-10 22:39:15 +01:00
2024-06-10 13:05:21 +01:00
uint8_t header = selected_radio - > read ( ) ; packet_size - - ;
2022-01-14 21:12:33 +01:00
uint8_t sequence = packetSequence ( header ) ;
2024-10-12 18:04:19 +01:00
if ( isSplitPacket ( header ) & & seq [ index ] = = SEQ_UNSET ) {
2022-01-14 21:12:33 +01:00
// This is the first part of a split
// packet, so we set the seq variable
// and add the data to the buffer
2024-10-12 18:04:19 +01:00
# if MCU_VARIANT == MCU_NRF52
2024-10-22 18:02:46 +01:00
int_mask = taskENTER_CRITICAL_FROM_ISR ( ) ; read_len [ index ] = 0 ; taskEXIT_CRITICAL_FROM_ISR ( int_mask ) ;
2024-10-12 18:04:19 +01:00
# else
2024-10-22 18:02:46 +01:00
read_len [ index ] = 0 ;
2024-10-12 18:04:19 +01:00
# endif
seq [ index ] = sequence ;
2022-01-10 22:14:30 +01:00
2024-06-10 13:05:21 +01:00
getPacketData ( selected_radio , packet_size ) ;
2022-01-11 02:54:32 +01:00
2024-10-12 18:04:19 +01:00
} else if ( isSplitPacket ( header ) & & seq [ index ] = = sequence ) {
2022-01-14 21:12:33 +01:00
// This is the second part of a split
// packet, so we add it to the buffer
// and set the ready flag.
2024-06-10 13:05:21 +01:00
getPacketData ( selected_radio , packet_size ) ;
2024-01-19 10:08:55 +00:00
2024-10-12 18:04:19 +01:00
seq [ index ] = SEQ_UNSET ;
ready = true ;
2022-01-14 21:12:33 +01:00
2024-10-12 18:04:19 +01:00
} else if ( isSplitPacket ( header ) & & seq [ index ] ! = sequence ) {
2022-01-14 21:12:33 +01:00
// This split packet does not carry the
// same sequence id, so we must assume
// that we are seeing the first part of
// a new split packet.
2024-10-12 18:04:19 +01:00
# if MCU_VARIANT == MCU_NRF52
2024-10-22 18:02:46 +01:00
int_mask = taskENTER_CRITICAL_FROM_ISR ( ) ; read_len [ index ] = 0 ; taskEXIT_CRITICAL_FROM_ISR ( int_mask ) ;
2024-10-12 18:04:19 +01:00
# else
2024-10-22 18:02:46 +01:00
read_len [ index ] = 0 ;
2024-10-12 18:04:19 +01:00
# endif
seq [ index ] = sequence ;
2022-01-11 02:54:32 +01:00
2024-06-10 13:05:21 +01:00
getPacketData ( selected_radio , packet_size ) ;
2022-01-11 02:54:32 +01:00
2022-01-14 21:12:33 +01:00
} else if ( ! isSplitPacket ( header ) ) {
// This is not a split packet, so we
// just read it and set the ready
// flag to true.
2022-01-11 02:54:32 +01:00
2024-10-12 18:04:19 +01:00
if ( seq [ index ] ! = SEQ_UNSET ) {
2022-01-14 21:12:33 +01:00
// If we already had part of a split
// packet in the buffer, we clear it.
2024-10-12 18:04:19 +01:00
# if MCU_VARIANT == MCU_NRF52
2024-10-22 18:02:46 +01:00
int_mask = taskENTER_CRITICAL_FROM_ISR ( ) ; read_len [ index ] = 0 ; taskEXIT_CRITICAL_FROM_ISR ( int_mask ) ;
2024-10-12 18:04:19 +01:00
# else
2024-10-22 18:02:46 +01:00
read_len [ index ] = 0 ;
2024-10-12 18:04:19 +01:00
# endif
seq [ index ] = SEQ_UNSET ;
2018-06-27 11:42:48 +02:00
}
2024-06-10 13:05:21 +01:00
getPacketData ( selected_radio , packet_size ) ;
2024-09-11 21:49:27 +01:00
2024-10-12 18:04:19 +01:00
ready = true ;
2022-01-14 21:12:33 +01:00
}
} else {
2022-01-14 21:41:10 +01:00
// In promiscuous mode, raw packets are
// output directly to the host
2024-10-22 18:02:46 +01:00
read_len [ index ] = 0 ;
2022-01-14 21:41:10 +01:00
2024-06-10 13:05:21 +01:00
getPacketData ( selected_radio , packet_size ) ;
2024-09-11 21:49:27 +01:00
2024-10-12 18:04:19 +01:00
ready = true ;
}
if ( ready ) {
2024-10-15 17:34:16 +01:00
queue_packet ( selected_radio , index ) ;
2022-01-10 22:14:30 +01:00
}
2024-09-04 17:37:09 +01:00
2024-07-03 11:06:52 +01:00
last_rx = millis ( ) ;
2022-01-10 22:14:30 +01:00
}
2024-06-10 13:05:21 +01:00
bool startRadio ( RadioInterface * radio ) {
update_radio_lock ( radio ) ;
if ( modems_installed & & ! console_active ) {
2025-02-03 17:25:02 +00:00
if ( ! radio - > getRadioOnline ( ) ) {
if ( ! radio - > getRadioLock ( ) & & hw_ready ) {
if ( ! radio - > begin ( ) ) {
// The radio could not be started.
// Indicate this failure over both the
// serial port and with the onboard LEDs
kiss_indicate_error ( ERROR_INITRADIO ) ;
led_indicate_error ( 0 ) ;
return false ;
} else {
radio - > enableCrc ( ) ;
2023-09-13 20:05:05 +02:00
2025-02-03 17:25:02 +00:00
radio - > onReceive ( receive_callback ) ;
2022-01-10 22:14:30 +01:00
2025-02-03 17:25:02 +00:00
radio - > updateBitrate ( ) ;
sort_interfaces ( ) ;
kiss_indicate_phy_stats ( radio ) ;
2022-01-10 22:14:30 +01:00
2025-02-03 17:25:02 +00:00
lora_receive ( radio ) ;
2022-01-10 22:14:30 +01:00
2025-02-03 17:25:02 +00:00
// Flash an info pattern to indicate
// that the radio is now on
kiss_indicate_radiostate ( radio ) ;
led_indicate_info ( 3 ) ;
return true ;
}
2022-01-10 22:14:30 +01:00
2025-02-03 17:25:02 +00:00
} else {
// Flash a warning pattern to indicate
// that the radio was locked, and thus
// not started
kiss_indicate_radiostate ( radio ) ;
led_indicate_warning ( 3 ) ;
return false ;
}
} else {
// If radio is already on, we silently
// ignore the request.
2024-06-10 13:05:21 +01:00
kiss_indicate_radiostate ( radio ) ;
2022-01-10 22:14:30 +01:00
return true ;
}
}
2025-02-03 17:43:08 +00:00
return false ;
2022-01-10 22:14:30 +01:00
}
2024-06-10 13:05:21 +01:00
void stopRadio ( RadioInterface * radio ) {
2025-02-03 17:25:02 +00:00
if ( radio - > getRadioOnline ( ) ) {
radio - > end ( ) ;
sort_interfaces ( ) ;
kiss_indicate_radiostate ( radio ) ;
}
2022-01-10 22:14:30 +01:00
}
2024-06-10 13:05:21 +01:00
void update_radio_lock ( RadioInterface * radio ) {
if ( radio - > getFrequency ( ) ! = 0 & & radio - > getSignalBandwidth ( ) ! = 0 & & radio - > getTxPower ( ) ! = 0xFF & & radio - > getSpreadingFactor ( ) ! = 0 ) {
radio - > setRadioLock ( false ) ;
2022-01-10 22:14:30 +01:00
} else {
2024-06-10 13:05:21 +01:00
radio - > setRadioLock ( true ) ;
2018-04-05 18:10:42 +02:00
}
}
2024-06-10 13:05:21 +01:00
// Check if the queue is full for the selected radio.
// Returns true if full, false if not
2025-02-03 17:25:02 +00:00
bool queue_full ( RadioInterface * radio ) {
2024-07-03 11:06:52 +01:00
return ( queue_height [ radio - > getIndex ( ) ] > = ( CONFIG_QUEUE_MAX_LENGTH ) | | queued_bytes [ radio - > getIndex ( ) ] > = ( getQueueSize ( radio - > getIndex ( ) ) ) ) ;
2018-06-27 10:22:44 +02:00
}
2020-05-28 22:18:19 +02:00
volatile bool queue_flushing = false ;
2024-06-10 13:05:21 +01:00
// Flushes all packets for the interface
2025-02-03 17:25:02 +00:00
void flush_queue ( RadioInterface * radio ) {
2024-06-10 13:05:21 +01:00
uint8_t index = radio - > getIndex ( ) ;
2020-05-28 22:18:19 +02:00
if ( ! queue_flushing ) {
queue_flushing = true ;
2018-06-27 10:22:44 +02:00
2023-09-14 22:32:26 +02:00
led_tx_on ( ) ;
2022-01-09 23:45:40 +01:00
uint16_t processed = 0 ;
2024-06-10 13:05:21 +01:00
uint8_t data_byte ;
2022-01-09 23:40:30 +01:00
2024-06-10 13:05:21 +01:00
while ( ! fifo16_isempty ( & packet_starts [ index ] ) ) {
uint16_t start = fifo16_pop ( & packet_starts [ index ] ) ;
uint16_t length = fifo16_pop ( & packet_lengths [ index ] ) ;
2018-06-27 10:22:44 +02:00
2020-05-29 14:58:10 +02:00
if ( length > = MIN_L & & length < = MTU ) {
2022-01-09 23:45:40 +01:00
for ( uint16_t i = 0 ; i < length ; i + + ) {
2024-07-03 11:06:52 +01:00
uint16_t pos = ( start + i ) % ( getQueueSize ( index ) ) ;
2024-06-10 13:05:21 +01:00
tbuf [ i ] = packet_queue [ index ] [ pos ] ;
2020-05-28 22:18:19 +02:00
}
2024-06-10 13:05:21 +01:00
transmit ( radio , length ) ;
2020-05-28 22:18:19 +02:00
processed + + ;
}
}
2023-09-14 22:32:26 +02:00
2024-06-10 13:05:21 +01:00
lora_receive ( radio ) ;
2023-09-14 22:32:26 +02:00
led_tx_off ( ) ;
2024-06-10 13:05:21 +01:00
2018-06-27 10:22:44 +02:00
}
2020-05-28 22:18:19 +02:00
2024-06-10 13:05:21 +01:00
queue_height [ index ] = 0 ;
queued_bytes [ index ] = 0 ;
selected_radio - > updateAirtime ( ) ;
2020-05-28 22:18:19 +02:00
queue_flushing = false ;
2025-02-10 14:06:41 +00:00
# if HAS_DISPLAY
display_tx [ radio - > getIndex ( ) ] = true ;
# endif
2018-06-27 10:22:44 +02:00
}
2025-02-03 17:25:02 +00:00
void pop_queue ( RadioInterface * radio ) {
uint8_t index = radio - > getIndex ( ) ;
2025-01-09 00:01:49 +01:00
if ( ! queue_flushing ) {
queue_flushing = true ;
led_tx_on ( ) ; uint16_t processed = 0 ;
# if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
2025-02-03 17:25:02 +00:00
if ( ! fifo16_isempty ( & packet_starts [ index ] ) ) {
2025-01-09 00:01:49 +01:00
# else
2025-02-03 17:25:02 +00:00
if ( ! fifo16_isempty_locked ( & packet_starts [ index ] ) ) {
2025-01-09 00:01:49 +01:00
# endif
2025-02-03 17:25:02 +00:00
uint16_t start = fifo16_pop ( & packet_starts [ index ] ) ;
uint16_t length = fifo16_pop ( & packet_lengths [ index ] ) ;
2025-01-09 00:01:49 +01:00
if ( length > = MIN_L & & length < = MTU ) {
for ( uint16_t i = 0 ; i < length ; i + + ) {
2025-02-03 17:25:02 +00:00
uint16_t pos = ( start + i ) % getQueueSize ( index ) ;
tbuf [ i ] = packet_queue [ index ] [ pos ] ;
2025-01-09 00:01:49 +01:00
}
2025-02-03 17:25:02 +00:00
transmit ( radio , length ) ; processed + + ;
2025-01-09 00:01:49 +01:00
}
2025-02-03 17:25:02 +00:00
queue_height [ index ] - = processed ;
queued_bytes [ index ] - = length ;
2025-01-09 00:01:49 +01:00
}
2025-02-03 17:25:02 +00:00
lora_receive ( radio ) ; led_tx_off ( ) ;
2025-01-09 00:01:49 +01:00
}
2025-02-03 17:25:02 +00:00
radio - > updateAirtime ( ) ;
2025-01-09 00:01:49 +01:00
queue_flushing = false ;
2024-10-12 18:04:19 +01:00
# if HAS_DISPLAY
2025-02-10 14:06:41 +00:00
display_tx [ radio - > getIndex ( ) ] = true ;
2024-10-12 18:04:19 +01:00
# endif
2018-06-27 10:22:44 +02:00
}
2024-06-10 13:05:21 +01:00
void transmit ( RadioInterface * radio , uint16_t size ) {
if ( radio - > getRadioOnline ( ) ) {
2018-06-27 11:42:48 +02:00
if ( ! promisc ) {
2022-01-09 23:45:40 +01:00
uint16_t written = 0 ;
2018-06-27 11:42:48 +02:00
uint8_t header = random ( 256 ) & 0xF0 ;
2018-04-05 18:10:42 +02:00
2018-06-27 11:42:48 +02:00
if ( size > SINGLE_MTU - HEADER_L ) {
header = header | FLAG_SPLIT ;
}
2018-04-05 18:10:42 +02:00
2024-06-10 13:05:21 +01:00
radio - > beginPacket ( ) ;
radio - > write ( header ) ; written + + ;
2018-04-05 18:10:42 +02:00
2022-01-14 10:51:40 +01:00
for ( uint16_t i = 0 ; i < size ; i + + ) {
2024-06-10 13:05:21 +01:00
radio - > write ( tbuf [ i ] ) ;
2018-06-27 10:22:44 +02:00
2018-06-27 11:42:48 +02:00
written + + ;
2018-04-05 18:10:42 +02:00
2024-10-12 12:45:20 +01:00
// Only start a new packet if this is a split packet and it has
// exceeded the length of a single packet
if ( written = = 255 & & header & 0x0F ) {
2025-02-03 17:25:02 +00:00
radio - > endPacket ( ) ; radio - > addAirtime ( ) ;
2024-06-10 13:05:21 +01:00
radio - > beginPacket ( ) ;
radio - > write ( header ) ;
2018-06-27 11:42:48 +02:00
written = 1 ;
}
2018-04-05 18:10:42 +02:00
}
2024-10-12 18:04:19 +01:00
if ( ! radio - > endPacket ( ) ) {
kiss_indicate_error ( ERROR_MODEM_TIMEOUT ) ;
kiss_indicate_error ( ERROR_TXFAILED ) ;
led_indicate_error ( 5 ) ;
hard_reset ( ) ;
}
2025-02-03 17:25:02 +00:00
radio - > addAirtime ( ) ;
2024-10-12 18:04:19 +01:00
2018-06-27 11:42:48 +02:00
} else {
// In promiscuous mode, we only send out
// plain raw LoRa packets with a maximum
// payload of 255 bytes
led_tx_on ( ) ;
2022-01-09 23:45:40 +01:00
uint16_t written = 0 ;
2018-06-27 11:42:48 +02:00
// Cap packets at 255 bytes
if ( size > SINGLE_MTU ) {
size = SINGLE_MTU ;
}
2018-04-26 10:34:39 +02:00
2021-03-12 18:48:50 +01:00
// If implicit header mode has been set,
// set packet length to payload data length
if ( ! implicit ) {
2024-06-10 13:05:21 +01:00
radio - > beginPacket ( ) ;
2021-03-12 18:48:50 +01:00
} else {
2024-06-10 13:05:21 +01:00
radio - > beginPacket ( size ) ;
2021-03-12 18:48:50 +01:00
}
2022-01-14 10:51:40 +01:00
for ( uint16_t i = 0 ; i < size ; i + + ) {
2024-06-10 13:05:21 +01:00
radio - > write ( tbuf [ i ] ) ;
2018-06-27 11:42:48 +02:00
written + + ;
}
2025-02-03 17:25:02 +00:00
radio - > endPacket ( ) ; radio - > addAirtime ( ) ;
2018-06-27 11:42:48 +02:00
}
2024-07-03 11:06:52 +01:00
last_tx = millis ( ) ;
2018-04-05 18:10:42 +02:00
} else {
kiss_indicate_error ( ERROR_TXFAILED ) ;
led_indicate_error ( 5 ) ;
}
}
2025-01-07 20:43:15 +01:00
void serial_callback ( uint8_t sbyte ) {
2024-06-10 13:05:21 +01:00
if ( IN_FRAME & & sbyte = = FEND & &
2025-01-09 21:26:58 +00:00
command = = CMD_DATA ) {
2018-04-05 18:10:42 +02:00
IN_FRAME = false ;
2018-06-27 10:22:44 +02:00
2025-01-09 21:26:58 +00:00
if ( interface < INTERFACE_COUNT ) {
if ( ! fifo16_isfull ( & packet_starts [ interface ] ) & & ( queued_bytes [ interface ] < ( getQueueSize ( interface ) ) ) ) {
uint16_t s = current_packet_start [ interface ] ;
int32_t e = queue_cursor [ interface ] - 1 ; if ( e = = - 1 ) e = ( getQueueSize ( interface ) ) - 1 ;
2024-06-10 13:05:21 +01:00
uint16_t l ;
if ( s ! = e ) {
2025-01-09 21:26:58 +00:00
l = ( s < e ) ? e - s + 1 : ( getQueueSize ( interface ) ) - s + e + 1 ;
2024-06-10 13:05:21 +01:00
} else {
l = 1 ;
}
2020-05-28 22:18:19 +02:00
2024-06-10 13:05:21 +01:00
if ( l > = MIN_L ) {
2025-01-09 21:26:58 +00:00
queue_height [ interface ] + + ;
2020-05-28 22:18:19 +02:00
2025-01-09 21:26:58 +00:00
fifo16_push ( & packet_starts [ interface ] , s ) ;
fifo16_push ( & packet_lengths [ interface ] , l ) ;
current_packet_start [ interface ] = queue_cursor [ interface ] ;
2024-06-10 13:05:21 +01:00
}
2020-05-28 22:18:19 +02:00
}
2018-06-27 10:22:44 +02:00
}
2020-05-28 22:18:19 +02:00
2018-04-05 18:10:42 +02:00
} else if ( sbyte = = FEND ) {
IN_FRAME = true ;
command = CMD_UNKNOWN ;
frame_len = 0 ;
} else if ( IN_FRAME & & frame_len < MTU ) {
// Have a look at the command byte first
if ( frame_len = = 0 & & command = = CMD_UNKNOWN ) {
command = sbyte ;
2024-06-10 13:05:21 +01:00
2025-01-09 21:26:58 +00:00
} else if ( command = = CMD_SEL_INT ) {
interface = sbyte ;
} else if ( command = = CMD_DATA ) {
2022-10-30 18:35:53 +01:00
if ( bt_state ! = BT_STATE_CONNECTED ) cable_state = CABLE_STATE_CONNECTED ;
2018-04-05 18:10:42 +02:00
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
2024-06-10 13:05:21 +01:00
2025-01-09 21:26:58 +00:00
if ( interface < INTERFACE_COUNT ) {
if ( queue_height [ interface ] < CONFIG_QUEUE_MAX_LENGTH & & queued_bytes [ interface ] < ( getQueueSize ( interface ) ) ) {
queued_bytes [ interface ] + + ;
packet_queue [ interface ] [ queue_cursor [ interface ] + + ] = sbyte ;
if ( queue_cursor [ interface ] = = ( getQueueSize ( interface ) ) ) queue_cursor [ interface ] = 0 ;
2024-06-10 13:05:21 +01:00
}
2020-05-28 22:18:19 +02:00
}
2018-04-05 18:10:42 +02:00
}
2024-06-10 13:05:21 +01:00
} else if ( command = = CMD_INTERFACES ) {
for ( int i = 0 ; i < INTERFACE_COUNT ; i + + ) {
kiss_indicate_interface ( i ) ;
}
2018-04-05 18:10:42 +02:00
} else if ( command = = CMD_FREQUENCY ) {
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
2022-11-01 21:11:41 +01:00
if ( frame_len < CMD_L ) cmdbuf [ frame_len + + ] = sbyte ;
2018-04-05 18:10:42 +02:00
}
if ( frame_len = = 4 ) {
2025-02-03 17:25:02 +00:00
selected_radio = interface_obj [ interface ] ;
2022-11-01 21:11:41 +01:00
uint32_t freq = ( uint32_t ) cmdbuf [ 0 ] < < 24 | ( uint32_t ) cmdbuf [ 1 ] < < 16 | ( uint32_t ) cmdbuf [ 2 ] < < 8 | ( uint32_t ) cmdbuf [ 3 ] ;
2018-04-05 18:10:42 +02:00
if ( freq = = 0 ) {
2024-06-10 13:05:21 +01:00
kiss_indicate_frequency ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
} else {
2024-06-10 13:05:21 +01:00
if ( op_mode = = MODE_HOST ) selected_radio - > setFrequency ( freq ) ;
kiss_indicate_frequency ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
}
2024-06-10 13:05:21 +01:00
interface = 0 ;
2018-04-05 18:10:42 +02:00
}
} else if ( command = = CMD_BANDWIDTH ) {
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
2022-11-01 21:11:41 +01:00
if ( frame_len < CMD_L ) cmdbuf [ frame_len + + ] = sbyte ;
2018-04-05 18:10:42 +02:00
}
if ( frame_len = = 4 ) {
2024-06-10 13:05:21 +01:00
selected_radio = interface_obj [ interface ] ;
2022-11-01 21:11:41 +01:00
uint32_t bw = ( uint32_t ) cmdbuf [ 0 ] < < 24 | ( uint32_t ) cmdbuf [ 1 ] < < 16 | ( uint32_t ) cmdbuf [ 2 ] < < 8 | ( uint32_t ) cmdbuf [ 3 ] ;
2024-06-10 13:05:21 +01:00
2018-04-05 18:10:42 +02:00
if ( bw = = 0 ) {
2024-06-10 13:05:21 +01:00
kiss_indicate_bandwidth ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
} else {
2024-06-10 13:05:21 +01:00
if ( op_mode = = MODE_HOST ) selected_radio - > setSignalBandwidth ( bw ) ;
selected_radio - > updateBitrate ( ) ;
sort_interfaces ( ) ;
kiss_indicate_bandwidth ( selected_radio ) ;
2024-08-24 11:08:13 +01:00
kiss_indicate_phy_stats ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
}
2024-06-10 13:05:21 +01:00
interface = 0 ;
2018-04-05 18:10:42 +02:00
}
} else if ( command = = CMD_TXPOWER ) {
2024-06-10 13:05:21 +01:00
selected_radio = interface_obj [ interface ] ;
2018-04-05 18:10:42 +02:00
if ( sbyte = = 0xFF ) {
2024-06-10 13:05:21 +01:00
kiss_indicate_txpower ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
} else {
2024-07-12 15:15:56 +01:00
int8_t txp = ( int8_t ) sbyte ;
2018-04-05 18:10:42 +02:00
2024-06-10 13:05:21 +01:00
if ( op_mode = = MODE_HOST ) setTXPower ( selected_radio , txp ) ;
kiss_indicate_txpower ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
}
2024-06-10 13:05:21 +01:00
interface = 0 ;
2018-04-05 18:10:42 +02:00
} else if ( command = = CMD_SF ) {
2024-06-10 13:05:21 +01:00
selected_radio = interface_obj [ interface ] ;
2018-04-05 18:10:42 +02:00
if ( sbyte = = 0xFF ) {
2024-06-10 13:05:21 +01:00
kiss_indicate_spreadingfactor ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
} else {
int sf = sbyte ;
2024-02-09 20:46:39 +00:00
if ( sf < 5 ) sf = 5 ;
2018-04-05 18:10:42 +02:00
if ( sf > 12 ) sf = 12 ;
2024-06-10 13:05:21 +01:00
if ( op_mode = = MODE_HOST ) selected_radio - > setSpreadingFactor ( sf ) ;
selected_radio - > updateBitrate ( ) ;
sort_interfaces ( ) ;
kiss_indicate_spreadingfactor ( selected_radio ) ;
2024-08-24 11:08:13 +01:00
kiss_indicate_phy_stats ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
}
2024-06-10 13:05:21 +01:00
interface = 0 ;
2018-06-20 08:45:11 +02:00
} else if ( command = = CMD_CR ) {
2024-06-10 13:05:21 +01:00
selected_radio = interface_obj [ interface ] ;
2018-06-20 08:45:11 +02:00
if ( sbyte = = 0xFF ) {
2024-06-10 13:05:21 +01:00
kiss_indicate_codingrate ( selected_radio ) ;
2018-06-20 08:45:11 +02:00
} else {
int cr = sbyte ;
if ( cr < 5 ) cr = 5 ;
if ( cr > 8 ) cr = 8 ;
2024-06-10 13:05:21 +01:00
if ( op_mode = = MODE_HOST ) selected_radio - > setCodingRate4 ( cr ) ;
selected_radio - > updateBitrate ( ) ;
sort_interfaces ( ) ;
kiss_indicate_codingrate ( selected_radio ) ;
2024-08-24 11:08:13 +01:00
kiss_indicate_phy_stats ( selected_radio ) ;
2018-06-20 08:45:11 +02:00
}
2024-06-10 13:05:21 +01:00
interface = 0 ;
2021-03-12 18:48:50 +01:00
} else if ( command = = CMD_IMPLICIT ) {
set_implicit_length ( sbyte ) ;
kiss_indicate_implicit_length ( ) ;
2022-10-29 16:44:49 +02:00
} else if ( command = = CMD_LEAVE ) {
if ( sbyte = = 0xFF ) {
2025-02-04 15:33:15 +00:00
display_unblank ( ) ;
2022-10-29 17:34:08 +02:00
cable_state = CABLE_STATE_DISCONNECTED ;
2024-06-10 13:05:21 +01:00
//current_rssi = -292;
2022-10-29 17:34:08 +02:00
last_rssi = - 292 ;
last_rssi_raw = 0x00 ;
last_snr_raw = 0x80 ;
2022-10-29 16:44:49 +02:00
}
2018-04-05 18:10:42 +02:00
} else if ( command = = CMD_RADIO_STATE ) {
2024-06-10 13:05:21 +01:00
selected_radio = interface_obj [ interface ] ;
2022-10-30 18:35:53 +01:00
if ( bt_state ! = BT_STATE_CONNECTED ) cable_state = CABLE_STATE_CONNECTED ;
2018-04-05 18:10:42 +02:00
if ( sbyte = = 0xFF ) {
2024-06-10 13:05:21 +01:00
kiss_indicate_radiostate ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
} else if ( sbyte = = 0x00 ) {
2024-06-10 13:05:21 +01:00
stopRadio ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
} else if ( sbyte = = 0x01 ) {
2024-06-10 13:05:21 +01:00
startRadio ( selected_radio ) ;
2018-04-05 18:10:42 +02:00
}
2024-06-10 13:05:21 +01:00
interface = 0 ;
2023-09-13 20:05:05 +02:00
} else if ( command = = CMD_ST_ALOCK ) {
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
if ( frame_len < CMD_L ) cmdbuf [ frame_len + + ] = sbyte ;
}
if ( frame_len = = 2 ) {
2025-02-03 17:25:02 +00:00
selected_radio = interface_obj [ interface ] ;
2023-09-13 20:05:05 +02:00
uint16_t at = ( uint16_t ) cmdbuf [ 0 ] < < 8 | ( uint16_t ) cmdbuf [ 1 ] ;
if ( at = = 0 ) {
2024-06-10 13:05:21 +01:00
selected_radio - > setSTALock ( 0.0 ) ;
2023-09-13 20:05:05 +02:00
} else {
2024-06-10 13:05:21 +01:00
int st_airtime_limit = ( float ) at / ( 100.0 * 100.0 ) ;
2023-09-13 20:05:05 +02:00
if ( st_airtime_limit > = 1.0 ) { st_airtime_limit = 0.0 ; }
2024-06-10 13:05:21 +01:00
selected_radio - > setSTALock ( st_airtime_limit ) ;
2023-09-13 20:05:05 +02:00
}
2024-06-10 13:05:21 +01:00
kiss_indicate_st_alock ( selected_radio ) ;
2025-02-03 17:25:02 +00:00
interface = 0 ;
2023-09-13 20:05:05 +02:00
}
} else if ( command = = CMD_LT_ALOCK ) {
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
if ( frame_len < CMD_L ) cmdbuf [ frame_len + + ] = sbyte ;
}
if ( frame_len = = 2 ) {
2025-02-03 17:25:02 +00:00
selected_radio = interface_obj [ interface ] ;
2023-09-13 20:05:05 +02:00
uint16_t at = ( uint16_t ) cmdbuf [ 0 ] < < 8 | ( uint16_t ) cmdbuf [ 1 ] ;
if ( at = = 0 ) {
2024-06-10 13:05:21 +01:00
selected_radio - > setLTALock ( 0.0 ) ;
2023-09-13 20:05:05 +02:00
} else {
2024-06-10 13:05:21 +01:00
int lt_airtime_limit = ( float ) at / ( 100.0 * 100.0 ) ;
2023-09-13 20:05:05 +02:00
if ( lt_airtime_limit > = 1.0 ) { lt_airtime_limit = 0.0 ; }
2024-06-10 13:05:21 +01:00
selected_radio - > setLTALock ( lt_airtime_limit ) ;
2023-09-13 20:05:05 +02:00
}
2024-06-10 13:05:21 +01:00
kiss_indicate_lt_alock ( selected_radio ) ;
2025-02-03 17:25:02 +00:00
interface = 0 ;
2023-09-13 20:05:05 +02:00
}
2018-04-05 18:10:42 +02:00
} else if ( command = = CMD_STAT_RX ) {
kiss_indicate_stat_rx ( ) ;
} else if ( command = = CMD_STAT_TX ) {
kiss_indicate_stat_tx ( ) ;
} else if ( command = = CMD_STAT_RSSI ) {
2025-01-09 21:26:58 +00:00
kiss_indicate_stat_rssi ( interface_obj [ interface ] ) ;
2018-04-05 18:10:42 +02:00
} else if ( command = = CMD_RADIO_LOCK ) {
2024-06-10 13:05:21 +01:00
selected_radio = interface_obj [ interface ] ;
update_radio_lock ( selected_radio ) ;
kiss_indicate_radio_lock ( selected_radio ) ;
interface = 0 ;
2018-04-05 18:10:42 +02:00
} else if ( command = = CMD_BLINK ) {
led_indicate_info ( sbyte ) ;
} else if ( command = = CMD_RANDOM ) {
2024-06-10 13:05:21 +01:00
// pick an interface at random to get data from
int int_index = random ( INTERFACE_COUNT ) ;
selected_radio = interface_obj [ int_index ] ;
kiss_indicate_random ( getRandom ( selected_radio ) ) ;
interface = 0 ;
2018-06-20 08:45:11 +02:00
} else if ( command = = CMD_DETECT ) {
if ( sbyte = = DETECT_REQ ) {
2022-10-30 18:35:53 +01:00
if ( bt_state ! = BT_STATE_CONNECTED ) cable_state = CABLE_STATE_CONNECTED ;
2018-06-20 08:45:11 +02:00
kiss_indicate_detect ( ) ;
}
2018-06-27 11:42:48 +02:00
} else if ( command = = CMD_PROMISC ) {
if ( sbyte = = 0x01 ) {
promisc_enable ( ) ;
} else if ( sbyte = = 0x00 ) {
promisc_disable ( ) ;
}
kiss_indicate_promisc ( ) ;
2020-05-20 16:16:04 +02:00
} else if ( command = = CMD_READY ) {
2024-06-10 13:05:21 +01:00
selected_radio = interface_obj [ interface ] ;
2025-02-03 17:25:02 +00:00
if ( ! queue_full ( selected_radio ) ) {
2020-05-20 16:16:04 +02:00
kiss_indicate_ready ( ) ;
} else {
kiss_indicate_not_ready ( ) ;
}
2018-06-20 08:45:11 +02:00
} else if ( command = = CMD_UNLOCK_ROM ) {
if ( sbyte = = ROM_UNLOCK_BYTE ) {
unlock_rom ( ) ;
}
2022-01-09 23:40:30 +01:00
} else if ( command = = CMD_RESET ) {
if ( sbyte = = CMD_RESET_BYTE ) {
hard_reset ( ) ;
}
2018-06-20 08:45:11 +02:00
} else if ( command = = CMD_ROM_READ ) {
kiss_dump_eeprom ( ) ;
} else if ( command = = CMD_ROM_WRITE ) {
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
2022-11-01 21:11:41 +01:00
if ( frame_len < CMD_L ) cmdbuf [ frame_len + + ] = sbyte ;
2018-06-20 08:45:11 +02:00
}
if ( frame_len = = 2 ) {
2022-11-01 21:11:41 +01:00
eeprom_write ( cmdbuf [ 0 ] , cmdbuf [ 1 ] ) ;
2018-06-20 08:45:11 +02:00
}
} else if ( command = = CMD_FW_VERSION ) {
kiss_indicate_version ( ) ;
2022-01-09 23:40:30 +01:00
} else if ( command = = CMD_PLATFORM ) {
kiss_indicate_platform ( ) ;
} else if ( command = = CMD_MCU ) {
kiss_indicate_mcu ( ) ;
2022-01-22 22:34:03 +01:00
} else if ( command = = CMD_BOARD ) {
kiss_indicate_board ( ) ;
2018-06-20 16:32:30 +02:00
} else if ( command = = CMD_CONF_SAVE ) {
2024-06-10 13:05:21 +01:00
// todo: add extra space in EEPROM so this isn't hardcoded
eeprom_conf_save ( interface_obj [ 0 ] ) ;
2018-06-20 16:32:30 +02:00
} else if ( command = = CMD_CONF_DELETE ) {
eeprom_conf_delete ( ) ;
2022-10-29 00:53:39 +02:00
} else if ( command = = CMD_FB_EXT ) {
# if HAS_DISPLAY == true
if ( sbyte = = 0xFF ) {
kiss_indicate_fbstate ( ) ;
} else if ( sbyte = = 0x00 ) {
ext_fb_disable ( ) ;
kiss_indicate_fbstate ( ) ;
} else if ( sbyte = = 0x01 ) {
ext_fb_enable ( ) ;
kiss_indicate_fbstate ( ) ;
}
# endif
} else if ( command = = CMD_FB_WRITE ) {
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
2022-11-01 21:11:41 +01:00
if ( frame_len < CMD_L ) cmdbuf [ frame_len + + ] = sbyte ;
2022-10-29 00:53:39 +02:00
}
2022-10-30 18:58:12 +01:00
# if HAS_DISPLAY
if ( frame_len = = 9 ) {
2022-11-01 21:11:41 +01:00
uint8_t line = cmdbuf [ 0 ] ;
2022-10-30 18:58:12 +01:00
if ( line > 63 ) line = 63 ;
int fb_o = line * 8 ;
2022-11-01 21:11:41 +01:00
memcpy ( fb + fb_o , cmdbuf + 1 , 8 ) ;
2022-10-30 18:58:12 +01:00
}
# endif
2022-10-29 00:53:39 +02:00
} else if ( command = = CMD_FB_READ ) {
if ( sbyte ! = 0x00 ) {
kiss_indicate_fb ( ) ;
}
2024-12-08 13:49:07 +01:00
} else if ( command = = CMD_DISP_READ ) {
if ( sbyte ! = 0x00 ) { kiss_indicate_disp ( ) ; }
2022-11-01 21:11:41 +01:00
} else if ( command = = CMD_DEV_HASH ) {
if ( sbyte ! = 0x00 ) {
kiss_indicate_device_hash ( ) ;
}
} else if ( command = = CMD_DEV_SIG ) {
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
if ( frame_len < CMD_L ) cmdbuf [ frame_len + + ] = sbyte ;
}
if ( frame_len = = DEV_SIG_LEN ) {
memcpy ( dev_sig , cmdbuf , DEV_SIG_LEN ) ;
device_save_signature ( ) ;
}
2022-11-03 00:58:45 +01:00
} else if ( command = = CMD_FW_UPD ) {
if ( sbyte = = 0x01 ) {
firmware_update_mode = true ;
} else {
firmware_update_mode = false ;
}
2022-11-01 22:21:07 +01:00
} else if ( command = = CMD_HASHES ) {
if ( sbyte = = 0x01 ) {
kiss_indicate_target_fw_hash ( ) ;
} else if ( sbyte = = 0x02 ) {
kiss_indicate_fw_hash ( ) ;
} else if ( sbyte = = 0x03 ) {
kiss_indicate_bootloader_hash ( ) ;
} else if ( sbyte = = 0x04 ) {
kiss_indicate_partition_table_hash ( ) ;
}
2022-11-01 21:11:41 +01:00
} else if ( command = = CMD_FW_HASH ) {
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
if ( frame_len < CMD_L ) cmdbuf [ frame_len + + ] = sbyte ;
}
if ( frame_len = = DEV_HASH_LEN ) {
2023-12-10 22:40:06 +01:00
memcpy ( dev_firmware_hash_target , cmdbuf , DEV_HASH_LEN ) ;
2022-11-01 21:11:41 +01:00
device_save_firmware_hash ( ) ;
}
2022-10-30 13:51:36 +01:00
} else if ( command = = CMD_BT_CTRL ) {
2024-04-23 00:52:57 +02:00
# if HAS_BLUETOOTH || HAS_BLE
2022-10-30 13:51:36 +01:00
if ( sbyte = = 0x00 ) {
2022-10-30 14:52:22 +01:00
bt_stop ( ) ;
bt_conf_save ( false ) ;
2022-10-30 13:51:36 +01:00
} else if ( sbyte = = 0x01 ) {
2022-10-30 14:52:22 +01:00
bt_start ( ) ;
bt_conf_save ( true ) ;
2022-10-30 13:51:36 +01:00
} else if ( sbyte = = 0x02 ) {
2024-10-12 18:04:19 +01:00
if ( bt_state = = BT_STATE_OFF ) {
bt_start ( ) ;
bt_conf_save ( true ) ;
}
if ( bt_state ! = BT_STATE_CONNECTED ) {
bt_enable_pairing ( ) ;
}
2022-10-30 13:51:36 +01:00
}
# endif
2022-11-01 21:11:41 +01:00
} else if ( command = = CMD_DISP_INT ) {
# if HAS_DISPLAY
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
display_intensity = sbyte ;
2023-05-03 14:05:49 +02:00
di_conf_save ( display_intensity ) ;
2024-09-29 02:33:02 +02:00
display_unblank ( ) ;
2022-11-01 21:11:41 +01:00
}
2023-09-19 18:32:29 +02:00
# endif
} else if ( command = = CMD_DISP_ADDR ) {
# if HAS_DISPLAY
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
display_addr = sbyte ;
da_conf_save ( display_addr ) ;
}
2024-10-12 18:04:19 +01:00
# endif
} else if ( command = = CMD_DISP_BLNK ) {
# if HAS_DISPLAY
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
db_conf_save ( sbyte ) ;
2024-09-29 02:33:02 +02:00
display_unblank ( ) ;
2024-10-12 18:04:19 +01:00
}
# endif
2024-12-31 13:23:48 +01:00
} else if ( command = = CMD_DISP_ROT ) {
# if HAS_DISPLAY
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
drot_conf_save ( sbyte ) ;
display_unblank ( ) ;
}
2024-12-31 14:13:52 +01:00
# endif
2025-01-09 17:58:46 +01:00
} else if ( command = = CMD_DIS_IA ) {
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
dia_conf_save ( sbyte ) ;
}
2024-12-31 14:13:52 +01:00
} else if ( command = = CMD_DISP_RCND ) {
# if HAS_DISPLAY
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
if ( sbyte > 0x00 ) recondition_display = true ;
}
2024-09-27 20:08:05 +02:00
# endif
2024-10-12 18:04:19 +01:00
} else if ( command = = CMD_NP_INT ) {
# if HAS_NP
if ( sbyte = = FESC ) {
ESCAPE = true ;
} else {
if ( ESCAPE ) {
if ( sbyte = = TFEND ) sbyte = FEND ;
if ( sbyte = = TFESC ) sbyte = FESC ;
ESCAPE = false ;
}
sbyte ;
led_set_intensity ( sbyte ) ;
np_int_conf_save ( sbyte ) ;
}
2022-11-01 21:11:41 +01:00
# endif
2018-04-05 18:10:42 +02:00
}
}
}
2022-01-14 21:12:33 +01:00
# if MCU_VARIANT == MCU_ESP32
portMUX_TYPE update_lock = portMUX_INITIALIZER_UNLOCKED ;
# endif
2025-02-03 17:25:02 +00:00
bool medium_free ( RadioInterface * radio ) {
radio - > updateModemStatus ( ) ;
if ( radio - > getAvdInterference ( ) & & radio - > getInterference ( ) ) { return false ; }
return ! radio - > getDCD ( ) ;
2018-04-26 15:52:43 +02:00
}
2022-11-01 21:11:41 +01:00
void validate_status ( ) {
2024-06-10 13:05:21 +01:00
# if MCU_VARIANT == MCU_ESP32
2022-01-09 23:40:30 +01:00
// TODO: Get ESP32 boot flags
uint8_t boot_flags = 0x02 ;
uint8_t F_POR = 0x00 ;
uint8_t F_BOR = 0x00 ;
uint8_t F_WDR = 0x01 ;
2024-01-19 10:08:55 +00:00
# elif MCU_VARIANT == MCU_NRF52
// TODO: Get NRF52 boot flags
uint8_t boot_flags = 0x02 ;
uint8_t F_POR = 0x00 ;
uint8_t F_BOR = 0x00 ;
uint8_t F_WDR = 0x01 ;
2022-01-09 23:40:30 +01:00
# endif
2022-11-01 21:11:41 +01:00
if ( hw_ready | | device_init_done ) {
hw_ready = false ;
Serial . write ( " Error, invalid hardware check state \r \n " ) ;
# if HAS_DISPLAY
2022-11-02 19:02:22 +01:00
if ( disp_ready ) {
device_init_done = true ;
update_display ( ) ;
}
2022-11-01 21:11:41 +01:00
# endif
led_indicate_boot_error ( ) ;
}
2022-01-09 23:40:30 +01:00
if ( boot_flags & ( 1 < < F_POR ) ) {
2021-12-26 11:27:32 +01:00
boot_vector = START_FROM_POWERON ;
2022-01-09 23:40:30 +01:00
} else if ( boot_flags & ( 1 < < F_BOR ) ) {
2021-12-26 11:27:32 +01:00
boot_vector = START_FROM_BROWNOUT ;
2022-01-09 23:40:30 +01:00
} else if ( boot_flags & ( 1 < < F_WDR ) ) {
2021-12-26 11:27:32 +01:00
boot_vector = START_FROM_BOOTLOADER ;
} else {
Serial . write ( " Error, indeterminate boot vector \r \n " ) ;
2022-10-29 16:44:49 +02:00
# if HAS_DISPLAY
2022-11-02 19:02:22 +01:00
if ( disp_ready ) {
device_init_done = true ;
update_display ( ) ;
}
2022-10-29 16:44:49 +02:00
# endif
2021-12-26 11:27:32 +01:00
led_indicate_boot_error ( ) ;
}
2022-01-09 23:40:30 +01:00
if ( boot_vector = = START_FROM_BOOTLOADER | | boot_vector = = START_FROM_POWERON ) {
2021-12-26 11:27:32 +01:00
if ( eeprom_lock_set ( ) ) {
if ( eeprom_product_valid ( ) & & eeprom_model_valid ( ) & & eeprom_hwrev_valid ( ) ) {
if ( eeprom_checksum_valid ( ) ) {
2022-11-03 00:58:45 +01:00
eeprom_ok = true ;
2024-06-10 13:05:21 +01:00
if ( modems_installed ) {
2024-09-12 10:57:16 -04:00
if ( device_init ( ) ) {
hw_ready = true ;
} else {
hw_ready = false ;
}
2023-01-07 16:35:07 +01:00
} else {
hw_ready = false ;
2024-10-12 18:04:19 +01:00
Serial . write ( " No radio module found \r \n " ) ;
2023-01-07 16:35:07 +01:00
# if HAS_DISPLAY
if ( disp_ready ) {
device_init_done = true ;
update_display ( ) ;
}
# endif
}
2022-11-03 00:58:45 +01:00
} else {
hw_ready = false ;
2024-10-12 18:04:19 +01:00
Serial . write ( " Invalid EEPROM checksum \r \n " ) ;
2022-11-03 00:58:45 +01:00
# if HAS_DISPLAY
if ( disp_ready ) {
device_init_done = true ;
update_display ( ) ;
}
# endif
2018-06-20 16:32:30 +02:00
}
2021-12-26 11:27:32 +01:00
} else {
hw_ready = false ;
2024-10-12 18:04:19 +01:00
Serial . write ( " Invalid EEPROM configuration \r \n " ) ;
2022-11-03 00:58:45 +01:00
# if HAS_DISPLAY
if ( disp_ready ) {
device_init_done = true ;
update_display ( ) ;
}
# endif
2018-06-20 08:45:11 +02:00
}
} else {
hw_ready = false ;
2024-10-12 18:04:19 +01:00
Serial . write ( " Device unprovisioned, no device configuration found in EEPROM \r \n " ) ;
2022-11-03 00:58:45 +01:00
# if HAS_DISPLAY
if ( disp_ready ) {
device_init_done = true ;
update_display ( ) ;
}
# endif
2018-06-20 08:45:11 +02:00
}
} else {
hw_ready = false ;
2021-12-26 11:27:32 +01:00
Serial . write ( " Error, incorrect boot vector \r \n " ) ;
2022-10-29 16:44:49 +02:00
# if HAS_DISPLAY
2022-11-02 19:02:22 +01:00
if ( disp_ready ) {
device_init_done = true ;
update_display ( ) ;
}
2022-10-29 16:44:49 +02:00
# endif
2021-12-26 11:27:32 +01:00
led_indicate_boot_error ( ) ;
2018-06-20 08:45:11 +02:00
}
}
2025-02-03 17:25:02 +00:00
void tx_queue_handler ( RadioInterface * radio ) {
if ( queue_height [ radio - > getIndex ( ) ] > 0 ) {
if ( radio - > getCW ( ) = = - 1 ) {
radio - > setCW ( random ( radio - > getCWMin ( ) , radio - > getCWMax ( ) ) ) ;
radio - > setCWWaitTarget ( radio - > getCW ( ) * radio - > getCSMASlotMS ( ) ) ;
2025-01-07 20:15:26 +01:00
}
2025-02-03 17:25:02 +00:00
if ( radio - > getDifsWaitStart ( ) = = 0 ) { // DIFS wait not yet started
if ( medium_free ( radio ) ) { radio - > setDifsWaitStart ( millis ( ) ) ; return ; } // Set DIFS wait start time
2025-01-07 20:15:26 +01:00
else { return ; } } // Medium not yet free, continue waiting
else { // We are waiting for DIFS or CW to pass
2025-02-03 17:25:02 +00:00
if ( ! medium_free ( radio ) ) { radio - > setDifsWaitStart ( 0 ) ; radio - > setCWWaitStart ( 0 ) ; return ; } // Medium became occupied while in DIFS wait, restart waiting when free again
2025-01-07 20:15:26 +01:00
else { // Medium is free, so continue waiting
2025-02-03 17:25:02 +00:00
if ( millis ( ) < radio - > getDifsWaitStart ( ) + radio - > getDifsMS ( ) ) { return ; } // DIFS has not yet passed, continue waiting
2025-01-07 20:15:26 +01:00
else { // DIFS has passed, and we are now in CW wait
2025-02-03 17:25:02 +00:00
if ( radio - > getCWWaitStart ( ) = = 0 ) { radio - > setCWWaitStart ( millis ( ) ) ; return ; } // If we haven't started counting CW wait time, do it from now
2025-01-07 20:15:26 +01:00
else { // If we are already counting CW wait time, add it to the counter
2025-02-03 17:25:02 +00:00
radio - > addCWWaitPassed ( millis ( ) - radio - > getCWWaitStart ( ) ) ; radio - > setCWWaitStart ( millis ( ) ) ;
if ( radio - > getCWWaitStatus ( ) ) { return ; } // Contention window wait time has not yet passed, continue waiting
2025-01-07 20:15:26 +01:00
else { // Wait time has passed, flush the queue
2025-02-03 17:25:02 +00:00
if ( ! radio - > getLimitRate ( ) ) { flush_queue ( radio ) ; } else { pop_queue ( radio ) ; }
radio - > resetCWWaitPassed ( ) ; radio - > setCW ( - 1 ) ; radio - > setDifsWaitStart ( 0 ) ; }
2025-01-07 20:15:26 +01:00
}
}
}
}
}
}
2025-01-15 18:38:14 +01:00
void work_while_waiting ( ) { loop ( ) ; }
2018-04-05 18:10:42 +02:00
void loop ( ) {
2024-10-12 18:04:19 +01:00
# if MCU_VARIANT == MCU_ESP32
modem_packet_t * modem_packet = NULL ;
if ( modem_packet_queue & & xQueueReceive ( modem_packet_queue , & modem_packet , 0 ) = = pdTRUE & & modem_packet ) {
2025-01-09 21:26:58 +00:00
uint8_t packet_interface = modem_packet - > interface ;
2024-10-22 18:02:46 +01:00
read_len [ packet_interface ] = modem_packet - > len ;
2024-10-12 18:04:19 +01:00
last_rssi = modem_packet - > rssi ;
last_snr_raw = modem_packet - > snr_raw ;
memcpy ( & pbuf , modem_packet - > data , modem_packet - > len ) ;
free ( modem_packet ) ;
modem_packet = NULL ;
2025-01-09 21:26:58 +00:00
kiss_indicate_stat_rssi ( interface_obj [ packet_interface ] ) ;
kiss_indicate_stat_snr ( interface_obj [ packet_interface ] ) ;
2024-09-11 21:49:27 +01:00
kiss_write_packet ( packet_interface ) ;
2024-10-12 18:04:19 +01:00
}
# elif MCU_VARIANT == MCU_NRF52
modem_packet_t * modem_packet = NULL ;
if ( modem_packet_queue & & xQueueReceive ( modem_packet_queue , & modem_packet , 0 ) = = pdTRUE & & modem_packet ) {
2025-01-09 21:26:58 +00:00
uint8_t packet_interface = modem_packet - > interface ;
2024-10-22 18:02:46 +01:00
read_len [ packet_interface ] = modem_packet - > len ;
2024-10-12 18:04:19 +01:00
last_rssi = modem_packet - > rssi ;
last_snr_raw = modem_packet - > snr_raw ;
2024-10-22 18:02:46 +01:00
memcpy ( & pbuf , modem_packet - > data , modem_packet - > len ) ;
2024-10-12 18:04:19 +01:00
free ( modem_packet ) ;
modem_packet = NULL ;
2025-02-03 17:25:02 +00:00
kiss_indicate_stat_rssi ( interface_obj [ packet_interface ] ) ;
kiss_indicate_stat_snr ( interface_obj [ packet_interface ] ) ;
2024-10-12 18:04:19 +01:00
kiss_write_packet ( packet_interface ) ;
}
# endif
2024-07-03 11:06:52 +01:00
2024-06-10 13:05:21 +01:00
bool ready = false ;
2024-07-03 11:06:52 +01:00
for ( int i = 0 ; i < INTERFACE_COUNT ; i + + ) {
selected_radio = interface_obj [ i ] ;
if ( selected_radio - > getRadioOnline ( ) ) {
ready = true ;
}
}
2024-06-10 13:05:21 +01:00
2024-07-03 11:06:52 +01:00
// If at least one radio is online then we can continue
2024-06-10 13:05:21 +01:00
if ( ready ) {
for ( int i = 0 ; i < INTERFACE_COUNT ; i + + ) {
selected_radio = interface_obj_sorted [ i ] ;
2020-05-28 22:18:19 +02:00
2024-06-10 13:05:21 +01:00
if ( selected_radio - > calculateALock ( ) | | ! selected_radio - > getRadioOnline ( ) ) {
// skip this interface
continue ;
}
2025-02-03 17:25:02 +00:00
tx_queue_handler ( selected_radio ) ;
selected_radio - > checkModemStatus ( ) ;
2018-04-26 15:52:43 +02:00
}
2018-06-27 10:22:44 +02:00
2018-06-18 22:30:24 +02:00
} else {
2018-06-20 08:45:11 +02:00
if ( hw_ready ) {
2023-01-06 22:29:23 +01:00
if ( console_active ) {
2023-01-11 09:42:11 +01:00
# if HAS_CONSOLE
console_loop ( ) ;
# endif
2023-01-06 22:29:23 +01:00
} else {
2023-01-10 14:27:03 +01:00
led_indicate_standby ( ) ;
2023-01-06 22:29:23 +01:00
}
2018-06-20 08:45:11 +02:00
} else {
led_indicate_not_ready ( ) ;
2024-06-10 13:05:21 +01:00
// shut down all radio interfaces
for ( int i = 0 ; i < INTERFACE_COUNT ; i + + ) {
stopRadio ( interface_obj [ i ] ) ;
}
2018-06-20 08:45:11 +02:00
}
2018-04-26 15:52:43 +02:00
}
2025-02-03 17:25:02 +00:00
process_serial ( ) ;
2022-10-29 00:53:39 +02:00
# if HAS_DISPLAY
2024-07-03 11:06:52 +01:00
# if DISPLAY == OLED
2022-10-29 16:44:49 +02:00
if ( disp_ready ) update_display ( ) ;
2024-07-03 11:06:52 +01:00
# elif DISPLAY == EINK_BW || DISPLAY == EINK_3C
// Display refreshes take so long on e-paper displays that they can disrupt
// the regular operation of the device. To combat this the time it is
// chosen to do so must be strategically chosen. Particularly on the
// RAK4631, the display and the potentially installed SX1280 modem share
// the same SPI bus. Thus it is not possible to solve this by utilising the
// callback functionality to poll the modem in this case. todo, this may be
// able to be improved in the future.
if ( disp_ready ) {
if ( millis ( ) - last_tx > = 4000 ) {
if ( millis ( ) - last_rx > = 1000 ) {
update_display ( ) ;
}
}
}
# endif
2022-10-29 00:53:39 +02:00
# endif
# if HAS_PMU
2022-10-29 16:44:49 +02:00
if ( pmu_ready ) update_pmu ( ) ;
2022-10-29 00:53:39 +02:00
# endif
2022-10-30 13:51:36 +01:00
2024-04-23 00:52:57 +02:00
# if HAS_BLUETOOTH || HAS_BLE == true
2023-01-07 16:35:07 +01:00
if ( ! console_active & & bt_ready ) update_bt ( ) ;
2022-10-30 13:51:36 +01:00
# endif
2024-05-02 01:20:33 +02:00
# if HAS_INPUT
input_read ( ) ;
# endif
2024-10-12 18:04:19 +01:00
if ( memory_low ) {
# if PLATFORM == PLATFORM_ESP32
if ( esp_get_free_heap_size ( ) < 8192 ) {
kiss_indicate_error ( ERROR_MEMORY_LOW ) ; memory_low = false ;
} else {
memory_low = false ;
}
# else
kiss_indicate_error ( ERROR_MEMORY_LOW ) ; memory_low = false ;
# endif
}
2024-05-02 01:20:33 +02:00
}
2024-05-20 20:14:16 +01:00
void process_serial ( ) {
buffer_serial ( ) ;
if ( ! fifo_isempty ( & serialFIFO ) ) serial_poll ( ) ;
}
2024-05-02 01:20:33 +02:00
void sleep_now ( ) {
# if HAS_SLEEP == true
2025-01-15 11:01:26 +01:00
# if PLATFORM == PLATFORM_ESP32
# if BOARD_MODEL == BOARD_T3S3
display_intensity = 0 ;
update_display ( true ) ;
# endif
# if PIN_DISP_SLEEP >= 0
pinMode ( PIN_DISP_SLEEP , OUTPUT ) ;
digitalWrite ( PIN_DISP_SLEEP , DISP_SLEEP_LEVEL ) ;
# endif
# if HAS_BLUETOOTH
if ( bt_state = = BT_STATE_CONNECTED ) {
bt_stop ( ) ;
delay ( 100 ) ;
}
# endif
esp_sleep_enable_ext0_wakeup ( PIN_WAKEUP , WAKEUP_LEVEL ) ;
esp_deep_sleep_start ( ) ;
# elif PLATFORM == PLATFORM_NRF52
# if BOARD_MODEL == BOARD_HELTEC_T114
npset ( 0 , 0 , 0 ) ;
2025-01-15 18:38:14 +01:00
digitalWrite ( PIN_VEXT_EN , LOW ) ;
2025-01-15 11:01:26 +01:00
digitalWrite ( PIN_T114_TFT_BLGT , HIGH ) ;
digitalWrite ( PIN_T114_TFT_EN , HIGH ) ;
2025-01-15 18:38:14 +01:00
# elif BOARD_MODEL == BOARD_TECHO
2025-01-16 11:00:39 +01:00
for ( uint8_t i = display_intensity ; i > 0 ; i - - ) { analogWrite ( pin_backlight , i - 1 ) ; delay ( 1 ) ; }
2025-01-16 12:20:01 +01:00
epd_black ( true ) ; delay ( 300 ) ; epd_black ( true ) ; delay ( 300 ) ; epd_black ( false ) ;
delay ( 2000 ) ;
2025-01-16 11:00:39 +01:00
analogWrite ( PIN_VEXT_EN , 0 ) ;
2024-10-12 18:04:19 +01:00
delay ( 100 ) ;
2025-01-15 11:01:26 +01:00
# endif
sd_power_gpregret_set ( 0 , 0x6d ) ;
nrf_gpio_cfg_sense_input ( pin_btn_usr1 , NRF_GPIO_PIN_PULLUP , NRF_GPIO_PIN_SENSE_LOW ) ;
NRF_POWER - > SYSTEMOFF = 1 ;
2024-10-12 18:04:19 +01:00
# endif
2024-05-02 01:20:33 +02:00
# endif
}
void button_event ( uint8_t event , unsigned long duration ) {
2024-10-01 17:40:18 +02:00
if ( display_blanked ) {
display_unblank ( ) ;
} else {
2024-10-12 18:04:19 +01:00
if ( duration > 10000 ) {
# if HAS_CONSOLE
# if HAS_BLUETOOTH || HAS_BLE
bt_stop ( ) ;
# endif
console_active = true ;
console_start ( ) ;
# endif
} else if ( duration > 5000 ) {
# if HAS_BLUETOOTH || HAS_BLE
if ( bt_state ! = BT_STATE_CONNECTED ) { bt_enable_pairing ( ) ; }
# endif
} else if ( duration > 700 ) {
# if HAS_SLEEP
sleep_now ( ) ;
# endif
} else {
# if HAS_BLUETOOTH || HAS_BLE
if ( bt_state ! = BT_STATE_CONNECTED ) {
if ( bt_state = = BT_STATE_OFF ) {
bt_start ( ) ;
bt_conf_save ( true ) ;
} else {
bt_stop ( ) ;
bt_conf_save ( false ) ;
}
}
# endif
}
2024-09-27 00:27:24 +02:00
}
2020-05-28 22:18:19 +02:00
}
2024-07-03 11:06:52 +01:00
void poll_buffers ( ) {
process_serial ( ) ;
}
2020-05-29 14:58:10 +02:00
volatile bool serial_polling = false ;
2020-05-28 22:18:19 +02:00
void serial_poll ( ) {
2020-05-29 14:58:10 +02:00
serial_polling = true ;
2022-01-09 23:40:30 +01:00
while ( ! fifo_isempty ( & serialFIFO ) ) {
2020-05-29 14:58:10 +02:00
char sbyte = fifo_pop ( & serialFIFO ) ;
2025-01-07 20:43:15 +01:00
serial_callback ( sbyte ) ;
2020-05-28 22:18:19 +02:00
}
2020-05-29 14:58:10 +02:00
serial_polling = false ;
2020-05-28 22:18:19 +02:00
}
2024-06-10 13:05:21 +01:00
# define MAX_CYCLES 20
2020-05-28 22:18:19 +02:00
void buffer_serial ( ) {
2020-05-29 14:58:10 +02:00
if ( ! serial_buffering ) {
serial_buffering = true ;
uint8_t c = 0 ;
2022-10-30 18:35:53 +01:00
2024-04-23 00:52:57 +02:00
# if HAS_BLUETOOTH || HAS_BLE == true
2022-10-30 18:35:53 +01:00
while (
c < MAX_CYCLES & &
( ( bt_state ! = BT_STATE_CONNECTED & & Serial . available ( ) ) | | ( bt_state = = BT_STATE_CONNECTED & & SerialBT . available ( ) ) )
)
# else
while ( c < MAX_CYCLES & & Serial . available ( ) )
# endif
{
2020-05-29 14:58:10 +02:00
c + + ;
2024-06-10 13:05:21 +01:00
# if HAS_BLUETOOTH || HAS_BLE == true
2024-01-21 09:05:02 +00:00
if ( bt_state = = BT_STATE_CONNECTED ) {
2022-10-30 18:35:53 +01:00
if ( ! fifo_isfull ( & serialFIFO ) ) {
fifo_push ( & serialFIFO , SerialBT . read ( ) ) ;
}
} else {
if ( ! fifo_isfull ( & serialFIFO ) ) {
fifo_push ( & serialFIFO , Serial . read ( ) ) ;
}
2022-01-09 23:40:30 +01:00
}
2024-01-21 09:05:02 +00:00
# else
if ( ! fifo_isfull ( & serialFIFO ) ) {
fifo_push ( & serialFIFO , Serial . read ( ) ) ;
}
2022-01-09 23:40:30 +01:00
# endif
2018-06-27 10:22:44 +02:00
}
2020-05-29 14:58:10 +02:00
serial_buffering = false ;
2018-04-05 18:10:42 +02:00
}
}