rtic/macros/src/codegen/module.rs

218 lines
5.7 KiB
Rust
Raw Normal View History

use crate::syntax::{ast::App, Context};
use crate::{analyze::Analysis, codegen::util};
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
2022-02-18 19:38:48 +01:00
#[allow(clippy::too_many_lines)]
2020-10-05 21:57:44 +02:00
pub fn codegen(
ctxt: Context,
2021-07-07 21:03:56 +02:00
shared_resources_tick: bool,
local_resources_tick: bool,
2020-10-05 21:57:44 +02:00
app: &App,
analysis: &Analysis,
) -> TokenStream2 {
let mut items = vec![];
2021-05-06 19:40:37 +02:00
let mut module_items = vec![];
let mut fields = vec![];
let mut values = vec![];
// Used to copy task cfgs to the whole module
let mut task_cfgs = vec![];
let name = ctxt.ident(app);
let mut lt = None;
match ctxt {
2020-08-27 13:21:56 +02:00
Context::Init => {
2020-12-10 20:33:13 +01:00
fields.push(quote!(
/// Core (Cortex-M) peripherals
pub core: rtic::export::Peripherals
));
if app.args.peripherals {
let device = &app.args.device;
fields.push(quote!(
/// Device peripherals
pub device: #device::Peripherals
));
values.push(quote!(device: #device::Peripherals::steal()));
}
lt = Some(quote!('a));
fields.push(quote!(
/// Critical section token for init
pub cs: rtic::export::CriticalSection<#lt>
));
values.push(quote!(cs: rtic::export::CriticalSection::new()));
values.push(quote!(core));
}
2022-02-18 19:38:48 +01:00
Context::Idle | Context::HardwareTask(_) | Context::SoftwareTask(_) => {}
}
2021-07-06 22:47:48 +02:00
if ctxt.has_local_resources(app) {
let ident = util::local_resources_ident(ctxt, app);
2021-07-07 21:03:56 +02:00
let lt = if local_resources_tick {
2021-07-06 22:47:48 +02:00
lt = Some(quote!('a));
Some(quote!('a))
} else {
None
};
2021-05-06 19:40:37 +02:00
module_items.push(quote!(
#[doc(inline)]
2021-07-06 22:47:48 +02:00
pub use super::#ident as LocalResources;
));
2021-07-06 22:47:48 +02:00
fields.push(quote!(
/// Local Resources this task has access to
pub local: #name::LocalResources<#lt>
));
values.push(quote!(local: #name::LocalResources::new()));
}
2021-07-06 22:47:48 +02:00
if ctxt.has_shared_resources(app) {
let ident = util::shared_resources_ident(ctxt, app);
2021-07-07 21:03:56 +02:00
let lt = if shared_resources_tick {
lt = Some(quote!('a));
Some(quote!('a))
} else {
None
};
2021-05-06 19:40:37 +02:00
module_items.push(quote!(
#[doc(inline)]
2021-07-06 22:47:48 +02:00
pub use super::#ident as SharedResources;
));
fields.push(quote!(
2021-07-06 22:47:48 +02:00
/// Shared Resources this task has access to
pub shared: #name::SharedResources<#lt>
));
let priority = if ctxt.is_init() {
None
} else {
Some(quote!(priority))
};
2021-07-06 22:47:48 +02:00
values.push(quote!(shared: #name::SharedResources::new(#priority)));
}
let doc = match ctxt {
Context::Idle => "Idle loop",
Context::Init => "Initialization function",
Context::HardwareTask(_) => "Hardware task",
Context::SoftwareTask(_) => "Software task",
};
2021-05-06 19:40:37 +02:00
let v = Vec::new();
let cfgs = match ctxt {
2023-01-04 20:29:16 +01:00
Context::HardwareTask(t) => &app.hardware_tasks[t].cfgs,
Context::SoftwareTask(t) => &app.software_tasks[t].cfgs,
2021-05-06 19:40:37 +02:00
_ => &v,
};
let core = if ctxt.is_init() {
2020-12-08 20:49:13 +01:00
Some(quote!(core: rtic::export::Peripherals,))
} else {
None
};
let priority = if ctxt.is_init() {
None
} else {
2020-06-11 19:18:29 +02:00
Some(quote!(priority: &#lt rtic::export::Priority))
};
2021-05-06 19:40:37 +02:00
let internal_context_name = util::internal_task_ident(name, "Context");
items.push(quote!(
#(#cfgs)*
/// Execution context
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
2021-05-06 19:40:37 +02:00
pub struct #internal_context_name<#lt> {
#(#fields,)*
}
2021-05-06 19:40:37 +02:00
#(#cfgs)*
impl<#lt> #internal_context_name<#lt> {
#[inline(always)]
2020-12-10 20:33:13 +01:00
pub unsafe fn new(#core #priority) -> Self {
2021-05-06 19:40:37 +02:00
#internal_context_name {
#(#values,)*
}
}
}
));
2021-05-06 19:40:37 +02:00
module_items.push(quote!(
#(#cfgs)*
#[doc(inline)]
2021-05-06 19:40:37 +02:00
pub use super::#internal_context_name as Context;
));
2020-10-05 21:57:44 +02:00
if let Context::SoftwareTask(..) = ctxt {
let spawnee = &app.software_tasks[name];
let priority = spawnee.args.priority;
let cfgs = &spawnee.cfgs;
// Store a copy of the task cfgs
task_cfgs = cfgs.clone();
2020-10-05 21:57:44 +02:00
let device = &app.args.device;
2020-10-05 21:57:44 +02:00
let enum_ = util::interrupt_ident();
2023-01-03 15:10:59 +01:00
let interrupt = &analysis
.interrupts
.get(&priority)
.expect("RTIC-ICE: interrupt identifer not found")
.0;
2020-10-05 21:57:44 +02:00
2021-05-06 19:40:37 +02:00
let internal_spawn_ident = util::internal_task_ident(name, "spawn");
2020-10-11 18:38:38 +02:00
// Spawn caller
2023-01-03 15:10:59 +01:00
let rq = util::rq_async_ident(name);
items.push(quote!(
2020-10-05 21:57:44 +02:00
2023-01-03 15:10:59 +01:00
#(#cfgs)*
/// Spawns the task directly
#[allow(non_snake_case)]
#[doc(hidden)]
pub fn #internal_spawn_ident() -> Result<(), ()> {
unsafe {
let r = rtic::export::interrupt::free(|_| (&mut *#rq.get_mut()).enqueue(()));
2020-10-05 21:57:44 +02:00
2023-01-03 15:10:59 +01:00
if r.is_ok() {
rtic::pend(#device::#enum_::#interrupt);
}
2020-10-05 21:57:44 +02:00
2023-01-03 15:10:59 +01:00
r
}
}));
2020-10-11 18:38:38 +02:00
2021-05-06 19:40:37 +02:00
module_items.push(quote!(
#(#cfgs)*
#[doc(inline)]
2021-05-06 19:40:37 +02:00
pub use super::#internal_spawn_ident as spawn;
));
2020-10-05 21:57:44 +02:00
}
2022-02-18 19:38:48 +01:00
if items.is_empty() {
quote!()
} else {
quote!(
2021-05-06 19:40:37 +02:00
#(#items)*
#[allow(non_snake_case)]
#(#task_cfgs)*
#[doc = #doc]
pub mod #name {
2021-05-06 19:40:37 +02:00
#(#module_items)*
}
)
}
}