From f90aebc891541c6e7c8a2d77119260187b6edf84 Mon Sep 17 00:00:00 2001 From: cottongin Date: Sun, 15 Feb 2026 16:42:27 -0500 Subject: [PATCH] fix: Defer low-power mode during section indexing and book loading Prevent the device from dropping to 10MHz CPU during first-time chapter indexing, cover prerendering, and other CPU-intensive reader operations. Three issues addressed: - ActivityWithSubactivity now delegates preventAutoSleep() and skipLoopDelay() to the active subactivity, so EpubReaderActivity's signal is visible through the ReaderActivity wrapper - Added post-loop() re-check of preventAutoSleep() in main.cpp to catch activity transitions that happen mid-loop - EpubReaderActivity uses both !section and a loadingSection flag to cover the full duration from activity entry through section file creation; TxtReaderActivity uses !initialized similarly Also syncs HalPowerManager.cpp log messages with upstream PR #852. Co-authored-by: Cursor --- lib/hal/HalPowerManager.cpp | 4 ++-- src/activities/ActivityWithSubactivity.h | 2 ++ src/activities/reader/EpubReaderActivity.cpp | 5 +++++ src/activities/reader/EpubReaderActivity.h | 7 +++++++ src/activities/reader/TxtReaderActivity.h | 3 +++ src/main.cpp | 7 +++++++ 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/hal/HalPowerManager.cpp b/lib/hal/HalPowerManager.cpp index c4ca41bf..31e9a7e8 100644 --- a/lib/hal/HalPowerManager.cpp +++ b/lib/hal/HalPowerManager.cpp @@ -17,14 +17,14 @@ void HalPowerManager::setPowerSaving(bool enabled) { if (enabled && !isLowPower) { LOG_DBG("PWR", "Going to low-power mode"); if (!setCpuFrequencyMhz(LOW_POWER_FREQ)) { - LOG_ERR("PWR", "Failed to set low-power CPU frequency"); + LOG_DBG("PWR", "Failed to set CPU frequency = %d MHz", LOW_POWER_FREQ); return; } } if (!enabled && isLowPower) { LOG_DBG("PWR", "Restoring normal CPU frequency"); if (!setCpuFrequencyMhz(normalFreq)) { - LOG_ERR("PWR", "Failed to restore normal CPU frequency"); + LOG_DBG("PWR", "Failed to set CPU frequency = %d MHz", normalFreq); return; } } diff --git a/src/activities/ActivityWithSubactivity.h b/src/activities/ActivityWithSubactivity.h index 141dbbcb..3189467d 100644 --- a/src/activities/ActivityWithSubactivity.h +++ b/src/activities/ActivityWithSubactivity.h @@ -14,4 +14,6 @@ class ActivityWithSubactivity : public Activity { : Activity(std::move(name), renderer, mappedInput) {} void loop() override; void onExit() override; + bool preventAutoSleep() override { return subActivity && subActivity->preventAutoSleep(); } + bool skipLoopDelay() override { return subActivity && subActivity->skipLoopDelay(); } }; diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 044c5470..3ad7e656 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -861,6 +861,8 @@ void EpubReaderActivity::renderScreen() { } if (!section) { + loadingSection = true; + const auto filepath = epub->getSpineItem(currentSpineIndex).href; LOG_DBG("ERS", "Loading file: %s, index: %d", filepath.c_str(), currentSpineIndex); section = std::unique_ptr
(new Section(epub, currentSpineIndex, renderer)); @@ -880,6 +882,7 @@ void EpubReaderActivity::renderScreen() { viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, popupFn)) { LOG_ERR("ERS", "Failed to persist page data to SD"); section.reset(); + loadingSection = false; return; } } else { @@ -912,6 +915,8 @@ void EpubReaderActivity::renderScreen() { section->currentPage = newPage; pendingPercentJump = false; } + + loadingSection = false; } renderer.clearScreen(); diff --git a/src/activities/reader/EpubReaderActivity.h b/src/activities/reader/EpubReaderActivity.h index 937c86af..56065c7c 100644 --- a/src/activities/reader/EpubReaderActivity.h +++ b/src/activities/reader/EpubReaderActivity.h @@ -29,6 +29,7 @@ class EpubReaderActivity final : public ActivityWithSubactivity { bool pendingSubactivityExit = false; // Defer subactivity exit to avoid use-after-free bool pendingGoHome = false; // Defer go home to avoid race condition with display task bool skipNextButtonCheck = false; // Skip button processing for one frame after subactivity exit + volatile bool loadingSection = false; // True during the entire !section block (read from main loop) const std::function onGoBack; const std::function onGoHome; @@ -55,4 +56,10 @@ class EpubReaderActivity final : public ActivityWithSubactivity { void onEnter() override; void onExit() override; void loop() override; + // Defer low-power mode and auto-sleep while a section is loading/building. + // !section covers the period before the Section object is created (including + // cover prerendering in onEnter). loadingSection covers the full !section block + // in renderScreen (including createSectionFile), during which section is non-null + // but the section file is still being built. + bool preventAutoSleep() override { return !section || loadingSection; } }; diff --git a/src/activities/reader/TxtReaderActivity.h b/src/activities/reader/TxtReaderActivity.h index 41ccbfbb..74618808 100644 --- a/src/activities/reader/TxtReaderActivity.h +++ b/src/activities/reader/TxtReaderActivity.h @@ -57,4 +57,7 @@ class TxtReaderActivity final : public ActivityWithSubactivity { void onEnter() override; void onExit() override; void loop() override; + // Defer low-power mode and auto-sleep while the reader is initializing + // (cover prerendering, page index building on first open). + bool preventAutoSleep() override { return !initialized; } }; diff --git a/src/main.cpp b/src/main.cpp index d99faea5..8aa0ccaf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -440,6 +440,13 @@ void loop() { } } + // Re-check preventAutoSleep: the activity may have changed during loop() above + // (e.g., HomeActivity transitioned to EpubReaderActivity with pending section work). + if (currentActivity && currentActivity->preventAutoSleep()) { + lastActivityTime = millis(); + powerManager.setPowerSaving(false); + } + // Add delay at the end of the loop to prevent tight spinning // When an activity requests skip loop delay (e.g., webserver running), use yield() for faster response // Otherwise, use longer delay to save power