another refactor to better handle variants without dynamic light sleep

This commit is contained in:
m1nl 2025-06-24 20:40:13 +02:00
parent fda2b899ff
commit 91d25d2b45
5 changed files with 89 additions and 65 deletions

View File

@ -29,17 +29,13 @@
#include "mesh/wifi/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#endif #endif
#ifndef SLEEP_TIME
#define SLEEP_TIME 30
#endif
#if MESHTASTIC_EXCLUDE_POWER_FSM #if MESHTASTIC_EXCLUDE_POWER_FSM
FakeFsm powerFSM; FakeFsm powerFSM;
void PowerFSM_setup(){}; void PowerFSM_setup(){};
#else #else
static uint32_t sleepStart; static uint32_t sleepStart;
static uint32_t sleepTime; static uint32_t sleepTime;
static uint32_t sleepLeft;
/// Should we behave as if we have AC power now? /// Should we behave as if we have AC power now?
static bool isPowered() static bool isPowered()
@ -89,13 +85,24 @@ static void lsEnter()
sleepStart = -1; sleepStart = -1;
sleepTime = 0; 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); powerMon->setState(meshtastic_PowerMon_State_CPU_LightSleep);
} }
static void lsIdle() static void lsIdle()
{ {
if (!doPreflightSleep()) { if (!doPreflightSleep()) {
#ifdef HAS_DYNAMIC_LIGHT_SLEEP #ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP
powerFSM.trigger(EVENT_WAKE_TIMER); powerFSM.trigger(EVENT_WAKE_TIMER);
#endif #endif
return; return;
@ -106,16 +113,15 @@ static void lsIdle()
} }
sleepTime = millis() - sleepStart; sleepTime = millis() - sleepStart;
#ifdef ARCH_ESP32
uint32_t sleepLeft;
sleepLeft = config.power.ls_secs * 1000LL - sleepTime; sleepLeft = config.power.ls_secs * 1000LL - sleepTime;
if (sleepLeft > SLEEP_TIME * 1000LL) { if (sleepLeft > SLEEP_TIME_QUANTUM_S * 1000LL) {
sleepLeft = SLEEP_TIME * 1000LL; sleepLeft = SLEEP_TIME_QUANTUM_S * 1000LL;
} }
#ifdef ARCH_ESP32
#ifndef HAS_ESP32_DYNAMIC_LIGHT_SLEEP
doLightSleep(sleepLeft); doLightSleep(sleepLeft);
#endif
esp_sleep_source_t cause = esp_sleep_get_wakeup_cause(); esp_sleep_source_t cause = esp_sleep_get_wakeup_cause();
@ -125,6 +131,11 @@ static void lsIdle()
powerFSM.trigger(EVENT_INPUT); powerFSM.trigger(EVENT_INPUT);
return; 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: case ESP_SLEEP_WAKEUP_EXT1:
LOG_DEBUG("Wake cause ESP_SLEEP_WAKEUP_EXT1"); LOG_DEBUG("Wake cause ESP_SLEEP_WAKEUP_EXT1");
powerFSM.trigger(EVENT_PRESS); powerFSM.trigger(EVENT_PRESS);
@ -132,7 +143,7 @@ static void lsIdle()
case ESP_SLEEP_WAKEUP_GPIO: case ESP_SLEEP_WAKEUP_GPIO:
LOG_DEBUG("Wake cause 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; return;
default: default:
@ -147,7 +158,7 @@ static void lsIdle()
static void lsExit() static void lsExit()
{ {
#ifdef ARCH_ESP32 #ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP
doLightSleep(LIGHT_SLEEP_ABORT); doLightSleep(LIGHT_SLEEP_ABORT);
#endif #endif
@ -321,7 +332,7 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WEB_REQUEST, NULL, "Web request"); powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WEB_REQUEST, NULL, "Web request");
powerFSM.add_transition(&stateDARK, &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 // 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(&stateLS, &stateDARK, EVENT_RADIO_INTERRUPT, NULL, "Radio interrupt");
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_RADIO_INTERRUPT, NULL, "Radio interrupt"); powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_RADIO_INTERRUPT, NULL, "Radio interrupt");

View File

@ -24,12 +24,16 @@
#define EVENT_RADIO_INTERRUPT 18 #define EVENT_RADIO_INTERRUPT 18
#define EVENT_WEB_REQUEST 19 #define EVENT_WEB_REQUEST 19
#ifdef HAS_DYNAMIC_LIGHT_SLEEP #ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP
#define WAKE_TIME_MS 500 #define WAKE_TIME_MS 500
#else #else
#define WAKE_TIME_MS (Default::getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs)) #define WAKE_TIME_MS (Default::getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs))
#endif #endif
#ifndef SLEEP_TIME_QUANTUM_S
#define SLEEP_TIME_QUANTUM_S 5
#endif
#if MESHTASTIC_EXCLUDE_POWER_FSM #if MESHTASTIC_EXCLUDE_POWER_FSM
class FakeFsm class FakeFsm
{ {
@ -49,11 +53,10 @@ class FakeFsm
}; };
extern FakeFsm powerFSM; extern FakeFsm powerFSM;
void PowerFSM_setup(); void PowerFSM_setup();
#else #else
#include <Fsm.h> #include <Fsm.h>
extern Fsm powerFSM; extern Fsm powerFSM;
extern State stateON, statePOWER, stateSERIAL, stateDARK, stateNB, stateLS; extern State stateON, statePOWER, stateSERIAL, stateDARK, stateNB, stateLS;
void PowerFSM_setup(); void PowerFSM_setup();
#endif #endif

View File

@ -219,5 +219,5 @@
// Setup flag, which indicates if our device supports dynamic light sleep // Setup flag, which indicates if our device supports dynamic light sleep
#if defined(HAS_ESP32_PM_SUPPORT) && defined(CONFIG_FREERTOS_USE_TICKLESS_IDLE) #if defined(HAS_ESP32_PM_SUPPORT) && defined(CONFIG_FREERTOS_USE_TICKLESS_IDLE)
#define HAS_DYNAMIC_LIGHT_SLEEP #define HAS_ESP32_DYNAMIC_LIGHT_SLEEP
#endif #endif

View File

@ -45,7 +45,7 @@ Observable<void *> notifyDeepSleep;
Observable<void *> notifyReboot; Observable<void *> notifyReboot;
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
// Wake cause when returning from a deep sleep // Wake cause when returning from sleep
esp_sleep_source_t wakeCause; esp_sleep_source_t wakeCause;
/// Called to tell observers that light sleep is about to begin /// Called to tell observers that light sleep is about to begin
@ -55,7 +55,7 @@ Observable<void *> notifyLightSleep;
Observable<esp_sleep_wakeup_cause_t> notifyLightSleepEnd; Observable<esp_sleep_wakeup_cause_t> notifyLightSleepEnd;
#ifdef HAS_ESP32_PM_SUPPORT #ifdef HAS_ESP32_PM_SUPPORT
esp_pm_lock_handle_t pmHandle; esp_pm_lock_handle_t pmLightSleepLock;
#endif #endif
// restores GPIO function after sleep // restores GPIO function after sleep
@ -323,8 +323,10 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false, bool skipSaveN
} }
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
static bool pmLockAcquired; #ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP
static concurrency::Lock *pmLightSleepLock; static bool pmLightSleepLockAcquired;
#endif
static concurrency::Lock *lightSleepConcurrencyLock;
/** /**
* enter light sleep (preserves ram but stops everything about CPU). * enter light sleep (preserves ram but stops everything about CPU).
@ -335,48 +337,45 @@ void doLightSleep(uint32_t sleepMsec)
{ {
esp_err_t res; esp_err_t res;
assert(pmLightSleepLock); assert(lightSleepConcurrencyLock);
pmLightSleepLock->lock(); lightSleepConcurrencyLock->lock();
if (sleepMsec == LIGHT_SLEEP_ABORT) { #ifndef HAS_ESP32_DYNAMIC_LIGHT_SLEEP
if (pmLockAcquired) { assert(sleepMsec != LIGHT_SLEEP_ABORT);
pmLightSleepLock->unlock(); assert(sleepMsec != LIGHT_SLEEP_DYNAMIC);
return; // nothing to do #else
if (!pmLightSleepLockAcquired) {
if (sleepMsec == LIGHT_SLEEP_DYNAMIC) {
lightSleepConcurrencyLock->unlock();
return;
} }
#ifdef HAS_ESP32_PM_SUPPORT res = esp_pm_lock_acquire(pmLightSleepLock);
res = esp_pm_lock_acquire(pmHandle);
assert(res == ESP_OK); assert(res == ESP_OK);
#endif
pmLockAcquired = true; wakeCause = esp_sleep_get_wakeup_cause();
pmLightSleepLockAcquired = true;
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
gpioReset(); gpioReset();
notifyLightSleepEnd.notifyObservers(esp_sleep_get_wakeup_cause()); notifyLightSleepEnd.notifyObservers(wakeCause);
pmLightSleepLock->unlock();
return;
} }
if (!pmLockAcquired) { if (sleepMsec == LIGHT_SLEEP_ABORT) {
console->flush(); lightSleepConcurrencyLock->unlock();
return;
#ifndef HAS_DYNAMIC_LIGHT_SLEEP }
esp_light_sleep_start();
#endif #endif
pmLightSleepLock->unlock();
return;
}
enableLoraInterrupt(); enableLoraInterrupt();
enableButtonInterrupt(); enableButtonInterrupt();
#ifndef HAS_DYNAMIC_LIGHT_SLEEP if (sleepMsec != LIGHT_SLEEP_DYNAMIC) {
res = esp_sleep_enable_timer_wakeup(sleepMsec * 1000LL); res = esp_sleep_enable_timer_wakeup(sleepMsec * 1000LL);
assert(res == ESP_OK); assert(res == ESP_OK);
#endif }
res = uart_set_wakeup_threshold(UART_NUM_0, 3); res = uart_set_wakeup_threshold(UART_NUM_0, 3);
assert(res == ESP_OK); assert(res == ESP_OK);
@ -387,7 +386,6 @@ void doLightSleep(uint32_t sleepMsec)
#if defined(VEXT_ENABLE) #if defined(VEXT_ENABLE)
gpio_hold_en((gpio_num_t)VEXT_ENABLE); gpio_hold_en((gpio_num_t)VEXT_ENABLE);
#endif #endif
#if defined(RESET_OLED) #if defined(RESET_OLED)
gpio_hold_en((gpio_num_t)RESET_OLED); gpio_hold_en((gpio_num_t)RESET_OLED);
#endif #endif
@ -415,17 +413,25 @@ void doLightSleep(uint32_t sleepMsec)
console->flush(); console->flush();
#ifdef HAS_ESP32_PM_SUPPORT if (sleepMsec != LIGHT_SLEEP_DYNAMIC) {
res = esp_pm_lock_release(pmHandle); esp_light_sleep_start();
assert(res == ESP_OK);
#endif
pmLockAcquired = false;
#ifndef HAS_DYNAMIC_LIGHT_SLEEP wakeCause = esp_sleep_get_wakeup_cause();
esp_light_sleep_start();
#endif
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 // Initialize power management settings to allow light sleep
@ -434,16 +440,16 @@ void initLightSleep()
esp_err_t res; esp_err_t res;
#ifdef HAS_ESP32_PM_SUPPORT #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); assert(res == ESP_OK);
res = esp_pm_lock_acquire(pmHandle); res = esp_pm_lock_acquire(pmLightSleepLock);
assert(res == ESP_OK); assert(res == ESP_OK);
esp_pm_config_esp32_t pm_config; esp_pm_config_esp32_t pm_config;
pm_config.max_freq_mhz = 80; pm_config.max_freq_mhz = 80;
pm_config.min_freq_mhz = 20; pm_config.min_freq_mhz = 20;
#ifdef HAS_DYNAMIC_LIGHT_SLEEP #ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP
pm_config.light_sleep_enable = true; pm_config.light_sleep_enable = true;
#else #else
pm_config.light_sleep_enable = false; pm_config.light_sleep_enable = false;
@ -456,8 +462,11 @@ void initLightSleep()
pm_config.max_freq_mhz, pm_config.light_sleep_enable); pm_config.max_freq_mhz, pm_config.light_sleep_enable);
#endif #endif
pmLightSleepLock = new concurrency::Lock(); lightSleepConcurrencyLock = new concurrency::Lock();
pmLockAcquired = true;
#ifdef HAS_ESP32_DYNAMIC_LIGHT_SLEEP
pmLightSleepLockAcquired = true;
#endif
} }
void gpioReset() void gpioReset()

View File

@ -13,6 +13,7 @@ extern XPowersLibInterface *PMU;
#include "esp_sleep.h" #include "esp_sleep.h"
#define LIGHT_SLEEP_ABORT 0 #define LIGHT_SLEEP_ABORT 0
#define LIGHT_SLEEP_DYNAMIC UINT32_MAX
void initLightSleep(); void initLightSleep();
void doLightSleep(uint32_t msecToWake); void doLightSleep(uint32_t msecToWake);