Skip to content

Commit a601c6e

Browse files
bors[bot]AfoHT
andauthored
Merge #691
691: Basic cfg support, kind of, for Monotonics r=korken89 a=AfoHT - Enable at least masking out a Monotonic - Add example cfg-ing a Monotonic, showing limitations imposed by rtic-syntax - Update changelog The use case detailed in linked issue seems to be covered: Fixes #664 Co-authored-by: Henrik Tjäder <[email protected]>
2 parents a5e18cd + 259be7b commit a601c6e

File tree

8 files changed

+162
-10
lines changed

8 files changed

+162
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
99

1010
### Added
1111

12+
- CFG: Slightly improved support for #[cfg] on Monotonics
1213
- CI: Check examples also for thumbv8.{base,main}
1314
- Allow custom `link_section` attributes for late resources
1415

ci/expected/cfg-monotonic.run

Whitespace-only changes.

examples/cfg-monotonic.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//! examples/cfg-monotonic.rs
2+
3+
#![deny(unsafe_code)]
4+
#![deny(warnings)]
5+
#![deny(missing_docs)]
6+
#![no_main]
7+
#![no_std]
8+
9+
use panic_semihosting as _;
10+
11+
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])]
12+
mod app {
13+
use cortex_m_semihosting::{debug, hprintln};
14+
use systick_monotonic::*; // Implements the `Monotonic` trait
15+
16+
// A monotonic timer to enable scheduling in RTIC
17+
#[cfg(feature = "killmono")]
18+
#[monotonic(binds = SysTick, default = true)]
19+
type MyMono = Systick<100>; // 100 Hz / 10 ms granularity
20+
21+
// Not allowed by current rtic-syntax:
22+
// error: `#[monotonic(...)]` on a specific type must appear at most once
23+
// --> examples/cfg-monotonic.rs:23:10
24+
// |
25+
// 23 | type MyMono = Systick<100>; // 100 Hz / 10 ms granularity
26+
// | ^^^^^^
27+
// #[monotonic(binds = SysTick, default = true)]
28+
// type MyMono = Systick<100>; // 100 Hz / 10 ms granularity
29+
30+
// Not allowed by current rtic-syntax:
31+
// error: this interrupt is already bound
32+
// --> examples/cfg-monotonic.rs:31:25
33+
// |
34+
// 31 | #[monotonic(binds = SysTick, default = true)]
35+
// | ^^^^^^^
36+
// #[monotonic(binds = SysTick, default = true)]
37+
// type MyMono2 = DwtSystick<100>; // 100 Hz / 10 ms granularity
38+
39+
// Resources shared between tasks
40+
#[shared]
41+
struct Shared {
42+
s1: u32,
43+
s2: i32,
44+
}
45+
46+
// Local resources to specific tasks (cannot be shared)
47+
#[local]
48+
struct Local {
49+
l1: u8,
50+
l2: i8,
51+
}
52+
53+
#[init]
54+
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
55+
let _systick = cx.core.SYST;
56+
57+
// Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
58+
#[cfg(feature = "killmono")]
59+
let mono = Systick::new(systick, 12_000_000);
60+
61+
// Spawn the task `foo` directly after `init` finishes
62+
foo::spawn().unwrap();
63+
64+
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
65+
66+
(
67+
// Initialization of shared resources
68+
Shared { s1: 0, s2: 1 },
69+
// Initialization of task local resources
70+
Local { l1: 2, l2: 3 },
71+
// Move the monotonic timer to the RTIC run-time, this enables
72+
// scheduling
73+
#[cfg(feature = "killmono")]
74+
init::Monotonics(mono),
75+
init::Monotonics(),
76+
)
77+
}
78+
79+
// Background task, runs whenever no other tasks are running
80+
#[idle]
81+
fn idle(_: idle::Context) -> ! {
82+
loop {
83+
continue;
84+
}
85+
}
86+
87+
// Software task, not bound to a hardware interrupt.
88+
// This task takes the task local resource `l1`
89+
// The resources `s1` and `s2` are shared between all other tasks.
90+
#[task(shared = [s1, s2], local = [l1])]
91+
fn foo(_: foo::Context) {
92+
// This task is only spawned once in `init`, hence this task will run
93+
// only once
94+
95+
hprintln!("foo");
96+
}
97+
98+
// Software task, also not bound to a hardware interrupt
99+
// This task takes the task local resource `l2`
100+
// The resources `s1` and `s2` are shared between all other tasks.
101+
#[task(shared = [s1, s2], local = [l2])]
102+
fn bar(_: bar::Context) {
103+
hprintln!("bar");
104+
105+
// Run `bar` once per second
106+
// bar::spawn_after(1.secs()).unwrap();
107+
}
108+
109+
// Hardware task, bound to a hardware interrupt
110+
// The resources `s1` and `s2` are shared between all other tasks.
111+
#[task(binds = UART0, priority = 3, shared = [s1, s2])]
112+
fn uart0_interrupt(_: uart0_interrupt::Context) {
113+
// This task is bound to the interrupt `UART0` and will run
114+
// whenever the interrupt fires
115+
116+
// Note that RTIC does NOT clear the interrupt flag, this is up to the
117+
// user
118+
119+
hprintln!("UART0 interrupt!");
120+
}
121+
}

