Preserve regulator recovery through planned resets and storage failures
This commit is contained in:
1 parent
c4a1d485ff
commit
c2998ae8d9
11 files changed
+236
-16
No files matched your search
@@ -33,6 +33,7 @@ static bool ota_ble_started = false;
|
||||
// Intentional reboot paths share the recovery policy's clean-reset marker.
|
||||
// Keep this optional for standalone board/library builds without the policy.
|
||||
extern "C" void meshRegulatorCleanReset() __attribute__((weak));
|
||||
extern "C" void meshRegulatorResumeRecovery() __attribute__((weak));
|
||||
|
||||
namespace {
|
||||
volatile mesh::power::RecoveryRecord regulator_recovery_record
|
||||
@@ -313,9 +314,15 @@ void NRF52Board::feedWatchdog(bool enabled) {
|
||||
// setting is turned off, deliberately stop reloading it; the resulting
|
||||
// watchdog reset is the only software-only way to return it to the stopped
|
||||
// state. On that next boot the disabled preference prevents it starting.
|
||||
if (!enabled) return;
|
||||
|
||||
const bool running = NRF_WDT->RUNSTATUS != 0;
|
||||
if (!enabled) {
|
||||
if (running && !watchdog_disable_reset_pending) {
|
||||
watchdog_disable_reset_pending = true;
|
||||
if (meshRegulatorCleanReset) meshRegulatorCleanReset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!running) {
|
||||
// Keep running during CPU sleep: the flash-driver failure this protects
|
||||
// against sleeps in sd_app_evt_wait(). Pause while halted so breakpoints
|
||||
@@ -329,6 +336,12 @@ void NRF52Board::feedWatchdog(bool enabled) {
|
||||
}
|
||||
|
||||
reloadWatchdogChannels();
|
||||
if (watchdog_disable_reset_pending) {
|
||||
watchdog_disable_reset_pending = false;
|
||||
// Cancel a planned watchdog-off reset with fresh recovery state. Feed
|
||||
// first so the callback's battery sampling cannot race an imminent expiry.
|
||||
if (meshRegulatorResumeRecovery) meshRegulatorResumeRecovery();
|
||||
}
|
||||
#else
|
||||
(void)enabled;
|
||||
#endif
|
||||
|
||||
@@ -37,7 +37,8 @@ protected:
|
||||
uint8_t startup_reason;
|
||||
char *ota_name;
|
||||
bool cpu_dcdc_supported = false;
|
||||
mesh::power::RegulatorMode cpu_regulator_mode = mesh::power::RegulatorMode::Ldo;
|
||||
mesh::power::RegulatorMode cpu_regulator_mode = mesh::power::RegulatorMode::Default;
|
||||
bool watchdog_disable_reset_pending = false;
|
||||
|
||||
#ifdef NRF52_POWER_MANAGEMENT
|
||||
void pwrmgtInit() { initPowerMgr(); }
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include "NRF52VoltageRules.h"
|
||||
#include "NRF52VoltagePolicy.h"
|
||||
#include "PersistentStoreFormat.h"
|
||||
#if defined(NRF52_PLATFORM)
|
||||
#include "AtomicFileWriter.h"
|
||||
#endif
|
||||
#include <Arduino.h>
|
||||
#include <Dispatcher.h>
|
||||
#include <stdio.h>
|
||||
@@ -51,6 +54,22 @@ bool readFile(const char* name, uint8_t (&data)[12]) {
|
||||
}
|
||||
bool save(RegulatorMode mcu, RegulatorMode radio, uint8_t fallback) {
|
||||
if (!settings_fs) return false;
|
||||
#if defined(NRF52_PLATFORM)
|
||||
uint8_t data[12], checked[12];
|
||||
encode(mcu, radio, fallback, data);
|
||||
// The shared LittleFS writer already stages, flushes, checks size/CRC32C,
|
||||
// atomically publishes and verifies the public file. Reuse it rather than
|
||||
// linking a second replacement transaction into flash-constrained targets.
|
||||
mesh::AtomicFileWriter file(settings_fs, path);
|
||||
if (!file || file.write(data, sizeof(data)) != sizeof(data) || !file.commit()) return false;
|
||||
// Retain the format validation and exact-byte comparison as well as the
|
||||
// writer's independent transaction checksum. Legacy .bak files remain
|
||||
// readable at boot and are retired only after this verified publication.
|
||||
if (!readFile(path, checked) || memcmp(data, checked, sizeof(data)) != 0) return false;
|
||||
settings_fs->remove(backup);
|
||||
saved_fallback = fallback;
|
||||
return true;
|
||||
#else
|
||||
settings_fs->remove(temporary);
|
||||
if (settings_fs->exists(temporary)) return false;
|
||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||
@@ -78,6 +97,7 @@ bool save(RegulatorMode mcu, RegulatorMode radio, uint8_t fallback) {
|
||||
settings_fs->remove(backup);
|
||||
saved_fallback = fallback;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t readBatteryPercent(bool& valid) {
|
||||
@@ -256,9 +276,25 @@ void markRegulatorCleanReset() {
|
||||
}
|
||||
}
|
||||
|
||||
void resumeRegulatorRecovery() {
|
||||
if (!initialized) return;
|
||||
bool valid = false;
|
||||
const uint8_t percent = readBatteryPercent(valid);
|
||||
const uint32_t now = millis();
|
||||
const uint8_t active_dcdc =
|
||||
(activeRegulatorMode(true) == RegulatorMode::Dcdc ? RECOVERY_MCU : 0)
|
||||
| (activeRegulatorMode(false) == RegulatorMode::Dcdc ? RECOVERY_RADIO : 0);
|
||||
recovery().arm(active_dcdc, now, percent, valid);
|
||||
last_service = last_battery = now;
|
||||
}
|
||||
|
||||
}} // namespace mesh::power
|
||||
|
||||
extern "C" void meshRegulatorCleanReset() {
|
||||
// Intentional resets can happen before the settings/filesystem is ready.
|
||||
mesh::power::markRegulatorCleanReset();
|
||||
}
|
||||
|
||||
extern "C" void meshRegulatorResumeRecovery() {
|
||||
mesh::power::resumeRegulatorRecovery();
|
||||
}
|
||||
@@ -21,3 +21,4 @@ bool regulatorRecoveryAvailable();
|
||||
}}
|
||||
|
||||
extern "C" void meshRegulatorCleanReset();
|
||||
extern "C" void meshRegulatorResumeRecovery();
|
||||
Reference in new issue
Block a user