rtic/macros/src/codegen/util.rs

285 lines
7.9 KiB
Rust
Raw Normal View History

2019-06-29 09:11:42 +02:00
use core::sync::atomic::{AtomicUsize, Ordering};
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
2020-08-27 13:21:56 +02:00
use rtic_syntax::{ast::App, Context};
2019-08-20 15:11:24 +02:00
use syn::{Attribute, Ident, LitInt, PatType};
use crate::check::Extra;
const RTIC_INTERNAL: &str = "__rtic_internal";
/// Turns `capacity` into an unsuffixed integer literal
2021-04-03 19:30:34 +02:00
pub fn capacity_literal(capacity: usize) -> LitInt {
2019-08-20 15:11:24 +02:00
LitInt::new(&capacity.to_string(), Span::call_site())
}
/// Identifier for the free queue
2020-08-27 13:21:56 +02:00
pub fn fq_ident(task: &Ident) -> Ident {
mark_internal_name(&format!("{}_FQ", task.to_string()))
}
/// Generates a `Mutex` implementation
pub fn impl_mutex(
extra: &Extra,
cfgs: &[Attribute],
resources_prefix: bool,
name: &Ident,
ty: TokenStream2,
ceiling: u8,
ptr: TokenStream2,
) -> TokenStream2 {
let (path, priority) = if resources_prefix {
2021-07-06 22:47:48 +02:00
(quote!(shared_resources::#name), quote!(self.priority()))
} else {
(quote!(#name), quote!(self.priority))
};
2020-10-23 10:35:56 +02:00
let device = &extra.device;
quote!(
#(#cfgs)*
2020-06-11 19:18:29 +02:00
impl<'a> rtic::Mutex for #path<'a> {
type T = #ty;
#[inline(always)]
fn lock<RTIC_INTERNAL_R>(&mut self, f: impl FnOnce(&mut #ty) -> RTIC_INTERNAL_R) -> RTIC_INTERNAL_R {
/// Priority ceiling
const CEILING: u8 = #ceiling;
unsafe {
2020-06-11 19:18:29 +02:00
rtic::export::lock(
#ptr,
#priority,
CEILING,
#device::NVIC_PRIO_BITS,
f,
)
}
}
}
)
}
/// Generates an identifier for the `INPUTS` buffer (`spawn` & `schedule` API)
2020-08-27 13:21:56 +02:00
pub fn inputs_ident(task: &Ident) -> Ident {
mark_internal_name(&format!("{}_INPUTS", task))
}
/// Generates an identifier for the `INSTANTS` buffer (`schedule` API)
pub fn monotonic_instants_ident(task: &Ident, monotonic: &Ident) -> Ident {
mark_internal_name(&format!("{}_{}_INSTANTS", task, monotonic))
}
2020-08-27 13:21:56 +02:00
pub fn interrupt_ident() -> Ident {
2019-06-18 10:31:31 +02:00
let span = Span::call_site();
Ident::new("interrupt", span)
2019-06-18 10:31:31 +02:00
}
pub fn timer_queue_marker_ident() -> Ident {
mark_internal_name(&"TIMER_QUEUE_MARKER")
}
2019-06-20 06:19:59 +02:00
/// Whether `name` is an exception with configurable priority
pub fn is_exception(name: &Ident) -> bool {
let s = name.to_string();
2020-10-13 16:16:33 +02:00
matches!(
&*s,
"MemoryManagement"
| "BusFault"
| "UsageFault"
| "SecureFault"
| "SVCall"
| "DebugMonitor"
| "PendSV"
| "SysTick"
)
2019-06-20 06:19:59 +02:00
}
/// Mark a name as internal
pub fn mark_internal_name(name: &str) -> Ident {
Ident::new(&format!("{}_{}", RTIC_INTERNAL, name), Span::call_site())
}
2021-05-06 19:40:37 +02:00
/// Generate an internal identifier for monotonics
pub fn internal_monotonics_ident(task: &Ident, monotonic: &Ident, ident_name: &str) -> Ident {
mark_internal_name(&format!(
"{}_{}_{}",
task.to_string(),
monotonic.to_string(),
ident_name,
))
2021-05-06 19:40:37 +02:00
}
/// Generate an internal identifier for tasks
pub fn internal_task_ident(task: &Ident, ident_name: &str) -> Ident {
mark_internal_name(&format!("{}_{}", task.to_string(), ident_name))
2021-05-06 19:40:37 +02:00
}
2019-06-29 09:11:42 +02:00
fn link_section_index() -> usize {
static INDEX: AtomicUsize = AtomicUsize::new(0);
INDEX.fetch_add(1, Ordering::Relaxed)
}
// NOTE `None` means in shared memory
pub fn link_section_uninit() -> Option<TokenStream2> {
let section = format!(".uninit.rtic{}", link_section_index());
2019-06-29 09:11:42 +02:00
Some(quote!(#[link_section = #section]))
}
// Regroups the inputs of a task
//
// `inputs` could be &[`input: Foo`] OR &[`mut x: i32`, `ref y: i64`]
pub fn regroup_inputs(
2019-08-20 15:11:24 +02:00
inputs: &[PatType],
) -> (
// args e.g. &[`_0`], &[`_0: i32`, `_1: i64`]
Vec<TokenStream2>,
// tupled e.g. `_0`, `(_0, _1)`
TokenStream2,
// untupled e.g. &[`_0`], &[`_0`, `_1`]
Vec<TokenStream2>,
// ty e.g. `Foo`, `(i32, i64)`
TokenStream2,
) {
if inputs.len() == 1 {
let ty = &inputs[0].ty;
(
vec![quote!(_0: #ty)],
quote!(_0),
vec![quote!(_0)],
quote!(#ty),
)
} else {
let mut args = vec![];
let mut pats = vec![];
let mut tys = vec![];
for (i, input) in inputs.iter().enumerate() {
let i = Ident::new(&format!("_{}", i), Span::call_site());
let ty = &input.ty;
args.push(quote!(#i: #ty));
pats.push(quote!(#i));
tys.push(quote!(#ty));
}
let tupled = {
let pats = pats.clone();
quote!((#(#pats,)*))
};
let ty = quote!((#(#tys,)*));
(args, tupled, pats, ty)
}
}
2021-07-07 22:50:59 +02:00
/// Get the ident for the name of the task
pub fn get_task_name(ctxt: Context, app: &App) -> Ident {
let s = match ctxt {
Context::Init => app.init.name.to_string(),
Context::Idle => app.idle.as_ref().unwrap().name.to_string(),
Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
};
Ident::new(&s, Span::call_site())
}
2021-07-05 21:40:01 +02:00
/// Generates a pre-reexport identifier for the "shared resources" struct
pub fn shared_resources_ident(ctxt: Context, app: &App) -> Ident {
let mut s = match ctxt {
2021-07-05 21:40:01 +02:00
Context::Init => app.init.name.to_string(),
2021-07-06 22:47:48 +02:00
Context::Idle => app.idle.as_ref().unwrap().name.to_string(),
Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
};
2021-07-05 21:40:01 +02:00
s.push_str("SharedResources");
mark_internal_name(&s)
2021-07-05 21:40:01 +02:00
}
/// Generates a pre-reexport identifier for the "local resources" struct
pub fn local_resources_ident(ctxt: Context, app: &App) -> Ident {
let mut s = match ctxt {
Context::Init => app.init.name.to_string(),
2021-07-06 22:47:48 +02:00
Context::Idle => app.idle.as_ref().unwrap().name.to_string(),
2021-07-05 21:40:01 +02:00
Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
};
s.push_str("LocalResources");
mark_internal_name(&s)
}
/// Generates an identifier for a ready queue
///
2020-09-01 19:04:55 +02:00
/// There may be several task dispatchers, one for each priority level.
/// The ready queues are SPSC queues
2020-08-27 13:21:56 +02:00
pub fn rq_ident(priority: u8) -> Ident {
mark_internal_name(&format!("P{}_RQ", priority))
}
/// Generates an identifier for the `enum` of `schedule`-able tasks
2020-08-27 13:21:56 +02:00
pub fn schedule_t_ident() -> Ident {
2020-12-13 14:52:16 +01:00
Ident::new(&"SCHED_T", Span::call_site())
}
/// Generates an identifier for the `enum` of `spawn`-able tasks
///
/// This identifier needs the same structure as the `RQ` identifier because there's one ready queue
/// for each of these `T` enums
2020-08-27 13:21:56 +02:00
pub fn spawn_t_ident(priority: u8) -> Ident {
2020-09-01 16:39:05 +02:00
Ident::new(&format!("P{}_T", priority), Span::call_site())
}
2020-12-13 14:52:16 +01:00
/// Suffixed identifier
2020-08-27 13:21:56 +02:00
pub fn suffixed(name: &str) -> Ident {
2019-06-18 10:31:31 +02:00
let span = Span::call_site();
2020-08-27 13:21:56 +02:00
Ident::new(name, span)
2019-06-18 10:31:31 +02:00
}
/// Generates an identifier for a timer queue
2020-12-08 20:49:13 +01:00
pub fn tq_ident(name: &str) -> Ident {
mark_internal_name(&format!("TQ_{}", name))
}
2020-12-13 14:52:16 +01:00
2021-02-18 19:30:59 +01:00
/// Generates an identifier for monotonic timer storage
pub fn monotonic_ident(name: &str) -> Ident {
mark_internal_name(&format!("MONOTONIC_STORAGE_{}", name))
2021-02-18 19:30:59 +01:00
}
2021-07-06 22:47:48 +02:00
pub fn static_shared_resource_ident(name: &Ident) -> Ident {
mark_internal_name(&format!("shared_resource_{}", name.to_string()))
2021-07-06 22:47:48 +02:00
}
pub fn static_local_resource_ident(name: &Ident) -> Ident {
mark_internal_name(&format!("local_resource_{}", name.to_string()))
2021-07-07 22:50:59 +02:00
}
pub fn declared_static_local_resource_ident(name: &Ident, task_name: &Ident) -> Ident {
mark_internal_name(&format!(
"local_{}_{}",
task_name.to_string(),
name.to_string()
))
2021-07-06 22:47:48 +02:00
}
pub fn need_to_lock_ident(name: &Ident) -> Ident {
Ident::new(
&format!("{}_that_needs_to_be_locked", name.to_string()),
name.span(),
)
}
2020-12-13 14:52:16 +01:00
/// The name to get better RT flag errors
pub fn rt_err_ident() -> Ident {
Ident::new(
&"you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml",
Span::call_site(),
)
}