riot_wrappers/interrupt.rs
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
//! Interaction with interrupts
//!
//! The RIOT wrappers offer two ways to interact with interrupts:
//!
//! * Utility functions can disable interrupts (creating critical sections), check whether
//! interrupts are enabled or to determine whether code is executed in a thread or an ISR.
//!
//! * Some functions (eg. [set_during](crate::thread::ValueInThread<crate::ztimer::Clock>::set_during))
//! take callbacks that will be called in an interrupt context.
//!
//! These are typechecked to be Send, as they are moved from the thread to the interrupt context.
//!
//! Not provided by riot-wrappers are methods of implementing interrupts that are directly called
//! by the CPU's interrupt mechanism. These are `extern "C"` functions (often with a `() -> ()`
//! signature) exported under a particular name using `#[no_mangle]`. Any platform specifics (such
//! as the [`riot_sys::inline::cortexm_isr_end()`] function) need to be managed by the
//! implementer, just as when implementing a C interrupt.
//!
//! Rust code intended for use within interrupts does not generally need special precautions -- but
//! several functions (generally, anything that blocks) are discouraged (as they may fail or stall
//! the system) outside of a thread context, or even "forbidden" (because they reliably lock up the
//! system, such as [crate::mutex::Mutex::lock()]). These functions often have preferred
//! alternatives that can be statically known to be executed in a thread context by keeping a copy
//! of [`crate::thread::InThread`].
/// Trivial safe wrapper for
/// [`irq_is_in`](https://doc.riot-os.org/group__core__irq.html#ga83decbeef665d955290f730125ef0e3f)
///
/// Returns true when called from an interrupt service routine
pub(crate) fn irq_is_in() -> bool {
unsafe { riot_sys::irq_is_in() }
}
/// Trivial safe wrapper for
/// [`irq_is_enabled`](https://doc.riot-os.org/group__core__irq.html#ga7fa965063ff2f4f4cea34f1c2a8fac25)
///
/// Returns true if interrupts are currently enabled
///
/// Note that this only returns reliable values when called from a thread context.
pub(crate) fn irq_is_enabled() -> bool {
unsafe { riot_sys::irq_is_enabled() }
}
impl crate::thread::InThread {
/// Trivial safe wrapper for
/// [`irq_is_enabled`](https://doc.riot-os.org/group__core__irq.html#ga7fa965063ff2f4f4cea34f1c2a8fac25)
///
/// Returns true if interrupts are currently enabled
///
/// Using this on an `InThread` token is preferred over the global function, as the function
/// only returns reliable values when called from a thread context.
pub fn irq_is_enabled(self) -> bool {
irq_is_enabled()
}
}
/// Proof of running inside a critical section. Reexported from the [bare_metal] crate.
pub use bare_metal::CriticalSection;
/// Run a closure in the current context, but with interrupts disabled.
///
/// The function gets passed a [`bare_metal::CriticalSection`] attesting to the fact that
/// interrupts are off.
///
/// This is equivalent to the [cortex_m crate function of the same
/// name](https://docs.rs/cortex-m/latest/cortex_m/interrupt/fn.free.html).
#[doc(alias = "irq_disable")]
pub fn free<R, F: FnOnce(&CriticalSection) -> R>(f: F) -> R {
let stored = unsafe { riot_sys::irq_disable() };
let cs = unsafe { CriticalSection::new() };
let ret = f(&cs);
unsafe { riot_sys::irq_restore(stored) };
ret
}