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",
|
"embedded-io-async",
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -226,6 +226,15 @@ dependencies = [
|
||||||
"litrs 0.4.1",
|
"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]]
|
[[package]]
|
||||||
name = "embassy-embedded-hal"
|
name = "embassy-embedded-hal"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
|
@ -561,7 +570,7 @@ dependencies = [
|
||||||
"nb 1.1.0",
|
"nb 1.1.0",
|
||||||
"paste",
|
"paste",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"riscv",
|
"riscv",
|
||||||
"serde",
|
"serde",
|
||||||
"strum 0.27.1",
|
"strum 0.27.1",
|
||||||
|
|
@ -697,7 +706,7 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"portable_atomic_enum",
|
"portable_atomic_enum",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -964,6 +973,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bleps",
|
"bleps",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
"ekv",
|
||||||
"embassy-executor",
|
"embassy-executor",
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
"embassy-net",
|
"embassy-net",
|
||||||
|
|
@ -982,6 +992,7 @@ dependencies = [
|
||||||
"libm",
|
"libm",
|
||||||
"log",
|
"log",
|
||||||
"postcard",
|
"postcard",
|
||||||
|
"rand_core 0.9.3",
|
||||||
"serde",
|
"serde",
|
||||||
"smart-leds",
|
"smart-leds",
|
||||||
"smoltcp",
|
"smoltcp",
|
||||||
|
|
@ -1192,6 +1203,12 @@ version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rgb"
|
name = "rgb"
|
||||||
version = "0.8.50"
|
version = "0.8.50"
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,9 @@ esp-storage = { version = "0.6.0", features = ["esp32c3"] }
|
||||||
embedded-storage = "0.3.1"
|
embedded-storage = "0.3.1"
|
||||||
postcard = { version = "1.1.2", features = [] }
|
postcard = { version = "1.1.2", features = [] }
|
||||||
serde = { version = "1.0.219", features = ["derive"], default-features = false }
|
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]
|
[profile.dev]
|
||||||
# Rust debug is too slow.
|
# Rust debug is too slow.
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,6 @@
|
||||||
nvs, data, nvs, 0x9000, 0x6000,
|
nvs, data, nvs, 0x9000, 0x6000,
|
||||||
phy_init, data, phy, 0xf000, 0x1000,
|
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,
|
app_store,0x40, 0x01, 0x10000, 0x10000,
|
||||||
factory, app, factory, 0x20000, 1M,
|
factory, app, factory, 0x20000, 1M,
|
||||||
|
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
use ekv::Database;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::select::select;
|
use embassy_futures::select::select;
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
|
|
@ -13,14 +14,16 @@ use embedded_storage::nor_flash::ReadNorFlash;
|
||||||
use esp_hal::Blocking;
|
use esp_hal::Blocking;
|
||||||
use esp_hal::clock::CpuClock;
|
use esp_hal::clock::CpuClock;
|
||||||
use esp_hal::gpio::{Input, InputConfig, Pull};
|
use esp_hal::gpio::{Input, InputConfig, Pull};
|
||||||
|
use esp_hal::rng::Rng;
|
||||||
use esp_hal::spi::master::{Config, Spi};
|
use esp_hal::spi::master::{Config, Spi};
|
||||||
use esp_hal::time::Rate;
|
use esp_hal::time::Rate;
|
||||||
use esp_hal::timer::systimer::SystemTimer;
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
use esp_hal::timer::timg::TimerGroup;
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
use esp_storage::FlashStorage;
|
use esp_storage::FlashStorage;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use m5stamp_c3_ws2812::FlashEkvStorage;
|
||||||
use postcard::from_bytes;
|
use postcard::from_bytes;
|
||||||
use postcard::to_vec;
|
use rand_core::RngCore;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use smart_leds::RGB8;
|
use smart_leds::RGB8;
|
||||||
|
|
@ -35,7 +38,7 @@ fn panic(_: &core::panic::PanicInfo) -> ! {
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||||
struct State {
|
struct State {
|
||||||
pub count: u8,
|
pub count: u8,
|
||||||
}
|
}
|
||||||
|
|
@ -50,6 +53,8 @@ static STATE: Mutex<CriticalSectionRawMutex, TargetState> = Mutex::new(TargetSta
|
||||||
enabled: [false; 12],
|
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];
|
const ORDER: [usize; 12] = [5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11];
|
||||||
|
|
||||||
//Keep in syn with partitions.csv
|
//Keep in syn with partitions.csv
|
||||||
|
|
@ -71,28 +76,57 @@ async fn main(spawner: Spawner) {
|
||||||
|
|
||||||
info!("Embassy initialized!");
|
info!("Embassy initialized!");
|
||||||
|
|
||||||
let mut flash = FlashStorage::new();
|
let mut rng = Rng::new(peripherals.RNG);
|
||||||
info!("Flash: {flash:?}");
|
|
||||||
|
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 state = {
|
||||||
let mut bytes = [0; 128];
|
let mut bytes = [0; 32];
|
||||||
flash.read(APP_DATA_OFFSET, &mut bytes[..]).unwrap();
|
|
||||||
info!("{bytes:x?}");
|
let r = {
|
||||||
if let Ok(data) = from_bytes::<State>(&bytes[..]) {
|
let trx = db.read_transaction().await;
|
||||||
info!("Successfully restored data.");
|
trx.read(STATE_DB_KEY, bytes.as_mut_slice()).await
|
||||||
data
|
};
|
||||||
} else {
|
|
||||||
State { count: 0 }
|
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 timer1 = TimerGroup::new(peripherals.TIMG0);
|
||||||
let _init = esp_wifi::init(
|
let _init = esp_wifi::init(timer1.timer0, rng, peripherals.RADIO_CLK).unwrap();
|
||||||
timer1.timer0,
|
|
||||||
esp_hal::rng::Rng::new(peripherals.RNG),
|
|
||||||
peripherals.RADIO_CLK,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let led_strip = {
|
let led_strip = {
|
||||||
let spi = Spi::new(
|
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);
|
state.count = state.count.saturating_add_signed(delta as i8).clamp(0, 12);
|
||||||
|
|
||||||
//Write Updated state
|
//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];
|
let mut d = [10u8; 32];
|
||||||
flash.read(APP_DATA_OFFSET, &mut bytes[..]).unwrap();
|
postcard::to_slice(&state, d.as_mut_slice()).unwrap();
|
||||||
info!("Write -> Reaa: {bytes:x?}");
|
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> {
|
struct RotaryEncoderConfig<'a, 'b> {
|
||||||
|
|
|
||||||
62
src/lib.rs
62
src/lib.rs
|
|
@ -1 +1,63 @@
|
||||||
#![no_std]
|
#![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