Use ekv for storage
This commit is contained in:
parent
b828cc4bde
commit
299504d1b5
5 changed files with 145 additions and 35 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
|
@ -83,7 +83,7 @@ dependencies = [
|
|||
"embedded-io-async",
|
||||
"futures",
|
||||
"log",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -226,6 +226,15 @@ dependencies = [
|
|||
"litrs 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ekv"
|
||||
version = "1.0.0"
|
||||
source = "git+https://github.com/embassy-rs/ekv.git#68b27c52eb587ba883f39f3a8000f671c858f587"
|
||||
dependencies = [
|
||||
"embassy-sync 0.7.0",
|
||||
"heapless 0.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embassy-embedded-hal"
|
||||
version = "0.3.0"
|
||||
|
|
@ -561,7 +570,7 @@ dependencies = [
|
|||
"nb 1.1.0",
|
||||
"paste",
|
||||
"portable-atomic",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"riscv",
|
||||
"serde",
|
||||
"strum 0.27.1",
|
||||
|
|
@ -697,7 +706,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"portable-atomic",
|
||||
"portable_atomic_enum",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -964,6 +973,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bleps",
|
||||
"critical-section",
|
||||
"ekv",
|
||||
"embassy-executor",
|
||||
"embassy-futures",
|
||||
"embassy-net",
|
||||
|
|
@ -982,6 +992,7 @@ dependencies = [
|
|||
"libm",
|
||||
"log",
|
||||
"postcard",
|
||||
"rand_core 0.9.3",
|
||||
"serde",
|
||||
"smart-leds",
|
||||
"smoltcp",
|
||||
|
|
@ -1192,6 +1203,12 @@ version = "0.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.50"
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ esp-storage = { version = "0.6.0", features = ["esp32c3"] }
|
|||
embedded-storage = "0.3.1"
|
||||
postcard = { version = "1.1.2", features = [] }
|
||||
serde = { version = "1.0.219", features = ["derive"], default-features = false }
|
||||
# Use git version, because released versions use old version of embassy-sync
|
||||
ekv = { git = "https://github.com/embassy-rs/ekv.git" }
|
||||
rand_core = "0.9.3"
|
||||
|
||||
[profile.dev]
|
||||
# Rust debug is too slow.
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
|
||||
# TODO Keep in sync with main.rs APP_DATA_OFFSET
|
||||
# TODO Keep in sync with lib.rs APP_DATA_START/SIZE
|
||||
app_store,0x40, 0x01, 0x10000, 0x10000,
|
||||
factory, app, factory, 0x20000, 1M,
|
||||
|
|
|
|||
|
|
|
@ -1,6 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use ekv::Database;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::select::select;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
|
|
@ -13,14 +14,16 @@ use embedded_storage::nor_flash::ReadNorFlash;
|
|||
use esp_hal::Blocking;
|
||||
use esp_hal::clock::CpuClock;
|
||||
use esp_hal::gpio::{Input, InputConfig, Pull};
|
||||
use esp_hal::rng::Rng;
|
||||
use esp_hal::spi::master::{Config, Spi};
|
||||
use esp_hal::time::Rate;
|
||||
use esp_hal::timer::systimer::SystemTimer;
|
||||
use esp_hal::timer::timg::TimerGroup;
|
||||
use esp_storage::FlashStorage;
|
||||
use log::info;
|
||||
use m5stamp_c3_ws2812::FlashEkvStorage;
|
||||
use postcard::from_bytes;
|
||||
use postcard::to_vec;
|
||||
use rand_core::RngCore;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use smart_leds::RGB8;
|
||||
|
|
@ -35,7 +38,7 @@ fn panic(_: &core::panic::PanicInfo) -> ! {
|
|||
|
||||
extern crate alloc;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
struct State {
|
||||
pub count: u8,
|
||||
}
|
||||
|
|
@ -50,6 +53,8 @@ static STATE: Mutex<CriticalSectionRawMutex, TargetState> = Mutex::new(TargetSta
|
|||
enabled: [false; 12],
|
||||
});
|
||||
|
||||
const STATE_DB_KEY: &[u8] = b"STATE";
|
||||
|
||||
const ORDER: [usize; 12] = [5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11];
|
||||
|
||||
//Keep in syn with partitions.csv
|
||||
|
|
@ -71,28 +76,57 @@ async fn main(spawner: Spawner) {
|
|||
|
||||
info!("Embassy initialized!");
|
||||
|
||||
let mut flash = FlashStorage::new();
|
||||
info!("Flash: {flash:?}");
|
||||
let mut rng = Rng::new(peripherals.RNG);
|
||||
|
||||
let db = {
|
||||
let random_seed = rng.random();
|
||||
let mut config = ekv::Config::default();
|
||||
config.random_seed = random_seed;
|
||||
Database::<_, NoopRawMutex>::new(FlashEkvStorage::default(), config)
|
||||
};
|
||||
info!("Database created.");
|
||||
|
||||
let mut state = {
|
||||
let mut bytes = [0; 128];
|
||||
flash.read(APP_DATA_OFFSET, &mut bytes[..]).unwrap();
|
||||
info!("{bytes:x?}");
|
||||
if let Ok(data) = from_bytes::<State>(&bytes[..]) {
|
||||
info!("Successfully restored data.");
|
||||
data
|
||||
} else {
|
||||
State { count: 0 }
|
||||
let mut bytes = [0; 32];
|
||||
|
||||
let r = {
|
||||
let trx = db.read_transaction().await;
|
||||
trx.read(STATE_DB_KEY, bytes.as_mut_slice()).await
|
||||
};
|
||||
|
||||
match r {
|
||||
Ok(_) => {
|
||||
info!("{bytes:x?}");
|
||||
match from_bytes::<State>(&bytes[..]) {
|
||||
Ok(data) => {
|
||||
info!("Successfully restored data.");
|
||||
data
|
||||
}
|
||||
Err(err) => {
|
||||
info!("Stored data was corrupted. {err:?}");
|
||||
State::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(ekv::ReadError::KeyNotFound) => {
|
||||
info!("No data was saved yet.");
|
||||
State::default()
|
||||
}
|
||||
Err(ekv::ReadError::Corrupted) => {
|
||||
info!("Database was corrupt - formatting database");
|
||||
let r = db.format().await;
|
||||
info!("{r:?}");
|
||||
State::default()
|
||||
}
|
||||
Err(err) => {
|
||||
info!("Error while reading stored state: {err:?}");
|
||||
State::default()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let timer1 = TimerGroup::new(peripherals.TIMG0);
|
||||
let _init = esp_wifi::init(
|
||||
timer1.timer0,
|
||||
esp_hal::rng::Rng::new(peripherals.RNG),
|
||||
peripherals.RADIO_CLK,
|
||||
)
|
||||
.unwrap();
|
||||
let _init = esp_wifi::init(timer1.timer0, rng, peripherals.RADIO_CLK).unwrap();
|
||||
|
||||
let led_strip = {
|
||||
let spi = Spi::new(
|
||||
|
|
@ -137,22 +171,16 @@ async fn main(spawner: Spawner) {
|
|||
state.count = state.count.saturating_add_signed(delta as i8).clamp(0, 12);
|
||||
|
||||
//Write Updated state
|
||||
let mut d = [10u8; 128];
|
||||
postcard::to_slice(&state, d.as_mut_slice()).unwrap();
|
||||
info!("{d:x?}");
|
||||
let r = flash.erase(APP_DATA_OFFSET, APP_DATA_OFFSET + (4 << 10));
|
||||
info!("{r:?}");
|
||||
let r = flash.write(APP_DATA_OFFSET, d.as_slice());
|
||||
info!("{r:?}");
|
||||
|
||||
{
|
||||
let mut bytes = [0; 128];
|
||||
flash.read(APP_DATA_OFFSET, &mut bytes[..]).unwrap();
|
||||
info!("Write -> Reaa: {bytes:x?}");
|
||||
let mut d = [10u8; 32];
|
||||
postcard::to_slice(&state, d.as_mut_slice()).unwrap();
|
||||
let mut trx = db.write_transaction().await;
|
||||
let r = trx.write(STATE_DB_KEY, d.as_slice()).await;
|
||||
info!("{r:?}");
|
||||
let r = trx.commit().await;
|
||||
info!("{r:?}");
|
||||
}
|
||||
}
|
||||
|
||||
// for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.0.0-beta.0/examples/src/bin
|
||||
}
|
||||
|
||||
struct RotaryEncoderConfig<'a, 'b> {
|
||||
|
|
|
|||
62
src/lib.rs
62
src/lib.rs
|
|
@ -1 +1,63 @@
|
|||
#![no_std]
|
||||
use ekv::{config, flash::Flash};
|
||||
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
|
||||
use esp_storage::{FlashStorage, FlashStorageError};
|
||||
|
||||
pub const APP_DATA_START: usize = 0x10_000;
|
||||
pub const APP_DATA_SIZE: usize = 0x10_000;
|
||||
|
||||
pub struct FlashEkvStorage {
|
||||
pub storage: FlashStorage,
|
||||
pub partition_start: usize,
|
||||
pub partition_size: usize,
|
||||
}
|
||||
|
||||
impl Default for FlashEkvStorage {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
storage: FlashStorage::new(),
|
||||
// Sync with Partitions.csv
|
||||
partition_start: APP_DATA_START,
|
||||
partition_size: APP_DATA_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Flash for FlashEkvStorage {
|
||||
type Error = FlashStorageError;
|
||||
|
||||
fn page_count(&self) -> usize {
|
||||
self.partition_size / config::PAGE_SIZE
|
||||
}
|
||||
|
||||
async fn erase(&mut self, page_id: ekv::flash::PageID) -> Result<(), Self::Error> {
|
||||
let from = page_id.index() * config::PAGE_SIZE;
|
||||
let to = (page_id.index() + 1) * config::PAGE_SIZE;
|
||||
self.storage.erase(
|
||||
(from + self.partition_start) as u32,
|
||||
(to + self.partition_start) as u32,
|
||||
)
|
||||
}
|
||||
|
||||
async fn read(
|
||||
&mut self,
|
||||
page_id: ekv::flash::PageID,
|
||||
offset: usize,
|
||||
data: &mut [u8],
|
||||
) -> Result<(), Self::Error> {
|
||||
let from = (page_id.index() * config::PAGE_SIZE) + offset;
|
||||
self.storage
|
||||
.read((from + self.partition_start) as u32, data)
|
||||
}
|
||||
|
||||
async fn write(
|
||||
&mut self,
|
||||
page_id: ekv::flash::PageID,
|
||||
offset: usize,
|
||||
data: &[u8],
|
||||
) -> Result<(), Self::Error> {
|
||||
let from = (page_id.index() * config::PAGE_SIZE) + offset;
|
||||
self.storage
|
||||
.write((from + self.partition_start) as u32, data)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue