wpan/mac: further cleanup
This commit is contained in:
parent
cd592cb055
commit
582006c75c
4 changed files with 257 additions and 161 deletions
|
@ -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<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)
|
||||
}
|
||||
}
|
||||
|
|
124
embassy-stm32-wpan/src/mac/ioctl.rs
Normal file
124
embassy-stm32-wpan/src/mac/ioctl.rs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<PWR, SPI>,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue