diff --git a/src/helpers/radiolib/CustomSX1276.h b/src/helpers/radiolib/CustomSX1276.h index e6f3270b..d34c028c 100644 --- a/src/helpers/radiolib/CustomSX1276.h +++ b/src/helpers/radiolib/CustomSX1276.h @@ -72,19 +72,24 @@ class CustomSX1276 : public SX1276 { | RH_RF95_MODEM_STATUS_HEADER_INFO_VALID)) != 0; } - int tryScanChannel() { + int tryScanChannel(unsigned long timeout_ms = 2000UL) { // start CAD int16_t state = startChannelScan(); RADIOLIB_ASSERT(state); - // wait for channel activity detected or timeout - unsigned long timeout = millis() + 16; - while(!this->mod->hal->digitalRead(this->mod->getIrq()) && millis() < timeout) { + // SX127x getChannelScanResult() reports a free channel before CAD has + // completed, so wait on its IRQ pins with the same bounded policy used + // by the generic wrapper. + const unsigned long started = millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->hal->digitalRead(this->mod->getGpio())) { return(RADIOLIB_PREAMBLE_DETECTED); } + if(millis() - started >= timeout_ms) { + return(RADIOLIB_ERR_RX_TIMEOUT); + } } - return 0; // timed out + return(RADIOLIB_CHANNEL_FREE); } }; diff --git a/src/helpers/radiolib/CustomSX1276Wrapper.h b/src/helpers/radiolib/CustomSX1276Wrapper.h index a85419ba..5f8138dc 100644 --- a/src/helpers/radiolib/CustomSX1276Wrapper.h +++ b/src/helpers/radiolib/CustomSX1276Wrapper.h @@ -41,6 +41,10 @@ public: uint8_t getSpreadingFactor() const override { return ((CustomSX1276 *)_radio)->spreadingFactor; } protected: + int16_t performChannelScan() override { + return ((CustomSX1276 *)_radio)->tryScanChannel(); + } + bool radioDeepInit() override { return ((CustomSX1276 *)_radio)->std_init(); } diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index 31be6de7..5576de9a 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -614,7 +614,21 @@ void RadioLibWrapper::onSendFinished() { } int16_t RadioLibWrapper::performChannelScan() { - return _radio->scanChannel(); + // RadioLib's blocking scanChannel() waits forever if the radio never raises + // its CAD-done IRQ. Keep CAD bounded so a missing IRQ cannot starve the main + // loop until the MCU watchdog resets the node. + int16_t result = _radio->startChannelScan(); + if (result != RADIOLIB_ERR_NONE) return result; + + const unsigned long started = millis(); + while (millis() - started < 2000UL) { + result = _radio->getChannelScanResult(); + if (result != RADIOLIB_ERR_UNKNOWN) return result; + yield(); + } + + MESH_DEBUG_PRINTLN("RadioLibWrapper: CAD scan timed out"); + return RADIOLIB_ERR_RX_TIMEOUT; } bool RadioLibWrapper::isChannelActive() {