diff --git a/lib/hal/HalGPIO.cpp b/lib/hal/HalGPIO.cpp index 89ce13ba..64a251de 100644 --- a/lib/hal/HalGPIO.cpp +++ b/lib/hal/HalGPIO.cpp @@ -1,11 +1,9 @@ #include #include -#include void HalGPIO::begin() { inputMgr.begin(); SPI.begin(EPD_SCLK, SPI_MISO, EPD_MOSI, EPD_CS); - pinMode(BAT_GPIO0, INPUT); pinMode(UART0_RXD, INPUT); } @@ -23,23 +21,6 @@ bool HalGPIO::wasAnyReleased() const { return inputMgr.wasAnyReleased(); } unsigned long HalGPIO::getHeldTime() const { return inputMgr.getHeldTime(); } -void HalGPIO::startDeepSleep() { - // Ensure that the power button has been released to avoid immediately turning back on if you're holding it - while (inputMgr.isPressed(BTN_POWER)) { - delay(50); - inputMgr.update(); - } - // Arm the wakeup trigger *after* the button is released - esp_deep_sleep_enable_gpio_wakeup(1ULL << InputManager::POWER_BUTTON_PIN, ESP_GPIO_WAKEUP_GPIO_LOW); - // Enter Deep Sleep - esp_deep_sleep_start(); -} - -int HalGPIO::getBatteryPercentage() const { - static const BatteryMonitor battery = BatteryMonitor(BAT_GPIO0); - return battery.readPercentage(); -} - bool HalGPIO::isUsbConnected() const { // U0RXD/GPIO20 reads HIGH when USB is connected return digitalRead(UART0_RXD) == HIGH; diff --git a/lib/hal/HalGPIO.h b/lib/hal/HalGPIO.h index 615a8d63..45ca50a5 100644 --- a/lib/hal/HalGPIO.h +++ b/lib/hal/HalGPIO.h @@ -38,12 +38,6 @@ class HalGPIO { bool wasAnyReleased() const; unsigned long getHeldTime() const; - // Setup wake up GPIO and enter deep sleep - void startDeepSleep(); - - // Get battery percentage (range 0-100) - int getBatteryPercentage() const; - // Check if USB is connected bool isUsbConnected() const; diff --git a/lib/hal/HalPowerManager.cpp b/lib/hal/HalPowerManager.cpp new file mode 100644 index 00000000..745579a3 --- /dev/null +++ b/lib/hal/HalPowerManager.cpp @@ -0,0 +1,48 @@ +#include "HalPowerManager.h" + +#include + +#include "HalGPIO.h" + +void HalPowerManager::begin() { + pinMode(BAT_GPIO0, INPUT); + normalFreq = getCpuFrequencyMhz(); +} + +void HalPowerManager::setPowerSaving(bool enabled) { + if (normalFreq <= 0) { + return; // invalid state + } + if (enabled && !isLowPower) { + Serial.printf("[%lu] [PWR] Going to low-power mode\n", millis()); + if (!setCpuFrequencyMhz(LOW_POWER_FREQ)) { + Serial.printf("[%lu] [PWR] Failed to set low-power CPU frequency\n", millis()); + return; + } + } + if (!enabled && isLowPower) { + Serial.printf("[%lu] [PWR] Restoring normal CPU frequency\n", millis()); + if (!setCpuFrequencyMhz(normalFreq)) { + Serial.printf("[%lu] [PWR] Failed to restore normal CPU frequency\n", millis()); + return; + } + } + isLowPower = enabled; +} + +void HalPowerManager::startDeepSleep(HalGPIO& gpio) const { + // Ensure that the power button has been released to avoid immediately turning back on if you're holding it + while (gpio.isPressed(HalGPIO::BTN_POWER)) { + delay(50); + gpio.update(); + } + // Arm the wakeup trigger *after* the button is released + esp_deep_sleep_enable_gpio_wakeup(1ULL << InputManager::POWER_BUTTON_PIN, ESP_GPIO_WAKEUP_GPIO_LOW); + // Enter Deep Sleep + esp_deep_sleep_start(); +} + +int HalPowerManager::getBatteryPercentage() const { + static const BatteryMonitor battery = BatteryMonitor(BAT_GPIO0); + return battery.readPercentage(); +} diff --git a/lib/hal/HalPowerManager.h b/lib/hal/HalPowerManager.h new file mode 100644 index 00000000..636b2c97 --- /dev/null +++ b/lib/hal/HalPowerManager.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +#include "HalGPIO.h" + +class HalPowerManager { + int normalFreq = 0; // MHz + bool isLowPower = false; + + public: + static constexpr int LOW_POWER_FREQ = 10; // MHz + static constexpr unsigned long IDLE_POWER_SAVING_MS = 3000; // ms + + void begin(); + + // Control CPU frequency for power saving + void setPowerSaving(bool enabled); + + // Setup wake up GPIO and enter deep sleep + void startDeepSleep(HalGPIO& gpio) const; + + // Get battery percentage (range 0-100) + int getBatteryPercentage() const; +}; diff --git a/src/main.cpp b/src/main.cpp index fa782556..d5746acb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ HalDisplay display; HalGPIO gpio; +HalPowerManager powerManager; MappedInputManager mappedInputManager(gpio); GfxRenderer renderer(display); Activity* currentActivity; @@ -181,7 +183,7 @@ void verifyPowerButtonDuration() { if (abort) { // Button released too early. Returning to sleep. // IMPORTANT: Re-arm the wakeup trigger before sleeping again - gpio.startDeepSleep(); + powerManager.startDeepSleep(gpio); } } @@ -204,7 +206,7 @@ void enterDeepSleep() { Serial.printf("[%lu] [ ] Power button press calibration value: %lu ms\n", millis(), t2 - t1); Serial.printf("[%lu] [ ] Entering deep sleep.\n", millis()); - gpio.startDeepSleep(); + powerManager.startDeepSleep(gpio); } void onGoHome(); @@ -281,6 +283,7 @@ void setup() { t1 = millis(); gpio.begin(); + powerManager.begin(); // Only start serial if USB connected if (gpio.isUsbConnected()) { @@ -316,7 +319,7 @@ void setup() { case HalGPIO::WakeupReason::AfterUSBPower: // If USB power caused a cold boot, go back to sleep Serial.printf("[%lu] [ ] Wakeup reason: After USB Power\n", millis()); - gpio.startDeepSleep(); + powerManager.startDeepSleep(gpio); break; case HalGPIO::WakeupReason::AfterFlash: // After flashing, just proceed to boot @@ -372,7 +375,8 @@ void loop() { // Check for any user activity (button press or release) or active background work static unsigned long lastActivityTime = millis(); if (gpio.wasAnyPressed() || gpio.wasAnyReleased() || (currentActivity && currentActivity->preventAutoSleep())) { - lastActivityTime = millis(); // Reset inactivity timer + lastActivityTime = millis(); // Reset inactivity timer + powerManager.setPowerSaving(false); // Restore normal CPU frequency on user activity } const unsigned long sleepTimeoutMs = SETTINGS.getSleepTimeoutMs(); @@ -410,9 +414,9 @@ void loop() { if (currentActivity && currentActivity->skipLoopDelay()) { yield(); // Give FreeRTOS a chance to run tasks, but return immediately } else { - static constexpr unsigned long IDLE_POWER_SAVING_MS = 3000; // 3 seconds - if (millis() - lastActivityTime >= IDLE_POWER_SAVING_MS) { + if (millis() - lastActivityTime >= HalPowerManager::IDLE_POWER_SAVING_MS) { // If we've been inactive for a while, increase the delay to save power + powerManager.setPowerSaving(true); // Lower CPU frequency after extended inactivity delay(50); } else { // Short delay to prevent tight loop while still being responsive