wpan/mac: further cleanup

This commit is contained in:
xoviat 2023-07-16 09:32:54 -05:00
parent cd592cb055
commit 582006c75c
4 changed files with 257 additions and 161 deletions

View file

@ -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::helpers::to_u16;
use super::indications::{ use super::indications::{
AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication, AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication,
@ -25,6 +30,7 @@ pub trait ParseableMacEvent {
Self: Sized; Self: Sized;
} }
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MacEvent { pub enum MacEvent {
MlmeAssociateCnf(AssociateConfirm), 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<NoopRawMutex, Message, 2, 1, 1>;
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<EventMask>,
}
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)
}
}

View file

@ -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<IoctlStateInner>,
wakers: RefCell<Wakers>,
}
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");
}
}
}

View file

@ -4,6 +4,7 @@ pub mod control;
pub mod event; pub mod event;
mod helpers; mod helpers;
pub mod indications; pub mod indications;
mod ioctl;
mod macros; mod macros;
mod opcodes; mod opcodes;
pub mod responses; pub mod responses;
@ -14,11 +15,10 @@ use core::slice;
use embassy_net_driver_channel as ch; 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::mac::control::{Control, Error as ControlError};
pub use crate::runner::Runner; use crate::mac::event::Events;
pub use crate::structs::BssInfo; use crate::mac::ioctl::IoctlState;
pub use crate::mac::runner::Runner;
use crate::sub::mac::Mac; use crate::sub::mac::Mac;
const MTU: usize = 1514; const MTU: usize = 1514;
@ -76,15 +76,15 @@ impl PowerManagementMode {
pub type NetDriver<'a> = ch::Device<'a, MTU>; pub type NetDriver<'a> = ch::Device<'a, MTU>;
pub async fn new<'a, PWR, SPI>( pub async fn new<'a>(
state: &'a mut State, state: &'a mut State,
mac_subsystem: Mac, mac_subsystem: Mac,
firmware: &[u8], 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 (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
let state_ch = ch_runner.state_runner(); 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; runner.init(firmware).await;

View file

@ -2,29 +2,12 @@ use embassy_futures::select::{select3, Either3};
use embassy_net_driver_channel as ch; use embassy_net_driver_channel as ch;
use embassy_sync::pubsub::PubSubBehavior; 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; use crate::sub::mac::Mac;
#[cfg(feature = "firmware-logs")] pub struct Runner<'a> {
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> {
ch: ch::Runner<'a, MTU>, ch: ch::Runner<'a, MTU>,
mac: Mac, mac: Mac,
@ -34,32 +17,18 @@ pub struct Runner<'a, PWR, SPI> {
sdpcm_seq_max: u8, sdpcm_seq_max: u8,
events: &'a Events, events: &'a Events,
#[cfg(feature = "firmware-logs")]
log: LogState,
} }
impl<'a, PWR, SPI> Runner<'a, PWR, SPI> impl<'a> Runner<'a> {
where pub(crate) fn new(ch: ch::Runner<'a, MTU>, mac: Mac, ioctl_state: &'a IoctlState, events: &'a Events) -> Self {
PWR: OutputPin,
SPI: SpiBusCyw43,
{
pub(crate) fn new(
ch: ch::Runner<'a, MTU>,
bus: Bus<PWR, SPI>,
ioctl_state: &'a IoctlState,
events: &'a Events,
) -> Self {
Self { Self {
ch, ch,
bus, mac,
ioctl_state, ioctl_state,
ioctl_id: 0, ioctl_id: 0,
sdpcm_seq: 0, sdpcm_seq: 0,
sdpcm_seq_max: 1, sdpcm_seq_max: 1,
events, events,
#[cfg(feature = "firmware-logs")]
log: LogState::default(),
} }
} }
@ -72,60 +41,6 @@ where
debug!("wifi init done"); 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) -> ! { pub async fn run(mut self) -> ! {
let mut buf = [0; 512]; let mut buf = [0; 512];
loop { loop {
@ -424,66 +339,4 @@ where
self.bus.wlan_write(&buf[..total_len / 4]).await; 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
}
} }