Service watchdog during bounded CAD

This commit is contained in:
mikecarper committed 2026-07-23 22:42:50 -07:00
1 parent fc1cfe6952
commit 9051955c6c
7 files changed
+44 -13

No files matched your search

+4
View File
@@ -53,6 +53,10 @@ public:
virtual void onAfterTransmit() { }
virtual void reboot() = 0;
virtual void powerOff() { /* no op */ }
// Reload an already-running system watchdog without enabling one. Long,
// internally bounded operations can use this while retaining their own
// timeout. Boards without an explicit watchdog need no implementation.
virtual void serviceWatchdog() { /* no op */ }
// Called by example setup() functions to signal that boot is complete.
// Boards may override to stop a boot-indicator LED sequence or similar.
// Default no-op: boards that don't care need not implement anything.
+20 -9
View File
@@ -56,6 +56,19 @@ void NRF52Board::begin() {
startup_reason = BD_STARTUP_NORMAL;
}
#if NRF52_WATCHDOG_TIMEOUT_SECONDS > 0
static void reloadWatchdogChannels() {
// Ordinarily only RR0 is enabled. If a bootloader left the watchdog running
// with a different reload channel, service every enabled channel.
const uint32_t enabled_channels = NRF_WDT->RREN & 0xFFUL;
for (uint8_t channel = 0; channel < 8; channel++) {
if (enabled_channels & (1UL << channel)) {
NRF_WDT->RR[channel] = WDT_RR_RR_Reload;
}
}
}
#endif
void NRF52Board::feedWatchdog(bool enabled) {
#if NRF52_WATCHDOG_TIMEOUT_SECONDS > 0
// The nRF52 watchdog cannot be stopped after it starts. When the persisted
@@ -77,20 +90,18 @@ void NRF52Board::feedWatchdog(bool enabled) {
NRF_WDT->TASKS_START = 1;
}
// Ordinarily only RR0 is enabled. If a bootloader left the watchdog running
// with a different reload channel, service every enabled channel rather
// than assuming ownership of RR0 and immediately entering a reset loop.
const uint32_t enabled_channels = NRF_WDT->RREN & 0xFFUL;
for (uint8_t channel = 0; channel < 8; channel++) {
if (enabled_channels & (1UL << channel)) {
NRF_WDT->RR[channel] = WDT_RR_RR_Reload;
}
}
reloadWatchdogChannels();
#else
(void)enabled;
#endif
}
void NRF52Board::serviceWatchdog() {
#if NRF52_WATCHDOG_TIMEOUT_SECONDS > 0
if (NRF_WDT->RUNSTATUS != 0) reloadWatchdogChannels();
#endif
}
#ifdef NRF52_POWER_MANAGEMENT
// Power Management global variables
uint32_t g_nrf52_reset_reason = 0; // Reset/Startup reason
+1
View File
@@ -58,6 +58,7 @@ public:
// A loop blocked forever in SoftDevice-backed flash I/O will stop feeding it
// and be reset automatically.
void feedWatchdog(bool enabled = true);
void serviceWatchdog() override;
virtual uint8_t getStartupReason() const override { return startup_reason; }
virtual float getMCUTemperature() override;
virtual void reboot() override { NVIC_SystemReset(); }
+9 -2
View File
@@ -1,6 +1,7 @@
#pragma once
#include <RadioLib.h>
#include "MeshCore.h"
#define RH_RF95_MODEM_STATUS_CLEAR 0x10
#define RH_RF95_MODEM_STATUS_HEADER_INFO_VALID 0x08
@@ -72,7 +73,7 @@ class CustomSX1276 : public SX1276 {
| RH_RF95_MODEM_STATUS_HEADER_INFO_VALID)) != 0;
}
int tryScanChannel(unsigned long timeout_ms = 2000UL) {
int tryScanChannel(unsigned long timeout_ms, mesh::MainBoard& board) {
// start CAD
int16_t state = startChannelScan();
RADIOLIB_ASSERT(state);
@@ -81,12 +82,18 @@ class CustomSX1276 : public SX1276 {
// completed, so wait on its IRQ pins with the same bounded policy used
// by the generic wrapper.
const unsigned long started = millis();
unsigned long last_watchdog_service = started;
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) {
const unsigned long now = millis();
if(now - last_watchdog_service >= 1000UL) {
board.serviceWatchdog();
last_watchdog_service = now;
}
if(now - started >= timeout_ms) {
return(RADIOLIB_ERR_RX_TIMEOUT);
}
}
+1 -1
View File
@@ -42,7 +42,7 @@ public:
protected:
int16_t performChannelScan() override {
return ((CustomSX1276 *)_radio)->tryScanChannel();
return ((CustomSX1276 *)_radio)->tryScanChannel(CAD_SCAN_TIMEOUT_MS, *_board);
}
bool radioDeepInit() override {
+8 -1
View File
@@ -621,9 +621,16 @@ int16_t RadioLibWrapper::performChannelScan() {
if (result != RADIOLIB_ERR_NONE) return result;
const unsigned long started = millis();
while (millis() - started < 2000UL) {
unsigned long last_watchdog_service = started;
while (millis() - started < CAD_SCAN_TIMEOUT_MS) {
result = _radio->getChannelScanResult();
if (result != RADIOLIB_ERR_UNKNOWN) return result;
const unsigned long now = millis();
if (now - last_watchdog_service >= 1000UL) {
_board->serviceWatchdog();
last_watchdog_service = now;
}
yield();
}
+1
View File
@@ -12,6 +12,7 @@
class RadioLibWrapper : public mesh::Radio {
protected:
static constexpr unsigned long CAD_SCAN_TIMEOUT_MS = 10000UL;
PhysicalLayer* _radio;
mesh::MainBoard* _board;
uint32_t n_recv, n_sent, n_recv_errors;