diff --git a/CHANGELOG.md b/CHANGELOG.md index 599c1a6a56..4d1e7fad95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,15 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] -## [v0.6.0-alpha.2] - 2020-04-08 +## [v0.6.0-alpha.3] - 2021-05-27 + +### Fixed + +- Fixed codegen structure to not have issues with local paths +- Default paths for monotonics now work properly +- New `embedded-time` version to `0.11` + +## [v0.6.0-alpha.2] - 2021-04-08 ### Added @@ -21,7 +29,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - The access to monotonic static methods was for example `MyMono::now()`, and is now `monotonics::MyMono::now()` -## [v0.6.0-alpha.1] - 2020-03-04 +## [v0.6.0-alpha.1] - 2021-03-04 ### Added diff --git a/Cargo.toml b/Cargo.toml index 08a1813403..a138b5155b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ name = "cortex-m-rtic" readme = "README.md" repository = "https://github.com/rtic-rs/cortex-m-rtic" -version = "0.6.0-alpha.2" +version = "0.6.0-alpha.4" [lib] name = "rtic" @@ -53,15 +53,15 @@ required-features = ["__v7"] [dependencies] cortex-m = "0.7.0" -cortex-m-rtic-macros = { path = "macros", version = "0.6.0-alpha.2" } -rtic-monotonic = "0.1.0-alpha.0" +cortex-m-rtic-macros = { path = "macros", version = "0.6.0-alpha.4" } +rtic-monotonic = "0.1.0-alpha.1" rtic-core = "0.3.1" heapless = "0.6.1" bare-metal = "1.0.0" generic-array = "0.14" [dependencies.dwt-systick-monotonic] -version = "0.1.0-alpha.0" +version = "0.1.0-alpha.2" optional = true [build-dependencies] @@ -110,3 +110,4 @@ overflow-checks = false [patch.crates-io] lm3s6965 = { git = "https://github.com/japaric/lm3s6965" } +# embedded-time = { path = "../../embedded-time" } diff --git a/examples/schedule.rs b/examples/schedule.rs index b89e51918d..bb5119c20a 100644 --- a/examples/schedule.rs +++ b/examples/schedule.rs @@ -14,8 +14,10 @@ mod app { use dwt_systick_monotonic::DwtSystick; use rtic::time::duration::Seconds; + const MONO_HZ: u32 = 8_000_000; // 8 MHz + #[monotonic(binds = SysTick, default = true)] - type MyMono = DwtSystick<8_000_000>; // 8 MHz + type MyMono = DwtSystick; #[init()] fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) { @@ -25,24 +27,24 @@ mod app { let mono = DwtSystick::new(&mut dcb, dwt, systick, 8_000_000); - hprintln!("init").unwrap(); + hprintln!("init").ok(); // Schedule `foo` to run 1 second in the future - foo::spawn_after(Seconds(1_u32)).unwrap(); + foo::spawn_after(Seconds(1_u32)).ok(); // Schedule `bar` to run 2 seconds in the future - bar::spawn_after(Seconds(2_u32)).unwrap(); + bar::spawn_after(Seconds(2_u32)).ok(); (init::LateResources {}, init::Monotonics(mono)) } #[task] fn foo(_: foo::Context) { - hprintln!("foo").unwrap(); + hprintln!("foo").ok(); } #[task] fn bar(_: bar::Context) { - hprintln!("bar").unwrap(); + hprintln!("bar").ok(); } } diff --git a/examples/t-schedule.rs b/examples/t-schedule.rs index 4ce62b47f0..d7051609f7 100644 --- a/examples/t-schedule.rs +++ b/examples/t-schedule.rs @@ -7,15 +7,11 @@ use panic_semihosting as _; -pub struct SomeStruct; - #[rtic::app(device = lm3s6965, dispatchers = [SSI0])] mod app { use dwt_systick_monotonic::DwtSystick; use rtic::time::duration::Seconds; - use super::SomeStruct; - #[monotonic(binds = SysTick, default = true)] type MyMono = DwtSystick<8_000_000>; // 8 MHz diff --git a/macros/Cargo.toml b/macros/Cargo.toml index fb4dffb37f..aa96d09ec6 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" name = "cortex-m-rtic-macros" readme = "../README.md" repository = "https://github.com/rtic-rs/cortex-m-rtic" -version = "0.6.0-alpha.2" +version = "0.6.0-alpha.4" [lib] proc-macro = true @@ -22,4 +22,4 @@ proc-macro2 = "1" proc-macro-error = "1" quote = "1" syn = "1" -rtic-syntax = "0.5.0-alpha.2" +rtic-syntax = "0.5.0-alpha.3" diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index de11cce461..113d17f9f6 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -97,8 +97,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { let user_code = &app.user_code; let name = &app.name; let device = &extra.device; - let app_name = &app.name; - let app_path = quote! {crate::#app_name}; let monotonic_parts: Vec<_> = app .monotonics @@ -106,7 +104,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { .map(|(_, monotonic)| { let name = &monotonic.ident; let name_str = &name.to_string(); - let ty = &monotonic.ty; let ident = util::monotonic_ident(&name_str); let ident = util::mark_internal_ident(&ident); let panic_str = &format!( @@ -117,7 +114,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { "This module holds the static implementation for `{}::now()`", name_str ); - let user_imports = &app.user_imports; let default_monotonic = if monotonic.args.default { quote!(pub use #name::now;) @@ -131,17 +127,13 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { #[doc = #doc] #[allow(non_snake_case)] pub mod #name { - #( - #[allow(unused_imports)] - #user_imports - )* /// Read the current time from this monotonic - pub fn now() -> rtic::time::Instant<#ty> { + pub fn now() -> rtic::time::Instant { rtic::export::interrupt::free(|_| { use rtic::Monotonic as _; use rtic::time::Clock as _; - if let Some(m) = unsafe{ #app_path::#ident.get_mut_unchecked() } { + if let Some(m) = unsafe{ super::super::#ident.get_mut_unchecked() } { if let Ok(v) = m.try_now() { v } else { @@ -163,11 +155,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { /// Holds static methods for each monotonic. pub mod monotonics { - #( - #[allow(unused_imports)] - #user_imports - )* - #(#monotonic_parts)* } ) diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs index 382e33fe40..65a3f5f649 100644 --- a/macros/src/codegen/dispatchers.rs +++ b/macros/src/codegen/dispatchers.rs @@ -82,8 +82,6 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec { @@ -95,7 +93,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec CodegenResult { mod_app = Some(constructor); } - let app_name = &app.name; - let app_path = quote! {crate::#app_name}; let locals_new = locals_new.iter(); let call_init = Some( - quote!(let (late, mut monotonics) = #app_path::#name(#(#locals_new,)* #name::Context::new(core.into()));), + quote!(let (late, mut monotonics) = #name(#(#locals_new,)* #name::Context::new(core.into()));), ); root_init.push(module::codegen( diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs index 9bcc8f640d..a3d3fab2e2 100644 --- a/macros/src/codegen/module.rs +++ b/macros/src/codegen/module.rs @@ -1,9 +1,8 @@ +use crate::{analyze::Analysis, check::Extra, codegen::util}; use proc_macro2::TokenStream as TokenStream2; use quote::quote; use rtic_syntax::{ast::App, Context}; -use crate::{analyze::Analysis, check::Extra, codegen::util}; - pub fn codegen( ctxt: Context, resources_tick: bool, @@ -12,48 +11,13 @@ pub fn codegen( extra: &Extra, ) -> TokenStream2 { let mut items = vec![]; + 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 app_name = &app.name; - let app_path = quote! {crate::#app_name}; - - let all_task_imports: Vec<_> = app - .software_tasks - .iter() - .map(|(name, st)| { - if !st.is_extern { - let cfgs = &st.cfgs; - quote! { - #(#cfgs)* - #[allow(unused_imports)] - use #app_path::#name as #name; - } - } else { - quote!() - } - }) - .chain(app.hardware_tasks.iter().map(|(name, ht)| { - if !ht.is_extern { - quote! { - #[allow(unused_imports)] - use #app_path::#name as #name; - } - } else { - quote!() - } - })) - .chain(app.user_types.iter().map(|ty| { - let t = &ty.ident; - quote! { - #[allow(unused_imports)] - use super::#t; - } - })) - .collect(); let mut lt = None; match ctxt { @@ -94,7 +58,7 @@ pub fn codegen( if ctxt.has_locals(app) { let ident = util::locals_ident(ctxt, app); - items.push(quote!( + module_items.push(quote!( #[doc(inline)] pub use super::#ident as Locals; )); @@ -110,14 +74,14 @@ pub fn codegen( None }; - items.push(quote!( + module_items.push(quote!( #[doc(inline)] pub use super::#ident as Resources; )); fields.push(quote!( /// Resources this task has access to - pub resources: Resources<#lt> + pub resources: #name::Resources<#lt> )); let priority = if ctxt.is_init() { @@ -125,7 +89,7 @@ pub fn codegen( } else { Some(quote!(priority)) }; - values.push(quote!(resources: Resources::new(#priority))); + values.push(quote!(resources: #name::Resources::new(#priority))); } if let Context::Init = ctxt { @@ -145,13 +109,17 @@ pub fn codegen( }) .collect::>(); + let internal_late_ident = util::mark_internal_name("LateResources"); items.push(quote!( /// Resources initialized at runtime #[allow(non_snake_case)] - pub struct LateResources { + pub struct #internal_late_ident { #(#late_fields),* } )); + module_items.push(quote!( + pub use super::#internal_late_ident as LateResources; + )); let monotonic_types: Vec<_> = app .monotonics @@ -162,13 +130,19 @@ pub fn codegen( }) .collect(); + let internal_monotonics_ident = util::mark_internal_name("Monotonics"); + items.push(quote!( /// Monotonics used by the system #[allow(non_snake_case)] - pub struct Monotonics( + pub struct #internal_monotonics_ident( #(pub #monotonic_types),* ); )); + + module_items.push(quote!( + pub use super::#internal_monotonics_ident as Monotonics; + )); } let doc = match ctxt { @@ -178,6 +152,19 @@ pub fn codegen( Context::SoftwareTask(_) => "Software task", }; + let v = Vec::new(); + let cfgs = match ctxt { + Context::HardwareTask(t) => { + &app.hardware_tasks[t].cfgs + // ... + } + Context::SoftwareTask(t) => { + &app.software_tasks[t].cfgs + // ... + } + _ => &v, + }; + let core = if ctxt.is_init() { Some(quote!(core: rtic::export::Peripherals,)) } else { @@ -190,22 +177,31 @@ pub fn codegen( Some(quote!(priority: &#lt rtic::export::Priority)) }; + let internal_context_name = util::internal_task_ident(name, "Context"); + items.push(quote!( + #(#cfgs)* /// Execution context - pub struct Context<#lt> { + pub struct #internal_context_name<#lt> { #(#fields,)* } - impl<#lt> Context<#lt> { + #(#cfgs)* + impl<#lt> #internal_context_name<#lt> { #[inline(always)] pub unsafe fn new(#core #priority) -> Self { - Context { + #internal_context_name { #(#values,)* } } } )); + module_items.push(quote!( + #(#cfgs)* + pub use super::#internal_context_name as Context; + )); + // not sure if this is the right way, maybe its backwards, // that spawn_module should put in in root @@ -234,26 +230,26 @@ pub fn codegen( .expect("RTIC-ICE: interrupt identifer not found") .0; + let internal_spawn_ident = util::internal_task_ident(name, "spawn"); + // Spawn caller items.push(quote!( - #(#all_task_imports)* - #(#cfgs)* /// Spawns the task directly - pub fn spawn(#(#args,)*) -> Result<(), #ty> { + pub fn #internal_spawn_ident(#(#args,)*) -> Result<(), #ty> { let input = #tupled; unsafe { - if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.get_mut_unchecked().dequeue()) { - #app_path::#inputs + if let Some(index) = rtic::export::interrupt::free(|_| #fq.get_mut_unchecked().dequeue()) { + #inputs .get_mut_unchecked() .get_unchecked_mut(usize::from(index)) .as_mut_ptr() .write(input); rtic::export::interrupt::free(|_| { - #app_path::#rq.get_mut_unchecked().enqueue_unchecked((#app_path::#t::#name, index)); + #rq.get_mut_unchecked().enqueue_unchecked((#t::#name, index)); }); rtic::pend(#device::#enum_::#interrupt); @@ -266,6 +262,11 @@ pub fn codegen( })); + module_items.push(quote!( + #(#cfgs)* + pub use super::#internal_spawn_ident as spawn; + )); + // Schedule caller for (_, monotonic) in &app.monotonics { let instants = util::monotonic_instants_ident(name, &monotonic.ident); @@ -282,12 +283,6 @@ pub fn codegen( let m_isr = &monotonic.args.binds; let enum_ = util::interrupt_ident(); - if monotonic.args.default { - items.push(quote!(pub use #m::spawn_after;)); - items.push(quote!(pub use #m::spawn_at;)); - items.push(quote!(pub use #m::SpawnHandle;)); - } - let (enable_interrupt, pend) = if &*m_isr.to_string() == "SysTick" { ( quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(()) @@ -297,49 +292,56 @@ pub fn codegen( } else { let rt_err = util::rt_err_ident(); ( - quote!(rtic::export::NVIC::unmask(#app_path::#rt_err::#enum_::#m_isr)), - quote!(rtic::pend(#app_path::#rt_err::#enum_::#m_isr)), + quote!(rtic::export::NVIC::unmask(#rt_err::#enum_::#m_isr)), + quote!(rtic::pend(#rt_err::#enum_::#m_isr)), ) }; - let user_imports = &app.user_imports; let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident()); // For future use // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); // items.push(quote!(#[doc = #doc])); + let internal_spawn_handle_ident = + util::internal_monotonics_ident(name, m, "SpawnHandle"); + let internal_spawn_at_ident = util::internal_monotonics_ident(name, m, "spawn_at"); + let internal_spawn_after_ident = + util::internal_monotonics_ident(name, m, "spawn_after"); + + if monotonic.args.default { + module_items.push(quote!( + pub use #m::spawn_after; + pub use #m::spawn_at; + pub use #m::SpawnHandle; + )); + } + module_items.push(quote!( + pub mod #m { + pub use super::super::#internal_spawn_after_ident as spawn_after; + pub use super::super::#internal_spawn_at_ident as spawn_at; + pub use super::super::#internal_spawn_handle_ident as SpawnHandle; + } + )); items.push(quote!( - /// Holds methods related to this monotonic - pub mod #m { - use super::*; - #[allow(unused_imports)] - use #app_path::#tq_marker; - #[allow(unused_imports)] - use #app_path::#t; - #( - #[allow(unused_imports)] - #user_imports - )* - - pub struct SpawnHandle { + pub struct #internal_spawn_handle_ident { #[doc(hidden)] marker: u32, } - impl SpawnHandle { + impl #internal_spawn_handle_ident { pub fn cancel(self) -> Result<#ty, ()> { rtic::export::interrupt::free(|_| unsafe { - let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr(); + let tq = &mut *#tq.get_mut_unchecked().as_mut_ptr(); if let Some((_task, index)) = tq.cancel_marker(self.marker) { // Get the message - let msg = #app_path::#inputs + let msg = #inputs .get_unchecked() .get_unchecked(usize::from(index)) .as_ptr() .read(); // Return the index to the free queue - #app_path::#fq.get_mut_unchecked().split().0.enqueue_unchecked(index); + #fq.get_mut_unchecked().split().0.enqueue_unchecked(index); Ok(msg) } else { @@ -351,20 +353,20 @@ pub fn codegen( #[inline] pub fn reschedule_after(self, duration: D) -> Result where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint, - D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>, + D::T: Into<<#mono_type as rtic::time::Clock>::T>, { - self.reschedule_at(#app_path::monotonics::#m::now() + duration) + self.reschedule_at(monotonics::#m::now() + duration) } - pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result + pub fn reschedule_at(self, instant: rtic::time::Instant<#mono_type>) -> Result { rtic::export::interrupt::free(|_| unsafe { let marker = *#tq_marker.get_mut_unchecked(); *#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1); - let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr(); + let tq = &mut *#tq.get_mut_unchecked().as_mut_ptr(); - tq.update_marker(self.marker, marker, instant, || #pend).map(|_| SpawnHandle { marker }) + tq.update_marker(self.marker, marker, instant, || #pend).map(|_| #name::#m::SpawnHandle { marker }) }) } } @@ -374,39 +376,39 @@ pub fn codegen( /// /// This will use the time `Instant::new(0)` as baseline if called in `#[init]`, /// so if you use a non-resetable timer use `spawn_at` when in `#[init]` - pub fn spawn_after( + pub fn #internal_spawn_after_ident( duration: D #(,#args)* - ) -> Result + ) -> Result<#name::#m::SpawnHandle, #ty> where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint, - D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>, + D::T: Into<<#mono_type as rtic::time::Clock>::T>, { - let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.get_mut_unchecked().is_none() }) { + let instant = if rtic::export::interrupt::free(|_| unsafe { #m_ident.get_mut_unchecked().is_none() }) { rtic::time::Instant::new(0) } else { - #app_path::monotonics::#m::now() + monotonics::#m::now() }; - spawn_at(instant + duration #(,#untupled)*) + #internal_spawn_at_ident(instant + duration #(,#untupled)*) } #(#cfgs)* /// Spawns the task at a fixed time instant - pub fn spawn_at( - instant: rtic::time::Instant<#app_path::#mono_type> + pub fn #internal_spawn_at_ident( + instant: rtic::time::Instant<#mono_type> #(,#args)* - ) -> Result { + ) -> Result<#name::#m::SpawnHandle, #ty> { unsafe { let input = #tupled; - if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.get_mut_unchecked().dequeue()) { - #app_path::#inputs + if let Some(index) = rtic::export::interrupt::free(|_| #fq.get_mut_unchecked().dequeue()) { + #inputs .get_mut_unchecked() .get_unchecked_mut(usize::from(index)) .as_mut_ptr() .write(input); - #app_path::#instants + #instants .get_mut_unchecked() .get_unchecked_mut(usize::from(index)) .as_mut_ptr() @@ -417,44 +419,40 @@ pub fn codegen( let nr = rtic::export::NotReady { instant, index, - task: #app_path::#t::#name, + task: #t::#name, marker, }; *#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1); - let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr(); + let tq = &mut *#tq.get_mut_unchecked().as_mut_ptr(); tq.enqueue_unchecked( nr, || #enable_interrupt, || #pend, - #app_path::#m_ident.get_mut_unchecked().as_mut()); + #m_ident.get_mut_unchecked().as_mut()); - Ok(SpawnHandle { marker }) + Ok(#name::#m::SpawnHandle { marker }) }) } else { Err(input) } } } - })); + )); } } if !items.is_empty() { - let user_imports = &app.user_imports; - quote!( + #(#items)* + #[allow(non_snake_case)] #(#task_cfgs)* #[doc = #doc] pub mod #name { - #( - #[allow(unused_imports)] - #user_imports - )* - #(#items)* + #(#module_items)* } ) } else { diff --git a/macros/src/codegen/pre_init.rs b/macros/src/codegen/pre_init.rs index 3a62da504e..531debac67 100644 --- a/macros/src/codegen/pre_init.rs +++ b/macros/src/codegen/pre_init.rs @@ -93,8 +93,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec Vec::DISABLE_INTERRUPT_ON_EMPTY_QUEUE { - rtic::export::NVIC::unmask(#app_path::#rt_err::#interrupt::#binds); + rtic::export::NVIC::unmask(#rt_err::#interrupt::#binds); } )); } diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs index 14e9105453..9e30d1001d 100644 --- a/macros/src/codegen/timer_queue.rs +++ b/macros/src/codegen/timer_queue.rs @@ -57,8 +57,6 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec Vec Vec bool { ) } +/// Generate an internal identifier for monotonics +pub fn internal_monotonics_ident(task: &Ident, monotonic: &Ident, ident_name: &str) -> Ident { + Ident::new( + &format!( + "__rtic_internal_{}_{}_{}", + task.to_string(), + monotonic.to_string(), + ident_name, + ), + Span::call_site(), + ) +} + +/// Generate an internal identifier for tasks +pub fn internal_task_ident(task: &Ident, ident_name: &str) -> Ident { + Ident::new( + &format!("__rtic_internal_{}_{}", task.to_string(), ident_name,), + Span::call_site(), + ) +} + /// Mark an ident as internal pub fn mark_internal_ident(ident: &Ident) -> Ident { Ident::new( @@ -119,6 +140,11 @@ pub fn mark_internal_ident(ident: &Ident) -> Ident { ) } +/// Mark an ident as internal +pub fn mark_internal_name(name: &str) -> Ident { + Ident::new(&format!("__rtic_internal_{}", name), Span::call_site()) +} + fn link_section_index() -> usize { static INDEX: AtomicUsize = AtomicUsize::new(0);