From bd477f0fb2c34c27fc162a25025a9efd6ea00b91 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 28 Jun 2020 11:12:12 -0700 Subject: [PATCH] turn on thread watchdog --- docs/software/TODO.md | 1 - src/WorkerThread.cpp | 9 +++++++++ src/WorkerThread.h | 20 +++++++++++++++++++- src/esp32/main-esp32.cpp | 19 ++++++++++++++++--- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 60d0e5b0..b9ad6eae 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -48,7 +48,6 @@ Items after the first final candidate release. - split out the software update utility so other projects can use it. Have the appload specify the URL for downloads. - read the PMU battery fault indicators and blink/led/warn user on screen - discard very old nodedb records (> 1wk) -- add a watchdog timer - handle millis() rollover in GPS.getTime - otherwise we will break after 50 days - report esp32 device code bugs back to the mothership via android - change BLE bonding to something more secure. see comment by pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND) diff --git a/src/WorkerThread.cpp b/src/WorkerThread.cpp index 3c7ea4c9..8831fab5 100644 --- a/src/WorkerThread.cpp +++ b/src/WorkerThread.cpp @@ -17,8 +17,15 @@ void Thread::callRun(void *_this) void WorkerThread::doRun() { + startWatchdog(); + while (!wantExit) { + stopWatchdog(); block(); + startWatchdog(); + + // no need - startWatchdog is guaranteed to give us one full watchdog interval + // serviceWatchdog(); // Let our loop worker have one full watchdog interval (at least) to run #ifdef DEBUG_STACK static uint32_t lastPrint = 0; @@ -30,6 +37,8 @@ void WorkerThread::doRun() loop(); } + + stopWatchdog(); } /** diff --git a/src/WorkerThread.h b/src/WorkerThread.h index ab186486..3a743220 100644 --- a/src/WorkerThread.h +++ b/src/WorkerThread.h @@ -1,5 +1,6 @@ -#include +#include "esp_task_wdt.h" #include "freertosinc.h" +#include #ifdef HAS_FREE_RTOS @@ -26,6 +27,23 @@ class Thread */ virtual void doRun() = 0; + /** + * All thread run methods must periodically call serviceWatchdog, or the system will declare them hung and panic. + * + * this only applies after startWatchdog() has been called. If you need to sleep for a long time call stopWatchdog() + */ + void serviceWatchdog() { esp_task_wdt_reset(); } + void startWatchdog() + { + auto r = esp_task_wdt_add(taskHandle); + assert(r == ESP_OK); + } + void stopWatchdog() + { + auto r = esp_task_wdt_delete(taskHandle); + assert(r == ESP_OK); + } + private: static void callRun(void *_this); }; diff --git a/src/esp32/main-esp32.cpp b/src/esp32/main-esp32.cpp index e0d53eab..b7bd2d7c 100644 --- a/src/esp32/main-esp32.cpp +++ b/src/esp32/main-esp32.cpp @@ -2,11 +2,12 @@ #include "MeshBluetoothService.h" #include "PowerFSM.h" #include "configuration.h" +#include "esp_task_wdt.h" #include "main.h" #include "power.h" #include "sleep.h" -#include "utils.h" #include "target_specific.h" +#include "utils.h" bool bluetoothOn; @@ -82,7 +83,9 @@ void readPowerStatus() } else { // If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error // In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in power.h - powerStatus.batteryChargePercent = clamp((int)(((powerStatus.batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)), 0, 100); + powerStatus.batteryChargePercent = clamp((int)(((powerStatus.batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / + (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)), + 0, 100); } DEBUG_MSG("Battery %dmV %d%%\n", powerStatus.batteryVoltageMv, powerStatus.batteryChargePercent); } @@ -193,6 +196,16 @@ void esp32Setup() #ifdef AXP192_SLAVE_ADDRESS axp192Init(); #endif + +// Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any +// false positives. The wait-to-sleep timeout for shutting down radios is 30 secs, so pick 45 for now. +#define APP_WATCHDOG_SECS 45 + + auto res = esp_task_wdt_init(APP_WATCHDOG_SECS, true); + assert(res == ESP_OK); + + res = esp_task_wdt_add(NULL); + assert(res == ESP_OK); } #if 0 @@ -215,10 +228,10 @@ uint32_t axpDebugRead() Periodic axpDebugOutput(axpDebugRead); #endif - /// loop code specific to ESP32 targets void esp32Loop() { + esp_task_wdt_reset(); // service our app level watchdog loopBLE(); // for debug printing