use core::cell::RefCell; use core::future::{Future, poll_fn}; use core::task::Poll; use embassy_sync::waitqueue::WakerRegistration; use crate::fmt::Bytes; #[derive(Clone, Copy)] pub struct PendingIoctl { pub buf: *mut [u8], pub req_len: usize, } #[derive(Clone, Copy)] enum IoctlState { Pending(PendingIoctl), Sent { buf: *mut [u8] }, Done { resp_len: usize }, } pub struct Shared(RefCell); struct SharedInner { ioctl: IoctlState, state: ControlState, control_waker: WakerRegistration, runner_waker: WakerRegistration, } #[derive(Clone, Copy)] pub(crate) enum ControlState { Init, Reboot, Ready, } impl Shared { pub fn new() -> Self { Self(RefCell::new(SharedInner { ioctl: IoctlState::Done { resp_len: 0 }, state: ControlState::Init, control_waker: WakerRegistration::new(), runner_waker: WakerRegistration::new(), })) } pub fn ioctl_wait_complete(&self) -> impl Future + '_ { poll_fn(|cx| { let mut this = self.0.borrow_mut(); if let IoctlState::Done { resp_len } = this.ioctl { Poll::Ready(resp_len) } else { this.control_waker.register(cx.waker()); Poll::Pending } }) } pub async fn ioctl_wait_pending(&self) -> PendingIoctl { let pending = poll_fn(|cx| { let mut this = self.0.borrow_mut(); if let IoctlState::Pending(pending) = this.ioctl { Poll::Ready(pending) } else { this.runner_waker.register(cx.waker()); Poll::Pending } }) .await; self.0.borrow_mut().ioctl = IoctlState::Sent { buf: pending.buf }; pending } pub fn ioctl_cancel(&self) { self.0.borrow_mut().ioctl = IoctlState::Done { resp_len: 0 }; } pub async fn ioctl(&self, buf: &mut [u8], req_len: usize) -> usize { trace!("ioctl req bytes: {:02x}", Bytes(&buf[..req_len])); { let mut this = self.0.borrow_mut(); this.ioctl = IoctlState::Pending(PendingIoctl { buf, req_len }); this.runner_waker.wake(); } self.ioctl_wait_complete().await } pub fn ioctl_done(&self, response: &[u8]) { let mut this = self.0.borrow_mut(); if let IoctlState::Sent { buf } = this.ioctl { trace!("ioctl resp bytes: {:02x}", Bytes(response)); // TODO fix this (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); this.ioctl = IoctlState::Done { resp_len: response.len(), }; this.control_waker.wake(); } else { warn!("IOCTL Response but no pending Ioctl"); } } // ota pub fn ota_done(&self) { let mut this = self.0.borrow_mut(); this.state = ControlState::Reboot; } // // // // // // // // // // // // // // // // // // // // // // check if ota is in progress pub(crate) fn state(&self) -> ControlState { let this = self.0.borrow(); this.state } pub fn init_done(&self) { let mut this = self.0.borrow_mut(); this.state = ControlState::Ready; this.control_waker.wake(); } pub fn init_wait(&self) -> impl Future + '_ { poll_fn(|cx| { let mut this = self.0.borrow_mut(); if let ControlState::Ready = this.state { Poll::Ready(()) } else { this.control_waker.register(cx.waker()); Poll::Pending } }) } }