cortex_m_rtic_macros/
check.rs
1use std::collections::HashSet;
2
3use proc_macro2::Span;
4use rtic_syntax::{analyze::Analysis, ast::App};
5use syn::{parse, Path};
6
7pub struct Extra {
8 pub device: Path,
9 pub peripherals: bool,
10}
11
12pub fn app(app: &App, _analysis: &Analysis) -> parse::Result<Extra> {
13 for name in app.args.extern_interrupts.keys() {
16 let name_s = name.to_string();
17
18 match &*name_s {
19 "NonMaskableInt" | "HardFault" | "MemoryManagement" | "BusFault" | "UsageFault"
20 | "SecureFault" | "SVCall" | "DebugMonitor" | "PendSV" | "SysTick" => {
21 return Err(parse::Error::new(
22 name.span(),
23 "Cortex-M exceptions can't be used as `extern` interrupts",
24 ));
25 }
26
27 _ => {}
28 }
29 }
30
31 let mut first = None;
34 let priorities = app
35 .software_tasks
36 .iter()
37 .map(|(name, task)| {
38 first = Some(name);
39 task.args.priority
40 })
41 .collect::<HashSet<_>>();
42
43 let need = priorities.len();
44 let given = app.args.extern_interrupts.len();
45 if need > given {
46 let s = {
47 format!(
48 "not enough interrupts to dispatch \
49 all software tasks (need: {}; given: {})",
50 need, given
51 )
52 };
53
54 return Err(parse::Error::new(first.unwrap().span(), s));
57 }
58
59 for (name, task) in &app.hardware_tasks {
62 let name_s = task.args.binds.to_string();
63 match &*name_s {
64 "NonMaskableInt" | "HardFault" => {
65 return Err(parse::Error::new(
66 name.span(),
67 "only exceptions with configurable priority can be used as hardware tasks",
68 ));
69 }
70
71 _ => {}
72 }
73 }
74
75 if let Some(device) = app.args.device.clone() {
76 Ok(Extra {
77 device,
78 peripherals: app.args.peripherals,
79 })
80 } else {
81 Err(parse::Error::new(
82 Span::call_site(),
83 "a `device` argument must be specified in `#[rtic::app]`",
84 ))
85 }
86}