@@ -99,8 +99,29 @@ void CrossPointSettings::validateFrontButtonMapping(CrossPointSettings& settings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <Preferences.h>
|
||||||
|
|
||||||
|
void CrossPointSettings::loadStartupFromNvs() {
|
||||||
|
Preferences nvs;
|
||||||
|
nvs.begin("Crosspoint", true); // read-only
|
||||||
|
btnShortPower = nvs.getUChar("bSPwr", BTN_DEFAULT);
|
||||||
|
btnDoublePower = nvs.getUChar("bDPwr", BTN_DEFAULT);
|
||||||
|
useClock = nvs.getUChar("useClk", 0);
|
||||||
|
nvs.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossPointSettings::saveStartupToNvs() const {
|
||||||
|
Preferences nvs;
|
||||||
|
nvs.begin("Crosspoint", false); // read-write
|
||||||
|
nvs.putUChar("bSPwr", btnShortPower);
|
||||||
|
nvs.putUChar("bDPwr", btnDoublePower);
|
||||||
|
nvs.putUChar("useClk", useClock);
|
||||||
|
nvs.end();
|
||||||
|
}
|
||||||
|
|
||||||
bool CrossPointSettings::saveToFile() const {
|
bool CrossPointSettings::saveToFile() const {
|
||||||
Storage.mkdir("/.crosspoint");
|
Storage.mkdir("/.crosspoint");
|
||||||
|
saveStartupToNvs();
|
||||||
return JsonSettingsIO::saveSettings(*this, SETTINGS_FILE_JSON);
|
return JsonSettingsIO::saveSettings(*this, SETTINGS_FILE_JSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +134,7 @@ bool CrossPointSettings::loadFromFile() {
|
|||||||
bool result = JsonSettingsIO::loadSettings(*this, json.c_str(), &resave);
|
bool result = JsonSettingsIO::loadSettings(*this, json.c_str(), &resave);
|
||||||
if (result) {
|
if (result) {
|
||||||
enforceFixedShortActions(*this);
|
enforceFixedShortActions(*this);
|
||||||
|
saveStartupToNvs(); // Ensure NVS is in sync on boot
|
||||||
if (resave) {
|
if (resave) {
|
||||||
if (saveToFile()) {
|
if (saveToFile()) {
|
||||||
LOG_DBG("CPS", "Resaved settings to update format");
|
LOG_DBG("CPS", "Resaved settings to update format");
|
||||||
|
|||||||
@@ -339,6 +339,8 @@ class CrossPointSettings {
|
|||||||
|
|
||||||
bool saveToFile() const;
|
bool saveToFile() const;
|
||||||
bool loadFromFile();
|
bool loadFromFile();
|
||||||
|
void loadStartupFromNvs();
|
||||||
|
void saveStartupToNvs() const;
|
||||||
|
|
||||||
static void validateFrontButtonMapping(CrossPointSettings& settings);
|
static void validateFrontButtonMapping(CrossPointSettings& settings);
|
||||||
|
|
||||||
|
|||||||
+37
-26
@@ -195,6 +195,15 @@ void setup() {
|
|||||||
powerManager.begin();
|
powerManager.begin();
|
||||||
gpio_deep_sleep_hold_dis(); // Release deep sleep GPIO hold state from previous sleep cycle
|
gpio_deep_sleep_hold_dis(); // Release deep sleep GPIO hold state from previous sleep cycle
|
||||||
|
|
||||||
|
const auto wakeupReason = gpio.getWakeupReason();
|
||||||
|
|
||||||
|
if (wakeupReason == HalGPIO::WakeupReason::AfterUSBPower) {
|
||||||
|
// If USB power caused a cold boot, go back to sleep immediately without initializing subsystems
|
||||||
|
LOG_DBG("MAIN", "Wakeup reason: After USB Power => Deep sleep");
|
||||||
|
powerManager.startDeepSleep(gpio);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_SERIAL_LOG
|
#ifdef ENABLE_SERIAL_LOG
|
||||||
if (gpio.isUsbConnected()) {
|
if (gpio.isUsbConnected()) {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
@@ -206,6 +215,25 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
LOG_INF("MAIN", "Hardware detect: %s", gpio.deviceIsX3() ? "X3" : "X4");
|
LOG_INF("MAIN", "Hardware detect: %s", gpio.deviceIsX3() ? "X3" : "X4");
|
||||||
|
LOG_DBG("MAIN", "Wakeup reason: %d, millis=%lu, rawPowerPin=%d", static_cast<int>(wakeupReason), millis(),
|
||||||
|
digitalRead(InputManager::POWER_BUTTON_PIN) == LOW);
|
||||||
|
|
||||||
|
// Load just the settings we need *before* initializing the SD card to speed up and reduce power on unverified wakes
|
||||||
|
SETTINGS.loadStartupFromNvs();
|
||||||
|
|
||||||
|
if (wakeupReason == HalGPIO::WakeupReason::PowerButton) {
|
||||||
|
LOG_DBG("MAIN", "Verifying power button press duration (required=%u ms)",
|
||||||
|
CrossPointSettings::getPowerButtonDuration());
|
||||||
|
|
||||||
|
// We only want to skip the hold verification (allowing a short press to wake) if the short
|
||||||
|
// press or double press actually have an action assigned, or if the clock screensaver is active.
|
||||||
|
// Otherwise, short presses from sleep should be ignored entirely and return to sleep.
|
||||||
|
bool allowShortPress = (SETTINGS.useClock != 0) || (SETTINGS.btnShortPower != CrossPointSettings::BTN_DEFAULT) ||
|
||||||
|
(SETTINGS.btnDoublePower != CrossPointSettings::BTN_DEFAULT);
|
||||||
|
|
||||||
|
gpio.verifyPowerButtonWakeup(CrossPointSettings::getPowerButtonDuration(), allowShortPress);
|
||||||
|
LOG_DBG("MAIN", "Power button verification passed, millis=%lu", millis());
|
||||||
|
}
|
||||||
|
|
||||||
// SD Card Initialization
|
// SD Card Initialization
|
||||||
// We need 6 open files concurrently when parsing a new chapter
|
// We need 6 open files concurrently when parsing a new chapter
|
||||||
@@ -216,8 +244,9 @@ void setup() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HalSystem::checkPanic();
|
|
||||||
SETTINGS.loadFromFile();
|
SETTINGS.loadFromFile();
|
||||||
|
|
||||||
|
HalSystem::checkPanic();
|
||||||
HalSystem::clearPanic(); // TODO: move this to an activity when we have one to display the panic info
|
HalSystem::clearPanic(); // TODO: move this to an activity when we have one to display the panic info
|
||||||
HalClock::applyTimezone(SETTINGS.timeZone);
|
HalClock::applyTimezone(SETTINGS.timeZone);
|
||||||
I18N.loadSettings();
|
I18N.loadSettings();
|
||||||
@@ -227,31 +256,6 @@ void setup() {
|
|||||||
UITheme::getInstance().reload();
|
UITheme::getInstance().reload();
|
||||||
ButtonNavigator::setMappedInputManager(mappedInputManager);
|
ButtonNavigator::setMappedInputManager(mappedInputManager);
|
||||||
|
|
||||||
const auto wakeupReason = gpio.getWakeupReason();
|
|
||||||
LOG_DBG("MAIN", "Wakeup reason: %d, millis=%lu, rawPowerPin=%d", static_cast<int>(wakeupReason), millis(),
|
|
||||||
digitalRead(InputManager::POWER_BUTTON_PIN) == LOW);
|
|
||||||
|
|
||||||
switch (wakeupReason) {
|
|
||||||
case HalGPIO::WakeupReason::PowerButton: {
|
|
||||||
constexpr uint16_t defaultPowerButtonDurationMs = 400;
|
|
||||||
LOG_DBG("MAIN", "Verifying power button press duration (required=%u ms, default only)",
|
|
||||||
defaultPowerButtonDurationMs);
|
|
||||||
gpio.verifyPowerButtonWakeup(defaultPowerButtonDurationMs, false);
|
|
||||||
LOG_DBG("MAIN", "Power button verification passed, millis=%lu", millis());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HalGPIO::WakeupReason::AfterUSBPower:
|
|
||||||
// If USB power caused a cold boot, go back to sleep
|
|
||||||
LOG_DBG("MAIN", "Wakeup reason: After USB Power");
|
|
||||||
powerManager.startDeepSleep(gpio);
|
|
||||||
break;
|
|
||||||
case HalGPIO::WakeupReason::AfterFlash:
|
|
||||||
// After flashing, just proceed to boot
|
|
||||||
case HalGPIO::WakeupReason::Other:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
@@ -277,6 +281,13 @@ void setup() {
|
|||||||
APP_STATE.saveToFile();
|
APP_STATE.saveToFile();
|
||||||
activityManager.goToReader(path);
|
activityManager.goToReader(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure we're not still holding the power button before leaving setup
|
||||||
|
// waitForStablePowerRelease protects against switch bounce that might register as a false double-press.
|
||||||
|
gpio.waitForStablePowerRelease();
|
||||||
|
// Flush any pin state transitions that occurred during boot before entering the main loop
|
||||||
|
mappedInputManager.update();
|
||||||
|
buttonEventManager.drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|||||||
Reference in New Issue
Block a user