mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-25 19:39:32 +01:00
Old xtask test pass
This commit is contained in:
parent
4c2c05a801
commit
ac4a3edf90
65 changed files with 1422 additions and 320 deletions
7
ci/expected/async-delay.run
Normal file
7
ci/expected/async-delay.run
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
init
|
||||||
|
hello from bar
|
||||||
|
hello from baz
|
||||||
|
hello from foo
|
||||||
|
bye from foo
|
||||||
|
bye from bar
|
||||||
|
bye from baz
|
6
ci/expected/async-infinite-loop.run
Normal file
6
ci/expected/async-infinite-loop.run
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
init
|
||||||
|
hello from async 0
|
||||||
|
hello from async 1
|
||||||
|
hello from async 2
|
||||||
|
hello from async 3
|
||||||
|
hello from async 4
|
5
ci/expected/async-task-multiple-prios.run
Normal file
5
ci/expected/async-task-multiple-prios.run
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
init
|
||||||
|
hello from normal 2
|
||||||
|
hello from async 2
|
||||||
|
hello from normal 1
|
||||||
|
hello from async 1
|
3
ci/expected/async-task.run
Normal file
3
ci/expected/async-task.run
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
init
|
||||||
|
hello from normal
|
||||||
|
hello from async
|
5
ci/expected/async-timeout.run
Normal file
5
ci/expected/async-timeout.run
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
init
|
||||||
|
hello from bar
|
||||||
|
hello from foo
|
||||||
|
foo no timeout
|
||||||
|
bar timeout
|
|
@ -1,4 +1,4 @@
|
||||||
foo Instant { ticks: 0 }
|
foo Instant { ticks: 0 }
|
||||||
foo Instant { ticks: 100 }
|
foo Instant { ticks: 10 }
|
||||||
foo Instant { ticks: 200 }
|
foo Instant { ticks: 20 }
|
||||||
foo Instant { ticks: 300 }
|
foo Instant { ticks: 30 }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
foo Instant { ticks: 0 }
|
foo Instant { ticks: 0 }
|
||||||
bar Instant { ticks: 10 }
|
bar Instant { ticks: 10 }
|
||||||
foo Instant { ticks: 110 }
|
foo Instant { ticks: 30 }
|
||||||
bar Instant { ticks: 120 }
|
bar Instant { ticks: 40 }
|
||||||
foo Instant { ticks: 220 }
|
foo Instant { ticks: 60 }
|
||||||
bar Instant { ticks: 230 }
|
bar Instant { ticks: 70 }
|
||||||
foo Instant { ticks: 330 }
|
foo Instant { ticks: 90 }
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
bar(0x20000088)
|
bar(0x20000084)
|
||||||
foo(0x2000010c)
|
foo(0x20000108)
|
||||||
|
|
67
examples/async-delay.rs
Normal file
67
examples/async-delay.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use panic_semihosting as _;
|
||||||
|
|
||||||
|
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)]
|
||||||
|
mod app {
|
||||||
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
|
use systick_monotonic::*;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {}
|
||||||
|
|
||||||
|
#[monotonic(binds = SysTick, default = true)]
|
||||||
|
type MyMono = Systick<100>;
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
|
foo::spawn().ok();
|
||||||
|
bar::spawn().ok();
|
||||||
|
baz::spawn().ok();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared {},
|
||||||
|
Local {},
|
||||||
|
init::Monotonics(Systick::new(cx.core.SYST, 12_000_000)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[idle]
|
||||||
|
fn idle(_: idle::Context) -> ! {
|
||||||
|
// debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
loop {
|
||||||
|
// hprintln!("idle");
|
||||||
|
cortex_m::asm::wfi(); // put the MCU in sleep mode until interrupt occurs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
async fn foo(_cx: foo::Context) {
|
||||||
|
hprintln!("hello from foo").ok();
|
||||||
|
monotonics::delay(100.millis()).await;
|
||||||
|
hprintln!("bye from foo").ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
async fn bar(_cx: bar::Context) {
|
||||||
|
hprintln!("hello from bar").ok();
|
||||||
|
monotonics::delay(200.millis()).await;
|
||||||
|
hprintln!("bye from bar").ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
async fn baz(_cx: baz::Context) {
|
||||||
|
hprintln!("hello from baz").ok();
|
||||||
|
monotonics::delay(300.millis()).await;
|
||||||
|
hprintln!("bye from baz").ok();
|
||||||
|
|
||||||
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
57
examples/async-infinite-loop.rs
Normal file
57
examples/async-infinite-loop.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use panic_semihosting as _;
|
||||||
|
|
||||||
|
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)]
|
||||||
|
mod app {
|
||||||
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
|
use systick_monotonic::*;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {}
|
||||||
|
|
||||||
|
#[monotonic(binds = SysTick, default = true)]
|
||||||
|
type MyMono = Systick<100>;
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
|
foo::spawn().ok();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared {},
|
||||||
|
Local {},
|
||||||
|
init::Monotonics(Systick::new(cx.core.SYST, 12_000_000)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[idle]
|
||||||
|
fn idle(_: idle::Context) -> ! {
|
||||||
|
loop {
|
||||||
|
cortex_m::asm::wfi(); // put the MCU in sleep mode until interrupt occurs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infinite loops are not allowed in RTIC, however in async tasks they are - if there is an
|
||||||
|
// await inside the loop.
|
||||||
|
#[task]
|
||||||
|
async fn foo(_cx: foo::Context) {
|
||||||
|
let mut i = 0;
|
||||||
|
loop {
|
||||||
|
if i == 5 {
|
||||||
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
hprintln!("hello from async {}", i).ok();
|
||||||
|
monotonics::delay(100.millis()).await; // This makes it okey!
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
examples/async-task-multiple-prios.rs
Normal file
76
examples/async-task-multiple-prios.rs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use panic_semihosting as _;
|
||||||
|
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
// - Async tasks cannot have `#[lock_free]` resources, as they can interleve and each async
|
||||||
|
// task can have a mutable reference stored.
|
||||||
|
// - Spawning an async task equates to it being polled once.
|
||||||
|
|
||||||
|
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0, UART0, UART1], peripherals = true)]
|
||||||
|
mod app {
|
||||||
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
|
use systick_monotonic::*;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {
|
||||||
|
a: u32,
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {}
|
||||||
|
|
||||||
|
#[monotonic(binds = SysTick, default = true)]
|
||||||
|
type MyMono = Systick<100>;
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
|
normal_task::spawn().ok();
|
||||||
|
async_task::spawn().ok();
|
||||||
|
normal_task2::spawn().ok();
|
||||||
|
async_task2::spawn().ok();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared { a: 0, b: 0 },
|
||||||
|
Local {},
|
||||||
|
init::Monotonics(Systick::new(cx.core.SYST, 12_000_000)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[idle]
|
||||||
|
fn idle(_: idle::Context) -> ! {
|
||||||
|
// debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
loop {
|
||||||
|
// hprintln!("idle");
|
||||||
|
cortex_m::asm::wfi(); // put the MCU in sleep mode until interrupt occurs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(priority = 1, shared = [a, b])]
|
||||||
|
fn normal_task(_cx: normal_task::Context) {
|
||||||
|
hprintln!("hello from normal 1").ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(priority = 1, shared = [a, b])]
|
||||||
|
async fn async_task(_cx: async_task::Context) {
|
||||||
|
hprintln!("hello from async 1").ok();
|
||||||
|
|
||||||
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(priority = 2, shared = [a, b])]
|
||||||
|
fn normal_task2(_cx: normal_task2::Context) {
|
||||||
|
hprintln!("hello from normal 2").ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(priority = 2, shared = [a, b])]
|
||||||
|
async fn async_task2(_cx: async_task2::Context) {
|
||||||
|
hprintln!("hello from async 2").ok();
|
||||||
|
}
|
||||||
|
}
|
61
examples/async-task.rs
Normal file
61
examples/async-task.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use panic_semihosting as _;
|
||||||
|
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
// - Async tasks cannot have `#[lock_free]` resources, as they can interleve and each async
|
||||||
|
// task can have a mutable reference stored.
|
||||||
|
// - Spawning an async task equates to it being polled once.
|
||||||
|
|
||||||
|
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)]
|
||||||
|
mod app {
|
||||||
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
|
use systick_monotonic::*;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {}
|
||||||
|
|
||||||
|
#[monotonic(binds = SysTick, default = true)]
|
||||||
|
type MyMono = Systick<100>;
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
|
normal_task::spawn().ok();
|
||||||
|
async_task::spawn().ok();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared {},
|
||||||
|
Local {},
|
||||||
|
init::Monotonics(Systick::new(cx.core.SYST, 12_000_000)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[idle]
|
||||||
|
fn idle(_: idle::Context) -> ! {
|
||||||
|
// debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
loop {
|
||||||
|
// hprintln!("idle");
|
||||||
|
cortex_m::asm::wfi(); // put the MCU in sleep mode until interrupt occurs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
fn normal_task(_cx: normal_task::Context) {
|
||||||
|
hprintln!("hello from normal").ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
async fn async_task(_cx: async_task::Context) {
|
||||||
|
hprintln!("hello from async").ok();
|
||||||
|
|
||||||
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
87
examples/async-timeout.rs
Normal file
87
examples/async-timeout.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use panic_semihosting as _;
|
||||||
|
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
// - Async tasks cannot have `#[lock_free]` resources, as they can interleve and each async
|
||||||
|
// task can have a mutable reference stored.
|
||||||
|
// - Spawning an async task equates to it being polled once.
|
||||||
|
|
||||||
|
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)]
|
||||||
|
mod app {
|
||||||
|
use core::{
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
|
use systick_monotonic::*;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {}
|
||||||
|
|
||||||
|
#[monotonic(binds = SysTick, default = true)]
|
||||||
|
type MyMono = Systick<100>;
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
|
foo::spawn().ok();
|
||||||
|
bar::spawn().ok();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared {},
|
||||||
|
Local {},
|
||||||
|
init::Monotonics(Systick::new(cx.core.SYST, 12_000_000)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[idle]
|
||||||
|
fn idle(_: idle::Context) -> ! {
|
||||||
|
loop {
|
||||||
|
cortex_m::asm::wfi(); // put the MCU in sleep mode until interrupt occurs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
async fn foo(_cx: foo::Context) {
|
||||||
|
hprintln!("hello from foo").ok();
|
||||||
|
|
||||||
|
// This will not timeout
|
||||||
|
match monotonics::timeout_after(monotonics::delay(100.millis()), 200.millis()).await {
|
||||||
|
Ok(_) => hprintln!("foo no timeout").ok(),
|
||||||
|
Err(_) => hprintln!("foo timeout").ok(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
async fn bar(_cx: bar::Context) {
|
||||||
|
hprintln!("hello from bar").ok();
|
||||||
|
|
||||||
|
// This will timeout
|
||||||
|
match monotonics::timeout_after(NeverEndingFuture {}, 300.millis()).await {
|
||||||
|
Ok(_) => hprintln!("bar no timeout").ok(),
|
||||||
|
Err(_) => hprintln!("bar timeout").ok(),
|
||||||
|
};
|
||||||
|
|
||||||
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NeverEndingFuture {}
|
||||||
|
|
||||||
|
impl Future for NeverEndingFuture {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
// Never finish
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -24,22 +23,21 @@ mod app {
|
||||||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
rtic::pend(Interrupt::UART0);
|
rtic::pend(Interrupt::UART0);
|
||||||
|
|
||||||
hprintln!("init");
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
(Shared {}, Local {}, init::Monotonics())
|
(Shared {}, Local {}, init::Monotonics())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle(_: idle::Context) -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
hprintln!("idle");
|
hprintln!("idle").unwrap();
|
||||||
|
|
||||||
rtic::pend(Interrupt::UART0);
|
rtic::pend(Interrupt::UART0);
|
||||||
|
|
||||||
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Exit moved after nop to ensure that rtic::pend gets
|
|
||||||
// to run before exiting
|
|
||||||
cortex_m::asm::nop();
|
cortex_m::asm::nop();
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +49,7 @@ mod app {
|
||||||
"foo called {} time{}",
|
"foo called {} time{}",
|
||||||
*cx.local.times,
|
*cx.local.times,
|
||||||
if *cx.local.times > 1 { "s" } else { "" }
|
if *cx.local.times > 1 { "s" } else { "" }
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ mod app {
|
||||||
// Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
|
// Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
|
||||||
let mono = Systick::new(systick, 12_000_000);
|
let mono = Systick::new(systick, 12_000_000);
|
||||||
|
|
||||||
hprintln!("init");
|
hprintln!("init").ok();
|
||||||
|
|
||||||
// Schedule `foo` to run 1 second in the future
|
// Schedule `foo` to run 1 second in the future
|
||||||
foo::spawn_after(1.secs()).unwrap();
|
foo::spawn_after(1.secs()).unwrap();
|
||||||
|
@ -43,7 +42,7 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo(_: foo::Context) {
|
fn foo(_: foo::Context) {
|
||||||
hprintln!("foo");
|
hprintln!("foo").ok();
|
||||||
|
|
||||||
// Schedule `bar` to run 2 seconds in the future (1 second after foo runs)
|
// Schedule `bar` to run 2 seconds in the future (1 second after foo runs)
|
||||||
let spawn_handle = baz::spawn_after(2.secs()).unwrap();
|
let spawn_handle = baz::spawn_after(2.secs()).unwrap();
|
||||||
|
@ -52,7 +51,7 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar(_: bar::Context, baz_handle: baz::SpawnHandle, do_reschedule: bool) {
|
fn bar(_: bar::Context, baz_handle: baz::SpawnHandle, do_reschedule: bool) {
|
||||||
hprintln!("bar");
|
hprintln!("bar").ok();
|
||||||
|
|
||||||
if do_reschedule {
|
if do_reschedule {
|
||||||
// Reschedule baz 2 seconds from now, instead of the original 1 second
|
// Reschedule baz 2 seconds from now, instead of the original 1 second
|
||||||
|
@ -68,7 +67,7 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn baz(_: baz::Context) {
|
fn baz(_: baz::Context) {
|
||||||
hprintln!("baz");
|
hprintln!("baz").ok();
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -38,12 +37,12 @@ mod app {
|
||||||
|
|
||||||
#[task(capacity = 4)]
|
#[task(capacity = 4)]
|
||||||
fn foo(_: foo::Context, x: u32) {
|
fn foo(_: foo::Context, x: u32) {
|
||||||
hprintln!("foo({})", x);
|
hprintln!("foo({})", x).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar(_: bar::Context) {
|
fn bar(_: bar::Context) {
|
||||||
hprintln!("bar");
|
hprintln!("bar").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -82,19 +81,6 @@ mod app {
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
|
|
||||||
// The whole task should disappear,
|
|
||||||
// currently still present in the Tasks enum
|
|
||||||
#[cfg(never)]
|
|
||||||
#[task(binds = UART1, shared = [count])]
|
|
||||||
fn foo3(mut _cx: foo3::Context) {
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
_cx.shared.count.lock(|count| *count += 10);
|
|
||||||
|
|
||||||
log::spawn(_cx.shared.count.lock(|count| *count)).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
#[task(capacity = 2)]
|
#[task(capacity = 2)]
|
||||||
fn log(_: log::Context, n: u32) {
|
fn log(_: log::Context, n: u32) {
|
||||||
|
@ -102,6 +88,7 @@ mod app {
|
||||||
"foo has been called {} time{}",
|
"foo has been called {} time{}",
|
||||||
n,
|
n,
|
||||||
if n == 1 { "" } else { "s" }
|
if n == 1 { "" } else { "s" }
|
||||||
);
|
)
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -74,7 +73,7 @@ mod app {
|
||||||
// This task is only spawned once in `init`, hence this task will run
|
// This task is only spawned once in `init`, hence this task will run
|
||||||
// only once
|
// only once
|
||||||
|
|
||||||
hprintln!("foo");
|
hprintln!("foo").ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Software task, also not bound to a hardware interrupt
|
// Software task, also not bound to a hardware interrupt
|
||||||
|
@ -82,7 +81,7 @@ mod app {
|
||||||
// The resources `s1` and `s2` are shared between all other tasks.
|
// The resources `s1` and `s2` are shared between all other tasks.
|
||||||
#[task(shared = [s1, s2], local = [l2])]
|
#[task(shared = [s1, s2], local = [l2])]
|
||||||
fn bar(_: bar::Context) {
|
fn bar(_: bar::Context) {
|
||||||
hprintln!("bar");
|
hprintln!("bar").ok();
|
||||||
|
|
||||||
// Run `bar` once per second
|
// Run `bar` once per second
|
||||||
bar::spawn_after(1.secs()).unwrap();
|
bar::spawn_after(1.secs()).unwrap();
|
||||||
|
@ -98,6 +97,6 @@ mod app {
|
||||||
// Note that RTIC does NOT clear the interrupt flag, this is up to the
|
// Note that RTIC does NOT clear the interrupt flag, this is up to the
|
||||||
// user
|
// user
|
||||||
|
|
||||||
hprintln!("UART0 interrupt!");
|
hprintln!("UART0 interrupt!").ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -26,7 +25,7 @@ mod app {
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
hprintln!("init");
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
(
|
(
|
||||||
Shared {
|
Shared {
|
||||||
|
@ -41,31 +40,31 @@ mod app {
|
||||||
|
|
||||||
#[idle(shared = [s2, s3])]
|
#[idle(shared = [s2, s3])]
|
||||||
fn idle(mut cx: idle::Context) -> ! {
|
fn idle(mut cx: idle::Context) -> ! {
|
||||||
hprintln!("idle p0 started");
|
hprintln!("idle p0 started").ok();
|
||||||
rtic::pend(Interrupt::GPIOC);
|
rtic::pend(Interrupt::GPIOC);
|
||||||
cx.shared.s3.lock(|s| {
|
cx.shared.s3.lock(|s| {
|
||||||
hprintln!("idle enter lock s3 {}", s);
|
hprintln!("idle enter lock s3 {}", s).ok();
|
||||||
hprintln!("idle pend t0");
|
hprintln!("idle pend t0").ok();
|
||||||
rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 3
|
rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 3
|
||||||
hprintln!("idle pend t1");
|
hprintln!("idle pend t1").ok();
|
||||||
rtic::pend(Interrupt::GPIOB); // t1 p3, with shared ceiling 3
|
rtic::pend(Interrupt::GPIOB); // t1 p3, with shared ceiling 3
|
||||||
hprintln!("idle pend t2");
|
hprintln!("idle pend t2").ok();
|
||||||
rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing
|
rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing
|
||||||
hprintln!("idle still in lock s3 {}", s);
|
hprintln!("idle still in lock s3 {}", s).ok();
|
||||||
});
|
});
|
||||||
hprintln!("\nback in idle");
|
hprintln!("\nback in idle").ok();
|
||||||
|
|
||||||
cx.shared.s2.lock(|s| {
|
cx.shared.s2.lock(|s| {
|
||||||
hprintln!("enter lock s2 {}", s);
|
hprintln!("enter lock s2 {}", s).ok();
|
||||||
hprintln!("idle pend t0");
|
hprintln!("idle pend t0").ok();
|
||||||
rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2
|
rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2
|
||||||
hprintln!("idle pend t1");
|
hprintln!("idle pend t1").ok();
|
||||||
rtic::pend(Interrupt::GPIOB); // t1 p3, no sharing
|
rtic::pend(Interrupt::GPIOB); // t1 p3, no sharing
|
||||||
hprintln!("idle pend t2");
|
hprintln!("idle pend t2").ok();
|
||||||
rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing
|
rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing
|
||||||
hprintln!("idle still in lock s2 {}", s);
|
hprintln!("idle still in lock s2 {}", s).ok();
|
||||||
});
|
});
|
||||||
hprintln!("\nidle exit");
|
hprintln!("\nidle exit").ok();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
||||||
|
@ -83,8 +82,9 @@ mod app {
|
||||||
"t0 p2 called {} time{}",
|
"t0 p2 called {} time{}",
|
||||||
*cx.local.times,
|
*cx.local.times,
|
||||||
if *cx.local.times > 1 { "s" } else { "" }
|
if *cx.local.times > 1 { "s" } else { "" }
|
||||||
);
|
)
|
||||||
hprintln!("t0 p2 exit");
|
.ok();
|
||||||
|
hprintln!("t0 p2 exit").ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(binds = GPIOB, priority = 3, local = [times: u32 = 0], shared = [s3, s4])]
|
#[task(binds = GPIOB, priority = 3, local = [times: u32 = 0], shared = [s3, s4])]
|
||||||
|
@ -96,18 +96,19 @@ mod app {
|
||||||
"t1 p3 called {} time{}",
|
"t1 p3 called {} time{}",
|
||||||
*cx.local.times,
|
*cx.local.times,
|
||||||
if *cx.local.times > 1 { "s" } else { "" }
|
if *cx.local.times > 1 { "s" } else { "" }
|
||||||
);
|
)
|
||||||
|
.ok();
|
||||||
|
|
||||||
cx.shared.s4.lock(|s| {
|
cx.shared.s4.lock(|s| {
|
||||||
hprintln!("t1 enter lock s4 {}", s);
|
hprintln!("t1 enter lock s4 {}", s).ok();
|
||||||
hprintln!("t1 pend t0");
|
hprintln!("t1 pend t0").ok();
|
||||||
rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2
|
rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2
|
||||||
hprintln!("t1 pend t2");
|
hprintln!("t1 pend t2").ok();
|
||||||
rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing
|
rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing
|
||||||
hprintln!("t1 still in lock s4 {}", s);
|
hprintln!("t1 still in lock s4 {}", s).ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
hprintln!("t1 p3 exit");
|
hprintln!("t1 p3 exit").ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(binds = GPIOC, priority = 4, local = [times: u32 = 0], shared = [s4])]
|
#[task(binds = GPIOC, priority = 4, local = [times: u32 = 0], shared = [s4])]
|
||||||
|
@ -119,12 +120,13 @@ mod app {
|
||||||
"t2 p4 called {} time{}",
|
"t2 p4 called {} time{}",
|
||||||
*cx.local.times,
|
*cx.local.times,
|
||||||
if *cx.local.times > 1 { "s" } else { "" }
|
if *cx.local.times > 1 { "s" } else { "" }
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
cx.shared.s4.lock(|s| {
|
cx.shared.s4.lock(|s| {
|
||||||
hprintln!("enter lock s4 {}", s);
|
hprintln!("enter lock s4 {}", s).ok();
|
||||||
*s += 1;
|
*s += 1;
|
||||||
});
|
});
|
||||||
hprintln!("t3 p4 exit");
|
hprintln!("t3 p4 exit").ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ mod app {
|
||||||
let b = cx.shared.b;
|
let b = cx.shared.b;
|
||||||
let c = cx.shared.c;
|
let c = cx.shared.c;
|
||||||
|
|
||||||
hprintln!("foo: a = {}, b = {}, c = {}", a, b, c);
|
hprintln!("foo: a = {}, b = {}, c = {}", a, b, c).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// De-structure-ing syntax
|
// De-structure-ing syntax
|
||||||
|
@ -51,6 +50,6 @@ mod app {
|
||||||
fn bar(cx: bar::Context) {
|
fn bar(cx: bar::Context) {
|
||||||
let bar::SharedResources { a, b, c } = cx.shared;
|
let bar::SharedResources { a, b, c } = cx.shared;
|
||||||
|
|
||||||
hprintln!("bar: a = {}, b = {}, c = {}", a, b, c);
|
hprintln!("bar: a = {}, b = {}, c = {}", a, b, c).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@ use panic_semihosting as _;
|
||||||
|
|
||||||
// Free function implementing the interrupt bound task `foo`.
|
// Free function implementing the interrupt bound task `foo`.
|
||||||
fn foo(_: app::foo::Context) {
|
fn foo(_: app::foo::Context) {
|
||||||
hprintln!("foo called");
|
hprintln!("foo called").ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rtic::app(device = lm3s6965)]
|
#[rtic::app(device = lm3s6965)]
|
||||||
|
@ -30,22 +29,21 @@ mod app {
|
||||||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
rtic::pend(Interrupt::UART0);
|
rtic::pend(Interrupt::UART0);
|
||||||
|
|
||||||
hprintln!("init");
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
(Shared {}, Local {}, init::Monotonics())
|
(Shared {}, Local {}, init::Monotonics())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle(_: idle::Context) -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
hprintln!("idle");
|
hprintln!("idle").unwrap();
|
||||||
|
|
||||||
rtic::pend(Interrupt::UART0);
|
rtic::pend(Interrupt::UART0);
|
||||||
|
|
||||||
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
cortex_m::asm::nop();
|
cortex_m::asm::nop();
|
||||||
// Exit moved after nop to ensure that rtic::pend gets
|
|
||||||
// to run before exiting
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@ use panic_semihosting as _;
|
||||||
|
|
||||||
// Free function implementing the spawnable task `foo`.
|
// Free function implementing the spawnable task `foo`.
|
||||||
fn foo(_c: app::foo::Context, x: i32, y: u32) {
|
fn foo(_c: app::foo::Context, x: i32, y: u32) {
|
||||||
hprintln!("foo {}, {}", x, y);
|
hprintln!("foo {}, {}", x, y).unwrap();
|
||||||
if x == 2 {
|
if x == 2 {
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -33,22 +32,19 @@ mod app {
|
||||||
|
|
||||||
#[task(binds = UART0, shared = [shared], local = [state: u32 = 0])]
|
#[task(binds = UART0, shared = [shared], local = [state: u32 = 0])]
|
||||||
fn uart0(c: uart0::Context) {
|
fn uart0(c: uart0::Context) {
|
||||||
hprintln!("UART0(STATE = {})", *c.local.state);
|
hprintln!("UART0(STATE = {})", *c.local.state).unwrap();
|
||||||
|
|
||||||
// second argument has type `shared::shared`
|
// second argument has type `shared::shared`
|
||||||
super::advance(c.local.state, c.shared.shared);
|
super::advance(c.local.state, c.shared.shared);
|
||||||
|
|
||||||
rtic::pend(Interrupt::UART1);
|
rtic::pend(Interrupt::UART1);
|
||||||
|
|
||||||
// Exit moved after nop to ensure that rtic::pend gets
|
|
||||||
// to run before exiting
|
|
||||||
cortex_m::asm::nop();
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(binds = UART1, priority = 2, shared = [shared], local = [state: u32 = 0])]
|
#[task(binds = UART1, priority = 2, shared = [shared], local = [state: u32 = 0])]
|
||||||
fn uart1(c: uart1::Context) {
|
fn uart1(c: uart1::Context) {
|
||||||
hprintln!("UART1(STATE = {})", *c.local.state);
|
hprintln!("UART1(STATE = {})", *c.local.state).unwrap();
|
||||||
|
|
||||||
// second argument has type `shared::shared`
|
// second argument has type `shared::shared`
|
||||||
super::advance(c.local.state, c.shared.shared);
|
super::advance(c.local.state, c.shared.shared);
|
||||||
|
@ -65,5 +61,5 @@ fn advance(state: &mut u32, mut shared: impl Mutex<T = u32>) {
|
||||||
(old, *shared)
|
(old, *shared)
|
||||||
});
|
});
|
||||||
|
|
||||||
hprintln!("shared: {} -> {}", old, new);
|
hprintln!("shared: {} -> {}", old, new).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -25,7 +24,7 @@ mod app {
|
||||||
// `init` returns because interrupts are disabled
|
// `init` returns because interrupts are disabled
|
||||||
rtic::pend(Interrupt::UART0); // equivalent to NVIC::pend
|
rtic::pend(Interrupt::UART0); // equivalent to NVIC::pend
|
||||||
|
|
||||||
hprintln!("init");
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
(Shared {}, Local {}, init::Monotonics())
|
(Shared {}, Local {}, init::Monotonics())
|
||||||
}
|
}
|
||||||
|
@ -34,15 +33,14 @@ mod app {
|
||||||
fn idle(_: idle::Context) -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
// interrupts are enabled again; the `UART0` handler runs at this point
|
// interrupts are enabled again; the `UART0` handler runs at this point
|
||||||
|
|
||||||
hprintln!("idle");
|
hprintln!("idle").unwrap();
|
||||||
|
|
||||||
rtic::pend(Interrupt::UART0);
|
rtic::pend(Interrupt::UART0);
|
||||||
|
|
||||||
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Exit moved after nop to ensure that rtic::pend gets
|
|
||||||
// to run before exiting
|
|
||||||
cortex_m::asm::nop();
|
cortex_m::asm::nop();
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +53,7 @@ mod app {
|
||||||
"UART0 called {} time{}",
|
"UART0 called {} time{}",
|
||||||
*cx.local.times,
|
*cx.local.times,
|
||||||
if *cx.local.times > 1 { "s" } else { "" }
|
if *cx.local.times > 1 { "s" } else { "" }
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -20,7 +19,7 @@ mod app {
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init(mut cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
fn init(mut cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
hprintln!("init");
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
// Set the ARM SLEEPONEXIT bit to go to sleep after handling interrupts
|
// Set the ARM SLEEPONEXIT bit to go to sleep after handling interrupts
|
||||||
// See https://developer.arm.com/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit
|
// See https://developer.arm.com/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit
|
||||||
|
@ -34,7 +33,7 @@ mod app {
|
||||||
// Locals in idle have lifetime 'static
|
// Locals in idle have lifetime 'static
|
||||||
let _x: &'static mut u32 = cx.local.x;
|
let _x: &'static mut u32 = cx.local.x;
|
||||||
|
|
||||||
hprintln!("idle");
|
hprintln!("idle").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -20,7 +19,7 @@ mod app {
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
hprintln!("init");
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
(Shared {}, Local {}, init::Monotonics())
|
(Shared {}, Local {}, init::Monotonics())
|
||||||
}
|
}
|
||||||
|
@ -30,7 +29,7 @@ mod app {
|
||||||
// Locals in idle have lifetime 'static
|
// Locals in idle have lifetime 'static
|
||||||
let _x: &'static mut u32 = cx.local.x;
|
let _x: &'static mut u32 = cx.local.x;
|
||||||
|
|
||||||
hprintln!("idle");
|
hprintln!("idle").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -33,7 +32,7 @@ mod app {
|
||||||
// to indicate that this is a critical seciton
|
// to indicate that this is a critical seciton
|
||||||
let _cs_token: bare_metal::CriticalSection = cx.cs;
|
let _cs_token: bare_metal::CriticalSection = cx.cs;
|
||||||
|
|
||||||
hprintln!("init");
|
hprintln!("init").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -18,11 +16,8 @@ mod app {
|
||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
struct Local {
|
struct Local {
|
||||||
/// Local foo
|
|
||||||
local_to_foo: i64,
|
local_to_foo: i64,
|
||||||
/// Local bar
|
|
||||||
local_to_bar: i64,
|
local_to_bar: i64,
|
||||||
/// Local idle
|
|
||||||
local_to_idle: i64,
|
local_to_idle: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +45,7 @@ mod app {
|
||||||
let local_to_idle = cx.local.local_to_idle;
|
let local_to_idle = cx.local.local_to_idle;
|
||||||
*local_to_idle += 1;
|
*local_to_idle += 1;
|
||||||
|
|
||||||
hprintln!("idle: local_to_idle = {}", local_to_idle);
|
hprintln!("idle: local_to_idle = {}", local_to_idle).unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
||||||
|
@ -74,7 +69,7 @@ mod app {
|
||||||
// error: no `local_to_bar` field in `foo::LocalResources`
|
// error: no `local_to_bar` field in `foo::LocalResources`
|
||||||
// cx.local.local_to_bar += 1;
|
// cx.local.local_to_bar += 1;
|
||||||
|
|
||||||
hprintln!("foo: local_to_foo = {}", local_to_foo);
|
hprintln!("foo: local_to_foo = {}", local_to_foo).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// `local_to_bar` can only be accessed from this context
|
// `local_to_bar` can only be accessed from this context
|
||||||
|
@ -86,6 +81,6 @@ mod app {
|
||||||
// error: no `local_to_foo` field in `bar::LocalResources`
|
// error: no `local_to_foo` field in `bar::LocalResources`
|
||||||
// cx.local.local_to_foo += 1;
|
// cx.local.local_to_foo += 1;
|
||||||
|
|
||||||
hprintln!("bar: local_to_bar = {}", local_to_bar);
|
hprintln!("bar: local_to_bar = {}", local_to_bar).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -34,7 +33,7 @@ mod app {
|
||||||
|
|
||||||
*c.shared.counter += 1; // <- no lock API required
|
*c.shared.counter += 1; // <- no lock API required
|
||||||
let counter = *c.shared.counter;
|
let counter = *c.shared.counter;
|
||||||
hprintln!(" foo = {}", counter);
|
hprintln!(" foo = {}", counter).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(shared = [counter])] // <- same priority
|
#[task(shared = [counter])] // <- same priority
|
||||||
|
@ -43,7 +42,7 @@ mod app {
|
||||||
|
|
||||||
*c.shared.counter += 1; // <- no lock API required
|
*c.shared.counter += 1; // <- no lock API required
|
||||||
let counter = *c.shared.counter;
|
let counter = *c.shared.counter;
|
||||||
hprintln!(" bar = {}", counter);
|
hprintln!(" bar = {}", counter).unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ mod app {
|
||||||
// when omitted priority is assumed to be `1`
|
// when omitted priority is assumed to be `1`
|
||||||
#[task(shared = [shared])]
|
#[task(shared = [shared])]
|
||||||
fn foo(mut c: foo::Context) {
|
fn foo(mut c: foo::Context) {
|
||||||
hprintln!("A");
|
hprintln!("A").unwrap();
|
||||||
|
|
||||||
// the lower priority task requires a critical section to access the data
|
// the lower priority task requires a critical section to access the data
|
||||||
c.shared.shared.lock(|shared| {
|
c.shared.shared.lock(|shared| {
|
||||||
|
@ -40,7 +39,7 @@ mod app {
|
||||||
// bar will *not* run right now due to the critical section
|
// bar will *not* run right now due to the critical section
|
||||||
bar::spawn().unwrap();
|
bar::spawn().unwrap();
|
||||||
|
|
||||||
hprintln!("B - shared = {}", *shared);
|
hprintln!("B - shared = {}", *shared).unwrap();
|
||||||
|
|
||||||
// baz does not contend for `shared` so it's allowed to run now
|
// baz does not contend for `shared` so it's allowed to run now
|
||||||
baz::spawn().unwrap();
|
baz::spawn().unwrap();
|
||||||
|
@ -48,7 +47,7 @@ mod app {
|
||||||
|
|
||||||
// critical section is over: bar can now start
|
// critical section is over: bar can now start
|
||||||
|
|
||||||
hprintln!("E");
|
hprintln!("E").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
@ -62,11 +61,11 @@ mod app {
|
||||||
*shared
|
*shared
|
||||||
});
|
});
|
||||||
|
|
||||||
hprintln!("D - shared = {}", shared);
|
hprintln!("D - shared = {}", shared).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 3)]
|
#[task(priority = 3)]
|
||||||
fn baz(_: baz::Context) {
|
fn baz(_: baz::Context) {
|
||||||
hprintln!("C");
|
hprintln!("C").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ mod app {
|
||||||
|
|
||||||
#[task(local = [count: u32 = 0])]
|
#[task(local = [count: u32 = 0])]
|
||||||
fn foo(cx: foo::Context) {
|
fn foo(cx: foo::Context) {
|
||||||
hprintln!("foo");
|
hprintln!("foo").unwrap();
|
||||||
|
|
||||||
bar::spawn(*cx.local.count).unwrap();
|
bar::spawn(*cx.local.count).unwrap();
|
||||||
*cx.local.count += 1;
|
*cx.local.count += 1;
|
||||||
|
@ -35,14 +34,14 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar(_: bar::Context, x: u32) {
|
fn bar(_: bar::Context, x: u32) {
|
||||||
hprintln!("bar({})", x);
|
hprintln!("bar({})", x).unwrap();
|
||||||
|
|
||||||
baz::spawn(x + 1, x + 2).unwrap();
|
baz::spawn(x + 1, x + 2).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn baz(_: baz::Context, x: u32, y: u32) {
|
fn baz(_: baz::Context, x: u32, y: u32) {
|
||||||
hprintln!("baz({}, {})", x, y);
|
hprintln!("baz({}, {})", x, y).unwrap();
|
||||||
|
|
||||||
if x + y > 4 {
|
if x + y > 4 {
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ mod app {
|
||||||
|
|
||||||
#[task(capacity = 3)]
|
#[task(capacity = 3)]
|
||||||
fn foo(_c: foo::Context, x: i32, y: u32) {
|
fn foo(_c: foo::Context, x: i32, y: u32) {
|
||||||
hprintln!("foo {}, {}", x, y);
|
hprintln!("foo {}, {}", x, y).unwrap();
|
||||||
if x == 2 {
|
if x == 2 {
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -49,7 +48,7 @@ mod app {
|
||||||
*s2 += 1;
|
*s2 += 1;
|
||||||
*s3 += 1;
|
*s3 += 1;
|
||||||
|
|
||||||
hprintln!("Multiple locks, s1: {}, s2: {}, s3: {}", *s1, *s2, *s3);
|
hprintln!("Multiple locks, s1: {}, s2: {}, s3: {}", *s1, *s2, *s3).unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
|
|
|
@ -2,16 +2,13 @@
|
||||||
|
|
||||||
// #![deny(unsafe_code)]
|
// #![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use panic_semihosting as _;
|
use panic_semihosting as _;
|
||||||
|
|
||||||
/// Not sync
|
|
||||||
pub struct NotSync {
|
pub struct NotSync {
|
||||||
/// Phantom action
|
|
||||||
_0: PhantomData<*const ()>,
|
_0: PhantomData<*const ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +22,6 @@ mod app {
|
||||||
|
|
||||||
#[shared]
|
#[shared]
|
||||||
struct Shared {
|
struct Shared {
|
||||||
/// This resource is not Sync
|
|
||||||
shared: NotSync,
|
shared: NotSync,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -31,13 +30,13 @@ mod app {
|
||||||
#[task(shared = [&key])]
|
#[task(shared = [&key])]
|
||||||
fn foo(cx: foo::Context) {
|
fn foo(cx: foo::Context) {
|
||||||
let key: &u32 = cx.shared.key;
|
let key: &u32 = cx.shared.key;
|
||||||
hprintln!("foo(key = {:#x})", key);
|
hprintln!("foo(key = {:#x})", key).unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 2, shared = [&key])]
|
#[task(priority = 2, shared = [&key])]
|
||||||
fn bar(cx: bar::Context) {
|
fn bar(cx: bar::Context) {
|
||||||
hprintln!("bar(key = {:#x})", cx.shared.key);
|
hprintln!("bar(key = {:#x})", cx.shared.key).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -36,15 +35,15 @@ mod app {
|
||||||
|
|
||||||
#[task(local = [cnt: u32 = 0])]
|
#[task(local = [cnt: u32 = 0])]
|
||||||
fn foo(cx: foo::Context, instant: fugit::TimerInstantU64<100>) {
|
fn foo(cx: foo::Context, instant: fugit::TimerInstantU64<100>) {
|
||||||
hprintln!("foo {:?}", instant);
|
hprintln!("foo {:?}", instant).ok();
|
||||||
*cx.local.cnt += 1;
|
*cx.local.cnt += 1;
|
||||||
|
|
||||||
if *cx.local.cnt == 4 {
|
if *cx.local.cnt == 4 {
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Periodic ever 1 seconds
|
// Periodic every 100 milliseconds
|
||||||
let next_instant = instant + 1.secs();
|
let next_instant = instant + 100.millis();
|
||||||
foo::spawn_at(next_instant, next_instant).unwrap();
|
foo::spawn_at(next_instant, next_instant).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ mod app {
|
||||||
// Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
|
// Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
|
||||||
let mut mono = Systick::new(systick, 12_000_000);
|
let mut mono = Systick::new(systick, 12_000_000);
|
||||||
|
|
||||||
foo::spawn_after(1.secs(), mono.now()).unwrap();
|
foo::spawn_after(200.millis(), mono.now()).unwrap();
|
||||||
|
|
||||||
(Shared {}, Local {}, init::Monotonics(mono))
|
(Shared {}, Local {}, init::Monotonics(mono))
|
||||||
}
|
}
|
||||||
|
@ -37,7 +36,7 @@ mod app {
|
||||||
// Using the explicit type of the timer implementation
|
// Using the explicit type of the timer implementation
|
||||||
#[task(local = [cnt: u32 = 0])]
|
#[task(local = [cnt: u32 = 0])]
|
||||||
fn foo(cx: foo::Context, instant: fugit::TimerInstantU64<100>) {
|
fn foo(cx: foo::Context, instant: fugit::TimerInstantU64<100>) {
|
||||||
hprintln!("foo {:?}", instant);
|
hprintln!("foo {:?}", instant).ok();
|
||||||
*cx.local.cnt += 1;
|
*cx.local.cnt += 1;
|
||||||
|
|
||||||
if *cx.local.cnt == 4 {
|
if *cx.local.cnt == 4 {
|
||||||
|
@ -53,10 +52,10 @@ mod app {
|
||||||
// This remains agnostic to the timer implementation
|
// This remains agnostic to the timer implementation
|
||||||
#[task(local = [cnt: u32 = 0])]
|
#[task(local = [cnt: u32 = 0])]
|
||||||
fn bar(_cx: bar::Context, instant: <MyMono as rtic_monotonic::Monotonic>::Instant) {
|
fn bar(_cx: bar::Context, instant: <MyMono as rtic_monotonic::Monotonic>::Instant) {
|
||||||
hprintln!("bar {:?}", instant);
|
hprintln!("bar {:?}", instant).ok();
|
||||||
|
|
||||||
// Spawn a new message with 1s offset to spawned time
|
// Spawn a new message with 200ms offset to spawned time
|
||||||
let next_instant = instant + 1.secs();
|
let next_instant = instant + 200.millis();
|
||||||
foo::spawn_at(next_instant, next_instant).unwrap();
|
foo::spawn_at(next_instant, next_instant).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -29,21 +28,21 @@ mod app {
|
||||||
// Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
|
// Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
|
||||||
let mono = Systick::new(systick, 12_000_000);
|
let mono = Systick::new(systick, 12_000_000);
|
||||||
|
|
||||||
foo::spawn_after(1.secs()).unwrap();
|
foo::spawn_after(100.millis()).unwrap();
|
||||||
|
|
||||||
(Shared {}, Local {}, init::Monotonics(mono))
|
(Shared {}, Local {}, init::Monotonics(mono))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(local = [cnt: u32 = 0])]
|
#[task(local = [cnt: u32 = 0])]
|
||||||
fn foo(cx: foo::Context) {
|
fn foo(cx: foo::Context) {
|
||||||
hprintln!("foo");
|
hprintln!("foo").ok();
|
||||||
*cx.local.cnt += 1;
|
*cx.local.cnt += 1;
|
||||||
|
|
||||||
if *cx.local.cnt == 4 {
|
if *cx.local.cnt == 4 {
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Periodic ever 1 seconds
|
// Periodic every 100ms
|
||||||
foo::spawn_after(1.secs()).unwrap();
|
foo::spawn_after(100.millis()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
//! examples/peripherals-taken.rs
|
|
||||||
#![deny(warnings)]
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(missing_docs)]
|
#![deny(warnings)]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
// pool!() generates a struct without docs
|
|
||||||
//#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -58,7 +56,7 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo(_: foo::Context, x: Box<P>) {
|
fn foo(_: foo::Context, x: Box<P>) {
|
||||||
hprintln!("foo({:?})", x.as_ptr());
|
hprintln!("foo({:?})", x.as_ptr()).unwrap();
|
||||||
|
|
||||||
// explicitly return the block to the pool
|
// explicitly return the block to the pool
|
||||||
drop(x);
|
drop(x);
|
||||||
|
@ -68,7 +66,7 @@ mod app {
|
||||||
|
|
||||||
#[task(priority = 2)]
|
#[task(priority = 2)]
|
||||||
fn bar(_: bar::Context, x: Box<P>) {
|
fn bar(_: bar::Context, x: Box<P>) {
|
||||||
hprintln!("bar({:?})", x.as_ptr());
|
hprintln!("bar({:?})", x.as_ptr()).unwrap();
|
||||||
|
|
||||||
// this is done automatically so we can omit the call to `drop`
|
// this is done automatically so we can omit the call to `drop`
|
||||||
// drop(x);
|
// drop(x);
|
||||||
|
|
|
@ -25,21 +25,21 @@ mod app {
|
||||||
|
|
||||||
#[task(priority = 1)]
|
#[task(priority = 1)]
|
||||||
fn foo(_: foo::Context) {
|
fn foo(_: foo::Context) {
|
||||||
hprintln!("foo - start");
|
hprintln!("foo - start").unwrap();
|
||||||
baz::spawn().unwrap();
|
baz::spawn().unwrap();
|
||||||
hprintln!("foo - end");
|
hprintln!("foo - end").unwrap();
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 2)]
|
#[task(priority = 2)]
|
||||||
fn bar(_: bar::Context) {
|
fn bar(_: bar::Context) {
|
||||||
hprintln!(" bar");
|
hprintln!(" bar").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 2)]
|
#[task(priority = 2)]
|
||||||
fn baz(_: baz::Context) {
|
fn baz(_: baz::Context) {
|
||||||
hprintln!(" baz - start");
|
hprintln!(" baz - start").unwrap();
|
||||||
bar::spawn().unwrap();
|
bar::spawn().unwrap();
|
||||||
hprintln!(" baz - end");
|
hprintln!(" baz - end").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! examples/ramfunc.rs
|
//! examples/ramfunc.rs
|
||||||
|
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -34,7 +33,7 @@ mod app {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[task]
|
#[task]
|
||||||
fn foo(_: foo::Context) {
|
fn foo(_: foo::Context) {
|
||||||
hprintln!("foo");
|
hprintln!("foo").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -56,7 +55,7 @@ mod app {
|
||||||
*shared
|
*shared
|
||||||
});
|
});
|
||||||
|
|
||||||
hprintln!("UART0: shared = {}", shared);
|
hprintln!("UART0: shared = {}", shared).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// `shared` can be accessed from this context
|
// `shared` can be accessed from this context
|
||||||
|
@ -67,6 +66,6 @@ mod app {
|
||||||
*shared
|
*shared
|
||||||
});
|
});
|
||||||
|
|
||||||
hprintln!("UART1: shared = {}", shared);
|
hprintln!("UART1: shared = {}", shared).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ mod app {
|
||||||
// Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
|
// Initialize the monotonic (SysTick rate in QEMU is 12 MHz)
|
||||||
let mono = Systick::new(systick, 12_000_000);
|
let mono = Systick::new(systick, 12_000_000);
|
||||||
|
|
||||||
hprintln!("init");
|
hprintln!("init").ok();
|
||||||
|
|
||||||
// Schedule `foo` to run 1 second in the future
|
// Schedule `foo` to run 1 second in the future
|
||||||
foo::spawn_after(1.secs()).unwrap();
|
foo::spawn_after(1.secs()).unwrap();
|
||||||
|
@ -43,7 +42,7 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo(_: foo::Context) {
|
fn foo(_: foo::Context) {
|
||||||
hprintln!("foo");
|
hprintln!("foo").ok();
|
||||||
|
|
||||||
// Schedule `bar` to run 2 seconds in the future (1 second after foo runs)
|
// Schedule `bar` to run 2 seconds in the future (1 second after foo runs)
|
||||||
bar::spawn_after(1.secs()).unwrap();
|
bar::spawn_after(1.secs()).unwrap();
|
||||||
|
@ -51,7 +50,7 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar(_: bar::Context) {
|
fn bar(_: bar::Context) {
|
||||||
hprintln!("bar");
|
hprintln!("bar").ok();
|
||||||
|
|
||||||
// Schedule `baz` to run 1 seconds from now, but with a specific time instant.
|
// Schedule `baz` to run 1 seconds from now, but with a specific time instant.
|
||||||
baz::spawn_at(monotonics::now() + 1.secs()).unwrap();
|
baz::spawn_at(monotonics::now() + 1.secs()).unwrap();
|
||||||
|
@ -59,7 +58,7 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn baz(_: baz::Context) {
|
fn baz(_: baz::Context) {
|
||||||
hprintln!("baz");
|
hprintln!("baz").ok();
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -16,9 +15,7 @@ mod app {
|
||||||
|
|
||||||
#[shared]
|
#[shared]
|
||||||
struct Shared {
|
struct Shared {
|
||||||
/// Producer
|
|
||||||
p: Producer<'static, u32, 5>,
|
p: Producer<'static, u32, 5>,
|
||||||
/// Consumer
|
|
||||||
c: Consumer<'static, u32, 5>,
|
c: Consumer<'static, u32, 5>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +34,7 @@ mod app {
|
||||||
fn idle(mut c: idle::Context) -> ! {
|
fn idle(mut c: idle::Context) -> ! {
|
||||||
loop {
|
loop {
|
||||||
if let Some(byte) = c.shared.c.lock(|c| c.dequeue()) {
|
if let Some(byte) = c.shared.c.lock(|c| c.dequeue()) {
|
||||||
hprintln!("received message: {}", byte);
|
hprintln!("received message: {}", byte).unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -20,7 +19,7 @@ mod app {
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
hprintln!("init");
|
hprintln!("init").unwrap();
|
||||||
foo::spawn().unwrap();
|
foo::spawn().unwrap();
|
||||||
|
|
||||||
(Shared {}, Local {}, init::Monotonics())
|
(Shared {}, Local {}, init::Monotonics())
|
||||||
|
@ -28,7 +27,7 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo(_: foo::Context) {
|
fn foo(_: foo::Context) {
|
||||||
hprintln!("foo");
|
hprintln!("foo").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ mod app {
|
||||||
loop {
|
loop {
|
||||||
// Lock-free access to the same underlying queue!
|
// Lock-free access to the same underlying queue!
|
||||||
if let Some(data) = c.local.c.dequeue() {
|
if let Some(data) = c.local.c.dequeue() {
|
||||||
hprintln!("received message: {}", data);
|
hprintln!("received message: {}", data).unwrap();
|
||||||
|
|
||||||
// Run foo until data
|
// Run foo until data
|
||||||
if data == 3 {
|
if data == 3 {
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
//! examples/t-htask-main.rs
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
//! examples/t-idle-main.rs
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -27,31 +26,31 @@ mod app {
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo(_: foo::Context) {
|
fn foo(_: foo::Context) {
|
||||||
hprintln!("foo - start");
|
hprintln!("foo - start").unwrap();
|
||||||
|
|
||||||
// spawns `bar` onto the task scheduler
|
// spawns `bar` onto the task scheduler
|
||||||
// `foo` and `bar` have the same priority so `bar` will not run until
|
// `foo` and `bar` have the same priority so `bar` will not run until
|
||||||
// after `foo` terminates
|
// after `foo` terminates
|
||||||
bar::spawn().unwrap();
|
bar::spawn().unwrap();
|
||||||
|
|
||||||
hprintln!("foo - middle");
|
hprintln!("foo - middle").unwrap();
|
||||||
|
|
||||||
// spawns `baz` onto the task scheduler
|
// spawns `baz` onto the task scheduler
|
||||||
// `baz` has higher priority than `foo` so it immediately preempts `foo`
|
// `baz` has higher priority than `foo` so it immediately preempts `foo`
|
||||||
baz::spawn().unwrap();
|
baz::spawn().unwrap();
|
||||||
|
|
||||||
hprintln!("foo - end");
|
hprintln!("foo - end").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar(_: bar::Context) {
|
fn bar(_: bar::Context) {
|
||||||
hprintln!("bar");
|
hprintln!("bar").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 2)]
|
#[task(priority = 2)]
|
||||||
fn baz(_: baz::Context) {
|
fn baz(_: baz::Context) {
|
||||||
hprintln!("baz");
|
hprintln!("baz").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
|
||||||
(&r.cfgs, &r.ty, false)
|
(&r.cfgs, &r.ty, false)
|
||||||
}
|
}
|
||||||
TaskLocal::Declared(r) => (&r.cfgs, &r.ty, true),
|
TaskLocal::Declared(r) => (&r.cfgs, &r.ty, true),
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
has_cfgs |= !cfgs.is_empty();
|
has_cfgs |= !cfgs.is_empty();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use core::ops;
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
|
@ -23,26 +22,6 @@ pub type Map<T> = IndexMap<Ident, T>;
|
||||||
/// An order set
|
/// An order set
|
||||||
pub type Set<T> = IndexSet<T>;
|
pub type Set<T> = IndexSet<T>;
|
||||||
|
|
||||||
/// Immutable pointer
|
|
||||||
pub struct P<T> {
|
|
||||||
ptr: Box<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> P<T> {
|
|
||||||
/// Boxes `x` making the value immutable
|
|
||||||
pub fn new(x: T) -> P<T> {
|
|
||||||
P { ptr: Box::new(x) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ops::Deref for P<T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
|
||||||
&self.ptr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Execution context
|
/// Execution context
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Context<'a> {
|
pub enum Context<'a> {
|
||||||
|
|
|
@ -338,8 +338,8 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Priority ceiling
|
// /// Priority ceiling
|
||||||
pub type Ceiling = Option<u8>;
|
// pub type Ceiling = Option<u8>;
|
||||||
|
|
||||||
/// Task priority
|
/// Task priority
|
||||||
pub type Priority = u8;
|
pub type Priority = u8;
|
||||||
|
@ -427,22 +427,22 @@ pub enum Ownership {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ownership {
|
// impl Ownership {
|
||||||
/// Whether this resource needs to a lock at this priority level
|
// /// Whether this resource needs to a lock at this priority level
|
||||||
pub fn needs_lock(&self, priority: u8) -> bool {
|
// pub fn needs_lock(&self, priority: u8) -> bool {
|
||||||
match self {
|
// match self {
|
||||||
Ownership::Owned { .. } | Ownership::CoOwned { .. } => false,
|
// Ownership::Owned { .. } | Ownership::CoOwned { .. } => false,
|
||||||
|
//
|
||||||
Ownership::Contended { ceiling } => {
|
// Ownership::Contended { ceiling } => {
|
||||||
debug_assert!(*ceiling >= priority);
|
// debug_assert!(*ceiling >= priority);
|
||||||
|
//
|
||||||
priority < *ceiling
|
// priority < *ceiling
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// Whether this resource is exclusively owned
|
// /// Whether this resource is exclusively owned
|
||||||
pub fn is_owned(&self) -> bool {
|
// pub fn is_owned(&self) -> bool {
|
||||||
matches!(self, Ownership::Owned { .. })
|
// matches!(self, Ownership::Owned { .. })
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
134
src/export.rs
134
src/export.rs
|
@ -1,11 +1,13 @@
|
||||||
#![allow(clippy::inline_always)]
|
#![allow(clippy::inline_always)]
|
||||||
|
pub use crate::{
|
||||||
|
sll::{IntrusiveSortedLinkedList, Node as IntrusiveNode},
|
||||||
|
tq::{TaskNotReady, TimerQueue, WakerNotReady},
|
||||||
|
};
|
||||||
|
pub use bare_metal::CriticalSection;
|
||||||
use core::{
|
use core::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::tq::{NotReady, TimerQueue};
|
|
||||||
pub use bare_metal::CriticalSection;
|
|
||||||
pub use cortex_m::{
|
pub use cortex_m::{
|
||||||
asm::nop,
|
asm::nop,
|
||||||
asm::wfi,
|
asm::wfi,
|
||||||
|
@ -16,10 +18,134 @@ pub use cortex_m::{
|
||||||
pub use heapless::sorted_linked_list::SortedLinkedList;
|
pub use heapless::sorted_linked_list::SortedLinkedList;
|
||||||
pub use heapless::spsc::Queue;
|
pub use heapless::spsc::Queue;
|
||||||
pub use heapless::BinaryHeap;
|
pub use heapless::BinaryHeap;
|
||||||
|
pub use heapless::Vec;
|
||||||
pub use rtic_monotonic as monotonic;
|
pub use rtic_monotonic as monotonic;
|
||||||
|
|
||||||
|
pub mod idle_executor {
|
||||||
|
use core::{
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn no_op(_: *const ()) {}
|
||||||
|
fn no_op_clone(_: *const ()) -> RawWaker {
|
||||||
|
noop_raw_waker()
|
||||||
|
}
|
||||||
|
|
||||||
|
static IDLE_WAKER_TABLE: RawWakerVTable = RawWakerVTable::new(no_op_clone, no_op, no_op, no_op);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn noop_raw_waker() -> RawWaker {
|
||||||
|
RawWaker::new(core::ptr::null(), &IDLE_WAKER_TABLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IdleExecutor<T>
|
||||||
|
where
|
||||||
|
T: Future,
|
||||||
|
{
|
||||||
|
idle: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IdleExecutor<T>
|
||||||
|
where
|
||||||
|
T: Future,
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new(idle: T) -> Self {
|
||||||
|
Self { idle }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn run(&mut self) -> ! {
|
||||||
|
let w = unsafe { Waker::from_raw(noop_raw_waker()) };
|
||||||
|
let mut ctxt = Context::from_waker(&w);
|
||||||
|
loop {
|
||||||
|
match unsafe { Pin::new_unchecked(&mut self.idle) }.poll(&mut ctxt) {
|
||||||
|
Poll::Pending => {
|
||||||
|
// All ok!
|
||||||
|
}
|
||||||
|
Poll::Ready(_) => {
|
||||||
|
// The idle executor will never return
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod executor {
|
||||||
|
use core::{
|
||||||
|
future::Future,
|
||||||
|
mem,
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
|
};
|
||||||
|
|
||||||
|
static WAKER_VTABLE: RawWakerVTable =
|
||||||
|
RawWakerVTable::new(waker_clone, waker_wake, waker_wake, waker_drop);
|
||||||
|
|
||||||
|
unsafe fn waker_clone(p: *const ()) -> RawWaker {
|
||||||
|
RawWaker::new(p, &WAKER_VTABLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn waker_wake(p: *const ()) {
|
||||||
|
// The only thing we need from a waker is the function to call to pend the async
|
||||||
|
// dispatcher.
|
||||||
|
let f: fn() = mem::transmute(p);
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn waker_drop(_: *const ()) {
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
//============
|
||||||
|
// AsyncTaskExecutor
|
||||||
|
|
||||||
|
pub struct AsyncTaskExecutor<F: Future + 'static> {
|
||||||
|
task: Option<F>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Future + 'static> AsyncTaskExecutor<F> {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self { task: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_running(&self) -> bool {
|
||||||
|
self.task.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn(&mut self, future: F) {
|
||||||
|
self.task = Some(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll(&mut self, wake: fn()) -> bool {
|
||||||
|
if let Some(future) = &mut self.task {
|
||||||
|
unsafe {
|
||||||
|
let waker = Waker::from_raw(RawWaker::new(wake as *const (), &WAKER_VTABLE));
|
||||||
|
let mut cx = Context::from_waker(&waker);
|
||||||
|
let future = Pin::new_unchecked(future);
|
||||||
|
|
||||||
|
match future.poll(&mut cx) {
|
||||||
|
Poll::Ready(_) => {
|
||||||
|
self.task = None;
|
||||||
|
true // Only true if we finished now
|
||||||
|
}
|
||||||
|
Poll::Pending => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type SCFQ<const N: usize> = Queue<u8, N>;
|
pub type SCFQ<const N: usize> = Queue<u8, N>;
|
||||||
pub type SCRQ<T, const N: usize> = Queue<(T, u8), N>;
|
pub type SCRQ<T, const N: usize> = Queue<(T, u8), N>;
|
||||||
|
pub type ASYNCRQ<T, const N: usize> = Queue<T, N>;
|
||||||
|
|
||||||
/// Mask is used to store interrupt masks on systems without a BASEPRI register (M0, M0+, M23).
|
/// Mask is used to store interrupt masks on systems without a BASEPRI register (M0, M0+, M23).
|
||||||
/// It needs to be large enough to cover all the relevant interrupts in use.
|
/// It needs to be large enough to cover all the relevant interrupts in use.
|
||||||
|
@ -117,7 +243,7 @@ impl Priority {
|
||||||
///
|
///
|
||||||
/// Will overwrite the current Priority
|
/// Will overwrite the current Priority
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn new(value: u8) -> Self {
|
pub const unsafe fn new(value: u8) -> Self {
|
||||||
Priority {
|
Priority {
|
||||||
inner: Cell::new(value),
|
inner: Cell::new(value),
|
||||||
}
|
}
|
||||||
|
|
129
src/lib.rs
129
src/lib.rs
|
@ -1,14 +1,125 @@
|
||||||
pub fn add(left: usize, right: usize) -> usize {
|
//! Real-Time Interrupt-driven Concurrency (RTIC) framework for ARM Cortex-M microcontrollers.
|
||||||
left + right
|
//!
|
||||||
|
//! **IMPORTANT**: This crate is published as [`cortex-m-rtic`] on crates.io but the name of the
|
||||||
|
//! library is `rtic`.
|
||||||
|
//!
|
||||||
|
//! [`cortex-m-rtic`]: https://crates.io/crates/cortex-m-rtic
|
||||||
|
//!
|
||||||
|
//! The user level documentation can be found [here].
|
||||||
|
//!
|
||||||
|
//! [here]: https://rtic.rs
|
||||||
|
//!
|
||||||
|
//! Don't forget to check the documentation of the `#[app]` attribute (listed under the reexports
|
||||||
|
//! section), which is the main component of the framework.
|
||||||
|
//!
|
||||||
|
//! # Minimum Supported Rust Version (MSRV)
|
||||||
|
//!
|
||||||
|
//! This crate is compiled and tested with the latest toolchain (rolling) as of the release date.
|
||||||
|
//! If you run into compilation errors, try the latest stable release of the rust toolchain.
|
||||||
|
//!
|
||||||
|
//! # Semantic Versioning
|
||||||
|
//!
|
||||||
|
//! Like the Rust project, this crate adheres to [SemVer]: breaking changes in the API and semantics
|
||||||
|
//! require a *semver bump* (since 1.0.0 a new major version release), with the exception of breaking changes
|
||||||
|
//! that fix soundness issues -- those are considered bug fixes and can be landed in a new patch
|
||||||
|
//! release.
|
||||||
|
//!
|
||||||
|
//! [SemVer]: https://semver.org/spec/v2.0.0.html
|
||||||
|
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
#![deny(rust_2021_compatibility)]
|
||||||
|
#![deny(rust_2018_compatibility)]
|
||||||
|
#![deny(rust_2018_idioms)]
|
||||||
|
#![no_std]
|
||||||
|
#![doc(
|
||||||
|
html_logo_url = "https://raw.githubusercontent.com/rtic-rs/cortex-m-rtic/master/book/en/src/RTIC.svg",
|
||||||
|
html_favicon_url = "https://raw.githubusercontent.com/rtic-rs/cortex-m-rtic/master/book/en/src/RTIC.svg"
|
||||||
|
)]
|
||||||
|
//deny_warnings_placeholder_for_ci
|
||||||
|
#![allow(clippy::inline_always)]
|
||||||
|
|
||||||
|
use cortex_m::{interrupt::InterruptNumber, peripheral::NVIC};
|
||||||
|
pub use rtic_core::{prelude as mutex_prelude, Exclusive, Mutex};
|
||||||
|
pub use rtic_macros::app;
|
||||||
|
pub use rtic_monotonic::{self, Monotonic};
|
||||||
|
|
||||||
|
/// module `mutex::prelude` provides `Mutex` and multi-lock variants. Recommended over `mutex_prelude`
|
||||||
|
pub mod mutex {
|
||||||
|
pub use rtic_core::prelude;
|
||||||
|
pub use rtic_core::Mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[doc(hidden)]
|
||||||
mod tests {
|
pub mod export;
|
||||||
use super::*;
|
#[doc(hidden)]
|
||||||
|
pub mod sll;
|
||||||
|
#[doc(hidden)]
|
||||||
|
mod tq;
|
||||||
|
|
||||||
#[test]
|
/// Sets the given `interrupt` as pending
|
||||||
fn it_works() {
|
///
|
||||||
let result = add(2, 2);
|
/// This is a convenience function around
|
||||||
assert_eq!(result, 4);
|
/// [`NVIC::pend`](../cortex_m/peripheral/struct.NVIC.html#method.pend)
|
||||||
|
pub fn pend<I>(interrupt: I)
|
||||||
|
where
|
||||||
|
I: InterruptNumber,
|
||||||
|
{
|
||||||
|
NVIC::pend(interrupt);
|
||||||
|
}
|
||||||
|
|
||||||
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
|
/// Internal replacement for `static mut T`
|
||||||
|
///
|
||||||
|
/// Used to represent RTIC Resources
|
||||||
|
///
|
||||||
|
/// Soundness:
|
||||||
|
/// 1) Unsafe API for internal use only
|
||||||
|
/// 2) ``get_mut(&self) -> *mut T``
|
||||||
|
/// returns a raw mutable pointer to the inner T
|
||||||
|
/// casting to &mut T is under control of RTIC
|
||||||
|
/// RTIC ensures &mut T to be unique under Rust aliasing rules.
|
||||||
|
///
|
||||||
|
/// Implementation uses the underlying ``UnsafeCell<T>``
|
||||||
|
/// self.0.get() -> *mut T
|
||||||
|
///
|
||||||
|
/// 3) get(&self) -> *const T
|
||||||
|
/// returns a raw immutable (const) pointer to the inner T
|
||||||
|
/// casting to &T is under control of RTIC
|
||||||
|
/// RTIC ensures &T to be shared under Rust aliasing rules.
|
||||||
|
///
|
||||||
|
/// Implementation uses the underlying ``UnsafeCell<T>``
|
||||||
|
/// self.0.get() -> *mut T, demoted to *const T
|
||||||
|
///
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct RacyCell<T>(UnsafeCell<T>);
|
||||||
|
|
||||||
|
impl<T> RacyCell<T> {
|
||||||
|
/// Create a ``RacyCell``
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn new(value: T) -> Self {
|
||||||
|
RacyCell(UnsafeCell::new(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get `*mut T`
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// See documentation notes for [`RacyCell`]
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn get_mut(&self) -> *mut T {
|
||||||
|
self.0.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get `*const T`
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// See documentation notes for [`RacyCell`]
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn get(&self) -> *const T {
|
||||||
|
self.0.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> Sync for RacyCell<T> {}
|
||||||
|
|
421
src/sll.rs
Normal file
421
src/sll.rs
Normal file
|
@ -0,0 +1,421 @@
|
||||||
|
//! An intrusive sorted priority linked list, designed for use in `Future`s in RTIC.
|
||||||
|
use core::cmp::Ordering;
|
||||||
|
use core::fmt;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
|
/// Marker for Min sorted [`IntrusiveSortedLinkedList`].
|
||||||
|
pub struct Min;
|
||||||
|
|
||||||
|
/// Marker for Max sorted [`IntrusiveSortedLinkedList`].
|
||||||
|
pub struct Max;
|
||||||
|
|
||||||
|
/// The linked list kind: min-list or max-list
|
||||||
|
pub trait Kind: private::Sealed {
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn ordering() -> Ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kind for Min {
|
||||||
|
fn ordering() -> Ordering {
|
||||||
|
Ordering::Less
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kind for Max {
|
||||||
|
fn ordering() -> Ordering {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sealed traits
|
||||||
|
mod private {
|
||||||
|
pub trait Sealed {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl private::Sealed for Max {}
|
||||||
|
impl private::Sealed for Min {}
|
||||||
|
|
||||||
|
/// A node in the [`IntrusiveSortedLinkedList`].
|
||||||
|
pub struct Node<T> {
|
||||||
|
pub val: T,
|
||||||
|
next: Option<NonNull<Node<T>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Node<T> {
|
||||||
|
pub fn new(val: T) -> Self {
|
||||||
|
Self { val, next: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The linked list.
|
||||||
|
pub struct IntrusiveSortedLinkedList<'a, T, K> {
|
||||||
|
head: Option<NonNull<Node<T>>>,
|
||||||
|
_kind: PhantomData<K>,
|
||||||
|
_lt: PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, K> fmt::Debug for IntrusiveSortedLinkedList<'a, T, K>
|
||||||
|
where
|
||||||
|
T: Ord + core::fmt::Debug,
|
||||||
|
K: Kind,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut l = f.debug_list();
|
||||||
|
let mut current = self.head;
|
||||||
|
|
||||||
|
while let Some(head) = current {
|
||||||
|
let head = unsafe { head.as_ref() };
|
||||||
|
current = head.next;
|
||||||
|
|
||||||
|
l.entry(&head.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
l.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, K> IntrusiveSortedLinkedList<'a, T, K>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
K: Kind,
|
||||||
|
{
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
head: None,
|
||||||
|
_kind: PhantomData,
|
||||||
|
_lt: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push to the list.
|
||||||
|
pub fn push(&mut self, new: &'a mut Node<T>) {
|
||||||
|
unsafe {
|
||||||
|
if let Some(head) = self.head {
|
||||||
|
if head.as_ref().val.cmp(&new.val) != K::ordering() {
|
||||||
|
// This is newer than head, replace head
|
||||||
|
new.next = self.head;
|
||||||
|
self.head = Some(NonNull::new_unchecked(new));
|
||||||
|
} else {
|
||||||
|
// It's not head, search the list for the correct placement
|
||||||
|
let mut current = head;
|
||||||
|
|
||||||
|
while let Some(next) = current.as_ref().next {
|
||||||
|
if next.as_ref().val.cmp(&new.val) != K::ordering() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
new.next = current.as_ref().next;
|
||||||
|
current.as_mut().next = Some(NonNull::new_unchecked(new));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// List is empty, place at head
|
||||||
|
self.head = Some(NonNull::new_unchecked(new))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get an iterator over the sorted list.
|
||||||
|
pub fn iter(&self) -> Iter<'_, T, K> {
|
||||||
|
Iter {
|
||||||
|
_list: self,
|
||||||
|
index: self.head,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find an element in the list that can be changed and resorted.
|
||||||
|
pub fn find_mut<F>(&mut self, mut f: F) -> Option<FindMut<'_, 'a, T, K>>
|
||||||
|
where
|
||||||
|
F: FnMut(&T) -> bool,
|
||||||
|
{
|
||||||
|
let head = self.head?;
|
||||||
|
|
||||||
|
// Special-case, first element
|
||||||
|
if f(&unsafe { head.as_ref() }.val) {
|
||||||
|
return Some(FindMut {
|
||||||
|
is_head: true,
|
||||||
|
prev_index: None,
|
||||||
|
index: self.head,
|
||||||
|
list: self,
|
||||||
|
maybe_changed: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut current = head;
|
||||||
|
|
||||||
|
while let Some(next) = unsafe { current.as_ref() }.next {
|
||||||
|
if f(&unsafe { next.as_ref() }.val) {
|
||||||
|
return Some(FindMut {
|
||||||
|
is_head: false,
|
||||||
|
prev_index: Some(current),
|
||||||
|
index: Some(next),
|
||||||
|
list: self,
|
||||||
|
maybe_changed: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Peek at the first element.
|
||||||
|
pub fn peek(&self) -> Option<&T> {
|
||||||
|
self.head.map(|head| unsafe { &head.as_ref().val })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pops the first element in the list.
|
||||||
|
///
|
||||||
|
/// Complexity is worst-case `O(1)`.
|
||||||
|
pub fn pop(&mut self) -> Option<&'a Node<T>> {
|
||||||
|
if let Some(head) = self.head {
|
||||||
|
let v = unsafe { head.as_ref() };
|
||||||
|
self.head = v.next;
|
||||||
|
Some(v)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the linked list is empty.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.head.is_none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterator for the linked list.
|
||||||
|
pub struct Iter<'a, T, K>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
K: Kind,
|
||||||
|
{
|
||||||
|
_list: &'a IntrusiveSortedLinkedList<'a, T, K>,
|
||||||
|
index: Option<NonNull<Node<T>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, K> Iterator for Iter<'a, T, K>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
K: Kind,
|
||||||
|
{
|
||||||
|
type Item = &'a T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let index = self.index?;
|
||||||
|
|
||||||
|
let node = unsafe { index.as_ref() };
|
||||||
|
self.index = node.next;
|
||||||
|
|
||||||
|
Some(&node.val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Comes from [`IntrusiveSortedLinkedList::find_mut`].
|
||||||
|
pub struct FindMut<'a, 'b, T, K>
|
||||||
|
where
|
||||||
|
T: Ord + 'b,
|
||||||
|
K: Kind,
|
||||||
|
{
|
||||||
|
list: &'a mut IntrusiveSortedLinkedList<'b, T, K>,
|
||||||
|
is_head: bool,
|
||||||
|
prev_index: Option<NonNull<Node<T>>>,
|
||||||
|
index: Option<NonNull<Node<T>>>,
|
||||||
|
maybe_changed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, T, K> FindMut<'a, 'b, T, K>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
K: Kind,
|
||||||
|
{
|
||||||
|
unsafe fn pop_internal(&mut self) -> &'b mut Node<T> {
|
||||||
|
if self.is_head {
|
||||||
|
// If it is the head element, we can do a normal pop
|
||||||
|
let mut head = self.list.head.unwrap_unchecked();
|
||||||
|
let v = head.as_mut();
|
||||||
|
self.list.head = v.next;
|
||||||
|
v
|
||||||
|
} else {
|
||||||
|
// Somewhere in the list
|
||||||
|
let mut prev = self.prev_index.unwrap_unchecked();
|
||||||
|
let mut curr = self.index.unwrap_unchecked();
|
||||||
|
|
||||||
|
// Re-point the previous index
|
||||||
|
prev.as_mut().next = curr.as_ref().next;
|
||||||
|
|
||||||
|
curr.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This will pop the element from the list.
|
||||||
|
///
|
||||||
|
/// Complexity is worst-case `O(1)`.
|
||||||
|
#[inline]
|
||||||
|
pub fn pop(mut self) -> &'b mut Node<T> {
|
||||||
|
unsafe { self.pop_internal() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This will resort the element into the correct position in the list if needed. The resorting
|
||||||
|
/// will only happen if the element has been accessed mutably.
|
||||||
|
///
|
||||||
|
/// Same as calling `drop`.
|
||||||
|
///
|
||||||
|
/// Complexity is worst-case `O(N)`.
|
||||||
|
#[inline]
|
||||||
|
pub fn finish(self) {
|
||||||
|
drop(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, T, K> Drop for FindMut<'_, 'b, T, K>
|
||||||
|
where
|
||||||
|
T: Ord + 'b,
|
||||||
|
K: Kind,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// Only resort the list if the element has changed
|
||||||
|
if self.maybe_changed {
|
||||||
|
unsafe {
|
||||||
|
let val = self.pop_internal();
|
||||||
|
self.list.push(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, K> Deref for FindMut<'_, '_, T, K>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
K: Kind,
|
||||||
|
{
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { &self.index.unwrap_unchecked().as_ref().val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, K> DerefMut for FindMut<'_, '_, T, K>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
K: Kind,
|
||||||
|
{
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.maybe_changed = true;
|
||||||
|
unsafe { &mut self.index.unwrap_unchecked().as_mut().val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn const_new() {
|
||||||
|
static mut _V1: IntrusiveSortedLinkedList<u32, Max> = IntrusiveSortedLinkedList::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_peek() {
|
||||||
|
let mut ll: IntrusiveSortedLinkedList<u32, Max> = IntrusiveSortedLinkedList::new();
|
||||||
|
|
||||||
|
let mut a = Node { val: 1, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
assert_eq!(ll.peek().unwrap(), &1);
|
||||||
|
|
||||||
|
let mut a = Node { val: 2, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
assert_eq!(ll.peek().unwrap(), &2);
|
||||||
|
|
||||||
|
let mut a = Node { val: 3, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
assert_eq!(ll.peek().unwrap(), &3);
|
||||||
|
|
||||||
|
let mut ll: IntrusiveSortedLinkedList<u32, Min> = IntrusiveSortedLinkedList::new();
|
||||||
|
|
||||||
|
let mut a = Node { val: 2, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
assert_eq!(ll.peek().unwrap(), &2);
|
||||||
|
|
||||||
|
let mut a = Node { val: 1, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
assert_eq!(ll.peek().unwrap(), &1);
|
||||||
|
|
||||||
|
let mut a = Node { val: 3, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
assert_eq!(ll.peek().unwrap(), &1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty() {
|
||||||
|
let ll: IntrusiveSortedLinkedList<u32, Max> = IntrusiveSortedLinkedList::new();
|
||||||
|
|
||||||
|
assert!(ll.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_updating() {
|
||||||
|
let mut ll: IntrusiveSortedLinkedList<u32, Max> = IntrusiveSortedLinkedList::new();
|
||||||
|
|
||||||
|
let mut a = Node { val: 1, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
|
||||||
|
let mut a = Node { val: 2, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
|
||||||
|
let mut a = Node { val: 3, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
|
||||||
|
let mut find = ll.find_mut(|v| *v == 2).unwrap();
|
||||||
|
|
||||||
|
*find += 1000;
|
||||||
|
find.finish();
|
||||||
|
|
||||||
|
assert_eq!(ll.peek().unwrap(), &1002);
|
||||||
|
|
||||||
|
let mut find = ll.find_mut(|v| *v == 3).unwrap();
|
||||||
|
|
||||||
|
*find += 1000;
|
||||||
|
find.finish();
|
||||||
|
|
||||||
|
assert_eq!(ll.peek().unwrap(), &1003);
|
||||||
|
|
||||||
|
// Remove largest element
|
||||||
|
ll.find_mut(|v| *v == 1003).unwrap().pop();
|
||||||
|
|
||||||
|
assert_eq!(ll.peek().unwrap(), &1002);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_updating_1() {
|
||||||
|
let mut ll: IntrusiveSortedLinkedList<u32, Max> = IntrusiveSortedLinkedList::new();
|
||||||
|
|
||||||
|
let mut a = Node { val: 1, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
|
||||||
|
let v = ll.pop().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(v.val, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_updating_2() {
|
||||||
|
let mut ll: IntrusiveSortedLinkedList<u32, Max> = IntrusiveSortedLinkedList::new();
|
||||||
|
|
||||||
|
let mut a = Node { val: 1, next: None };
|
||||||
|
ll.push(&mut a);
|
||||||
|
|
||||||
|
let mut find = ll.find_mut(|v| *v == 1).unwrap();
|
||||||
|
|
||||||
|
*find += 1000;
|
||||||
|
find.finish();
|
||||||
|
|
||||||
|
assert_eq!(ll.peek().unwrap(), &1001);
|
||||||
|
}
|
||||||
|
}
|
277
src/tq.rs
277
src/tq.rs
|
@ -1,29 +1,28 @@
|
||||||
use crate::Monotonic;
|
use crate::{
|
||||||
|
sll::{IntrusiveSortedLinkedList, Min as IsslMin, Node as IntrusiveNode},
|
||||||
|
Monotonic,
|
||||||
|
};
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use heapless::sorted_linked_list::{LinkedIndexU16, Min, SortedLinkedList};
|
use core::task::Waker;
|
||||||
|
use heapless::sorted_linked_list::{LinkedIndexU16, Min as SllMin, SortedLinkedList};
|
||||||
|
|
||||||
pub struct TimerQueue<Mono, Task, const N: usize>(
|
pub struct TimerQueue<'a, Mono, Task, const N_TASK: usize>
|
||||||
pub SortedLinkedList<NotReady<Mono, Task>, LinkedIndexU16, Min, N>,
|
|
||||||
)
|
|
||||||
where
|
|
||||||
Mono: Monotonic,
|
|
||||||
Task: Copy;
|
|
||||||
|
|
||||||
impl<Mono, Task, const N: usize> TimerQueue<Mono, Task, N>
|
|
||||||
where
|
where
|
||||||
Mono: Monotonic,
|
Mono: Monotonic,
|
||||||
Task: Copy,
|
Task: Copy,
|
||||||
{
|
{
|
||||||
/// # Safety
|
pub task_queue: SortedLinkedList<TaskNotReady<Mono, Task>, LinkedIndexU16, SllMin, N_TASK>,
|
||||||
///
|
pub waker_queue: IntrusiveSortedLinkedList<'a, WakerNotReady<Mono>, IsslMin>,
|
||||||
/// Writing to memory with a transmute in order to enable
|
}
|
||||||
/// interrupts of the ``SysTick`` timer
|
|
||||||
///
|
impl<'a, Mono, Task, const N_TASK: usize> TimerQueue<'a, Mono, Task, N_TASK>
|
||||||
/// Enqueue a task without checking if it is full
|
where
|
||||||
#[inline]
|
Mono: Monotonic + 'a,
|
||||||
pub unsafe fn enqueue_unchecked<F1, F2>(
|
Task: Copy,
|
||||||
&mut self,
|
{
|
||||||
nr: NotReady<Mono, Task>,
|
fn check_if_enable<F1, F2>(
|
||||||
|
&self,
|
||||||
|
instant: Mono::Instant,
|
||||||
enable_interrupt: F1,
|
enable_interrupt: F1,
|
||||||
pend_handler: F2,
|
pend_handler: F2,
|
||||||
mono: Option<&mut Mono>,
|
mono: Option<&mut Mono>,
|
||||||
|
@ -33,11 +32,17 @@ where
|
||||||
{
|
{
|
||||||
// Check if the top contains a non-empty element and if that element is
|
// Check if the top contains a non-empty element and if that element is
|
||||||
// greater than nr
|
// greater than nr
|
||||||
let if_heap_max_greater_than_nr =
|
let if_task_heap_max_greater_than_nr = self
|
||||||
self.0.peek().map_or(true, |head| nr.instant < head.instant);
|
.task_queue
|
||||||
|
.peek()
|
||||||
|
.map_or(true, |head| instant < head.instant);
|
||||||
|
let if_waker_heap_max_greater_than_nr = self
|
||||||
|
.waker_queue
|
||||||
|
.peek()
|
||||||
|
.map_or(true, |head| instant < head.instant);
|
||||||
|
|
||||||
if if_heap_max_greater_than_nr {
|
if if_task_heap_max_greater_than_nr || if_waker_heap_max_greater_than_nr {
|
||||||
if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE && self.0.is_empty() {
|
if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE && self.is_empty() {
|
||||||
if let Some(mono) = mono {
|
if let Some(mono) = mono {
|
||||||
mono.enable_timer();
|
mono.enable_timer();
|
||||||
}
|
}
|
||||||
|
@ -46,19 +51,49 @@ where
|
||||||
|
|
||||||
pend_handler();
|
pend_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.0.push_unchecked(nr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the timer queue is empty.
|
/// Enqueue a task without checking if it is full
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn enqueue_task_unchecked<F1, F2>(
|
||||||
|
&mut self,
|
||||||
|
nr: TaskNotReady<Mono, Task>,
|
||||||
|
enable_interrupt: F1,
|
||||||
|
pend_handler: F2,
|
||||||
|
mono: Option<&mut Mono>,
|
||||||
|
) where
|
||||||
|
F1: FnOnce(),
|
||||||
|
F2: FnOnce(),
|
||||||
|
{
|
||||||
|
self.check_if_enable(nr.instant, enable_interrupt, pend_handler, mono);
|
||||||
|
self.task_queue.push_unchecked(nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enqueue a waker
|
||||||
|
#[inline]
|
||||||
|
pub fn enqueue_waker<F1, F2>(
|
||||||
|
&mut self,
|
||||||
|
nr: &'a mut IntrusiveNode<WakerNotReady<Mono>>,
|
||||||
|
enable_interrupt: F1,
|
||||||
|
pend_handler: F2,
|
||||||
|
mono: Option<&mut Mono>,
|
||||||
|
) where
|
||||||
|
F1: FnOnce(),
|
||||||
|
F2: FnOnce(),
|
||||||
|
{
|
||||||
|
self.check_if_enable(nr.val.instant, enable_interrupt, pend_handler, mono);
|
||||||
|
self.waker_queue.push(nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if all the timer queue is empty.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.0.is_empty()
|
self.task_queue.is_empty() && self.waker_queue.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cancel the marker value
|
/// Cancel the marker value for a task
|
||||||
pub fn cancel_marker(&mut self, marker: u32) -> Option<(Task, u8)> {
|
pub fn cancel_task_marker(&mut self, marker: u32) -> Option<(Task, u8)> {
|
||||||
if let Some(val) = self.0.find_mut(|nr| nr.marker == marker) {
|
if let Some(val) = self.task_queue.find_mut(|nr| nr.marker == marker) {
|
||||||
let nr = val.pop();
|
let nr = val.pop();
|
||||||
|
|
||||||
Some((nr.task, nr.index))
|
Some((nr.task, nr.index))
|
||||||
|
@ -67,16 +102,23 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the instant at an marker value to a new instant
|
/// Cancel the marker value for a waker
|
||||||
|
pub fn cancel_waker_marker(&mut self, marker: u32) {
|
||||||
|
if let Some(val) = self.waker_queue.find_mut(|nr| nr.marker == marker) {
|
||||||
|
let _ = val.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the instant at an marker value for a task to a new instant
|
||||||
#[allow(clippy::result_unit_err)]
|
#[allow(clippy::result_unit_err)]
|
||||||
pub fn update_marker<F: FnOnce()>(
|
pub fn update_task_marker<F: FnOnce()>(
|
||||||
&mut self,
|
&mut self,
|
||||||
marker: u32,
|
marker: u32,
|
||||||
new_marker: u32,
|
new_marker: u32,
|
||||||
instant: Mono::Instant,
|
instant: Mono::Instant,
|
||||||
pend_handler: F,
|
pend_handler: F,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
if let Some(mut val) = self.0.find_mut(|nr| nr.marker == marker) {
|
if let Some(mut val) = self.task_queue.find_mut(|nr| nr.marker == marker) {
|
||||||
val.instant = instant;
|
val.instant = instant;
|
||||||
val.marker = new_marker;
|
val.marker = new_marker;
|
||||||
|
|
||||||
|
@ -89,6 +131,62 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dequeue_task_queue(
|
||||||
|
&mut self,
|
||||||
|
instant: Mono::Instant,
|
||||||
|
mono: &mut Mono,
|
||||||
|
) -> Option<(Task, u8)> {
|
||||||
|
if instant <= mono.now() {
|
||||||
|
// task became ready
|
||||||
|
let nr = unsafe { self.task_queue.pop_unchecked() };
|
||||||
|
Some((nr.task, nr.index))
|
||||||
|
} else {
|
||||||
|
// Set compare
|
||||||
|
mono.set_compare(instant);
|
||||||
|
|
||||||
|
// Double check that the instant we set is really in the future, else
|
||||||
|
// dequeue. If the monotonic is fast enough it can happen that from the
|
||||||
|
// read of now to the set of the compare, the time can overflow. This is to
|
||||||
|
// guard against this.
|
||||||
|
if instant <= mono.now() {
|
||||||
|
let nr = unsafe { self.task_queue.pop_unchecked() };
|
||||||
|
Some((nr.task, nr.index))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dequeue_waker_queue(&mut self, instant: Mono::Instant, mono: &mut Mono) -> bool {
|
||||||
|
let mut did_wake = false;
|
||||||
|
|
||||||
|
if instant <= mono.now() {
|
||||||
|
// Task became ready, wake the waker
|
||||||
|
if let Some(v) = self.waker_queue.pop() {
|
||||||
|
v.val.waker.wake_by_ref();
|
||||||
|
|
||||||
|
did_wake = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Set compare
|
||||||
|
mono.set_compare(instant);
|
||||||
|
|
||||||
|
// Double check that the instant we set is really in the future, else
|
||||||
|
// dequeue. If the monotonic is fast enough it can happen that from the
|
||||||
|
// read of now to the set of the compare, the time can overflow. This is to
|
||||||
|
// guard against this.
|
||||||
|
if instant <= mono.now() {
|
||||||
|
if let Some(v) = self.waker_queue.pop() {
|
||||||
|
v.val.waker.wake_by_ref();
|
||||||
|
|
||||||
|
did_wake = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
did_wake
|
||||||
|
}
|
||||||
|
|
||||||
/// Dequeue a task from the ``TimerQueue``
|
/// Dequeue a task from the ``TimerQueue``
|
||||||
pub fn dequeue<F>(&mut self, disable_interrupt: F, mono: &mut Mono) -> Option<(Task, u8)>
|
pub fn dequeue<F>(&mut self, disable_interrupt: F, mono: &mut Mono) -> Option<(Task, u8)>
|
||||||
where
|
where
|
||||||
|
@ -96,59 +194,72 @@ where
|
||||||
{
|
{
|
||||||
mono.clear_compare_flag();
|
mono.clear_compare_flag();
|
||||||
|
|
||||||
if let Some(instant) = self.0.peek().map(|p| p.instant) {
|
loop {
|
||||||
if instant <= mono.now() {
|
let tq = self.task_queue.peek().map(|p| p.instant);
|
||||||
// task became ready
|
let wq = self.waker_queue.peek().map(|p| p.instant);
|
||||||
let nr = unsafe { self.0.pop_unchecked() };
|
|
||||||
|
|
||||||
Some((nr.task, nr.index))
|
let dequeue_task;
|
||||||
} else {
|
let instant;
|
||||||
// Set compare
|
|
||||||
mono.set_compare(instant);
|
|
||||||
|
|
||||||
// Double check that the instant we set is really in the future, else
|
match (tq, wq) {
|
||||||
// dequeue. If the monotonic is fast enough it can happen that from the
|
(Some(tq_instant), Some(wq_instant)) => {
|
||||||
// read of now to the set of the compare, the time can overflow. This is to
|
if tq_instant <= wq_instant {
|
||||||
// guard against this.
|
dequeue_task = true;
|
||||||
if instant <= mono.now() {
|
instant = tq_instant;
|
||||||
let nr = unsafe { self.0.pop_unchecked() };
|
} else {
|
||||||
|
dequeue_task = false;
|
||||||
|
instant = wq_instant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(tq_instant), None) => {
|
||||||
|
dequeue_task = true;
|
||||||
|
instant = tq_instant;
|
||||||
|
}
|
||||||
|
(None, Some(wq_instant)) => {
|
||||||
|
dequeue_task = false;
|
||||||
|
instant = wq_instant;
|
||||||
|
}
|
||||||
|
(None, None) => {
|
||||||
|
// The queue is empty, disable the interrupt.
|
||||||
|
if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
|
||||||
|
disable_interrupt();
|
||||||
|
mono.disable_timer();
|
||||||
|
}
|
||||||
|
|
||||||
Some((nr.task, nr.index))
|
return None;
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// The queue is empty, disable the interrupt.
|
|
||||||
if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
|
|
||||||
disable_interrupt();
|
|
||||||
mono.disable_timer();
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
if dequeue_task {
|
||||||
|
return self.dequeue_task_queue(instant, mono);
|
||||||
|
} else if !self.dequeue_waker_queue(instant, mono) {
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
// Run the dequeue again
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NotReady<Mono, Task>
|
pub struct TaskNotReady<Mono, Task>
|
||||||
where
|
where
|
||||||
Task: Copy,
|
Task: Copy,
|
||||||
Mono: Monotonic,
|
Mono: Monotonic,
|
||||||
{
|
{
|
||||||
|
pub task: Task,
|
||||||
pub index: u8,
|
pub index: u8,
|
||||||
pub instant: Mono::Instant,
|
pub instant: Mono::Instant,
|
||||||
pub task: Task,
|
|
||||||
pub marker: u32,
|
pub marker: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Mono, Task> Eq for NotReady<Mono, Task>
|
impl<Mono, Task> Eq for TaskNotReady<Mono, Task>
|
||||||
where
|
where
|
||||||
Task: Copy,
|
Task: Copy,
|
||||||
Mono: Monotonic,
|
Mono: Monotonic,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Mono, Task> Ord for NotReady<Mono, Task>
|
impl<Mono, Task> Ord for TaskNotReady<Mono, Task>
|
||||||
where
|
where
|
||||||
Task: Copy,
|
Task: Copy,
|
||||||
Mono: Monotonic,
|
Mono: Monotonic,
|
||||||
|
@ -158,7 +269,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Mono, Task> PartialEq for NotReady<Mono, Task>
|
impl<Mono, Task> PartialEq for TaskNotReady<Mono, Task>
|
||||||
where
|
where
|
||||||
Task: Copy,
|
Task: Copy,
|
||||||
Mono: Monotonic,
|
Mono: Monotonic,
|
||||||
|
@ -168,7 +279,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Mono, Task> PartialOrd for NotReady<Mono, Task>
|
impl<Mono, Task> PartialOrd for TaskNotReady<Mono, Task>
|
||||||
where
|
where
|
||||||
Task: Copy,
|
Task: Copy,
|
||||||
Mono: Monotonic,
|
Mono: Monotonic,
|
||||||
|
@ -177,3 +288,41 @@ where
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct WakerNotReady<Mono>
|
||||||
|
where
|
||||||
|
Mono: Monotonic,
|
||||||
|
{
|
||||||
|
pub waker: Waker,
|
||||||
|
pub instant: Mono::Instant,
|
||||||
|
pub marker: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Mono> Eq for WakerNotReady<Mono> where Mono: Monotonic {}
|
||||||
|
|
||||||
|
impl<Mono> Ord for WakerNotReady<Mono>
|
||||||
|
where
|
||||||
|
Mono: Monotonic,
|
||||||
|
{
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.instant.cmp(&other.instant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Mono> PartialEq for WakerNotReady<Mono>
|
||||||
|
where
|
||||||
|
Mono: Monotonic,
|
||||||
|
{
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.instant == other.instant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Mono> PartialOrd for WakerNotReady<Mono>
|
||||||
|
where
|
||||||
|
Mono: Monotonic,
|
||||||
|
{
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: not enough interrupts to dispatch all software tasks (need: 1; given: 0)
|
error: not enough interrupts to dispatch all software and async tasks (need: 1; given: 0) - one interrupt is needed per priority and sync/async task
|
||||||
--> $DIR/extern-interrupt-not-enough.rs:17:8
|
--> ui/extern-interrupt-not-enough.rs:17:8
|
||||||
|
|
|
|
||||||
17 | fn a(_: a::Context) {}
|
17 | fn a(_: a::Context) {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
@ -9,7 +9,7 @@ mod app {
|
||||||
struct Local {}
|
struct Local {}
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
(Shared {}, Local {}, init::Monotonics())
|
(Shared {}, Local {}, init::Monotonics())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
warning: unused variable: `cx`
|
||||||
|
--> ui/task-priority-too-high.rs:12:13
|
||||||
|
|
|
||||||
|
12 | fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
| ^^ help: if this is intentional, prefix it with an underscore: `_cx`
|
||||||
|
|
|
||||||
|
= note: `#[warn(unused_variables)]` on by default
|
||||||
|
|
||||||
error[E0080]: evaluation of constant value failed
|
error[E0080]: evaluation of constant value failed
|
||||||
--> ui/task-priority-too-high.rs:3:1
|
--> ui/task-priority-too-high.rs:3:1
|
||||||
|
|
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ impl<'a> CargoCommand<'a> {
|
||||||
mode,
|
mode,
|
||||||
} => {
|
} => {
|
||||||
let mut args = vec![
|
let mut args = vec![
|
||||||
|
"+nightly",
|
||||||
self.name(),
|
self.name(),
|
||||||
"--example",
|
"--example",
|
||||||
example,
|
example,
|
||||||
|
@ -69,7 +70,7 @@ impl<'a> CargoCommand<'a> {
|
||||||
features,
|
features,
|
||||||
mode,
|
mode,
|
||||||
} => {
|
} => {
|
||||||
let mut args = vec![self.name(), "--examples", "--target", target];
|
let mut args = vec!["+nightly", self.name(), "--examples", "--target", target];
|
||||||
|
|
||||||
if let Some(feature_name) = features {
|
if let Some(feature_name) = features {
|
||||||
args.extend_from_slice(&["--features", feature_name]);
|
args.extend_from_slice(&["--features", feature_name]);
|
||||||
|
|
Loading…
Reference in a new issue