diff --git a/examples/async_systick3.rs b/examples/async_systick3.rs new file mode 100644 index 0000000000..eaaa325708 --- /dev/null +++ b/examples/async_systick3.rs @@ -0,0 +1,215 @@ +//! examples/async_task2 +#![no_main] +#![no_std] +#![feature(const_fn)] +#![feature(type_alias_impl_trait)] + +// use core::cell::Cell; +// use core::cell::UnsafeCell; +use core::future::Future; +use core::mem; +// use core::mem::MaybeUninit; +use core::pin::Pin; +// use core::ptr; +// use core::ptr::NonNull; +// use core::sync::atomic::{AtomicPtr, AtomicU32, Ordering}; +use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; +use rtic::async_util::Task; + +use cortex_m_semihosting::{debug, hprintln}; + +use panic_semihosting as _; +use rtic::Mutex; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use crate::*; + + #[resources] + struct Resources { + systick: Systick, + } + + #[init] + fn init(cx: init::Context) -> init::LateResources { + hprintln!("init").ok(); + foo::spawn().unwrap(); + init::LateResources { + systick: Systick { + syst: cx.core.SYST, + state: State::Done, + queue: BinaryHeap::new(), + // waker: None, + }, + } + } + + #[idle] + fn idle(_: idle::Context) -> ! { + // debug::exit(debug::EXIT_SUCCESS); + loop { + hprintln!("idle").ok(); + cortex_m::asm::wfi(); // put the MCU in sleep mode until interrupt occurs + } + } + + #[task(resources = [systick])] + async fn foo(mut cx: foo::Context) { + // BEGIN BOILERPLATE + type F = impl Future + 'static; + fn create(cx: foo::Context<'static>) -> F { + task(cx) + } + + static mut TASK: Task = Task::new(); + + hprintln!("foo trampoline").ok(); + unsafe { + match TASK { + Task::Idle | Task::Done(_) => { + hprintln!("foo spawn task").ok(); + TASK.spawn(|| create(mem::transmute(cx))); + } + _ => {} + }; + + hprintln!("foo trampoline poll").ok(); + TASK.poll(|| { + let _ = foo::spawn(); + }); + + match TASK { + Task::Done(ref r) => { + hprintln!("foo trampoline done").ok(); + // hprintln!("r = {:?}", mem::transmute::<_, &u32>(r)).ok(); + } + _ => { + hprintln!("foo trampoline running").ok(); + } + } + } + // END BOILERPLATE + + async fn task(mut cx: foo::Context<'static>) { + hprintln!("foo task").ok(); + + hprintln!("prepare two futures").ok(); + let d1 = timer_delay(&mut cx.resources.systick, 5000000); + let d2 = timer_delay(&mut cx.resources.systick, 1000000); + + //let pair = futures::future::join(d1, d2); + hprintln!("foo task resumed").ok(); + + hprintln!("delay short time").ok(); + timer_delay(&mut cx.resources.systick, 1000000).await; + hprintln!("foo task resumed").ok(); + } + } + + // RTIC task bound to the HW SysTick interrupt + #[task(binds = SysTick, resources = [systick], priority = 2)] + fn systic(mut cx: systic::Context) { + hprintln!("systic interrupt").ok(); + cx.resources.systick.lock(|s| { + s.syst.disable_interrupt(); + s.state = State::Done; + s.queue.pop().map(|w| w.waker.wake()); + if let Some(w) = s.queue.peek() { + s.syst.set_reload(w.time); + } else { + s.syst.disable_interrupt(); + } + }); + } +} + +//============= +// Timer +// Later we want a proper queue + +//use core::cmp::{Ord, Ordering, PartialOrd}; +use core::cmp::Ordering; +use heapless::binary_heap::{BinaryHeap, Max}; +use heapless::consts::U8; +use heapless::Vec; + +pub enum State { + Started, + Done, +} + +struct Timeout { + time: u32, + waker: Waker, +} + +impl Ord for Timeout { + fn cmp(&self, other: &Self) -> Ordering { + self.time.cmp(&other.time) + } +} + +impl PartialOrd for Timeout { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(&other)) + } +} + +impl PartialEq for Timeout { + fn eq(&self, other: &Self) -> bool { + self.time == other.time + } +} + +impl Eq for Timeout {} + +pub struct Systick { + syst: cortex_m::peripheral::SYST, + state: State, + queue: BinaryHeap, +} + +//============= +// Timer +// Later we want a proper queue + +pub struct Timer<'a, T: Mutex> { + request: Option, + systick: &'a mut T, +} + +impl<'a, T: Mutex> Future for Timer<'a, T> { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let Self { request, systick } = &mut *self; + systick.lock(|s| { + // enqueue a new request + request.take().map(|t| { + s.syst.set_reload(t); + s.syst.enable_counter(); + s.syst.enable_interrupt(); + s.state = State::Started; + s.queue.push(Timeout { + time: t, + waker: cx.waker().clone(), + }); + }); + + match s.state { + State::Done => Poll::Ready(()), + State::Started => { + // s.waker = Some(cx.waker().clone()); + Poll::Pending + } + } + }) + } +} + +fn timer_delay<'a, T: Mutex>(systick: &'a mut T, t: u32) -> Timer<'a, T> { + hprintln!("timer_delay {}", t); + Timer { + request: Some(t), + systick, + } +}