diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index 0a1549851..2bae9c000 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -80,6 +80,7 @@ void Dispatcher::loop() { MESH_DEBUG_PRINTLN("%s Dispatcher::loop(): WARNING: outbound packed send timed out!", getLogDateTime()); _radio->onSendFinished(); + _radio->onTXRXFault(); logTxFail(outbound, 2 + outbound->path_len + outbound->payload_len); releasePacket(outbound); // return to pool diff --git a/src/Dispatcher.h b/src/Dispatcher.h index 25a41d82c..406cbd857 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -56,6 +56,11 @@ class Radio { */ virtual void onSendFinished() = 0; + /** + * \brief optional hook for handling radio TX/RX fault recovery + */ + virtual void onTXRXFault() { } + /** * \brief do any processing needed on each loop cycle */ diff --git a/src/helpers/radiolib/CustomSX1262Wrapper.h b/src/helpers/radiolib/CustomSX1262Wrapper.h index 1afee5e8b..78433b422 100644 --- a/src/helpers/radiolib/CustomSX1262Wrapper.h +++ b/src/helpers/radiolib/CustomSX1262Wrapper.h @@ -19,6 +19,21 @@ class CustomSX1262Wrapper : public RadioLibWrapper { int sf = ((CustomSX1262 *)_radio)->spreadingFactor; return packetScoreInt(snr, sf, packet_len); } + void onTXRXFault() override { + auto radio = static_cast(_radio); + int16_t result = radio->reset(); + if (result != RADIOLIB_ERR_NONE) { + MESH_DEBUG_PRINTLN("CustomSX1262Wrapper: reset failed (%d)", result); + return; + } + if (!radio->std_init()) { + MESH_DEBUG_PRINTLN("CustomSX1262Wrapper: re-init failed"); + return; + } + // Rebind ISR and restart receive after reset. + RadioLibWrapper::begin(); + startRecv(); + } virtual void powerOff() override { ((CustomSX1262 *)_radio)->sleep(false); } diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index e34078211..e2c1743a0 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -24,6 +24,32 @@ void setFlag(void) { state |= STATE_INT_READY; } +// Decide which radio TX/RX errors warrant a reset (hardware/timeout), versus logic/parameter errors. +static bool shouldResetOnTXRXError(int err) { +#ifdef RADIOLIB_ERR_TX_TIMEOUT + if (err == RADIOLIB_ERR_TX_TIMEOUT) return true; +#endif +#ifdef RADIOLIB_ERR_SPI_CMD_FAILED + if (err == RADIOLIB_ERR_SPI_CMD_FAILED) return true; +#endif +#ifdef RADIOLIB_ERR_SPI_CMD_INVALID + if (err == RADIOLIB_ERR_SPI_CMD_INVALID) return true; +#endif +#ifdef RADIOLIB_ERR_SPI_WRITE_FAILED + if (err == RADIOLIB_ERR_SPI_WRITE_FAILED) return true; +#endif +#ifdef RADIOLIB_ERR_SPI_READ_FAILED + if (err == RADIOLIB_ERR_SPI_READ_FAILED) return true; +#endif +#ifdef RADIOLIB_ERR_CHIP_NOT_FOUND + if (err == RADIOLIB_ERR_CHIP_NOT_FOUND) return true; +#endif +#ifdef RADIOLIB_ERR_DEVICE_BUSY + if (err == RADIOLIB_ERR_DEVICE_BUSY) return true; +#endif + return false; +} + void RadioLibWrapper::begin() { _radio->setPacketReceivedAction(setFlag); // this is also SentComplete interrupt state = STATE_IDLE; @@ -88,6 +114,13 @@ void RadioLibWrapper::startRecv() { state = STATE_RX; } else { MESH_DEBUG_PRINTLN("RadioLibWrapper: error: startReceive(%d)", err); + static bool in_rx_recover = false; + // Prevent recursive recovery attempts if startReceive keeps failing during re-init. + if (!in_rx_recover && shouldResetOnTXRXError(err)) { + in_rx_recover = true; + onTXRXFault(); + in_rx_recover = false; + } } } @@ -114,12 +147,7 @@ int RadioLibWrapper::recvRaw(uint8_t* bytes, int sz) { } if (state != STATE_RX) { - int err = _radio->startReceive(); - if (err == RADIOLIB_ERR_NONE) { - state = STATE_RX; - } else { - MESH_DEBUG_PRINTLN("RadioLibWrapper: error: startReceive(%d)", err); - } + startRecv(); } return len; } @@ -137,6 +165,11 @@ bool RadioLibWrapper::startSendRaw(const uint8_t* bytes, int len) { } MESH_DEBUG_PRINTLN("RadioLibWrapper: error: startTransmit(%d)", err); idle(); // trigger another startRecv() + if (shouldResetOnTXRXError(err)) { + onTXRXFault(); + } else { + startRecv(); + } _board->onAfterTransmit(); return false; } diff --git a/variants/rak4631/RAK4631Board.h b/variants/rak4631/RAK4631Board.h index a181256b0..7b33cf109 100644 --- a/variants/rak4631/RAK4631Board.h +++ b/variants/rak4631/RAK4631Board.h @@ -7,7 +7,7 @@ // LoRa radio module pins for RAK4631 #define P_LORA_DIO_1 47 #define P_LORA_NSS 42 -#define P_LORA_RESET RADIOLIB_NC // 38 +#define P_LORA_RESET 38 #define P_LORA_BUSY 46 #define P_LORA_SCLK 43 #define P_LORA_MISO 45