1use crate::{Mcu, pac::interrupt};
2use alloc::boxed::Box;
3use core::cell::{Cell, OnceCell};
4
5pub struct Callback {
6 callback: OnceCell<Cell<Box<dyn FnMut()>>>,
7 it_line: interrupt,
8}
9
10unsafe impl Sync for Callback {}
11
12impl Callback {
16 pub const fn new(it_line: interrupt) -> Self {
17 Self {
18 callback: OnceCell::new(),
19 it_line,
20 }
21 }
22
23 pub fn set(&self, mcu: &mut Mcu, callback: impl FnMut() + 'static) {
26 let cb = Cell::new(Box::new(callback));
27 critical_section::with(|_| {
28 assert!(self.callback.set(cb).is_ok());
29 });
30 mcu.nvic.enable(self.it_line, true);
31 }
32
33 pub unsafe fn call(&self) {
34 if let Some(cb) = self.callback.get() {
35 unsafe { (*cb.as_ptr())() }
36 }
37 }
38}
39
40#[macro_export]
41macro_rules! interrupt_handler {
42 ($(
43 ($LINE:ident, $CALLBACK:ident),
44 )+) => {$(
45 pub static $CALLBACK: $crate::interrupt::Callback =
46 $crate::interrupt::Callback::new($crate::pac::interrupt::$LINE);
47
48 #[allow(non_snake_case)]
49 #[interrupt]
50 fn $LINE() {
51 unsafe { $CALLBACK.call() }
52 }
53 )+};
54}