diff --git a/src/checked.rs b/src/checked.rs new file mode 100644 index 0000000000..836890d0ba --- /dev/null +++ b/src/checked.rs @@ -0,0 +1,77 @@ +//! Safe, run-time checked resources + +use core::marker::PhantomData; +use core::cell::UnsafeCell; + +use cortex_m::interrupt; +use cortex_m::register::{basepri, basepri_max}; + +use Ceiling; + +unsafe fn acquire(locked: &UnsafeCell, ceiling: u8) -> u8 { + interrupt::free( + |_| { + assert!(!*locked.get(), "resource already locked"); + let old_basepri = basepri::read(); + basepri_max::write(ceiling); + *locked.get() = true; + old_basepri + }, + ) +} + +unsafe fn release(locked: &UnsafeCell, old_basepri: u8) { + interrupt::free( + |_| { + basepri::write(old_basepri); + *locked.get() = false; + }, + ); +} + +/// A totally safe `Resource` that panics on misuse +pub struct Resource { + _marker: PhantomData, + data: UnsafeCell, + locked: UnsafeCell, +} + +impl Resource +where + C: Ceiling, +{ + /// Creates a new `Resource` with ceiling `C` + pub const fn new(data: T) -> Resource { + Resource { + _marker: PhantomData, + data: UnsafeCell::new(data), + locked: UnsafeCell::new(false), + } + } + + /// Locks the resource, blocking tasks with priority equal or smaller than + /// the ceiling `C` + pub fn lock(&'static self, f: F) + where + F: FnOnce(&T), + { + unsafe { + let old_basepri = acquire(&self.locked, C::ceiling()); + f(&*self.data.get()); + release(&self.locked, old_basepri); + } + } + + /// Mutably locks the resource, blocking tasks with priority equal or + /// smaller than the ceiling `C` + pub fn lock_mut(&'static self, f: F) + where + F: FnOnce(&mut T), + { + unsafe { + let old_basepri = acquire(&self.locked, C::ceiling()); + f(&mut *self.data.get()); + release(&self.locked, old_basepri); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index bf0b7bd542..95aa8ba34c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,8 @@ extern crate cortex_m; +pub mod checked; + use cortex_m::ctxt::Context; use cortex_m::interrupt::{CriticalSection, Nr}; use cortex_m::peripheral::{Peripheral, NVIC};