diff --git a/platformio.ini b/platformio.ini index de8e2317..71f9bb9b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -95,6 +95,7 @@ build_flags = -DLOG_LEVEL=2 ; Set log level to debug for development builds -DFREEINK_CAP_BLE_HID_HOST=1 ; BLE HID page-turner host (NimBLE) -DFREEINK_BLE_HID_SCAN_DEBUG=1 ; verbose BLE scan lifecycle/advertisement logs for bring-up + -DFREEINK_BLE_HID_REPORT_DEBUG=1 ; raw HID report hex dumps + report-map hints (bring-up) [env:gh_release] diff --git a/src/SilentRestart.h b/src/SilentRestart.h index f94345c5..7c7099f5 100644 --- a/src/SilentRestart.h +++ b/src/SilentRestart.h @@ -6,3 +6,7 @@ void silentRestart(); // home screen void silentRestartToReader(); // currently-open EPUB (APP_STATE.openEpubPath) +// True when this boot itself came from a silent restart. Callers that restart +// as a last-resort defrag must check this so a failure that survives the +// restart degrades to an error instead of a reboot loop. +bool bootWasSilentRestart(); diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 3ae5365b..a983d241 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -33,6 +33,7 @@ #include "QrDisplayActivity.h" #include "ReaderUtils.h" #include "RecentBooksStore.h" +#include "SilentRestart.h" #include "components/UITheme.h" #include "fontIds.h" #include "util/BookmarkUtil.h" @@ -883,6 +884,16 @@ void EpubReaderActivity::render(RenderLock&& lock) { bleinput::showConnectingUntilLinked(renderer, mappedInput); requestGhostCleanup(); } + if (!built && !bootWasSilentRestart()) { + // Even with BLE freed, the build can fail when this session's parse churn has + // fragmented the heap beyond in-place recovery. A silent restart is the only + // real defrag on this heap (no compaction); it resumes into this book and + // rebuilds the section on a fresh heap. Guarded by bootWasSilentRestart() so a + // build that fails again after the restart degrades to the error popup below + // instead of reboot-looping. + LOG_ERR("ERS", "Section build failed after BLE recovery; silent restart to defrag heap"); + silentRestartToReader(); + } if (!built) { LOG_ERR("ERS", "Failed to persist page data to SD"); section.reset(); diff --git a/src/main.cpp b/src/main.cpp index 3622413c..5bad1891 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -128,6 +128,12 @@ enum class BootResume : uint8_t { QuickResume, // wake from a quick-resume deep sleep (SD flag; survives power loss) }; +// Latched in setup() from the read-and-clear of the RTC flag, so the reboot-loop +// guard in bootWasSilentRestart() has the answer for the whole session. +static bool bootWasSilentRestartFlag = false; + +bool bootWasSilentRestart() { return bootWasSilentRestartFlag; } + // Latched true once enterDeepSleep() commits to sleeping, before it tears down // the current activity. WiFi activities call silentRestart() in onExit() to // clear heap fragmentation on the way out, but deep sleep is a full chip reset @@ -330,6 +336,7 @@ void setup() { (isSilentReboot && silentRebootTarget <= SILENT_REBOOT_TARGET_READER) ? silentRebootTarget : 0; silentRebootMagic = 0; silentRebootTarget = 0; + bootWasSilentRestartFlag = isSilentReboot; gpio.begin(); powerManager.begin();