2019-06-13 23:56:59 +02:00
|
|
|
use proc_macro2::TokenStream as TokenStream2;
|
|
|
|
use quote::quote;
|
2020-06-11 19:18:29 +02:00
|
|
|
use rtic_syntax::{ast::App, Context};
|
2019-06-13 23:56:59 +02:00
|
|
|
|
2020-10-05 21:57:44 +02:00
|
|
|
use crate::{analyze::Analysis, check::Extra, codegen::util};
|
|
|
|
|
|
|
|
pub fn codegen(
|
|
|
|
ctxt: Context,
|
|
|
|
resources_tick: bool,
|
|
|
|
app: &App,
|
|
|
|
analysis: &Analysis,
|
|
|
|
extra: &Extra,
|
|
|
|
) -> TokenStream2 {
|
2019-06-13 23:56:59 +02:00
|
|
|
let mut items = vec![];
|
|
|
|
let mut fields = vec![];
|
|
|
|
let mut values = vec![];
|
2020-10-16 10:20:43 +02:00
|
|
|
// Used to copy task cfgs to the whole module
|
|
|
|
let mut task_cfgs = vec![];
|
2019-06-13 23:56:59 +02:00
|
|
|
|
|
|
|
let name = ctxt.ident(app);
|
|
|
|
|
|
|
|
let mut needs_instant = false;
|
|
|
|
let mut lt = None;
|
|
|
|
match ctxt {
|
2020-08-27 13:21:56 +02:00
|
|
|
Context::Init => {
|
2020-10-23 10:35:56 +02:00
|
|
|
if let Some(m) = &extra.monotonic {
|
2019-06-13 23:56:59 +02:00
|
|
|
fields.push(quote!(
|
|
|
|
/// System start time = `Instant(0 /* cycles */)`
|
2020-06-11 19:18:29 +02:00
|
|
|
pub start: <#m as rtic::Monotonic>::Instant
|
2019-06-13 23:56:59 +02:00
|
|
|
));
|
|
|
|
|
2020-06-11 19:18:29 +02:00
|
|
|
values.push(quote!(start: <#m as rtic::Monotonic>::zero()));
|
2019-06-13 23:56:59 +02:00
|
|
|
|
|
|
|
fields.push(quote!(
|
|
|
|
/// Core (Cortex-M) peripherals minus the SysTick
|
2020-06-11 19:18:29 +02:00
|
|
|
pub core: rtic::Peripherals
|
2019-06-13 23:56:59 +02:00
|
|
|
));
|
|
|
|
} else {
|
|
|
|
fields.push(quote!(
|
|
|
|
/// Core (Cortex-M) peripherals
|
2020-06-11 19:18:29 +02:00
|
|
|
pub core: rtic::export::Peripherals
|
2019-06-13 23:56:59 +02:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2020-08-27 13:21:56 +02:00
|
|
|
if extra.peripherals {
|
2020-10-23 10:35:56 +02:00
|
|
|
let device = &extra.device;
|
2019-06-13 23:56:59 +02:00
|
|
|
|
|
|
|
fields.push(quote!(
|
|
|
|
/// Device peripherals
|
|
|
|
pub device: #device::Peripherals
|
|
|
|
));
|
|
|
|
|
|
|
|
values.push(quote!(device: #device::Peripherals::steal()));
|
|
|
|
}
|
|
|
|
|
2020-10-01 20:01:25 +02:00
|
|
|
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()));
|
|
|
|
|
2019-06-13 23:56:59 +02:00
|
|
|
values.push(quote!(core));
|
|
|
|
}
|
|
|
|
|
2020-08-27 13:21:56 +02:00
|
|
|
Context::Idle => {}
|
2019-06-13 23:56:59 +02:00
|
|
|
|
|
|
|
Context::HardwareTask(..) => {
|
2020-10-23 10:35:56 +02:00
|
|
|
if let Some(m) = &extra.monotonic {
|
2019-06-13 23:56:59 +02:00
|
|
|
fields.push(quote!(
|
|
|
|
/// Time at which this handler started executing
|
2020-06-11 19:18:29 +02:00
|
|
|
pub start: <#m as rtic::Monotonic>::Instant
|
2019-06-13 23:56:59 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
values.push(quote!(start: instant));
|
|
|
|
|
|
|
|
needs_instant = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Context::SoftwareTask(..) => {
|
2020-10-23 10:35:56 +02:00
|
|
|
if let Some(m) = &extra.monotonic {
|
2019-06-13 23:56:59 +02:00
|
|
|
fields.push(quote!(
|
|
|
|
/// The time at which this task was scheduled to run
|
2020-06-11 19:18:29 +02:00
|
|
|
pub scheduled: <#m as rtic::Monotonic>::Instant
|
2019-06-13 23:56:59 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
values.push(quote!(scheduled: instant));
|
|
|
|
|
|
|
|
needs_instant = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ctxt.has_locals(app) {
|
|
|
|
let ident = util::locals_ident(ctxt, app);
|
|
|
|
items.push(quote!(
|
|
|
|
#[doc(inline)]
|
|
|
|
pub use super::#ident as Locals;
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ctxt.has_resources(app) {
|
|
|
|
let ident = util::resources_ident(ctxt, app);
|
|
|
|
let lt = if resources_tick {
|
|
|
|
lt = Some(quote!('a));
|
|
|
|
Some(quote!('a))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
items.push(quote!(
|
|
|
|
#[doc(inline)]
|
|
|
|
pub use super::#ident as Resources;
|
|
|
|
));
|
|
|
|
|
|
|
|
fields.push(quote!(
|
|
|
|
/// Resources this task has access to
|
|
|
|
pub resources: Resources<#lt>
|
|
|
|
));
|
|
|
|
|
|
|
|
let priority = if ctxt.is_init() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(quote!(priority))
|
|
|
|
};
|
|
|
|
values.push(quote!(resources: Resources::new(#priority)));
|
|
|
|
}
|
|
|
|
|
2020-08-27 13:21:56 +02:00
|
|
|
if let Context::Init = ctxt {
|
2020-09-01 18:12:42 +02:00
|
|
|
let init = &app.inits.first().unwrap();
|
2020-10-01 19:38:49 +02:00
|
|
|
let late_resources = util::late_resources_ident(&init.name);
|
2019-06-13 23:56:59 +02:00
|
|
|
|
2020-10-01 19:38:49 +02:00
|
|
|
items.push(quote!(
|
|
|
|
#[doc(inline)]
|
|
|
|
pub use super::#late_resources as LateResources;
|
|
|
|
));
|
2019-06-13 23:56:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
let doc = match ctxt {
|
2020-08-27 13:21:56 +02:00
|
|
|
Context::Idle => "Idle loop",
|
|
|
|
Context::Init => "Initialization function",
|
2019-06-13 23:56:59 +02:00
|
|
|
Context::HardwareTask(_) => "Hardware task",
|
|
|
|
Context::SoftwareTask(_) => "Software task",
|
|
|
|
};
|
|
|
|
|
|
|
|
let core = if ctxt.is_init() {
|
2020-10-11 18:38:38 +02:00
|
|
|
if extra.monotonic.is_some() {
|
2020-06-11 19:18:29 +02:00
|
|
|
Some(quote!(core: rtic::Peripherals,))
|
2019-06-13 23:56:59 +02:00
|
|
|
} else {
|
2020-06-11 19:18:29 +02:00
|
|
|
Some(quote!(core: rtic::export::Peripherals,))
|
2019-06-13 23:56:59 +02:00
|
|
|
}
|
|
|
|
} 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))
|
2019-06-13 23:56:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
let instant = if needs_instant {
|
2020-10-23 10:35:56 +02:00
|
|
|
let m = extra.monotonic.clone().expect("RTIC-ICE: UNREACHABLE");
|
2019-06-13 23:56:59 +02:00
|
|
|
|
2020-06-11 19:18:29 +02:00
|
|
|
Some(quote!(, instant: <#m as rtic::Monotonic>::Instant))
|
2019-06-13 23:56:59 +02:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
items.push(quote!(
|
|
|
|
/// Execution context
|
|
|
|
pub struct Context<#lt> {
|
|
|
|
#(#fields,)*
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<#lt> Context<#lt> {
|
|
|
|
#[inline(always)]
|
|
|
|
pub unsafe fn new(#core #priority #instant) -> Self {
|
|
|
|
Context {
|
|
|
|
#(#values,)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
));
|
|
|
|
|
2020-10-05 21:57:44 +02:00
|
|
|
// not sure if this is the right way, maybe its backwards,
|
|
|
|
// that spawn_module should put in in root
|
|
|
|
|
|
|
|
if let Context::SoftwareTask(..) = ctxt {
|
|
|
|
let spawnee = &app.software_tasks[name];
|
|
|
|
let priority = spawnee.args.priority;
|
|
|
|
let t = util::spawn_t_ident(priority);
|
|
|
|
let cfgs = &spawnee.cfgs;
|
2020-10-16 10:20:43 +02:00
|
|
|
// Store a copy of the task cfgs
|
|
|
|
task_cfgs = cfgs.clone();
|
2020-10-05 21:57:44 +02:00
|
|
|
let (args, tupled, _untupled, ty) = util::regroup_inputs(&spawnee.inputs);
|
|
|
|
let args = &args;
|
|
|
|
let tupled = &tupled;
|
|
|
|
let fq = util::fq_ident(name);
|
|
|
|
let rq = util::rq_ident(priority);
|
|
|
|
let inputs = util::inputs_ident(name);
|
|
|
|
|
|
|
|
let app_name = &app.name;
|
|
|
|
let app_path = quote! {crate::#app_name};
|
|
|
|
|
2020-10-23 10:35:56 +02:00
|
|
|
let device = &extra.device;
|
2020-10-05 21:57:44 +02:00
|
|
|
let enum_ = util::interrupt_ident();
|
2020-10-23 10:35:56 +02:00
|
|
|
let interrupt = &analysis
|
|
|
|
.interrupts
|
|
|
|
.get(&priority)
|
|
|
|
.expect("RTIC-ICE: interrupt identifer not found")
|
|
|
|
.0;
|
2020-10-05 21:57:44 +02:00
|
|
|
|
2020-10-11 18:38:38 +02:00
|
|
|
// Spawn caller
|
2020-10-05 21:57:44 +02:00
|
|
|
items.push(quote!(
|
|
|
|
#(#cfgs)*
|
|
|
|
pub fn spawn(#(#args,)*) -> Result<(), #ty> {
|
|
|
|
// #let_instant // do we need it?
|
|
|
|
use rtic::Mutex as _;
|
|
|
|
|
|
|
|
let input = #tupled;
|
2020-10-08 17:33:16 +02:00
|
|
|
|
2020-10-11 18:38:38 +02:00
|
|
|
unsafe {
|
|
|
|
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
|
2020-10-05 21:57:44 +02:00
|
|
|
#app_path::#inputs
|
|
|
|
.get_unchecked_mut(usize::from(index))
|
|
|
|
.as_mut_ptr()
|
|
|
|
.write(input);
|
|
|
|
|
2020-10-11 18:38:38 +02:00
|
|
|
rtic::export::interrupt::free(|_| {
|
|
|
|
#app_path::#rq.enqueue_unchecked((#app_path::#t::#name, index));
|
|
|
|
});
|
2020-10-05 21:57:44 +02:00
|
|
|
|
2020-10-11 18:38:38 +02:00
|
|
|
rtic::pend(#device::#enum_::#interrupt);
|
2020-10-05 21:57:44 +02:00
|
|
|
|
2020-10-11 18:38:38 +02:00
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(input)
|
|
|
|
}
|
2020-10-05 21:57:44 +02:00
|
|
|
}
|
2020-10-08 17:33:16 +02:00
|
|
|
|
2020-10-05 21:57:44 +02:00
|
|
|
}));
|
2020-10-11 18:38:38 +02:00
|
|
|
|
|
|
|
// Schedule caller
|
2020-10-23 10:35:56 +02:00
|
|
|
if let Some(m) = &extra.monotonic {
|
2020-10-11 18:38:38 +02:00
|
|
|
let instants = util::instants_ident(name);
|
|
|
|
|
|
|
|
let tq = util::tq_ident();
|
|
|
|
let t = util::schedule_t_ident();
|
|
|
|
|
|
|
|
items.push(quote!(
|
|
|
|
#(#cfgs)*
|
|
|
|
pub fn schedule(
|
|
|
|
instant: <#m as rtic::Monotonic>::Instant
|
|
|
|
#(,#args)*
|
|
|
|
) -> Result<(), #ty> {
|
|
|
|
unsafe {
|
|
|
|
use rtic::Mutex as _;
|
|
|
|
|
|
|
|
let input = #tupled;
|
|
|
|
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
|
|
|
|
#app_path::#inputs
|
|
|
|
.get_unchecked_mut(usize::from(index))
|
|
|
|
.as_mut_ptr()
|
|
|
|
.write(input);
|
|
|
|
|
|
|
|
#app_path::#instants
|
|
|
|
.get_unchecked_mut(usize::from(index))
|
|
|
|
.as_mut_ptr()
|
|
|
|
.write(instant);
|
|
|
|
|
|
|
|
let nr = rtic::export::NotReady {
|
|
|
|
instant,
|
|
|
|
index,
|
|
|
|
task: #app_path::#t::#name,
|
|
|
|
};
|
|
|
|
|
|
|
|
rtic::export::interrupt::free(|_| #app_path::#tq.enqueue_unchecked(nr));
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(input)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
2020-10-05 21:57:44 +02:00
|
|
|
}
|
|
|
|
|
2019-06-13 23:56:59 +02:00
|
|
|
if !items.is_empty() {
|
2020-10-11 19:41:57 +02:00
|
|
|
let user_imports = &app.user_imports;
|
|
|
|
|
2019-06-13 23:56:59 +02:00
|
|
|
quote!(
|
|
|
|
#[allow(non_snake_case)]
|
2020-10-16 10:20:43 +02:00
|
|
|
#(#task_cfgs)*
|
2019-06-13 23:56:59 +02:00
|
|
|
#[doc = #doc]
|
|
|
|
pub mod #name {
|
2020-10-11 19:41:57 +02:00
|
|
|
#(
|
|
|
|
#[allow(unused_imports)]
|
|
|
|
#user_imports
|
|
|
|
)*
|
2019-06-13 23:56:59 +02:00
|
|
|
#(#items)*
|
|
|
|
}
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
quote!()
|
|
|
|
}
|
|
|
|
}
|