aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml1
-rw-r--r--examples/baseline.rs10
-rw-r--r--examples/capacity.rs16
-rw-r--r--examples/cfg.rs12
-rw-r--r--examples/double_schedule.rs14
-rw-r--r--examples/message.rs24
-rw-r--r--examples/not-send.rs68
-rw-r--r--examples/periodic.rs8
-rw-r--r--examples/pool.rs8
-rw-r--r--examples/ramfunc.rs12
-rw-r--r--examples/schedule.rs6
-rw-r--r--examples/spawn.rs35
-rw-r--r--examples/spawn2.rs41
-rw-r--r--examples/t-cfg.rs4
-rw-r--r--examples/t-schedule.rs42
-rw-r--r--examples/t-spawn.rs50
-rw-r--r--examples/t-stask-main.rs6
-rw-r--r--examples/task.rs14
-rw-r--r--examples/types.rs19
-rw-r--r--macros/Cargo.toml2
-rw-r--r--macros/src/analyze.rs1
-rw-r--r--macros/src/check.rs62
-rw-r--r--macros/src/codegen.rs19
-rw-r--r--macros/src/codegen/dispatchers.rs24
-rw-r--r--macros/src/codegen/hardware_tasks.rs5
-rw-r--r--macros/src/codegen/idle.rs8
-rw-r--r--macros/src/codegen/init.rs8
-rw-r--r--macros/src/codegen/module.rs260
-rw-r--r--macros/src/codegen/pre_init.rs10
-rw-r--r--macros/src/codegen/schedule.rs90
-rw-r--r--macros/src/codegen/schedule_body.rs59
-rw-r--r--macros/src/codegen/software_tasks.rs89
-rw-r--r--macros/src/codegen/spawn.rs121
-rw-r--r--macros/src/codegen/spawn_body.rs75
-rw-r--r--macros/src/codegen/timer_queue.rs70
-rw-r--r--macros/src/codegen/util.rs16
-rw-r--r--macros/src/lib.rs1
-rw-r--r--ui/single/exception-systick-used.rs5
38 files changed, 420 insertions, 895 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8da98678..def72c95 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -251,7 +251,6 @@ jobs:
capacity
types
- not-send
not-sync
shared-with-init
diff --git a/examples/baseline.rs b/examples/baseline.rs
index 3ab40dbb..0b7e3ea0 100644
--- a/examples/baseline.rs
+++ b/examples/baseline.rs
@@ -12,19 +12,19 @@ use panic_semihosting as _;
// NOTE: does NOT properly work on QEMU
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app {
- #[init(spawn = [foo])]
+ #[init]
fn init(cx: init::Context) -> init::LateResources {
// omitted: initialization of `CYCCNT`
hprintln!("init(baseline = {:?})", cx.start).unwrap();
// `foo` inherits the baseline of `init`: `Instant(0)`
- cx.spawn.foo().unwrap();
+ foo::spawn().unwrap();
init::LateResources {}
}
- #[task(schedule = [foo])]
+ #[task]
fn foo(cx: foo::Context) {
static mut ONCE: bool = true;
@@ -39,12 +39,12 @@ mod app {
}
}
- #[task(binds = UART0, spawn = [foo])]
+ #[task(binds = UART0)]
fn uart0(cx: uart0::Context) {
hprintln!("UART0(baseline = {:?})", cx.start).unwrap();
// `foo` inherits the baseline of `UART0`: its `start` time
- cx.spawn.foo().unwrap();
+ foo::spawn().unwrap();
}
// RTIC requires that unused interrupts are declared in an extern block when
diff --git a/examples/capacity.rs b/examples/capacity.rs
index ba8b15b0..f903acbc 100644
--- a/examples/capacity.rs
+++ b/examples/capacity.rs
@@ -18,14 +18,14 @@ mod app {
init::LateResources {}
}
- #[task(binds = UART0, spawn = [foo, bar])]
- fn uart0(c: uart0::Context) {
- c.spawn.foo(0).unwrap();
- c.spawn.foo(1).unwrap();
- c.spawn.foo(2).unwrap();
- c.spawn.foo(3).unwrap();
-
- c.spawn.bar().unwrap();
+ #[task(binds = UART0)]
+ fn uart0(_: uart0::Context) {
+ foo::spawn(0).unwrap();
+ foo::spawn(1).unwrap();
+ foo::spawn(2).unwrap();
+ foo::spawn(3).unwrap();
+
+ bar::spawn().unwrap();
}
#[task(capacity = 4)]
diff --git a/examples/cfg.rs b/examples/cfg.rs
index d49f54c7..c8892eaf 100644
--- a/examples/cfg.rs
+++ b/examples/cfg.rs
@@ -19,10 +19,10 @@ mod app {
count: u32,
}
- #[init(spawn = [foo])]
- fn init(cx: init::Context) -> init::LateResources {
- cx.spawn.foo().unwrap();
- cx.spawn.foo().unwrap();
+ #[init]
+ fn init(_: init::Context) -> init::LateResources {
+ foo::spawn().unwrap();
+ foo::spawn().unwrap();
init::LateResources {}
}
@@ -36,13 +36,13 @@ mod app {
}
}
- #[task(capacity = 2, resources = [count], spawn = [log])]
+ #[task(capacity = 2, resources = [count])]
fn foo(_cx: foo::Context) {
#[cfg(debug_assertions)]
{
*_cx.resources.count += 1;
- _cx.spawn.log(*_cx.resources.count).unwrap();
+ log::spawn(*_cx.resources.count).unwrap();
}
// this wouldn't compile in `release` mode
diff --git a/examples/double_schedule.rs b/examples/double_schedule.rs
index b1b78b80..d242c57e 100644
--- a/examples/double_schedule.rs
+++ b/examples/double_schedule.rs
@@ -16,21 +16,21 @@ mod app {
nothing: (),
}
- #[init(spawn = [task1])]
- fn init(cx: init::Context) -> init::LateResources {
- cx.spawn.task1().ok();
+ #[init]
+ fn init(_: init::Context) -> init::LateResources {
+ task1::spawn().ok();
init::LateResources { nothing: () }
}
- #[task(schedule = [task2])]
+ #[task]
fn task1(_cx: task1::Context) {
- _cx.schedule.task2(_cx.scheduled + 100.cycles()).ok();
+ task2::schedule(_cx.scheduled + 100.cycles()).ok();
}
- #[task(schedule = [task1])]
+ #[task]
fn task2(_cx: task2::Context) {
- _cx.schedule.task1(_cx.scheduled + 100.cycles()).ok();
+ task1::schedule(_cx.scheduled + 100.cycles()).ok();
}
extern "C" {
diff --git a/examples/message.rs b/examples/message.rs
index f9736728..5ff6288a 100644
--- a/examples/message.rs
+++ b/examples/message.rs
@@ -10,39 +10,39 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
- #[init(spawn = [foo])]
- fn init(c: init::Context) -> init::LateResources {
- c.spawn.foo(/* no message */).unwrap();
+ #[init]
+ fn init(_: init::Context) -> init::LateResources {
+ foo::spawn(/* no message */).unwrap();
init::LateResources {}
}
- #[task(spawn = [bar])]
- fn foo(c: foo::Context) {
+ #[task]
+ fn foo(_: foo::Context) {
static mut COUNT: u32 = 0;
hprintln!("foo").unwrap();
- c.spawn.bar(*COUNT).unwrap();
+ bar::spawn(*COUNT).unwrap();
*COUNT += 1;
}
- #[task(spawn = [baz])]
- fn bar(c: bar::Context, x: u32) {
+ #[task]
+ fn bar(_: bar::Context, x: u32) {
hprintln!("bar({})", x).unwrap();
- c.spawn.baz(x + 1, x + 2).unwrap();
+ baz::spawn(x + 1, x + 2).unwrap();
}
- #[task(spawn = [foo])]
- fn baz(c: baz::Context, x: u32, y: u32) {
+ #[task]
+ fn baz(_: baz::Context, x: u32, y: u32) {
hprintln!("baz({}, {})", x, y).unwrap();
if x + y > 4 {
debug::exit(debug::EXIT_SUCCESS);
}
- c.spawn.foo().unwrap();
+ foo::spawn().unwrap();
}
// RTIC requires that unused interrupts are declared in an extern block when
diff --git a/examples/not-send.rs b/examples/not-send.rs
deleted file mode 100644
index 18071fc5..00000000
--- a/examples/not-send.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-//! `examples/not-send.rs`
-
-#![deny(unsafe_code)]
-#![deny(warnings)]
-#![no_main]
-#![no_std]
-
-use core::marker::PhantomData;
-
-use cortex_m_semihosting::debug;
-use panic_halt as _;
-use rtic::app;
-
-pub struct NotSend {
- _0: PhantomData<*const ()>,
-}
-
-#[app(device = lm3s6965)]
-mod app {
- use super::NotSend;
-
- #[resources]
- struct Resources {
- #[init(None)]
- shared: Option<NotSend>,
- }
-
- #[init(spawn = [baz, quux])]
- fn init(c: init::Context) -> init::LateResources {
- c.spawn.baz().unwrap();
- c.spawn.quux().unwrap();
-
- init::LateResources {}
- }
-
- #[task(spawn = [bar])]
- fn foo(c: foo::Context) {
- // scenario 1: message passed to task that runs at the same priority
- c.spawn.bar(NotSend { _0: PhantomData }).ok();
- }
-
- #[task]
- fn bar(_: bar::Context, _x: NotSend) {
- // scenario 1
- }
-
- #[task(priority = 2, resources = [shared])]
- fn baz(c: baz::Context) {
- // scenario 2: resource shared between tasks that run at the same priority
- *c.resources.shared = Some(NotSend { _0: PhantomData });
- }
-
- #[task(priority = 2, resources = [shared])]
- fn quux(c: quux::Context) {
- // scenario 2
- let _not_send = c.resources.shared.take().unwrap();
-
- debug::exit(debug::EXIT_SUCCESS);
- }
-
- // RTIC requires that unused interrupts are declared in an extern block when
- // using software tasks; these free interrupts will be used to dispatch the
- // software tasks.
- extern "C" {
- fn SSI0();
- fn QEI0();
- }
-}
diff --git a/examples/periodic.rs b/examples/periodic.rs
index d3aedd32..95cd1451 100644
--- a/examples/periodic.rs
+++ b/examples/periodic.rs
@@ -15,21 +15,21 @@ const PERIOD: u32 = 8_000_000;
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app {
- #[init(schedule = [foo])]
+ #[init]
fn init(cx: init::Context) -> init::LateResources {
// omitted: initialization of `CYCCNT`
- cx.schedule.foo(cx.start + PERIOD.cycles()).unwrap();
+ foo::schedule(cx.start + PERIOD.cycles()).unwrap();
init::LateResources {}
}
- #[task(schedule = [foo])]
+ #[task]
fn foo(cx: foo::Context) {
let now = Instant::now();
hprintln!("foo(scheduled = {:?}, now = {:?})", cx.scheduled, now).unwrap();
- cx.schedule.foo(cx.scheduled + PERIOD.cycles()).unwrap();
+ foo::schedule(cx.scheduled + PERIOD.cycles()).unwrap();
}
// RTIC requires that unused interrupts are declared in an extern block when
diff --git a/examples/pool.rs b/examples/pool.rs
index cdbabca7..2ad99841 100644
--- a/examples/pool.rs
+++ b/examples/pool.rs
@@ -36,16 +36,16 @@ mod app {
init::LateResources {}
}
- #[task(binds = I2C0, priority = 2, spawn = [foo, bar])]
- fn i2c0(c: i2c0::Context) {
+ #[task(binds = I2C0, priority = 2)]
+ fn i2c0(_: i2c0::Context) {
// claim a memory block, leave it uninitialized and ..
let x = P::alloc().unwrap().freeze();
// .. send it to the `foo` task
- c.spawn.foo(x).ok().unwrap();
+ foo::spawn(x).ok().unwrap();
// send another block to the task `bar`
- c.spawn.bar(P::alloc().unwrap().freeze()).ok().unwrap();
+ bar::spawn(P::alloc().unwrap().freeze()).ok().unwrap();
}
#[task]
diff --git a/examples/ramfunc.rs b/examples/ramfunc.rs
index 5ff167a3..84d633dd 100644
--- a/examples/ramfunc.rs
+++ b/examples/ramfunc.rs
@@ -10,9 +10,9 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
- #[init(spawn = [bar])]
- fn init(c: init::Context) -> init::LateResources {
- c.spawn.bar().unwrap();
+ #[init]
+ fn init(_: init::Context) -> init::LateResources {
+ foo::spawn().unwrap();
init::LateResources {}
}
@@ -28,9 +28,9 @@ mod app {
// run this task from RAM
#[inline(never)]
#[link_section = ".data.bar"]
- #[task(priority = 2, spawn = [foo])]
- fn bar(c: bar::Context) {
- c.spawn.foo().unwrap();
+ #[task(priority = 2)]
+ fn bar(_: bar::Context) {
+ foo::spawn().unwrap();
}
extern "C" {
diff --git a/examples/schedule.rs b/examples/schedule.rs
index 7e6adc1a..fa67a566 100644
--- a/examples/schedule.rs
+++ b/examples/schedule.rs
@@ -13,7 +13,7 @@ use rtic::cyccnt::{Instant, U32Ext as _};
// NOTE: does NOT work on QEMU!
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app {
- #[init(schedule = [foo, bar])]
+ #[init()]
fn init(mut cx: init::Context) -> init::LateResources {
// Initialize (enable) the monotonic timer (CYCCNT)
cx.core.DCB.enable_trace();
@@ -28,10 +28,10 @@ mod app {
hprintln!("init @ {:?}", now).unwrap();
// Schedule `foo` to run 8e6 cycles (clock cycles) in the future
- cx.schedule.foo(now + 8_000_000.cycles()).unwrap();
+ foo::schedule(now + 8_000_000.cycles()).unwrap();
// Schedule `bar` to run 4e6 cycles in the future
- cx.schedule.bar(now + 4_000_000.cycles()).unwrap();
+ bar::schedule(now + 4_000_000.cycles()).unwrap();
init::LateResources {}
}
diff --git a/examples/spawn.rs b/examples/spawn.rs
new file mode 100644
index 00000000..0720bf95
--- /dev/null
+++ b/examples/spawn.rs
@@ -0,0 +1,35 @@
+//! examples/message.rs
+
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![no_main]
+#![no_std]
+
+use cortex_m_semihosting::{debug, hprintln};
+use panic_semihosting as _;
+
+#[rtic::app(device = lm3s6965)]
+mod app {
+ #[init]
+ fn init(_c: init::Context) -> init::LateResources {
+ foo::spawn(1, 2).unwrap();
+
+ init::LateResources {}
+ }
+
+ #[task()]
+ fn foo(_c: foo::Context, x: i32, y: u32) {
+ hprintln!("foo {}, {}", x, y).unwrap();
+ if x == 2 {
+ debug::exit(debug::EXIT_SUCCESS);
+ }
+ foo::spawn(2, 3).unwrap();
+ }
+
+ // RTIC requires that unused interrupts are declared in an extern block when
+ // using software tasks; these free interrupts will be used to dispatch the
+ // software tasks.
+ extern "C" {
+ fn SSI0();
+ }
+}
diff --git a/examples/spawn2.rs b/examples/spawn2.rs
new file mode 100644
index 00000000..2998d16c
--- /dev/null
+++ b/examples/spawn2.rs
@@ -0,0 +1,41 @@
+//! examples/message.rs
+
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![no_main]
+#![no_std]
+
+use cortex_m_semihosting::{debug, hprintln};
+use panic_semihosting as _;
+
+#[rtic::app(device = lm3s6965)]
+mod app {
+ #[init]
+ fn init(_c: init::Context) -> init::LateResources {
+ foo::spawn(1, 2).unwrap();
+
+ init::LateResources {}
+ }
+
+ #[task]
+ fn foo(_c: foo::Context, x: i32, y: u32) {
+ hprintln!("foo {}, {}", x, y).unwrap();
+ if x == 2 {
+ debug::exit(debug::EXIT_SUCCESS);
+ }
+ foo2::spawn(2).unwrap();
+ }
+
+ #[task]
+ fn foo2(_c: foo2::Context, x: i32) {
+ hprintln!("foo2 {}", x).unwrap();
+ foo::spawn(x, 0).unwrap();
+ }
+
+ // RTIC requires that unused interrupts are declared in an extern block when
+ // using software tasks; these free interrupts will be used to dispatch the
+ // software tasks.
+ extern "C" {
+ fn SSI0();
+ }
+}
diff --git a/examples/t-cfg.rs b/examples/t-cfg.rs
index 3da20d4e..7076f5d7 100644
--- a/examples/t-cfg.rs
+++ b/examples/t-cfg.rs
@@ -32,13 +32,13 @@ mod app {
}
}
- #[task(resources = [foo], schedule = [quux], spawn = [quux])]
+ #[task(resources = [foo])]
fn foo(_: foo::Context) {
#[cfg(never)]
static mut BAR: u32 = 0;
}
- #[task(priority = 3, resources = [foo], schedule = [quux], spawn = [quux])]
+ #[task(priority = 3, resources = [foo])]
fn bar(_: bar::Context) {
#[cfg(never)]
static mut BAR: u32 = 0;
diff --git a/examples/t-schedule.rs b/examples/t-schedule.rs
index d5a6d3ff..7c2c420c 100644
--- a/examples/t-schedule.rs
+++ b/examples/t-schedule.rs
@@ -10,45 +10,45 @@ use rtic::cyccnt::{Instant, U32Ext as _};
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app {
- #[init(schedule = [foo, bar, baz])]
+ #[init]
fn init(c: init::Context) -> init::LateResources {
- let _: Result<(), ()> = c.schedule.foo(c.start + 10.cycles());
- let _: Result<(), u32> = c.schedule.bar(c.start + 20.cycles(), 0);
- let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 30.cycles(), 0, 1);
+ let _: Result<(), ()> = foo::schedule(c.start + 10.cycles());
+ let _: Result<(), u32> = bar::schedule(c.start + 20.cycles(), 0);
+ let _: Result<(), (u32, u32)> = baz::schedule(c.start + 30.cycles(), 0, 1);
init::LateResources {}
}
- #[idle(schedule = [foo, bar, baz])]
- fn idle(c: idle::Context) -> ! {
- let _: Result<(), ()> = c.schedule.foo(Instant::now() + 40.cycles());
- let _: Result<(), u32> = c.schedule.bar(Instant::now() + 50.cycles(), 0);
- let _: Result<(), (u32, u32)> = c.schedule.baz(Instant::now() + 60.cycles(), 0, 1);
+ #[idle]
+ fn idle(_: idle::Context) -> ! {
+ let _: Result<(), ()> = foo::schedule(Instant::now() + 40.cycles());
+ let _: Result<(), u32> = bar::schedule(Instant::now() + 50.cycles(), 0);
+ let _: Result<(), (u32, u32)> = baz::schedule(Instant::now() + 60.cycles(), 0, 1);
loop {
cortex_m::asm::nop();
}
}
- #[task(binds = SVCall, schedule = [foo, bar, baz])]
+ #[task(binds = SVCall)]
fn svcall(c: svcall::Context) {
- let _: Result<(), ()> = c.schedule.foo(c.start + 70.cycles());
- let _: Result<(), u32> = c.schedule.bar(c.start + 80.cycles(), 0);
- let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 90.cycles(), 0, 1);
+ let _: Result<(), ()> = foo::schedule(c.start + 70.cycles());
+ let _: Result<(), u32> = bar::schedule(c.start + 80.cycles(), 0);
+ let _: Result<(), (u32, u32)> = baz::schedule(c.start + 90.cycles(), 0, 1);
}
- #[task(binds = UART0, schedule = [foo, bar, baz])]
+ #[task(binds = UART0)]
fn uart0(c: uart0::Context) {
- let _: Result<(), ()> = c.schedule.foo(c.start + 100.cycles());
- let _: Result<(), u32> = c.schedule.bar(c.start + 110.cycles(), 0);
- let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 120.cycles(), 0, 1);
+ let _: Result<(), ()> = foo::schedule(c.start + 100.cycles());
+ let _: Result<(), u32> = bar::schedule(c.start + 110.cycles(), 0);
+ let _: Result<(), (u32, u32)> = baz::schedule(c.start + 120.cycles(), 0, 1);
}
- #[task(schedule = [foo, bar, baz])]
+ #[task]
fn foo(c: foo::Context) {
- let _: Result<(), ()> = c.schedule.foo(c.scheduled + 130.cycles());
- let _: Result<(), u32> = c.schedule.bar(c.scheduled + 140.cycles(), 0);
- let _: Result<(), (u32, u32)> = c.schedule.baz(c.scheduled + 150.cycles(), 0, 1);
+ let _: Result<(), ()> = foo::schedule(c.scheduled + 130.cycles());
+ let _: Result<(), u32> = bar::schedule(c.scheduled + 140.cycles(), 0);
+ let _: Result<(), (u32, u32)> = baz::schedule(c.scheduled + 150.cycles(), 0, 1);
}
#[task]
diff --git a/examples/t-spawn.rs b/examples/t-spawn.rs
index efb748bc..cf850e46 100644
--- a/examples/t-spawn.rs
+++ b/examples/t-spawn.rs
@@ -9,45 +9,45 @@ use panic_halt as _;
#[rtic::app(device = lm3s6965)]
mod app {
- #[init(spawn = [foo, bar, baz])]
- fn init(c: init::Context) -> init::LateResources {
- let _: Result<(), ()> = c.spawn.foo();
- let _: Result<(), u32> = c.spawn.bar(0);
- let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
+ #[init]
+ fn init(_: init::Context) -> init::LateResources {
+ let _: Result<(), ()> = foo::spawn();
+ let _: Result<(), u32> = bar::spawn(0);
+ let _: Result<(), (u32, u32)> = baz::spawn(0, 1);
init::LateResources {}
}
- #[idle(spawn = [foo, bar, baz])]
- fn idle(c: idle::Context) -> ! {
- let _: Result<(), ()> = c.spawn.foo();
- let _: Result<(), u32> = c.spawn.bar(0);
- let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
+ #[idle]
+ fn idle(_: idle::Context) -> ! {
+ let _: Result<(), ()> = foo::spawn();
+ let _: Result<(), u32> = bar::spawn(0);
+ let _: Result<(), (u32, u32)> = baz::spawn(0, 1);
loop {
cortex_m::asm::nop();
}
}
- #[task(binds = SVCall, spawn = [foo, bar, baz])]
- fn svcall(c: svcall::Context) {
- let _: Result<(), ()> = c.spawn.foo();
- let _: Result<(), u32> = c.spawn.bar(0);
- let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
+ #[task(binds = SVCall)]
+ fn svcall(_: svcall::Context) {
+ let _: Result<(), ()> = foo::spawn();
+ let _: Result<(), u32> = bar::spawn(0);
+ let _: Result<(), (u32, u32)> = baz::spawn(0, 1);
}
- #[task(binds = UART0, spawn = [foo, bar, baz])]
- fn uart0(c: uart0::Context) {
- let _: Result<(), ()> = c.spawn.foo();
- let _: Result<(), u32> = c.spawn.bar(0);
- let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
+ #[task(binds = UART0)]
+ fn uart0(_: uart0::Context) {
+ let _: Result<(), ()> = foo::spawn();
+ let _: Result<(), u32> = bar::spawn(0);
+ let _: Result<(), (u32, u32)> = baz::spawn(0, 1);
}
- #[task(spawn = [foo, bar, baz])]
- fn foo(c: foo::Context) {
- let _: Result<(), ()> = c.spawn.foo();
- let _: Result<(), u32> = c.spawn.bar(0);
- let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
+ #[task]
+ fn foo(_: foo::Context) {
+ let _: Result<(), ()> = foo::spawn();
+ let _: Result<(), u32> = bar::spawn(0);
+ let _: Result<(), (u32, u32)> = baz::spawn(0, 1);
}
#[task]
diff --git a/examples/t-stask-main.rs b/examples/t-stask-main.rs
index 74335c18..3337c7d3 100644
--- a/examples/t-stask-main.rs
+++ b/examples/t-stask-main.rs
@@ -8,9 +8,9 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
- #[init(spawn = [taskmain])]
- fn init(cx: init::Context) -> init::LateResources {
- cx.spawn.taskmain().ok();
+ #[init]
+ fn init(_: init::Context) -> init::LateResources {
+ taskmain::spawn().ok();
init::LateResources {}
}
diff --git a/examples/task.rs b/examples/task.rs
index 80a9c431..f3d916f3 100644
--- a/examples/task.rs
+++ b/examples/task.rs
@@ -10,27 +10,27 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
- #[init(spawn = [foo])]
- fn init(c: init::Context) -> init::LateResources {
- c.spawn.foo().unwrap();
+ #[init]
+ fn init(_: init::Context) -> init::LateResources {
+ foo::spawn().unwrap();
init::LateResources {}
}
- #[task(spawn = [bar, baz])]
- fn foo(c: foo::Context) {
+ #[task]
+ fn foo(_: foo::Context) {
hprintln!("foo - start").unwrap();
// spawns `bar` onto the task scheduler
// `foo` and `bar` have the same priority so `bar` will not run until
// after `foo` terminates
- c.spawn.bar().unwrap();
+ bar::spawn().unwrap();
hprintln!("foo - middle").unwrap();
// spawns `baz` onto the task scheduler
// `baz` has higher priority than `foo` so it immediately preempts `foo`
- c.spawn.baz().unwrap();
+ baz::spawn().unwrap();
hprintln!("foo - end").unwrap();
}
diff --git a/examples/types.rs b/examples/types.rs
index 251d004c..b55a98c6 100644
--- a/examples/types.rs
+++ b/examples/types.rs
@@ -17,44 +17,35 @@ mod app {
shared: u32,
}
- #[init(schedule = [foo], spawn = [foo])]
+ #[init]
fn init(cx: init::Context) -> init::LateResources {
let _: cyccnt::Instant = cx.start;
let _: rtic::Peripherals = cx.core;
let _: lm3s6965::Peripherals = cx.device;
- let _: init::Schedule = cx.schedule;
- let _: init::Spawn = cx.spawn;
debug::exit(debug::EXIT_SUCCESS);
init::LateResources {}
}
- #[idle(schedule = [foo], spawn = [foo])]
- fn idle(cx: idle::Context) -> ! {
- let _: idle::Schedule = cx.schedule;
- let _: idle::Spawn = cx.spawn;
-
+ #[idle]
+ fn idle(_: idle::Context) -> ! {
loop {
cortex_m::asm::nop();
}
}
- #[task(binds = UART0, resources = [shared], schedule = [foo], spawn = [foo])]
+ #[task(binds = UART0, resources = [shared])]
fn uart0(cx: uart0::Context) {
let _: cyccnt::Instant = cx.start;
let _: resources::shared = cx.resources.shared;
- let _: uart0::Schedule = cx.schedule;
- let _: uart0::Spawn = cx.spawn;
}
- #[task(priority = 2, resources = [shared], schedule = [foo], spawn = [foo])]
+ #[task(priority = 2, resources = [shared])]
fn foo(cx: foo::Context) {
let _: cyccnt::Instant = cx.scheduled;
let _: &mut u32 = cx.resources.shared;
let _: foo::Resources = cx.resources;
- let _: foo::Schedule = cx.schedule;
- let _: foo::Spawn = cx.spawn;
}
// RTIC requires that unused interrupts are declared in an extern block when
diff --git a/macros/Cargo.toml b/macros/Cargo.toml
index 610890bb..1413c6f3 100644
--- a/macros/Cargo.toml
+++ b/macros/Cargo.toml
@@ -21,5 +21,5 @@ proc-macro = true
proc-macro2 = "1"
quote = "1"
syn = "1"
-rtic-syntax = { git = "https://github.com/rtic-rs/rtic-syntax", branch = "master", version = "0.4.0" }
+rtic-syntax = { git = "https://github.com/rtic-rs/rtic-syntax", branch = "no_spawn_no_schedule", version = "0.4.0" }
diff --git a/macros/src/analyze.rs b/macros/src/analyze.rs
index 38018c8c..e0231a2e 100644
--- a/macros/src/analyze.rs
+++ b/macros/src/analyze.rs
@@ -29,7 +29,6 @@ pub fn app(analysis: P<analyze::Analysis>, app: &App) -> P<Analysis> {
.software_tasks
.values()
.filter_map(|task| Some(task.args.priority))
- .chain(analysis.timer_queues.first().map(|tq| tq.priority))
.collect::<BTreeSet<_>>();
if !priorities.is_empty() {
diff --git a/macros/src/check.rs b/macros/src/check.rs
index 0e57bb73..5a1d3aff 100644
--- a/macros/src/check.rs
+++ b/macros/src/check.rs
@@ -19,35 +19,7 @@ impl<'a> Extra<'a> {
}
}
-pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
- // Check that all exceptions are valid; only exceptions with configurable priorities are
- // accepted
- for (name, task) in &app.hardware_tasks {
- let name_s = task.args.binds.to_string();
- match &*name_s {
- "SysTick" => {
- // If the timer queue is used, then SysTick is unavailable
- if !analysis.timer_queues.is_empty() {
- return Err(parse::Error::new(
- name.span(),
- "this exception can't be used because it's being used by the runtime",
- ));
- } else {
- // OK
- }
- }
-
- "NonMaskableInt" | "HardFault" => {
- return Err(parse::Error::new(
- name.span(),
- "only exceptions with configurable priority can be used as hardware tasks",
- ));
- }
-
- _ => {}
- }
- }
-
+pub fn app<'a>(app: &'a App, _analysis: &Analysis) -> parse::Result<Extra<'a>> {
// Check that external (device-specific) interrupts are not named after known (Cortex-M)
// exceptions
for name in app.extern_interrupts.keys() {
@@ -76,7 +48,6 @@ pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
first = Some(name);
Some(task.args.priority)
})
- .chain(analysis.timer_queues.first().map(|tq| tq.priority))
.collect::<HashSet<_>>();
let need = priorities.len();
@@ -141,11 +112,32 @@ pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
}
}
- if !&analysis.timer_queues.is_empty() && monotonic.is_none() {
- return Err(parse::Error::new(
- Span::call_site(),
- "a `monotonic` timer must be specified to use the `schedule` API",
- ));
+ // Check that all exceptions are valid; only exceptions with configurable priorities are
+ // accepted
+ for (name, task) in &app.hardware_tasks {
+ let name_s = task.args.binds.to_string();
+ match &*name_s {
+ "SysTick" => {
+ // If the timer queue is used, then SysTick is unavailable
+ if monotonic.is_some() {
+ return Err(parse::Error::new(
+ name.span(),
+ "this exception can't be used because it's being used by the runtime",
+ ));
+ } else {
+ // OK
+ }
+ }
+
+ "NonMaskableInt" | "HardFault" => {
+ return Err(parse::Error::new(
+ name.span(),
+ "only exceptions with configurable priority can be used as hardware tasks",
+ ));
+ }
+
+ _ => {}
+ }
}
if let Some(device) = device {
diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs
index e89776c5..4ce876b5 100644
--- a/macros/src/codegen.rs
+++ b/macros/src/codegen.rs
@@ -15,11 +15,7 @@ mod post_init;
mod pre_init;
mod resources;
mod resources_struct;
-mod schedule;
-mod schedule_body;
mod software_tasks;
-mod spawn;
-mod spawn_body;
mod timer_queue;
mod util;
@@ -115,17 +111,12 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
) = software_tasks::codegen(app, analysis, extra);
let mod_app_dispatchers = dispatchers::codegen(app, analysis, extra);
-
- let mod_app_spawn = spawn::codegen(app, analysis, extra);
-
let mod_app_timer_queue = timer_queue::codegen(app, analysis, extra);
-
- let mod_app_schedule = schedule::codegen(app, extra);
-
- let user_imports = app.user_imports.clone();
- let user_code = app.user_code.clone();
+ let user_imports = &app.user_imports;
+ let user_code = &app.user_code;
let name = &app.name;
let device = extra.device;
+
quote!(
#(#user)*
@@ -170,12 +161,8 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
#(#mod_app_dispatchers)*
- #(#mod_app_spawn)*
-
#(#mod_app_timer_queue)*
- #(#mod_app_schedule)*
-
#(#mains)*
}
)
diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs
index 300aa996..bf6986b8 100644
--- a/macros/src/codegen/dispatchers.rs
+++ b/macros/src/codegen/dispatchers.rs
@@ -35,7 +35,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
#[doc = #doc]
- enum #t {
+ pub enum #t {
#(#variants,)*
}
));
@@ -57,27 +57,9 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
);
items.push(quote!(
#[doc = #doc]
- static mut #rq: #rq_ty = #rq_expr;
+ pub static mut #rq: #rq_ty = #rq_expr;
));
- if let Some(ceiling) = channel.ceiling {
- items.push(quote!(
- struct #rq<'a> {
- priority: &'a rtic::export::Priority,
- }
- ));
-
- items.push(util::impl_mutex(
- extra,
- &[],
- false,
- &rq,
- rq_ty,
- ceiling,
- quote!(&mut #rq),
- ));
- }
-
let arms = channel
.tasks
.iter()
@@ -88,7 +70,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let inputs = util::inputs_ident(name);
let (_, tupled, pats, _) = util::regroup_inputs(&task.inputs);
- let (let_instant, instant) = if app.uses_schedule() {
+ let (let_instant, instant) = if extra.monotonic.is_some() {
let instants = util::instants_ident(name);
(
diff --git a/macros/src/codegen/hardware_tasks.rs b/macros/src/codegen/hardware_tasks.rs
index 25f1df41..ebfa69b9 100644
--- a/macros/src/codegen/hardware_tasks.rs
+++ b/macros/src/codegen/hardware_tasks.rs
@@ -32,9 +32,7 @@ pub fn codegen(
let mut hardware_tasks_imports = vec![];
for (name, task) in &app.hardware_tasks {
- let (let_instant, instant) = if app.uses_schedule() {
- let m = extra.monotonic();
-
+ let (let_instant, instant) = if let Some(m) = extra.monotonic {
(
Some(quote!(let instant = <#m as rtic::Monotonic>::now();)),
Some(quote!(, instant)),
@@ -97,6 +95,7 @@ pub fn codegen(
Context::HardwareTask(name),
needs_lt,
app,
+ analysis,
extra,
));
diff --git a/macros/src/codegen/idle.rs b/macros/src/codegen/idle.rs
index 2e2932d7..5e73329f 100644
--- a/macros/src/codegen/idle.rs
+++ b/macros/src/codegen/idle.rs
@@ -62,7 +62,13 @@ pub fn codegen(
root_idle.push(locals);
}
- root_idle.push(module::codegen(Context::Idle, needs_lt, app, extra));
+ root_idle.push(module::codegen(
+ Context::Idle,
+ needs_lt,
+ app,
+ analysis,
+ extra,
+ ));
let attrs = &idle.attrs;
let context = &idle.context;
diff --git a/macros/src/codegen/init.rs b/macros/src/codegen/init.rs
index 8942439b..465a927d 100644
--- a/macros/src/codegen/init.rs
+++ b/macros/src/codegen/init.rs
@@ -116,7 +116,13 @@ pub fn codegen(
quote!(let late = crate::#name(#(#locals_new,)* #name::Context::new(core.into()));),
);
- root_init.push(module::codegen(Context::Init, needs_lt, app, extra));
+ root_init.push(module::codegen(
+ Context::Init,
+ needs_lt,
+ app,
+ analysis,
+ extra,
+ ));
(mod_app, root_init, user_init, user_init_imports, call_init)
} else {
diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs
index 3d90cbd3..e3b0ed9b 100644
--- a/macros/src/codegen/module.rs
+++ b/macros/src/codegen/module.rs
@@ -2,9 +2,15 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
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 {
+use crate::{analyze::Analysis, check::Extra, codegen::util};
+
+pub fn codegen(
+ ctxt: Context,
+ resources_tick: bool,
+ app: &App,
+ analysis: &Analysis,
+ extra: &Extra,
+) -> TokenStream2 {
let mut items = vec![];
let mut fields = vec![];
let mut values = vec![];
@@ -15,9 +21,7 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
let mut lt = None;
match ctxt {
Context::Init => {
- if extra.monotonic.is_some() {
- let m = extra.monotonic();
-
+ if let Some(m) = extra.monotonic {
fields.push(quote!(
/// System start time = `Instant(0 /* cycles */)`
pub start: <#m as rtic::Monotonic>::Instant
@@ -61,9 +65,7 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
Context::Idle => {}
Context::HardwareTask(..) => {
- if app.uses_schedule() {
- let m = extra.monotonic();
-
+ if let Some(m) = extra.monotonic {
fields.push(quote!(
/// Time at which this handler started executing
pub start: <#m as rtic::Monotonic>::Instant
@@ -76,9 +78,7 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
}
Context::SoftwareTask(..) => {
- if app.uses_schedule() {
- let m = extra.monotonic();
-
+ if let Some(m) = extra.monotonic {
fields.push(quote!(
/// The time at which this task was scheduled to run
pub scheduled: <#m as rtic::Monotonic>::Instant
@@ -126,139 +126,6 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
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> {
- priority: &'a rtic::export::Priority,
- }
-
- impl<'a> Schedule<'a> {
- #[doc(hidden)]
- #[inline(always)]
- 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> {
- priority: &'a rtic::export::Priority,
- }
- ));
-
- values.push(quote!(spawn: Spawn { priority }));
- } else {
- let instant_field = if app.uses_schedule() {
- let m = extra.monotonic();
-
- needs_instant = true;
- instant_method = Some(quote!(
- pub unsafe fn instant(&self) -> <#m as rtic::Monotonic>::Instant {
- self.instant
- }
- ));
- 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
- 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)]
- pub unsafe fn priority(&self) -> &rtic::export::Priority {
- self.priority
- }
-
- #instant_method
- }
- ));
- }
- }
-
if let Context::Init = ctxt {
let init = &app.inits.first().unwrap();
let late_resources = util::late_resources_ident(&init.name);
@@ -316,11 +183,114 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
}
));
+ // not sure if this is the right way, maybe its backwards,
+ // that spawn_module should put in in root
+
+ if let Context::SoftwareTask(..) = ctxt {
+ let spawnee = &app.software_tasks[name];
+ let priority = spawnee.args.priority;
+ let t = util::spawn_t_ident(priority);
+ let cfgs = &spawnee.cfgs;
+ let (args, tupled, _untupled, ty) = util::regroup_inputs(&spawnee.inputs);
+ let args = &args;
+ let tupled = &tupled;
+ let fq = util::fq_ident(name);
+ let rq = util::rq_ident(priority);
+ let inputs = util::inputs_ident(name);
+
+ let app_name = &app.name;
+ let app_path = quote! {crate::#app_name};
+
+ let device = extra.device;
+ let enum_ = util::interrupt_ident();
+ let interrupt = &analysis.interrupts.get(&priority);
+
+ // Spawn caller
+ items.push(quote!(
+ #(#cfgs)*
+ pub fn spawn(#(#args,)*) -> Result<(), #ty> {
+ // #let_instant // do we need it?
+ use rtic::Mutex as _;
+
+ let input = #tupled;
+
+ unsafe {
+ if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
+ #app_path::#inputs
+ .get_unchecked_mut(usize::from(index))
+ .as_mut_ptr()
+ .write(input);
+
+ rtic::export::interrupt::free(|_| {
+ #app_path::#rq.enqueue_unchecked((#app_path::#t::#name, index));
+ });
+
+ rtic::pend(#device::#enum_::#interrupt);
+
+ Ok(())
+ } else {
+ Err(input)
+ }
+ }
+
+ }));
+
+ // Schedule caller
+ if let Some(m) = extra.monotonic {
+ let instants = util::instants_ident(name);
+
+ let tq = util::tq_ident();
+ let t = util::schedule_t_ident();
+
+ items.push(quote!(
+ #(#cfgs)*
+ pub fn schedule(
+ instant: <#m as rtic::Monotonic>::Instant
+ #(,#args)*
+ ) -> Result<(), #ty> {
+ unsafe {
+ use rtic::Mutex as _;
+
+ let input = #tupled;
+ if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
+ #app_path::#inputs
+ .get_unchecked_mut(usize::from(index))
+ .as_mut_ptr()
+ .write(input);
+
+ #app_path::#instants
+ .get_unchecked_mut(usize::from(index))
+ .as_mut_ptr()
+ .write(instant);
+
+ let nr = rtic::export::NotReady {
+ instant,
+ index,
+ task: #app_path::#t::#name,
+ };
+
+ rtic::export::interrupt::free(|_| #app_path::#tq.enqueue_unchecked(nr));
+
+ Ok(())
+ } else {
+ Err(input)
+ }
+ }
+ }));
+ }
+ }
+
if !items.is_empty() {
+ let user_imports = &app.user_imports;
+
quote!(
#[allow(non_snake_case)]
#[doc = #doc]
pub mod #name {
+ #(
+ #[allow(unused_imports)]
+ #user_imports
+ )*
#(#items)*
}
)
diff --git a/macros/src/codegen/pre_init.rs b/macros/src/codegen/pre_init.rs
index 2aaf9ebd..17c9c2f4 100644
--- a/macros/src/codegen/pre_init.rs
+++ b/macros/src/codegen/pre_init.rs
@@ -12,12 +12,8 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
stmts.push(quote!(rtic::export::interrupt::disable();));
// Populate the FreeQueue
- for fq in &analysis.free_queues {
- // Get the task name
- let name = fq.0;
- let task = &app.software_tasks[name];
+ for (name, task) in &app.software_tasks {
let cap = task.args.capacity;
-
let fq_ident = util::fq_ident(name);
stmts.push(quote!(
@@ -81,8 +77,8 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
}
// Initialize the SysTick if there exist a TimerQueue
- if let Some(tq) = analysis.timer_queues.first() {
- let priority = tq.priority;
+ if extra.monotonic.is_some() {
+ let priority = analysis.channels.keys().max().unwrap();
// Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
diff --git a/macros/src/codegen/schedule.rs b/macros/src/codegen/schedule.rs
deleted file mode 100644
index 5a887496..00000000
--- a/macros/src/codegen/schedule.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-use std::collections::HashSet;
-
-use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
-use rtic_syntax::ast::App;
-
-use crate::{
- check::Extra,
- codegen::{schedule_body, util},
-};
-
-/// Generates all `${ctxt}::Schedule` methods
-pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
- let mut items = vec![];
-
- let mut seen = HashSet::<_>::new();
- for (scheduler, schedulees) in app.schedule_callers() {
- let m = extra.monotonic();
- let instant = quote!(<#m as rtic::Monotonic>::Instant);
-
- let mut methods = vec![];
-
- for name in schedulees {
- let schedulee = &app.software_tasks[name];
- let cfgs = &schedulee.cfgs;
- let (args, _, untupled, ty) = util::regroup_inputs(&schedulee.inputs);
- let args = &args;
-
- if scheduler.is_init() {
- // `init` uses a special `schedule` implementation; it doesn't use the
- // `schedule_${name}` functions which are shared by other contexts
-
- let body = schedule_body::codegen(scheduler, &name, app);
-
- methods.push(quote!(
- #(#cfgs)*
- pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
- #body
- }
- ));
- } else {
- let schedule = util::schedule_ident(name);
-
- if !seen.contains(name) {
- // Generate a `schedule_${name}_S${sender}` function
- seen.insert(name);
-
- let body = schedule_body::codegen(scheduler, &name, app);
-
- items.push(quote!(
- #(#cfgs)*
- pub unsafe fn #schedule(
- priority: &rtic::export::Priority,
- instant: #instant
- #(,#args)*
- ) -> Result<(), #ty> {
- #body
- }
- ));
- }
-
- methods.push(quote!(
- #(#cfgs)*
- #[inline(always)]
- pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
- unsafe {
- #schedule(self.priority(), instant #(,#untupled)*)
- }
- }
- ));
- }
- }
-
- let lt = if scheduler.is_init() {
- None
- } else {
- Some(quote!('a))
- };
-
- let scheduler = scheduler.ident(app);
- debug_assert!(!methods.is_empty());
- items.push(quote!(
- impl<#lt> #scheduler::Schedule<#lt> {
- #(#methods)*
- }
- ));
- }
-
- items
-}
diff --git a/macros/src/codegen/schedule_body.rs b/macros/src/codegen/schedule_body.rs
deleted file mode 100644
index 644930d7..00000000
--- a/macros/src/codegen/schedule_body.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
-use rtic_syntax::{ast::App, Context};
-use syn::Ident;
-
-use crate::codegen::util;
-
-pub fn codegen(scheduler: Context, name: &Ident, app: &App) -> TokenStream2 {
- let schedulee = &app.software_tasks[name];
-
- let fq = util::fq_ident(name);
- let tq = util::tq_ident();
- let (dequeue, enqueue) = if scheduler.is_init() {
- (quote!(#fq.dequeue()), quote!(#tq.enqueue_unchecked(nr);))
- } else {
- (
- quote!((#fq { priority }).lock(|fq| fq.split().1.dequeue())),
- quote!((#tq { priority }).lock(|tq| tq.enqueue_unchecked(nr));),
- )
- };
-
- let write_instant = if app.uses_schedule() {
- let instants = util::instants_ident(name);
-
- Some(quote!(
- #instants.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(instant);
- ))
- } else {
- None
- };
-
- let (_, tupled, _, _) = util::regroup_inputs(&schedulee.inputs);
- let inputs = util::inputs_ident(name);
- let t = util::schedule_t_ident();
- quote!(
- unsafe {
- use rtic::Mutex as _;
-
- let input = #tupled;
- if let Some(index) = #dequeue {
- #inputs.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(input);
-
- #write_instant
-
- let nr = rtic::export::NotReady {
- instant,
- index,
- task: #t::#name,
- };
-
- #enqueue
-
- Ok(())
- } else {
- Err(input)
- }
- }
- )
-}
diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs
index 4ae37e4e..9918dea1 100644
--- a/macros/src/codegen/software_tasks.rs
+++ b/macros/src/codegen/software_tasks.rs
@@ -39,71 +39,49 @@ pub fn codegen(
let cap_ty = util::capacity_typenum(cap, true);
// Create free queues and inputs / instants buffers
- if let Some(&ceiling) = analysis.free_queues.get(name) {
- let fq = util::fq_ident(name);
-
- let (fq_ty, fq_expr, mk_uninit): (_, _, Box<dyn Fn() -> Option<_>>) = {
- (
- quote!(rtic::export::SCFQ<#cap_ty>),
- quote!(rtic::export::Queue(unsafe {
- rtic::export::iQueue::u8_sc()
- })),
- Box::new(|| util::link_section_uninit(true)),
- )
- };
- mod_app.push(quote!(
- /// Queue version of a free-list that keeps track of empty slots in
- /// the following buffers
- static mut #fq: #fq_ty = #fq_expr;
- ));
+ let fq = util::fq_ident(name);
+
+ let (fq_ty, fq_expr, mk_uninit): (_, _, Box<dyn Fn() -> Option<_>>) = {
+ (
+ quote!(rtic::export::SCFQ<#cap_ty>),
+ quote!(rtic::export::Queue(unsafe {
+ rtic::export::iQueue::u8_sc()
+ })),
+ Box::new(|| util::link_section_uninit(true)),
+ )
+ };
+ mod_app.push(quote!(
+ /// Queue version of a free-list that keeps track of empty slots in
+ /// the following buffers
+ pub static mut #fq: #fq_ty = #fq_expr;
+ ));
- // Generate a resource proxy if needed
- if let Some(ceiling) = ceiling {
- mod_app.push(quote!(
- struct #fq<'a> {
- priority: &'a rtic::export::Priority,
- }
- ));
-
- mod_app.push(util::impl_mutex(
- extra,
- &[],
- false,
- &fq,
- fq_ty,
- ceiling,
- quote!(&mut #fq),
- ));
- }
+ let ref elems = (0..cap)
+ .map(|_| quote!(core::mem::MaybeUninit::uninit()))
+ .collect::<Vec<_>>();
- let ref elems = (0..cap)
- .map(|_| quote!(core::mem::MaybeUninit::uninit()))
- .collect::<Vec<_>>();
-
- if app.uses_schedule() {
- let m = extra.monotonic();
- let instants = util::instants_ident(name);
-
- let uninit = mk_uninit();
- mod_app.push(quote!(
- #uninit
- /// Buffer that holds the instants associated to the inputs of a task
- static mut #instants:
- [core::mem::MaybeUninit<<#m as rtic::Monotonic>::Instant>; #cap_lit] =
- [#(#elems,)*];
- ));
- }
+ if let Some(m) = extra.monotonic {
+ let instants = util::instants_ident(name);
let uninit = mk_uninit();
- let inputs = util::inputs_ident(name);
mod_app.push(quote!(
#uninit
- /// Buffer that holds the inputs of a task
- static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
+ /// Buffer that holds the instants associated to the inputs of a task
+ pub static mut #instants:
+ [core::mem::MaybeUninit<<#m as rtic::Monotonic>::Instant>; #cap_lit] =
[#(#elems,)*];
));
}
+ let uninit = mk_uninit();
+ let inputs_ident = util::inputs_ident(name);
+ mod_app.push(quote!(
+ #uninit
+ /// Buffer that holds the inputs of a task
+ pub static mut #inputs_ident: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
+ [#(#elems,)*];
+ ));
+
// `${task}Resources`
let mut needs_lt = false;
if !task.args.resources.is_empty() {
@@ -161,6 +139,7 @@ pub fn codegen(
Context::SoftwareTask(name),
needs_lt,
app,
+ analysis,
extra,
));
}
diff --git a/macros/src/codegen/spawn.rs b/macros/src/codegen/spawn.rs
deleted file mode 100644
index da281516..00000000
--- a/macros/src/codegen/spawn.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-use std::collections::HashSet;
-
-use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
-use rtic_syntax::ast::App;
-
-use crate::{
- analyze::Analysis,
- check::Extra,
- codegen::{spawn_body, util},
-};
-
-/// Generates all `${ctxt}::Spawn` methods
-pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
- let mut items = vec![];
-
- let mut seen = HashSet::<_>::new();
- for (spawner, spawnees) in app.spawn_callers() {
- let mut methods = vec![];
-
- for name in spawnees {
- let spawnee = &app.software_tasks[name];
- let cfgs = &spawnee.cfgs;
- let (args, _, untupled, ty) = util::regroup_inputs(&spawnee.inputs);
- let args = &args;
-
- if spawner.is_init() {
- // `init` uses a special spawn implementation; it doesn't use the `spawn_${name}`
- // functions which are shared by other contexts
-
- let body = spawn_body::codegen(spawner, &name, app, analysis, extra);
-
- let let_instant = if app.uses_schedule() {
- let m = extra.monotonic();
-
- Some(quote!(let instant = unsafe { <#m as rtic::Monotonic>::zero() };))
- } else {
- None
- };
-
- methods.push(quote!(
- #(#cfgs)*
- pub fn #name(&self #(,#args)*) -> Result<(), #ty> {
- #let_instant
- #body
- }
- ));
- } else {
- let spawn = util::spawn_ident(name);
-
- if !seen.contains(name) {
- // Generate a `spawn_${name}_S${sender}` function
- seen.insert(name);
-
- let instant = if app.uses_schedule() {
- let m = extra.monotonic();
-
- Some(quote!(, instant: <#m as rtic::Monotonic>::Instant))
- } else {
- None
- };
-
- let body = spawn_body::codegen(spawner, &name, app, analysis, extra);
-
- items.push(quote!(
- #(#cfgs)*
- unsafe fn #spawn(
- priority: &rtic::export::Priority
- #instant
- #(,#args)*
- ) -> Result<(), #ty> {
- #body
- }
- ));
- }
-
- let (let_instant, instant) = if app.uses_schedule() {
- let m = extra.monotonic();
-
- (
- Some(if spawner.is_idle() {
- quote!(let instant = <#m as rtic::Monotonic>::now();)
- } else {
- quote!(let instant = self.instant();)
- }),
- Some(quote!(, instant)),
- )
- } else {
- (None, None)
- };
-
- methods.push(quote!(
- #(#cfgs)*
- #[inline(always)]
- pub fn #name(&self #(,#args)*) -> Result<(), #ty> {
- unsafe {
- #let_instant
- #spawn(self.priority() #instant #(,#untupled)*)
- }
- }
- ));
- }
- }
-
- let lt = if spawner.is_init() {
- None
- } else {
- Some(quote!('a))
- };
-
- let spawner = spawner.ident(app);
- debug_assert!(!methods.is_empty());
- items.push(quote!(
- impl<#lt> #spawner::Spawn<#lt> {
- #(#methods)*
- }
- ));
- }
-
- items
-}
diff --git a/macros/src/codegen/spawn_body.rs b/macros/src/codegen/spawn_body.rs
deleted file mode 100644
index f29393a6..00000000
--- a/macros/src/codegen/spawn_body.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
-use rtic_syntax::{ast::App, Context};
-use syn::Ident;
-
-use crate::{analyze::Analysis, check::Extra, codegen::util};
-
-pub fn codegen(
- spawner: Context,
- name: &Ident,
- app: &App,
- analysis: &Analysis,
- _extra: &Extra,
-) -> TokenStream2 {
- let spawnee = &app.software_tasks[name];
- let priority = spawnee.args.priority;
-
- let write_instant = if app.uses_schedule() {
- let instants = util::instants_ident(name);
-
- Some(quote!(
- #instants.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(instant);
- ))
- } else {
- None
- };
-
- let t = util::spawn_t_ident(priority);
- let fq = util::fq_ident(name);
- let rq = util::rq_ident(priority);
- let (dequeue, enqueue) = if spawner.is_init() {
- (
- quote!(#fq.dequeue()),
- quote!(#rq.enqueue_unchecked((#t::#name, index));),
- )
- } else {
- (
- quote!((#fq { priority }.lock(|fq| fq.split().1.dequeue()))),
- quote!((#rq { priority }.lock(|rq| {
- rq.split().0.enqueue_unchecked((#t::#name, index))
- }));),
- )
- };
-
- let enum_ = util::interrupt_ident();
- let interrupt = &analysis.interrupts.get(&priority);
- let pend = {
- quote!(
- rtic::pend(you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml::#enum_::#interrupt);
- )
- };
-
- let (_, tupled, _, _) = util::regroup_inputs(&spawnee.inputs);
- let inputs = util::inputs_ident(name);
- quote!(
- unsafe {
- use rtic::Mutex as _;
-
- let input = #tupled;
- if let Some(index) = #dequeue {
- #inputs.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(input);
-
- #write_instant
-
- #enqueue
-
- #pend
-
- Ok(())
- } else {
- Err(input)
- }
- }
- )
-}
diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs
index 0abbf49d..c898a7fd 100644
--- a/macros/src/codegen/timer_queue.rs
+++ b/macros/src/codegen/timer_queue.rs
@@ -8,16 +8,16 @@ use crate::{analyze::Analysis, check::Extra, codegen::util};
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![];
- if let Some(timer_queue) = &analysis.timer_queues.first() {
+ if let Some(m) = extra.monotonic {
let t = util::schedule_t_ident();
// Enumeration of `schedule`-able tasks
{
- let variants = timer_queue
- .tasks
+ let variants = app
+ .software_tasks
.iter()
- .map(|name| {
- let cfgs = &app.software_tasks[name].cfgs;
+ .map(|(name, task)| {
+ let cfgs = &task.cfgs;
quote!(
#(#cfgs)*
@@ -31,7 +31,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
#[doc = #doc]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
- enum #t {
+ pub enum #t {
#(#variants,)*
}
));
@@ -42,42 +42,30 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
// Static variable and resource proxy
{
let doc = format!("Timer queue");
- let m = extra.monotonic();
- let n = util::capacity_typenum(timer_queue.capacity, false);
+ let cap = app
+ .software_tasks
+ .iter()
+ .map(|(_name, task)| task.args.capacity)
+ .sum();
+ let n = util::capacity_typenum(cap, false);
let tq_ty = quote!(rtic::export::TimerQueue<#m, #t, #n>);
items.push(quote!(
#[doc = #doc]
- static mut #tq: #tq_ty = rtic::export::TimerQueue(
+ pub static mut #tq: #tq_ty = rtic::export::TimerQueue(
rtic::export::BinaryHeap(
rtic::export::iBinaryHeap::new()
)
);
-
- struct #tq<'a> {
- priority: &'a rtic::export::Priority,
- }
- ));
-
- items.push(util::impl_mutex(
- extra,
- &[],
- false,
- &tq,
- tq_ty,
- timer_queue.ceiling,
- quote!(&mut #tq),
));
}
// Timer queue handler
{
- let arms = timer_queue
- .tasks
+ let arms = app
+ .software_tasks
.iter()
- .map(|name| {
- let task = &app.software_tasks[name];
-
+ .map(|(name, task)| {
let cfgs = &task.cfgs;
let priority = task.args.priority;
let rq = util::rq_ident(priority);
@@ -94,9 +82,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
quote!(
#(#cfgs)*
#t::#name => {
- (#rq { priority: &rtic::export::Priority::new(PRIORITY) }).lock(|rq| {
- rq.split().0.enqueue_unchecked((#rqt::#name, index))
- });
+ rtic::export::interrupt::free(|_| #rq.split().0.enqueue_unchecked((#rqt::#name, index)));
#pend
}
@@ -104,30 +90,18 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
})
.collect::<Vec<_>>();
- let priority = timer_queue.priority;
let sys_tick = util::suffixed("SysTick");
items.push(quote!(
#[no_mangle]
unsafe fn #sys_tick() {
use rtic::Mutex as _;
- /// The priority of this handler
- const PRIORITY: u8 = #priority;
-
- rtic::export::run(PRIORITY, || {
- while let Some((task, index)) = (#tq {
- // NOTE dynamic priority is always the static priority at this point
- priority: &rtic::export::Priority::new(PRIORITY),
- })
- // NOTE `inline(always)` produces faster and smaller code
- .lock(#[inline(always)]
- |tq| tq.dequeue())
- {
- match task {
- #(#arms)*
- }
+ while let Some((task, index)) = rtic::export::interrupt::free(|_| #tq.dequeue())
+ {
+ match task {
+ #(#arms)*
}
- });
+ }
}
));
}
diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs
index 41ee3ca7..f04ccb23 100644
--- a/macros/src/codegen/util.rs
+++ b/macros/src/codegen/util.rs
@@ -207,23 +207,9 @@ pub fn rq_ident(priority: u8) -> Ident {
Ident::new(&format!("P{}_RQ", priority), Span::call_site())
}
-/// Generates an identifier for a "schedule" function
-///
-/// The methods of the `Schedule` structs invoke these functions.
-pub fn schedule_ident(name: &Ident) -> Ident {
- Ident::new(&format!("schedule_{}", name.to_string()), Span::call_site())
-}
-
/// Generates an identifier for the `enum` of `schedule`-able tasks
pub fn schedule_t_ident() -> Ident {
- Ident::new(&format!("T"), Span::call_site())
-}
-
-/// Generates an identifier for a "spawn" function
-///
-/// The methods of the `Spawn` structs invoke these functions.
-pub fn spawn_ident(name: &Ident) -> Ident {
- Ident::new(&format!("spawn_{}", name.to_string()), Span::call_site())
+ Ident::new(&format!("SCHED_T"), Span::call_site())
}
/// Generates an identifier for the `enum` of `spawn`-able tasks
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index e659559e..b39cf0b8 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -207,7 +207,6 @@ pub fn app(args: TokenStream, input: TokenStream) -> TokenStream {
settings.optimize_priorities = true;
settings.parse_binds = true;
settings.parse_extern_interrupt = true;
- settings.parse_schedule = true;
let (app, analysis) = match rtic_syntax::parse(args, input, settings) {
Err(e) => return e.to_compile_error().into(),
diff --git a/ui/single/exception-systick-used.rs b/ui/single/exception-systick-used.rs
index 1c30b700..9e94c739 100644
--- a/ui/single/exception-systick-used.rs
+++ b/ui/single/exception-systick-used.rs
@@ -1,10 +1,7 @@
#![no_main]
-#[rtic::app(device = lm3s6965)]
+#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app {
#[task(binds = SysTick)]
fn sys_tick(_: sys_tick::Context) {}
-
- #[task(schedule = [foo])]
- fn foo(_: foo::Context) {}
}