From 6d8f409018f9fabd23e80e07a20b357989c4d841 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 27 May 2023 10:29:21 +0200 Subject: Add BlockingPartition --- embassy-embedded-hal/src/flash/mod.rs | 5 +- embassy-embedded-hal/src/flash/partition.rs | 145 --------------------- embassy-embedded-hal/src/flash/partition/asynch.rs | 129 ++++++++++++++++++ .../src/flash/partition/blocking.rs | 125 ++++++++++++++++++ embassy-embedded-hal/src/flash/partition/mod.rs | 30 +++++ 5 files changed, 285 insertions(+), 149 deletions(-) delete mode 100644 embassy-embedded-hal/src/flash/partition.rs create mode 100644 embassy-embedded-hal/src/flash/partition/asynch.rs 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 0210b198d..7e4ef290f 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.rs deleted file mode 100644 index 66d93c0ea..000000000 --- a/embassy-embedded-hal/src/flash/partition.rs +++ /dev/null @@ -1,145 +0,0 @@ -use embassy_sync::blocking_mutex::raw::RawMutex; -use embassy_sync::mutex::Mutex; -use embedded_storage::nor_flash::{ErrorType, NorFlashError, NorFlashErrorKind}; -use embedded_storage_async::nor_flash::{NorFlash, ReadNorFlash}; - -/// 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 Partition<'a, M: RawMutex, T: NorFlash> { - flash: &'a Mutex, - offset: u32, - 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 { - 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 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; - - async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - if offset + bytes.len() as u32 > self.size { - return Err(Error::OutOfBounds); - } - - let mut flash = self.flash.lock().await; - flash.read(self.offset + offset, bytes).await.map_err(Error::Flash) - } - - fn capacity(&self) -> usize { - self.size as usize - } -} - -#[cfg(feature = "nightly")] -impl NorFlash for Partition<'_, M, T> { - const WRITE_SIZE: usize = T::WRITE_SIZE; - const ERASE_SIZE: usize = T::ERASE_SIZE; - - async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - if offset + bytes.len() as u32 > self.size { - return Err(Error::OutOfBounds); - } - - let mut flash = self.flash.lock().await; - flash.write(self.offset + offset, bytes).await.map_err(Error::Flash) - } - - async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - if to > self.size { - return Err(Error::OutOfBounds); - } - - let mut flash = self.flash.lock().await; - flash - .erase(self.offset + from, self.offset + to) - .await - .map_err(Error::Flash) - } -} - -#[cfg(test)] -mod tests { - use embassy_sync::blocking_mutex::raw::NoopRawMutex; - - use super::*; - use crate::flash::mem_flash::MemFlash; - - #[futures_test::test] - async 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 = Partition::new(&flash, 128, 256); - - let mut read_buf = [0; 8]; - partition.read(4, &mut read_buf).await.unwrap(); - - assert!(read_buf.iter().position(|&x| x != 0xAA).is_none()); - } - - #[futures_test::test] - async fn can_write() { - let flash = MemFlash::<1024, 128, 4>::default(); - - let flash = Mutex::::new(flash); - let mut partition = Partition::new(&flash, 128, 256); - - let write_buf = [0xAA; 8]; - partition.write(4, &write_buf).await.unwrap(); - - let flash = flash.try_lock().unwrap(); - assert!(flash.mem[132..132 + 8].iter().position(|&x| x != 0xAA).is_none()); - } - - #[futures_test::test] - async fn can_erase() { - let flash = MemFlash::<1024, 128, 4>::new(0x00); - - let flash = Mutex::::new(flash); - let mut partition = Partition::new(&flash, 128, 256); - - partition.erase(0, 128).await.unwrap(); - - let flash = flash.try_lock().unwrap(); - assert!(flash.mem[128..256].iter().position(|&x| x != 0xFF).is_none()); - } -} diff --git a/embassy-embedded-hal/src/flash/partition/asynch.rs b/embassy-embedded-hal/src/flash/partition/asynch.rs new file mode 100644 index 000000000..141e0d9fc --- /dev/null +++ b/embassy-embedded-hal/src/flash/partition/asynch.rs @@ -0,0 +1,129 @@ +use embassy_sync::blocking_mutex::raw::RawMutex; +use embassy_sync::mutex::Mutex; +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, +/// 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 Partition<'a, M: RawMutex, T: NorFlash> { + flash: &'a Mutex, + offset: u32, + size: u32, +} + +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 { + 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 Partition<'_, M, T> { + type Error = Error; +} + +impl ReadNorFlash for Partition<'_, M, T> { + const READ_SIZE: usize = T::READ_SIZE; + + async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + if offset + bytes.len() as u32 > self.size { + return Err(Error::OutOfBounds); + } + + let mut flash = self.flash.lock().await; + flash.read(self.offset + offset, bytes).await.map_err(Error::Flash) + } + + fn capacity(&self) -> usize { + self.size as usize + } +} + +impl NorFlash for Partition<'_, M, T> { + const WRITE_SIZE: usize = T::WRITE_SIZE; + const ERASE_SIZE: usize = T::ERASE_SIZE; + + async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + if offset + bytes.len() as u32 > self.size { + return Err(Error::OutOfBounds); + } + + let mut flash = self.flash.lock().await; + flash.write(self.offset + offset, bytes).await.map_err(Error::Flash) + } + + async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + if to > self.size { + return Err(Error::OutOfBounds); + } + + let mut flash = self.flash.lock().await; + flash + .erase(self.offset + from, self.offset + to) + .await + .map_err(Error::Flash) + } +} + +#[cfg(test)] +mod tests { + use embassy_sync::blocking_mutex::raw::NoopRawMutex; + + use super::*; + use crate::flash::mem_flash::MemFlash; + + #[futures_test::test] + async 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 = Partition::new(&flash, 128, 256); + + let mut read_buf = [0; 8]; + partition.read(4, &mut read_buf).await.unwrap(); + + assert!(read_buf.iter().position(|&x| x != 0xAA).is_none()); + } + + #[futures_test::test] + async fn can_write() { + let flash = MemFlash::<1024, 128, 4>::default(); + + let flash = Mutex::::new(flash); + let mut partition = Partition::new(&flash, 128, 256); + + let write_buf = [0xAA; 8]; + partition.write(4, &write_buf).await.unwrap(); + + let flash = flash.try_lock().unwrap(); + assert!(flash.mem[132..132 + 8].iter().position(|&x| x != 0xAA).is_none()); + } + + #[futures_test::test] + async fn can_erase() { + let flash = MemFlash::<1024, 128, 4>::new(0x00); + + let flash = Mutex::::new(flash); + let mut partition = Partition::new(&flash, 128, 256); + + partition.erase(0, 128).await.unwrap(); + + let flash = flash.try_lock().unwrap(); + assert!(flash.mem[128..256].iter().position(|&x| x != 0xFF).is_none()); + } +} 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 000000000..1a4c80f92 --- /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 000000000..a12e49ce1 --- /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(), + } + } +} -- cgit