diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock index 3dbe320..bc1d6b7 100644 --- a/firmware/Cargo.lock +++ b/firmware/Cargo.lock @@ -18,6 +18,7 @@ dependencies = [ "ekv", "embassy-embedded-hal", "embassy-executor", + "embassy-sync 0.6.2", "embassy-sync 0.7.2", "embassy-time", "embedded-cli", @@ -1692,6 +1693,7 @@ dependencies = [ "futures-sink", "futures-util", "heapless 0.8.0", + "log", ] [[package]] diff --git a/firmware/acid-firmware/Cargo.toml b/firmware/acid-firmware/Cargo.toml index 267d8dc..6d155bb 100644 --- a/firmware/acid-firmware/Cargo.toml +++ b/firmware/acid-firmware/Cargo.toml @@ -44,6 +44,7 @@ embassy-executor = { version = "0.9", features = ["log"] } embassy-time = { version = "0.5.0", features = ["log"] } embassy-embedded-hal = "0.5.0" embassy-sync = { version = "0.7.2", features = ["log"] } +embassy-sync-old = { package = "embassy-sync", version = "0.6.2", features = ["log"] } esp-backtrace = { version = "0.18", default-features = false, features = [ "esp32s3", "println", @@ -97,7 +98,8 @@ features = [ "crc", "max-page-count-2048", "max-key-size-256", - "max-value-size-65536", + # "max-value-size-65536", + "max-value-size-1024", # These must adhere to `FlashStorage`'s parameters. "align-4", "page-size-4096", diff --git a/firmware/acid-firmware/src/db/mod.rs b/firmware/acid-firmware/src/db/mod.rs index 1a32409..314b3aa 100644 --- a/firmware/acid-firmware/src/db/mod.rs +++ b/firmware/acid-firmware/src/db/mod.rs @@ -4,13 +4,16 @@ use core::{ }; use alloc::{borrow::Cow, boxed::Box, vec::Vec}; -use ekv::{Database, flash::PageID}; +use ekv::{ + Database, ReadTransaction, + flash::{Flash, PageID}, +}; use embassy_embedded_hal::{adapter::BlockingAsync, flash::partition::Partition}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; use embedded_storage_async::nor_flash::{NorFlash, ReadNorFlash}; use esp_hal::rng::Trng; use esp_storage::FlashStorage; -use log::info; +use log::{debug, info}; pub type PartitionAcid = Partition<'static, CriticalSectionRawMutex, BlockingAsync>>; @@ -241,7 +244,7 @@ impl<'a> IntoIterator for DbPathSpectreUsers { } pub struct DbPathSpectreUserSites<'a> { - username: DbPathSegment<'a>, + pub username: DbPathSegment<'a>, } impl<'a> IntoIterator for DbPathSpectreUserSites<'a> { @@ -260,8 +263,8 @@ impl<'a> IntoIterator for DbPathSpectreUserSites<'a> { } pub struct DbPathSpectreUserSite<'a> { - user_sites: DbPathSpectreUserSites<'a>, - site: DbPathSegment<'a>, + pub user_sites: DbPathSpectreUserSites<'a>, + pub site: DbPathSegment<'a>, } impl<'a> IntoIterator for DbPathSpectreUserSite<'a> { @@ -275,3 +278,42 @@ impl<'a> IntoIterator for DbPathSpectreUserSite<'a> { .chain(core::iter::once(self.site)) } } + +pub trait ReadTransactionExt +where + F: Flash, +{ + async fn read_to_vec<'b>( + &self, + key: &[u8], + buffer: &'b mut Vec, + ) -> Result<&'b mut [u8], ekv::ReadError>; +} + +impl<'a, F, M> ReadTransactionExt for ReadTransaction<'a, F, M> +where + F: Flash + 'a, + M: embassy_sync_old::blocking_mutex::raw::RawMutex + 'a, +{ + async fn read_to_vec<'b>( + &self, + key: &[u8], + buffer: &'b mut Vec, + ) -> Result<&'b mut [u8], ekv::ReadError> { + if buffer.len() == 0 { + buffer.resize(1, 0); + } + + loop { + match self.read(key, buffer.as_mut_slice()).await { + Ok(size) => break Ok(&mut buffer[..size]), + Err(ekv::ReadError::BufferTooSmall) => { + let new_size = buffer.len() * 2; + debug!("Resizing read buffer to {new_size} bytes."); + buffer.resize(new_size, 0) + } + Err(error) => break Err(error), + } + } + } +} diff --git a/firmware/acid-firmware/src/main.rs b/firmware/acid-firmware/src/main.rs index e75ee03..a48091c 100644 --- a/firmware/acid-firmware/src/main.rs +++ b/firmware/acid-firmware/src/main.rs @@ -42,6 +42,7 @@ use esp_hal::lcd_cam::LcdCam; use esp_hal::lcd_cam::lcd::dpi::Dpi; use esp_hal::mcpwm::{McPwm, PeripheralClockConfig}; use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock}; +use esp_hal::ram; use esp_hal::rng::TrngSource; use esp_hal::sha::{Sha, ShaBackend}; use esp_hal::system::Stack; @@ -151,7 +152,9 @@ async fn main(_spawner: Spawner) { // TODO: Can we combine the regular link section with dram2? // esp_alloc::heap_allocator!(size: 80 * 1024); // esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 72 * 1024); - esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024); + //esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024); + esp_alloc::heap_allocator!(#[ram(reclaimed)] size: 72 * 1024); + esp_alloc::heap_allocator!(size: 16 * 1024); info!("Heap initialized! {:#?}", esp_alloc::HEAP.stats()); // Initialize the PSRAM allocator. @@ -164,10 +167,12 @@ async fn main(_spawner: Spawner) { MemoryCapability::External.into(), )); } + info!( + "PSRAM allocator initialized with capacity of {} MiB!", + psram_size / 1024 / 1024 + ); } - info!("PSRAM allocator initialized!"); - // let mut io = Io::new(peripherals.IO_MUX); // io.set_interrupt_handler(interrupt_handler); @@ -376,7 +381,7 @@ async fn main(_spawner: Spawner) { let window_size = [framebuffer.height, framebuffer.width]; let framebuffer_ptr = FramebufferPtr(framebuffer.as_target_pixels() as _); - static SECOND_CORE_STACK: StaticCell> = StaticCell::new(); + static SECOND_CORE_STACK: StaticCell> = StaticCell::new(); let second_core_stack = SECOND_CORE_STACK.init(Stack::new()); esp_rtos::start_second_core( peripherals.CPU_CTRL, diff --git a/firmware/acid-firmware/src/ui/mod.rs b/firmware/acid-firmware/src/ui/mod.rs index 6f870e7..940d91b 100644 --- a/firmware/acid-firmware/src/ui/mod.rs +++ b/firmware/acid-firmware/src/ui/mod.rs @@ -34,7 +34,10 @@ use spectre_api_sys::{ use crate::FRAME_DURATION_MIN; use crate::{ SIGNAL_LCD_SUBMIT, SIGNAL_UI_RENDER, - db::{AcidDatabase, DbKey, DbPathSpectreUsers, PartitionAcid}, + db::{ + AcidDatabase, DbKey, DbPathSpectreUserSite, DbPathSpectreUserSites, DbPathSpectreUsers, + PartitionAcid, ReadTransactionExt, + }, ui::backend::SlintBackend, util::DurationExt, }; @@ -123,6 +126,21 @@ struct SpectreSiteConfig { last_used: NaiveDateTime, } +impl Default for SpectreSiteConfig { + fn default() -> Self { + Self { + algorithm: SpectreAlgorithm::Current, + counter: SpectreCounter::Default, + result_type: SpectreResultType::SpectreResultDefaultResult, + password: None, + login_type: SpectreResultType::SpectreResultDefaultLogin, + login_name: None, + uses: 0, + last_used: Default::default(), + } + } +} + #[derive(Clone, Debug, PartialEq, Eq)] struct SpectreSite { username: String, @@ -142,6 +160,30 @@ pub async fn run_renderer_task(backend: SlintBackend, flash_part_acid: Partition { let mut write = db.write_transaction().await; + write + .write( + &DbKey::new(DbPathSpectreUserSite { + user_sites: DbPathSpectreUserSites { + username: "test".into(), + }, + site: "example.org".into(), + }), + &postcard::to_allocvec(&SpectreSiteConfig::default()).unwrap(), + ) + .await + .unwrap(); + write + .write( + &DbKey::new(DbPathSpectreUserSite { + user_sites: DbPathSpectreUserSites { + username: "test".into(), + }, + site: "sub.example.org".into(), + }), + &postcard::to_allocvec(&SpectreSiteConfig::default()).unwrap(), + ) + .await + .unwrap(); write .write( &DbKey::new(DbPathSpectreUsers), @@ -155,19 +197,42 @@ pub async fn run_renderer_task(backend: SlintBackend, flash_part_acid: Partition let read_value = { let read = db.read_transaction().await; // TODO: https://github.com/embassy-rs/ekv/issues/20 - let mut buffer = Vec::new(); - let length = read - .read(&DbKey::new(DbPathSpectreUsers), &mut buffer) + let mut buffer = vec![0; 256]; + let slice = read + .read_to_vec(&DbKey::new(DbPathSpectreUsers), &mut buffer) .await .unwrap(); - buffer.resize(length, 0); - read.read(&DbKey::new(DbPathSpectreUsers), &mut buffer) + let read_value = postcard::from_bytes::(&slice).unwrap(); + + let key_sites = DbKey::new(DbPathSpectreUserSites { + username: "test".into(), + }); + let mut key_buffer = [0_u8; ekv::config::MAX_KEY_SIZE]; + let mut cursor = read + .read_range(key_sites.range_of_children()) .await .unwrap(); - postcard::from_bytes::(&buffer).unwrap() + while let Some((key_len, value_len)) = + cursor.next(&mut key_buffer, &mut buffer).await.unwrap() + { + let key = DbKey::from_raw(key_buffer[..key_len].into()); + let mut key_segments = key.segments(); + let value = &buffer[..value_len]; + let site_config = postcard::from_bytes::(&value).unwrap(); + let site = SpectreSite { + config: site_config, + username: key_segments.nth(2).unwrap().into(), + site_name: key_segments.nth(1).unwrap().into(), + }; + + info!("site = {:#?}", site); + } + + read_value }; + info!("read_value = {:#?}", read_value); assert_eq!(value, read_value, "values do not match"); // TODO: