1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 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 {}