Skip to content

fix(mesh): return real status from reconfigure() and stop panicking on SPI errors#10430

Open
DatanoiseTV wants to merge 1 commit into
meshtastic:developfrom
DatanoiseTV:fix/radio-reconfigure-return-status
Open

fix(mesh): return real status from reconfigure() and stop panicking on SPI errors#10430
DatanoiseTV wants to merge 1 commit into
meshtastic:developfrom
DatanoiseTV:fix/radio-reconfigure-return-status

Conversation

@DatanoiseTV
Copy link
Copy Markdown
Contributor

reconfigure() in all five chip drivers (SX126x, SX128x, LR11x0, LR20x0,
RF95) was returning true unconditionally, even when individual SPI
setters failed. The caller in RadioInterface::cppInit() reboots the
device when reconfigure returns false, so the failure-recovery path was
silently disabled. Track failures in a local bool and return its
accumulated state.

Same drivers also asserted on remote SPI calls in reconfigure() and
setStandby() — a momentary glitch on the SPI bus would panic-reset the
firmware. Replaced with log-and-continue; the new return value lets the
caller make the reboot decision instead of crashing inline.

Split out from #10424 per @thebentern's request — single-concern PR.

Build verification

pio run -e t-deck-tft succeeds, no new warnings.

Attestations

  • I have tested that my proposed changes behave as described — review/static-analysis only, not on-air.
  • On-hardware testing requested from community: build-verified t-deck-tft only.

…I errors

reconfigure() in all five chip drivers (SX126x, SX128x, LR11x0, LR20x0,
RF95) was returning true unconditionally, even when individual SPI
setters failed. The caller in RadioInterface::cppInit() reboots the
device when reconfigure returns false, so the failure-recovery path was
silently disabled. Track failures in a local bool and return its
accumulated state.

Same drivers also asserted on remote SPI calls in reconfigure() and
setStandby() — a momentary glitch on the SPI bus would panic-reset the
firmware. Replaced with log-and-continue; the new return value lets the
caller make the reboot decision instead of crashing inline.
@github-actions github-actions Bot added needs-review Needs human review bugfix Pull request that fixes bugs labels May 9, 2026
@thebentern thebentern requested a review from Copilot May 9, 2026 11:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to make radio driver reconfigure() report real failure status (so RadioInterface::cppInit() can trigger its reboot-based recovery path) and to reduce panic-resets caused by SPI glitches by replacing some assert() calls with log-and-continue behavior.

Changes:

  • Update reconfigure() across multiple radio drivers to accumulate per-setter failures in a local bool ok and return it instead of always returning true.
  • Replace several assert(err == RADIOLIB_ERR_NONE) checks in radio reconfigure/standby paths with logging and failure tracking.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/mesh/SX128xInterface.cpp Adds ok accumulation in reconfigure() and removes a standby assert; still calls startReceive() unconditionally.
src/mesh/SX126xInterface.cpp Adds ok accumulation in reconfigure() and removes a standby assert; ok does not include RX gain setter, and standby failures now only log at DEBUG.
src/mesh/RF95Interface.cpp Adds ok accumulation in reconfigure(), but RF95 still has assert-based SPI panics in setStandby()/startReceive() that are reachable from reconfigure().
src/mesh/LR20x0Interface.cpp Adds ok accumulation in reconfigure() and removes standby assert; ok does not include RX gain setter and startReceive() is unconditional.
src/mesh/LR11x0Interface.cpp Adds ok accumulation in reconfigure() and removes standby assert; ok does not include RX gain setter and startReceive() is unconditional.
Comments suppressed due to low confidence (3)

