diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/mac/event.rs index dfce21fe..ea326a33 100644 --- a/embassy-stm32-wpan/src/mac/event.rs +++ b/embassy-stm32-wpan/src/mac/event.rs @@ -1,3 +1,8 @@ +use core::cell::RefCell; + +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::pubsub::{PubSubChannel, Subscriber}; + use super::helpers::to_u16; use super::indications::{ AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication, @@ -25,6 +30,7 @@ pub trait ParseableMacEvent { Self: Sized; } +#[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum MacEvent { MlmeAssociateCnf(AssociateConfirm), @@ -92,3 +98,116 @@ impl TryFrom<&[u8]> for MacEvent { } } } + +// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient. +pub type EventQueue = PubSubChannel; +pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>; + +pub struct Events { + pub queue: EventQueue, + pub mask: SharedEventMask, +} + +impl Events { + pub fn new() -> Self { + Self { + queue: EventQueue::new(), + mask: SharedEventMask::default(), + } + } +} + +#[derive(Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Status { + pub event_type: MacEvent, + pub status: u32, +} + +#[derive(Clone, Copy)] +pub enum Payload { + None, + // BssInfo(BssInfo), +} + +#[derive(Clone)] + +pub struct Message { + pub header: Status, + pub payload: Payload, +} + +impl Message { + pub fn new(status: Status, payload: Payload) -> Self { + Self { + header: status, + payload, + } + } +} + +#[derive(Default)] +struct EventMask { + mask: [u32; Self::WORD_COUNT], +} + +impl EventMask { + const WORD_COUNT: usize = ((Event::LAST as u32 + (u32::BITS - 1)) / u32::BITS) as usize; + + fn enable(&mut self, event: MacEvent) { + let n = event as u32; + let word = n / u32::BITS; + let bit = n % u32::BITS; + + self.mask[word as usize] |= 1 << bit; + } + + fn disable(&mut self, event: MacEvent) { + let n = event as u32; + let word = n / u32::BITS; + let bit = n % u32::BITS; + + self.mask[word as usize] &= !(1 << bit); + } + + fn is_enabled(&self, event: MacEvent) -> bool { + let n = event as u32; + let word = n / u32::BITS; + let bit = n % u32::BITS; + + self.mask[word as usize] & (1 << bit) > 0 + } +} + +#[derive(Default)] + +pub struct SharedEventMask { + mask: RefCell, +} + +impl SharedEventMask { + pub fn enable(&self, events: &[MacEvent]) { + let mut mask = self.mask.borrow_mut(); + for event in events { + mask.enable(*event); + } + } + + #[allow(dead_code)] + pub fn disable(&self, events: &[MacEvent]) { + let mut mask = self.mask.borrow_mut(); + for event in events { + mask.disable(*event); + } + } + + pub fn disable_all(&self) { + let mut mask = self.mask.borrow_mut(); + mask.mask = Default::default(); + } + + pub fn is_enabled(&self, event: MacEvent) -> bool { + let mask = self.mask.borrow(); + mask.is_enabled(event) + } +} diff --git a/embassy-stm32-wpan/src/mac/ioctl.rs b/embassy-stm32-wpan/src/mac/ioctl.rs new file mode 100644 index 00000000..0fe55cd6 --- /dev/null +++ b/embassy-stm32-wpan/src/mac/ioctl.rs @@ -0,0 +1,124 @@ +use core::cell::{Cell, RefCell}; +use core::future::poll_fn; +use core::task::{Poll, Waker}; + +use embassy_sync::waitqueue::WakerRegistration; + +#[derive(Clone, Copy)] +pub enum IoctlType { + Get = 0, + Set = 2, +} + +#[derive(Clone, Copy)] +pub struct PendingIoctl { + pub buf: *mut [u8], + pub kind: IoctlType, + pub cmd: u32, + pub iface: u32, +} + +#[derive(Clone, Copy)] +enum IoctlStateInner { + Pending(PendingIoctl), + Sent { buf: *mut [u8] }, + Done { resp_len: usize }, +} + +struct Wakers { + control: WakerRegistration, + runner: WakerRegistration, +} + +impl Default for Wakers { + fn default() -> Self { + Self { + control: WakerRegistration::new(), + runner: WakerRegistration::new(), + } + } +} + +pub struct IoctlState { + state: Cell, + wakers: RefCell, +} + +impl IoctlState { + pub fn new() -> Self { + Self { + state: Cell::new(IoctlStateInner::Done { resp_len: 0 }), + wakers: Default::default(), + } + } + + fn wake_control(&self) { + self.wakers.borrow_mut().control.wake(); + } + + fn register_control(&self, waker: &Waker) { + self.wakers.borrow_mut().control.register(waker); + } + + fn wake_runner(&self) { + self.wakers.borrow_mut().runner.wake(); + } + + fn register_runner(&self, waker: &Waker) { + self.wakers.borrow_mut().runner.register(waker); + } + + pub async fn wait_complete(&self) -> usize { + poll_fn(|cx| { + if let IoctlStateInner::Done { resp_len } = self.state.get() { + Poll::Ready(resp_len) + } else { + self.register_control(cx.waker()); + Poll::Pending + } + }) + .await + } + + pub async fn wait_pending(&self) -> PendingIoctl { + let pending = poll_fn(|cx| { + if let IoctlStateInner::Pending(pending) = self.state.get() { + Poll::Ready(pending) + } else { + self.register_runner(cx.waker()); + Poll::Pending + } + }) + .await; + + self.state.set(IoctlStateInner::Sent { buf: pending.buf }); + pending + } + + pub fn cancel_ioctl(&self) { + self.state.set(IoctlStateInner::Done { resp_len: 0 }); + } + + pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { + self.state + .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface })); + self.wake_runner(); + self.wait_complete().await + } + + pub fn ioctl_done(&self, response: &[u8]) { + if let IoctlStateInner::Sent { buf } = self.state.get() { + // trace!("IOCTL Response: {:02x}", Bytes(response)); + + // TODO fix this + (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); + + self.state.set(IoctlStateInner::Done { + resp_len: response.len(), + }); + self.wake_control(); + } else { + warn!("IOCTL Response but no pending Ioctl"); + } + } +} diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs index e27f0ba7..67dc429e 100644 --- a/embassy-stm32-wpan/src/mac/mod.rs +++ b/embassy-stm32-wpan/src/mac/mod.rs @@ -4,6 +4,7 @@ pub mod control; pub mod event; mod helpers; pub mod indications; +mod ioctl; mod macros; mod opcodes; pub mod responses; @@ -14,11 +15,10 @@ use core::slice; use embassy_net_driver_channel as ch; -use crate::bus::Bus; -pub use crate::bus::SpiBusCyw43; pub use crate::mac::control::{Control, Error as ControlError}; -pub use crate::runner::Runner; -pub use crate::structs::BssInfo; +use crate::mac::event::Events; +use crate::mac::ioctl::IoctlState; +pub use crate::mac::runner::Runner; use crate::sub::mac::Mac; const MTU: usize = 1514; @@ -76,15 +76,15 @@ impl PowerManagementMode { pub type NetDriver<'a> = ch::Device<'a, MTU>; -pub async fn new<'a, PWR, SPI>( +pub async fn new<'a>( state: &'a mut State, mac_subsystem: Mac, firmware: &[u8], -) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) { +) -> (NetDriver<'a>, Control<'a>, Runner<'a>) { let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); let state_ch = ch_runner.state_runner(); - let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events); + let mut runner = Runner::new(ch_runner, mac_subsystem, &state.ioctl_state, &state.events); runner.init(firmware).await; diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index 7f0bbd67..fbb7cb74 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -2,29 +2,12 @@ use embassy_futures::select::{select3, Either3}; use embassy_net_driver_channel as ch; use embassy_sync::pubsub::PubSubBehavior; +use crate::mac::event::Events; +use crate::mac::ioctl::{IoctlState, PendingIoctl}; +use crate::mac::MTU; use crate::sub::mac::Mac; -#[cfg(feature = "firmware-logs")] -struct LogState { - addr: u32, - last_idx: usize, - buf: [u8; 256], - buf_count: usize, -} - -#[cfg(feature = "firmware-logs")] -impl Default for LogState { - fn default() -> Self { - Self { - addr: Default::default(), - last_idx: Default::default(), - buf: [0; 256], - buf_count: Default::default(), - } - } -} - -pub struct Runner<'a, PWR, SPI> { +pub struct Runner<'a> { ch: ch::Runner<'a, MTU>, mac: Mac, @@ -34,32 +17,18 @@ pub struct Runner<'a, PWR, SPI> { sdpcm_seq_max: u8, events: &'a Events, - - #[cfg(feature = "firmware-logs")] - log: LogState, } -impl<'a, PWR, SPI> Runner<'a, PWR, SPI> -where - PWR: OutputPin, - SPI: SpiBusCyw43, -{ - pub(crate) fn new( - ch: ch::Runner<'a, MTU>, - bus: Bus, - ioctl_state: &'a IoctlState, - events: &'a Events, - ) -> Self { +impl<'a> Runner<'a> { + pub(crate) fn new(ch: ch::Runner<'a, MTU>, mac: Mac, ioctl_state: &'a IoctlState, events: &'a Events) -> Self { Self { ch, - bus, + mac, ioctl_state, ioctl_id: 0, sdpcm_seq: 0, sdpcm_seq_max: 1, events, - #[cfg(feature = "firmware-logs")] - log: LogState::default(), } } @@ -72,60 +41,6 @@ where debug!("wifi init done"); } - #[cfg(feature = "firmware-logs")] - async fn log_init(&mut self) { - // Initialize shared memory for logging. - - let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size; - let shared_addr = self.bus.bp_read32(addr).await; - debug!("shared_addr {:08x}", shared_addr); - - let mut shared = [0; SharedMemData::SIZE]; - self.bus.bp_read(shared_addr, &mut shared).await; - let shared = SharedMemData::from_bytes(&shared); - - self.log.addr = shared.console_addr + 8; - } - - #[cfg(feature = "firmware-logs")] - async fn log_read(&mut self) { - // Read log struct - let mut log = [0; SharedMemLog::SIZE]; - self.bus.bp_read(self.log.addr, &mut log).await; - let log = SharedMemLog::from_bytes(&log); - - let idx = log.idx as usize; - - // If pointer hasn't moved, no need to do anything. - if idx == self.log.last_idx { - return; - } - - // Read entire buf for now. We could read only what we need, but then we - // run into annoying alignment issues in `bp_read`. - let mut buf = [0; 0x400]; - self.bus.bp_read(log.buf, &mut buf).await; - - while self.log.last_idx != idx as usize { - let b = buf[self.log.last_idx]; - if b == b'\r' || b == b'\n' { - if self.log.buf_count != 0 { - let s = unsafe { core::str::from_utf8_unchecked(&self.log.buf[..self.log.buf_count]) }; - debug!("LOGS: {}", s); - self.log.buf_count = 0; - } - } else if self.log.buf_count < self.log.buf.len() { - self.log.buf[self.log.buf_count] = b; - self.log.buf_count += 1; - } - - self.log.last_idx += 1; - if self.log.last_idx == 0x400 { - self.log.last_idx = 0; - } - } - } - pub async fn run(mut self) -> ! { let mut buf = [0; 512]; loop { @@ -424,66 +339,4 @@ where self.bus.wlan_write(&buf[..total_len / 4]).await; } - - async fn core_disable(&mut self, core: Core) { - let base = core.base_addr(); - - // Dummy read? - let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; - - // Check it isn't already reset - let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; - if r & AI_RESETCTRL_BIT_RESET != 0 { - return; - } - - self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await; - let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; - - block_for(Duration::from_millis(1)); - - self.bus - .bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET) - .await; - let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; - } - - async fn core_reset(&mut self, core: Core) { - self.core_disable(core).await; - - let base = core.base_addr(); - self.bus - .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) - .await; - let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; - - self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await; - - Timer::after(Duration::from_millis(1)).await; - - self.bus - .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN) - .await; - let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; - - Timer::after(Duration::from_millis(1)).await; - } - - async fn core_is_up(&mut self, core: Core) -> bool { - let base = core.base_addr(); - - let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; - if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN { - debug!("core_is_up: returning false due to bad ioctrl {:02x}", io); - return false; - } - - let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; - if r & (AI_RESETCTRL_BIT_RESET) != 0 { - debug!("core_is_up: returning false due to bad resetctrl {:02x}", r); - return false; - } - - true - } }