cleanup
This commit is contained in:
@@ -565,13 +565,7 @@ impl Esp<'_> {
|
|||||||
/// Retries once on flash error.
|
/// Retries once on flash error.
|
||||||
pub(crate) async fn save_config(&mut self, config: Vec<u8>) -> FatResult<()> {
|
pub(crate) async fn save_config(&mut self, config: Vec<u8>) -> FatResult<()> {
|
||||||
let timestamp = self.get_time().to_rfc3339();
|
let timestamp = self.get_time().to_rfc3339();
|
||||||
match self.savegame.save(config.as_slice(), ×tamp) {
|
self.savegame.save(config.as_slice(), ×tamp)
|
||||||
Ok(()) => Ok(()),
|
|
||||||
Err(e) => {
|
|
||||||
warn!("First save attempt failed: {e:?}. Retrying...");
|
|
||||||
self.savegame.save(config.as_slice(), ×tamp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete a specific save slot by erasing it on flash.
|
/// Delete a specific save slot by erasing it on flash.
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ use alloc::vec::Vec;
|
|||||||
use bincode::{Decode, Encode};
|
use bincode::{Decode, Encode};
|
||||||
use embedded_savegame::storage::{Flash, Storage};
|
use embedded_savegame::storage::{Flash, Storage};
|
||||||
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
|
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
|
||||||
use esp_bootloader_esp_idf::partitions::{Error as PartitionError, Error, FlashRegion};
|
use esp_bootloader_esp_idf::partitions::{Error as PartitionError, FlashRegion};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::fat_error::{FatError, FatResult};
|
use crate::fat_error::{FatError, FatResult};
|
||||||
use crate::hal::shared_flash::MutexFlashStorage;
|
use crate::hal::shared_flash::MutexFlashStorage;
|
||||||
@@ -26,7 +26,7 @@ pub struct SaveInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper that includes both the config data and metadata like creation timestamp.
|
/// Wrapper that includes both the config data and metadata like creation timestamp.
|
||||||
#[derive(Serialize, Deserialize, Debug, Encode, Decode)]
|
#[derive(Serialize, Debug, Encode, Decode)]
|
||||||
struct SaveWrapper {
|
struct SaveWrapper {
|
||||||
/// UTC timestamp in RFC3339 format
|
/// UTC timestamp in RFC3339 format
|
||||||
created_at: alloc::string::String,
|
created_at: alloc::string::String,
|
||||||
@@ -72,7 +72,7 @@ impl Flash for SavegameFlashAdapter<'_> {
|
|||||||
let aligned_start = (addr / ERASE_SIZE) * ERASE_SIZE;
|
let aligned_start = (addr / ERASE_SIZE) * ERASE_SIZE;
|
||||||
// Align end address up to erase boundary
|
// Align end address up to erase boundary
|
||||||
let end = addr + SAVEGAME_SLOT_SIZE as u32;
|
let end = addr + SAVEGAME_SLOT_SIZE as u32;
|
||||||
let aligned_end = ((end + ERASE_SIZE - 1) / ERASE_SIZE) * ERASE_SIZE;
|
let aligned_end = end.div_ceil(ERASE_SIZE) * ERASE_SIZE;
|
||||||
|
|
||||||
if aligned_start != addr || aligned_end != end {
|
if aligned_start != addr || aligned_end != end {
|
||||||
log::warn!("Flash erase address not aligned: addr=0x{:x}, slot_size=0x{:x}. Aligned to 0x{:x}-0x{:x}", addr, SAVEGAME_SLOT_SIZE, aligned_start, aligned_end);
|
log::warn!("Flash erase address not aligned: addr=0x{:x}, slot_size=0x{:x}. Aligned to 0x{:x}-0x{:x}", addr, SAVEGAME_SLOT_SIZE, aligned_start, aligned_end);
|
||||||
@@ -126,38 +126,18 @@ impl SavegameManager {
|
|||||||
};
|
};
|
||||||
let mut serialized = bincode::encode_to_vec(&wrapper, bincode::config::standard())?;
|
let mut serialized = bincode::encode_to_vec(&wrapper, bincode::config::standard())?;
|
||||||
info!("Serialized config with size {}", serialized.len());
|
info!("Serialized config with size {}", serialized.len());
|
||||||
(&mut self.storage).append(&mut serialized)?;
|
self.storage.append(&mut serialized)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load the most recently saved data. Returns `None` if no valid save exists.
|
/// Load the most recently saved data. Returns `None` if no valid save exists.
|
||||||
/// Unwraps the SaveWrapper and returns only the config data.
|
/// Unwraps the SaveWrapper and returns only the config data.
|
||||||
pub fn load_latest(&mut self) -> FatResult<Option<Vec<u8>>> {
|
pub fn load_latest(&mut self) -> FatResult<Option<Vec<u8>>> {
|
||||||
let slot = (&mut self.storage).scan()?;
|
let slot = self.storage.scan()?;
|
||||||
match slot {
|
match slot {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(slot) => {
|
Some(slot) => {
|
||||||
let mut buf = alloc::vec![0u8; SAVEGAME_SLOT_SIZE];
|
self.load_slot(slot.idx)
|
||||||
match (&mut self.storage).read(slot.idx, &mut buf)? {
|
|
||||||
None => Ok(None),
|
|
||||||
Some(data) => {
|
|
||||||
// Try to deserialize as SaveWrapper (new Bincode format)
|
|
||||||
match bincode::decode_from_slice::<SaveWrapper, _>(
|
|
||||||
data,
|
|
||||||
bincode::config::standard(),
|
|
||||||
) {
|
|
||||||
Ok((wrapper, _)) => Ok(Some(wrapper.data)),
|
|
||||||
Err(_) => {
|
|
||||||
// Fallback to JSON SaveWrapper (intermediate format)
|
|
||||||
match serde_json::from_slice::<SaveWrapper>(data) {
|
|
||||||
Ok(wrapper) => Ok(Some(wrapper.data)),
|
|
||||||
// Fallback to raw data for backwards compatibility
|
|
||||||
Err(_) => Ok(Some(data.to_vec())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,31 +147,22 @@ impl SavegameManager {
|
|||||||
/// Unwraps the SaveWrapper and returns only the config data.
|
/// Unwraps the SaveWrapper and returns only the config data.
|
||||||
pub fn load_slot(&mut self, idx: usize) -> FatResult<Option<Vec<u8>>> {
|
pub fn load_slot(&mut self, idx: usize) -> FatResult<Option<Vec<u8>>> {
|
||||||
let mut buf = alloc::vec![0u8; SAVEGAME_SLOT_SIZE];
|
let mut buf = alloc::vec![0u8; SAVEGAME_SLOT_SIZE];
|
||||||
match (&mut self.storage).read(idx, &mut buf)? {
|
match self.storage.read(idx, &mut buf)? {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(data) => {
|
Some(data) => {
|
||||||
// Try to deserialize as SaveWrapper (new Bincode format)
|
// Try to deserialize as SaveWrapper (new Bincode format)
|
||||||
match bincode::decode_from_slice::<SaveWrapper, _>(
|
let (wrapper, _) = bincode::decode_from_slice::<SaveWrapper, _>(
|
||||||
data,
|
data,
|
||||||
bincode::config::standard(),
|
bincode::config::standard(),
|
||||||
) {
|
)?;
|
||||||
Ok((wrapper, _)) => Ok(Some(wrapper.data)),
|
Ok(Some(wrapper.data))
|
||||||
Err(_) => {
|
|
||||||
// Fallback to JSON SaveWrapper (intermediate format)
|
|
||||||
match serde_json::from_slice::<SaveWrapper>(data) {
|
|
||||||
Ok(wrapper) => Ok(Some(wrapper.data)),
|
|
||||||
// Fallback to raw data for backwards compatibility
|
|
||||||
Err(_) => Ok(Some(data.to_vec())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Erase a specific slot by index, effectively deleting it.
|
/// Erase a specific slot by index, effectively deleting it.
|
||||||
pub fn delete_slot(&mut self, idx: usize) -> FatResult<()> {
|
pub fn delete_slot(&mut self, idx: usize) -> FatResult<()> {
|
||||||
(&mut self.storage).erase(idx).map_err(Into::into)
|
self.storage.erase(idx).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate all slots and return metadata for every slot that contains a
|
/// Iterate all slots and return metadata for every slot that contains a
|
||||||
@@ -201,27 +172,17 @@ impl SavegameManager {
|
|||||||
let mut saves = Vec::new();
|
let mut saves = Vec::new();
|
||||||
let mut buf = alloc::vec![0u8; SAVEGAME_SLOT_SIZE];
|
let mut buf = alloc::vec![0u8; SAVEGAME_SLOT_SIZE];
|
||||||
for idx in 0..SAVEGAME_SLOT_COUNT {
|
for idx in 0..SAVEGAME_SLOT_COUNT {
|
||||||
if let Some(data) = (&mut self.storage).read(idx, &mut buf)? {
|
if let Some(data) = self.storage.read(idx, &mut buf)? {
|
||||||
// Try to deserialize as SaveWrapper (new Bincode format)
|
// Try to deserialize as SaveWrapper (new Bincode format)
|
||||||
let (len, created_at) = match bincode::decode_from_slice::<SaveWrapper, _>(
|
let (wrapper, _) = bincode::decode_from_slice::<SaveWrapper, _>(
|
||||||
data,
|
data,
|
||||||
bincode::config::standard(),
|
bincode::config::standard(),
|
||||||
) {
|
)?;
|
||||||
Ok((wrapper, _)) => (wrapper.data.len() as u32, Some(wrapper.created_at)),
|
|
||||||
Err(_) => {
|
|
||||||
// Fallback to JSON SaveWrapper (intermediate format)
|
|
||||||
match serde_json::from_slice::<SaveWrapper>(data) {
|
|
||||||
Ok(wrapper) => (wrapper.data.len() as u32, Some(wrapper.created_at)),
|
|
||||||
// Old format without timestamp
|
|
||||||
Err(_) => (data.len() as u32, None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
saves.push(SaveInfo {
|
saves.push(SaveInfo {
|
||||||
idx,
|
idx,
|
||||||
len,
|
len: wrapper.data.len() as u32,
|
||||||
created_at,
|
created_at: Some(wrapper.created_at),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user