Introduce watchdog and serialization improvements

- Added watchdog timer for improved system stability and responsiveness.
- Switched save data serialization to Bincode for better efficiency.
- Enhanced compatibility by supporting fallback to older JSON format.
- Improved logging during flash operations for easier debugging.
- Simplified SavegameManager by managing storage directly.
This commit is contained in:
2026-04-12 20:38:52 +02:00
parent 95f7488fa3
commit b26206eb96
7 changed files with 152 additions and 68 deletions

View File

@@ -3,8 +3,8 @@ use lib_bms_protocol::BmsReadable;
pub(crate) mod battery;
// mod can_api; // replaced by external canapi crate
pub mod esp;
pub(crate) mod savegame_manager;
pub(crate) mod rtc;
pub(crate) mod savegame_manager;
mod shared_flash;
mod v4_hal;
mod water;
@@ -85,7 +85,7 @@ use esp_alloc as _;
use esp_backtrace as _;
use esp_bootloader_esp_idf::ota::{Ota, OtaImageState};
use esp_hal::delay::Delay;
use esp_hal::i2c::master::{BusTimeout, Config, I2c};
use esp_hal::i2c::master::{BusTimeout, Config, FsmTimeout, I2c, SoftwareTimeout};
use esp_hal::interrupt::software::SoftwareInterruptControl;
use esp_hal::pcnt::unit::Unit;
use esp_hal::pcnt::Pcnt;
@@ -93,7 +93,7 @@ use esp_hal::rng::Rng;
use esp_hal::rtc_cntl::{Rtc, SocResetReason};
use esp_hal::system::reset_reason;
use esp_hal::time::Rate;
use esp_hal::timer::timg::TimerGroup;
use esp_hal::timer::timg::{MwdtStage, TimerGroup, Wdt};
use esp_hal::uart::Uart;
use esp_hal::Blocking;
use esp_radio::{init, Controller};
@@ -108,6 +108,13 @@ pub const PLANT_COUNT: usize = 8;
pub static PROGRESS_ACTIVE: AtomicBool = AtomicBool::new(false);
pub static WATCHDOG: OnceLock<
embassy_sync::blocking_mutex::Mutex<
CriticalSectionRawMutex,
RefCell<Wdt<esp_hal::peripherals::TIMG0>>,
>,
> = OnceLock::new();
const TANK_MULTI_SAMPLE: usize = 11;
pub static I2C_DRIVER: OnceLock<
embassy_sync::blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<I2c<Blocking>>>,
@@ -174,6 +181,9 @@ pub trait BoardInteraction<'a> {
// Indicate progress is active to suppress default wait_infinity blinking
PROGRESS_ACTIVE.store(true, core::sync::atomic::Ordering::Relaxed);
// Feed watchdog during long-running webserver operations
PlantHal::feed_watchdog();
let current = counter % PLANT_COUNT as u32;
for led in 0..PLANT_COUNT {
if let Err(err) = self.fault(led, current == led as u32).await {
@@ -251,6 +261,16 @@ impl PlantHal {
let sw_int = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
esp_rtos::start(timg0.timer0, sw_int.software_interrupt0);
// Initialize and enable the watchdog with 30 second timeout
let mut wdt = timg0.wdt;
wdt.set_timeout(MwdtStage::Stage0, esp_hal::time::Duration::from_secs(30));
wdt.enable();
WATCHDOG
.init(embassy_sync::blocking_mutex::Mutex::new(RefCell::new(wdt)))
.map_err(|_| FatError::String {
error: "Watchdog already initialized".to_string(),
})?;
let boot_button = Input::new(
peripherals.GPIO9,
InputConfig::default().with_pull(Pull::None),
@@ -380,7 +400,11 @@ impl PlantHal {
);
let savegame = SavegameManager::new(data);
info!("Savegame storage initialized ({} slots × {} KB)", savegame_manager::SAVEGAME_SLOT_COUNT, savegame_manager::SAVEGAME_SLOT_SIZE / 1024);
info!(
"Savegame storage initialized ({} slots × {} KB)",
savegame_manager::SAVEGAME_SLOT_COUNT,
savegame_manager::SAVEGAME_SLOT_SIZE / 1024
);
let uart0 =
Uart::new(peripherals.UART0, UartConfig::default()).map_err(|_| FatError::String {
@@ -458,11 +482,16 @@ impl PlantHal {
let sda = peripherals.GPIO20;
let scl = peripherals.GPIO19;
// Configure I2C with 1-second timeout
// At 100 Hz I2C clock, one bus cycle = 10ms
// For 1 second timeout: 100 bus cycles
let i2c = I2c::new(
peripherals.I2C0,
Config::default()
.with_frequency(Rate::from_hz(100))
.with_timeout(BusTimeout::Maximum),
//.with_frequency(Rate::from_hz(100))
//1s at 100khz
.with_timeout(BusTimeout::BusCycles(100_000))
.with_scl_main_st_timeout(FsmTimeout::new(21)?),
)?
.with_scl(scl)
.with_sda(sda);
@@ -563,6 +592,15 @@ impl PlantHal {
Ok(Mutex::new(hal))
}
/// Feed the watchdog timer to prevent system reset
pub fn feed_watchdog() {
if let Some(wdt_mutex) = WATCHDOG.try_get() {
wdt_mutex.lock(|cell| {
cell.borrow_mut().feed();
});
}
}
}
fn ota_state(