Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 88 additions & 1 deletion partition-manager/partition-manager/src/ext/bdd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use aligned::Aligned;
use block_device_driver::BlockDevice;
use embassy_sync::blocking_mutex::raw::RawMutex;

use crate::{Error, Partition, RO, RW};
use crate::{Error, Partition, PartitionGuard, RO, RW};

impl<F, MARKER, M: RawMutex> Partition<'_, F, MARKER, M> {
/// Returns the block number on the parent storage medium, given a block size.
Expand Down Expand Up @@ -37,6 +37,33 @@ impl<F, MARKER, M: RawMutex> Partition<'_, F, MARKER, M> {
}
}

impl<F, MARKER, M: RawMutex> PartitionGuard<'_, F, MARKER, M> {
const fn start_block(&self, block_size: u32) -> Option<u32> {
if self.offset % block_size != 0 {
None
} else {
Some(self.offset / block_size)
}
}

const fn check_access<const SIZE: usize>(
&self,
block_address: u32,
data: &[Aligned<F::Align, [u8; SIZE]>],
) -> Result<(), Error<F::Error>>
where
F: BlockDevice<SIZE>,
{
let offset = block_address * SIZE as u32;
let size = (data.len() * SIZE) as u32;
if !self.within_bounds(offset, size) {
Err(Error::OutOfBounds)
Comment on lines +57 to +60
} else {
Ok(())
}
}
}

impl<const SIZE: usize, F: BlockDevice<SIZE>, M: RawMutex> BlockDevice<SIZE> for Partition<'_, F, RO, M> {
type Error = Error<F::Error>;
type Align = F::Align;
Expand Down Expand Up @@ -94,3 +121,63 @@ impl<const SIZE: usize, F: BlockDevice<SIZE>, M: RawMutex> BlockDevice<SIZE> for
Ok(self.size as u64)
}
}

// PartitionGuard trait implementations
impl<const SIZE: usize, F: BlockDevice<SIZE>, M: RawMutex> BlockDevice<SIZE> for PartitionGuard<'_, F, RO, M> {
type Error = Error<F::Error>;
type Align = F::Align;

async fn read(
&mut self,
block_address: u32,
data: &mut [Aligned<Self::Align, [u8; SIZE]>],
) -> Result<(), Self::Error> {
self.check_access(block_address, data)?;
let start_block = self.start_block(SIZE as u32).ok_or(Error::NotAligned)?;

Ok(self.guard.read(start_block + block_address, data).await?)
}

async fn write(
&mut self,
_block_address: u32,
_data: &[Aligned<Self::Align, [u8; SIZE]>],
) -> Result<(), Self::Error> {
Err(Error::ReadOnly)
}

async fn size(&mut self) -> Result<u64, Self::Error> {
Ok(self.size as u64)
}
}

impl<const SIZE: usize, F: BlockDevice<SIZE>, M: RawMutex> BlockDevice<SIZE> for PartitionGuard<'_, F, RW, M> {
type Error = Error<F::Error>;
type Align = F::Align;

async fn read(
&mut self,
block_address: u32,
data: &mut [Aligned<Self::Align, [u8; SIZE]>],
) -> Result<(), Self::Error> {
self.check_access(block_address, data)?;
let start_block = self.start_block(SIZE as u32).ok_or(Error::NotAligned)?;

Ok(self.guard.read(start_block + block_address, data).await?)
}

async fn write(
&mut self,
block_address: u32,
data: &[Aligned<Self::Align, [u8; SIZE]>],
) -> Result<(), Self::Error> {
self.check_access(block_address, data)?;
let start_block = self.start_block(SIZE as u32).ok_or(Error::NotAligned)?;

Ok(self.guard.write(start_block + block_address, data).await?)
}

async fn size(&mut self) -> Result<u64, Self::Error> {
Ok(self.size as u64)
}
}
63 changes: 62 additions & 1 deletion partition-manager/partition-manager/src/ext/esa.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Embedded Storage Async

use crate::{Error, Partition, RO, RW};
use crate::{Error, Partition, PartitionGuard, RO, RW};
use core::fmt::Debug;
use embassy_sync::blocking_mutex::raw::RawMutex;
use embedded_storage_async::nor_flash::{
Expand All @@ -22,6 +22,10 @@ impl<F: ReadNorFlash, MARKER, M: RawMutex> ErrorType for Partition<'_, F, MARKER
type Error = Error<F::Error>;
}

impl<F: ReadNorFlash, MARKER, M: RawMutex> ErrorType for PartitionGuard<'_, F, MARKER, M> {
type Error = Error<F::Error>;
}

impl<F: ReadNorFlash, M: RawMutex> ReadNorFlash for Partition<'_, F, RO, M> {
const READ_SIZE: usize = F::READ_SIZE;

