From 6d8f409018f9fabd23e80e07a20b357989c4d841 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 27 May 2023 10:29:21 +0200 Subject: [PATCH 1/2] Add BlockingPartition --- embassy-embedded-hal/src/flash/mod.rs | 5 +- .../{partition.rs => partition/asynch.rs} | 22 +-- .../src/flash/partition/blocking.rs | 125 ++++++++++++++++++ .../src/flash/partition/mod.rs | 30 +++++ 4 files changed, 159 insertions(+), 23 deletions(-) rename embassy-embedded-hal/src/flash/{partition.rs => partition/asynch.rs} (89%) create mode 100644 embassy-embedded-hal/src/flash/partition/blocking.rs create mode 100644 embassy-embedded-hal/src/flash/partition/mod.rs diff --git a/embassy-embedded-hal/src/flash/mod.rs b/embassy-embedded-hal/src/flash/mod.rs index 0210b198..7e4ef290 100644 --- a/embassy-embedded-hal/src/flash/mod.rs +++ b/embassy-embedded-hal/src/flash/mod.rs @@ -3,9 +3,6 @@ mod concat_flash; #[cfg(test)] pub(crate) mod mem_flash; -#[cfg(feature = "nightly")] -mod partition; +pub mod partition; pub use concat_flash::ConcatFlash; -#[cfg(feature = "nightly")] -pub use partition::Partition; diff --git a/embassy-embedded-hal/src/flash/partition.rs b/embassy-embedded-hal/src/flash/partition/asynch.rs similarity index 89% rename from embassy-embedded-hal/src/flash/partition.rs rename to embassy-embedded-hal/src/flash/partition/asynch.rs index 66d93c0e..141e0d9f 100644 --- a/embassy-embedded-hal/src/flash/partition.rs +++ b/embassy-embedded-hal/src/flash/partition/asynch.rs @@ -1,8 +1,10 @@ use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::mutex::Mutex; -use embedded_storage::nor_flash::{ErrorType, NorFlashError, NorFlashErrorKind}; +use embedded_storage::nor_flash::ErrorType; use embedded_storage_async::nor_flash::{NorFlash, ReadNorFlash}; +use super::Error; + /// A logical partition of an underlying shared flash /// /// A partition holds an offset and a size of the flash, @@ -16,13 +18,6 @@ pub struct Partition<'a, M: RawMutex, T: NorFlash> { size: u32, } -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Error { - OutOfBounds, - Flash(T), -} - impl<'a, M: RawMutex, T: NorFlash> Partition<'a, M, T> { /// Create a new partition pub const fn new(flash: &'a Mutex, offset: u32, size: u32) -> Self { @@ -37,20 +32,10 @@ impl<'a, M: RawMutex, T: NorFlash> Partition<'a, M, T> { } } -impl NorFlashError for Error { - fn kind(&self) -> NorFlashErrorKind { - match self { - Error::OutOfBounds => NorFlashErrorKind::OutOfBounds, - Error::Flash(f) => f.kind(), - } - } -} - impl ErrorType for Partition<'_, M, T> { type Error = Error; } -#[cfg(feature = "nightly")] impl ReadNorFlash for Partition<'_, M, T> { const READ_SIZE: usize = T::READ_SIZE; @@ -68,7 +53,6 @@ impl ReadNorFlash for Partition<'_, M, T> { } } -#[cfg(feature = "nightly")] impl NorFlash for Partition<'_, M, T> { const WRITE_SIZE: usize = T::WRITE_SIZE; const ERASE_SIZE: usize = T::ERASE_SIZE; diff --git a/embassy-embedded-hal/src/flash/partition/blocking.rs b/embassy-embedded-hal/src/flash/partition/blocking.rs new file mode 100644 index 00000000..1a4c80f9 --- /dev/null +++ b/embassy-embedded-hal/src/flash/partition/blocking.rs @@ -0,0 +1,125 @@ +use embassy_sync::blocking_mutex::raw::RawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; + +use super::Error; + +/// A logical partition of an underlying shared flash +/// +/// A partition holds an offset and a size of the flash, +/// and is restricted to operate with that range. +/// There is no guarantee that muliple partitions on the same flash +/// operate on mutually exclusive ranges - such a separation is up to +/// the user to guarantee. +pub struct BlockingPartition<'a, M: RawMutex, T: NorFlash> { + flash: &'a Mutex, + offset: u32, + size: u32, +} + +impl<'a, M: RawMutex, T: NorFlash> BlockingPartition<'a, M, T> { + /// Create a new partition + pub const fn new(flash: &'a Mutex, offset: u32, size: u32) -> Self { + if offset % T::READ_SIZE as u32 != 0 || offset % T::WRITE_SIZE as u32 != 0 || offset % T::ERASE_SIZE as u32 != 0 + { + panic!("Partition offset must be a multiple of read, write and erase size"); + } + if size % T::READ_SIZE as u32 != 0 || size % T::WRITE_SIZE as u32 != 0 || size % T::ERASE_SIZE as u32 != 0 { + panic!("Partition size must be a multiple of read, write and erase size"); + } + Self { flash, offset, size } + } +} + +impl ErrorType for BlockingPartition<'_, M, T> { + type Error = Error; +} + +impl ReadNorFlash for BlockingPartition<'_, M, T> { + const READ_SIZE: usize = T::READ_SIZE; + + fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + if offset + bytes.len() as u32 > self.size { + return Err(Error::OutOfBounds); + } + + self.flash + .lock(|flash| flash.read(self.offset + offset, bytes).map_err(Error::Flash)) + } + + fn capacity(&self) -> usize { + self.size as usize + } +} + +impl NorFlash for BlockingPartition<'_, M, T> { + const WRITE_SIZE: usize = T::WRITE_SIZE; + const ERASE_SIZE: usize = T::ERASE_SIZE; + + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + if offset + bytes.len() as u32 > self.size { + return Err(Error::OutOfBounds); + } + + self.flash + .lock(|flash| flash.write(self.offset + offset, bytes).map_err(Error::Flash)) + } + + fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + if to > self.size { + return Err(Error::OutOfBounds); + } + + self.flash + .lock(|flash| flash.erase(self.offset + from, self.offset + to).map_err(Error::Flash)) + } +} + +#[cfg(test)] +mod tests { + use embassy_sync::blocking_mutex::raw::NoopRawMutex; + + use super::*; + use crate::flash::mem_flash::MemFlash; + + #[test] + fn can_read() { + let mut flash = MemFlash::<1024, 128, 4>::default(); + flash.mem[132..132 + 8].fill(0xAA); + + let flash = Mutex::::new(flash); + let mut partition = BlockingPartition::new(&flash, 128, 256); + + let mut read_buf = [0; 8]; + partition.read(4, &mut read_buf).unwrap(); + + assert!(read_buf.iter().position(|&x| x != 0xAA).is_none()); + } + + #[test] + fn can_write() { + let flash = MemFlash::<1024, 128, 4>::default(); + + let flash = Mutex::::new(flash); + let mut partition = BlockingPartition::new(&flash, 128, 256); + + let write_buf = [0xAA; 8]; + partition.write(4, &write_buf).unwrap(); + + let flash = flash.into_inner(); + assert!(flash.mem[132..132 + 8].iter().position(|&x| x != 0xAA).is_none()); + } + + #[test] + fn can_erase() { + let flash = MemFlash::<1024, 128, 4>::new(0x00); + + let flash = Mutex::::new(flash); + let mut partition = BlockingPartition::new(&flash, 128, 256); + + partition.erase(0, 128).unwrap(); + + let flash = flash.into_inner(); + assert!(flash.mem[128..256].iter().position(|&x| x != 0xFF).is_none()); + } +} diff --git a/embassy-embedded-hal/src/flash/partition/mod.rs b/embassy-embedded-hal/src/flash/partition/mod.rs new file mode 100644 index 00000000..a12e49ce --- /dev/null +++ b/embassy-embedded-hal/src/flash/partition/mod.rs @@ -0,0 +1,30 @@ +//! Flash Partition utilities + +use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; + +#[cfg(feature = "nightly")] +mod asynch; +mod blocking; + +#[cfg(feature = "nightly")] +pub use asynch::Partition; +pub use blocking::BlockingPartition; + +/// Partition error +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// The requested flash area is outside the partition + OutOfBounds, + /// Underlying flash error + Flash(T), +} + +impl NorFlashError for Error { + fn kind(&self) -> NorFlashErrorKind { + match self { + Error::OutOfBounds => NorFlashErrorKind::OutOfBounds, + Error::Flash(f) => f.kind(), + } + } +} From 85ce44f78e6d269675085ce6aa54c6353ed13ec7 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 27 May 2023 17:02:54 +0200 Subject: [PATCH 2/2] Use RefCell in blocking mutex --- .../src/flash/partition/blocking.rs | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/embassy-embedded-hal/src/flash/partition/blocking.rs b/embassy-embedded-hal/src/flash/partition/blocking.rs index 1a4c80f9..dc52e292 100644 --- a/embassy-embedded-hal/src/flash/partition/blocking.rs +++ b/embassy-embedded-hal/src/flash/partition/blocking.rs @@ -1,3 +1,5 @@ +use core::cell::RefCell; + use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::Mutex; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; @@ -12,14 +14,14 @@ use super::Error; /// operate on mutually exclusive ranges - such a separation is up to /// the user to guarantee. pub struct BlockingPartition<'a, M: RawMutex, T: NorFlash> { - flash: &'a Mutex, + flash: &'a Mutex>, offset: u32, size: u32, } impl<'a, M: RawMutex, T: NorFlash> BlockingPartition<'a, M, T> { /// Create a new partition - pub const fn new(flash: &'a Mutex, offset: u32, size: u32) -> Self { + pub const fn new(flash: &'a Mutex>, offset: u32, size: u32) -> Self { if offset % T::READ_SIZE as u32 != 0 || offset % T::WRITE_SIZE as u32 != 0 || offset % T::ERASE_SIZE as u32 != 0 { panic!("Partition offset must be a multiple of read, write and erase size"); @@ -43,8 +45,12 @@ impl ReadNorFlash for BlockingPartition<'_, M, T> { return Err(Error::OutOfBounds); } - self.flash - .lock(|flash| flash.read(self.offset + offset, bytes).map_err(Error::Flash)) + self.flash.lock(|flash| { + flash + .borrow_mut() + .read(self.offset + offset, bytes) + .map_err(Error::Flash) + }) } fn capacity(&self) -> usize { @@ -61,8 +67,12 @@ impl NorFlash for BlockingPartition<'_, M, T> { return Err(Error::OutOfBounds); } - self.flash - .lock(|flash| flash.write(self.offset + offset, bytes).map_err(Error::Flash)) + self.flash.lock(|flash| { + flash + .borrow_mut() + .write(self.offset + offset, bytes) + .map_err(Error::Flash) + }) } fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { @@ -70,8 +80,12 @@ impl NorFlash for BlockingPartition<'_, M, T> { return Err(Error::OutOfBounds); } - self.flash - .lock(|flash| flash.erase(self.offset + from, self.offset + to).map_err(Error::Flash)) + self.flash.lock(|flash| { + flash + .borrow_mut() + .erase(self.offset + from, self.offset + to) + .map_err(Error::Flash) + }) } } @@ -87,7 +101,7 @@ mod tests { let mut flash = MemFlash::<1024, 128, 4>::default(); flash.mem[132..132 + 8].fill(0xAA); - let flash = Mutex::::new(flash); + let flash = Mutex::::new(RefCell::new(flash)); let mut partition = BlockingPartition::new(&flash, 128, 256); let mut read_buf = [0; 8]; @@ -100,13 +114,13 @@ mod tests { fn can_write() { let flash = MemFlash::<1024, 128, 4>::default(); - let flash = Mutex::::new(flash); + let flash = Mutex::::new(RefCell::new(flash)); let mut partition = BlockingPartition::new(&flash, 128, 256); let write_buf = [0xAA; 8]; partition.write(4, &write_buf).unwrap(); - let flash = flash.into_inner(); + let flash = flash.into_inner().take(); assert!(flash.mem[132..132 + 8].iter().position(|&x| x != 0xAA).is_none()); } @@ -114,12 +128,12 @@ mod tests { fn can_erase() { let flash = MemFlash::<1024, 128, 4>::new(0x00); - let flash = Mutex::::new(flash); + let flash = Mutex::::new(RefCell::new(flash)); let mut partition = BlockingPartition::new(&flash, 128, 256); partition.erase(0, 128).unwrap(); - let flash = flash.into_inner(); + let flash = flash.into_inner().take(); assert!(flash.mem[128..256].iter().position(|&x| x != 0xFF).is_none()); } }