mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-27 14:04:56 +01:00
async idle working
This commit is contained in:
parent
4a349653b4
commit
561bef45e7
3 changed files with 121 additions and 4 deletions
51
examples/async-idle.rs
Normal file
51
examples/async-idle.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#![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();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared {},
|
||||||
|
Local {},
|
||||||
|
init::Monotonics(Systick::new(cx.core.SYST, 12_000_000)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[idle]
|
||||||
|
async fn idle(_: idle::Context) -> ! {
|
||||||
|
hprintln!("idle");
|
||||||
|
|
||||||
|
for i in 0..2 {
|
||||||
|
monotonics::delay(100.millis()).await;
|
||||||
|
hprintln!("async delay {}").ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,10 +63,15 @@ pub fn codegen(
|
||||||
let attrs = &idle.attrs;
|
let attrs = &idle.attrs;
|
||||||
let context = &idle.context;
|
let context = &idle.context;
|
||||||
let stmts = &idle.stmts;
|
let stmts = &idle.stmts;
|
||||||
|
let async_ = if idle.is_async {
|
||||||
|
quote!(async)
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
let user_idle = Some(quote!(
|
let user_idle = Some(quote!(
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn #name(#context: #name::Context) -> ! {
|
#async_ fn #name(#context: #name::Context) -> ! {
|
||||||
use rtic::Mutex as _;
|
use rtic::Mutex as _;
|
||||||
use rtic::mutex::prelude::*;
|
use rtic::mutex::prelude::*;
|
||||||
|
|
||||||
|
@ -74,9 +79,16 @@ pub fn codegen(
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
let call_idle = quote!(#name(
|
let call_idle = if idle.is_async {
|
||||||
#name::Context::new(&rtic::export::Priority::new(0))
|
quote!(
|
||||||
));
|
let idle_task = #name(#name::Context::new(&rtic::export::Priority::new(0)));
|
||||||
|
rtic::export::idle_executor::IdleExecutor::new(idle_task).run();
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
quote!(#name(
|
||||||
|
#name::Context::new(&rtic::export::Priority::new(0))
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
(mod_app, root_idle, user_idle, call_idle)
|
(mod_app, root_idle, user_idle, call_idle)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21,6 +21,60 @@ pub use heapless::BinaryHeap;
|
||||||
pub use heapless::Vec;
|
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 {
|
pub mod executor {
|
||||||
use core::{
|
use core::{
|
||||||
future::Future,
|
future::Future,
|
||||||
|
|
Loading…
Reference in a new issue