diff --git a/Cargo.toml b/Cargo.toml index 112e624a8b..5e9d548338 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,35 @@ name = "cortex-m-rtfm" repository = "https://github.com/japaric/cortex-m-rtfm" version = "0.3.2" +[[example]] +name = "async-after" +required-features = ["timer-queue"] + +[[example]] +name = "async" + +[[example]] +name = "empty" + +[[example]] +name = "interrupt" + +[[example]] +name = "periodic-payload" +required-features = ["timer-queue"] + +[[example]] +name = "periodic-preemption-payload" +required-features = ["timer-queue"] + +[[example]] +name = "periodic-preemption" +required-features = ["timer-queue"] + +[[example]] +name = "periodic" +required-features = ["timer-queue"] + [dependencies] cortex-m = "0.4.0" cortex-m-rtfm-macros = { path = "macros", version = "0.3.1" } @@ -32,6 +61,7 @@ version = "0.9.0" [features] cm7-r0p1 = ["cortex-m/cm7-r0p1"] +timer-queue = ["cortex-m-rtfm-macros/timer-queue"] [profile.release] lto = true diff --git a/macros/Cargo.toml b/macros/Cargo.toml index fd38f32966..4161ed3448 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -20,3 +20,6 @@ either = "1.5.0" [lib] proc-macro = true + +[features] +timer-queue = [] \ No newline at end of file diff --git a/macros/src/check.rs b/macros/src/check.rs index 424c3e8bc5..300eac82c6 100644 --- a/macros/src/check.rs +++ b/macros/src/check.rs @@ -1,7 +1,15 @@ use syntax::check::App; use syntax::Result; -pub fn app(_app: &App) -> Result<()> { - // TODO ??? +pub fn app(app: &App) -> Result<()> { + if !cfg!(feature = "timer-queue") { + if !app.init.async_after.is_empty() + || app.tasks.values().any(|task| !task.async_after.is_empty()) + { + return Err(format_err!( + "async_after is not supported. Enable the 'timer-queue' feature to use it" + )); + } + } Ok(()) } diff --git a/macros/src/trans.rs b/macros/src/trans.rs index 612d9e5876..ec36d10f8b 100644 --- a/macros/src/trans.rs +++ b/macros/src/trans.rs @@ -108,28 +108,51 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens { // primitive type and there's no way to import that type into a module (we don't know its // full path). So instead we just assume that `#input` has been imported in the root; this // forces us to put anything that refers to `#input` in the root. - root.push(quote! { - pub struct #__context<#lifetime> { - pub async: #name::Async, - pub baseline: u32, - pub input: #input, - pub resources: #name::Resources<#lifetime>, - pub threshold: #hidden::#krate::Threshold<#name::Priority>, - } + if cfg!(feature = "timer-queue") { + root.push(quote! { + pub struct #__context<#lifetime> { + pub async: #name::Async, + pub baseline: u32, + pub input: #input, + pub resources: #name::Resources<#lifetime>, + pub threshold: #hidden::#krate::Threshold<#name::Priority>, + } - #[allow(unsafe_code)] - impl<#lifetime> #__context<#lifetime> { - pub unsafe fn new(bl: #hidden::#krate::Instant, payload: #input) -> Self { - #__context { - async: #name::Async::new(bl), - baseline: bl.into(), - input: payload, - resources: #name::Resources::new(), - threshold: #hidden::#krate::Threshold::new(), + #[allow(unsafe_code)] + impl<#lifetime> #__context<#lifetime> { + pub unsafe fn new(bl: #hidden::#krate::Instant, payload: #input) -> Self { + #__context { + async: #name::Async::new(bl), + baseline: bl.into(), + input: payload, + resources: #name::Resources::new(), + threshold: #hidden::#krate::Threshold::new(), + } } } - } - }); + }); + } else { + root.push(quote! { + pub struct #__context<#lifetime> { + pub async: #name::Async, + pub input: #input, + pub resources: #name::Resources<#lifetime>, + pub threshold: #hidden::#krate::Threshold<#name::Priority>, + } + + #[allow(unsafe_code)] + impl<#lifetime> #__context<#lifetime> { + pub unsafe fn new(payload: #input) -> Self { + #__context { + async: #name::Async::new(), + input: payload, + resources: #name::Resources::new(), + threshold: #hidden::#krate::Threshold::new(), + } + } + } + }); + } let res_fields = task.resources .iter() @@ -163,7 +186,13 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens { let async_exprs = task.async .iter() - .map(|task| quote!(#task: ::__async::#task::new(_bl))) + .map(|task| { + if cfg!(feature = "timer-queue") { + quote!(#task: ::__async::#task::new(_bl)) + } else { + quote!(#task: ::__async::#task::new()) + } + }) .chain( task.async_after .iter() @@ -189,15 +218,6 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens { #(#async_fields,)* } - #[allow(unsafe_code)] - impl Async { - pub unsafe fn new(_bl: #krate::Instant) -> Self { - Async { - #(#async_exprs,)* - } - } - } - #[allow(non_snake_case)] pub struct Resources<#lifetime> { #(#res_fields,)* @@ -213,18 +233,49 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens { } }); + if cfg!(feature = "timer-queue") { + mod_.push(quote! { + #[allow(unsafe_code)] + impl Async { + pub unsafe fn new(_bl: #krate::Instant) -> Self { + Async { + #(#async_exprs,)* + } + } + } + + }); + } else { + mod_.push(quote! { + #[allow(unsafe_code)] + impl Async { + pub unsafe fn new() -> Self { + Async { + #(#async_exprs,)* + } + } + } + + }); + } + match task.interrupt_or_capacity { Either::Left(interrupt) => { let export_name = interrupt.as_ref(); let fn_name = Ident::from(format!("__{}", interrupt)); + let bl = if cfg!(feature = "timer-queue") { + Some(quote!(#hidden::#krate::Instant::now(),)) + } else { + None + }; root.push(quote! { #[allow(non_snake_case)] #[allow(unsafe_code)] #[export_name = #export_name] pub unsafe extern "C" fn #fn_name() { let _ = #device::Interrupt::#interrupt; // verify that the interrupt exists - #name::HANDLER(#name::Context::new(#hidden::#krate::Instant::now(), ())) + #name::HANDLER(#name::Context::new(#bl ())) } }); } @@ -293,44 +344,90 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens { )); let qc = Ident::from(format!("U{}", ctxt.ceilings.dispatch_queues()[&priority])); - quote! { - #[allow(non_camel_case_types)] - pub struct #name { baseline: #krate::Instant } + if cfg!(feature = "timer-queue") { + quote! { + #[allow(non_camel_case_types)] + pub struct #name { baseline: #krate::Instant } - #[allow(unsafe_code)] - impl #name { - pub unsafe fn new(bl: #krate::Instant) -> Self { - #name { baseline: bl } + #[allow(unsafe_code)] + impl #name { + pub unsafe fn new(bl: #krate::Instant) -> Self { + #name { baseline: bl } + } + + // XXX or take `self`? + #[inline] + pub fn post
( + &self, + t: &mut #krate::Threshold
, + payload: #ty, + ) -> Result<(), #ty> + where + P: #krate::Unsigned + + #krate::Max<#krate::#sqc> + + #krate::Max<#krate::#qc>, + #krate::Maximum
: #krate::Unsigned, + #krate::Maximum
: #krate::Unsigned, + { + unsafe { + if let Some(slot) = + ::#name::SQ::new().claim_mut(t, |sq, _| sq.dequeue()) { + let tp = slot + .write(self.baseline, payload) + .tag(::#__priority::Task::#name); + + ::#__priority::Q::new().claim_mut(t, |q, _| { + q.split().0.enqueue_unchecked(tp); + }); + + Ok(()) + } else { + Err(payload) + } + } + } } + } + } else { + quote! { + #[allow(non_camel_case_types)] + pub struct #name {} - // XXX or take `self`? - #[inline] - pub fn post
( - &self, - t: &mut #krate::Threshold
, - payload: #ty, - ) -> Result<(), #ty> - where - P: #krate::Unsigned + - #krate::Max<#krate::#sqc> + - #krate::Max<#krate::#qc>, - #krate::Maximum
: #krate::Unsigned, - #krate::Maximum
: #krate::Unsigned, - { - unsafe { - if let Some(slot) = - ::#name::SQ::new().claim_mut(t, |sq, _| sq.dequeue()) { - let tp = slot - .write(self.baseline, payload) - .tag(::#__priority::Task::#name); + #[allow(unsafe_code)] + impl #name { + pub unsafe fn new() -> Self { + #name {} + } - ::#__priority::Q::new().claim_mut(t, |q, _| { - q.split().0.enqueue_unchecked(tp); - }); + // XXX or take `self`? + #[inline] + pub fn post
( + &self, + t: &mut #krate::Threshold
, + payload: #ty, + ) -> Result<(), #ty> + where + P: #krate::Unsigned + + #krate::Max<#krate::#sqc> + + #krate::Max<#krate::#qc>, + #krate::Maximum
: #krate::Unsigned, + #krate::Maximum
: #krate::Unsigned,
+ {
+ unsafe {
+ if let Some(slot) =
+ ::#name::SQ::new().claim_mut(t, |sq, _| sq.dequeue()) {
+ let tp = slot
+ .write(payload)
+ .tag(::#__priority::Task::#name);
- Ok(())
- } else {
- Err(payload)
+ ::#__priority::Q::new().claim_mut(t, |q, _| {
+ q.split().0.enqueue_unchecked(tp);
+ });
+
+ Ok(())
+ } else {
+ Err(payload)
+ }
}
}
}
@@ -537,14 +634,27 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
.tasks()
.iter()
.map(|name| {
- quote! {
+ // NOTE(get) this is the only `Slot` producer because a task can only be
+ // dispatched at one priority
+ if cfg!(feature = "timer-queue") {
+ quote! {
#__priority::Task::#name => {
let (bl, payload, slot) = payload.coerce().read();
- // NOTE(get) only `Slot` producer because a task can only be dispatched at one
// priority
#name::SQ::get().split().0.enqueue_unchecked(slot);
#name::HANDLER(#name::Context::new(bl, payload));
}
+
+ }
+ } else {
+ quote! {
+ #__priority::Task::#name => {
+ let (payload, slot) = payload.coerce().read();
+ // priority
+ #name::SQ::get().split().0.enqueue_unchecked(slot);
+ #name::HANDLER(#name::Context::new(payload));
+ }
+ }
}
})
.collect::