macros/src/codegen.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,18 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
108108
.map(|(_, monotonic)| {
109109
let name = &monotonic.ident;
110110
let name_str = &name.to_string();
111+
let cfgs = &monotonic.cfgs;
111112
let ident = util::monotonic_ident(name_str);
112113
let doc = &format!(
113114
"This module holds the static implementation for `{}::now()`",
114115
name_str
115116
);
116117

117118
let default_monotonic = if monotonic.args.default {
118-
quote!(pub use #name::now;)
119+
quote!(
120+
#(#cfgs)*
121+
pub use #name::now;
122+
)
119123
} else {
120124
quote!()
121125
};
@@ -125,6 +129,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
125129

126130
#[doc = #doc]
127131
#[allow(non_snake_case)]
132+
#(#cfgs)*
128133
pub mod #name {
129134

130135
/// Read the current time from this monotonic

macros/src/codegen/module.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,12 @@ pub fn codegen(
116116
.monotonics
117117
.iter()
118118
.map(|(_, monotonic)| {
119+
let cfgs = &monotonic.cfgs;
119120
let mono = &monotonic.ty;
120-
quote! {#mono}
121+
quote! {
122+
#(#cfgs)*
123+
pub #mono
124+
}
121125
})
122126
.collect();
123127

@@ -128,7 +132,7 @@ pub fn codegen(
128132
#[allow(non_snake_case)]
129133
#[allow(non_camel_case_types)]
130134
pub struct #internal_monotonics_ident(
131-
#(pub #monotonic_types),*
135+
#(#monotonic_types),*
132136
);
133137
));
134138

@@ -226,8 +230,8 @@ pub fn codegen(
226230
// Spawn caller
227231
items.push(quote!(
228232

229-
#(#cfgs)*
230233
/// Spawns the task directly
234+
#(#cfgs)*
231235
pub fn #internal_spawn_ident(#(#args,)*) -> Result<(), #ty> {
232236
let input = #tupled;
233237

@@ -267,6 +271,7 @@ pub fn codegen(
267271
let tq = util::tq_ident(&monotonic.ident.to_string());
268272
let t = util::schedule_t_ident();
269273
let m = &monotonic.ident;
274+
let cfgs = &monotonic.cfgs;
270275
let m_ident = util::monotonic_ident(&monotonic_name);
271276
let m_isr = &monotonic.args.binds;
272277
let enum_ = util::interrupt_ident();
@@ -298,13 +303,17 @@ pub fn codegen(
298303

299304
if monotonic.args.default {
300305
module_items.push(quote!(
306+
#(#cfgs)*
301307
pub use #m::spawn_after;
308+
#(#cfgs)*
302309
pub use #m::spawn_at;
310+
#(#cfgs)*
303311
pub use #m::SpawnHandle;
304312
));
305313
}
306314
module_items.push(quote!(
307315
#[doc(hidden)]
316+
#(#cfgs)*
308317
pub mod #m {
309318
pub use super::super::#internal_spawn_after_ident as spawn_after;
310319
pub use super::super::#internal_spawn_at_ident as spawn_at;
@@ -322,6 +331,7 @@ pub fn codegen(
322331
marker: u32,
323332
}
324333

334+
#(#cfgs)*
325335
impl core::fmt::Debug for #internal_spawn_handle_ident {
326336
#[doc(hidden)]
327337
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
@@ -353,6 +363,7 @@ pub fn codegen(
353363

354364
/// Reschedule after
355365
#[inline]
366+
#(#cfgs)*
356367
pub fn reschedule_after(
357368
self,
358369
duration: <#m as rtic::Monotonic>::Duration
@@ -361,6 +372,7 @@ pub fn codegen(
361372
}
362373

363374
/// Reschedule at
375+
#(#cfgs)*
364376
pub fn reschedule_at(
365377
self,
366378
instant: <#m as rtic::Monotonic>::Instant
@@ -376,11 +388,11 @@ pub fn codegen(
376388
}
377389
}
378390

379-
#(#cfgs)*
380391
/// Spawns the task after a set duration relative to the current time
381392
///
382393
/// This will use the time `Instant::new(0)` as baseline if called in `#[init]`,
383394
/// so if you use a non-resetable timer use `spawn_at` when in `#[init]`
395+
#(#cfgs)*
384396
#[allow(non_snake_case)]
385397
pub fn #internal_spawn_after_ident(
386398
duration: <#m as rtic::Monotonic>::Duration

macros/src/codegen/post_init.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,28 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
4343
}
4444
}
4545

46-
for (i, (monotonic, _)) in app.monotonics.iter().enumerate() {
46+
for (i, (monotonic_ident, monotonic)) in app.monotonics.iter().enumerate() {
4747
// For future use
4848
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
4949
// stmts.push(quote!(#[doc = #doc]));
50+
let cfgs = &monotonic.cfgs;
5051

5152
#[allow(clippy::cast_possible_truncation)]
5253
let idx = Index {
5354
index: i as u32,
5455
span: Span::call_site(),
5556
};
56-
stmts.push(quote!(monotonics.#idx.reset();));
57+
stmts.push(quote!(
58+
#(#cfgs)*
59+
monotonics.#idx.reset();
60+
));
5761

5862
// Store the monotonic
59-
let name = util::monotonic_ident(&monotonic.to_string());
60-
stmts.push(quote!(#name.get_mut().write(Some(monotonics.#idx));));
63+
let name = util::monotonic_ident(&monotonic_ident.to_string());
64+
stmts.push(quote!(
65+
#(#cfgs)*
66+
#name.get_mut().write(Some(monotonics.#idx));
67+
));
6168
}
6269

6370
// Enable the interrupts -- this completes the `init`-ialization phase

macros/src/codegen/software_tasks.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub fn codegen(
6262
for (_, monotonic) in &app.monotonics {
6363
let instants = util::monotonic_instants_ident(name, &monotonic.ident);
6464
let mono_type = &monotonic.ty;
65+
let cfgs = &monotonic.cfgs;
6566

6667
let uninit = mk_uninit();
6768
// For future use
@@ -73,6 +74,7 @@ pub fn codegen(
7374
#[allow(non_camel_case_types)]
7475
#[allow(non_upper_case_globals)]
7576
#[doc(hidden)]
77+
#(#cfgs)*
7678
static #instants:
7779
rtic::RacyCell<[core::mem::MaybeUninit<<#mono_type as rtic::Monotonic>::Instant>; #cap_lit]> =
7880
rtic::RacyCell::new([#(#elems,)*]);

macros/src/codegen/timer_queue.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
1313
// Generate the marker counter used to track for `cancel` and `reschedule`
1414
let tq_marker = util::timer_queue_marker_ident();
1515
items.push(quote!(
16-
// #[doc = #doc]
1716
#[doc(hidden)]
1817
#[allow(non_camel_case_types)]
1918
#[allow(non_upper_case_globals)]
@@ -56,6 +55,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
5655
let tq = util::tq_ident(&monotonic_name);
5756
let t = util::schedule_t_ident();
5857
let mono_type = &monotonic.ty;
58+
let cfgs = &monotonic.cfgs;
5959
let m_ident = util::monotonic_ident(&monotonic_name);
6060

6161
// Static variables and resource proxy
@@ -76,6 +76,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
7676
#[doc(hidden)]
7777
#[allow(non_camel_case_types)]
7878
#[allow(non_upper_case_globals)]
79+
#(#cfgs)*
7980
static #tq: rtic::RacyCell<#tq_ty> =
8081
rtic::RacyCell::new(rtic::export::TimerQueue(rtic::export::SortedLinkedList::new_u16()));
8182
));
@@ -88,6 +89,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
8889
#[doc(hidden)]
8990
#[allow(non_camel_case_types)]
9091
#[allow(non_upper_case_globals)]
92+
#(#cfgs)*
9193
static #mono: rtic::RacyCell<Option<#mono_type>> = rtic::RacyCell::new(None);
9294
));
9395
}
@@ -126,6 +128,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
126128
})
127129
.collect::<Vec<_>>();
128130

131+
let cfgs = &monotonic.cfgs;
129132
let bound_interrupt = &monotonic.args.binds;
130133
let disable_isr = if &*bound_interrupt.to_string() == "SysTick" {
131134
quote!(core::mem::transmute::<_, rtic::export::SYST>(()).disable_interrupt())
@@ -136,6 +139,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
136139
items.push(quote!(
137140
#[no_mangle]
138141
#[allow(non_snake_case)]
142+
#(#cfgs)*
139143
unsafe fn #bound_interrupt() {
140144
while let Some((task, index)) = rtic::export::interrupt::free(|_|
141145
if let Some(mono) = (&mut *#m_ident.get_mut()).as_mut() {

0 commit comments

Comments
 (0)