firmware for my Touchscreen E-Paper Input Module for Framework Laptop 16
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

eepy: add tickv and overhaul intercore communication

+761 -202
+3 -1
Cargo.toml
··· 40 40 serialport = "4.7" 41 41 tar = "0.4" 42 42 zstd = "0.13" 43 - strum = { version = "0.26", default-features = false, features = ["derive"] } 43 + strum = { version = "0.26", default-features = false, features = ["derive"] } 44 + tickv = "2.0" 45 + siphasher = "1.0"
+30 -12
eepy-example-app/src/main.rs
··· 15 15 use eepy_gui::element::button::Button; 16 16 use eepy_gui::element::{Gui, DEFAULT_TEXT_STYLE}; 17 17 use eepy_sys::header::ProgramSlotHeader; 18 - use eepy_sys::image::RefreshBlockMode; 19 18 use eepy_sys::input::{has_event, next_event, set_touch_enabled}; 19 + use eepy_sys::kv_store; 20 20 21 21 #[link_section = ".header"] 22 22 #[used] 23 23 static HEADER: ProgramSlotHeader = ProgramSlotHeader::partial( 24 24 "ExampleApp", 25 25 env!("CARGO_PKG_VERSION"), 26 - entry, 26 + main, 27 27 ); 28 28 29 - #[no_mangle] 30 - pub extern "C" fn entry() { 29 + fn load_counter() -> u32 { 30 + let mut buf = [0u8; size_of::<i32>()]; 31 + match kv_store::get(b"counter", &mut buf) { 32 + Ok(_) => u32::from_ne_bytes(buf), 33 + Err(_) => 0, 34 + } 35 + } 36 + 37 + fn save_counter(counter: u32) { 38 + let _ = kv_store::put(b"counter", &counter.to_ne_bytes()); 39 + } 40 + 41 + fn render_counter(draw_target: &mut EpdDrawTarget, counter: u32) { 42 + let mut s = String::<16>::new(); 43 + write!(s, "{counter}").unwrap(); 44 + Text::new(&s, Point::new(10, 80), DEFAULT_TEXT_STYLE) 45 + .draw(draw_target) 46 + .unwrap(); 47 + } 48 + 49 + extern "C" fn main() { 31 50 set_touch_enabled(true); 32 51 33 52 let mut draw_target = EpdDrawTarget::default(); ··· 36 55 let mut button = Button::with_default_style_auto_sized(Point::new(10, 40), "Click me", true); 37 56 let mut exit_button = Button::with_default_style_auto_sized(Point::new(10, 386), "Exit", false); 38 57 58 + let mut counter = load_counter(); 59 + 39 60 text.draw(&mut draw_target).unwrap(); 40 61 button.draw_init(&mut draw_target); 41 62 exit_button.draw_init(&mut draw_target); 42 - draw_target.refresh(false, RefreshBlockMode::BlockAcknowledge); 63 + render_counter(&mut draw_target, counter); 64 + draw_target.refresh(false); 43 65 44 - let mut counter = 0; 45 66 46 67 loop { 47 68 while let Some(ev) = next_event() { 48 69 if exit_button.tick(&mut draw_target, ev).clicked { 70 + save_counter(counter); 49 71 return; 50 72 } 51 73 ··· 59 81 exit_button.draw_init(&mut draw_target); 60 82 61 83 counter += 1; 62 - let mut s = String::<16>::new(); 63 - write!(s, "{counter}").unwrap(); 64 - Text::new(&s, Point::new(10, 80), DEFAULT_TEXT_STYLE) 65 - .draw(&mut draw_target) 66 - .unwrap(); 84 + render_counter(&mut draw_target, counter); 67 85 needs_refresh = true; 68 86 } 69 87 needs_refresh |= response.needs_refresh; 70 88 71 89 if needs_refresh { 72 - draw_target.refresh(true, RefreshBlockMode::NonBlocking); 90 + draw_target.maybe_refresh(true); 73 91 } 74 92 } 75 93
+7 -4
eepy-gui/src/draw_target.rs
··· 4 4 use embedded_graphics::Pixel; 5 5 use embedded_graphics::pixelcolor::BinaryColor; 6 6 use embedded_graphics::primitives::Rectangle; 7 - use eepy_sys::image::{refresh, write_image, RefreshBlockMode}; 7 + use eepy_sys::image::{maybe_refresh, refresh}; 8 8 use tp370pgh01::{DIM_X, DIM_Y, IMAGE_BYTES}; 9 9 10 10 pub struct EpdDrawTarget { ··· 62 62 } 63 63 64 64 impl EpdDrawTarget { 65 - pub fn refresh(&self, fast_refresh: bool, block_mode: RefreshBlockMode) { 66 - write_image(&self.framebuffer); 67 - refresh(fast_refresh, block_mode); 65 + pub fn refresh(&self, fast_refresh: bool) { 66 + refresh(&self.framebuffer, fast_refresh); 67 + } 68 + 69 + pub fn maybe_refresh(&self, fast_refresh: bool) { 70 + maybe_refresh(&self.framebuffer, fast_refresh); 68 71 } 69 72 }
+21 -28
eepy-launcher/src/main.rs
··· 17 17 use eepy_gui::element::Gui; 18 18 use eepy_gui::element::slider::Slider; 19 19 use eepy_sys::exec::exec; 20 - use eepy_sys::image::RefreshBlockMode; 21 20 use eepy_sys::input::{has_event, next_event, set_touch_enabled}; 22 21 use eepy_sys::input_common::{Event, TouchEventType}; 23 22 use eepy_sys::header::{ProgramSlotHeader, Programs}; ··· 33 32 static HEADER: ProgramSlotHeader = ProgramSlotHeader::partial( 34 33 "Launcher", 35 34 env!("CARGO_PKG_VERSION"), 36 - entry, 35 + main, 37 36 ); 38 37 39 38 #[derive(Copy, Clone, Debug, Eq, PartialEq)] ··· 98 97 if s.clicked { 99 98 return Some(Page::ScratchpadPage); 100 99 } else if s.needs_refresh { 101 - draw_target.refresh(true, RefreshBlockMode::BlockAcknowledge); 100 + draw_target.refresh(true); 102 101 } 103 102 104 103 for b in &mut self.app_buttons { ··· 115 114 } 116 115 117 116 if needs_refresh { 118 - draw_target.refresh(true, RefreshBlockMode::NonBlocking); 117 + draw_target.refresh(true); 119 118 } 120 119 121 120 None ··· 171 170 } 172 171 173 172 fn tick(&mut self, draw_target: &mut EpdDrawTarget, ev: Event) -> Self::Output { 174 - let mut refresh: Option<RefreshBlockMode> = None; 173 + let mut refresh = false; 174 + let mut maybe_refresh = false; 175 175 let mut handle_drawing: bool = true; 176 176 177 177 let e = self.exit_button.tick(draw_target, ev); 178 178 if e.clicked { 179 179 return Some(Page::MainPage); 180 180 } 181 - if e.needs_refresh { 182 - refresh = Some(RefreshBlockMode::BlockAcknowledge); 183 - } 181 + refresh |= e.needs_refresh; 184 182 185 183 let c = self.clear_button.tick(draw_target, ev); 186 184 if c.clicked { 187 185 draw_target.clear(BinaryColor::Off).unwrap(); 188 186 self.draw_init(draw_target); 189 - draw_target.refresh(false, RefreshBlockMode::BlockAcknowledge); 187 + draw_target.refresh(false); 190 188 return None; 191 189 } 192 - if c.needs_refresh { 193 - refresh = Some(RefreshBlockMode::BlockAcknowledge); 194 - } 190 + refresh |= c.needs_refresh; 195 191 196 192 let t = self.toggle_button.tick(draw_target, ev); 197 193 if t.clicked { 198 194 self.eraser = !self.eraser; 199 195 self.toggle_button.label = if self.eraser { "Pen" } else { "Eraser" }; 200 - refresh = Some(RefreshBlockMode::NonBlocking); 201 196 } 202 - if t.needs_refresh { 203 - refresh = Some(RefreshBlockMode::BlockAcknowledge); 204 - } 197 + maybe_refresh |= t.clicked; 198 + refresh |= t.needs_refresh; 205 199 206 200 if self.slider.tick(draw_target, ev) { 207 - refresh = Some(RefreshBlockMode::NonBlocking); 201 + maybe_refresh = true; 208 202 handle_drawing = false; 209 203 } 210 204 ··· 229 223 230 224 self.draw_init(draw_target); 231 225 232 - if refresh.is_none() { 233 - refresh = Some(RefreshBlockMode::NonBlocking); 234 - } 226 + maybe_refresh = true; 235 227 } 236 228 } 237 229 ··· 240 232 } 241 233 } 242 234 243 - if let Some(mode) = refresh { 244 - draw_target.refresh(true, mode); 235 + if refresh { 236 + draw_target.refresh(true); 237 + } else if maybe_refresh { 238 + draw_target.maybe_refresh(true); 245 239 } 246 240 247 241 None ··· 290 284 self.current_page = page; 291 285 draw_target.clear(BinaryColor::Off).unwrap(); 292 286 self.draw_init(draw_target); 293 - draw_target.refresh(false, RefreshBlockMode::BlockAcknowledge); 287 + draw_target.refresh(false); 294 288 } 295 289 } 296 290 } ··· 308 302 } 309 303 } 310 304 311 - #[no_mangle] 312 - pub extern "C" fn entry() { 305 + extern "C" fn main() { 313 306 #[allow(static_mut_refs)] 314 307 unsafe { 315 308 let bus = UsbBusAllocator::new(UsbBus::init()); ··· 337 330 set_touch_enabled(true); 338 331 let mut gui = MainGui::new(); 339 332 gui.draw_init(&mut draw_target); 340 - draw_target.refresh(false, RefreshBlockMode::BlockAcknowledge); 333 + draw_target.refresh(false); 341 334 342 335 loop { 343 336 if !HOST_APP.load(Ordering::Relaxed) { ··· 349 342 gui.main_page.refresh_buttons(); 350 343 if gui.current_page == Page::MainPage { 351 344 gui.draw_init(&mut draw_target); 352 - draw_target.refresh(false, RefreshBlockMode::BlockAcknowledge); 345 + draw_target.refresh(false); 353 346 } 354 347 } else if NEEDS_REFRESH.swap(false, Ordering::Relaxed) { 355 348 gui.draw_init(&mut draw_target); 356 - draw_target.refresh(false, RefreshBlockMode::BlockAcknowledge); 349 + draw_target.refresh(false); 357 350 } else if !has_event() { 358 351 // has_event() is a syscall. The SVCall exception is a WFE wakeup event, so we need two 359 352 // WFEs so we don't immediately wake up.
+3 -5
eepy-launcher/src/serial.rs
··· 5 5 use usbd_serial::SerialPort; 6 6 use eepy_serial::{Response, SerialCommand}; 7 7 use eepy_sys::flash::erase_and_program; 8 - use eepy_sys::image::{refresh, write_image, RefreshBlockMode}; 8 + use eepy_sys::image::refresh; 9 9 use eepy_sys::IMAGE_BYTES; 10 10 use eepy_sys::input::{next_event, set_touch_enabled}; 11 11 use eepy_sys::misc::{debug, info, trace}; ··· 119 119 }, 120 120 Ok(SerialCommand::EnterHostApp) => { 121 121 HOST_APP.store(true, Ordering::Relaxed); 122 - write_image(&[0u8; IMAGE_BYTES]); 123 - refresh(false, RefreshBlockMode::NonBlocking); 122 + refresh(&[0u8; IMAGE_BYTES], false); 124 123 set_touch_enabled(false); 125 124 write_all(serial, &[Response::Ack as u8]); 126 125 }, ··· 142 141 if let Ok(count) = serial.read(&mut buf[*index..]) { 143 142 *index += count; 144 143 if *index == IMAGE_BYTES { 145 - write_image(buf); 146 - refresh(*fast_refresh, RefreshBlockMode::NonBlocking); 144 + refresh(buf, *fast_refresh); 147 145 write_all(serial, &[Response::Ack as u8]); 148 146 *state = SerialState::ReadyForCommand; 149 147 }
+1
eepy-sys/Cargo.toml
··· 13 13 critical-section = { workspace = true, optional = true } 14 14 once_cell = { workspace = true, optional = true } 15 15 strum.workspace = true 16 + tickv = { workspace = true, optional = true } 16 17 17 18 [features] 18 19 defmt = ["dep:defmt", "usb-device/defmt"]
+8 -16
eepy-sys/src/image.rs
··· 6 6 #[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] 7 7 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 8 8 pub enum ImageSyscall { 9 - WriteImage = 0, 10 - Refresh = 1, 11 - } 12 - 13 - #[repr(usize)] 14 - #[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] 15 - #[cfg_attr(feature = "defmt", derive(defmt::Format))] 16 - pub enum RefreshBlockMode { 17 - NonBlocking = 0, 18 - BlockAcknowledge = 1, 19 - BlockFinish = 2, 9 + Refresh = 0, 10 + MaybeRefresh = 1, 20 11 } 21 12 22 - pub fn write_image(image: &[u8; IMAGE_BYTES]) { 13 + pub fn refresh(image: &[u8; IMAGE_BYTES], fast_refresh: bool) { 23 14 unsafe { 24 15 syscall!( 25 16 SyscallNumber::Image, 26 - in ImageSyscall::WriteImage, 17 + in ImageSyscall::Refresh, 18 + in fast_refresh, 27 19 in &raw const *image, 28 20 ); 29 21 } 30 22 } 31 23 32 - pub fn refresh(fast_refresh: bool, refresh_block_mode: RefreshBlockMode) { 24 + pub fn maybe_refresh(image: &[u8; IMAGE_BYTES], fast_refresh: bool) { 33 25 unsafe { 34 26 syscall!( 35 27 SyscallNumber::Image, 36 - in ImageSyscall::Refresh, 28 + in ImageSyscall::MaybeRefresh, 37 29 in fast_refresh, 38 - in refresh_block_mode, 30 + in &raw const *image, 39 31 ); 40 32 } 41 33 }
+223
eepy-sys/src/kv_store.rs
··· 1 + use core::mem::MaybeUninit; 2 + use crate::{syscall, SafeResult}; 3 + use crate::syscall::SyscallNumber; 4 + 5 + #[repr(usize)] 6 + #[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] 7 + #[cfg_attr(feature = "defmt", derive(defmt::Format))] 8 + pub enum KvStoreSyscall { 9 + ReadKey = 0, 10 + AppendKey = 1, 11 + PutKey = 2, 12 + InvalidateKey = 3, 13 + ZeroiseKey = 4, 14 + } 15 + 16 + #[repr(C)] 17 + pub struct ReadKeyArgs { 18 + pub key_len: usize, 19 + pub key_ptr: *const u8, 20 + pub buf_len: usize, 21 + pub buf_ptr: *mut u8, 22 + } 23 + 24 + #[repr(C)] 25 + pub struct WriteKeyArgs { 26 + pub key_len: usize, 27 + pub key_ptr: *const u8, 28 + pub value_len: usize, 29 + pub value_ptr: *const u8, 30 + } 31 + 32 + #[repr(usize)] 33 + #[derive(Copy, Clone, Debug, Eq, PartialEq)] 34 + pub enum ReadKeyError { 35 + FlashCorrupt, 36 + InvalidChecksum, 37 + NotFound, 38 + BufferTooSmall(usize), 39 + } 40 + 41 + #[cfg(feature = "tickv")] 42 + impl TryFrom<tickv::ErrorCode> for ReadKeyError { 43 + type Error = tickv::ErrorCode; 44 + 45 + fn try_from(value: tickv::ErrorCode) -> Result<Self, Self::Error> { 46 + use tickv::ErrorCode as E; 47 + 48 + match value { 49 + E::CorruptData => Ok(Self::FlashCorrupt), 50 + E::InvalidCheckSum => Ok(Self::InvalidChecksum), 51 + E::KeyNotFound => Ok(Self::NotFound), 52 + E::BufferTooSmall(size) => Ok(Self::BufferTooSmall(size)), 53 + _ => Err(value), 54 + } 55 + } 56 + } 57 + 58 + #[repr(usize)] 59 + #[derive(Copy, Clone, Debug, Eq, PartialEq)] 60 + pub enum AppendKeyError { 61 + FlashCorrupt, 62 + AlreadyExists, 63 + RegionFull, 64 + FlashFull, 65 + } 66 + 67 + #[cfg(feature = "tickv")] 68 + impl TryFrom<tickv::ErrorCode> for AppendKeyError { 69 + type Error = tickv::ErrorCode; 70 + 71 + fn try_from(value: tickv::ErrorCode) -> Result<Self, Self::Error> { 72 + use tickv::ErrorCode as E; 73 + 74 + match value { 75 + E::CorruptData => Ok(Self::FlashCorrupt), 76 + E::KeyAlreadyExists => Ok(Self::AlreadyExists), 77 + E::RegionFull => Ok(Self::RegionFull), 78 + E::FlashFull => Ok(Self::FlashFull), 79 + _ => Err(value), 80 + } 81 + } 82 + } 83 + 84 + #[repr(usize)] 85 + #[derive(Copy, Clone, Debug, Eq, PartialEq)] 86 + pub enum PutKeyError { 87 + FlashCorrupt, 88 + RegionFull, 89 + FlashFull, 90 + } 91 + 92 + #[cfg(feature = "tickv")] 93 + impl TryFrom<tickv::ErrorCode> for PutKeyError { 94 + type Error = tickv::ErrorCode; 95 + 96 + fn try_from(value: tickv::ErrorCode) -> Result<Self, Self::Error> { 97 + use tickv::ErrorCode as E; 98 + 99 + match value { 100 + E::CorruptData => Ok(Self::FlashCorrupt), 101 + E::RegionFull => Ok(Self::RegionFull), 102 + E::FlashFull => Ok(Self::FlashFull), 103 + _ => Err(value), 104 + } 105 + } 106 + } 107 + 108 + #[repr(usize)] 109 + #[derive(Copy, Clone, Debug, Eq, PartialEq)] 110 + pub enum DeleteKeyError { 111 + FlashCorrupt, 112 + NotFound, 113 + } 114 + 115 + #[cfg(feature = "tickv")] 116 + impl TryFrom<tickv::ErrorCode> for DeleteKeyError { 117 + type Error = tickv::ErrorCode; 118 + 119 + fn try_from(value: tickv::ErrorCode) -> Result<Self, Self::Error> { 120 + use tickv::ErrorCode as E; 121 + 122 + match value { 123 + E::CorruptData => Ok(Self::FlashCorrupt), 124 + E::KeyNotFound => Ok(Self::NotFound), 125 + _ => Err(value), 126 + } 127 + } 128 + } 129 + 130 + pub fn get(key: &[u8], buf: &mut [u8]) -> Result<usize, ReadKeyError> { 131 + let args = ReadKeyArgs { 132 + key_len: key.len(), 133 + key_ptr: key.as_ptr(), 134 + buf_len: buf.len(), 135 + buf_ptr: buf.as_mut_ptr(), 136 + }; 137 + let mut res: MaybeUninit<SafeResult<usize, ReadKeyError>> = MaybeUninit::uninit(); 138 + 139 + unsafe { 140 + syscall!( 141 + SyscallNumber::KvStore, 142 + in KvStoreSyscall::ReadKey, 143 + in &raw const args, 144 + in res.as_mut_ptr(), 145 + ); 146 + 147 + res.assume_init().into() 148 + } 149 + } 150 + 151 + pub fn append(key: &[u8], value: &[u8]) -> Result<(), AppendKeyError> { 152 + let args = WriteKeyArgs { 153 + key_len: key.len(), 154 + key_ptr: key.as_ptr(), 155 + value_len: value.len(), 156 + value_ptr: value.as_ptr(), 157 + }; 158 + let mut res: MaybeUninit<SafeResult<(), AppendKeyError>> = MaybeUninit::uninit(); 159 + 160 + unsafe { 161 + syscall!( 162 + SyscallNumber::KvStore, 163 + in KvStoreSyscall::AppendKey, 164 + in &raw const args, 165 + in res.as_mut_ptr(), 166 + ); 167 + 168 + res.assume_init().into() 169 + } 170 + } 171 + 172 + pub fn put(key: &[u8], value: &[u8]) -> Result<(), PutKeyError> { 173 + let args = WriteKeyArgs { 174 + key_len: key.len(), 175 + key_ptr: key.as_ptr(), 176 + value_len: value.len(), 177 + value_ptr: value.as_ptr(), 178 + }; 179 + let mut res: MaybeUninit<SafeResult<(), PutKeyError>> = MaybeUninit::uninit(); 180 + 181 + unsafe { 182 + syscall!( 183 + SyscallNumber::KvStore, 184 + in KvStoreSyscall::PutKey, 185 + in &raw const args, 186 + in res.as_mut_ptr(), 187 + ); 188 + 189 + res.assume_init().into() 190 + } 191 + } 192 + 193 + pub fn invalidate(key: &[u8]) -> Result<(), DeleteKeyError> { 194 + let mut res: MaybeUninit<SafeResult<(), DeleteKeyError>> = MaybeUninit::uninit(); 195 + 196 + unsafe { 197 + syscall!( 198 + SyscallNumber::KvStore, 199 + in KvStoreSyscall::InvalidateKey, 200 + in key.as_ptr(), 201 + in key.len(), 202 + in res.as_mut_ptr(), 203 + ); 204 + 205 + res.assume_init().into() 206 + } 207 + } 208 + 209 + pub fn zeroise(key: &[u8]) -> Result<(), DeleteKeyError> { 210 + let mut res: MaybeUninit<SafeResult<(), DeleteKeyError>> = MaybeUninit::uninit(); 211 + 212 + unsafe { 213 + syscall!( 214 + SyscallNumber::KvStore, 215 + in KvStoreSyscall::ZeroiseKey, 216 + in key.as_ptr(), 217 + in key.len(), 218 + in res.as_mut_ptr(), 219 + ); 220 + 221 + res.assume_init().into() 222 + } 223 + }
+3
eepy-sys/src/lib.rs
··· 18 18 pub mod critical_section; 19 19 #[cfg(all(target_os = "none", target_arch = "arm"))] 20 20 pub mod flash; 21 + #[cfg(all(target_os = "none", target_arch = "arm"))] 22 + pub mod kv_store; 23 + 21 24 pub mod input_common; 22 25 23 26
+1
eepy-sys/src/syscall.rs
··· 9 9 Exec = 4, 10 10 CriticalSection = 5, 11 11 Flash = 6, 12 + KvStore = 7, 12 13 } 13 14 14 15 /// Perform a raw system call.
eepy/.gdbinit eepy/core0.gdbinit
+5 -2
eepy/Cargo.toml
··· 5 5 6 6 [dependencies] 7 7 fw16-epd-bsp = { path = "../fw16-epd-bsp", features = ["defmt"] } 8 - eepy-sys = { path = "../eepy-sys", features = ["defmt"] } 8 + eepy-sys = { path = "../eepy-sys", features = ["defmt", "tickv"] } 9 9 tp370pgh01 = { path = "../tp370pgh01", features = ["rp2040", "defmt"] } 10 10 cortex-m.workspace = true 11 11 cortex-m-rt.workspace = true ··· 18 18 portable-atomic.workspace = true 19 19 usb-device = { workspace = true, features = ["defmt"] } 20 20 once_cell.workspace = true 21 - mcp9808.workspace = true 21 + mcp9808.workspace = true 22 + tickv.workspace = true 23 + siphasher.workspace = true 24 + strum.workspace = true
+5
eepy/core1.gdbinit
··· 1 + target extended-remote :3334 2 + 3 + define mri 4 + monitor reset init 5 + end
+130
eepy/src/core1.rs
··· 1 + use core::cell::RefCell; 2 + use core::sync::atomic::{AtomicBool, Ordering}; 3 + use critical_section::Mutex; 4 + use defmt::{trace, warn}; 5 + use eepy_sys::input_common::Event; 6 + use fw16_epd_bsp::hal::gpio::bank0::Gpio11; 7 + use fw16_epd_bsp::hal::gpio::{FunctionSioOutput, PullNone}; 8 + use fw16_epd_bsp::hal::{Sio, Timer}; 9 + use fw16_epd_bsp::{pac, EpdBusy, EpdCs, EpdDc, EpdReset, EpdSck}; 10 + use fw16_epd_bsp::hal::sio::SioFifo; 11 + use fw16_epd_bsp::pac::interrupt; 12 + use tp370pgh01::{Tp370pgh01, IMAGE_BYTES}; 13 + use tp370pgh01::rp2040::{IoPin, Rp2040PervasiveSpiDelays}; 14 + use crate::{EVENT_QUEUE, IMAGE_BUFFER, TEMP}; 15 + 16 + type SdaIo = IoPin<Gpio11, FunctionSioOutput, PullNone>; 17 + type Epd = Tp370pgh01<EpdCs, SdaIo, EpdSck, EpdDc, EpdBusy, EpdReset, Timer, Rp2040PervasiveSpiDelays>; 18 + 19 + pub(crate) static GLOBAL_EPD: Mutex<RefCell<Option<Epd>>> = Mutex::new(RefCell::new(None)); 20 + 21 + pub(crate) static IDLE: AtomicBool = AtomicBool::new(true); 22 + 23 + /// Function in RAM to be executed by core1 whilst flashing programs (core1 cannot be executing code 24 + /// from flash whilst writing/erasing flash) 25 + #[link_section = ".data.ram_func"] 26 + fn core1_flash_wait(fifo: &mut SioFifo) { 27 + cortex_m::interrupt::free(|_cs| { 28 + fifo.write_blocking(ToCore0Message::FlashAck as u32); 29 + trace!("core1 waiting for flash operation"); 30 + 31 + while fifo.read_blocking() != ToCore1Message::FlashFinished as u32 { 32 + warn!("Received message other than FlashFinished while in flashing state"); 33 + } 34 + }); 35 + } 36 + 37 + pub(crate) fn core1_main() { 38 + unsafe { 39 + pac::NVIC::unmask(interrupt::SIO_IRQ_PROC1); 40 + } 41 + 42 + loop { 43 + cortex_m::asm::wfi(); 44 + } 45 + } 46 + 47 + #[repr(u32)] 48 + #[derive(Copy, Clone, Debug, Eq, PartialEq, defmt::Format, strum::FromRepr)] 49 + pub(crate) enum ToCore1Message { 50 + FlashWait, 51 + FlashFinished, 52 + HardResetEpd, 53 + RefreshNormal, 54 + MaybeRefreshNormal, 55 + RefreshFast, 56 + MaybeRefreshFast, 57 + } 58 + 59 + #[repr(u32)] 60 + #[derive(Copy, Clone, Debug, Eq, PartialEq, defmt::Format, strum::FromRepr)] 61 + pub(crate) enum ToCore0Message { 62 + FlashAck, 63 + RefreshAck, 64 + } 65 + 66 + fn refresh(fast: bool, image: &mut [u8; IMAGE_BYTES], prev_image: &mut [u8; IMAGE_BYTES], epd: &mut Epd) { 67 + if fast { 68 + prev_image.copy_from_slice(image); 69 + critical_section::with(|cs| image.copy_from_slice(IMAGE_BUFFER.borrow_ref(cs).as_ref())); 70 + epd.soft_reset().unwrap(); 71 + epd.refresh_fast(image, prev_image, TEMP.load(Ordering::Relaxed)).unwrap(); 72 + } else { 73 + critical_section::with(|cs| image.copy_from_slice(IMAGE_BUFFER.borrow_ref(cs).as_ref())); 74 + epd.soft_reset().unwrap(); 75 + epd.refresh(image, TEMP.load(Ordering::Relaxed)).unwrap(); 76 + } 77 + 78 + critical_section::with(|cs| EVENT_QUEUE.borrow_ref_mut(cs).push(Event::RefreshFinished)); 79 + cortex_m::asm::sev(); 80 + } 81 + 82 + #[interrupt] 83 + fn SIO_IRQ_PROC1() { 84 + static mut EPD: Option<Epd> = None; 85 + static mut IMAGE: [u8; IMAGE_BYTES] = [0u8; IMAGE_BYTES]; 86 + static mut PREV_IMAGE: [u8; IMAGE_BYTES] = [0u8; IMAGE_BYTES]; 87 + 88 + trace!("SIO_IRQ_PROC1"); 89 + 90 + IDLE.store(false, Ordering::Relaxed); 91 + 92 + if EPD.is_none() { 93 + critical_section::with(|cs| *EPD = GLOBAL_EPD.borrow(cs).take()); 94 + } 95 + let epd = EPD.as_mut().unwrap(); 96 + 97 + let sio = unsafe { pac::Peripherals::steal() }.SIO; 98 + unsafe { sio.fifo_st().write_with_zero(|x| x) }; 99 + let mut fifo = Sio::new(sio).fifo; 100 + 101 + while let Some(val) = fifo.read() { 102 + let message = ToCore1Message::from_repr(val); 103 + match message { 104 + Some(ToCore1Message::FlashWait) => core1_flash_wait(&mut fifo), 105 + Some(ToCore1Message::FlashFinished) => warn!("Received FlashFinished but wasn't in flashing state"), 106 + Some(ToCore1Message::HardResetEpd) => epd.hard_reset().unwrap(), 107 + Some(ToCore1Message::RefreshNormal) => { 108 + fifo.write_blocking(ToCore0Message::RefreshAck as u32); 109 + refresh(false, IMAGE, PREV_IMAGE, epd); 110 + }, 111 + Some(ToCore1Message::MaybeRefreshNormal) => { 112 + if !fifo.is_read_ready() { 113 + refresh(false, IMAGE, PREV_IMAGE, epd); 114 + } 115 + }, 116 + Some(ToCore1Message::RefreshFast) => { 117 + fifo.write_blocking(ToCore0Message::RefreshAck as u32); 118 + refresh(true, IMAGE, PREV_IMAGE, epd); 119 + }, 120 + Some(ToCore1Message::MaybeRefreshFast) => { 121 + if !fifo.is_read_ready() { 122 + refresh(true, IMAGE, PREV_IMAGE, epd); 123 + } 124 + }, 125 + None => warn!("core1 received unknown FIFO message {}", val), 126 + } 127 + } 128 + 129 + IDLE.store(true, Ordering::Relaxed); 130 + }
+56
eepy/src/flash.rs
··· 1 + use defmt::{trace, warn}; 2 + use eepy_sys::header::XIP_BASE; 3 + use fw16_epd_bsp::hal::Sio; 4 + use fw16_epd_bsp::pac; 5 + use crate::core1::{ToCore0Message, ToCore1Message}; 6 + 7 + fn flash_op(f: impl FnOnce()) { 8 + let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 9 + 10 + fifo.write_blocking(ToCore1Message::FlashWait as u32); 11 + // Wait until core1 has acknowledged that it is now in RAM code 12 + while fifo.read_blocking() != ToCore0Message::FlashAck as u32 { 13 + warn!("received incorrect message"); 14 + } 15 + 16 + trace!("core1 is in safe state, performing flash operation..."); 17 + cortex_m::interrupt::free(|_cs| f()); 18 + 19 + // Wake up core1 20 + fifo.write_blocking(ToCore1Message::FlashFinished as u32); 21 + } 22 + 23 + fn flush_cache_range(start_addr: u32, len: u32) { 24 + // RP2040 Datasheet 2.6.3.2: 25 + // "A write to the 0x10… mirror will look up the addressed location in the cache, and delete 26 + // any matching entry found. Writing to all word-aligned locations in an address range (e.g. 27 + // a flash sector that has just been erased and reprogrammed) therefore eliminates the 28 + // possibility of stale cached data in this range, without suffering the effects of a 29 + // complete cache flush." 30 + 31 + unsafe { 32 + let start_ptr: *mut u32 = XIP_BASE.add(start_addr as usize).cast_mut().cast(); 33 + let words = len / 4; 34 + for _ in 0..words { 35 + start_ptr.add(words as usize).write_volatile(0); 36 + } 37 + } 38 + } 39 + 40 + pub(crate) unsafe fn erase(start_addr: u32, len: u32) { 41 + trace!("flash erasing start {} len {}", start_addr, len); 42 + flash_op(|| rp2040_flash::flash::flash_range_erase(start_addr, len, true)); 43 + flush_cache_range(start_addr, len); 44 + } 45 + 46 + pub(crate) unsafe fn program(start_addr: u32, data: &[u8]) { 47 + trace!("flash programming start {} len {}", start_addr, data.len()); 48 + flash_op(|| rp2040_flash::flash::flash_range_program(start_addr, data, true)); 49 + flush_cache_range(start_addr, data.len() as u32); 50 + } 51 + 52 + pub(crate) unsafe fn erase_and_program(start_addr: u32, data: &[u8]) { 53 + trace!("flash programming and erasing start {} len {}", start_addr, data.len()); 54 + flash_op(|| rp2040_flash::flash::flash_range_erase_and_program(start_addr, data, true)); 55 + flush_cache_range(start_addr, data.len() as u32); 56 + }
+11 -67
eepy/src/main.rs
··· 7 7 mod launcher; 8 8 mod usb; 9 9 mod exception; 10 + mod tickv; 11 + mod flash; 12 + mod core1; 10 13 11 14 extern crate panic_probe; 12 15 extern crate defmt_rtt; ··· 38 41 use eepy_sys::input_common::{Event, TouchEvent, TouchEventType}; 39 42 use tp370pgh01::rp2040::{Rp2040PervasiveSpiDelays, IoPin}; 40 43 use tp370pgh01::{Tp370pgh01, IMAGE_BYTES}; 44 + use crate::core1::{core1_main, ToCore1Message, GLOBAL_EPD, IDLE}; 41 45 use crate::ringbuffer::RingBuffer; 42 46 43 47 const SRAM_END: *mut u8 = 0x20042000 as *mut u8; ··· 53 57 static GLOBAL_ALARM0: Mutex<RefCell<Option<Alarm0>>> = Mutex::new(RefCell::new(None)); 54 58 55 59 static IMAGE_BUFFER: Mutex<RefCell<[u8; IMAGE_BYTES]>> = Mutex::new(RefCell::new([0; IMAGE_BYTES])); 56 - static DO_REFRESH: AtomicBool = AtomicBool::new(false); 57 - static FAST_REFRESH: AtomicBool = AtomicBool::new(false); 58 - static REFRESHING: AtomicBool = AtomicBool::new(false); 59 - static EPD_NEEDS_HARD_RESET: AtomicBool = AtomicBool::new(true); 60 60 static TEMP: AtomicU8 = AtomicU8::new(20); 61 61 static SERIAL_NUMBER: OnceCell<[u8; 16]> = OnceCell::new(); 62 62 63 63 static EVENT_QUEUE: Mutex<RefCell<RingBuffer<Event>>> = Mutex::new(RefCell::new(RingBuffer::new())); 64 64 static TOUCH_ENABLED: AtomicBool = AtomicBool::new(false); 65 - 66 - static FLASHING: AtomicBool = AtomicBool::new(false); 67 - static FLASHING_ACK: AtomicBool = AtomicBool::new(false); 68 - 69 - /// Function in RAM to be executed by core1 whilst flashing programs (core1 cannot be executing code 70 - /// from flash whilst writing/erasing flash) 71 - /// 72 - /// To exit this function from core0, set [FLASHING] to false and SEV 73 - #[link_section = ".data.ram_func"] 74 - fn core1_flash_wait() { 75 - cortex_m::interrupt::disable(); 76 - FLASHING_ACK.store(true, Ordering::Relaxed); 77 - 78 - while FLASHING.load(Ordering::Relaxed) { 79 - cortex_m::asm::wfe(); 80 - } 81 - 82 - FLASHING_ACK.store(false, Ordering::Relaxed); 83 - unsafe { cortex_m::interrupt::enable() }; 84 - } 85 65 86 66 #[entry] 87 67 fn main() -> ! { ··· 247 227 core.NVIC.set_priority(interrupt::USBCTRL_IRQ, 0b11000000); 248 228 } 249 229 230 + let epd = Tp370pgh01::new(cs, IoPin::new(sda), sck, dc, busy, rst, timer, Rp2040PervasiveSpiDelays); 231 + critical_section::with(|cs| GLOBAL_EPD.borrow_ref_mut(cs).replace(epd)); 250 232 let mut mc = Multicore::new(&mut pac.PSM, &mut pac.PPB, &mut sio.fifo); 251 233 let core1 = &mut mc.cores()[1]; 252 - core1.spawn(CORE1_STACK.take().unwrap(), move || { 253 - info!("core1 init"); 254 - 255 - let mut epd = Tp370pgh01::new(cs, IoPin::new(sda), sck, dc, busy, rst, timer, Rp2040PervasiveSpiDelays); 256 - 257 - let mut prev_image = [0u8; IMAGE_BYTES]; 258 - let mut image = [0u8; IMAGE_BYTES]; 259 - 260 - loop { 261 - cortex_m::asm::wfe(); 262 - 263 - if FLASHING.load(Ordering::Relaxed) { 264 - core1_flash_wait(); 265 - continue; 266 - } 267 - 268 - if EPD_NEEDS_HARD_RESET.swap(false, Ordering::Relaxed) { 269 - epd.hard_reset().unwrap(); 270 - } 271 - 272 - REFRESHING.store(true, Ordering::Relaxed); 273 - 274 - if DO_REFRESH.swap(false, Ordering::Relaxed) { 275 - if FAST_REFRESH.load(Ordering::Relaxed) { 276 - prev_image.copy_from_slice(&image); 277 - critical_section::with(|cs| image.copy_from_slice(IMAGE_BUFFER.borrow_ref(cs).as_ref())); 278 - epd.soft_reset().unwrap(); 279 - epd.refresh_fast(&image, &prev_image, TEMP.load(Ordering::Relaxed)).unwrap(); 280 - } else { 281 - critical_section::with(|cs| image.copy_from_slice(IMAGE_BUFFER.borrow_ref(cs).as_ref())); 282 - epd.soft_reset().unwrap(); 283 - epd.refresh(&image, TEMP.load(Ordering::Relaxed)).unwrap(); 284 - } 285 - 286 - critical_section::with(|cs| EVENT_QUEUE.borrow_ref_mut(cs).push(Event::RefreshFinished)); 287 - cortex_m::asm::sev(); 288 - } 289 - 290 - REFRESHING.store(false, Ordering::Relaxed); 291 - } 292 - }).unwrap(); 234 + core1.spawn(CORE1_STACK.take().unwrap(), core1_main).unwrap(); 235 + sio.fifo.write_blocking(ToCore1Message::HardResetEpd as u32); 293 236 294 237 unsafe { 295 238 core.NVIC.set_priority(interrupt::IO_IRQ_BANK0, 0); ··· 423 366 } 424 367 425 368 // Wait until refresh has finished 426 - while REFRESHING.load(Ordering::Relaxed) {} 369 + while !IDLE.load(Ordering::Relaxed) {} 427 370 428 371 // Power down temp sensor 429 372 if let Some(i2c) = &mut i2c { ··· 458 401 power_pin.set_low().unwrap(); 459 402 } 460 403 461 - EPD_NEEDS_HARD_RESET.store(true, Ordering::Relaxed); 404 + let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 405 + fifo.write_blocking(ToCore1Message::HardResetEpd as u32); 462 406 463 407 if let Some(reset) = TOUCH_RESET_PIN { 464 408 cortex_m::asm::delay(1000000);
+154 -66
eepy/src/syscall.rs
··· 34 34 Some(SyscallNumber::Exec) => handle_exec(stack_values, using_psp), 35 35 Some(SyscallNumber::CriticalSection) => cs::handle_cs(stack_values), 36 36 Some(SyscallNumber::Flash) => flash::handle_flash(stack_values), 37 + Some(SyscallNumber::KvStore) => kv_store::handle_kv_store(stack_values), 37 38 None => panic!("illegal syscall"), 38 39 } 39 40 } ··· 137 138 } 138 139 139 140 mod image { 140 - use core::sync::atomic::Ordering; 141 - use eepy_sys::image::{ImageSyscall, RefreshBlockMode}; 141 + use eepy_sys::image::ImageSyscall; 142 + use fw16_epd_bsp::hal::Sio; 143 + use fw16_epd_bsp::pac; 142 144 use tp370pgh01::IMAGE_BYTES; 143 - use crate::{DO_REFRESH, FAST_REFRESH, IMAGE_BUFFER, REFRESHING}; 145 + use crate::IMAGE_BUFFER; 146 + use crate::core1::{ToCore0Message, ToCore1Message}; 144 147 use super::StackFrame; 145 148 146 149 pub(super) fn handle_image(stack_values: &mut StackFrame) { 147 150 match ImageSyscall::from_repr(stack_values.r0) { 148 - Some(ImageSyscall::WriteImage) => handle_write_image(stack_values), 149 151 Some(ImageSyscall::Refresh) => handle_refresh(stack_values), 152 + Some(ImageSyscall::MaybeRefresh) => handle_maybe_refresh(stack_values), 150 153 None => panic!("illegal syscall"), 151 154 } 152 155 } 153 156 154 - fn handle_write_image(stack_values: &mut StackFrame) { 155 - let image: &[u8; IMAGE_BYTES] = unsafe { &*(stack_values.r1 as *const [u8; IMAGE_BYTES]) }; 156 - critical_section::with(|cs| IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(image)); 157 - } 158 - 159 157 fn handle_refresh(stack_values: &mut StackFrame) { 160 158 let fast_refresh = stack_values.r1 != 0; 161 - let blocking_mode = RefreshBlockMode::from_repr(stack_values.r2).expect("illegal refresh blocking mode"); 159 + let image: &[u8; IMAGE_BYTES] = unsafe { &*(stack_values.r2 as *const [u8; IMAGE_BYTES]) }; 160 + critical_section::with(|cs| IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(image)); 162 161 163 - DO_REFRESH.store(true, Ordering::Relaxed); 164 - FAST_REFRESH.store(fast_refresh, Ordering::Relaxed); 165 - cortex_m::asm::sev(); 162 + let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 163 + let message = if fast_refresh { ToCore1Message::RefreshFast } else { ToCore1Message::RefreshNormal }; 164 + fifo.write_blocking(message as u32); 166 165 167 - if matches!(blocking_mode, RefreshBlockMode::BlockAcknowledge | RefreshBlockMode::BlockFinish) { 168 - while DO_REFRESH.load(Ordering::Relaxed) {} 166 + if fifo.read_blocking() != ToCore0Message::RefreshAck as u32 { 167 + panic!("received incorrect message"); 169 168 } 169 + } 170 + 171 + fn handle_maybe_refresh(stack_values: &mut StackFrame) { 172 + let fast_refresh = stack_values.r1 != 0; 173 + let image: &[u8; IMAGE_BYTES] = unsafe { &*(stack_values.r2 as *const [u8; IMAGE_BYTES]) }; 174 + critical_section::with(|cs| IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(image)); 170 175 171 - if matches!(blocking_mode, RefreshBlockMode::BlockFinish) { 172 - while REFRESHING.load(Ordering::Relaxed) {} 176 + let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 177 + let message = if fast_refresh { ToCore1Message::MaybeRefreshFast } else { ToCore1Message::MaybeRefreshNormal }; 178 + if fifo.is_write_ready() { 179 + fifo.write(message as u32); 173 180 } 174 181 } 175 182 } ··· 248 255 } 249 256 250 257 mod flash { 251 - use core::sync::atomic::Ordering; 252 258 use eepy_sys::flash::FlashSyscall; 253 259 use eepy_sys::header::{SLOT_SIZE, XIP_BASE}; 254 260 use crate::exception::StackFrame; 255 - use crate::{FLASHING, FLASHING_ACK}; 261 + use crate::flash::{erase, erase_and_program, program}; 256 262 257 263 pub(super) fn handle_flash(stack_values: &mut StackFrame) { 258 264 match FlashSyscall::from_repr(stack_values.r0) { ··· 283 289 } 284 290 } 285 291 286 - fn begin() { 287 - // Make sure core1 is running code from RAM with interrupts disabled 288 - FLASHING.store(true, Ordering::Relaxed); 289 - cortex_m::asm::sev(); 290 - // Wait until core1 has acknowledged that it is now in RAM code 291 - while !FLASHING_ACK.load(Ordering::Relaxed) {} 292 - // Disable interrupts on this core 293 - cortex_m::interrupt::disable(); 294 - } 295 - 296 - fn end() { 297 - // Enable interrupts 298 - unsafe { cortex_m::interrupt::enable() } 299 - // Wake up core1 300 - FLASHING.store(false, Ordering::Relaxed); 301 - cortex_m::asm::sev(); 302 - } 303 - 304 - fn flush_cache_range(start_addr: u32, len: u32) { 305 - // RP2040 Datasheet 2.6.3.2: 306 - // "A write to the 0x10… mirror will look up the addressed location in the cache, and delete 307 - // any matching entry found. Writing to all word-aligned locations in an address range (e.g. 308 - // a flash sector that has just been erased and reprogrammed) therefore eliminates the 309 - // possibility of stale cached data in this range, without suffering the effects of a 310 - // complete cache flush." 311 - 312 - unsafe { 313 - let start_ptr: *mut u32 = XIP_BASE.add(start_addr as usize).cast_mut().cast(); 314 - let words = len / 4; 315 - for _ in 0..words { 316 - start_ptr.add(words as usize).write_volatile(0); 317 - } 318 - } 319 - } 320 - 321 292 fn handle_erase(stack_values: &mut StackFrame) { 322 293 let start_addr = stack_values.r1 as u32; 323 294 let len = stack_values.r2 as u32; ··· 326 297 panic!("unaligned flash erase"); 327 298 } 328 299 329 - begin(); 330 300 unsafe { 331 - rp2040_flash::flash::flash_range_erase(start_addr, len, true); 332 - flush_cache_range(start_addr, len); 301 + erase(start_addr, len); 333 302 } 334 - end(); 335 303 } 336 304 337 305 fn handle_program(stack_values: &mut StackFrame) { ··· 342 310 panic!("unaligned flash program"); 343 311 } 344 312 345 - begin(); 346 313 unsafe { 347 - rp2040_flash::flash::flash_range_program(start_addr, data, true); 348 - flush_cache_range(start_addr, data.len() as u32); 314 + program(start_addr, data); 349 315 } 350 - end(); 351 316 } 352 317 353 318 fn handle_erase_and_program(stack_values: &mut StackFrame) { ··· 358 323 panic!("unaligned flash erase"); 359 324 } 360 325 361 - begin(); 362 326 unsafe { 363 - rp2040_flash::flash::flash_range_erase_and_program(start_addr, data, true); 364 - flush_cache_range(start_addr, data.len() as u32); 327 + erase_and_program(start_addr, data); 365 328 } 366 - end(); 329 + } 330 + } 331 + 332 + mod kv_store { 333 + use core::hash::Hasher; 334 + use siphasher::sip::SipHasher; 335 + use tickv::{ErrorCode, TicKV}; 336 + use eepy_sys::header::{slot, SLOT_SIZE}; 337 + use eepy_sys::kv_store::{AppendKeyError, DeleteKeyError, KvStoreSyscall, PutKeyError, ReadKeyArgs, ReadKeyError, WriteKeyArgs}; 338 + use eepy_sys::SafeResult; 339 + use crate::exception::StackFrame; 340 + use crate::tickv::{with_tickv, EepyFlashController}; 341 + 342 + pub(super) fn handle_kv_store(stack_values: &mut StackFrame) { 343 + match KvStoreSyscall::from_repr(stack_values.r0) { 344 + Some(KvStoreSyscall::ReadKey) => handle_kv_get(stack_values), 345 + Some(KvStoreSyscall::AppendKey) => handle_kv_append(stack_values), 346 + Some(KvStoreSyscall::PutKey) => handle_kv_put(stack_values), 347 + Some(KvStoreSyscall::InvalidateKey) => handle_kv_invalidate(stack_values), 348 + Some(KvStoreSyscall::ZeroiseKey) => handle_kv_zeroise(stack_values), 349 + None => panic!("illegal syscall"), 350 + } 351 + } 352 + 353 + fn hash(stack_values: &mut StackFrame, key: &[u8]) -> u64 { 354 + let slot_number = (stack_values.pc as usize) / SLOT_SIZE; 355 + let slot_header = unsafe { slot(slot_number as u8) }; 356 + let program_name = unsafe { core::slice::from_raw_parts((*slot_header).name_ptr, (*slot_header).name_len) }; 357 + 358 + let mut hasher = SipHasher::new(); 359 + hasher.write(program_name); 360 + hasher.write(key); 361 + hasher.finish() 362 + } 363 + 364 + fn append_key_gc(tickv: &TicKV<EepyFlashController, 4096>, key: u64, value: &[u8]) -> Result<(), ErrorCode> { 365 + let mut res = tickv.append_key(key, value).map(|_| ()); 366 + if let Err(ErrorCode::RegionFull | ErrorCode::FlashFull) = res { 367 + res = tickv.garbage_collect().map(|_| ()); 368 + if res.is_ok() { 369 + res = tickv.append_key(key, value).map(|_| ()); 370 + } 371 + } 372 + res 373 + } 374 + 375 + fn handle_kv_get(stack_values: &mut StackFrame) { 376 + let args = stack_values.r1 as *const ReadKeyArgs; 377 + let key = unsafe { core::slice::from_raw_parts((*args).key_ptr, (*args).key_len) }; 378 + let buf = unsafe { core::slice::from_raw_parts_mut((*args).buf_ptr, (*args).buf_len) }; 379 + 380 + let hashed_key = hash(stack_values, key); 381 + let res = unsafe { with_tickv(|tickv| tickv.get_key(hashed_key, buf)) }; 382 + 383 + let res_ptr = stack_values.r2 as *mut SafeResult<usize, ReadKeyError>; 384 + let res: SafeResult<usize, ReadKeyError> = res 385 + .map(|(_, read)| read) 386 + .map_err(|e| e.try_into().unwrap()) 387 + .into(); 388 + unsafe { res_ptr.write(res) }; 389 + } 390 + 391 + fn handle_kv_append(stack_values: &mut StackFrame) { 392 + let args = stack_values.r1 as *const WriteKeyArgs; 393 + let key = unsafe { core::slice::from_raw_parts((*args).key_ptr, (*args).key_len) }; 394 + let value = unsafe { core::slice::from_raw_parts((*args).value_ptr, (*args).value_len) }; 395 + 396 + let hashed_key = hash(stack_values, key); 397 + let res = unsafe { with_tickv(|tickv| append_key_gc(tickv, hashed_key, value)) }; 398 + 399 + let res_ptr = stack_values.r2 as *mut SafeResult<(), AppendKeyError>; 400 + let res: SafeResult<(), AppendKeyError> = res 401 + .map(|_| ()) 402 + .map_err(|e| e.try_into().unwrap()) 403 + .into(); 404 + unsafe { res_ptr.write(res) }; 405 + } 406 + 407 + fn handle_kv_put(stack_values: &mut StackFrame) { 408 + let args = stack_values.r1 as *const WriteKeyArgs; 409 + let key = unsafe { core::slice::from_raw_parts((*args).key_ptr, (*args).key_len) }; 410 + let value = unsafe { core::slice::from_raw_parts((*args).value_ptr, (*args).value_len) }; 411 + 412 + let hashed_key = hash(stack_values, key); 413 + let mut res = unsafe { with_tickv(|tickv| append_key_gc(tickv, hashed_key, value)) }; 414 + 415 + // if there is already a value for this key, invalidate it and write the new value 416 + if let Err(ErrorCode::KeyAlreadyExists) = res { 417 + res = unsafe { with_tickv(|tickv| tickv.invalidate_key(hashed_key).map(|_| ())) }; 418 + if res.is_ok() { 419 + res = unsafe { with_tickv(|tickv| append_key_gc(tickv, hashed_key, value)) }; 420 + } 421 + } 422 + 423 + let res_ptr = stack_values.r2 as *mut SafeResult<(), PutKeyError>; 424 + let res: SafeResult<(), PutKeyError> = res 425 + .map(|_| ()) 426 + .map_err(|e| e.try_into().unwrap()) 427 + .into(); 428 + unsafe { res_ptr.write(res) }; 429 + } 430 + 431 + fn handle_kv_invalidate(stack_values: &mut StackFrame) { 432 + let key = unsafe { core::slice::from_raw_parts(stack_values.r1 as *const u8, stack_values.r2) }; 433 + let hashed_key = hash(stack_values, key); 434 + let res = unsafe { with_tickv(|tickv| tickv.invalidate_key(hashed_key)) }; 435 + 436 + let res_ptr = stack_values.r3 as *mut SafeResult<(), DeleteKeyError>; 437 + let res: SafeResult<(), DeleteKeyError> = res 438 + .map(|_| ()) 439 + .map_err(|e| e.try_into().unwrap()) 440 + .into(); 441 + unsafe { res_ptr.write(res) }; 442 + } 443 + 444 + fn handle_kv_zeroise(stack_values: &mut StackFrame) { 445 + let key = unsafe { core::slice::from_raw_parts(stack_values.r1 as *const u8, stack_values.r2) }; 446 + let hashed_key = hash(stack_values, key); 447 + let res = unsafe { with_tickv(|tickv| tickv.zeroise_key(hashed_key)) }; 448 + 449 + let res_ptr = stack_values.r3 as *mut SafeResult<(), DeleteKeyError>; 450 + let res: SafeResult<(), DeleteKeyError> = res 451 + .map(|_| ()) 452 + .map_err(|e| e.try_into().unwrap()) 453 + .into(); 454 + unsafe { res_ptr.write(res) }; 367 455 } 368 456 }
+99
eepy/src/tickv.rs
··· 1 + use once_cell::unsync::OnceCell; 2 + use defmt::trace; 3 + use siphasher::sip::SipHasher; 4 + use tickv::{ErrorCode, FlashController, TicKV, MAIN_KEY}; 5 + 6 + const TICKV_START_XIP: *const u8 = 0x10040000 as *const u8; 7 + const TICKV_START_FLASH: usize = 0x40000; 8 + const TICKV_SIZE: usize = 256 * 1024; 9 + 10 + pub(crate) struct EepyFlashController; 11 + 12 + impl FlashController<4096> for EepyFlashController { 13 + fn read_region(&self, region_number: usize, buf: &mut [u8; 4096]) -> Result<(), ErrorCode> { 14 + trace!("kv read_region"); 15 + 16 + unsafe { 17 + let start_addr = TICKV_START_XIP.add(region_number * 4096); 18 + let slice = core::slice::from_raw_parts(start_addr, 4096); 19 + buf.copy_from_slice(slice); 20 + Ok(()) 21 + } 22 + } 23 + 24 + fn write(&self, mut address: usize, mut buf: &[u8]) -> Result<(), ErrorCode> { 25 + trace!("kv write"); 26 + 27 + // If the address is unaligned, read-modify-write the first part 28 + if address % 256 != 0 { 29 + let write_len = usize::min(buf.len(), 256 - (address % 256)); 30 + let block_start = address & !(256 - 1); 31 + 32 + let mut write_buf = [0u8; 256]; 33 + unsafe { 34 + write_buf.copy_from_slice(core::slice::from_raw_parts(TICKV_START_XIP.add(block_start), 256)); 35 + } 36 + write_buf[address % 256..address % 256 + write_len].copy_from_slice(&buf[..write_len]); 37 + 38 + unsafe { 39 + crate::flash::program((TICKV_START_FLASH + block_start) as u32, &write_buf); 40 + } 41 + 42 + buf = &buf[write_len..]; 43 + address += write_len; 44 + } 45 + 46 + let blocks = buf.len() / 256; 47 + if blocks > 0 { 48 + unsafe { 49 + crate::flash::program((TICKV_START_FLASH + address) as u32, &buf[..blocks * 256]); 50 + } 51 + } 52 + address += blocks * 256; 53 + buf = &buf[blocks * 256..]; 54 + 55 + if buf.len() > 0 { 56 + let mut write_buf = [0u8; 256]; 57 + write_buf[..buf.len()].copy_from_slice(buf); 58 + unsafe { 59 + write_buf[buf.len()..].copy_from_slice(core::slice::from_raw_parts(TICKV_START_XIP.add(address), 256 - buf.len())); 60 + } 61 + 62 + unsafe { 63 + crate::flash::program((TICKV_START_FLASH + address) as u32, &write_buf); 64 + } 65 + } 66 + 67 + Ok(()) 68 + } 69 + 70 + fn erase_region(&self, region_number: usize) -> Result<(), ErrorCode> { 71 + trace!("kv erase_region"); 72 + 73 + unsafe { 74 + crate::flash::erase((TICKV_START_FLASH + region_number * 4096) as u32, 4096); 75 + } 76 + Ok(()) 77 + } 78 + } 79 + 80 + static mut TICKV_BUFFER: [u8; 4096] = [0u8; 4096]; 81 + static mut TICKV: OnceCell<TicKV<EepyFlashController, 4096>> = OnceCell::new(); 82 + 83 + /// SAFETY: this must only be called once 84 + unsafe fn init_tickv() -> TicKV<'static, EepyFlashController, 4096> { 85 + // SAFETY: this is only called once, so we can't have aliased mutable references 86 + #[allow(static_mut_refs)] 87 + let read_buffer = unsafe { &mut TICKV_BUFFER }; 88 + 89 + let tickv = TicKV::new(EepyFlashController, read_buffer, TICKV_SIZE); 90 + 91 + let hasher = SipHasher::new(); 92 + tickv.initialise(hasher.hash(MAIN_KEY)).expect("Failed to initialise TicKV"); 93 + tickv 94 + } 95 + 96 + #[allow(static_mut_refs)] 97 + pub(crate) unsafe fn with_tickv<R>(f: impl FnOnce(&TicKV<EepyFlashController, 4096>) -> R) -> R { 98 + f(TICKV.get_or_init(|| init_tickv())) 99 + }
+1 -1
memory.x
··· 2 2 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 3 3 FLASH : ORIGIN = 0x10000100, LENGTH = 128K - 0x100 4 4 LAUNCHER: ORIGIN = 0x10020000, LENGTH = 128K 5 - RESERVED: ORIGIN = 0x10040000, LENGTH = 256K 5 + TICKV: ORIGIN = 0x10040000, LENGTH = 256K 6 6 SLOTS: ORIGIN = 0x10080000, LENGTH = 16M - 512K 7 7 RAM : ORIGIN = 0x20000000, LENGTH = 128K 8 8 PROGRAM_RAM : ORIGIN = 0x20020000, LENGTH = 136K