This commit is contained in:
jacob.eva 2024-10-11 18:54:40 +01:00
parent 6ed29517c7
commit 0aaf722088
No known key found for this signature in database
GPG Key ID: 0B92E083BBCCAA1E
25 changed files with 1028 additions and 576 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ Release/*.zip
Release/*.json Release/*.json
Console/build Console/build
build/* build/*
.vscode

View File

@ -259,9 +259,34 @@ void bt_disable_pairing() {
void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) { void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) {
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
BLEConnection* connection = Bluefruit.Connection(conn_handle);
ble_gap_conn_sec_mode_t security = connection->getSecureMode();
// On the NRF52 it is not possible with the Arduino library to reject
// requests from devices with no IO capabilities, which would allow
// bypassing pin entry through pairing using the "just works" mode.
// Therefore, we must check the security level of the connection after
// pairing to ensure "just works" has not been used. If it has, we need
// to disconnect, unpair and delete any bonding information immediately.
// Settings on the SerialBT service should prevent unauthorised access to
// the serial port anyway, but this is still wise to do regardless.
//
// Note: It may be nice to have this done in the BLESecurity class in the
// future, but as it stands right now I'd have to fork the BSP to do
// that, which I don't fancy doing. Impact on security is likely minimal.
// Requires investigation.
if (security.sm == 1 && security.lv >= 3) {
bt_state = BT_STATE_CONNECTED; bt_state = BT_STATE_CONNECTED;
cable_state = CABLE_STATE_DISCONNECTED; cable_state = CABLE_STATE_DISCONNECTED;
bt_disable_pairing(); bt_disable_pairing();
} else {
if (connection->bonded()) {
connection->removeBondKey();
}
connection->disconnect();
}
} else { } else {
bt_ssp_pin = 0; bt_ssp_pin = 0;
} }
@ -273,21 +298,26 @@ bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool ma
bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i); bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i);
} }
kiss_indicate_btpin(); kiss_indicate_btpin();
if (match_request) {
if (bt_allow_pairing) { if (bt_allow_pairing) {
return true; return true;
} }
}
return false; return false;
} }
void bt_connect_callback(uint16_t conn_handle) { void bt_connect_callback(uint16_t conn_handle) {
bt_state = BT_STATE_CONNECTED; bt_state = BT_STATE_CONNECTED;
cable_state = CABLE_STATE_DISCONNECTED; cable_state = CABLE_STATE_DISCONNECTED;
BLEConnection* conn = Bluefruit.Connection(conn_handle);
conn->requestPHY(BLE_GAP_PHY_2MBPS);
conn->requestMtuExchange(512+3);
conn->requestDataLengthUpdate();
} }
void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) { void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) {
if (reason != BLE_GAP_SEC_STATUS_SUCCESS) {
bt_state = BT_STATE_ON; bt_state = BT_STATE_ON;
}
} }
bool bt_setup_hw() { bool bt_setup_hw() {
@ -305,11 +335,20 @@ bool bt_setup_hw() {
Bluefruit.autoConnLed(false); Bluefruit.autoConnLed(false);
if (Bluefruit.begin()) { if (Bluefruit.begin()) {
Bluefruit.setTxPower(8); // Check bluefruit.h for supported values Bluefruit.setTxPower(8); // Check bluefruit.h for supported values
Bluefruit.Security.setIOCaps(true, true, false); Bluefruit.Security.setIOCaps(true, false, false); // display, yes; yes / no, no; keyboard, no
// This device is indeed capable of yes / no through the pairing mode
// being set, but I have chosen to set it thus to force the input of the
// pin on the device initiating the pairing. This prevents it from being
// paired with automatically by a hypothetical malicious device nearby
// without physical access to the RNode.
Bluefruit.Security.setMITM(true);
Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback); Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback);
Bluefruit.Periph.setConnectCallback(bt_connect_callback); Bluefruit.Security.setSecuredCallback(bt_connect_callback);
Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback); Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback);
Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete); Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete);
Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms
const ble_gap_addr_t gap_addr = Bluefruit.getAddr(); const ble_gap_addr_t gap_addr = Bluefruit.getAddr();
char *data = (char*)malloc(BT_DEV_ADDR_LEN+1); char *data = (char*)malloc(BT_DEV_ADDR_LEN+1);
for (int i = 0; i < BT_DEV_ADDR_LEN; i++) { for (int i = 0; i < BT_DEV_ADDR_LEN; i++) {
@ -340,6 +379,9 @@ void bt_start() {
// start device information service // start device information service
bledis.begin(); bledis.begin();
SerialBT.bufferTXD(true); // enable buffering
SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial
SerialBT.begin(); SerialBT.begin();
blebas.begin(); blebas.begin();

125
Boards.h
View File

@ -39,6 +39,8 @@
#define BOARD_RNODE_NG_20 0x40 #define BOARD_RNODE_NG_20 0x40
#define BOARD_RNODE_NG_21 0x41 #define BOARD_RNODE_NG_21 0x41
#define BOARD_T3S3 0x42 #define BOARD_T3S3 0x42
#define BOARD_TECHO 0x43
#define BOARD_E22_ESP32 0x44
#define BOARD_GENERIC_NRF52 0x50 #define BOARD_GENERIC_NRF52 0x50
#define BOARD_RAK4631 0x51 #define BOARD_RAK4631 0x51
@ -50,7 +52,7 @@
#if defined(ESP32) #if defined(ESP32)
#define PLATFORM PLATFORM_ESP32 #define PLATFORM PLATFORM_ESP32
#define MCU_VARIANT MCU_ESP32 #define MCU_VARIANT MCU_ESP32
#elif defined(NRF52840_XXAA) #elif defined(NRF52840_XXAA) || defined(_VARIANT_PCA10056_)
#include <variant.h> #include <variant.h>
#define PLATFORM PLATFORM_NRF52 #define PLATFORM PLATFORM_NRF52
#define MCU_VARIANT MCU_NRF52 #define MCU_VARIANT MCU_NRF52
@ -624,12 +626,110 @@
-1 // pin_tcxo_enable -1 // pin_tcxo_enable
} }
}; };
#elif BOARD_MODEL == BOARD_E22_ESP32
#define HAS_DISPLAY true
#define DISPLAY OLED
#define HAS_BLUETOOTH true
#define HAS_BLE true
#define HAS_CONSOLE true
#define HAS_SD false
#define HAS_EEPROM true
#define I2C_SDA 21
#define I2C_SCL 22
#define INTERFACE_COUNT 1
const int pin_led_rx = 2;
const int pin_led_tx = 4;
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
5, // pin_sclk
27, // pin_mosi
19, // pin_miso
32, // pin_busy
33, // pin_dio
23, // pin_reset
-1, // pin_txen
14, // pin_rxen
-1 // pin_tcxo_enable
}
};
#else #else
#error An unsupported ESP32 board was selected. Cannot compile RNode firmware. #error An unsupported ESP32 board was selected. Cannot compile RNode firmware.
#endif #endif
#elif MCU_VARIANT == MCU_NRF52 #elif MCU_VARIANT == MCU_NRF52
#if BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_FREENODE #if BOARD_MODEL == BOARD_TECHO
#define VALIDATE_FIRMWARE false
//#define GPS_BAUD_RATE 115200
//#define PIN_GPS_TX 41
//#define PIN_GPS_RX 40
#define EEPROM_SIZE 296
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
//#define HAS_EEPROM true
//#define HAS_SD true
//#define HAS_DISPLAY true
//#define HAS_CONSOLE true
//#define HAS_TXCO true
//#define DISPLAY EINK_BW
//#define HAS_BLE true
//#define HAS_PMU true
#define CONFIG_UART_BUFFER_SIZE 40000
#define CONFIG_QUEUE_0_SIZE 6144
#define CONFIG_QUEUE_MAX_LENGTH 200
#define BLE_MANUFACTURER "LilyGO"
#define BLE_MODEL "T-Echo"
#define INTERFACE_COUNT 1
//#define I2C_SDA 26
//#define I2C_SCL 27
#define CONFIG_QUEUE_1_SIZE 40000
// first interface in list is the primary
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1262
{
false, // DEFAULT_SPI
true, // HAS_TCXO
true // DIO2_AS_RF_SWITCH
}
};
const int8_t interface_pins[INTERFACE_COUNT][10] = {
// SX1262
{
24, // pin_ss
19, // pin_sclk
22, // pin_mosi
23, // pin_miso
17, // pin_busy
20, // pin_dio
25, // pin_reset
-1, // pin_txen
-1, // pin_rxen
21 // pin_tcxo_enable
}
};
const int pin_disp_cs = 30;
const int pin_disp_dc = 28;
const int pin_disp_reset = 2;
const int pin_disp_busy = 3;
const int pin_disp_en = 43;
const int pin_led_rx = LED_BLUE;
const int pin_led_tx = LED_RED;
#elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_FREENODE
#define HAS_EEPROM false #define HAS_EEPROM false
#define HAS_DISPLAY true #define HAS_DISPLAY true
#define DISPLAY EINK_BW #define DISPLAY EINK_BW
@ -639,7 +739,7 @@
#define HAS_PMU true #define HAS_PMU true
#define HAS_NP false #define HAS_NP false
#define HAS_SD false #define HAS_SD false
#define CONFIG_UART_BUFFER_SIZE 6144 #define CONFIG_UART_BUFFER_SIZE 40000
#define CONFIG_QUEUE_0_SIZE 6144 #define CONFIG_QUEUE_0_SIZE 6144
#define CONFIG_QUEUE_MAX_LENGTH 200 #define CONFIG_QUEUE_MAX_LENGTH 200
#define EEPROM_SIZE 296 #define EEPROM_SIZE 296
@ -678,7 +778,7 @@
#elif BOARD_VARIANT == MODEL_13 || BOARD_VARIANT == MODEL_14 || BOARD_VARIANT == MODEL_21 #elif BOARD_VARIANT == MODEL_13 || BOARD_VARIANT == MODEL_14 || BOARD_VARIANT == MODEL_21
#define INTERFACE_COUNT 2 #define INTERFACE_COUNT 2
#define CONFIG_QUEUE_1_SIZE 20000 #define CONFIG_QUEUE_1_SIZE 40000
// first interface in list is the primary // first interface in list is the primary
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X, SX128X}; const uint8_t interfaces[INTERFACE_COUNT] = {SX126X, SX128X};
@ -726,17 +826,6 @@
}; };
#endif #endif
#define INTERFACE_SPI
// Required because on RAK4631, non-default SPI pins must be initialised when class is declared.
const SPIClass interface_spi[1] = {
// SX1262
SPIClass(
NRF_SPIM2,
interface_pins[0][3],
interface_pins[0][1],
interface_pins[0][2]
)
};
const int pin_disp_cs = SS; const int pin_disp_cs = SS;
const int pin_disp_dc = WB_IO1; const int pin_disp_dc = WB_IO1;
@ -752,10 +841,4 @@
#endif #endif
#endif #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
const SPIClass interface_spi[1];
#endif
#endif #endif

View File

@ -29,6 +29,8 @@
#define CABLE_STATE_CONNECTED 0x01 #define CABLE_STATE_CONNECTED 0x01
uint8_t cable_state = CABLE_STATE_DISCONNECTED; uint8_t cable_state = CABLE_STATE_DISCONNECTED;
#define MAX_INTERFACES 12
#define BT_STATE_NA 0xff #define BT_STATE_NA 0xff
#define BT_STATE_OFF 0x00 #define BT_STATE_OFF 0x00
#define BT_STATE_ON 0x01 #define BT_STATE_ON 0x01
@ -78,6 +80,9 @@
bool implicit = false; bool implicit = false;
uint8_t implicit_l = 0; uint8_t implicit_l = 0;
volatile bool packet_ready = false;
volatile uint8_t packet_interface = 0xFF;
uint8_t op_mode = MODE_HOST; uint8_t op_mode = MODE_HOST;
uint8_t model = 0x00; uint8_t model = 0x00;
uint8_t hwrev = 0x00; uint8_t hwrev = 0x00;
@ -88,6 +93,12 @@
uint8_t seq = 0xFF; uint8_t seq = 0xFF;
uint16_t read_len = 0; uint16_t read_len = 0;
bool serial_in_frame = false;
FIFOBuffer packet_rdy_interfaces;
uint8_t packet_rdy_interfaces_buf[MAX_INTERFACES];
// Incoming packet buffer // Incoming packet buffer
uint8_t pbuf[MTU]; uint8_t pbuf[MTU];

View File

@ -14,10 +14,10 @@ dirs:
@mkdir -p ./build/images @mkdir -p ./build/images
pages: pages:
python ./build.py python3 ./build.py
pages-debug: pages-debug:
python ./build.py --no-gz --no-remap python3 ./build.py --no-gz --no-remap
sourcepack: sourcepack:
@echo Packing firmware sources... @echo Packing firmware sources...
@ -44,4 +44,4 @@ site: clean external dirs data sourcepack pages
local: clean external dirs data sourcepack pages-debug local: clean external dirs data sourcepack pages-debug
serve: serve:
python -m http.server 7777 --bind 127.0.0.1 --directory ./build python3 -m http.server 7777 --bind 127.0.0.1 --directory ./build

View File

@ -259,14 +259,12 @@ void device_validate_partitions() {
// todo, add bootloader, partition table, or softdevice? // todo, add bootloader, partition table, or softdevice?
calculate_region_hash(APPLICATION_START, USER_DATA_START, dev_firmware_hash); calculate_region_hash(APPLICATION_START, USER_DATA_START, dev_firmware_hash);
#endif #endif
#if VALIDATE_FIRMWARE
for (uint8_t i = 0; i < DEV_HASH_LEN; i++) { for (uint8_t i = 0; i < DEV_HASH_LEN; i++) {
if (dev_firmware_hash_target[i] != dev_firmware_hash[i]) { if (dev_firmware_hash_target[i] != dev_firmware_hash[i]) {
fw_signature_validated = false; fw_signature_validated = false;
break; break;
} }
} }
#endif
} }
bool device_firmware_ok() { bool device_firmware_ok() {
@ -275,6 +273,7 @@ bool device_firmware_ok() {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
bool device_init() { bool device_init() {
#if VALIDATE_FIRMWARE
if (bt_ready) { if (bt_ready) {
#if MCU_VARIANT == MCU_ESP32 #if MCU_VARIANT == MCU_ESP32
for (uint8_t i=0; i<EEPROM_SIG_LEN; i++){dev_eeprom_signature[i]=EEPROM.read(eeprom_addr(ADDR_SIGNATURE+i));} for (uint8_t i=0; i<EEPROM_SIG_LEN; i++){dev_eeprom_signature[i]=EEPROM.read(eeprom_addr(ADDR_SIGNATURE+i));}
@ -310,9 +309,9 @@ bool device_init() {
hash.end(dev_hash); hash.end(dev_hash);
#endif #endif
device_load_signature(); device_load_signature();
device_validate_signature(); device_validate_signature();
device_validate_partitions(); device_validate_partitions();
#if MCU_VARIANT == MCU_NRF52 #if MCU_VARIANT == MCU_NRF52
@ -323,5 +322,9 @@ bool device_init() {
} else { } else {
return false; return false;
} }
#else
// Skip hash comparison and checking BT
return true;
#endif
} }
#endif #endif

View File

@ -106,15 +106,23 @@ void busyCallback(const void* p) {
#if DISPLAY == OLED #if DISPLAY == OLED
Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST); Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST);
float disp_target_fps = 7; float disp_target_fps = 7;
#define SCREENSAVER_TIME 500 // ms
uint32_t last_screensaver = 0;
#define SCREENSAVER_INTERVAL 600000 // 10 minutes in ms
bool screensaver_enabled = false;
#endif #endif
#endif #endif
#if BOARD_MODEL == BOARD_RAK4631 #if BOARD_MODEL == BOARD_RAK4631
#if DISPLAY == EINK_BW #if DISPLAY == EINK_BW
GxEPD2_BW<DISPLAY_MODEL, DISPLAY_MODEL::HEIGHT> display(DISPLAY_MODEL(pin_disp_cs, pin_disp_dc, pin_disp_reset, pin_disp_busy)); GxEPD2_BW<DISPLAY_MODEL, DISPLAY_MODEL::HEIGHT> display(DISPLAY_MODEL(pin_disp_cs, pin_disp_dc, pin_disp_reset, pin_disp_busy));
float disp_target_fps = 0.2; float disp_target_fps = 0.2;
uint32_t last_epd_refresh = 0;
#define REFRESH_PERIOD 300000 // 5 minutes in ms
#elif DISPLAY == EINK_3C #elif DISPLAY == EINK_3C
GxEPD2_3C<DISPLAY_MODEL, DISPLAY_MODEL::HEIGHT> display(DISPLAY_MODEL(pin_disp_cs, pin_disp_dc, pin_disp_reset, pin_disp_busy)); GxEPD2_3C<DISPLAY_MODEL, DISPLAY_MODEL::HEIGHT> display(DISPLAY_MODEL(pin_disp_cs, pin_disp_dc, pin_disp_reset, pin_disp_busy));
float disp_target_fps = 0.05; // refresh usually takes longer on 3C, hence 4x the refresh period float disp_target_fps = 0.05; // refresh usually takes longer on 3C, hence this is 4x the BW refresh period
uint32_t last_epd_refresh = 0;
#define REFRESH_PERIOD 600000 // 10 minutes in ms
#endif #endif
#else #else
// add more eink compatible boards here // add more eink compatible boards here
@ -129,6 +137,7 @@ uint8_t disp_ext_fb = false;
unsigned char fb[512]; unsigned char fb[512];
uint32_t last_disp_update = 0; uint32_t last_disp_update = 0;
int disp_update_interval = 1000/disp_target_fps; int disp_update_interval = 1000/disp_target_fps;
uint32_t last_page_flip = 0; uint32_t last_page_flip = 0;
uint32_t last_interface_page_flip = 0; uint32_t last_interface_page_flip = 0;
int page_interval = 4000; int page_interval = 4000;
@ -1111,14 +1120,37 @@ void update_display(bool blank = false) {
update_stat_area(); update_stat_area();
update_disp_area(); update_disp_area();
display.display(); display.display();
uint32_t current = millis();
// Invert display to protect against OLED screen burn in
if (screensaver_enabled) {
if (current-last_screensaver >= SCREENSAVER_INTERVAL+SCREENSAVER_TIME) {
display.invertDisplay(0);
last_screensaver = current;
screensaver_enabled = false;
}
}
else if (current-last_screensaver >= SCREENSAVER_INTERVAL) {
display.invertDisplay(1);
screensaver_enabled = true;
}
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
display.setFullWindow(); display.setFullWindow();
display.fillScreen(GxEPD_WHITE); display.fillScreen(GxEPD_WHITE);
update_stat_area(); update_stat_area();
update_disp_area(); update_disp_area();
uint32_t current = millis();
if (current-last_epd_refresh >= REFRESH_PERIOD) {
// Perform a full refresh after the correct time has elapsed
display.display(false);
last_epd_refresh = current;
} else {
// Only perform a partial refresh
display.display(true); display.display(true);
}
#endif #endif
last_disp_update = millis(); last_disp_update = current;
} }
} }
} }

View File

@ -1,6 +1,6 @@
# Building # Building
## Prerequisites ## Prerequisites
The build system of this repository is based on Make. The `Makefile` is in the base of the repository. Please ensure you have `arduino-cli` installed before proceeding. The build system of this repository is based on GNU Make. The `Makefile` is in the base of the repository. Please ensure you have `arduino-cli`, `python3` and `make` installed before proceeding.
Firstly, figure out which MCU platform your supported board is based on. The table below can help you. Firstly, figure out which MCU platform your supported board is based on. The table below can help you.
@ -54,6 +54,60 @@ Ensure you replace [target] with the target you selected. For example:
`make upload-rak4631` `make upload-rak4631`
If you are flashing a custom board, you will need to generate a signing key in rnodeconf prior to flashing if you do not already have one by running:
`rnodeconf -k`
After flashing a custom board, you will also need to provision the EEPROM before use:
`rnodeconf /dev/ttyACM0 -r --platform ESP32 --model a9 --product f0 --hwrev 3`
- platform must either be AVR, ESP32 or NRF52
- hwrev is required (any integer between 1 and 255)
- model should be something from the list below without the leading `0x` and in lowercase (example `e8`):
```
0x11: [430000000, 510000000, 22, "430 - 510 MHz", "rnode_firmware_rak4631.zip", "SX1262"],
0x12: [779000000, 928000000, 22, "779 - 928 MHz", "rnode_firmware_rak4631.zip", "SX1262"],
0xA4: [410000000, 525000000, 14, "410 - 525 MHz", "rnode_firmware.hex", "SX1278"],
0xA9: [820000000, 1020000000, 17, "820 - 1020 MHz", "rnode_firmware.hex", "SX1276"],
0xA1: [410000000, 525000000, 22, "410 - 525 MHz", "rnode_firmware_t3s3.zip", "SX1268"],
0xA6: [820000000, 1020000000, 22, "820 - 960 MHz", "rnode_firmware_t3s3.zip", "SX1262"],
0xA2: [410000000, 525000000, 17, "410 - 525 MHz", "rnode_firmware_ng21.zip", "SX1278"],
0xA7: [820000000, 1020000000, 17, "820 - 1020 MHz", "rnode_firmware_ng21.zip", "SX1276"],
0xA3: [410000000, 525000000, 17, "410 - 525 MHz", "rnode_firmware_ng20.zip", "SX1278"],
0xA8: [820000000, 1020000000, 17, "820 - 1020 MHz", "rnode_firmware_ng20.zip", "SX1276"],
0xB3: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_lora32v20.zip", "SX1278"],
0xB8: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_lora32v20.zip", "SX1276"],
0xB4: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_lora32v21.zip", "SX1278"],
0xB9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_lora32v21.zip", "SX1276"],
0x04: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_lora32v21_tcxo.zip", "SX1278"],
0x09: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_lora32v21_tcxo.zip", "SX1276"],
0xBA: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_lora32v10.zip", "SX1278"],
0xBB: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_lora32v10.zip", "SX1276"],
0xC4: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_heltec32v2.zip", "SX1278"],
0xC9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_heltec32v2.zip", "SX1276"],
0xC5: [470000000, 510000000, 21, "470 - 510 MHz", "rnode_firmware_heltec32v3.zip", "SX1262"],
0xCA: [863000000, 928000000, 21, "863 - 928 MHz", "rnode_firmware_heltec32v3.zip", "SX1262"],
0xE4: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_tbeam.zip", "SX1278"],
0xE9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_tbeam.zip", "SX1276"],
0xE3: [420000000, 520000000, 22, "420 - 520 MHz", "rnode_firmware_tbeam_sx1262.zip", "SX1268"],
0xE8: [850000000, 950000000, 22, "850 - 950 MHz", "rnode_firmware_tbeam_sx1262.zip", "SX1262"],
0xFE: [100000000, 1100000000, 17, "(Band capabilities unknown)", None, "Unknown"],
0xFF: [100000000, 1100000000, 14, "(Band capabilities unknown)", None, "Unknown"],
```
- product should be a code from the following list below without the leading `0x` and in lowercase (example `f0`):
```
PRODUCT_RAK4631 = 0x10
PRODUCT_RNODE = 0x03
PRODUCT_T32_10 = 0xB2
PRODUCT_T32_20 = 0xB0
PRODUCT_T32_21 = 0xB1
PRODUCT_H32_V2 = 0xC0
PRODUCT_H32_V3 = 0xC1
PRODUCT_TBEAM = 0xE0
PRODUCT_HMBRW = 0xF0
```
**Please note**, you must re-compile the firmware each time you make changes **before** you flash it, else you will just be flashing the previous version of the firmware without the new changes! **Please note**, you must re-compile the firmware each time you make changes **before** you flash it, else you will just be flashing the previous version of the firmware without the new changes!
These commands can also be run as a one liner. For example: These commands can also be run as a one liner. For example:

View File

@ -1,47 +1,77 @@
# Board support # Board support
If you wish to add support for a specific board to the project, all you have to do (if it's ESP32 or nRF52), is write an additional entry for `Boards.h`. If you wish to add support for a specific board to the project, all you have to do (if it's ESP32 or nRF52), is write an additional entry for `Boards.h` and `Utilities.h` and the `Makefile` .
This entry should include, at a minimum, the following: ### Boards.h
This entry in `Boards.h` should include, at a minimum, the following:
* whether the device has bluetooth / BLE * whether the device has bluetooth / BLE
* whether the device has a PMU * whether the device has a PMU
* whether the device has an EEPROM (false in all cases for nRF52, true for ESP32) * whether the device has an EEPROM (false in all cases for nRF52, true for ESP32)
* pin mappings for SPI NSS, SCLK, MOSI, MISO, modem reset and dio0 * pin mappings for SPI NSS, SCLK, MOSI, MISO, modem reset and dio0
* the type of modem on the board (if undefined it defaults to SX127x) * the type of modem on the board
* the number of interfaces (modems)
* whether the modem has a busy pin * whether the modem has a busy pin
* RX and TX leds (preferably LEDs of different colours) * RX and TX leds (preferably LEDs of different colours)
# Check this area... You should also define a unique name for your board (with a unique value), for
see https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.h#L39 example:
Effectively, there are multiple SPI buses we can map to pins on these ```
devices (including the hardware SPI bus) #define BOARD_MY_WICKED_BOARD 0x3B
```
An example of a minimal entry can be seen below: **Check your chosen value is not in use** in `Boards.h` first!
The board definition should look as follows:
``` ```
#elif BOARD_MODEL == BOARD_MY_WICKED_BOARD #elif BOARD_MODEL == BOARD_MY_WICKED_BOARD
#define HAS_BLUETOOTH true #define HAS_BLUETOOTH false
#define HAS_PMU true #define HAS_CONSOLE true
#define HAS_EEPROM true #define HAS_EEPROM true
#define EEPROM_SIZE 296 // minimum EEPROM size #define INTERFACE_COUNT 1
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED const int pin_led_rx = 9;
const int pin_cs = 20; const int pin_led_tx = 8;
const int pin_reset = 19; const uint8_t interfaces[INTERFACE_COUNT] = {SX127X};
// const int pin_cs = 1; not needed here const bool interface_cfg[INTERFACE_COUNT][3] = {
// const int pin_sclk = 2; not needed here // SX127X
// const int pin_mosi = 3; not needed here {
// const int pin_miso = 4; not needed here true, // DEFAULT_SPI
const int pin_dio = 18; false, // HAS_TCXO
// const int pin_busy = 0; not present false // DIO2_AS_RF_SWITCH
const int pin_led_rx = 5; },
const int pin_led_tx = 6; };
const int8_t interface_pins[INTERFACE_COUNT][10] = {
// SX127X
{
7, // pin_ss
4, // pin_sclk
6, // pin_mosi
5, // pin_miso
-1, // pin_busy
2, // pin_dio
3, // pin_reset
-1, // pin_txen
-1, // pin_rxen
-1 // pin_tcxo_enable
}
};
``` ```
Note, this will have to be pasted in the section according to the MCU variant,
e.g. nRF52 or ESP32. Find the section by searching for the comparison where
`MCU_VARIANT` is checked for your MCU variant. **Do not change the order of the
pins or options in any of the interface_cfg or interface_pins arrays.** You
have been warned.
[There are multiple SPI
buses](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.h#L39)
we can map to pins on these devices (including the hardware SPI bus).
In some cases the SPI pins will not be required, as they will be the default pins for the SPI library supporting the board anyway, and therefore do not need overriding in the config. In some cases the SPI pins will not be required, as they will be the default pins for the SPI library supporting the board anyway, and therefore do not need overriding in the config.
If the SX1262 is being used the following should also be considered: If the SX1262 is being used the following should also be considered:
* the modem busy pin
* whether DIO2 should be used as the RF switch (DIO2_AS_RF_SWITCH) * whether DIO2 should be used as the RF switch (DIO2_AS_RF_SWITCH)
* whether an rf on/off switch also has to be operated (through the pin pin_rxen) * whether an RF on/off switch also has to be operated (through the pin pin_rxen)
* whether a TCXO is connected to the modem (HAS_TCXO) * whether a TCXO is connected to the modem (HAS_TCXO and pin_tcxo_enable to enable the TCXO if present)
* the enable pin for the TCXO (if present) * whether the SPI pins are the default used by the SPI library
An example of an entry using the SX1262 modem can be seen below: An example of an entry using the SX1262 modem can be seen below:
``` ```
@ -51,22 +81,34 @@ An example of an entry using the SX1262 modem can be seen below:
#define HAS_EEPROM true #define HAS_EEPROM true
#define EEPROM_SIZE 296 // minimum EEPROM size #define EEPROM_SIZE 296 // minimum EEPROM size
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
#define MODEM SX1262
#define DIO2_AS_RF_SWITCH true
#define HAS_TCXO true
#define HAS_BUSY true
const int pin_cs = 20;
const int pin_reset = 19;
const int pin_rxen = 10;
// const int pin_cs = 1; not needed here
// const int pin_sclk = 2; not needed here
// const int pin_mosi = 3; not needed here
// const int pin_miso = 4; not needed here
const int pin_dio = 18;
const int pin_busy = 7;
const int pin_tcxo_enable = -1;
const int pin_led_rx = 5; const int pin_led_rx = 5;
const int pin_led_tx = 6; const int pin_led_tx = 6;
#define INTERFACE_COUNT 1
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1262
{
false, // DEFAULT_SPI
true, // HAS_TCXO
true // DIO2_AS_RF_SWITCH
}
};
const int8_t interface_pins[INTERFACE_COUNT][10] = {
// SX1262
{
42, // pin_ss
43, // pin_sclk
44, // pin_mosi
45, // pin_miso
46, // pin_busy
47, // pin_dio
38, // pin_reset
-1, // pin_txen
37, // pin_rxen
-1 // pin_tcxo_enable
}
};
``` ```
If the SX1280 is being used, the following should also be added: If the SX1280 is being used, the following should also be added:
@ -80,24 +122,116 @@ An example of an entry using the SX1280 modem can be seen below:
#define HAS_EEPROM true #define HAS_EEPROM true
#define EEPROM_SIZE 296 // minimum EEPROM size #define EEPROM_SIZE 296 // minimum EEPROM size
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
#define MODEM SX1280
#define HAS_BUSY true
#define HAS_RF_SWITCH_RX_TX true
const int pin_cs = 20;
const int pin_reset = 19;
const int pin_rxen = 10;
const int pin_txen = 11;
// const int pin_cs = 1; not needed here
// const int pin_sclk = 2; not needed here
// const int pin_mosi = 3; not needed here
// const int pin_miso = 4; not needed here
const int pin_dio = 18;
const int pin_busy = 7;
const int pin_tcxo_enable = -1;
const int pin_led_rx = 5; const int pin_led_rx = 5;
const int pin_led_tx = 6; const int pin_led_tx = 6;
#define INTERFACE_COUNT 1
const uint8_t interfaces[INTERFACE_COUNT] = {SX128X};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1280
{
true, // DEFAULT_SPI
false,// HAS_TCXO
false // DIO2_AS_RF_SWITCH
}
};
const int8_t interface_pins[INTERFACE_COUNT][10] = {
// SX1280
{
24, // pin_ss
3, // pin_sclk
30, // pin_mosi
29, // pin_miso
25, // pin_busy
15, // pin_dio
16, // pin_reset
20, // pin_txen
19, // pin_rxen
-1 // pin_tcxo_enable
}
};
``` ```
#### INTERFACE_SPI (nRF52 only)
If you are using non-default SPI pins on an nRF52 MCU variant, you **must** ensure that you add this section to the bottom of your board config:
```
// Required because on nRF52, 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]
)
};
```
This will ensure the pins are set correctly in the SPI class.
### Utilities.h
You should add something similar to the following to drive the LEDs depending on your configuration:
```
#elif BOARD_MODEL == BOARD_MY_WICKED_BOARD
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); }
```
Note: this will again have to be pasted in the correct section according to
your MCU variant. Please search for the other definitions of `led_rx_on()` to
find the correct section, then find the final section by searching for the
comparison where `MCU_VARIANT` is checked for your MCU variant.
### Makefile
You can add the example target below to the makefile for your board, but **you must replace the FQBN** in the arduino-cli command with the correct one for your board.
```
firmware-wicked_esp32:
arduino-cli compile --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\""
```
Pay attention the the DBOARD_MODEL= value as you must insert the one you chose earlier here.
Another entry to upload to the board. Again substitute your FQBN, and you may have to experiment with the commands to get it to flash:
#### ESP32
```
upload-wicked_esp32:
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32c3
@sleep 1
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32c3/RNode_Firmware_CE.ino.bin)
@sleep 3
python3 ./Release/esptool/esptool.py --chip esp32c3 --port /dev/ttyACM0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
```
#### nRF52
```
upload-wicked_nrf52:
arduino-cli upload -p /dev/ttyACM0 --fqbn rakwireless:nrf52:WisCoreRAK4631Board
unzip -o build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.zip -d build/rakwireless.nrf52.WisCoreRAK4631Board
rnodeconf /dev/ttyACM0 --firmware-hash $$(sha256sum ./build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.bin | grep -o '^\S*')
```
And one final entry to make a release for the firmware:
#### ESP32
```
release-wicked_esp32:
arduino-cli compile --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_wicked_esp32.boot_app0
cp build/esp32.esp32.esp32c3/RNode_Firmware_CE.ino.bin build/rnode_firmware_wicked_esp32.bin
cp build/esp32.esp32.esp32c3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_wicked_esp32.bootloader
cp build/esp32.esp32.esp32c3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_wicked_esp32.partitions
zip --junk-paths ./Release/rnode_firmware_wicked_esp32.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_wicked_esp32.boot_app0 build/rnode_firmware_wicked_esp32.bin build/rnode_firmware_wicked_esp32.bootloader build/rnode_firmware_wicked_esp32.partitions
rm -r build
```
#### nRF52
```
release-wicked_nrf52:
arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\""
cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.hex build/rnode_firmware_wicked_nrf52.hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_wicked_nrf52.hex Release/rnode_firmware_wicked_nrf52.zip
```
Don't forget to add this entry to the `release-all` target!
```
release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 ***release-wicked_esp32*** release-heltec32_v2 release-heltec32_v3 release-heltec32_v2_extled release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-hashes
```
You can of course replace the ESP32 target with the nRF52 target, if you are building for that MCU variant, as seen in previous instructions.
Please submit this, and any other support in different areas of the project your board may require, as a PR for my consideration. Please submit this, and any other support in different areas of the project your board may require, as a PR for my consideration.
# Feature request # Feature request

130
Makefile
View File

@ -22,19 +22,7 @@ VFLAG =-v
endif endif
COMMON_BUILD_FLAGS = $(VFLAG) -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" COMMON_BUILD_FLAGS = $(VFLAG) -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152"
COMMON_UPLOAD_FlAGS = $(VFLAG) --chip esp32 --port $(SERIAL_DEV) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 COMMON_ESP_UPLOAD_FlAGS = $(VFLAG) --chip esp32 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000
ifndef SERIAL_DEV
ifneq (,$(wildcard /dev/ttyUSB0))
SERIAL_DEV = /dev/ttyUSB0
else ifneq (,$(wildcard /dev/ttyACM0))
SERIAL_DEV = /dev/ttyACM0
else ifneq (,$(wildcard /dev/cu.usbserial*))
SERIAL_DEV = $(wildcard /dev/cu.usbserial*)
else
SERIAL_DEV = unknown
endif
endif
all: release all: release
@ -42,27 +30,27 @@ clean:
-rm -rf ./build -rm -rf ./build
-rm -f ./Release/rnode_firmware* -rm -f ./Release/rnode_firmware*
prep: prep-esp32 prep-samd prep: prep-esp32 prep-nrf
prep-index: prep-index:
arduino-cli core update-index --config-file arduino-cli.yaml arduino-cli core update-index --config-file arduino-cli.yaml
prep-esp32: prep-esp32:
arduino-cli core install esp32:esp32@2.0.17 --config-file arduino-cli.yaml arduino-cli core install esp32:esp32@$(ESP_IDF_VER) --config-file arduino-cli.yaml
arduino-cli lib install "Adafruit SSD1306" arduino-cli lib install "Adafruit SSD1306"
arduino-cli lib install "XPowersLib" arduino-cli lib install "XPowersLib"
arduino-cli lib install "Crypto" arduino-cli lib install "Crypto"
arduino-cli lib install "Adafruit NeoPixel" arduino-cli lib install "Adafruit NeoPixel"
pip install pyserial rns --upgrade --user --break-system-packages # This looks scary, but it's actually just telling pip to install packages as a user instead of trying to install them systemwide, which bypasses the "externally managed environment" error.
prep-samd:
arduino-cli core install adafruit:samd --config-file arduino-cli.yaml
prep-nrf: prep-nrf:
arduino-cli core install adafruit:nrf52 --config-file arduino-cli.yaml
arduino-cli core install rakwireless:nrf52 --config-file arduino-cli.yaml arduino-cli core install rakwireless:nrf52 --config-file arduino-cli.yaml
arduino-cli lib install "Crypto" arduino-cli lib install "Crypto"
arduino-cli lib install "Adafruit GFX Library" arduino-cli lib install "Adafruit GFX Library"
arduino-cli lib install "GxEPD2" arduino-cli lib install "GxEPD2"
pip install adafruit-nrfutil --upgrade pip install pyserial rns --upgrade --user --break-system-packages
pip install adafruit-nrfutil --upgrade --user --break-system-packages # This looks scary, but it's actually just telling pip to install packages as a user instead of trying to install them systemwide, which bypasses the "externally managed environment" error.
console-site: console-site:
make -C Console clean site make -C Console clean site
@ -70,13 +58,13 @@ console-site:
spiffs: console-site spiffs-image spiffs: console-site spiffs-image
spiffs-image: spiffs-image:
python Release/esptool/spiffsgen.py 1966080 ./Console/build Release/console_image.bin python3 Release/esptool/spiffsgen.py 1966080 ./Console/build Release/console_image.bin
upload-spiffs: upload-spiffs:
@echo Deploying SPIFFS image... @echo Deploying SPIFFS image...
python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin
all-firmware: $(shell grep ^firmware- Makefile | cut -d: -f1) firmware: $(shell grep ^firmware- Makefile | cut -d: -f1)
firmware-tbeam: firmware-tbeam:
arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\"" arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\""
@ -84,12 +72,23 @@ firmware-tbeam:
firmware-tbeam_sx126x: firmware-tbeam_sx126x:
arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DMODEM=0x03\"" arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DMODEM=0x03\""
firmware-techo: firmware-techo4 firmware-techo9
firmware-techo4:
arduino-cli compile --fqbn adafruit:nrf52:pca10056 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x43\" \"-DBOARD_VARIANT=0x16\""
firmware-techo9:
arduino-cli compile --fqbn adafruit:nrf52:pca10056 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x43\" \"-DBOARD_VARIANT=0x17\""
firmware-t3s3_sx1262: firmware-t3s3_sx1262:
arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xA1\"" arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xA1\""
firmware-t3s3_sx1280_pa: firmware-t3s3_sx1280_pa:
arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xA5\"" arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xA5\""
firmware-e22_esp32:
arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\" \"-DEXTERNAL_LEDS=true\""
firmware-lora32_v10: firmware-lora32_v10:
arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\"" arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\""
@ -139,92 +138,104 @@ firmware-freenode:
arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x21\"" arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x21\""
upload-tbeam: upload-tbeam:
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:t-beam arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:t-beam
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.t-beam/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.t-beam/RNode_Firmware_CE.ino.bin)
@sleep 3 @sleep 3
python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FLAGS)
upload-techo:
arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn adafruit:nrf52:pca10056
unzip -o build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.zip -d build/adafruit.nrf52.pca10056
rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(sha256sum ./build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.bin | grep -o '^\S*')
upload-lora32_v10: upload-lora32_v10:
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:ttgo-lora32 arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3 @sleep 3
python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS)
upload-lora32_v20: upload-lora32_v20:
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:ttgo-lora32 arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3 @sleep 3
python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS)
upload-lora32_v21: upload-lora32_v21:
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:ttgo-lora32 arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3 @sleep 3
python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FlAGS)
upload-heltec32_v2: upload-heltec32_v2:
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:heltec_wifi_lora_32_V2 arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:heltec_wifi_lora_32_V2
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware_CE.ino.bin)
@sleep 3 @sleep 3
python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS)
upload-heltec32_v3: upload-heltec32_v3:
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:heltec_wifi_lora_32_V3 arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:heltec_wifi_lora_32_V3
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bin)
@sleep 3 @sleep 3
python ./Release/esptool/esptool.py --chip esp32-s3 --port $(SERIAL_DEV) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS)
upload-rnode_ng_20: upload-rnode_ng_20:
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:ttgo-lora32 arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3 @sleep 3
python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS)
upload-rnode_ng_21: upload-rnode_ng_21:
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:ttgo-lora32 arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3 @sleep 3
python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FlAGS)
upload-t3s3: upload-t3s3:
@echo @echo
@echo Put board into flashing mode by holding BOOT button while momentarily pressing the RESET button. Hit enter when done. @echo Put board into flashing mode by holding BOOT button while momentarily pressing the RESET button. Hit enter when done.
@read @read
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:esp32s3 arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3
@sleep 2 @sleep 2
python ./Release/esptool/esptool.py --chip esp32s3 --port $(SERIAL_DEV) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin python3 ./Release/esptool/esptool.py --chip esp32s3 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
@echo @echo
@echo Press the RESET button on the board now, and hit enter @echo Press the RESET button on the board now, and hit enter
@read @read
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin)
upload-featheresp32: upload-featheresp32:
arduino-cli upload -p $(SERIAL_DEV) --fqbn esp32:esp32:featheresp32 arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:featheresp32
@sleep 1 @sleep 1
rnodeconf $(SERIAL_DEV) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.featheresp32/RNode_Firmware_CE.ino.bin) rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.featheresp32/RNode_Firmware_CE.ino.bin)
@sleep 3 @sleep 3
python ./Release/esptool/esptool.py $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin python ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin
upload-rak4631: upload-rak4631:
arduino-cli upload -p $(SERIAL_DEV) --fqbn rakwireless:nrf52:WisCoreRAK4631Board arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn rakwireless:nrf52:WisCoreRAK4631Board
unzip -o build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.zip -d build/rakwireless.nrf52.WisCoreRAK4631Board unzip -o build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.zip -d build/rakwireless.nrf52.WisCoreRAK4631Board
rnodeconf $(SERIAL_DEV) --firmware-hash $$(sha256sum ./build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.bin | grep -o '^\S*') rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(sha256sum ./build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.bin | grep -o '^\S*')
upload-e22_esp32:
arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:esp32
@sleep 1
rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bin)
@sleep 3
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS)
release: release-all release: release-all
release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 release-heltec32_v2 release-heltec32_v3 release-heltec32_v2_extled release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-hashes release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 release-heltec32_v2 release-heltec32_v3 release-heltec32_v2_extled release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-e22_esp32 release-hashes
release-hashes: release-hashes:
python ./release_hashes.py > ./Release/release.json python3 ./release_hashes.py > ./Release/release.json
release-tbeam: release-tbeam:
arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\"" arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\""
@ -361,6 +372,15 @@ release-t3s3:
zip --junk-paths ./Release/rnode_firmware_t3s3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3.boot_app0 build/rnode_firmware_t3s3.bin build/rnode_firmware_t3s3.bootloader build/rnode_firmware_t3s3.partitions zip --junk-paths ./Release/rnode_firmware_t3s3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3.boot_app0 build/rnode_firmware_t3s3.bin build/rnode_firmware_t3s3.bootloader build/rnode_firmware_t3s3.partitions
rm -r build rm -r build
release-e22_esp32:
arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_esp32_e22.boot_app0
cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bin build/rnode_firmware_esp32_e22.bin
cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_esp32_e22.bootloader
cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_esp32_e22.partitions
zip --junk-paths ./Release/rnode_firmware_esp32_e22.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_esp32_e22.boot_app0 build/rnode_firmware_esp32_e22.bin build/rnode_firmware_esp32_e22.bootloader build/rnode_firmware_esp32_e22.partitions
rm -r build
release-featheresp32: release-featheresp32:
arduino-cli compile --fqbn esp32:esp32:featheresp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\"" arduino-cli compile --fqbn esp32:esp32:featheresp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_featheresp32.boot_app0 cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_featheresp32.boot_app0

12
Power.h
View File

@ -273,6 +273,16 @@ void measure_battery() {
if (battery_percent >= 98) { if (battery_percent >= 98) {
battery_state = BATTERY_STATE_CHARGED; battery_state = BATTERY_STATE_CHARGED;
} }
#if HAS_BLE
if ((bt_state == BT_STATE_ON) || bt_state == BT_STATE_CONNECTED) {
if (battery_state != BATTERY_STATE_CHARGING) {
blebas.write(battery_percent);
} else {
blebas.write(100);
}
}
#endif
#endif #endif
if (battery_ready) { if (battery_ready) {
@ -421,7 +431,7 @@ bool init_pmu() {
PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
return true; return true;
#elif BOARD_MODEL == BOARD_RAK4631 #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_FREENODE
// board doesn't have PMU but we can measure batt voltage // board doesn't have PMU but we can measure batt voltage
// prep ADC for reading battery level // prep ADC for reading battery level

View File

@ -58,7 +58,7 @@ The RNode Firmware supports all transceiver modules based on the following chips
* Semtech SX1278 * Semtech SX1278
* Semtech SX1280 * Semtech SX1280
These also must have an **SPI interface** and **DIO_0** pin connected to the MCU directly. These also must have an **SPI interface** and **DIO_0 (sometimes called DIO_1)** pin connected to the MCU directly.
## One Tool, Many Uses ## One Tool, Many Uses

View File

@ -17,10 +17,37 @@
#include <SPI.h> #include <SPI.h>
#include "Utilities.h" #include "Utilities.h"
#if BOARD_MODEL == BOARD_HELTEC32_V3 #if MCU_VARIANT == MCU_NRF52
// Default stack size for loop function on Heltec32 V3 is not large enough, #define INTERFACE_SPI
// must be increased to 11kb to prevent crashes. #if BOARD_MODEL == BOARD_RAK4631
SET_LOOP_TASK_STACK_SIZE(11 * 1024); // 11KB // 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]
)
};
#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
#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];
#endif #endif
FIFOBuffer serialFIFO; FIFOBuffer serialFIFO;
@ -49,11 +76,6 @@ volatile bool serial_buffering = false;
char sbuf[128]; char sbuf[128];
bool packet_ready = false;
volatile bool process_packet = false;
volatile uint8_t packet_interface = 0;
uint8_t *packet_queue[INTERFACE_COUNT]; uint8_t *packet_queue[INTERFACE_COUNT];
void setup() { void setup() {
@ -120,11 +142,15 @@ void setup() {
memset(packet_lengths_buf, 0, sizeof(packet_starts_buf)); memset(packet_lengths_buf, 0, sizeof(packet_starts_buf));
for (int i = 0; i < INTERFACE_COUNT; i++) { for (int i = 0; i < INTERFACE_COUNT; i++) {
fifo16_init(&packet_starts[i], packet_starts_buf, CONFIG_QUEUE_MAX_LENGTH); 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); fifo16_init(&packet_lengths[i], packet_lengths_buf, CONFIG_QUEUE_MAX_LENGTH+1);
packet_queue[i] = (uint8_t*)malloc(getQueueSize(i)); packet_queue[i] = (uint8_t*)malloc(getQueueSize(i)+1);
} }
memset(packet_rdy_interfaces_buf, 0, sizeof(packet_rdy_interfaces_buf));
fifo_init(&packet_rdy_interfaces, packet_rdy_interfaces_buf, MAX_INTERFACES);
// Create and configure interface objects // Create and configure interface objects
for (uint8_t i = 0; i < INTERFACE_COUNT; i++) { for (uint8_t i = 0; i < INTERFACE_COUNT; i++) {
switch (interfaces[i]) { switch (interfaces[i]) {
@ -134,13 +160,13 @@ void setup() {
sx126x* obj; sx126x* obj;
// if default spi enabled // if default spi enabled
if (interface_cfg[i][0]) { if (interface_cfg[i][0]) {
obj = new sx126x(i, SPI, interface_cfg[i][1], obj = new sx126x(i, &SPI, interface_cfg[i][1],
interface_cfg[i][2], interface_pins[i][0], interface_pins[i][1], 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][2], interface_pins[i][3], interface_pins[i][6],
interface_pins[i][5], interface_pins[i][4], interface_pins[i][8]); interface_pins[i][5], interface_pins[i][4], interface_pins[i][8]);
} }
else { else {
obj = new sx126x(i, interface_spi[i], interface_cfg[i][1], obj = new sx126x(i, &interface_spi[i], interface_cfg[i][1],
interface_cfg[i][2], interface_pins[i][0], interface_pins[i][1], 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][2], interface_pins[i][3], interface_pins[i][6],
interface_pins[i][5], interface_pins[i][4], interface_pins[i][8]); interface_pins[i][5], interface_pins[i][4], interface_pins[i][8]);
@ -157,12 +183,12 @@ void setup() {
sx127x* obj; sx127x* obj;
// if default spi enabled // if default spi enabled
if (interface_cfg[i][0]) { if (interface_cfg[i][0]) {
obj = new sx127x(i, SPI, interface_pins[i][0], obj = new sx127x(i, &SPI, interface_pins[i][0],
interface_pins[i][1], interface_pins[i][2], interface_pins[i][3], 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][6], interface_pins[i][5], interface_pins[i][4]);
} }
else { else {
obj = new sx127x(i, interface_spi[i], interface_pins[i][0], obj = new sx127x(i, &interface_spi[i], interface_pins[i][0],
interface_pins[i][1], interface_pins[i][2], interface_pins[i][3], 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][6], interface_pins[i][5], interface_pins[i][4]);
} }
@ -177,13 +203,13 @@ void setup() {
sx128x* obj; sx128x* obj;
// if default spi enabled // if default spi enabled
if (interface_cfg[i][0]) { if (interface_cfg[i][0]) {
obj = new sx128x(i, SPI, interface_cfg[i][1], obj = new sx128x(i, &SPI, interface_cfg[i][1],
interface_pins[i][0], interface_pins[i][1], interface_pins[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][3], interface_pins[i][6], interface_pins[i][5],
interface_pins[i][4], interface_pins[i][8], interface_pins[i][7]); interface_pins[i][4], interface_pins[i][8], interface_pins[i][7]);
} }
else { else {
obj = new sx128x(i, interface_spi[i], interface_cfg[i][1], obj = new sx128x(i, &interface_spi[i], interface_cfg[i][1],
interface_pins[i][0], interface_pins[i][1], interface_pins[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][3], interface_pins[i][6], interface_pins[i][5],
interface_pins[i][4], interface_pins[i][8], interface_pins[i][7]); interface_pins[i][4], interface_pins[i][8], interface_pins[i][7]);
@ -315,18 +341,18 @@ inline void getPacketData(RadioInterface* radio, uint16_t len) {
} }
} }
void ISR_VECT receive_callback(uint8_t index, int packet_size) { void receive_callback(uint8_t index, int packet_size) {
if (!promisc) {
selected_radio = interface_obj[index]; selected_radio = interface_obj[index];
bool ready = false;
if (!promisc) {
// The standard operating mode allows large // The standard operating mode allows large
// packets with a payload up to 500 bytes, // packets with a payload up to 500 bytes,
// by combining two raw LoRa packets. // by combining two raw LoRa packets.
// We read the 1-byte header and extract // We read the 1-byte header and extract
// packet sequence number and split flags // packet sequence number and split flags
uint8_t header = selected_radio->read(); packet_size--; uint8_t header = selected_radio->read(); packet_size--;
uint8_t sequence = packetSequence(header); uint8_t sequence = packetSequence(header);
bool ready = false;
if (isSplitPacket(header) && seq == SEQ_UNSET) { if (isSplitPacket(header) && seq == SEQ_UNSET) {
// This is the first part of a split // This is the first part of a split
@ -345,7 +371,8 @@ void ISR_VECT receive_callback(uint8_t index, int packet_size) {
getPacketData(selected_radio, packet_size); getPacketData(selected_radio, packet_size);
seq = SEQ_UNSET; seq = SEQ_UNSET;
ready = true; packet_interface = index;
packet_ready = true;
} else if (isSplitPacket(header) && seq != sequence) { } else if (isSplitPacket(header) && seq != sequence) {
// This split packet does not carry the // This split packet does not carry the
@ -370,10 +397,8 @@ void ISR_VECT receive_callback(uint8_t index, int packet_size) {
} }
getPacketData(selected_radio, packet_size); getPacketData(selected_radio, packet_size);
ready = true;
}
if (ready) { packet_interface = index;
packet_ready = true; packet_ready = true;
} }
} else { } else {
@ -382,8 +407,11 @@ void ISR_VECT receive_callback(uint8_t index, int packet_size) {
read_len = 0; read_len = 0;
getPacketData(selected_radio, packet_size); getPacketData(selected_radio, packet_size);
packet_interface = index;
packet_ready = true; packet_ready = true;
} }
last_rx = millis(); last_rx = millis();
} }
@ -436,6 +464,7 @@ bool startRadio(RadioInterface* radio) {
void stopRadio(RadioInterface* radio) { void stopRadio(RadioInterface* radio) {
radio->end(); radio->end();
sort_interfaces(); sort_interfaces();
kiss_indicate_radiostate(radio);
} }
void update_radio_lock(RadioInterface* radio) { void update_radio_lock(RadioInterface* radio) {
@ -570,9 +599,9 @@ void serialCallback(uint8_t sbyte) {
if (getInterfaceIndex(command) < INTERFACE_COUNT) { if (getInterfaceIndex(command) < INTERFACE_COUNT) {
uint8_t index = getInterfaceIndex(command); uint8_t index = getInterfaceIndex(command);
if (!fifo16_isfull(&packet_starts[index]) && queued_bytes[index] < (getQueueSize(index))) { if (!fifo16_isfull(&packet_starts[index]) && (queued_bytes[index] < (getQueueSize(index)))) {
uint16_t s = current_packet_start[index]; uint16_t s = current_packet_start[index];
int16_t e = queue_cursor[index]-1; if (e == -1) e = (getQueueSize(index))-1; int32_t e = queue_cursor[index]-1; if (e == -1) e = (getQueueSize(index))-1;
uint16_t l; uint16_t l;
if (s != e) { if (s != e) {
@ -697,8 +726,8 @@ void serialCallback(uint8_t sbyte) {
if (op_mode == MODE_HOST) selected_radio->setSignalBandwidth(bw); if (op_mode == MODE_HOST) selected_radio->setSignalBandwidth(bw);
selected_radio->updateBitrate(); selected_radio->updateBitrate();
sort_interfaces(); sort_interfaces();
kiss_indicate_phy_stats(selected_radio);
kiss_indicate_bandwidth(selected_radio); kiss_indicate_bandwidth(selected_radio);
kiss_indicate_phy_stats(selected_radio);
} }
interface = 0; interface = 0;
} }
@ -727,8 +756,8 @@ void serialCallback(uint8_t sbyte) {
if (op_mode == MODE_HOST) selected_radio->setSpreadingFactor(sf); if (op_mode == MODE_HOST) selected_radio->setSpreadingFactor(sf);
selected_radio->updateBitrate(); selected_radio->updateBitrate();
sort_interfaces(); sort_interfaces();
kiss_indicate_phy_stats(selected_radio);
kiss_indicate_spreadingfactor(selected_radio); kiss_indicate_spreadingfactor(selected_radio);
kiss_indicate_phy_stats(selected_radio);
} }
interface = 0; interface = 0;
} else if (command == CMD_CR) { } else if (command == CMD_CR) {
@ -743,8 +772,8 @@ void serialCallback(uint8_t sbyte) {
if (op_mode == MODE_HOST) selected_radio->setCodingRate4(cr); if (op_mode == MODE_HOST) selected_radio->setCodingRate4(cr);
selected_radio->updateBitrate(); selected_radio->updateBitrate();
sort_interfaces(); sort_interfaces();
kiss_indicate_phy_stats(selected_radio);
kiss_indicate_codingrate(selected_radio); kiss_indicate_codingrate(selected_radio);
kiss_indicate_phy_stats(selected_radio);
} }
interface = 0; interface = 0;
} else if (command == CMD_IMPLICIT) { } else if (command == CMD_IMPLICIT) {
@ -765,10 +794,8 @@ void serialCallback(uint8_t sbyte) {
kiss_indicate_radiostate(selected_radio); kiss_indicate_radiostate(selected_radio);
} else if (sbyte == 0x00) { } else if (sbyte == 0x00) {
stopRadio(selected_radio); stopRadio(selected_radio);
kiss_indicate_radiostate(selected_radio);
} else if (sbyte == 0x01) { } else if (sbyte == 0x01) {
startRadio(selected_radio); startRadio(selected_radio);
kiss_indicate_radiostate(selected_radio);
} }
interface = 0; interface = 0;
} else if (command == CMD_ST_ALOCK) { } else if (command == CMD_ST_ALOCK) {
@ -1142,22 +1169,7 @@ void validate_status() {
} }
void loop() { void loop() {
packet_poll();
bool ready = false;
for (int i = 0; i < INTERFACE_COUNT; i++) {
selected_radio = interface_obj[i];
if (selected_radio->getRadioOnline()) {
selected_radio->checkModemStatus();
ready = true;
}
}
// If at least one radio is online then we can continue
if (ready) {
if (packet_ready) { if (packet_ready) {
selected_radio = interface_obj[packet_interface];
#if MCU_VARIANT == MCU_ESP32 #if MCU_VARIANT == MCU_ESP32
portENTER_CRITICAL(&update_lock); portENTER_CRITICAL(&update_lock);
#elif MCU_VARIANT == MCU_NRF52 #elif MCU_VARIANT == MCU_NRF52
@ -1175,6 +1187,18 @@ void loop() {
kiss_write_packet(packet_interface); kiss_write_packet(packet_interface);
} }
bool ready = false;
for (int i = 0; i < INTERFACE_COUNT; i++) {
selected_radio = interface_obj[i];
if (selected_radio->getRadioOnline()) {
selected_radio->checkModemStatus();
ready = true;
}
}
// If at least one radio is online then we can continue
if (ready) {
for (int i = 0; i < INTERFACE_COUNT; i++) { for (int i = 0; i < INTERFACE_COUNT; i++) {
selected_radio = interface_obj_sorted[i]; selected_radio = interface_obj_sorted[i];
@ -1187,7 +1211,7 @@ void loop() {
// loop, it still needs to be the first to transmit, so check if this // loop, it still needs to be the first to transmit, so check if this
// is the case. // is the case.
for (int j = 0; j < INTERFACE_COUNT; j++) { for (int j = 0; j < INTERFACE_COUNT; j++) {
if (!interface_obj_sorted[j]->calculateALock() || interface_obj_sorted[j]->getRadioOnline()) { if (!interface_obj_sorted[j]->calculateALock() && interface_obj_sorted[j]->getRadioOnline()) {
if (interface_obj_sorted[j]->getBitrate() > selected_radio->getBitrate()) { if (interface_obj_sorted[j]->getBitrate() > selected_radio->getBitrate()) {
if (queue_height[interface_obj_sorted[j]->getIndex()] > 0) { if (queue_height[interface_obj_sorted[j]->getIndex()] > 0) {
selected_radio = interface_obj_sorted[j]; selected_radio = interface_obj_sorted[j];
@ -1197,7 +1221,7 @@ void loop() {
} }
if (queue_height[selected_radio->getIndex()] > 0) { if (queue_height[selected_radio->getIndex()] > 0) {
long check_time = millis(); uint32_t check_time = millis();
if (check_time > selected_radio->getPostTxYieldTimeout()) { if (check_time > selected_radio->getPostTxYieldTimeout()) {
if (selected_radio->getDCDWaiting() && (check_time >= selected_radio->getDCDWaitUntil())) { selected_radio->setDCDWaiting(false); } if (selected_radio->getDCDWaiting() && (check_time >= selected_radio->getDCDWaitUntil())) { selected_radio->setDCDWaiting(false); }
if (!selected_radio->getDCDWaiting()) { if (!selected_radio->getDCDWaiting()) {
@ -1306,26 +1330,6 @@ void poll_buffers() {
process_serial(); process_serial();
} }
void packet_poll() {
#if MCU_VARIANT == MCU_ESP32
portENTER_CRITICAL(&update_lock);
#elif MCU_VARIANT == MCU_NRF52
portENTER_CRITICAL();
#endif
// If we have received a packet on an interface which needs to be processed
if (process_packet) {
selected_radio = interface_obj[packet_interface];
selected_radio->clearIRQStatus();
selected_radio->handleDio0Rise();
process_packet = false;
}
#if MCU_VARIANT == MCU_ESP32
portEXIT_CRITICAL(&update_lock);
#elif MCU_VARIANT == MCU_NRF52
portEXIT_CRITICAL();
#endif
}
volatile bool serial_polling = false; volatile bool serial_polling = false;
void serial_poll() { void serial_poll() {
serial_polling = true; serial_polling = true;

3
ROM.h
View File

@ -32,6 +32,9 @@
#define MODEL_12 0x12 #define MODEL_12 0x12
#define MODEL_13 0x13 // RAK4631 LF with WisBlock SX1280 module (LIBSYS002) #define MODEL_13 0x13 // RAK4631 LF with WisBlock SX1280 module (LIBSYS002)
#define MODEL_14 0x14 // RAK4631 HF with WisBlock SX1280 module (LIBSYS002) #define MODEL_14 0x14 // RAK4631 HF with WisBlock SX1280 module (LIBSYS002)
#define PRODUCT_TECHO 0x15
#define MODEL_16 0x16 // T-Echo 433
#define MODEL_17 0x17 // T-Echo 915
#define MODEL_21 0x21 // European band, 868MHz #define MODEL_21 0x21 // European band, 868MHz
#define MODEL_A1 0xA1 #define MODEL_A1 0xA1
#define MODEL_A5 0xA5 // T3S3 SX1280 PA #define MODEL_A5 0xA5 // T3S3 SX1280 PA

308
Radio.cpp
View File

@ -4,7 +4,7 @@
// Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva // Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva
// Obviously still under the MIT license. // Obviously still under the MIT license.
#include "Radio.h" #include "Radio.hpp"
#if PLATFORM == PLATFORM_ESP32 #if PLATFORM == PLATFORM_ESP32
#if defined(ESP32) and !defined(CONFIG_IDF_TARGET_ESP32S3) #if defined(ESP32) and !defined(CONFIG_IDF_TARGET_ESP32S3)
@ -88,8 +88,7 @@
#define FREQ_DIV_6X (double)pow(2.0, 25.0) #define FREQ_DIV_6X (double)pow(2.0, 25.0)
#define FREQ_STEP_6X (double)(XTAL_FREQ_6X / FREQ_DIV_6X) #define FREQ_STEP_6X (double)(XTAL_FREQ_6X / FREQ_DIV_6X)
extern bool process_packet; extern FIFOBuffer packet_rdy_interfaces;
extern uint8_t packet_interface;
extern RadioInterface* interface_obj[]; extern RadioInterface* interface_obj[];
// ISRs cannot provide parameters to the functions they call. Since we have // ISRs cannot provide parameters to the functions they call. Since we have
@ -97,16 +96,26 @@ extern RadioInterface* interface_obj[];
// which one is high. We can then use the index of this pin in the 2D array to // which one is high. We can then use the index of this pin in the 2D array to
// signal the correct interface to the main loop // signal the correct interface to the main loop
void ISR_VECT onDio0Rise() { void ISR_VECT onDio0Rise() {
BaseType_t int_status = taskENTER_CRITICAL_FROM_ISR();
for (int i = 0; i < INTERFACE_COUNT; i++) { for (int i = 0; i < INTERFACE_COUNT; i++) {
if (digitalRead(interface_pins[i][5]) == HIGH) { if (digitalRead(interface_pins[i][5]) == HIGH) {
process_packet = true; if (interface_obj[i]->getPacketValidity()) {
packet_interface = i; interface_obj[i]->handleDio0Rise();
break; }
if (interfaces[i] == SX128X) {
// On the SX1280, there is a bug which can cause the busy line
// to remain high if a high amount of packets are received when
// in continuous RX mode. This is documented as Errata 16.1 in
// the SX1280 datasheet v3.2 (page 149)
// Therefore, the modem is set into receive mode each time a packet is received.
interface_obj[i]->receive();
} }
} }
}
taskEXIT_CRITICAL_FROM_ISR(int_status);
} }
sx126x::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) : sx126x::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) :
RadioInterface(index), RadioInterface(index),
_spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiModem(spi), _ss(ss), _spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiModem(spi), _ss(ss),
_sclk(sclk), _mosi(mosi), _miso(miso), _reset(reset), _dio0(dio0), _sclk(sclk), _mosi(mosi), _miso(miso), _reset(reset), _dio0(dio0),
@ -130,12 +139,12 @@ bool sx126x::preInit() {
// todo: check if this change causes issues on any platforms // todo: check if this change causes issues on any platforms
#if MCU_VARIANT == MCU_ESP32 #if MCU_VARIANT == MCU_ESP32
if (_sclk != -1 && _miso != -1 && _mosi != -1 && _ss != -1) { if (_sclk != -1 && _miso != -1 && _mosi != -1 && _ss != -1) {
_spiModem.begin(_sclk, _miso, _mosi, _ss); _spiModem->begin(_sclk, _miso, _mosi, _ss);
} else { } else {
_spiModem.begin(); _spiModem->begin();
} }
#else #else
_spiModem.begin(); _spiModem->begin();
#endif #endif
// check version (retry for up to 2 seconds) // check version (retry for up to 2 seconds)
@ -177,15 +186,15 @@ uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(opcode); _spiModem->transfer(opcode);
_spiModem.transfer((address & 0xFF00) >> 8); _spiModem->transfer((address & 0xFF00) >> 8);
_spiModem.transfer(address & 0x00FF); _spiModem->transfer(address & 0x00FF);
if (opcode == OP_READ_REGISTER_6X) { if (opcode == OP_READ_REGISTER_6X) {
_spiModem.transfer(0x00); _spiModem->transfer(0x00);
} }
response = _spiModem.transfer(value); response = _spiModem->transfer(value);
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
@ -222,15 +231,15 @@ void sx126x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size)
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(opcode); _spiModem->transfer(opcode);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
_spiModem.transfer(buffer[i]); _spiModem->transfer(buffer[i]);
} }
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
@ -241,16 +250,16 @@ void sx126x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size)
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(opcode); _spiModem->transfer(opcode);
_spiModem.transfer(0x00); _spiModem->transfer(0x00);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
buffer[i] = _spiModem.transfer(0x00); buffer[i] = _spiModem->transfer(0x00);
} }
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
@ -261,17 +270,17 @@ void sx126x::writeBuffer(const uint8_t* buffer, size_t size)
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(OP_FIFO_WRITE_6X); _spiModem->transfer(OP_FIFO_WRITE_6X);
_spiModem.transfer(_fifo_tx_addr_ptr); _spiModem->transfer(_fifo_tx_addr_ptr);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
_spiModem.transfer(buffer[i]); _spiModem->transfer(buffer[i]);
_fifo_tx_addr_ptr++; _fifo_tx_addr_ptr++;
} }
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
@ -282,17 +291,17 @@ void sx126x::readBuffer(uint8_t* buffer, size_t size)
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(OP_FIFO_READ_6X); _spiModem->transfer(OP_FIFO_READ_6X);
_spiModem.transfer(_fifo_rx_addr_ptr); _spiModem->transfer(_fifo_rx_addr_ptr);
_spiModem.transfer(0x00); _spiModem->transfer(0x00);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
buffer[i] = _spiModem.transfer(0x00); buffer[i] = _spiModem->transfer(0x00);
} }
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
@ -451,7 +460,7 @@ void sx126x::end()
sleep(); sleep();
// stop SPI // stop SPI
_spiModem.end(); _spiModem->end();
_bitrate = 0; _bitrate = 0;
@ -676,7 +685,7 @@ void sx126x::onReceive(void(*callback)(uint8_t, int))
executeOpcode(OP_SET_IRQ_FLAGS_6X, buf, 8); executeOpcode(OP_SET_IRQ_FLAGS_6X, buf, 8);
#ifdef SPI_HAS_NOTUSINGINTERRUPT #ifdef SPI_HAS_NOTUSINGINTERRUPT
_spiModem.usingInterrupt(digitalPinToInterrupt(_dio0)); _spiModem->usingInterrupt(digitalPinToInterrupt(_dio0));
#endif #endif
// make function available // make function available
extern void onDio0Rise(); extern void onDio0Rise();
@ -685,7 +694,7 @@ void sx126x::onReceive(void(*callback)(uint8_t, int))
} else { } else {
detachInterrupt(digitalPinToInterrupt(_dio0)); detachInterrupt(digitalPinToInterrupt(_dio0));
#ifdef SPI_HAS_NOTUSINGINTERRUPT #ifdef SPI_HAS_NOTUSINGINTERRUPT
_spiModem.notUsingInterrupt(digitalPinToInterrupt(_dio0)); _spiModem->notUsingInterrupt(digitalPinToInterrupt(_dio0));
#endif #endif
} }
} }
@ -735,6 +744,8 @@ void sx126x::enableTCXO() {
uint8_t buf[4] = {MODE_TCXO_3_3V_6X, 0x00, 0x00, 0xFF}; uint8_t buf[4] = {MODE_TCXO_3_3V_6X, 0x00, 0x00, 0xFF};
#elif BOARD_MODEL == BOARD_TBEAM #elif BOARD_MODEL == BOARD_TBEAM
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
#elif BOARD_MODEL == BOARD_TECHO
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
#elif BOARD_MODEL == BOARD_T3S3 #elif BOARD_MODEL == BOARD_T3S3
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
#else #else
@ -965,16 +976,6 @@ void sx126x::implicitHeaderMode()
void sx126x::handleDio0Rise() void 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 // received a packet
_packetIndex = 0; _packetIndex = 0;
@ -986,12 +987,6 @@ void sx126x::handleDio0Rise()
if (_onReceive) { if (_onReceive) {
_onReceive(_index, packetLength); _onReceive(_index, packetLength);
} }
}
// else {
// Serial.println("CRCE");
// Serial.println(buf[0]);
// Serial.println(buf[1]);
// }
} }
void sx126x::updateBitrate() { void sx126x::updateBitrate() {
@ -1014,7 +1009,7 @@ void sx126x::updateBitrate() {
} }
} }
void sx126x::clearIRQStatus() { bool ISR_VECT sx126x::getPacketValidity() {
uint8_t buf[2]; uint8_t buf[2];
buf[0] = 0x00; buf[0] = 0x00;
@ -1023,6 +1018,12 @@ void sx126x::clearIRQStatus() {
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, buf, 2); executeOpcode(OP_CLEAR_IRQ_STATUS_6X, buf, 2);
if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_6X) == 0) {
return true;
} else {
return false;
}
} }
// SX127x registers // SX127x registers
#define REG_FIFO_7X 0x00 #define REG_FIFO_7X 0x00
@ -1081,7 +1082,7 @@ void sx126x::clearIRQStatus() {
#define SYNC_WORD_7X 0x12 #define SYNC_WORD_7X 0x12
sx127x::sx127x(uint8_t index, SPIClass spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy) : sx127x::sx127x(uint8_t index, SPIClass* spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy) :
RadioInterface(index), RadioInterface(index),
_spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiSettings(8E6, MSBFIRST, SPI_MODE0),
_spiModem(spi), _spiModem(spi),
@ -1116,12 +1117,12 @@ bool sx127x::preInit() {
// todo: check if this change causes issues on any platforms // todo: check if this change causes issues on any platforms
#if MCU_VARIANT == MCU_ESP32 #if MCU_VARIANT == MCU_ESP32
if (_sclk != -1 && _miso != -1 && _mosi != -1 && _ss != -1) { if (_sclk != -1 && _miso != -1 && _mosi != -1 && _ss != -1) {
_spiModem.begin(_sclk, _miso, _mosi, _ss); _spiModem->begin(_sclk, _miso, _mosi, _ss);
} else { } else {
_spiModem.begin(); _spiModem->begin();
} }
#else #else
_spiModem.begin(); _spiModem->begin();
#endif #endif
// Check modem version // Check modem version
@ -1143,10 +1144,10 @@ uint8_t ISR_VECT sx127x::singleTransfer(uint8_t address, uint8_t value) {
uint8_t response; uint8_t response;
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(address); _spiModem->transfer(address);
response = _spiModem.transfer(value); response = _spiModem->transfer(value);
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
return response; return response;
@ -1193,7 +1194,7 @@ int sx127x::begin() {
void sx127x::end() { void sx127x::end() {
sleep(); sleep();
_spiModem.end(); _spiModem->end();
_bitrate = 0; _bitrate = 0;
_radio_online = false; _radio_online = false;
_preinit_done = false; _preinit_done = false;
@ -1331,7 +1332,7 @@ void sx127x::onReceive(void(*callback)(uint8_t, int)) {
writeRegister(REG_DIO_MAPPING_1_7X, 0x00); writeRegister(REG_DIO_MAPPING_1_7X, 0x00);
#ifdef SPI_HAS_NOTUSINGINTERRUPT #ifdef SPI_HAS_NOTUSINGINTERRUPT
_spiModem.usingInterrupt(digitalPinToInterrupt(_dio0)); _spiModem->usingInterrupt(digitalPinToInterrupt(_dio0));
#endif #endif
// make function available // make function available
@ -1343,7 +1344,7 @@ void sx127x::onReceive(void(*callback)(uint8_t, int)) {
detachInterrupt(digitalPinToInterrupt(_dio0)); detachInterrupt(digitalPinToInterrupt(_dio0));
#ifdef SPI_HAS_NOTUSINGINTERRUPT #ifdef SPI_HAS_NOTUSINGINTERRUPT
_spiModem.notUsingInterrupt(digitalPinToInterrupt(_dio0)); _spiModem->notUsingInterrupt(digitalPinToInterrupt(_dio0));
#endif #endif
} }
} }
@ -1515,11 +1516,6 @@ void sx127x::optimizeModemSensitivity() {
} }
void sx127x::handleDio0Rise() { void 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; _packetIndex = 0;
int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH_7X) : readRegister(REG_RX_NB_BYTES_7X); 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)); writeRegister(REG_FIFO_ADDR_PTR_7X, readRegister(REG_FIFO_RX_CURRENT_ADDR_7X));
@ -1527,7 +1523,6 @@ void sx127x::handleDio0Rise() {
_onReceive(_index, packetLength); _onReceive(_index, packetLength);
} }
writeRegister(REG_FIFO_ADDR_PTR_7X, 0); writeRegister(REG_FIFO_ADDR_PTR_7X, 0);
}
} }
void sx127x::updateBitrate() { void sx127x::updateBitrate() {
@ -1549,11 +1544,17 @@ void sx127x::updateBitrate() {
} }
} }
void sx127x::clearIRQStatus() { bool ISR_VECT sx127x::getPacketValidity() {
int irqFlags = readRegister(REG_IRQ_FLAGS_7X); int irqFlags = readRegister(REG_IRQ_FLAGS_7X);
// Clear IRQs // Clear IRQs
writeRegister(REG_IRQ_FLAGS_7X, irqFlags); writeRegister(REG_IRQ_FLAGS_7X, irqFlags);
if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK_7X) == 0) {
return true;
} else {
return false;
}
} }
// SX128x registers // SX128x registers
@ -1599,7 +1600,7 @@ void sx127x::clearIRQStatus() {
#define FREQ_DIV_8X (double)pow(2.0, 18.0) #define FREQ_DIV_8X (double)pow(2.0, 18.0)
#define FREQ_STEP_8X (double)(XTAL_FREQ_8X / FREQ_DIV_8X) #define FREQ_STEP_8X (double)(XTAL_FREQ_8X / FREQ_DIV_8X)
sx128x::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) : sx128x::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) :
RadioInterface(index), RadioInterface(index),
_spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiSettings(8E6, MSBFIRST, SPI_MODE0),
_spiModem(spi), _spiModem(spi),
@ -1626,12 +1627,12 @@ bool sx128x::preInit() {
// todo: check if this change causes issues on any platforms // todo: check if this change causes issues on any platforms
#if MCU_VARIANT == MCU_ESP32 #if MCU_VARIANT == MCU_ESP32
if (_sclk != -1 && _miso != -1 && _mosi != -1 && _ss != -1) { if (_sclk != -1 && _miso != -1 && _mosi != -1 && _ss != -1) {
_spiModem.begin(_sclk, _miso, _mosi, _ss); _spiModem->begin(_sclk, _miso, _mosi, _ss);
} else { } else {
_spiModem.begin(); _spiModem->begin();
} }
#else #else
_spiModem.begin(); _spiModem->begin();
#endif #endif
// check version (retry for up to 2 seconds) // check version (retry for up to 2 seconds)
@ -1676,15 +1677,15 @@ uint8_t ISR_VECT sx128x::singleTransfer(uint8_t opcode, uint16_t address, uint8_
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(opcode); _spiModem->transfer(opcode);
_spiModem.transfer((address & 0xFF00) >> 8); _spiModem->transfer((address & 0xFF00) >> 8);
_spiModem.transfer(address & 0x00FF); _spiModem->transfer(address & 0x00FF);
if (opcode == OP_READ_REGISTER_8X) { if (opcode == OP_READ_REGISTER_8X) {
_spiModem.transfer(0x00); _spiModem->transfer(0x00);
} }
response = _spiModem.transfer(value); response = _spiModem->transfer(value);
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
@ -1734,15 +1735,15 @@ void sx128x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size)
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(opcode); _spiModem->transfer(opcode);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
_spiModem.transfer(buffer[i]); _spiModem->transfer(buffer[i]);
} }
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
@ -1753,16 +1754,16 @@ void sx128x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size)
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(opcode); _spiModem->transfer(opcode);
_spiModem.transfer(0x00); _spiModem->transfer(0x00);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
buffer[i] = _spiModem.transfer(0x00); buffer[i] = _spiModem->transfer(0x00);
} }
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
@ -1773,17 +1774,17 @@ void sx128x::writeBuffer(const uint8_t* buffer, size_t size)
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(OP_FIFO_WRITE_8X); _spiModem->transfer(OP_FIFO_WRITE_8X);
_spiModem.transfer(_fifo_tx_addr_ptr); _spiModem->transfer(_fifo_tx_addr_ptr);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
_spiModem.transfer(buffer[i]); _spiModem->transfer(buffer[i]);
_fifo_tx_addr_ptr++; _fifo_tx_addr_ptr++;
} }
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
@ -1794,17 +1795,17 @@ void sx128x::readBuffer(uint8_t* buffer, size_t size)
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
_spiModem.beginTransaction(_spiSettings); _spiModem->beginTransaction(_spiSettings);
_spiModem.transfer(OP_FIFO_READ_8X); _spiModem->transfer(OP_FIFO_READ_8X);
_spiModem.transfer(_fifo_rx_addr_ptr); _spiModem->transfer(_fifo_rx_addr_ptr);
_spiModem.transfer(0x00); _spiModem->transfer(0x00);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
buffer[i] = _spiModem.transfer(0x00); buffer[i] = _spiModem->transfer(0x00);
} }
_spiModem.endTransaction(); _spiModem->endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
@ -1921,7 +1922,7 @@ void sx128x::end()
sleep(); sleep();
// stop SPI // stop SPI
_spiModem.end(); _spiModem->end();
_bitrate = 0; _bitrate = 0;
@ -2043,7 +2044,7 @@ uint8_t ISR_VECT sx128x::packetSnrRaw() {
float ISR_VECT sx128x::packetSnr() { float ISR_VECT sx128x::packetSnr() {
uint8_t buf[5] = {0}; uint8_t buf[5] = {0};
executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 3); executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5);
return float(buf[1]) * 0.25; return float(buf[1]) * 0.25;
} }
@ -2083,6 +2084,27 @@ int ISR_VECT sx128x::read()
return -1; return -1;
} }
// if received new packet
if (_packetIndex == 0) {
uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2);
int size;
// If implicit header mode is enabled, read packet length as payload length instead.
// See SX1280 datasheet v3.2, page 92
if (_implicitHeaderMode == 0x80) {
size = _payloadLength;
} else {
size = rxbuf[0];
}
_fifo_rx_addr_ptr = rxbuf[1];
if (size > 255) {
size = 255;
}
readBuffer(_packet, size);
}
uint8_t byte = _packet[_packetIndex]; uint8_t byte = _packet[_packetIndex];
_packetIndex++; _packetIndex++;
return byte; return byte;
@ -2116,9 +2138,16 @@ void sx128x::onReceive(void(*callback)(uint8_t, int))
buf[0] = 0xFF; buf[0] = 0xFF;
buf[1] = 0xFF; buf[1] = 0xFF;
// On the SX1280, no RxDone IRQ is generated if a packet is received with
// an invalid header, but the modem will be taken out of single RX mode.
// This can cause the modem to not receive packets until it is reset
// again. This is documented as Errata 16.2 in the SX1280 datasheet v3.2
// (page 150) Below, the header error IRQ is mapped to dio0 so that the
// modem can be set into RX mode again on reception of a corrupted
// header.
// set dio0 masks // set dio0 masks
buf[2] = 0x00; buf[2] = 0x00;
buf[3] = IRQ_RX_DONE_MASK_8X; buf[3] = IRQ_RX_DONE_MASK_8X | IRQ_HEADER_ERROR_MASK_8X;
// set dio1 masks // set dio1 masks
buf[4] = 0x00; buf[4] = 0x00;
@ -2129,9 +2158,9 @@ void sx128x::onReceive(void(*callback)(uint8_t, int))
buf[7] = 0x00; buf[7] = 0x00;
executeOpcode(OP_SET_IRQ_FLAGS_8X, buf, 8); executeOpcode(OP_SET_IRQ_FLAGS_8X, buf, 8);
//#ifdef SPI_HAS_NOTUSINGINTERRUPT #ifdef SPI_HAS_NOTUSINGINTERRUPT
// _spiModem.usingInterrupt(digitalPinToInterrupt(_dio0)); _spiModem->usingInterrupt(digitalPinToInterrupt(_dio0));
//#endif #endif
// make function available // make function available
extern void onDio0Rise(); extern void onDio0Rise();
@ -2139,9 +2168,9 @@ void sx128x::onReceive(void(*callback)(uint8_t, int))
attachInterrupt(digitalPinToInterrupt(_dio0), onDio0Rise, RISING); attachInterrupt(digitalPinToInterrupt(_dio0), onDio0Rise, RISING);
} else { } else {
detachInterrupt(digitalPinToInterrupt(_dio0)); detachInterrupt(digitalPinToInterrupt(_dio0));
//#ifdef SPI_HAS_NOTUSINGINTERRUPT #ifdef SPI_HAS_NOTUSINGINTERRUPT
// _spiModem.notUsingInterrupt(digitalPinToInterrupt(_dio0)); _spiModem->notUsingInterrupt(digitalPinToInterrupt(_dio0));
//#endif #endif
} }
} }
@ -2160,7 +2189,12 @@ void sx128x::receive(int size)
rxAntEnable(); rxAntEnable();
uint8_t mode[3] = {0xFF, 0xFF, 0xFF}; // continuous mode // On the SX1280, there is a bug which can cause the busy line
// to remain high if a high amount of packets are received when
// in continuous RX mode. This is documented as Errata 16.1 in
// the SX1280 datasheet v3.2 (page 149)
// Therefore, the modem is set to single RX mode below instead.
uint8_t mode[3] = {0}; // single RX mode
executeOpcode(OP_RX_8X, mode, 3); executeOpcode(OP_RX_8X, mode, 3);
} }
@ -2528,9 +2562,12 @@ void sx128x::disableCrc()
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
} }
byte sx128x::random() uint8_t sx128x::random()
{ {
// todo: implement // todo: implement
return 0x4; //chosen by fair die roll
//guarenteed to be random
//https://xkcd.com/221/
} }
void sx128x::setSPIFrequency(uint32_t frequency) void sx128x::setSPIFrequency(uint32_t frequency)
@ -2564,30 +2601,23 @@ void sx128x::implicitHeaderMode()
void sx128x::handleDio0Rise() void 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 // received a packet
_packetIndex = 0; _packetIndex = 0;
uint8_t rxbuf[2] = {0}; uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2); executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2);
// If implicit header mode is enabled, read packet length as payload length instead.
// See SX1280 datasheet v3.2, page 92
if (_implicitHeaderMode == 0x80) {
_rxPacketLength = _payloadLength;
} else {
_rxPacketLength = rxbuf[0]; _rxPacketLength = rxbuf[0];
_fifo_rx_addr_ptr = rxbuf[1]; }
readBuffer(_packet, _rxPacketLength);
if (_onReceive) { if (_onReceive) {
_onReceive(_index, _rxPacketLength); _onReceive(_index, _rxPacketLength);
} }
}
} }
void sx128x::updateBitrate() { void sx128x::updateBitrate() {
@ -2599,11 +2629,11 @@ void sx128x::updateBitrate() {
_csma_slot_ms = 10; _csma_slot_ms = 10;
float target_preamble_symbols; float target_preamble_symbols;
if (_bitrate <= LORA_FAST_BITRATE_THRESHOLD) { //if (_bitrate <= LORA_FAST_BITRATE_THRESHOLD) {
target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
} else { //} else {
target_preamble_symbols = (LORA_PREAMBLE_FAST_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; /*target_preamble_symbols = (LORA_PREAMBLE_FAST_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
} }*/
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) {
target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
} else { } else {
@ -2616,7 +2646,7 @@ void sx128x::updateBitrate() {
} }
} }
void sx128x::clearIRQStatus() { bool ISR_VECT sx128x::getPacketValidity() {
uint8_t buf[2]; uint8_t buf[2];
buf[0] = 0x00; buf[0] = 0x00;
@ -2625,4 +2655,10 @@ void sx128x::clearIRQStatus() {
executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2); executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
executeOpcode(OP_CLEAR_IRQ_STATUS_8X, buf, 2); executeOpcode(OP_CLEAR_IRQ_STATUS_8X, buf, 2);
if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_8X) == 0) {
return true;
} else {
return false;
}
} }

