From fda2b899ffa2aff4bd58d84bab6f600f262a5ec2 Mon Sep 17 00:00:00 2001 From: m1nl Date: Tue, 24 Jun 2025 11:20:13 +0200 Subject: [PATCH] make some variables static, refactor GPIO reset logic --- src/PowerFSM.cpp | 22 ++----- src/sleep.cpp | 165 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 137 insertions(+), 50 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index df2e088cd..77ebee1dc 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -16,6 +16,7 @@ #include "configuration.h" #include "graphics/Screen.h" #include "main.h" +#include "power.h" #include "sleep.h" #include "target_specific.h" @@ -36,6 +37,10 @@ FakeFsm powerFSM; void PowerFSM_setup(){}; #else + +static uint32_t sleepStart; +static uint32_t sleepTime; + /// Should we behave as if we have AC power now? static bool isPowered() { @@ -61,19 +66,12 @@ static bool isPowered() return !isPowerSavingMode && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB()); } -static void sdsEnter() -{ - LOG_DEBUG("State: SDS"); - // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw - doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, false); -} - static void lowBattSDSEnter() { LOG_DEBUG("State: Lower batt SDS"); + // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, true); } -extern Power *power; static void shutdownEnter() { @@ -81,11 +79,6 @@ static void shutdownEnter() power->shutdown(); } -#include "error.h" - -uint32_t sleepStart; -uint32_t sleepTime; - static void lsEnter() { LOG_DEBUG("State: LS"); @@ -234,7 +227,6 @@ static void bootEnter() } State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN"); -State stateSDS(sdsEnter, NULL, NULL, "SDS"); State stateLowBattSDS(lowBattSDSEnter, NULL, NULL, "SDS"); State stateLS(lsEnter, lsIdle, lsExit, "LS"); State stateDARK(darkEnter, NULL, NULL, "DARK"); @@ -249,7 +241,7 @@ void PowerFSM_setup() bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0); bool hasPower = isPowered(); - LOG_INFO("PowerFSM init, USB power=%d, is_power_saving=%d, wake_time_ms=%d", hasPower ? 1 : 0, + LOG_INFO("PowerFSM init, has_power=%d, is_power_saving=%d, wake_time_ms=%d", hasPower ? 1 : 0, config.power.is_power_saving ? 1 : 0, WAKE_TIME_MS); powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout"); diff --git a/src/sleep.cpp b/src/sleep.cpp index ace271f46..683fb2bb2 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -58,11 +58,13 @@ Observable notifyLightSleepEnd; esp_pm_lock_handle_t pmHandle; #endif -// internal helper functions -void gpioResetHold(void); +// restores GPIO function after sleep +void gpioReset(void); +// enables button wake-up interrupt void enableButtonInterrupt(void); - +// enables LoRa wake-up-interrupt void enableLoraInterrupt(void); + bool shouldLoraWake(uint32_t msecToWake); #endif @@ -154,7 +156,7 @@ void initDeepSleep() #ifdef ARCH_ESP32 if (wakeCause != ESP_SLEEP_WAKEUP_UNDEFINED) { - gpioResetHold(); + gpioReset(); } #endif #endif @@ -321,8 +323,8 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false, bool skipSaveN } #ifdef ARCH_ESP32 -bool pmLockAcquired; -concurrency::Lock *pmLightSleepLock; +static bool pmLockAcquired; +static concurrency::Lock *pmLightSleepLock; /** * enter light sleep (preserves ram but stops everything about CPU). @@ -349,7 +351,7 @@ void doLightSleep(uint32_t sleepMsec) pmLockAcquired = true; esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); - gpioResetHold(); + gpioReset(); notifyLightSleepEnd.notifyObservers(esp_sleep_get_wakeup_cause()); @@ -382,14 +384,6 @@ void doLightSleep(uint32_t sleepMsec) res = esp_sleep_enable_uart_wakeup(UART_NUM_0); assert(res == ESP_OK); -#ifdef PMU_IRQ - // wake due to PMU can happen repeatedly if there is no battery installed or the battery fills - if (pmu_found) { - res = gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_LOW_LEVEL); // pmu irq - assert(res == ESP_OK); - } -#endif - #if defined(VEXT_ENABLE) gpio_hold_en((gpio_num_t)VEXT_ENABLE); #endif @@ -402,10 +396,17 @@ void doLightSleep(uint32_t sleepMsec) res = gpio_wakeup_enable((gpio_num_t)INPUTDRIVER_ENCODER_BTN, GPIO_INTR_LOW_LEVEL); assert(res == ESP_OK); #endif -#if defined(T_WATCH_S3) || defined(ELECROW) +#ifdef WAKE_ON_TOUCH res = gpio_wakeup_enable((gpio_num_t)SCREEN_TOUCH_INT, GPIO_INTR_LOW_LEVEL); assert(res == ESP_OK); #endif +#ifdef PMU_IRQ + // wake due to PMU can happen repeatedly if there is no battery installed or the battery fills + if (pmu_found) { + res = gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_LOW_LEVEL); // pmu irq + assert(res == ESP_OK); + } +#endif res = esp_sleep_enable_gpio_wakeup(); assert(res == ESP_OK); @@ -459,15 +460,79 @@ void initLightSleep() pmLockAcquired = true; } -void gpioResetHold() +void gpioReset() { + esp_err_t res; + + // deinitialize RTC GPIOs and holds for (uint8_t i = 0; i <= GPIO_NUM_MAX; i++) { if (rtc_gpio_is_valid_gpio((gpio_num_t)i)) { rtc_gpio_hold_dis((gpio_num_t)i); rtc_gpio_deinit((gpio_num_t)i); - } else if (GPIO_IS_VALID_OUTPUT_GPIO((gpio_num_t)i)) + } else if (GPIO_IS_VALID_OUTPUT_GPIO((gpio_num_t)i)) { gpio_hold_dis((gpio_num_t)i); + } + } + + // restore negative-edge interrupt triggers for input pins +#ifdef INPUTDRIVER_ENCODER_BTN + res = gpio_set_intr_type((gpio_num_t)INPUTDRIVER_ENCODER_BTN, GPIO_INTR_NEGEDGE); + assert(res == ESP_OK); +#endif +#ifdef WAKE_ON_TOUCH + res = gpio_set_intr_type((gpio_num_t)SCREEN_TOUCH_INT, GPIO_INTR_NEGEDGE); + assert(res == ESP_OK); +#endif +#ifdef PMU_IRQ + if (pmu_found) { + res = gpio_set_intr_type((gpio_num_t)PMU_IRQ, GPIO_INTR_NEGEDGE); + assert(res == ESP_OK); + } +#endif + + gpio_num_t pin = GPIO_NUM_NC; + +#if defined(LORA_DIO1) && (LORA_DIO1 != GPIO_NUM_NC) + pin = (gpio_num_t)LORA_DIO1; +#elif defined(RF95_IRQ) && (RF95_IRQ != GPIO_NUM_NC) + pin = (gpio_num_t)RF95_IRQ; +#endif + + // need to restore original GPIO interrupt trigger when it's not RTC GPIO or we don't support EXT wakeup + if (pin != GPIO_NUM_NC) { +#ifdef SOC_PM_SUPPORT_EXT_WAKEUP + if (!rtc_gpio_is_valid_gpio(pin)) { +#endif + res = gpio_set_intr_type(pin, GPIO_INTR_POSEDGE); + assert(res == ESP_OK); +#ifdef SOC_PM_SUPPORT_EXT_WAKEUP + } +#endif + } + + pin = GPIO_NUM_NC; + + if (config.device.button_gpio) { + pin = (gpio_num_t)config.device.button_gpio; + } + +#ifdef BUTTON_PIN + if (pin == GPIO_NUM_NC) { + pin = (gpio_num_t)BUTTON_PIN; + } +#endif + + // need to restore original GPIO interrupt trigger when it's not RTC GPIO or we don't support EXT wakeup + if (pin != GPIO_NUM_NC) { +#ifdef SOC_PM_SUPPORT_EXT_WAKEUP + if (!rtc_gpio_is_valid_gpio(pin)) { +#endif + res = gpio_set_intr_type(pin, GPIO_INTR_ANYEDGE); + assert(res == ESP_OK); +#ifdef SOC_PM_SUPPORT_EXT_WAKEUP + } +#endif } } @@ -476,8 +541,22 @@ void enableButtonInterrupt() esp_err_t res; gpio_num_t pin; + pin = GPIO_NUM_NC; + + if (config.device.button_gpio) { + pin = (gpio_num_t)config.device.button_gpio; + } + #ifdef BUTTON_PIN - pin = (gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN); + if (pin == GPIO_NUM_NC) { + pin = (gpio_num_t)BUTTON_PIN; + } +#endif + + if (pin == GPIO_NUM_NC) { + return; + } + #ifdef SOC_PM_SUPPORT_EXT_WAKEUP if (rtc_gpio_is_valid_gpio(pin)) { LOG_DEBUG("Setup button pin (GPIO%02d) with wakeup by ext1 source", pin); @@ -487,29 +566,38 @@ void enableButtonInterrupt() #endif res = rtc_gpio_hold_en((gpio_num_t)pin); assert(res == ESP_OK); +#ifdef CONFIG_IDF_TARGET_ESP32 + res = esp_sleep_enable_ext1_wakeup(1ULL << pin, ESP_EXT1_WAKEUP_ALL_LOW); +#else res = esp_sleep_enable_ext1_wakeup(1ULL << pin, ESP_EXT1_WAKEUP_ANY_LOW); +#endif + assert(res == ESP_OK); } else { LOG_DEBUG("Setup button pin (GPIO%02d) with wakeup by GPIO interrupt", pin); #ifdef BUTTON_NEED_PULLUP - gpio_pullup_en(pin); + res = gpio_pullup_en(pin); assert(res == ESP_OK); #endif - res = gpio_hold_en((gpio_num_t)pin); - assert(res == ESP_OK); res = gpio_wakeup_enable(pin, GPIO_INTR_LOW_LEVEL); + assert(res == ESP_OK); + if (GPIO_IS_VALID_OUTPUT_GPIO(pin)) { + res = gpio_hold_en((gpio_num_t)pin); + assert(res == ESP_OK); + } } #else #ifdef BUTTON_NEED_PULLUP - gpio_pullup_en(pin); + res = gpio_pullup_en(pin); assert(res == ESP_OK); #endif - res = gpio_hold_en((gpio_num_t)pin); - assert(res == ESP_OK); res = gpio_wakeup_enable(pin, GPIO_INTR_LOW_LEVEL); - LOG_DEBUG("Setup button pin (GPIO%02d) with wakeup by GPIO interrupt", pin); -#endif assert(res == ESP_OK); + LOG_DEBUG("Setup button pin (GPIO%02d) with wakeup by GPIO interrupt", pin); + if (GPIO_IS_VALID_OUTPUT_GPIO(pin)) { + res = gpio_hold_en((gpio_num_t)pin); + assert(res == ESP_OK); + } #endif } @@ -526,9 +614,11 @@ void enableLoraInterrupt() pin = (gpio_num_t)RF95_IRQ; #endif - assert(pin != GPIO_NUM_NC); + if (pin == GPIO_NUM_NC) { + return; + } -#if defined(LORA_RESET) && (LORA_RESET != RADIOLIB_NC) +#if defined(LORA_RESET) && (LORA_RESET != GPIO_NUM_NC) gpio_hold_en((gpio_num_t)LORA_RESET); #endif @@ -540,24 +630,29 @@ void enableLoraInterrupt() res = rtc_gpio_hold_en((gpio_num_t)pin); assert(res == ESP_OK); res = esp_sleep_enable_ext0_wakeup(pin, HIGH); - + assert(res == ESP_OK); } else { LOG_DEBUG("Setup radio interrupt (GPIO%02d) with wakeup by GPIO interrupt", pin); res = gpio_pulldown_en((gpio_num_t)pin); assert(res == ESP_OK); - res = gpio_hold_en((gpio_num_t)pin); - assert(res == ESP_OK); res = gpio_wakeup_enable(pin, GPIO_INTR_HIGH_LEVEL); + assert(res == ESP_OK); + if (GPIO_IS_VALID_OUTPUT_GPIO(pin)) { + res = gpio_hold_en((gpio_num_t)pin); + assert(res == ESP_OK); + } } #else LOG_DEBUG("Setup radio interrupt (GPIO%02d) with wakeup by GPIO interrupt", pin); res = gpio_pulldown_en((gpio_num_t)pin); assert(res == ESP_OK); - res = gpio_hold_en((gpio_num_t)pin); - assert(res == ESP_OK); res = gpio_wakeup_enable(pin, GPIO_INTR_HIGH_LEVEL); -#endif assert(res == ESP_OK); + if (GPIO_IS_VALID_OUTPUT_GPIO(pin)) { + res = gpio_hold_en((gpio_num_t)pin); + assert(res == ESP_OK); + } +#endif } bool shouldLoraWake(uint32_t msecToWake)