Enhance radio watchdog functionality in Dispatcher to prevent false alarms in quiet mesh environments. Introduce a composite timestamp for radio activity, incorporating last RX, ISR events, and successful TX. Update related methods in Dispatcher and RadioLibWrapper to track radio activity accurately. This improves radio management and troubleshooting capabilities.

This commit is contained in:
agessaman committed 2026-04-14 16:16:49 -07:00
1 parent 7e4f75c9a5
commit 961f829321
6 files changed
+28 -2618

No files matched your search

+21 -10
View File
@@ -58,16 +58,26 @@ void Dispatcher::loop() {
_err_flags |= ERR_EVENT_STARTRX_TIMEOUT;
}
// Radio watchdog: detect radio stuck in RX mode but not receiving any packets
if (is_recv && _radio->getLastRecvMillis() > 0) {
unsigned long silent_ms = _ms->getMillis() - _radio->getLastRecvMillis();
unsigned long since_recovery = _ms->getMillis() - last_watchdog_recovery;
if (silent_ms > RADIO_WATCHDOG_MS && since_recovery > RADIO_WATCHDOG_MS) {
_err_flags |= ERR_EVENT_RADIO_WATCHDOG;
MESH_DEBUG_PRINTLN("Radio watchdog: silent %lu ms, state=%d, recovering", silent_ms, _radio->getRadioState());
_radio->idle();
_radio->startRecv();
last_watchdog_recovery = _ms->getMillis();
// Radio watchdog: detect radio stuck in RX mode but not receiving any packets.
// Use a composite "last radio activity" timestamp: the most recent of any valid RX,
// any ISR event (even CRC errors), or any successful TX. This prevents false firings
// in quiet mesh environments where packets may be more than RADIO_WATCHDOG_MS apart,
// while still catching a truly stuck radio (PSRAM starvation → missed ISR → no activity).
{
unsigned long last_recv = _radio->getLastRecvMillis();
unsigned long last_irq = _radio->getLastRadioInterruptMillis();
unsigned long last_active = (last_recv > last_irq ? last_recv : last_irq);
if (last_radio_active_ms > last_active) last_active = last_radio_active_ms;
if (is_recv && last_active > 0) {
unsigned long silent_ms = _ms->getMillis() - last_active;
unsigned long since_recovery = _ms->getMillis() - last_watchdog_recovery;
if (silent_ms > RADIO_WATCHDOG_MS && since_recovery > RADIO_WATCHDOG_MS) {
_err_flags |= ERR_EVENT_RADIO_WATCHDOG;
MESH_DEBUG_PRINTLN("Radio watchdog: silent %lu ms, state=%d, recovering", silent_ms, _radio->getRadioState());
_radio->idle();
_radio->startRecv();
last_watchdog_recovery = _ms->getMillis();
}
}
}
@@ -81,6 +91,7 @@ void Dispatcher::loop() {
next_tx_time = futureMillis(t * getAirtimeBudgetFactor());
_radio->onSendFinished();
last_radio_active_ms = _ms->getMillis(); // TX success → radio is alive
logTx(outbound, 2 + outbound->getPathByteLen() + outbound->payload_len);
if (outbound->isRouteFlood()) {
n_sent_flood++;
+3
View File
@@ -72,6 +72,7 @@ public:
virtual uint8_t getRadioState() const { return 0; }
virtual unsigned long getLastRecvMillis() const { return 0; }
virtual unsigned long getLastRadioInterruptMillis() const { return 0; }
virtual bool isInRecvMode() const = 0;
@@ -132,6 +133,7 @@ class Dispatcher {
Packet* outbound; // current outbound packet
unsigned long outbound_expiry, outbound_start, total_air_time, rx_air_time;
unsigned long last_watchdog_recovery;
unsigned long last_radio_active_ms; // updated on any TX or RX event; used by watchdog
unsigned long next_tx_time;
unsigned long cad_busy_start;
unsigned long radio_nonrx_start;
@@ -160,6 +162,7 @@ protected:
radio_nonrx_start = 0;
prev_isrecv_mode = true;
last_watchdog_recovery = 0;
last_radio_active_ms = 0;
}
virtual DispatcherAction onRecvPacket(Packet* pkt) = 0;
Binary file not shown.
@@ -109,6 +109,7 @@ bool RadioLibWrapper::isInRecvMode() const {
int RadioLibWrapper::recvRaw(uint8_t* bytes, int sz) {
int len = 0;
if (state & STATE_INT_READY) {
last_radio_interrupt_millis = millis(); // ISR fired → radio hardware is alive
len = _radio->getPacketLength();
if (len > 0) {
if (len > sz) { len = sz; }
+3 -1
View File
@@ -12,13 +12,14 @@ protected:
uint16_t _num_floor_samples;
int32_t _floor_sample_sum;
unsigned long last_recv_millis;
unsigned long last_radio_interrupt_millis; // updated on any ISR event, even CRC errors
float packetScoreInt(float snr, int sf, int packet_len);
virtual bool isReceivingPacket() =0;
virtual void doResetAGC();
public:
RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) : _radio(&radio), _board(&board) { n_recv = n_sent = 0; last_recv_millis = 0; }
RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) : _radio(&radio), _board(&board) { n_recv = n_sent = 0; last_recv_millis = 0; last_radio_interrupt_millis = 0; }
void idle() override;
void startRecv() override;
@@ -54,6 +55,7 @@ public:
uint8_t getRadioState() const override;
unsigned long getLastRecvMillis() const override { return last_recv_millis; }
unsigned long getLastRadioInterruptMillis() const override { return last_radio_interrupt_millis; }
virtual float getLastRSSI() const override;
virtual float getLastSNR() const override;
-2607
View File
File diff suppressed because it is too large. Load diff