Fixes
This commit is contained in:
+59
-27
@@ -135,7 +135,25 @@ constexpr uint32_t SILENT_REBOOT_MAGIC = 0xC1EAB007;
|
|||||||
constexpr uint32_t SILENT_REBOOT_TARGET_HOME = 0;
|
constexpr uint32_t SILENT_REBOOT_TARGET_HOME = 0;
|
||||||
constexpr uint32_t SILENT_REBOOT_TARGET_READER = 1;
|
constexpr uint32_t SILENT_REBOOT_TARGET_READER = 1;
|
||||||
|
|
||||||
|
// How the device is coming back to life, resolved once at boot. Both resume
|
||||||
|
// flows suppress the splash and leave the panel holding its pre-boot frame; a
|
||||||
|
// plain boot shows the splash. See setup() for the resolution.
|
||||||
|
enum class BootResume : uint8_t {
|
||||||
|
Splash, // cold boot, flash, panic, or plain reboot
|
||||||
|
Silent, // heap-defrag ESP.restart() (RTC flag; lost on power loss)
|
||||||
|
QuickResume, // wake from a quick-resume deep sleep (SD flag; survives power loss)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// on wake and already clears the heap, so rebooting here would just power the
|
||||||
|
// device back up against the user's sleep gesture. Never cleared:
|
||||||
|
// startDeepSleep() does not return, so a set latch only ends at the wakeup reset.
|
||||||
|
static bool deepSleepInProgress = false;
|
||||||
|
|
||||||
void silentRestart() {
|
void silentRestart() {
|
||||||
|
if (deepSleepInProgress) return; // sleeping supersedes the heap-defrag reboot
|
||||||
silentRebootTarget = SILENT_REBOOT_TARGET_HOME;
|
silentRebootTarget = SILENT_REBOOT_TARGET_HOME;
|
||||||
silentRebootMagic = SILENT_REBOOT_MAGIC;
|
silentRebootMagic = SILENT_REBOOT_MAGIC;
|
||||||
LOG_DBG("MAIN", "Silent restart (target=home)");
|
LOG_DBG("MAIN", "Silent restart (target=home)");
|
||||||
@@ -144,6 +162,7 @@ void silentRestart() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void silentRestartToReader() {
|
void silentRestartToReader() {
|
||||||
|
if (deepSleepInProgress) return; // sleeping supersedes the heap-defrag reboot
|
||||||
silentRebootTarget = SILENT_REBOOT_TARGET_READER;
|
silentRebootTarget = SILENT_REBOOT_TARGET_READER;
|
||||||
silentRebootMagic = SILENT_REBOOT_MAGIC;
|
silentRebootMagic = SILENT_REBOOT_MAGIC;
|
||||||
LOG_DBG("MAIN", "Silent restart (target=reader)");
|
LOG_DBG("MAIN", "Silent restart (target=reader)");
|
||||||
@@ -217,6 +236,10 @@ void enterDeepSleep(bool fromTimeout = false) {
|
|||||||
WiFi.disconnect(true);
|
WiFi.disconnect(true);
|
||||||
WiFi.mode(WIFI_OFF);
|
WiFi.mode(WIFI_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Commit to sleeping before goToSleep() runs the outgoing activity's onExit():
|
||||||
|
// a WiFi activity would otherwise silentRestart() here and reboot instead.
|
||||||
|
deepSleepInProgress = true;
|
||||||
activityManager.goToSleep(fromTimeout);
|
activityManager.goToSleep(fromTimeout);
|
||||||
|
|
||||||
// Persist the moon-icon-overlaid framebuffer after goToSleep() has painted it.
|
// Persist the moon-icon-overlaid framebuffer after goToSleep() has painted it.
|
||||||
@@ -421,34 +444,43 @@ void setup() {
|
|||||||
// First serial output only here to avoid timing inconsistencies for power button press duration verification
|
// First serial output only here to avoid timing inconsistencies for power button press duration verification
|
||||||
LOG_DBG("MAIN", "Starting CrossPoint version " CROSSPOINT_VERSION);
|
LOG_DBG("MAIN", "Starting CrossPoint version " CROSSPOINT_VERSION);
|
||||||
|
|
||||||
const bool seamlessWake = !isSilentReboot && !APP_STATE.showBootScreen;
|
// Resolve the single boot-presentation decision. Skipping the splash also
|
||||||
setupDisplayAndFonts(seamlessWake);
|
// skips the panel-clearing pass and the X3 initial-full-sync arming (see
|
||||||
|
// HalDisplay::begin), so the first paint is FAST_REFRESH (~500ms) over the
|
||||||
|
// retained frame and input dispatches against a visible UI.
|
||||||
|
const BootResume resume = isSilentReboot ? BootResume::Silent
|
||||||
|
: !APP_STATE.showBootScreen ? BootResume::QuickResume
|
||||||
|
: BootResume::Splash;
|
||||||
|
|
||||||
if (isSilentReboot) {
|
setupDisplayAndFonts(resume != BootResume::Splash);
|
||||||
// After a silent reboot the panel still shows the previous session's pixels but
|
|
||||||
// the SDK's RED-RAM diff buffer was cleared by begin(). A FAST refresh would only
|
switch (resume) {
|
||||||
// flip pixels the SDK *thinks* changed, leaving the old screen visible. Force the
|
case BootResume::Silent:
|
||||||
// first paint to HALF_REFRESH so the panel cleanly repaints; subsequent paints
|
// After a silent reboot the panel still shows the previous session's pixels but
|
||||||
// resume FAST as normal.
|
// the SDK's RED-RAM diff buffer was cleared by begin(). A FAST refresh would only
|
||||||
renderer.setNextDisplayRefreshMode(HalDisplay::HALF_REFRESH);
|
// flip pixels the SDK *thinks* changed, leaving the old screen visible. Force the
|
||||||
} else if (seamlessWake && loadSleepFrameBuffer()) {
|
// first paint to HALF_REFRESH so the panel cleanly repaints; subsequent paints
|
||||||
// Quick Resume wake: framebuffer restored. Overlay a small loading icon to signal
|
// resume FAST as normal.
|
||||||
// the device is busy reaching the reader (replacing the moon icon painted at sleep).
|
renderer.setNextDisplayRefreshMode(HalDisplay::HALF_REFRESH);
|
||||||
const auto pageHeight = renderer.getScreenHeight();
|
break;
|
||||||
renderer.drawImage(LoadingIcon, 0, pageHeight - LOADINGICON_HEIGHT, LOADINGICON_WIDTH, LOADINGICON_HEIGHT);
|
case BootResume::QuickResume:
|
||||||
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
|
// One-shot flag: re-arm the splash for the next non-quick-resume boot. Save
|
||||||
// Next sleep (whether crash, cold boot, or anything that doesn't go through enterDeepSleep)
|
// before any painting so a hang in the blocking paint path can't strand
|
||||||
// must fall back to a proper boot screen.
|
// us in a quick-resume-with-no-frame loop on the next boot.
|
||||||
APP_STATE.showBootScreen = true;
|
|
||||||
APP_STATE.saveToFile();
|
|
||||||
} else {
|
|
||||||
if (seamlessWake) {
|
|
||||||
// We promised a seamless wake but the framebuffer file was missing or unreadable —
|
|
||||||
// reset the flag so future cycles don't hit the same bad state.
|
|
||||||
APP_STATE.showBootScreen = true;
|
APP_STATE.showBootScreen = true;
|
||||||
APP_STATE.saveToFile();
|
APP_STATE.saveToFile();
|
||||||
}
|
if (loadSleepFrameBuffer()) {
|
||||||
activityManager.goToBoot();
|
// Frame restored: swap the sleep moon for the loading icon.
|
||||||
|
const auto pageHeight = renderer.getScreenHeight();
|
||||||
|
renderer.drawImage(LoadingIcon, 0, pageHeight - LOADINGICON_HEIGHT, LOADINGICON_WIDTH, LOADINGICON_HEIGHT);
|
||||||
|
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
|
||||||
|
} else {
|
||||||
|
activityManager.goToBoot(); // frame file missing, fall back to the splash
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BootResume::Splash:
|
||||||
|
activityManager.goToBoot();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
HalClock::restore();
|
HalClock::restore();
|
||||||
@@ -460,10 +492,10 @@ void setup() {
|
|||||||
// Skip normal home/reader routing: jump straight into the SD firmware picker.
|
// Skip normal home/reader routing: jump straight into the SD firmware picker.
|
||||||
activityManager.replaceActivity(
|
activityManager.replaceActivity(
|
||||||
std::make_unique<SdFirmwareUpdateActivity>(renderer, mappedInputManager, /*recoveryMode=*/true));
|
std::make_unique<SdFirmwareUpdateActivity>(renderer, mappedInputManager, /*recoveryMode=*/true));
|
||||||
} else if (isSilentReboot && silentRebootTargetSnapshot == SILENT_REBOOT_TARGET_READER &&
|
} else if (resume == BootResume::Silent && silentRebootTargetSnapshot == SILENT_REBOOT_TARGET_READER &&
|
||||||
!APP_STATE.openEpubPath.empty()) {
|
!APP_STATE.openEpubPath.empty()) {
|
||||||
activityManager.goToReader(APP_STATE.openEpubPath);
|
activityManager.goToReader(APP_STATE.openEpubPath);
|
||||||
} else if (isSilentReboot) {
|
} else if (resume == BootResume::Silent) {
|
||||||
// target == home (or reader with no open book): land on home — don't fall
|
// target == home (or reader with no open book): land on home — don't fall
|
||||||
// through to the sleep-wake "resume reader" logic, which fires on stale
|
// through to the sleep-wake "resume reader" logic, which fires on stale
|
||||||
// openEpubPath + lastSleepFromReader from a prior session.
|
// openEpubPath + lastSleepFromReader from a prior session.
|
||||||
|
|||||||
Reference in New Issue
Block a user