aboutsummaryrefslogtreecommitdiff
path: root/src/ctxt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ctxt.rs')
-rw-r--r--src/ctxt.rs160
1 files changed, 160 insertions, 0 deletions
diff --git a/src/ctxt.rs b/src/ctxt.rs
new file mode 100644
index 0000000..727090b
--- /dev/null
+++ b/src/ctxt.rs
@@ -0,0 +1,160 @@
+//! Interrupt / Exception context local data
+//!
+//! The main use case is safely adding state to exception / interrupt handlers.
+//!
+//! This is done in two stages, first you define a token that will appear in the
+//! interrupt handler signature; each handler will have its unique token. This
+//! token must be zero sized type because interrupt handlers' real signature is
+//! `fn()` and it must also implement the `Context` trait. You must also make
+//! sure that the token can't be constructed outside of the crate where it's
+//! defined.
+//!
+//! ```
+//! # use cortex_m::ctxt::Context;
+//! // This must be in a library crate
+//! /// Token unique to the TIM7 interrupt handler
+//! pub struct Tim7 { _0: () }
+//!
+//! unsafe impl Context for Tim7 {}
+//! ```
+//!
+//! Then in the application one can pin data to the interrupt handler using
+//! `Local`.
+//!
+//! ```
+//! # #![feature(const_fn)]
+//! # use std::cell::Cell;
+//! # use cortex_m::ctxt::{Context, Local};
+//! # struct Tim7;
+//! # unsafe impl Context for Tim7 {}
+//! // omitted: how to put this handler in the vector table
+//! extern "C" fn tim7(ctxt: Tim7) {
+//! static STATE: Local<Cell<bool>, Tim7> = Local::new(Cell::new(false));
+//!
+//! let state = STATE.borrow(&ctxt);
+//!
+//! // toggle state
+//! state.set(!state.get());
+//!
+//! if state.get() {
+//! // something
+//! } else {
+//! // something else
+//! }
+//! }
+//! ```
+//!
+//! Note that due to the uniqueness of tokens, other handlers won't be able to
+//! access context local data. (Given that you got the signatures right)
+//!
+//! ```
+//! # #![feature(const_fn)]
+//! # use std::cell::Cell;
+//! # use cortex_m::ctxt::{Context, Local};
+//! # struct Tim3;
+//! # struct Tim4;
+//! static TIM3_DATA: Local<Cell<bool>, Tim3> = Local::new(Cell::new(false));
+//!
+//! extern "C" fn tim3(ctxt: Tim3) {
+//! let data = TIM3_DATA.borrow(&ctxt);
+//! }
+//!
+//! extern "C" fn tim4(ctxt: Tim4) {
+//! //let data = TIM3_DATA.borrow(&ctxt);
+//! // ^ wouldn't work
+//! }
+//! # unsafe impl Context for Tim3 {}
+//! # fn main() {}
+//! ```
+//!
+//! To have the application use these tokenized function signatures, you can
+//! define, in a library, a `Handlers` struct that represents the vector table:
+//!
+//! ```
+//! # struct Tim1;
+//! # struct Tim2;
+//! # struct Tim3;
+//! # struct Tim4;
+//! # extern "C" fn default_handler<T>(_: T) {}
+//! #[repr(C)]
+//! pub struct Handlers {
+//! tim1: extern "C" fn(Tim1),
+//! tim2: extern "C" fn(Tim2),
+//! tim3: extern "C" fn(Tim3),
+//! tim4: extern "C" fn(Tim4),
+//! /* .. */
+//! }
+//!
+//! pub const DEFAULT_HANDLERS: Handlers = Handlers {
+//! tim1: default_handler,
+//! tim2: default_handler,
+//! tim3: default_handler,
+//! tim4: default_handler,
+//! /* .. */
+//! };
+//! ```
+//!
+//! Then have the user use that `struct` to register the interrupt handlers:
+//!
+//! ```
+//! # struct Tim3;
+//! # struct Handlers { tim3: extern "C" fn(Tim3), tim4: extern "C" fn(Tim3) }
+//! # const DEFAULT_HANDLERS: Handlers = Handlers { tim3: tim3, tim4: tim3 };
+//! extern "C" fn tim3(ctxt: Tim3) { /* .. */ }
+//!
+//! // override the TIM3 interrupt handler
+//! #[no_mangle]
+//! static _INTERRUPTS: Handlers = Handlers {
+//! tim3: tim3, ..DEFAULT_HANDLERS
+//! };
+//! ```
+//!
+//! This pattern is implemented for exceptions in this crate. See
+//! `exception::Handlers` and `exception::DEFAULT_HANDLERS`.
+
+use core::marker::PhantomData;
+use core::cell::UnsafeCell;
+
+/// Data local to a context
+pub struct Local<T, Ctxt>
+where
+ Ctxt: Context,
+{
+ _ctxt: PhantomData<Ctxt>,
+ data: UnsafeCell<T>,
+}
+
+impl<T, Ctxt> Local<T, Ctxt>
+where
+ Ctxt: Context,
+{
+ /// Initializes context local data
+ pub const fn new(value: T) -> Self {
+ Local {
+ _ctxt: PhantomData,
+ data: UnsafeCell::new(value),
+ }
+ }
+
+ /// Acquires a reference to the context local data
+ pub fn borrow<'ctxt>(&'static self, _ctxt: &'ctxt Ctxt) -> &'ctxt T {
+ unsafe { &*self.data.get() }
+ }
+
+ /// Acquires a mutable reference to the context local data
+ pub fn borrow_mut<'ctxt>(
+ &'static self,
+ _ctxt: &'ctxt mut Ctxt,
+ ) -> &'ctxt mut T {
+ unsafe { &mut *self.data.get() }
+ }
+}
+
+unsafe impl<T, Ctxt> Sync for Local<T, Ctxt>
+where
+ Ctxt: Context,
+{
+}
+
+/// A token unique to a context
+pub unsafe trait Context {}