//! 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 cortex_m_semihosting::{debug, hprintln}; use panic_semihosting as _; #[rtic::app(device = lm3s6965, dispatchers = [SSI0], peripherals = true)] mod app { use crate::*; #[resources] struct Resources { syst: cortex_m::peripheral::SYST, #[init(None)] waker: Option, } #[init] fn init(cx: init::Context) -> init::LateResources { // foo::spawn().unwrap(); let mut syst = cx.core.SYST; syst.set_reload(100000); syst.enable_interrupt(); syst.enable_counter(); hprintln!("init").unwrap(); init::LateResources { syst } } #[idle] fn idle(_: idle::Context) -> ! { // foo::spawn().unwrap(); // debug::exit(debug::EXIT_SUCCESS); loop { continue; } } #[task] fn foo(_c: foo::Context) { // BEGIN BOILERPLATE type F = impl Future + 'static; fn create() -> F { task() } static mut TASK: Task = Task::new(); hprintln!("foo trampoline").ok(); unsafe { match TASK { Task::Idle | Task::Done(_) => { hprintln!("create task").ok(); TASK.spawn(create); } _ => {} }; hprintln!("poll").ok(); TASK.poll(|| {}); match TASK { Task::Done(ref r) => { hprintln!("done").ok(); hprintln!("r = {:?}", mem::transmute::<_, &u32>(r)).ok(); } _ => { hprintln!("running").ok(); } } } // END BOILERPLATE async fn task() -> u32 { hprintln!("foo1").ok(); // let a: u32 = bar::spawn().await; // hprintln!("foo2 {}", a).ok(); 5 } } #[task(resources = [syst, waker])] fn timer(cx: timer::Context<'static>, ticks: u32) { // BEGIN BOILERPLATE type F = impl Future + 'static; fn create(cx: timer::Context<'static>, ticks: u32) -> F { task(cx, ticks) } static mut TASK: Task = Task::new(); hprintln!("timer trampoline").ok(); unsafe { match TASK { Task::Idle | Task::Done(_) => { hprintln!("create task").ok(); TASK.spawn(|| create(mem::transmute(cx), ticks)); } _ => {} }; hprintln!("timer poll").ok(); TASK.poll(|| {}); match TASK { Task::Done(_) => { hprintln!("timer done").ok(); } _ => { hprintln!("running").ok(); } } } // END BOILERPLATE // for now assume this async task is done directly async fn task(mut cx: timer::Context<'static>, ticks: u32) { hprintln!("SysTick {:?}", ticks).ok(); // let q = Q {}; //q.await; // cx.resources.waker.lock(|w| *w = Some()) } // static mut Q: Q =Q // struct Q { // Init // } // impl Future for Q { // type Output = (); // fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // // you get the waker in cx.waker() // Poll::Pending // } // } } // This the actual RTIC task, binds to systic. #[task(binds = SysTick, resources = [waker], priority = 2)] fn systic(mut cx: systic::Context) { hprintln!("waker {}", cx.resources.waker.lock(|w| w.is_some())).ok(); } } //============= // 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 ()) { let f: fn() = mem::transmute(p); f(); } unsafe fn waker_drop(_: *const ()) { // nop } //============ // Task enum Task { Idle, Running(F), Done(F::Output), } impl Task { const fn new() -> Self { Self::Idle } fn spawn(&mut self, future: impl FnOnce() -> F) { *self = Task::Running(future()); } unsafe fn poll(&mut self, wake: fn()) { match self { Task::Idle => {} Task::Running(future) => { let future = Pin::new_unchecked(future); let waker_data: *const () = mem::transmute(wake); let waker = Waker::from_raw(RawWaker::new(waker_data, &WAKER_VTABLE)); let mut cx = Context::from_waker(&waker); match future.poll(&mut cx) { Poll::Ready(r) => *self = Task::Done(r), Poll::Pending => {} }; } Task::Done(_) => {} } } unsafe fn get_waker(&mut self, wake: fn()) -> Waker { match self { Task::Running(future) => { let future = Pin::new_unchecked(future); let waker_data: *const () = mem::transmute(wake); let waker = Waker::from_raw(RawWaker::new(waker_data, &WAKER_VTABLE)); waker } _ => unreachable!(), } } } //============= // Yield struct Yield { done: bool, } impl Future for Yield { type Output = u32; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { if self.done { Poll::Ready(73) } else { cx.waker().wake_by_ref(); self.done = true; Poll::Pending } } } fn please_yield() -> Yield { Yield { done: false } }