Compare commits
4 Commits
530d43997b
...
d02e21a48f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d02e21a48f | ||
|
|
6ec5fc5603 | ||
|
|
9125a7ce68 | ||
|
|
dc6562a51c |
@@ -74,13 +74,14 @@ void GfxRenderer::drawPixel(const int x, const int y, const bool state) const {
|
||||
}
|
||||
|
||||
int GfxRenderer::getTextWidth(const int fontId, const char* text, const EpdFontFamily::Style style) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
const auto fontIt = fontMap.find(fontId);
|
||||
if (fontIt == fontMap.end()) {
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w = 0, h = 0;
|
||||
fontMap.at(fontId).getTextDimensions(text, &w, &h, style);
|
||||
fontIt->second.getTextDimensions(text, &w, &h, style);
|
||||
return w;
|
||||
}
|
||||
|
||||
@@ -100,11 +101,12 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y, const cha
|
||||
return;
|
||||
}
|
||||
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
const auto fontIt = fontMap.find(fontId);
|
||||
if (fontIt == fontMap.end()) {
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return;
|
||||
}
|
||||
const auto font = fontMap.at(fontId);
|
||||
const auto& font = fontIt->second;
|
||||
|
||||
// no printable characters
|
||||
if (!font.hasPrintableChars(text, style)) {
|
||||
@@ -709,52 +711,58 @@ int GfxRenderer::getScreenHeight() const {
|
||||
}
|
||||
|
||||
int GfxRenderer::getSpaceWidth(const int fontId) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
const auto fontIt = fontMap.find(fontId);
|
||||
if (fontIt == fontMap.end()) {
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fontMap.at(fontId).getGlyph(' ', EpdFontFamily::REGULAR)->advanceX;
|
||||
return fontIt->second.getGlyph(' ', EpdFontFamily::REGULAR)->advanceX;
|
||||
}
|
||||
|
||||
int GfxRenderer::getTextAdvanceX(const int fontId, const char* text) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
const auto fontIt = fontMap.find(fontId);
|
||||
if (fontIt == fontMap.end()) {
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t cp;
|
||||
int width = 0;
|
||||
const auto& font = fontIt->second;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||
width += fontMap.at(fontId).getGlyph(cp, EpdFontFamily::REGULAR)->advanceX;
|
||||
width += font.getGlyph(cp, EpdFontFamily::REGULAR)->advanceX;
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
int GfxRenderer::getFontAscenderSize(const int fontId) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
const auto fontIt = fontMap.find(fontId);
|
||||
if (fontIt == fontMap.end()) {
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->ascender;
|
||||
return fontIt->second.getData(EpdFontFamily::REGULAR)->ascender;
|
||||
}
|
||||
|
||||
int GfxRenderer::getLineHeight(const int fontId) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
const auto fontIt = fontMap.find(fontId);
|
||||
if (fontIt == fontMap.end()) {
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->advanceY;
|
||||
return fontIt->second.getData(EpdFontFamily::REGULAR)->advanceY;
|
||||
}
|
||||
|
||||
int GfxRenderer::getTextHeight(const int fontId) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
const auto fontIt = fontMap.find(fontId);
|
||||
if (fontIt == fontMap.end()) {
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->ascender;
|
||||
return fontIt->second.getData(EpdFontFamily::REGULAR)->ascender;
|
||||
}
|
||||
|
||||
void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y, const char* text, const bool black,
|
||||
@@ -764,11 +772,13 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y
|
||||
return;
|
||||
}
|
||||
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
const auto fontIt = fontMap.find(fontId);
|
||||
if (fontIt == fontMap.end()) {
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return;
|
||||
}
|
||||
const auto font = fontMap.at(fontId);
|
||||
|
||||
const auto& font = fontIt->second;
|
||||
|
||||
// No printable characters
|
||||
if (!font.hasPrintableChars(text, style)) {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#include <HalGPIO.h>
|
||||
#include <SPI.h>
|
||||
#include <esp_sleep.h>
|
||||
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
95
lib/hal/HalPowerManager.cpp
Normal file
95
lib/hal/HalPowerManager.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "HalPowerManager.h"
|
||||
|
||||
#include <Logging.h>
|
||||
#include <WiFi.h>
|
||||
#include <esp_sleep.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "HalGPIO.h"
|
||||
|
||||
HalPowerManager powerManager; // Singleton instance
|
||||
|
||||
void HalPowerManager::begin() {
|
||||
pinMode(BAT_GPIO0, INPUT);
|
||||
normalFreq = getCpuFrequencyMhz();
|
||||
modeMutex = xSemaphoreCreateMutex();
|
||||
assert(modeMutex != nullptr);
|
||||
}
|
||||
|
||||
void HalPowerManager::setPowerSaving(bool enabled) {
|
||||
if (normalFreq <= 0) {
|
||||
return; // invalid state
|
||||
}
|
||||
|
||||
auto wifiMode = WiFi.getMode();
|
||||
if (wifiMode != WIFI_MODE_NULL) {
|
||||
// Wifi is active, force disabling power saving
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
// Note: We don't use mutex here to avoid too much overhead,
|
||||
// it's not very important if we read a slightly stale value for currentLockMode
|
||||
const LockMode mode = currentLockMode;
|
||||
|
||||
if (mode == None && enabled && !isLowPower) {
|
||||
LOG_DBG("PWR", "Going to low-power mode");
|
||||
if (!setCpuFrequencyMhz(LOW_POWER_FREQ)) {
|
||||
LOG_DBG("PWR", "Failed to set CPU frequency = %d MHz", LOW_POWER_FREQ);
|
||||
return;
|
||||
}
|
||||
isLowPower = true;
|
||||
|
||||
} else if ((!enabled || mode != None) && isLowPower) {
|
||||
LOG_DBG("PWR", "Restoring normal CPU frequency");
|
||||
if (!setCpuFrequencyMhz(normalFreq)) {
|
||||
LOG_DBG("PWR", "Failed to set CPU frequency = %d MHz", normalFreq);
|
||||
return;
|
||||
}
|
||||
isLowPower = false;
|
||||
}
|
||||
|
||||
// Otherwise, no change needed
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
HalPowerManager::Lock::Lock() {
|
||||
xSemaphoreTake(powerManager.modeMutex, portMAX_DELAY);
|
||||
// Current limitation: only one lock at a time
|
||||
if (powerManager.currentLockMode != None) {
|
||||
LOG_ERR("PWR", "Lock already held, ignore");
|
||||
valid = false;
|
||||
} else {
|
||||
powerManager.currentLockMode = NormalSpeed;
|
||||
valid = true;
|
||||
}
|
||||
xSemaphoreGive(powerManager.modeMutex);
|
||||
if (valid) {
|
||||
// Immediately restore normal CPU frequency if currently in low-power mode
|
||||
powerManager.setPowerSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
HalPowerManager::Lock::~Lock() {
|
||||
xSemaphoreTake(powerManager.modeMutex, portMAX_DELAY);
|
||||
if (valid) {
|
||||
powerManager.currentLockMode = None;
|
||||
}
|
||||
xSemaphoreGive(powerManager.modeMutex);
|
||||
}
|
||||
56
lib/hal/HalPowerManager.h
Normal file
56
lib/hal/HalPowerManager.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <InputManager.h>
|
||||
#include <Logging.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "HalGPIO.h"
|
||||
|
||||
class HalPowerManager;
|
||||
extern HalPowerManager powerManager; // Singleton
|
||||
|
||||
class HalPowerManager {
|
||||
int normalFreq = 0; // MHz
|
||||
bool isLowPower = false;
|
||||
|
||||
enum LockMode { None, NormalSpeed };
|
||||
LockMode currentLockMode = None;
|
||||
SemaphoreHandle_t modeMutex = nullptr; // Protect access to currentLockMode
|
||||
|
||||
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
|
||||
// Should be called inside main loop() to handle the currentLockMode
|
||||
void startDeepSleep(HalGPIO& gpio) const;
|
||||
|
||||
// Get battery percentage (range 0-100)
|
||||
int getBatteryPercentage() const;
|
||||
|
||||
// RAII helper class to manage power saving locks
|
||||
// Usage: create an instance of Lock in a scope to disable power saving, for example when running a task that needs
|
||||
// full performance. When the Lock instance is destroyed (goes out of scope), power saving will be re-enabled.
|
||||
class Lock {
|
||||
friend class HalPowerManager;
|
||||
bool valid = false;
|
||||
|
||||
public:
|
||||
explicit Lock();
|
||||
~Lock();
|
||||
|
||||
// Non-copyable and non-movable
|
||||
Lock(const Lock&) = delete;
|
||||
Lock& operator=(const Lock&) = delete;
|
||||
Lock(Lock&&) = delete;
|
||||
Lock& operator=(Lock&&) = delete;
|
||||
};
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "Activity.h"
|
||||
|
||||
#include <HalPowerManager.h>
|
||||
|
||||
void Activity::renderTaskTrampoline(void* param) {
|
||||
auto* self = static_cast<Activity*>(param);
|
||||
self->renderTaskLoop();
|
||||
@@ -9,6 +11,7 @@ void Activity::renderTaskLoop() {
|
||||
while (true) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
{
|
||||
HalPowerManager::Lock powerLock; // Ensure we don't go into low-power mode while rendering
|
||||
RenderLock lock(*this);
|
||||
render(std::move(lock));
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "ActivityWithSubactivity.h"
|
||||
|
||||
#include <HalPowerManager.h>
|
||||
|
||||
void ActivityWithSubactivity::renderTaskLoop() {
|
||||
while (true) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
{
|
||||
HalPowerManager::Lock powerLock; // Ensure we don't go into low-power mode while rendering
|
||||
RenderLock lock(*this);
|
||||
if (!subActivity) {
|
||||
render(std::move(lock));
|
||||
|
||||
@@ -189,7 +189,7 @@ void OpdsBookBrowserActivity::render(Activity::RenderLock&&) {
|
||||
if (!entries.empty() && entries[selectorIndex].type == OpdsEntryType::BOOK) {
|
||||
confirmLabel = tr(STR_DOWNLOAD);
|
||||
}
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), confirmLabel, "", "");
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), confirmLabel, tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
if (entries.empty()) {
|
||||
|
||||
@@ -196,8 +196,8 @@ void MyLibraryActivity::render(Activity::RenderLock&&) {
|
||||
const auto pageHeight = renderer.getScreenHeight();
|
||||
auto metrics = UITheme::getInstance().getMetrics();
|
||||
|
||||
auto folderName = basepath == "/" ? tr(STR_SD_CARD) : basepath.substr(basepath.rfind('/') + 1).c_str();
|
||||
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, folderName);
|
||||
std::string folderName = (basepath == "/") ? tr(STR_SD_CARD) : basepath.substr(basepath.rfind('/') + 1);
|
||||
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, folderName.c_str());
|
||||
|
||||
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
|
||||
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing;
|
||||
|
||||
@@ -92,7 +92,7 @@ void NetworkModeSelectionActivity::render(Activity::RenderLock&&) {
|
||||
}
|
||||
|
||||
// Draw help text at bottom
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "", "");
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
renderer.displayBuffer();
|
||||
|
||||
@@ -310,8 +310,8 @@ void KOReaderSyncActivity::render(Activity::RenderLock&&) {
|
||||
}
|
||||
renderer.drawText(UI_10_FONT_ID, 20, optionY + optionHeight, tr(STR_UPLOAD_LOCAL), selectedOption != 1);
|
||||
|
||||
// Bottom button hints: show Back and Select
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "", "");
|
||||
// Bottom button hints
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
renderer.displayBuffer();
|
||||
return;
|
||||
|
||||
@@ -149,7 +149,7 @@ void CalibreSettingsActivity::render(Activity::RenderLock&&) {
|
||||
}
|
||||
|
||||
// Draw button hints
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "", "");
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
renderer.displayBuffer();
|
||||
|
||||
@@ -13,6 +13,7 @@ class ClearCacheActivity final : public ActivityWithSubactivity {
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
bool skipLoopDelay() override { return true; } // Prevent power-saving mode
|
||||
void render(Activity::RenderLock&&) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -173,7 +173,7 @@ void KOReaderSettingsActivity::render(Activity::RenderLock&&) {
|
||||
}
|
||||
|
||||
// Draw button hints
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "", "");
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
renderer.displayBuffer();
|
||||
|
||||
@@ -87,7 +87,7 @@ void LanguageSelectActivity::render(Activity::RenderLock&&) {
|
||||
}
|
||||
|
||||
// Button hints
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "", "");
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
renderer.displayBuffer();
|
||||
|
||||
@@ -34,4 +34,5 @@ class OtaUpdateActivity : public ActivityWithSubactivity {
|
||||
void loop() override;
|
||||
void render(Activity::RenderLock&&) override;
|
||||
bool preventAutoSleep() override { return state == CHECKING_FOR_UPDATE || state == UPDATE_IN_PROGRESS; }
|
||||
bool skipLoopDelay() override { return true; } // Prevent power-saving mode
|
||||
};
|
||||
|
||||
18
src/main.cpp
18
src/main.cpp
@@ -3,6 +3,7 @@
|
||||
#include <GfxRenderer.h>
|
||||
#include <HalDisplay.h>
|
||||
#include <HalGPIO.h>
|
||||
#include <HalPowerManager.h>
|
||||
#include <HalStorage.h>
|
||||
#include <I18n.h>
|
||||
#include <Logging.h>
|
||||
@@ -183,7 +184,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +207,7 @@ void enterDeepSleep() {
|
||||
LOG_DBG("MAIN", "Power button press calibration value: %lu ms", t2 - t1);
|
||||
LOG_DBG("MAIN", "Entering deep sleep");
|
||||
|
||||
gpio.startDeepSleep();
|
||||
powerManager.startDeepSleep(gpio);
|
||||
}
|
||||
|
||||
void onGoHome();
|
||||
@@ -283,6 +284,7 @@ void setup() {
|
||||
t1 = millis();
|
||||
|
||||
gpio.begin();
|
||||
powerManager.begin();
|
||||
|
||||
// Only start serial if USB connected
|
||||
if (gpio.isUsbConnected()) {
|
||||
@@ -319,7 +321,7 @@ void setup() {
|
||||
case HalGPIO::WakeupReason::AfterUSBPower:
|
||||
// If USB power caused a cold boot, go back to sleep
|
||||
LOG_DBG("MAIN", "Wakeup reason: After USB Power");
|
||||
gpio.startDeepSleep();
|
||||
powerManager.startDeepSleep(gpio);
|
||||
break;
|
||||
case HalGPIO::WakeupReason::AfterFlash:
|
||||
// After flashing, just proceed to boot
|
||||
@@ -391,7 +393,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();
|
||||
@@ -426,11 +429,12 @@ void loop() {
|
||||
// When an activity requests skip loop delay (e.g., webserver running), use yield() for faster response
|
||||
// Otherwise, use longer delay to save power
|
||||
if (currentActivity && currentActivity->skipLoopDelay()) {
|
||||
yield(); // Give FreeRTOS a chance to run tasks, but return immediately
|
||||
powerManager.setPowerSaving(false); // Make sure we're at full performance when skipLoopDelay is requested
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user