rtic/macros/src/codegen/module.rs

325 lines
8.9 KiB
Rust
Raw Normal View History

use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
2020-06-11 19:18:29 +02:00
use rtic_syntax::{ast::App, Context};
use crate::{check::Extra, codegen::util};
pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> TokenStream2 {
let mut items = vec![];
let mut fields = vec![];
let mut values = vec![];
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 => {
if app.uses_schedule() {
let m = extra.monotonic();
fields.push(quote!(
/// System start time = `Instant(0 /* cycles */)`
2020-06-11 19:18:29 +02:00
pub start: <#m as rtic::Monotonic>::Instant
));
2020-06-11 19:18:29 +02:00
values.push(quote!(start: <#m as rtic::Monotonic>::zero()));
fields.push(quote!(
/// Core (Cortex-M) peripherals minus the SysTick
2020-06-11 19:18:29 +02:00
pub core: rtic::Peripherals
));
} else {
fields.push(quote!(
/// Core (Cortex-M) peripherals
2020-06-11 19:18:29 +02:00
pub core: rtic::export::Peripherals
));
}
2020-08-27 13:21:56 +02:00
if extra.peripherals {
let device = extra.device;
fields.push(quote!(
/// Device peripherals
pub device: #device::Peripherals
));
values.push(quote!(device: #device::Peripherals::steal()));
}
values.push(quote!(core));
}
2020-08-27 13:21:56 +02:00
Context::Idle => {}
Context::HardwareTask(..) => {
2020-08-27 13:21:56 +02:00
if app.uses_schedule() {
let m = extra.monotonic();
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
));
values.push(quote!(start: instant));
needs_instant = true;
}
}
Context::SoftwareTask(..) => {
2020-08-27 13:21:56 +02:00
if app.uses_schedule() {
let m = extra.monotonic();
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
));
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)));
}
if ctxt.uses_schedule(app) {
let doc = "Tasks that can be `schedule`-d from this context";
if ctxt.is_init() {
items.push(quote!(
#[doc = #doc]
#[derive(Clone, Copy)]
pub struct Schedule {
_not_send: core::marker::PhantomData<*mut ()>,
}
));
fields.push(quote!(
#[doc = #doc]
pub schedule: Schedule
));
values.push(quote!(
schedule: Schedule { _not_send: core::marker::PhantomData }
));
} else {
lt = Some(quote!('a));
items.push(quote!(
#[doc = #doc]
#[derive(Clone, Copy)]
pub struct Schedule<'a> {
2020-06-11 19:18:29 +02:00
priority: &'a rtic::export::Priority,
}
impl<'a> Schedule<'a> {
#[doc(hidden)]
#[inline(always)]
2020-06-11 19:18:29 +02:00
pub unsafe fn priority(&self) -> &rtic::export::Priority {
&self.priority
}
}
));
fields.push(quote!(
#[doc = #doc]
pub schedule: Schedule<'a>
));
values.push(quote!(
schedule: Schedule { priority }
));
}
}
if ctxt.uses_spawn(app) {
let doc = "Tasks that can be `spawn`-ed from this context";
if ctxt.is_init() {
fields.push(quote!(
#[doc = #doc]
pub spawn: Spawn
));
items.push(quote!(
#[doc = #doc]
#[derive(Clone, Copy)]
pub struct Spawn {
_not_send: core::marker::PhantomData<*mut ()>,
}
));
values.push(quote!(spawn: Spawn { _not_send: core::marker::PhantomData }));
} else {
lt = Some(quote!('a));
fields.push(quote!(
#[doc = #doc]
pub spawn: Spawn<'a>
));
let mut instant_method = None;
if ctxt.is_idle() {
items.push(quote!(
#[doc = #doc]
#[derive(Clone, Copy)]
pub struct Spawn<'a> {
2020-06-11 19:18:29 +02:00
priority: &'a rtic::export::Priority,
}
));
values.push(quote!(spawn: Spawn { priority }));
} else {
2020-08-27 13:21:56 +02:00
let instant_field = if app.uses_schedule() {
let m = extra.monotonic();
needs_instant = true;
instant_method = Some(quote!(
2020-06-11 19:18:29 +02:00
pub unsafe fn instant(&self) -> <#m as rtic::Monotonic>::Instant {
self.instant
}
));
2020-06-11 19:18:29 +02:00
Some(quote!(instant: <#m as rtic::Monotonic>::Instant,))
} else {
None
};
items.push(quote!(
/// Tasks that can be spawned from this context
#[derive(Clone, Copy)]
pub struct Spawn<'a> {
#instant_field
2020-06-11 19:18:29 +02:00
priority: &'a rtic::export::Priority,
}
));
let _instant = if needs_instant {
Some(quote!(, instant))
} else {
None
};
values.push(quote!(
spawn: Spawn { priority #_instant }
));
}
items.push(quote!(
impl<'a> Spawn<'a> {
#[doc(hidden)]
#[inline(always)]
2020-06-11 19:18:29 +02:00
pub unsafe fn priority(&self) -> &rtic::export::Priority {
self.priority
}
#instant_method
}
));
}
}
2020-08-27 13:21:56 +02:00
if let Context::Init = ctxt {
let init = &app.inits.first().unwrap();
if init.returns_late_resources {
let late_resources = util::late_resources_ident(&init.name);
items.push(quote!(
#[doc(inline)]
pub use super::#late_resources as LateResources;
));
}
}
let doc = match ctxt {
2020-08-27 13:21:56 +02:00
Context::Idle => "Idle loop",
Context::Init => "Initialization function",
Context::HardwareTask(_) => "Hardware task",
Context::SoftwareTask(_) => "Software task",
};
let core = if ctxt.is_init() {
2020-08-27 13:21:56 +02:00
if app.uses_schedule() {
2020-06-11 19:18:29 +02:00
Some(quote!(core: rtic::Peripherals,))
} else {
2020-06-11 19:18:29 +02: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))
};
let instant = if needs_instant {
let m = extra.monotonic();
2020-06-11 19:18:29 +02:00
Some(quote!(, instant: <#m as rtic::Monotonic>::Instant))
} 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,)*
}
}
}
));
if !items.is_empty() {
quote!(
#[allow(non_snake_case)]
#[doc = #doc]
pub mod #name {
#(#items)*
}
)
} else {
quote!()
}
}