From 55466763bd08399a6a13768c7ebbd45d915eda7a Mon Sep 17 00:00:00 2001 From: GlassOnTin Date: Tue, 7 Apr 2026 21:03:26 +0100 Subject: [PATCH] Fix three LoRa blockers: stack overflow, warm reset, SPI mutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Stack overflow on first GPS fix: lxmf_build_message() and lxmf_build_announce() allocated ~1.2KB of local arrays on the stack (telemetry[128], payload[256], hashed_part[288], signed_part[320], signed_data[256]). Combined with LVGL, IMU, GPS, BLE this exceeded the 8KB task stack. Fixed by making these static — functions are never called concurrently. 2. hw_ready=0 after watchdog warm reset: device_init() required bt_ready which fails on warm reset (BLE hardware not fully reset). For T-Watch and T-Beam Supreme dev boards, skip the BLE requirement since we bypass signatures anyway. 3. Silent TX failure: shared_spi_mutex was removed from radio code but beacon_transmit() does SPI transactions that can collide with SD card access. Added mutex around the TX path in beacon_transmit() and diagnostic logging on TX failure. Verified: T-Beam receives watch LXMF announce (↓191 B) after GPS fix. No crash on first beacon. Interference at -74 dBm. --- Device.h | 5 +++++ LxmfBeacon.h | 13 ++++++++----- RNode_Firmware.ino | 11 +++++++++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Device.h b/Device.h index 958811f..99061fb 100644 --- a/Device.h +++ b/Device.h @@ -220,7 +220,12 @@ bool device_firmware_ok() { #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 bool device_init() { + #if BOARD_MODEL == BOARD_TWATCH_ULT || BOARD_MODEL == BOARD_TBEAM_S_V1 + // Dev boards: proceed even if BLE not ready (warm reset race) + if (true) { + #else if (bt_ready) { + #endif #if MCU_VARIANT == MCU_ESP32 for (uint8_t i=0; i sizeof(hashed_part)) return -1; memcpy(hashed_part, dest_hash16, 16); @@ -419,7 +423,6 @@ static int lxmf_build_message(uint8_t *out, size_t out_cap, sha256_once(hashed_part, hp_len, message_hash); // signed_part = hashed_part + message_hash - uint8_t signed_part[256 + 32 + 32]; size_t sp_len = hp_len + 32; if (sp_len > sizeof(signed_part)) return -1; memcpy(signed_part, hashed_part, hp_len); @@ -537,7 +540,7 @@ static int lxmf_build_announce(uint8_t *out, size_t out_cap, const char *display // signature: Ed25519Sign(dest_hash + public_key + name_hash + random_hash + app_data) // signed_data = dest_hash(16) + public_key(64) + name_hash(10) + random_hash(10) + app_data - uint8_t signed_data[256]; + static uint8_t signed_data[256]; size_t sd_len = 0; memcpy(&signed_data[sd_len], lxmf_source_hash, 16); sd_len += 16; memcpy(&signed_data[sd_len], lxmf_x25519_pk, 32); sd_len += 32; diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index 5cf8213..044cdf0 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -1017,12 +1017,19 @@ void beacon_transmit(uint16_t size) { diag_beacon_post_len = size; } + #if BOARD_MODEL == BOARD_TWATCH_ULT + if (shared_spi_mutex) xSemaphoreTake(shared_spi_mutex, portMAX_DELAY); + #endif LoRa->beginPacket(); for (uint16_t i = 0; i < size; i++) { LoRa->write(tbuf[i]); } - if (!LoRa->endPacket()) { - led_indicate_error(5); + bool tx_ok = LoRa->endPacket(); + #if BOARD_MODEL == BOARD_TWATCH_ULT + if (shared_spi_mutex) xSemaphoreGive(shared_spi_mutex); + #endif + if (!tx_ok) { + Serial.println("[beacon] TX failed"); } stat_tx++; add_airtime(size);