rtic/macros/src/check.rs

101 lines
3.1 KiB
Rust
Raw Normal View History

use std::collections::HashSet;
2018-11-03 17:02:41 +01:00
use proc_macro2::Span;
2020-10-23 10:35:56 +02:00
use rtic_syntax::{analyze::Analysis, ast::App};
use syn::{parse, Path};
2020-10-23 10:35:56 +02:00
pub struct Extra {
pub device: Path,
pub monotonic: Option<Path>,
2020-08-27 13:21:56 +02:00
pub peripherals: bool,
}
2020-10-23 10:35:56 +02:00
pub fn app(app: &App, _analysis: &Analysis) -> parse::Result<Extra> {
2020-09-01 19:04:55 +02:00
// Check that external (device-specific) interrupts are not named after known (Cortex-M)
// exceptions
2020-10-23 10:35:56 +02:00
for name in app.args.extern_interrupts.keys() {
let name_s = name.to_string();
match &*name_s {
"NonMaskableInt" | "HardFault" | "MemoryManagement" | "BusFault" | "UsageFault"
| "SecureFault" | "SVCall" | "DebugMonitor" | "PendSV" | "SysTick" => {
return Err(parse::Error::new(
name.span(),
"Cortex-M exceptions can't be used as `extern` interrupts",
));
}
_ => {}
}
}
2020-09-01 19:04:55 +02:00
// Check that there are enough external interrupts to dispatch the software tasks and the timer
// queue handler
2020-08-27 13:21:56 +02:00
let mut first = None;
let priorities = app
.software_tasks
.iter()
2020-10-13 16:16:33 +02:00
.map(|(name, task)| {
2020-08-27 13:21:56 +02:00
first = Some(name);
2020-10-13 16:16:33 +02:00
task.args.priority
2020-08-27 13:21:56 +02:00
})
.collect::<HashSet<_>>();
let need = priorities.len();
2020-10-23 10:35:56 +02:00
let given = app.args.extern_interrupts.len();
2020-08-27 13:21:56 +02:00
if need > given {
let s = {
format!(
2020-10-23 10:35:56 +02:00
"not enough interrupts to dispatch \
2020-08-27 13:21:56 +02:00
all software tasks (need: {}; given: {})",
need, given
)
};
// If not enough tasks and first still is None, may cause
2020-09-01 19:04:55 +02:00
// "custom attribute panicked" due to unwrap on None
2020-08-27 13:21:56 +02:00
return Err(parse::Error::new(first.unwrap().span(), &s));
2018-11-03 17:02:41 +01:00
}
2020-10-11 18:38:38 +02:00
// Check that all exceptions are valid; only exceptions with configurable priorities are
// accepted
for (name, task) in &app.hardware_tasks {
let name_s = task.args.binds.to_string();
match &*name_s {
"SysTick" => {
// If the timer queue is used, then SysTick is unavailable
2020-10-23 10:35:56 +02:00
if app.args.monotonic.is_some() {
2020-10-11 18:38:38 +02:00
return Err(parse::Error::new(
name.span(),
"this exception can't be used because it's being used by the runtime",
));
} else {
// OK
}
}
"NonMaskableInt" | "HardFault" => {
return Err(parse::Error::new(
name.span(),
"only exceptions with configurable priority can be used as hardware tasks",
));
}
_ => {}
}
2018-11-03 17:02:41 +01:00
}
2020-10-23 10:35:56 +02:00
if let Some(device) = app.args.device.clone() {
Ok(Extra {
device,
2020-10-23 10:35:56 +02:00
monotonic: app.args.monotonic.clone(),
peripherals: app.args.peripherals,
})
} else {
Err(parse::Error::new(
Span::call_site(),
2020-06-11 19:18:29 +02:00
"a `device` argument must be specified in `#[rtic::app]`",
))
2018-11-03 17:02:41 +01:00
}
2017-07-04 18:26:11 +02:00
}