From c89a0e9929f4247d40569f568ccb1d216cc66762 Mon Sep 17 00:00:00 2001 From: Quency-D Date: Thu, 22 Jan 2026 15:03:40 +0800 Subject: [PATCH 1/4] Add an external watchdog module --- examples/companion_radio/main.cpp | 7 ++++++ examples/simple_repeater/main.cpp | 12 +++++++++- examples/simple_room_server/main.cpp | 7 ++++++ examples/simple_secure_chat/main.cpp | 7 ++++++ examples/simple_sensor/main.cpp | 7 ++++++ src/helpers/ExWatchdogManager.h | 11 +++++++++ variants/heltec_mesh_solar/platformio.ini | 5 ++++ variants/heltec_mesh_solar/target.cpp | 28 +++++++++++++++++++++++ variants/heltec_mesh_solar/target.h | 11 +++++++++ variants/heltec_mesh_solar/variant.h | 4 ++-- 10 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 src/helpers/ExWatchdogManager.h diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 82c8c21d93..2035d78974 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -110,6 +110,10 @@ void setup() { board.begin(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.begin(); +#endif + #ifdef DISPLAY_CLASS DisplayDriver* disp = NULL; if (display.begin()) { @@ -228,4 +232,7 @@ void loop() { ui_task.loop(); #endif rtc_clock.tick(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.loop(); +#endif } diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 8c745613e7..f371cb4651 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -29,6 +29,10 @@ void setup() { board.begin(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.begin(); +#endif + // For power saving lastActive = millis(); // mark last active time since boot @@ -124,11 +128,17 @@ void loop() { ui_task.loop(); #endif rtc_clock.tick(); - +#ifdef HAS_EX_WATCHDOG + ex_watchdog.loop(); +#endif if (the_mesh.getNodePrefs()->powersaving_enabled && // To check if power saving is enabled the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep if (!the_mesh.hasPendingWork()) { // No pending work. Safe to sleep +#ifdef HAS_EX_WATCHDOG + board.sleep(ex_watchdog.getIntervalMs()>1800?1800:ex_watchdog.getIntervalMs()); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet +#else board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet +#endif lastActive = millis(); nextSleepinSecs = 5; // Default: To work for 5s and sleep again } else { diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 1a3b4d6e0f..e468b84e87 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -24,6 +24,10 @@ void setup() { board.begin(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.begin(); +#endif + #ifdef DISPLAY_CLASS if (display.begin()) { display.startFrame(); @@ -111,4 +115,7 @@ void loop() { ui_task.loop(); #endif rtc_clock.tick(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.loop(); +#endif } diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index da1bac5b32..693ebfeea6 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -559,6 +559,10 @@ void setup() { board.begin(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.begin(); +#endif + if (!radio_init()) { halt(); } fast_rng.begin(radio_get_rng_seed()); @@ -588,4 +592,7 @@ void setup() { void loop() { the_mesh.loop(); rtc_clock.tick(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.loop(); +#endif } diff --git a/examples/simple_sensor/main.cpp b/examples/simple_sensor/main.cpp index a5fcc1484f..9712a20724 100644 --- a/examples/simple_sensor/main.cpp +++ b/examples/simple_sensor/main.cpp @@ -58,6 +58,10 @@ void setup() { board.begin(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.begin(); +#endif + #ifdef DISPLAY_CLASS if (display.begin()) { display.startFrame(); @@ -145,4 +149,7 @@ void loop() { ui_task.loop(); #endif rtc_clock.tick(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.loop(); +#endif } diff --git a/src/helpers/ExWatchdogManager.h b/src/helpers/ExWatchdogManager.h new file mode 100644 index 0000000000..65f178b0cd --- /dev/null +++ b/src/helpers/ExWatchdogManager.h @@ -0,0 +1,11 @@ +#pragma once + +class ExWatchdogManager { +public: + unsigned long next_feed_watchdog; + ExWatchdogManager() { next_feed_watchdog = 0; } + virtual bool begin() { return false; } + virtual void loop() { } + virtual unsigned long getIntervalMs() const { return 0; } + virtual void feed() { } +}; diff --git a/variants/heltec_mesh_solar/platformio.ini b/variants/heltec_mesh_solar/platformio.ini index 7bfbac85a7..3eb51f0a59 100644 --- a/variants/heltec_mesh_solar/platformio.ini +++ b/variants/heltec_mesh_solar/platformio.ini @@ -14,6 +14,11 @@ build_flags = ${nrf52_base.build_flags} -D LORA_TX_POWER=22 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 + -D HAS_EX_WATCHDOG + -D EX_WATCHDOG_DONE_PIN=9 + -D EX_WATCHDOG_WAKE_PIN=10 + -D EX_WATCHDOG_TIMEOUT_MS=480000 ;(6*60*1000) ; 6 minute watchdog + build_src_filter = ${nrf52_base.build_src_filter} + +<../variants/heltec_mesh_solar> diff --git a/variants/heltec_mesh_solar/target.cpp b/variants/heltec_mesh_solar/target.cpp index ad79f71712..060f20c38f 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -13,6 +13,7 @@ VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); SolarSensorManager sensors = SolarSensorManager(nmea); +SolarExWatchdog ex_watchdog; #ifdef DISPLAY_CLASS DISPLAY_CLASS display; @@ -121,3 +122,30 @@ bool SolarSensorManager::setSettingValue(const char* name, const char* value) { } return false; // not supported } + +bool SolarExWatchdog::begin() { + next_feed_watchdog = 0; + pinMode(EX_WATCHDOG_WAKE_PIN, INPUT); + pinMode(EX_WATCHDOG_DONE_PIN, OUTPUT); + delay(1); + digitalWrite(EX_WATCHDOG_DONE_PIN, LOW); + delay(1); + feed(); + return true; +} +void SolarExWatchdog::loop() { + if (millis() > next_feed_watchdog) { + feed(); + next_feed_watchdog = millis() + EX_WATCHDOG_TIMEOUT_MS; + } +} + +unsigned long SolarExWatchdog::getIntervalMs() const { + return next_feed_watchdog - millis(); +} + +void SolarExWatchdog::feed() { + digitalWrite(EX_WATCHDOG_DONE_PIN, HIGH); + delay(1); + digitalWrite(EX_WATCHDOG_DONE_PIN, LOW); +} \ No newline at end of file diff --git a/variants/heltec_mesh_solar/target.h b/variants/heltec_mesh_solar/target.h index e301a27351..c535f68ec8 100644 --- a/variants/heltec_mesh_solar/target.h +++ b/variants/heltec_mesh_solar/target.h @@ -8,6 +8,7 @@ #include #include #include +#include #ifdef DISPLAY_CLASS #include #endif @@ -30,10 +31,20 @@ class SolarSensorManager : public SensorManager { bool setSettingValue(const char* name, const char* value) override; }; +class SolarExWatchdog : public ExWatchdogManager { +public: + SolarExWatchdog() {} + bool begin() override; + void loop() override; + unsigned long getIntervalMs() const override; + void feed() override; +}; + extern MeshSolarBoard board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SolarSensorManager sensors; +extern SolarExWatchdog ex_watchdog; #ifdef DISPLAY_CLASS extern DISPLAY_CLASS display; diff --git a/variants/heltec_mesh_solar/variant.h b/variants/heltec_mesh_solar/variant.h index 14956619f0..3c1b378dfa 100644 --- a/variants/heltec_mesh_solar/variant.h +++ b/variants/heltec_mesh_solar/variant.h @@ -34,8 +34,8 @@ #define PIN_SERIAL1_RX (37) #define PIN_SERIAL1_TX (39) -#define PIN_SERIAL2_RX (9) -#define PIN_SERIAL2_TX (10) +#define PIN_SERIAL2_RX (-1) +#define PIN_SERIAL2_TX (-1) //////////////////////////////////////////////////////////////////////////////// // I2C pin definition From 53ff4ed57f69c38c5aae7e41e51aa1016cdf2016 Mon Sep 17 00:00:00 2001 From: Quency-D Date: Mon, 9 Feb 2026 11:43:41 +0800 Subject: [PATCH 2/4] Fix watchdog code in repeater --- examples/simple_repeater/main.cpp | 23 ++++++++++++++++++++--- src/helpers/ExWatchdogManager.h | 3 ++- variants/heltec_mesh_solar/target.cpp | 9 +++++++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 6cc2ac77a8..1760abeaaf 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -29,6 +29,10 @@ void setup() { board.begin(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.begin(); +#endif + #if defined(MESH_DEBUG) && defined(NRF52_PLATFORM) // give some extra time for serial to settle so // boot debug messages can be seen on terminal @@ -134,11 +138,24 @@ void loop() { #endif rtc_clock.tick(); +#ifdef HAS_EX_WATCHDOG + ex_watchdog.loop(); +#endif if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) { - #if defined(NRF52_PLATFORM) +#if defined(NRF52_PLATFORM) +#ifdef HAS_EX_WATCHDOG + uint32_t sleep_interval = ex_watchdog.getIntervalMs()/1000; + board.sleep((sleep_interval > 1800) ? 1800 : sleep_interval); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet +#else + board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet +#endif board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible - #else +#else if (the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep +#ifdef HAS_EX_WATCHDOG + uint32_t sleep_interval = ex_watchdog.getIntervalMs()/1000; + board.sleep((sleep_interval > 1800) ? 1800 : sleep_interval); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet +#else board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet #endif lastActive = millis(); @@ -146,6 +163,6 @@ void loop() { } else { nextSleepinSecs += 5; // When there is pending work, to work another 5s } - #endif +#endif } } diff --git a/src/helpers/ExWatchdogManager.h b/src/helpers/ExWatchdogManager.h index 65f178b0cd..4df901b7f6 100644 --- a/src/helpers/ExWatchdogManager.h +++ b/src/helpers/ExWatchdogManager.h @@ -1,8 +1,9 @@ #pragma once class ExWatchdogManager { -public: +protected: unsigned long next_feed_watchdog; +public: ExWatchdogManager() { next_feed_watchdog = 0; } virtual bool begin() { return false; } virtual void loop() { } diff --git a/variants/heltec_mesh_solar/target.cpp b/variants/heltec_mesh_solar/target.cpp index c9172aa1a6..7eb44bfafb 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -141,11 +141,16 @@ void SolarExWatchdog::loop() { } unsigned long SolarExWatchdog::getIntervalMs() const { - return next_feed_watchdog - millis(); + unsigned long interval_ms = 0; + interval_ms = next_feed_watchdog - millis(); + if(interval_ms > EX_WATCHDOG_TIMEOUT_MS) { + interval_ms = EX_WATCHDOG_TIMEOUT_MS; + } + return interval_ms; } void SolarExWatchdog::feed() { digitalWrite(EX_WATCHDOG_DONE_PIN, HIGH); delay(1); digitalWrite(EX_WATCHDOG_DONE_PIN, LOW); -} \ No newline at end of file +} From 1ab8a6f6da2de8c94c94d1e29b93bdaeef02ef6a Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Wed, 4 Mar 2026 03:13:53 +0100 Subject: [PATCH 3/4] Address review comments --- examples/companion_radio/main.cpp | 8 +++--- examples/simple_repeater/main.cpp | 16 ++++++------ examples/simple_room_server/main.cpp | 8 +++--- examples/simple_secure_chat/main.cpp | 8 +++--- examples/simple_sensor/main.cpp | 8 +++--- ...dogManager.h => ExternalWatchdogManager.h} | 4 +-- variants/heltec_mesh_solar/platformio.ini | 8 +++--- variants/heltec_mesh_solar/target.cpp | 26 +++++++++---------- variants/heltec_mesh_solar/target.h | 8 +++--- 9 files changed, 47 insertions(+), 47 deletions(-) rename src/helpers/{ExWatchdogManager.h => ExternalWatchdogManager.h} (71%) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 3c69625a15..88ef392455 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -110,8 +110,8 @@ void setup() { board.begin(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.begin(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.begin(); #endif #ifdef DISPLAY_CLASS @@ -229,7 +229,7 @@ void loop() { ui_task.loop(); #endif rtc_clock.tick(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.loop(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.loop(); #endif } diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 1760abeaaf..f0271c8896 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -29,8 +29,8 @@ void setup() { board.begin(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.begin(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.begin(); #endif #if defined(MESH_DEBUG) && defined(NRF52_PLATFORM) @@ -138,13 +138,13 @@ void loop() { #endif rtc_clock.tick(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.loop(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.loop(); #endif if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) { #if defined(NRF52_PLATFORM) -#ifdef HAS_EX_WATCHDOG - uint32_t sleep_interval = ex_watchdog.getIntervalMs()/1000; +#ifdef HAS_EXTERNAL_WATCHDOG + uint32_t sleep_interval = external_watchdog.getIntervalMs()/1000; board.sleep((sleep_interval > 1800) ? 1800 : sleep_interval); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet #else board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet @@ -152,8 +152,8 @@ void loop() { board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible #else if (the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep -#ifdef HAS_EX_WATCHDOG - uint32_t sleep_interval = ex_watchdog.getIntervalMs()/1000; +#ifdef HAS_EXTERNAL_WATCHDOG + uint32_t sleep_interval = external_watchdog.getIntervalMs()/1000; board.sleep((sleep_interval > 1800) ? 1800 : sleep_interval); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet #else board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index bb6a860b82..d20ebc6d19 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -24,8 +24,8 @@ void setup() { board.begin(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.begin(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.begin(); #endif #ifdef DISPLAY_CLASS @@ -117,7 +117,7 @@ void loop() { ui_task.loop(); #endif rtc_clock.tick(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.loop(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.loop(); #endif } diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index a218223634..a21741db51 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -559,8 +559,8 @@ void setup() { board.begin(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.begin(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.begin(); #endif if (!radio_init()) { halt(); } @@ -594,7 +594,7 @@ void setup() { void loop() { the_mesh.loop(); rtc_clock.tick(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.loop(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.loop(); #endif } diff --git a/examples/simple_sensor/main.cpp b/examples/simple_sensor/main.cpp index e9ff9387ea..346f4dfc99 100644 --- a/examples/simple_sensor/main.cpp +++ b/examples/simple_sensor/main.cpp @@ -58,8 +58,8 @@ void setup() { board.begin(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.begin(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.begin(); #endif #ifdef DISPLAY_CLASS @@ -151,7 +151,7 @@ void loop() { ui_task.loop(); #endif rtc_clock.tick(); -#ifdef HAS_EX_WATCHDOG - ex_watchdog.loop(); +#ifdef HAS_EXTERNAL_WATCHDOG + external_watchdog.loop(); #endif } diff --git a/src/helpers/ExWatchdogManager.h b/src/helpers/ExternalWatchdogManager.h similarity index 71% rename from src/helpers/ExWatchdogManager.h rename to src/helpers/ExternalWatchdogManager.h index 4df901b7f6..9ef8abaa61 100644 --- a/src/helpers/ExWatchdogManager.h +++ b/src/helpers/ExternalWatchdogManager.h @@ -1,10 +1,10 @@ #pragma once -class ExWatchdogManager { +class ExternalWatchdogManager { protected: unsigned long next_feed_watchdog; public: - ExWatchdogManager() { next_feed_watchdog = 0; } + ExternalWatchdogManager() { next_feed_watchdog = 0; } virtual bool begin() { return false; } virtual void loop() { } virtual unsigned long getIntervalMs() const { return 0; } diff --git a/variants/heltec_mesh_solar/platformio.ini b/variants/heltec_mesh_solar/platformio.ini index 3eb51f0a59..1bc7e7fa7a 100644 --- a/variants/heltec_mesh_solar/platformio.ini +++ b/variants/heltec_mesh_solar/platformio.ini @@ -14,10 +14,10 @@ build_flags = ${nrf52_base.build_flags} -D LORA_TX_POWER=22 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 - -D HAS_EX_WATCHDOG - -D EX_WATCHDOG_DONE_PIN=9 - -D EX_WATCHDOG_WAKE_PIN=10 - -D EX_WATCHDOG_TIMEOUT_MS=480000 ;(6*60*1000) ; 6 minute watchdog + -D HAS_EXTERNAL_WATCHDOG + -D EXTERNAL_WATCHDOG_DONE_PIN=9 + -D EXTERNAL_WATCHDOG_WAKE_PIN=10 + -D EXTERNAL_WATCHDOG_TIMEOUT_MS=480000 ;(6*60*1000) ; 6 minute watchdog build_src_filter = ${nrf52_base.build_src_filter} + diff --git a/variants/heltec_mesh_solar/target.cpp b/variants/heltec_mesh_solar/target.cpp index 7eb44bfafb..fa2342026d 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -13,7 +13,7 @@ VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); SolarSensorManager sensors = SolarSensorManager(nmea); -SolarExWatchdog ex_watchdog; +SolarExternalWatchdog external_watchdog; #ifdef DISPLAY_CLASS DISPLAY_CLASS display; @@ -123,34 +123,34 @@ bool SolarSensorManager::setSettingValue(const char* name, const char* value) { return false; // not supported } -bool SolarExWatchdog::begin() { +bool SolarExternalWatchdog::begin() { next_feed_watchdog = 0; - pinMode(EX_WATCHDOG_WAKE_PIN, INPUT); - pinMode(EX_WATCHDOG_DONE_PIN, OUTPUT); + pinMode(EXTERNAL_WATCHDOG_WAKE_PIN, INPUT); + pinMode(EXTERNAL_WATCHDOG_DONE_PIN, OUTPUT); delay(1); - digitalWrite(EX_WATCHDOG_DONE_PIN, LOW); + digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, LOW); delay(1); feed(); return true; } -void SolarExWatchdog::loop() { +void SolarExternalWatchdog::loop() { if (millis() > next_feed_watchdog) { feed(); - next_feed_watchdog = millis() + EX_WATCHDOG_TIMEOUT_MS; + next_feed_watchdog = millis() + EXTERNAL_WATCHDOG_TIMEOUT_MS; } } -unsigned long SolarExWatchdog::getIntervalMs() const { +unsigned long SolarExternalWatchdog::getIntervalMs() const { unsigned long interval_ms = 0; interval_ms = next_feed_watchdog - millis(); - if(interval_ms > EX_WATCHDOG_TIMEOUT_MS) { - interval_ms = EX_WATCHDOG_TIMEOUT_MS; + if(interval_ms > EXTERNAL_WATCHDOG_TIMEOUT_MS) { + interval_ms = EXTERNAL_WATCHDOG_TIMEOUT_MS; } return interval_ms; } -void SolarExWatchdog::feed() { - digitalWrite(EX_WATCHDOG_DONE_PIN, HIGH); +void SolarExternalWatchdog::feed() { + digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, HIGH); delay(1); - digitalWrite(EX_WATCHDOG_DONE_PIN, LOW); + digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, LOW); } diff --git a/variants/heltec_mesh_solar/target.h b/variants/heltec_mesh_solar/target.h index 3fc786726e..124e3afb3e 100644 --- a/variants/heltec_mesh_solar/target.h +++ b/variants/heltec_mesh_solar/target.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #ifdef DISPLAY_CLASS #include #endif @@ -31,9 +31,9 @@ class SolarSensorManager : public SensorManager { bool setSettingValue(const char* name, const char* value) override; }; -class SolarExWatchdog : public ExWatchdogManager { +class SolarExternalWatchdog : public ExternalWatchdogManager { public: - SolarExWatchdog() {} + SolarExternalWatchdog() {} bool begin() override; void loop() override; unsigned long getIntervalMs() const override; @@ -44,7 +44,7 @@ extern MeshSolarBoard board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SolarSensorManager sensors; -extern SolarExWatchdog ex_watchdog; +extern SolarExternalWatchdog external_watchdog; #ifdef DISPLAY_CLASS extern DISPLAY_CLASS display; From 363ac44461a9299c9a43641598c18ba65fb6ffea Mon Sep 17 00:00:00 2001 From: Quency-D Date: Mon, 27 Apr 2026 15:32:02 +0800 Subject: [PATCH 4/4] Fix external watchdog timing around sleep --- examples/simple_repeater/main.cpp | 11 ++++++----- src/helpers/ExternalWatchdogManager.h | 4 ++-- variants/heltec_mesh_solar/platformio.ini | 4 ++-- variants/heltec_mesh_solar/target.cpp | 15 +++++++-------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index f636c32abd..c4e318d512 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -164,16 +164,17 @@ void loop() { if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) { #if defined(NRF52_PLATFORM) #ifdef HAS_EXTERNAL_WATCHDOG - uint32_t sleep_interval = external_watchdog.getIntervalMs()/1000; - board.sleep((sleep_interval > 1800) ? 1800 : sleep_interval); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet + external_watchdog.feed(); + uint32_t sleep_interval = external_watchdog.getIntervalMs() / 1000; + board.sleep((sleep_interval > 1800) ? 1800 : sleep_interval); // nrf ignores seconds param, sleeps whenever possible #else - board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet -#endif board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible +#endif #else if (the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep #ifdef HAS_EXTERNAL_WATCHDOG - uint32_t sleep_interval = external_watchdog.getIntervalMs()/1000; + external_watchdog.feed(); + uint32_t sleep_interval = external_watchdog.getIntervalMs() / 1000; board.sleep((sleep_interval > 1800) ? 1800 : sleep_interval); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet #else board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet diff --git a/src/helpers/ExternalWatchdogManager.h b/src/helpers/ExternalWatchdogManager.h index 9ef8abaa61..cb4f492360 100644 --- a/src/helpers/ExternalWatchdogManager.h +++ b/src/helpers/ExternalWatchdogManager.h @@ -2,9 +2,9 @@ class ExternalWatchdogManager { protected: - unsigned long next_feed_watchdog; + unsigned long last_feed_watchdog; public: - ExternalWatchdogManager() { next_feed_watchdog = 0; } + ExternalWatchdogManager() { last_feed_watchdog = 0; } virtual bool begin() { return false; } virtual void loop() { } virtual unsigned long getIntervalMs() const { return 0; } diff --git a/variants/heltec_mesh_solar/platformio.ini b/variants/heltec_mesh_solar/platformio.ini index 1bc7e7fa7a..38594ecc2c 100644 --- a/variants/heltec_mesh_solar/platformio.ini +++ b/variants/heltec_mesh_solar/platformio.ini @@ -17,7 +17,7 @@ build_flags = ${nrf52_base.build_flags} -D HAS_EXTERNAL_WATCHDOG -D EXTERNAL_WATCHDOG_DONE_PIN=9 -D EXTERNAL_WATCHDOG_WAKE_PIN=10 - -D EXTERNAL_WATCHDOG_TIMEOUT_MS=480000 ;(6*60*1000) ; 6 minute watchdog + -D EXTERNAL_WATCHDOG_FEED_INTERVAL_MS=480000 ; 8 minute feed interval, safely inside the hardware watchdog timeout build_src_filter = ${nrf52_base.build_src_filter} + @@ -97,4 +97,4 @@ build_src_filter = ${Heltec_mesh_solar.build_src_filter} +<../examples/companion_radio/*.cpp> lib_deps = ${Heltec_mesh_solar.lib_deps} - densaugeo/base64 @ ~1.4.0 \ No newline at end of file + densaugeo/base64 @ ~1.4.0 diff --git a/variants/heltec_mesh_solar/target.cpp b/variants/heltec_mesh_solar/target.cpp index a40b8ce999..96411c55f3 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -124,7 +124,7 @@ bool SolarSensorManager::setSettingValue(const char* name, const char* value) { } bool SolarExternalWatchdog::begin() { - next_feed_watchdog = 0; + last_feed_watchdog = 0; pinMode(EXTERNAL_WATCHDOG_WAKE_PIN, INPUT); pinMode(EXTERNAL_WATCHDOG_DONE_PIN, OUTPUT); delay(1); @@ -134,23 +134,22 @@ bool SolarExternalWatchdog::begin() { return true; } void SolarExternalWatchdog::loop() { - if (millis() > next_feed_watchdog) { + if (millis() - last_feed_watchdog >= EXTERNAL_WATCHDOG_FEED_INTERVAL_MS) { feed(); - next_feed_watchdog = millis() + EXTERNAL_WATCHDOG_TIMEOUT_MS; } } unsigned long SolarExternalWatchdog::getIntervalMs() const { - unsigned long interval_ms = 0; - interval_ms = next_feed_watchdog - millis(); - if(interval_ms > EXTERNAL_WATCHDOG_TIMEOUT_MS) { - interval_ms = EXTERNAL_WATCHDOG_TIMEOUT_MS; + unsigned long elapsed_ms = millis() - last_feed_watchdog; + if (elapsed_ms >= EXTERNAL_WATCHDOG_FEED_INTERVAL_MS) { + return 0; } - return interval_ms; + return EXTERNAL_WATCHDOG_FEED_INTERVAL_MS - elapsed_ms; } void SolarExternalWatchdog::feed() { digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, HIGH); delay(1); digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, LOW); + last_feed_watchdog = millis(); }