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
//! 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. [`ZTimer::set_ticks_during`](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
#[deprecated(note = "Use crate::thread::InThread::new() instead")]
pub 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.
#[deprecated(note = "use crate::thread::InThread::irq_is_enabled() instead")]
pub 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 {
unsafe { riot_sys::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
}
/// Wrap a Rust interrupt handler in an extern "C" wrapper that does the post-return cleaups.
///
/// As with all code executed in interrupt contexts, the wrapped function should not panic.
///
/// ## Caveats
///
/// This is Cortex-M specific.
#[deprecated(
note = "See module documentation: This needs to be done manually per platform; it is incomplete as riot-wrappers provides no method of enabling platform specific interrupts, and provides no other access to configure the peripheral through registers. If it is re-introduced, it will likely carry an `InIsr` token into the function."
)]
#[macro_export]
macro_rules! interrupt {
($isr_name:ident, $rust_handler:expr) => {
#[no_mangle]
pub extern "C" fn $isr_name() -> () {
$rust_handler();
unsafe { riot_sys::inline::cortexm_isr_end() };
}
};
}