Expand Down Expand Up @@ -75,3 +79,60 @@ impl<F: NorFlash, M: RawMutex> NorFlash for Partition<'_, F, RW, M> {
}

impl<F: MultiwriteNorFlash, M: RawMutex> MultiwriteNorFlash for Partition<'_, F, RW, M> {}

// PartitionGuard trait implementations

impl<F: ReadNorFlash, M: RawMutex> ReadNorFlash for PartitionGuard<'_, F, RO, M> {
const READ_SIZE: usize = F::READ_SIZE;

async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
if !self.within_bounds(offset, bytes.len() as u32) {
return Err(Error::OutOfBounds);
}

Ok(self.guard.read(offset + self.offset, bytes).await?)
}

fn capacity(&self) -> usize {
self.size as usize
}
}

impl<F: ReadNorFlash, M: RawMutex> ReadNorFlash for PartitionGuard<'_, F, RW, M> {
const READ_SIZE: usize = F::READ_SIZE;

async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
if !self.within_bounds(offset, bytes.len() as u32) {
return Err(Error::OutOfBounds);
}

Ok(self.guard.read(offset + self.offset, bytes).await?)
}
Comment on lines +88 to +110

fn capacity(&self) -> usize {
self.size as usize
}
}

impl<F: NorFlash, M: RawMutex> NorFlash for PartitionGuard<'_, F, RW, M> {
const WRITE_SIZE: usize = F::WRITE_SIZE;
const ERASE_SIZE: usize = F::ERASE_SIZE;

async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
if !self.within_bounds(from, to.saturating_sub(from)) {
return Err(Error::OutOfBounds);
}

Ok(self.guard.erase(from + self.offset, to + self.offset).await?)
}

async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
if !self.within_bounds(offset, bytes.len() as u32) {
return Err(Error::OutOfBounds);
}

Ok(self.guard.write(offset + self.offset, bytes).await?)
}
}

impl<F: MultiwriteNorFlash, M: RawMutex> MultiwriteNorFlash for PartitionGuard<'_, F, RW, M> {}
47 changes: 46 additions & 1 deletion partition-manager/partition-manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ pub use partition_manager_macros as macros;
use core::{fmt::Debug, marker::PhantomData};
use embassy_sync::{
blocking_mutex::raw::{NoopRawMutex, RawMutex},
mutex::Mutex,
mutex::{Mutex, MutexGuard},
};

pub use embassy_sync::mutex::TryLockError;

mod ext;

#[cfg(test)]
Expand Down Expand Up @@ -43,6 +45,37 @@ impl<'a, F, MARKER, M: RawMutex> Partition<'a, F, MARKER, M> {
_marker: PhantomData,
}
}

/// Lock the underlying storage and return a guard that allows direct operations.
pub async fn lock(&self) -> PartitionGuard<'_, F, MARKER, M> {
PartitionGuard {
guard: self.storage.lock().await,
offset: self.offset,
size: self.size,
_marker: PhantomData,
}
}

/// Attempt to lock the underlying storage without blocking.
pub fn try_lock(&self) -> Result<PartitionGuard<'_, F, MARKER, M>, TryLockError> {
Ok(PartitionGuard {
guard: self.storage.try_lock()?,
offset: self.offset,
size: self.size,
_marker: PhantomData,
})
}
Comment on lines +49 to +67
}

/// A guard that provides access to a partition's underlying storage.
///
/// Obtained via [`Partition::lock`] or [`Partition::try_lock`].
/// The underlying mutex is held for the lifetime of this guard.
pub struct PartitionGuard<'a, F, MARKER, M: RawMutex = NoopRawMutex> {
guard: MutexGuard<'a, M, F>,
offset: u32,
size: u32,
_marker: PhantomData<MARKER>,
}

impl<F, M: RawMutex> Partition<'_, F, RW, M> {
Expand Down Expand Up @@ -101,6 +134,18 @@ impl<F, MARKER, M: RawMutex> Partition<'_, F, MARKER, M> {
}
}

impl<F, MARKER, M: RawMutex> PartitionGuard<'_, F, MARKER, M> {
/// Checks whether an address range lies within the partition.
#[allow(unused)]
const fn within_bounds(&self, offset: u32, size: u32) -> bool {
if let Some(end) = offset.checked_add(size) {
end <= self.size
} else {
false
}
}
}

/// Marker type for read-only partitions.
pub struct RO;

Expand Down
3 changes: 0 additions & 3 deletions partition-manager/partition-manager/src/test/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
#![allow(clippy::panic)]
#![allow(clippy::unwrap_used)]

mod mock;

#[cfg(feature = "bdd")]
Comment on lines 1 to 3
Expand Down
Loading