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:
1 parent
7e4f75c9a5
commit
961f829321
6 files changed
+28
-2618
No files matched your search
+21
-10
@@ -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++;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user