View File

@ -11,6 +11,7 @@
#include <SPI.h> #include <SPI.h>
#include "Interfaces.h" #include "Interfaces.h"
#include "Boards.h" #include "Boards.h"
#include "src/misc/FIFOBuffer.h"
#define MAX_PKT_LENGTH 255 #define MAX_PKT_LENGTH 255
@ -128,7 +129,7 @@ public:
virtual void updateBitrate() = 0; virtual void updateBitrate() = 0;
virtual void handleDio0Rise() = 0; virtual void handleDio0Rise() = 0;
virtual void clearIRQStatus() = 0; virtual bool getPacketValidity() = 0;
uint32_t getBitrate() { return _bitrate; }; uint32_t getBitrate() { return _bitrate; };
uint8_t getIndex() { return _index; }; uint8_t getIndex() { return _index; };
void setRadioLock(bool lock) { _radio_locked = lock; }; void setRadioLock(bool lock) { _radio_locked = lock; };
@ -333,7 +334,7 @@ protected:
class sx126x : public RadioInterface { class sx126x : public RadioInterface {
public: 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 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); dio0, int busy, int rxen);
int begin(); int begin();
@ -421,11 +422,11 @@ private:
void reset(void); void reset(void);
void calibrate(void); void calibrate(void);
void calibrate_image(uint32_t frequency); void calibrate_image(uint32_t frequency);
void clearIRQStatus(); bool getPacketValidity();
private: private:
SPISettings _spiSettings; SPISettings _spiSettings;
SPIClass _spiModem; SPIClass* _spiModem;
int _ss; int _ss;
int _sclk; int _sclk;
int _mosi; int _mosi;
@ -454,7 +455,7 @@ private:
class sx127x : public RadioInterface { class sx127x : public RadioInterface {
public: public:
sx127x(uint8_t index, SPIClass spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy); sx127x(uint8_t index, SPIClass* spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy);
int begin(); int begin();
void end(); void end();
@ -511,7 +512,7 @@ public:
void updateBitrate(); void updateBitrate();
void handleDio0Rise(); void handleDio0Rise();
void clearIRQStatus(); bool getPacketValidity();
private: private:
void setSyncWord(uint8_t sw); void setSyncWord(uint8_t sw);
void explicitHeaderMode(); void explicitHeaderMode();
@ -529,7 +530,7 @@ private:
private: private:
SPISettings _spiSettings; SPISettings _spiSettings;
SPIClass _spiModem; SPIClass* _spiModem;
int _ss; int _ss;
int _sclk; int _sclk;
int _mosi; int _mosi;
@ -548,7 +549,7 @@ private:
class sx128x : public RadioInterface { class sx128x : public RadioInterface {
public: 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); 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(); int begin();
void end(); void end();
@ -608,7 +609,8 @@ public:
void handleDio0Rise(); void handleDio0Rise();
void clearIRQStatus(); bool getPacketValidity();
private: private:
void writeBuffer(const uint8_t* buffer, size_t size); void writeBuffer(const uint8_t* buffer, size_t size);
void readBuffer(uint8_t* buffer, size_t size); void readBuffer(uint8_t* buffer, size_t size);
@ -636,7 +638,7 @@ private:
private: private:
SPISettings _spiSettings; SPISettings _spiSettings;
SPIClass _spiModem; SPIClass* _spiModem;
int _ss; int _ss;
int _sclk; int _sclk;
int _mosi; int _mosi;

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# #
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, Espressif Systems (Shanghai) CO LTD, other contributors as noted. # SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, Espressif Systems (Shanghai) CO LTD, other contributors as noted.
# #

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# #
# ESP32 partition table generation tool # ESP32 partition table generation tool
# #

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# #
# spiffsgen is a tool used to generate a spiffs image from a directory # spiffsgen is a tool used to generate a spiffs image from a directory
# #

View File

@ -13,7 +13,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Radio.h" #include "Radio.hpp"
#include "Config.h" #include "Config.h"
// Included for sorting // Included for sorting
@ -142,6 +142,11 @@ uint8_t boot_vector = 0x00;
void led_rx_off() { digitalWrite(pin_led_rx, LOW); } void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); } void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); } void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
#elif BOARD_MODEL == BOARD_E22_ESP32
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
#elif BOARD_MODEL == BOARD_TBEAM #elif BOARD_MODEL == BOARD_TBEAM
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); } void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
@ -210,6 +215,11 @@ uint8_t boot_vector = 0x00;
void led_rx_off() { digitalWrite(pin_led_rx, LOW); } void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); } void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); } void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
#elif BOARD_MODEL == BOARD_TECHO
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); }
#endif #endif
#endif #endif
@ -578,6 +588,18 @@ void serial_write(uint8_t byte) {
Serial.write(byte); Serial.write(byte);
} else { } else {
SerialBT.write(byte); SerialBT.write(byte);
#if MCU_VARIANT == MCU_NRF52 && HAS_BLE
// This ensures that the TX buffer is flushed after a frame is queued in serial.
// serial_in_frame is used to ensure that the flush only happens at the end of the frame
if (serial_in_frame && byte == FEND) {
SerialBT.flushTXD();
serial_in_frame = false;
}
else if (!serial_in_frame && byte == FEND) {
serial_in_frame = true;
}
#endif
} }
#else #else
Serial.write(byte); Serial.write(byte);
@ -1100,7 +1122,7 @@ uint8_t getInterfaceCommandByte(uint8_t index) {
} }
} }
uint32_t getQueueSize(uint8_t index) { uint16_t getQueueSize(uint8_t index) {
switch (index) { switch (index) {
case 0: case 0:
return CONFIG_QUEUE_0_SIZE; return CONFIG_QUEUE_0_SIZE;
@ -1148,6 +1170,8 @@ uint32_t getQueueSize(uint8_t index) {
case 11: case 11:
return CONFIG_QUEUE_11_SIZE; return CONFIG_QUEUE_11_SIZE;
#endif #endif
default:
return CONFIG_QUEUE_0_SIZE;
} }
} }
@ -1322,7 +1346,7 @@ bool eeprom_product_valid() {
#if 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) { if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3) {
#elif PLATFORM == PLATFORM_NRF52 #elif PLATFORM == PLATFORM_NRF52
if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW || rval == PRODUCT_FREENODE) { if (rval == PRODUCT_TECHO || rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW || rval == PRODUCT_FREENODE) {
#else #else
if (false) { if (false) {
#endif #endif
@ -1350,6 +1374,8 @@ bool eeprom_model_valid() {
if (model == MODEL_FF || model == MODEL_FE) { if (model == MODEL_FF || model == MODEL_FE) {
#elif BOARD_MODEL == BOARD_TBEAM #elif BOARD_MODEL == BOARD_TBEAM
if (model == MODEL_E4 || model == MODEL_E9 || model == MODEL_E3 || model == MODEL_E8) { if (model == MODEL_E4 || model == MODEL_E9 || model == MODEL_E3 || model == MODEL_E8) {
#elif BOARD_MODEL == BOARD_TECHO
if (model == MODEL_16 || model == MODEL_17) {
#elif BOARD_MODEL == BOARD_LORA32_V1_0 #elif BOARD_MODEL == BOARD_LORA32_V1_0
if (model == MODEL_BA || model == MODEL_BB) { if (model == MODEL_BA || model == MODEL_BB) {
#elif BOARD_MODEL == BOARD_LORA32_V2_0 #elif BOARD_MODEL == BOARD_LORA32_V2_0
@ -1516,168 +1542,4 @@ void unlock_rom() {
eeprom_erase(); eeprom_erase();
} }
typedef struct FIFOBuffer #include "src/misc/FIFOBuffer.h"
{
unsigned char *begin;
unsigned char *end;
unsigned char * volatile head;
unsigned char * volatile tail;
} FIFOBuffer;
inline bool fifo_isempty(const FIFOBuffer *f) {
return f->head == f->tail;
}
inline bool fifo_isfull(const FIFOBuffer *f) {
return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1);
}
inline void fifo_push(FIFOBuffer *f, unsigned char c) {
*(f->tail) = c;
if (f->tail == f->end) {
f->tail = f->begin;
} else {
f->tail++;
}
}
inline unsigned char fifo_pop(FIFOBuffer *f) {
if(f->head == f->end) {
f->head = f->begin;
return *(f->end);
} else {
return *(f->head++);
}
}
inline void fifo_flush(FIFOBuffer *f) {
f->head = f->tail;
}
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
static inline bool fifo_isempty_locked(const FIFOBuffer *f) {
bool result;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
result = fifo_isempty(f);
}
return result;
}
static inline bool fifo_isfull_locked(const FIFOBuffer *f) {
bool result;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
result = fifo_isfull(f);
}
return result;
}
static inline void fifo_push_locked(FIFOBuffer *f, unsigned char c) {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
fifo_push(f, c);
}
}
#endif
/*
static inline unsigned char fifo_pop_locked(FIFOBuffer *f) {
unsigned char c;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
c = fifo_pop(f);
}
return c;
}
*/
inline void fifo_init(FIFOBuffer *f, unsigned char *buffer, size_t size) {
f->head = f->tail = f->begin = buffer;
f->end = buffer + size;
}
inline size_t fifo_len(FIFOBuffer *f) {
return f->end - f->begin;
}
typedef struct FIFOBuffer16
{
uint16_t *begin;
uint16_t *end;
uint16_t * volatile head;
uint16_t * volatile tail;
} FIFOBuffer16;
inline bool fifo16_isempty(const FIFOBuffer16 *f) {
return f->head == f->tail;
}
inline bool fifo16_isfull(const FIFOBuffer16 *f) {
return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1);
}
inline void fifo16_push(FIFOBuffer16 *f, uint16_t c) {
*(f->tail) = c;
if (f->tail == f->end) {
f->tail = f->begin;
} else {
f->tail++;
}
}
inline uint16_t fifo16_pop(FIFOBuffer16 *f) {
if(f->head == f->end) {
f->head = f->begin;
return *(f->end);
} else {
return *(f->head++);
}
}
inline void fifo16_flush(FIFOBuffer16 *f) {
f->head = f->tail;
}
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
static inline bool fifo16_isempty_locked(const FIFOBuffer16 *f) {
bool result;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
result = fifo16_isempty(f);
}
return result;
}
#endif
/*
static inline bool fifo16_isfull_locked(const FIFOBuffer16 *f) {
bool result;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
result = fifo16_isfull(f);
}
return result;
}
static inline void fifo16_push_locked(FIFOBuffer16 *f, uint16_t c) {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
fifo16_push(f, c);
}
}
static inline size_t fifo16_pop_locked(FIFOBuffer16 *f) {
size_t c;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
c = fifo16_pop(f);
}
return c;
}
*/
inline void fifo16_init(FIFOBuffer16 *f, uint16_t *buffer, uint16_t size) {
f->head = f->tail = f->begin = buffer;
f->end = buffer + size;
}
inline uint16_t fifo16_len(FIFOBuffer16 *f) {
return (f->end - f->begin);
}

View File

@ -1,4 +1,5 @@
board_manager: board_manager:
additional_urls: additional_urls:
- https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
- https://liberatedsystems.co.uk/rnode-firmware-ce/esp-custom-package.json - https://liberatedsystems.co.uk/rnode-firmware-ce/esp-custom-package.json
- https://raw.githubusercontent.com/RAKwireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless_index.json - https://raw.githubusercontent.com/RAKwireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless_index.json

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# Copyright (C) 2023, Mark Qvist # Copyright (C) 2023, Mark Qvist

View File

@ -1,4 +1,4 @@
#!/bin/python #!/bin/python3
# Copyright (C) 2023, Mark Qvist # Copyright (C) 2023, Mark Qvist

95
src/misc/FIFOBuffer.c Normal file
View File

@ -0,0 +1,95 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "FIFOBuffer.h"
#ifdef __cplusplus
extern "C" {
#endif
bool fifo_isempty(const FIFOBuffer *f) {
return f->head == f->tail;
}
bool fifo_isfull(const FIFOBuffer *f) {
return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1);
}
void fifo_push(FIFOBuffer *f, unsigned char c) {
*(f->tail) = c;
if (f->tail == f->end) {
f->tail = f->begin;
} else {
f->tail++;
}
}
unsigned char fifo_pop(FIFOBuffer *f) {
if(f->head == f->end) {
f->head = f->begin;
return *(f->end);
} else {
return *(f->head++);
}
}
void fifo_flush(FIFOBuffer *f) {
f->head = f->tail;
}
void fifo_init(FIFOBuffer *f, unsigned char *buffer, size_t size) {
f->head = f->tail = f->begin = buffer;
f->end = buffer + size;
}
// todo, fix this so it actually displays the amount of data in the fifo
// buffer, not just the size allocated for the buffer
size_t fifo_len(FIFOBuffer *f) {
return f->end - f->begin;
}
bool fifo16_isempty(const FIFOBuffer16 *f) {
return f->head == f->tail;
}
bool fifo16_isfull(const FIFOBuffer16 *f) {
return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1);
}
void fifo16_push(FIFOBuffer16 *f, uint16_t c) {
*(f->tail) = c;
if (f->tail == f->end) {
f->tail = f->begin;
} else {
f->tail++;
}
}
uint16_t fifo16_pop(FIFOBuffer16 *f) {
if(f->head == f->end) {
f->head = f->begin;
return *(f->end);
} else {
return *(f->head++);
}
}
void fifo16_flush(FIFOBuffer16 *f) {
f->head = f->tail;
}
void fifo16_init(FIFOBuffer16 *f, uint16_t *buffer, uint16_t size) {
f->head = f->tail = f->begin = buffer;
f->end = buffer + size;
}
uint16_t fifo16_len(FIFOBuffer16 *f) {
return (f->end - f->begin);
}
#ifdef __cplusplus
}
#endif

59
src/misc/FIFOBuffer.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef FIFOBUFFER_H
#define FIFOBUFFER_H
#ifdef __cplusplus
extern "C" {
#endif
/* An 8 bit FIFO buffer implementation */
typedef struct FIFOBuffer
{
unsigned char *begin;
unsigned char *end;
unsigned char * volatile head;
unsigned char * volatile tail;
} FIFOBuffer;
bool fifo_isempty(const FIFOBuffer *f);
bool fifo_isfull(const FIFOBuffer *f);
void fifo_push(FIFOBuffer *f, unsigned char c);
unsigned char fifo_pop(FIFOBuffer *f);
void fifo_flush(FIFOBuffer *f);
void fifo_init(FIFOBuffer *f, unsigned char *buffer, size_t size);
size_t fifo_len(FIFOBuffer *f);
/* A 16-bit implementation of the same FIFO buffer. */
typedef struct FIFOBuffer16
{
uint16_t *begin;
uint16_t *end;
uint16_t * volatile head;
uint16_t * volatile tail;
} FIFOBuffer16;
bool fifo16_isempty(const FIFOBuffer16 *f);
bool fifo16_isfull(const FIFOBuffer16 *f);
void fifo16_push(FIFOBuffer16 *f, uint16_t c);
uint16_t fifo16_pop(FIFOBuffer16 *f);
void fifo16_flush(FIFOBuffer16 *f);
void fifo16_init(FIFOBuffer16 *f, uint16_t *buffer, uint16_t size);
uint16_t fifo16_len(FIFOBuffer16 *f);
#ifdef __cplusplus
}
#endif
#endif