//! 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, 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, 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) {} //! #[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 where Ctxt: Context, { _ctxt: PhantomData, data: UnsafeCell, } impl Local 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 Sync for Local where Ctxt: Context, { } /// A token unique to a context pub unsafe trait Context {}