From 91d25d2b4510ffffe5242f4e6cf21e2cffc480aa Mon Sep 17 00:00:00 2001 From: m1nl Date: Tue, 24 Jun 2025 20:40:13 +0200 Subject: [PATCH] another refactor to better handle variants without dynamic light sleep --- src/PowerFSM.cpp | 41 +++++++----- src/PowerFSM.h | 9 ++- src/platform/esp32/architecture.h | 2 +- src/sleep.cpp | 101 ++++++++++++++++-------------- src/sleep.h | 1 + 5 files changed, 89 insertions(+), 65 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 77ebee1dc..5d04b1215 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -29,17 +29,13 @@ #include "mesh/wifi/WiFiAPClient.h" #endif -#ifndef SLEEP_TIME -#define SLEEP_TIME 30 -#endif - #if MESHTASTIC_EXCLUDE_POWER_FSM FakeFsm powerFSM; void PowerFSM_setup(){}; #else - static uint32_t sleepStart; static uint32_t sleepTime; +static uint32_t sleepLeft; /// Should we behave as if we have AC power now? static bool isPowered() @@ -89,13 +85,24 @@ static void lsEnter() sleepStart = -1; sleepTime = 0; +#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP + if (!doPreflightSleep()) { + LOG_DEBUG("Transition to LS state aborted because of tasks pending"); + powerFSM.trigger(EVENT_WAKE_TIMER); + return; + } + + sleepStart = millis(); + doLightSleep(LIGHT_SLEEP_DYNAMIC); +#endif + powerMon->setState(meshtastic_PowerMon_State_CPU_LightSleep); } static void lsIdle() { if (!doPreflightSleep()) { -#ifdef HAS_DYNAMIC_LIGHT_SLEEP +#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP powerFSM.trigger(EVENT_WAKE_TIMER); #endif return; @@ -106,16 +113,15 @@ static void lsIdle() } sleepTime = millis() - sleepStart; - -#ifdef ARCH_ESP32 - uint32_t sleepLeft; - sleepLeft = config.power.ls_secs * 1000LL - sleepTime; - if (sleepLeft > SLEEP_TIME * 1000LL) { - sleepLeft = SLEEP_TIME * 1000LL; + if (sleepLeft > SLEEP_TIME_QUANTUM_S * 1000LL) { + sleepLeft = SLEEP_TIME_QUANTUM_S * 1000LL; } +#ifdef ARCH_ESP32 +#ifndef HAS_ESP32_DYNAMIC_LIGHT_SLEEP doLightSleep(sleepLeft); +#endif esp_sleep_source_t cause = esp_sleep_get_wakeup_cause(); @@ -125,6 +131,11 @@ static void lsIdle() powerFSM.trigger(EVENT_INPUT); return; + case ESP_SLEEP_WAKEUP_EXT0: + LOG_DEBUG("Wake cause ESP_SLEEP_WAKEUP_EXT0"); + powerFSM.trigger(EVENT_RADIO_INTERRUPT); + return; + case ESP_SLEEP_WAKEUP_EXT1: LOG_DEBUG("Wake cause ESP_SLEEP_WAKEUP_EXT1"); powerFSM.trigger(EVENT_PRESS); @@ -132,7 +143,7 @@ static void lsIdle() case ESP_SLEEP_WAKEUP_GPIO: LOG_DEBUG("Wake cause ESP_SLEEP_WAKEUP_GPIO"); - powerFSM.trigger(EVENT_WAKE_TIMER); + // FSM events should be triggered by interrupt handlers return; default: @@ -147,7 +158,7 @@ static void lsIdle() static void lsExit() { -#ifdef ARCH_ESP32 +#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP doLightSleep(LIGHT_SLEEP_ABORT); #endif @@ -321,7 +332,7 @@ void PowerFSM_setup() powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WEB_REQUEST, NULL, "Web request"); powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_WEB_REQUEST, NULL, "Web request"); -#ifdef HAS_DYNAMIC_LIGHT_SLEEP +#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP // it's better to exit dynamic light sleep when packet is received to ensure routing is properly handled powerFSM.add_transition(&stateLS, &stateDARK, EVENT_RADIO_INTERRUPT, NULL, "Radio interrupt"); powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_RADIO_INTERRUPT, NULL, "Radio interrupt"); diff --git a/src/PowerFSM.h b/src/PowerFSM.h index e79bc07ed..eb630e79b 100644 --- a/src/PowerFSM.h +++ b/src/PowerFSM.h @@ -24,12 +24,16 @@ #define EVENT_RADIO_INTERRUPT 18 #define EVENT_WEB_REQUEST 19 -#ifdef HAS_DYNAMIC_LIGHT_SLEEP +#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP #define WAKE_TIME_MS 500 #else #define WAKE_TIME_MS (Default::getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs)) #endif +#ifndef SLEEP_TIME_QUANTUM_S +#define SLEEP_TIME_QUANTUM_S 5 +#endif + #if MESHTASTIC_EXCLUDE_POWER_FSM class FakeFsm { @@ -49,11 +53,10 @@ class FakeFsm }; extern FakeFsm powerFSM; void PowerFSM_setup(); - #else #include extern Fsm powerFSM; extern State stateON, statePOWER, stateSERIAL, stateDARK, stateNB, stateLS; void PowerFSM_setup(); -#endif \ No newline at end of file +#endif diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index caf2585db..048579b9d 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -219,5 +219,5 @@ // Setup flag, which indicates if our device supports dynamic light sleep #if defined(HAS_ESP32_PM_SUPPORT) && defined(CONFIG_FREERTOS_USE_TICKLESS_IDLE) -#define HAS_DYNAMIC_LIGHT_SLEEP +#define HAS_ESP32_DYNAMIC_LIGHT_SLEEP #endif diff --git a/src/sleep.cpp b/src/sleep.cpp index 683fb2bb2..f45417a12 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -45,7 +45,7 @@ Observable notifyDeepSleep; Observable notifyReboot; #ifdef ARCH_ESP32 -// Wake cause when returning from a deep sleep +// Wake cause when returning from sleep esp_sleep_source_t wakeCause; /// Called to tell observers that light sleep is about to begin @@ -55,7 +55,7 @@ Observable notifyLightSleep; Observable notifyLightSleepEnd; #ifdef HAS_ESP32_PM_SUPPORT -esp_pm_lock_handle_t pmHandle; +esp_pm_lock_handle_t pmLightSleepLock; #endif // restores GPIO function after sleep @@ -323,8 +323,10 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false, bool skipSaveN } #ifdef ARCH_ESP32 -static bool pmLockAcquired; -static concurrency::Lock *pmLightSleepLock; +#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP +static bool pmLightSleepLockAcquired; +#endif +static concurrency::Lock *lightSleepConcurrencyLock; /** * enter light sleep (preserves ram but stops everything about CPU). @@ -335,48 +337,45 @@ void doLightSleep(uint32_t sleepMsec) { esp_err_t res; - assert(pmLightSleepLock); - pmLightSleepLock->lock(); + assert(lightSleepConcurrencyLock); + lightSleepConcurrencyLock->lock(); - if (sleepMsec == LIGHT_SLEEP_ABORT) { - if (pmLockAcquired) { - pmLightSleepLock->unlock(); - return; // nothing to do +#ifndef HAS_ESP32_DYNAMIC_LIGHT_SLEEP + assert(sleepMsec != LIGHT_SLEEP_ABORT); + assert(sleepMsec != LIGHT_SLEEP_DYNAMIC); +#else + if (!pmLightSleepLockAcquired) { + if (sleepMsec == LIGHT_SLEEP_DYNAMIC) { + lightSleepConcurrencyLock->unlock(); + return; } -#ifdef HAS_ESP32_PM_SUPPORT - res = esp_pm_lock_acquire(pmHandle); + res = esp_pm_lock_acquire(pmLightSleepLock); assert(res == ESP_OK); -#endif - pmLockAcquired = true; + + wakeCause = esp_sleep_get_wakeup_cause(); + + pmLightSleepLockAcquired = true; esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); gpioReset(); - notifyLightSleepEnd.notifyObservers(esp_sleep_get_wakeup_cause()); - - pmLightSleepLock->unlock(); - return; + notifyLightSleepEnd.notifyObservers(wakeCause); } - if (!pmLockAcquired) { - console->flush(); - -#ifndef HAS_DYNAMIC_LIGHT_SLEEP - esp_light_sleep_start(); + if (sleepMsec == LIGHT_SLEEP_ABORT) { + lightSleepConcurrencyLock->unlock(); + return; + } #endif - pmLightSleepLock->unlock(); - return; - } - enableLoraInterrupt(); enableButtonInterrupt(); -#ifndef HAS_DYNAMIC_LIGHT_SLEEP - res = esp_sleep_enable_timer_wakeup(sleepMsec * 1000LL); - assert(res == ESP_OK); -#endif + if (sleepMsec != LIGHT_SLEEP_DYNAMIC) { + res = esp_sleep_enable_timer_wakeup(sleepMsec * 1000LL); + assert(res == ESP_OK); + } res = uart_set_wakeup_threshold(UART_NUM_0, 3); assert(res == ESP_OK); @@ -387,7 +386,6 @@ void doLightSleep(uint32_t sleepMsec) #if defined(VEXT_ENABLE) gpio_hold_en((gpio_num_t)VEXT_ENABLE); #endif - #if defined(RESET_OLED) gpio_hold_en((gpio_num_t)RESET_OLED); #endif @@ -415,17 +413,25 @@ void doLightSleep(uint32_t sleepMsec) console->flush(); -#ifdef HAS_ESP32_PM_SUPPORT - res = esp_pm_lock_release(pmHandle); - assert(res == ESP_OK); -#endif - pmLockAcquired = false; + if (sleepMsec != LIGHT_SLEEP_DYNAMIC) { + esp_light_sleep_start(); -#ifndef HAS_DYNAMIC_LIGHT_SLEEP - esp_light_sleep_start(); -#endif + wakeCause = esp_sleep_get_wakeup_cause(); - pmLightSleepLock->unlock(); + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); + gpioReset(); + + notifyLightSleepEnd.notifyObservers(wakeCause); + + } else { +#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP + res = esp_pm_lock_release(pmLightSleepLock); + assert(res == ESP_OK); + pmLightSleepLockAcquired = false; +#endif + } + + lightSleepConcurrencyLock->unlock(); } // Initialize power management settings to allow light sleep @@ -434,16 +440,16 @@ void initLightSleep() esp_err_t res; #ifdef HAS_ESP32_PM_SUPPORT - res = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "meshtastic", &pmHandle); + res = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "meshtastic", &pmLightSleepLock); assert(res == ESP_OK); - res = esp_pm_lock_acquire(pmHandle); + res = esp_pm_lock_acquire(pmLightSleepLock); assert(res == ESP_OK); esp_pm_config_esp32_t pm_config; pm_config.max_freq_mhz = 80; pm_config.min_freq_mhz = 20; -#ifdef HAS_DYNAMIC_LIGHT_SLEEP +#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP pm_config.light_sleep_enable = true; #else pm_config.light_sleep_enable = false; @@ -456,8 +462,11 @@ void initLightSleep() pm_config.max_freq_mhz, pm_config.light_sleep_enable); #endif - pmLightSleepLock = new concurrency::Lock(); - pmLockAcquired = true; + lightSleepConcurrencyLock = new concurrency::Lock(); + +#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP + pmLightSleepLockAcquired = true; +#endif } void gpioReset() diff --git a/src/sleep.h b/src/sleep.h index 9ce97258e..14ac890b2 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -13,6 +13,7 @@ extern XPowersLibInterface *PMU; #include "esp_sleep.h" #define LIGHT_SLEEP_ABORT 0 +#define LIGHT_SLEEP_DYNAMIC UINT32_MAX void initLightSleep(); void doLightSleep(uint32_t msecToWake);