src/mesh/SX126xInterface.cpp:276

  • reconfigure() now returns ok, but ok is not updated when lora.setRxBoostedGainMode(...) fails. As a result, a SPI glitch during this setter can still yield reconfigure()==true and prevent the caller’s reboot/recovery path. Consider setting ok = false on error (and optionally recording a critical error) to match the comment about tracking every SPI setter.
    // Apply RX gain mode — valid in STDBY (datasheet §9.6), matches resetAGC() pattern
    err = lora.setRxBoostedGainMode(config.lora.sx126x_rx_boosted_gain);
    if (err != RADIOLIB_ERR_NONE)
        LOG_WARN("SX126X setRxBoostedGainMode %s%d", radioLibErr, err);

src/mesh/LR11x0Interface.cpp:231

  • reconfigure() logs on setRxBoostedGainMode(...) failure but does not set ok = false, so reconfigure() can still return success after a SPI glitch in this setter. Consider marking ok false on error to ensure the caller can trigger the intended recovery path.
    // Apply RX gain mode — valid in STDBY, matches resetAGC() pattern
    err = lora.setRxBoostedGainMode(config.lora.sx126x_rx_boosted_gain);
    if (err != RADIOLIB_ERR_NONE)
        LOG_WARN("LR11x0 setRxBoostedGainMode %s%d", radioLibErr, err);

src/mesh/LR20x0Interface.cpp:259

  • setRxBoostedGainMode(...) failures are only logged, but ok is not set false. This can still make reconfigure() return true after a SPI glitch in this setter, bypassing the caller’s recovery logic. Consider setting ok = false on error.
    // Apply RX gain mode — valid in STDBY, matches resetAGC() pattern
    err = lora.setRxBoostedGainMode(config.lora.sx126x_rx_boosted_gain);
    if (err != RADIOLIB_ERR_NONE)
        LOG_WARN("LR20x0 setRxBoostedGainMode %s%d", radioLibErr, err);

@@ -262,7 +277,7 @@

startReceive(); // restart receiving
Comment on lines 292 to 299
int err = lora.standby();

if (err != RADIOLIB_ERR_NONE)
LOG_DEBUG("SX126x standby %s%d", radioLibErr, err);
#ifdef ARCH_PORTDUINO
if (err != RADIOLIB_ERR_NONE)
portduino_status.LoRa_in_error = true;
#else
assert(err == RADIOLIB_ERR_NONE);
#endif
ok = false;
}

startReceive(); // restart receiving
@@ -212,7 +232,7 @@ template <typename T> bool LR11x0Interface<T>::reconfigure()

startReceive(); // restart receiving
@@ -240,7 +260,7 @@ template <typename T> bool LR20x0Interface<T>::reconfigure()

startReceive(); // restart receiving
Comment on lines 269 to 272
startReceive(); // restart receiving

return true;
return ok;
}
@caveman99
Copy link
Copy Markdown
Member

@DatanoiseTV could you address the copilot findings here?

@caveman99 caveman99 added tech debt Code or lib references that are not up to date or propper standards triaged Reviewed by the team, has enough information and ready to work on now. cleanup Code cleanup or refactor and removed needs-review Needs human review labels May 11, 2026
@cvaldess
Copy link
Copy Markdown
Contributor

Tested on Nordic nRF54L15-DK with EBYTE E22-900M30S (SX1262) on EU_868,
stacked on top of #10227 / #10432 / #10217 / #10441 / #10271 / #10252 in
the same experiment branch.

  • Builds clean across all SX/LR/RF95 interfaces touched (5 files, no
    warnings).
  • SX1262 init came back result 0 — the new error path didn't fire, but
    the previous behaviour was the bigger concern on this port: with
    CONFIG_RESET_ON_FATAL_ERROR=n our fault handler does a
    sys_reboot(SYS_REBOOT_COLD), so a transient SPI hiccup during
    bring-up used to silently reboot the device instead of surfacing a
    status code we could log.
  • ~5 min of normal LoRa RX/TX traffic with no regressions; rxGood counts
    correctly, no spurious resets.

LGTM.

Tested-by: cvaldess

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Pull request that fixes bugs cleanup Code cleanup or refactor tech debt Code or lib references that are not up to date or propper standards triaged Reviewed by the team, has enough information and ready to work on now.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants