Skip to content

Recover the radio by re-initialising it instead of reporting a fault - #3

Closed
caveman99 wants to merge 1 commit into
meshmy:fix/radio-spi-transient-failure-assertsfrom
caveman99:radio-reinit-recovery
Closed

caveman99 wants to merge 1 commit into
meshmy:fix/radio-spi-transient-failure-assertsfrom
caveman99:radio-reinit-recovery

Conversation

@caveman99

Copy link
Copy Markdown
Collaborator

Targets this PR's branch. Builds on the assert removal by making the recovered-from state actually recover.

WRONG_MODEM from a LoRa-only setter does not mean anything put the chip into FSK. RadioLib checks the packet type first, and getPacketType() discards the SPI result:

uint8_t SX126x::getPacketType() {
  uint8_t data = 0xFF;
  this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1);
  return(data);
}

So a failed read leaves 0xFF, which is not PACKET_TYPE_LORA, and every LoRa setter returns WRONG_MODEM. The error covers three cases: the chip really is in FSK, SetPacketType was never issued because begin() did not complete, or the chip is asleep/unresponsive. Recording a critical error leaves it in that state, which is what issue meshtastic#11220 reports: a T3-S3 flashed fresh, region UNSET, then a runtime region change fails every setter and the region reverts.

Changes:

  • the three runtime SPI sites and a WRONG_MODEM during reconfigure() request recovery instead of recording a fault, in all five interfaces
  • loop() tears the interface down and runs initLoRa() again, generalising what the Portduino daemon already did for portduino_status.LoRa_in_error
  • the ISR is detached before the interface is destroyed, since ~RadioLibInterface only clears instance and setDio1Action would otherwise be left pointing at freed memory

Only WRONG_MODEM arms recovery from reconfigure(). An out-of-range setting still records INVALID_RADIO_SETTING on its own, because re-initialising cannot fix operator config and would retry forever.

On embedded targets a second failed attempt reports NO_RADIO and stops retrying. Portduino keeps its existing reboot, and its CH341 re-enumeration stays Portduino-only.

Not tested on hardware; the failure it targets needs a device that reproduces meshtastic#11220.

A LoRa-only setter returning WRONG_MODEM does not mean the chip was put into FSK: RadioLib reads the packet type first and getPacketType() discards the SPI result, leaving 0xFF when the chip is asleep, unresponsive or never received SetPacketType. Recording a critical error leaves the radio in that state.

The runtime SPI failures and a WRONG_MODEM during reconfigure now request recovery instead, and the loop tears the interface down and runs initLoRa() again, which is what the Portduino daemon already did for its own error flag. The ISR is detached before the interface is destroyed so a pending DIO edge cannot reach freed memory.

Only WRONG_MODEM arms recovery from reconfigure; an out-of-range setting still records INVALID_RADIO_SETTING alone, since re-initialising cannot fix operator config and would retry forever. On embedded targets a second failed attempt reports NO_RADIO and stops retrying; Portduino keeps its existing reboot.
@ndoo
ndoo deleted the branch meshmy:fix/radio-spi-transient-failure-asserts August 28, 2026 18:30
@ndoo ndoo closed this Aug 28, 2026
ndoo pushed a commit that referenced this pull request Sep 4, 2026
meshtastic#11715)

The T-Deck Pro V1.1 boots into Critical Fault #3 (NoRadio) because
LORA_EN (GPIO 46) is never driven high, so the SX1262 never receives
power and is never detected.

Before meshtastic#9438 this pin was driven from src/main.cpp under
`#elif defined(T_DECK_PRO)`, which covered both the t-deck-pro and the
t-deck-pro-v1_1 environments, since both build with -D T_DECK_PRO.
meshtastic#9438 moved that block into variants/esp32s3/t-deck-pro/variant.cpp and
linked it with a build_src_filter added only to the t-deck-pro
environment. t-deck-pro-v1_1 had been added five days earlier and has
neither a variant.cpp nor a build_src_filter, so it silently lost the
pin setup: earlyInitVariant() is a weak symbol with an empty default in
main.cpp, so a missing strong override produces no compile or link
error.

Give t-deck-pro-v1_1 the same variant.cpp as t-deck-pro, plus the
build_src_filter needed to actually link it. This also restores the
LORA_CS, SDCARD_CS and PIN_EINK_CS pre-init lost at the same time; all
three share the SPI bus and need their chip selects deasserted before
the bus is used.

Fixes meshtastic#11708

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants