aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--ci/expected/cfg-monotonic.run0
-rw-r--r--examples/cfg-monotonic.rs121
-rw-r--r--macros/src/codegen.rs7
-rw-r--r--macros/src/codegen/module.rs20
-rw-r--r--macros/src/codegen/post_init.rs15
-rw-r--r--macros/src/codegen/software_tasks.rs2
-rw-r--r--macros/src/codegen/timer_queue.rs6
8 files changed, 162 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc84e159..cbbc9c4b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
### Added
+- CFG: Slightly improved support for #[cfg] on Monotonics
- CI: Check examples also for thumbv8.{base,main}
- Allow custom `link_section` attributes for late resources
diff --git a/ci/expected/cfg-monotonic.run b/ci/expected/cfg-monotonic.run
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ci/expected/cfg-monotonic.run
diff --git a/examples/cfg-monotonic.rs b/examples/cfg-monotonic.rs
new file mode 100644
index 00000000..88c0d6f0
--- /dev/null
+++ b/examples/cfg-monotonic.rs
@@ -0,0 +1,121 @@
+//! examples/cfg-monotonic.rs
+
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![deny(missing_docs)]
+#![no_main]
+#![no_std]
+
+use panic_semihosting as _;
+
+#[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])]
+mod app {
+ use cortex_m_semihosting::{debug, hprintln};
+ use systick_monotonic::*; // Implements the `Monotonic` trait
+
+ // A monotonic timer to enable scheduling in RTIC
+ #[cfg(feature = "killmono")]
+ #[monotonic(binds = SysTick, default = true)]
+ type MyMono = Systick<100>; // 100 Hz / 10 ms granularity
+
+ // Not allowed by current rtic-syntax:
+ // error: `#[monotonic(...)]` on a specific type must appear at most once
+ // --> examples/cfg-monotonic.rs:23:10
+ // |
+ // 23 | type MyMono = Systick<100>; // 100 Hz / 10 ms granularity
+ // | ^^^^^^
+ // #[monotonic(binds = SysTick, default = true)]
+ // type MyMono = Systick<100>; // 100 Hz / 10 ms granularity
+
+ // Not allowed by current rtic-syntax:
+ // error: this interrupt is already bound
+ // --> examples/cfg-monotonic.rs:31:25
+ // |
+ // 31 | #[monotonic(binds = SysTick, default = true)]
+ // | ^^^^^^^
+ // #[monotonic(binds = SysTick, default = true)]
+ // type MyMono2 = DwtSystick<100>; // 100 Hz / 10 ms granularity
+
+ // Resources shared between tasks
+ #[shared]
+ struct Shared {
+ s1: u32,
+ s2: i32,
+ }
+
+ // Local resources to specific tasks (cannot be shared)
+ #[local]
+ struct Local {
+ l1: u8,
+ l2: i8,
+ }
+
+ #[init]
+ fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
+ let _systick = cx.core.SYST;
+
+ // Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
+ #[cfg(feature = "killmono")]
+ let mono = Systick::new(systick, 12_000_000);
+
+ // Spawn the task `foo` directly after `init` finishes
+ foo::spawn().unwrap();
+
+ debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
+
+ (
+ // Initialization of shared resources
+ Shared { s1: 0, s2: 1 },
+ // Initialization of task local resources
+ Local { l1: 2, l2: 3 },
+ // Move the monotonic timer to the RTIC run-time, this enables
+ // scheduling
+ #[cfg(feature = "killmono")]
+ init::Monotonics(mono),
+ init::Monotonics(),
+ )
+ }
+
+ // Background task, runs whenever no other tasks are running
+ #[idle]
+ fn idle(_: idle::Context) -> ! {
+ loop {
+ continue;
+ }
+ }
+
+ // Software task, not bound to a hardware interrupt.
+ // This task takes the task local resource `l1`
+ // The resources `s1` and `s2` are shared between all other tasks.
+ #[task(shared = [s1, s2], local = [l1])]
+ fn foo(_: foo::Context) {
+ // This task is only spawned once in `init`, hence this task will run
+ // only once
+
+ hprintln!("foo");
+ }
+
+ // Software task, also not bound to a hardware interrupt
+ // This task takes the task local resource `l2`
+ // The resources `s1` and `s2` are shared between all other tasks.
+ #[task(shared = [s1, s2], local = [l2])]
+ fn bar(_: bar::Context) {
+ hprintln!("bar");
+
+ // Run `bar` once per second
+ // bar::spawn_after(1.secs()).unwrap();
+ }
+
+ // Hardware task, bound to a hardware interrupt
+ // The resources `s1` and `s2` are shared between all other tasks.
+ #[task(binds = UART0, priority = 3, shared = [s1, s2])]
+ fn uart0_interrupt(_: uart0_interrupt::Context) {
+ // This task is bound to the interrupt `UART0` and will run
+ // whenever the interrupt fires
+
+ // Note that RTIC does NOT clear the interrupt flag, this is up to the
+ // user
+
+ hprintln!("UART0 interrupt!");
+ }
+}
diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs
index 9c444fed..89173d45 100644
--- a/macros/src/codegen.rs
+++ b/macros/src/codegen.rs
@@ -108,6 +108,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
.map(|(_, monotonic)| {
let name = &monotonic.ident;
let name_str = &name.to_string();
+ let cfgs = &monotonic.cfgs;
let ident = util::monotonic_ident(name_str);
let doc = &format!(
"This module holds the static implementation for `{}::now()`",
@@ -115,7 +116,10 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
);
let default_monotonic = if monotonic.args.default {
- quote!(pub use #name::now;)
+ quote!(
+ #(#cfgs)*
+ pub use #name::now;
+ )
} else {
quote!()
};
@@ -125,6 +129,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
#[doc = #doc]
#[allow(non_snake_case)]
+ #(#cfgs)*
pub mod #name {
/// Read the current time from this monotonic
diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs
index d05784d1..71bcfa8e 100644
--- a/macros/src/codegen/module.rs
+++ b/macros/src/codegen/module.rs
@@ -116,8 +116,12 @@ pub fn codegen(
.monotonics
.iter()
.map(|(_, monotonic)| {
+ let cfgs = &monotonic.cfgs;
let mono = &monotonic.ty;
- quote! {#mono}
+ quote! {
+ #(#cfgs)*
+ pub #mono
+ }
})
.collect();
@@ -128,7 +132,7 @@ pub fn codegen(
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
pub struct #internal_monotonics_ident(
- #(pub #monotonic_types),*
+ #(#monotonic_types),*
);
));
@@ -226,8 +230,8 @@ pub fn codegen(
// Spawn caller
items.push(quote!(
- #(#cfgs)*
/// Spawns the task directly
+ #(#cfgs)*
pub fn #internal_spawn_ident(#(#args,)*) -> Result<(), #ty> {
let input = #tupled;
@@ -267,6 +271,7 @@ pub fn codegen(
let tq = util::tq_ident(&monotonic.ident.to_string());
let t = util::schedule_t_ident();
let m = &monotonic.ident;
+ let cfgs = &monotonic.cfgs;
let m_ident = util::monotonic_ident(&monotonic_name);
let m_isr = &monotonic.args.binds;
let enum_ = util::interrupt_ident();
@@ -298,13 +303,17 @@ pub fn codegen(
if monotonic.args.default {
module_items.push(quote!(
+ #(#cfgs)*
pub use #m::spawn_after;
+ #(#cfgs)*
pub use #m::spawn_at;
+ #(#cfgs)*
pub use #m::SpawnHandle;
));
}
module_items.push(quote!(
#[doc(hidden)]
+ #(#cfgs)*
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;
@@ -322,6 +331,7 @@ pub fn codegen(
marker: u32,
}
+ #(#cfgs)*
impl core::fmt::Debug for #internal_spawn_handle_ident {
#[doc(hidden)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
@@ -353,6 +363,7 @@ pub fn codegen(
/// Reschedule after
#[inline]
+ #(#cfgs)*
pub fn reschedule_after(
self,
duration: <#m as rtic::Monotonic>::Duration
@@ -361,6 +372,7 @@ pub fn codegen(
}
/// Reschedule at
+ #(#cfgs)*
pub fn reschedule_at(
self,
instant: <#m as rtic::Monotonic>::Instant
@@ -376,11 +388,11 @@ pub fn codegen(
}
}
- #(#cfgs)*
/// Spawns the task after a set duration relative to the current time
///
/// 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]`
+ #(#cfgs)*
#[allow(non_snake_case)]
pub fn #internal_spawn_after_ident(
duration: <#m as rtic::Monotonic>::Duration
diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs
index 9531254c..460b4e21 100644
--- a/macros/src/codegen/post_init.rs
+++ b/macros/src/codegen/post_init.rs
@@ -43,21 +43,28 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
}
}
- for (i, (monotonic, _)) in app.monotonics.iter().enumerate() {
+ for (i, (monotonic_ident, monotonic)) in app.monotonics.iter().enumerate() {
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
// stmts.push(quote!(#[doc = #doc]));
+ let cfgs = &monotonic.cfgs;
#[allow(clippy::cast_possible_truncation)]
let idx = Index {
index: i as u32,
span: Span::call_site(),
};
- stmts.push(quote!(monotonics.#idx.reset();));
+ stmts.push(quote!(
+ #(#cfgs)*
+ monotonics.#idx.reset();
+ ));
// Store the monotonic
- let name = util::monotonic_ident(&monotonic.to_string());
- stmts.push(quote!(#name.get_mut().write(Some(monotonics.#idx));));
+ let name = util::monotonic_ident(&monotonic_ident.to_string());
+ stmts.push(quote!(
+ #(#cfgs)*
+ #name.get_mut().write(Some(monotonics.#idx));
+ ));
}
// Enable the interrupts -- this completes the `init`-ialization phase
diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs
index 7c3f70fb..6bd2a71f 100644
--- a/macros/src/codegen/software_tasks.rs
+++ b/macros/src/codegen/software_tasks.rs
@@ -62,6 +62,7 @@ pub fn codegen(
for (_, monotonic) in &app.monotonics {
let instants = util::monotonic_instants_ident(name, &monotonic.ident);
let mono_type = &monotonic.ty;
+ let cfgs = &monotonic.cfgs;
let uninit = mk_uninit();
// For future use
@@ -73,6 +74,7 @@ pub fn codegen(
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
#[doc(hidden)]
+ #(#cfgs)*
static #instants:
rtic::RacyCell<[core::mem::MaybeUninit<<#mono_type as rtic::Monotonic>::Instant>; #cap_lit]> =
rtic::RacyCell::new([#(#elems,)*]);
diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs
index 32e288c5..f5867dc4 100644
--- a/macros/src/codegen/timer_queue.rs
+++ b/macros/src/codegen/timer_queue.rs
@@ -13,7 +13,6 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
// Generate the marker counter used to track for `cancel` and `reschedule`
let tq_marker = util::timer_queue_marker_ident();
items.push(quote!(
- // #[doc = #doc]
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
@@ -56,6 +55,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let tq = util::tq_ident(&monotonic_name);
let t = util::schedule_t_ident();
let mono_type = &monotonic.ty;
+ let cfgs = &monotonic.cfgs;
let m_ident = util::monotonic_ident(&monotonic_name);
// Static variables and resource proxy
@@ -76,6 +76,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
+ #(#cfgs)*
static #tq: rtic::RacyCell<#tq_ty> =
rtic::RacyCell::new(rtic::export::TimerQueue(rtic::export::SortedLinkedList::new_u16()));
));
@@ -88,6 +89,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
+ #(#cfgs)*
static #mono: rtic::RacyCell<Option<#mono_type>> = rtic::RacyCell::new(None);
));
}
@@ -126,6 +128,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
})
.collect::<Vec<_>>();
+ let cfgs = &monotonic.cfgs;
let bound_interrupt = &monotonic.args.binds;
let disable_isr = if &*bound_interrupt.to_string() == "SysTick" {
quote!(core::mem::transmute::<_, rtic::export::SYST>(()).disable_interrupt())
@@ -136,6 +139,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
items.push(quote!(
#[no_mangle]
#[allow(non_snake_case)]
+ #(#cfgs)*
unsafe fn #bound_interrupt() {
while let Some((task, index)) = rtic::export::interrupt::free(|_|
if let Some(mono) = (&mut *#m_ident.get_mut()).as_mut() {