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
#![doc(html_root_url = "https://docs.rs/ruspiro-interrupt-macros/0.2.2")]
extern crate proc_macro;
extern crate quote;
extern crate syn;
use proc_macro::*;
use quote::quote;
use syn::*;
#[proc_macro_attribute]
#[allow(non_snake_case)]
pub fn IrqHandler(attr: TokenStream, item: TokenStream) -> TokenStream {
println!("implement handler for IRQ: \"{}\"", attr.to_string());
let func = parse_macro_input!(item as ItemFn);
let args: AttributeArgs = parse_macro_input!(attr as AttributeArgs);
let irq_name = match args.get(0) {
Some(NestedMeta::Meta(Meta::Path(meta))) => &meta.segments.first().unwrap().ident,
_ => {
return quote! {
compile_error!("interrupt identifier missing in `#[IrqHandler(identifier)`");
}
.into();
}
};
let valid_common_signature = func.sig.constness.is_none()
&& func.vis == Visibility::Inherited
&& func.sig.abi.is_none()
&& func.sig.generics.params.is_empty()
&& func.sig.generics.where_clause.is_none()
&& func.sig.variadic.is_none()
&& match func.sig.output {
ReturnType::Default => true,
_ => false,
};
let irq_id_s = irq_name.to_string();
let irq_func_suffix = match &*irq_id_s {
"Aux" => {
let aux_source = match args.get(1) {
Some(NestedMeta::Meta(Meta::Path(meta))) => meta,
_=> {
return quote! {
compile_error!("`Aux` interrupt source missing in `#[IrqHandler(Aux, <SOURCE>)`. <SOURCE> could be one of: `Uart1` | `Spi1` | `Spi2`.");
}.into()
}
};
let aux_source_s = aux_source.segments.first().unwrap().ident.to_string();
if &*aux_source_s != "Uart1" && &*aux_source_s != "Spi1" && &*aux_source_s != "Spi2" {
return quote! { compile_error!("Wrong source for `Aux` interrupt in `#[IrqHandler(Aux, <SOURCE>)`. <SOURCE> could be one of: `Uart1` | `Spi1` | `Spi2`.");
}.into();
}
let valid_signature = valid_common_signature;
if !valid_signature {
return quote! {
compile_error!("interrupt handler must have signature `[unsafe] fn(tx: IsrSender(Box<dyn Any>))`");
}.into();
}
format!("{}_{}", irq_name.to_string(), aux_source_s)
}
_ => {
let valid_signature = valid_common_signature;
if !valid_signature {
return quote! {
compile_error!("interrupt handler must have signature `[unsafe] fn(tx: IsrSender(Box<dyn Any>)))`");
}.into();
}
irq_name.to_string()
}
};
let ident = func.sig.ident;
let attrs = func.attrs;
let block = func.block;
let stmts = block.stmts;
let irq_name_s = format!("__irq_handler__{}", irq_func_suffix);
return quote!(
#[allow(non_snake_case)]
#[export_name = #irq_name_s]
#(#attrs)*
#[no_mangle]
pub unsafe extern "C" fn #ident(tx: Option<ruspiro_interrupt::IsrSender<crate::alloc::boxed::Box<dyn Any>>>) {
ruspiro_interrupt::Interrupt::#irq_name;
#(#stmts)*
}
)
.into();
}