From 0b63af33135784c1410dc8667cfefbaa538a1f04 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 15 Jul 2023 19:02:04 -0500 Subject: [PATCH 01/15] wpan: prepare net impl. --- embassy-net-driver/src/lib.rs | 3 +++ embassy-net/Cargo.toml | 1 + embassy-net/src/device.rs | 2 ++ embassy-net/src/lib.rs | 13 ++++++++++++- embassy-stm32-wpan/Cargo.toml | 3 ++- examples/stm32wb/Cargo.toml | 3 ++- 6 files changed, 22 insertions(+), 3 deletions(-) diff --git a/embassy-net-driver/src/lib.rs b/embassy-net-driver/src/lib.rs index 4149bf4a..09def20c 100644 --- a/embassy-net-driver/src/lib.rs +++ b/embassy-net-driver/src/lib.rs @@ -164,6 +164,9 @@ pub enum Medium { /// /// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode. Ip, + + /// IEEE 802_15_4 medium + Ieee802154, } impl Default for Medium { diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 6dc429dd..9b6a11c1 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -37,6 +37,7 @@ proto-ipv4 = ["smoltcp/proto-ipv4"] proto-ipv6 = ["smoltcp/proto-ipv6"] medium-ethernet = ["smoltcp/medium-ethernet"] medium-ip = ["smoltcp/medium-ip"] +medium-ieee802154 = ["smoltcp/medium-ieee802154"] igmp = ["smoltcp/proto-igmp"] [dependencies] diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index 4513c86d..d29ab897 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -51,6 +51,8 @@ where Medium::Ethernet => phy::Medium::Ethernet, #[cfg(feature = "medium-ip")] Medium::Ip => phy::Medium::Ip, + #[cfg(feature = "medium-ieee802154")] + Medium::Ieee802154 => phy::Medium::Ieee802154, #[allow(unreachable_patterns)] _ => panic!( "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.", diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 0d0a986f..ad98d7f6 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -24,9 +24,11 @@ use embassy_net_driver::{Driver, LinkState, Medium}; use embassy_sync::waitqueue::WakerRegistration; use embassy_time::{Instant, Timer}; use futures::pin_mut; +#[allow(unused_imports)] use heapless::Vec; #[cfg(feature = "igmp")] pub use smoltcp::iface::MulticastError; +#[allow(unused_imports)] use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage}; #[cfg(feature = "dhcpv4")] use smoltcp::socket::dhcpv4::{self, RetryConfig}; @@ -34,6 +36,8 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig}; pub use smoltcp::wire::IpListenEndpoint; #[cfg(feature = "medium-ethernet")] pub use smoltcp::wire::{EthernetAddress, HardwareAddress}; +#[cfg(feature = "medium-ieee802154")] +pub use smoltcp::wire::{HardwareAddress, Ieee802154Address}; pub use smoltcp::wire::{IpAddress, IpCidr, IpEndpoint}; #[cfg(feature = "proto-ipv4")] pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; @@ -232,7 +236,7 @@ impl Stack { resources: &'static mut StackResources, random_seed: u64, ) -> Self { - #[cfg(feature = "medium-ethernet")] + #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] let medium = device.capabilities().medium; let hardware_addr = match medium { @@ -240,6 +244,8 @@ impl Stack { Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress(device.ethernet_address())), #[cfg(feature = "medium-ip")] Medium::Ip => HardwareAddress::Ip, + #[cfg(feature = "medium-ieee802154")] + Medium::Ieee802154 => HardwareAddress::Ieee802154(Ieee802154Address::Absent), #[allow(unreachable_patterns)] _ => panic!( "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.", @@ -262,6 +268,7 @@ impl Stack { let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN; + #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))] let mut socket = SocketStack { sockets, iface, @@ -269,6 +276,7 @@ impl Stack { next_local_port, }; + #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))] let mut inner = Inner { device, link_up: false, @@ -287,6 +295,9 @@ impl Stack { dns_waker: WakerRegistration::new(), }; + #[cfg(feature = "medium-ieee802154")] + let _ = config; + #[cfg(feature = "proto-ipv4")] match config.ipv4 { ConfigV4::Static(config) => { diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 868bffe7..082d00f1 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -17,6 +17,7 @@ embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" } embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel", optional=true } defmt = { version = "0.3", optional = true } cortex-m = "0.7.6" @@ -32,7 +33,7 @@ bitflags = { version = "2.3.3", optional = true } defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"] ble = ["dep:stm32wb-hci"] -mac = ["dep:bitflags"] +mac = ["dep:bitflags", "dep:embassy-net-driver-channel"] stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index becf2d3f..8585b99f 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -10,6 +10,7 @@ embassy-executor = { version = "0.2.0", path = "../../embassy-executor", feature embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "medium-ieee802154", "nightly"], optional=true } defmt = "0.3" defmt-rtt = "0.4" @@ -24,7 +25,7 @@ heapless = { version = "0.7.5", default-features = false } [features] default = ["ble", "mac"] -mac = ["embassy-stm32-wpan/mac"] +mac = ["embassy-stm32-wpan/mac", "dep:embassy-net"] ble = ["embassy-stm32-wpan/ble"] [[bin]] From cd592cb0550146158ea6f9d90ba8afe9e1b06a92 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 15 Jul 2023 19:15:01 -0500 Subject: [PATCH 02/15] wpan: add files from cyw43 --- embassy-stm32-wpan/src/lib.rs | 3 +- embassy-stm32-wpan/src/mac/control.rs | 454 ++++++++++++++++++++++++ embassy-stm32-wpan/src/mac/driver.rs | 102 ++++++ embassy-stm32-wpan/src/mac/mod.rs | 92 +++++ embassy-stm32-wpan/src/mac/runner.rs | 489 ++++++++++++++++++++++++++ 5 files changed, 1139 insertions(+), 1 deletion(-) create mode 100644 embassy-stm32-wpan/src/mac/control.rs create mode 100644 embassy-stm32-wpan/src/mac/driver.rs create mode 100644 embassy-stm32-wpan/src/mac/runner.rs diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 57f0dc4f..6836d7a8 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] -#![cfg_attr(feature = "ble", feature(async_fn_in_trait))] +#![cfg_attr(any(feature = "ble", feature = "mac"), feature(async_fn_in_trait))] +#![cfg_attr(feature = "mac", feature(type_alias_impl_trait, concat_bytes))] // This must go FIRST so that all the other modules see its macros. pub mod fmt; diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs new file mode 100644 index 00000000..c67614dd --- /dev/null +++ b/embassy-stm32-wpan/src/mac/control.rs @@ -0,0 +1,454 @@ +use core::cmp::{max, min}; + +use ch::driver::LinkState; +use embassy_net_driver_channel as ch; +use embassy_time::{Duration, Timer}; + +pub use crate::bus::SpiBusCyw43; +use crate::consts::*; +use crate::events::{Event, EventSubscriber, Events}; +use crate::fmt::Bytes; +use crate::ioctl::{IoctlState, IoctlType}; +use crate::structs::*; +use crate::{countries, events, PowerManagementMode}; + +#[derive(Debug)] +pub struct Error { + pub status: u32, +} + +pub struct Control<'a> { + state_ch: ch::StateRunner<'a>, + events: &'a Events, + ioctl_state: &'a IoctlState, +} + +impl<'a> Control<'a> { + pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { + Self { + state_ch, + events: event_sub, + ioctl_state, + } + } + + pub async fn init(&mut self, clm: &[u8]) { + const CHUNK_SIZE: usize = 1024; + + debug!("Downloading CLM..."); + + let mut offs = 0; + for chunk in clm.chunks(CHUNK_SIZE) { + let mut flag = DOWNLOAD_FLAG_HANDLER_VER; + if offs == 0 { + flag |= DOWNLOAD_FLAG_BEGIN; + } + offs += chunk.len(); + if offs == clm.len() { + flag |= DOWNLOAD_FLAG_END; + } + + let header = DownloadHeader { + flag, + dload_type: DOWNLOAD_TYPE_CLM, + len: chunk.len() as _, + crc: 0, + }; + let mut buf = [0; 8 + 12 + CHUNK_SIZE]; + buf[0..8].copy_from_slice(b"clmload\x00"); + buf[8..20].copy_from_slice(&header.to_bytes()); + buf[20..][..chunk.len()].copy_from_slice(&chunk); + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()]) + .await; + } + + // check clmload ok + assert_eq!(self.get_iovar_u32("clmload_status").await, 0); + + debug!("Configuring misc stuff..."); + + // Disable tx gloming which transfers multiple packets in one request. + // 'glom' is short for "conglomerate" which means "gather together into + // a compact mass". + self.set_iovar_u32("bus:txglom", 0).await; + self.set_iovar_u32("apsta", 1).await; + + // read MAC addr. + let mut mac_addr = [0; 6]; + assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6); + debug!("mac addr: {:02x}", Bytes(&mac_addr)); + + let country = countries::WORLD_WIDE_XX; + let country_info = CountryInfo { + country_abbrev: [country.code[0], country.code[1], 0, 0], + country_code: [country.code[0], country.code[1], 0, 0], + rev: if country.rev == 0 { -1 } else { country.rev as _ }, + }; + self.set_iovar("country", &country_info.to_bytes()).await; + + // set country takes some time, next ioctls fail if we don't wait. + Timer::after(Duration::from_millis(100)).await; + + // Set antenna to chip antenna + self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await; + + self.set_iovar_u32("bus:txglom", 0).await; + Timer::after(Duration::from_millis(100)).await; + //self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...?? + //Timer::after(Duration::from_millis(100)).await; + self.set_iovar_u32("ampdu_ba_wsize", 8).await; + Timer::after(Duration::from_millis(100)).await; + self.set_iovar_u32("ampdu_mpdu", 4).await; + Timer::after(Duration::from_millis(100)).await; + //self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes + + //Timer::after(Duration::from_millis(100)).await; + + // evts + let mut evts = EventMask { + iface: 0, + events: [0xFF; 24], + }; + + // Disable spammy uninteresting events. + evts.unset(Event::RADIO); + evts.unset(Event::IF); + evts.unset(Event::PROBREQ_MSG); + evts.unset(Event::PROBREQ_MSG_RX); + evts.unset(Event::PROBRESP_MSG); + evts.unset(Event::PROBRESP_MSG); + evts.unset(Event::ROAM); + + self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await; + + Timer::after(Duration::from_millis(100)).await; + + // set wifi up + self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; + + Timer::after(Duration::from_millis(100)).await; + + self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto + self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any + + Timer::after(Duration::from_millis(100)).await; + + self.state_ch.set_ethernet_address(mac_addr); + + debug!("INIT DONE"); + } + + pub async fn set_power_management(&mut self, mode: PowerManagementMode) { + // power save mode + let mode_num = mode.mode(); + if mode_num == 2 { + self.set_iovar_u32("pm2_sleep_ret", mode.sleep_ret_ms() as u32).await; + self.set_iovar_u32("bcn_li_bcn", mode.beacon_period() as u32).await; + self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await; + self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await; + } + self.ioctl_set_u32(86, 0, mode_num).await; + } + + pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { + self.set_iovar_u32("ampdu_ba_wsize", 8).await; + + self.ioctl_set_u32(134, 0, 0).await; // wsec = open + self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; + self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 + self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0) + + let mut i = SsidInfo { + len: ssid.len() as _, + ssid: [0; 32], + }; + i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); + + self.wait_for_join(i).await + } + + pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { + self.set_iovar_u32("ampdu_ba_wsize", 8).await; + + self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2 + self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; + self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; + self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; + + Timer::after(Duration::from_millis(100)).await; + + let mut pfi = PassphraseInfo { + len: passphrase.len() as _, + flags: 1, + passphrase: [0; 64], + }; + pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes()); + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) + .await; // WLC_SET_WSEC_PMK + + self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 + self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open) + self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth + + let mut i = SsidInfo { + len: ssid.len() as _, + ssid: [0; 32], + }; + i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); + + self.wait_for_join(i).await + } + + async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { + self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); + let mut subscriber = self.events.queue.subscriber().unwrap(); + // the actual join operation starts here + // we make sure to enable events before so we don't miss any + + // set_ssid + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes()) + .await; + + // to complete the join, we wait for a SET_SSID event + // we also save the AUTH status for the user, it may be interesting + let mut auth_status = 0; + let status = loop { + let msg = subscriber.next_message_pure().await; + if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS { + auth_status = msg.header.status; + } else if msg.header.event_type == Event::SET_SSID { + // join operation ends with SET_SSID event + break msg.header.status; + } + }; + + self.events.mask.disable_all(); + if status == EStatus::SUCCESS { + // successful join + self.state_ch.set_link_state(LinkState::Up); + debug!("JOINED"); + Ok(()) + } else { + warn!("JOIN failed with status={} auth={}", status, auth_status); + Err(Error { status }) + } + } + + pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) { + assert!(gpio_n < 3); + self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 }) + .await + } + + pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) { + self.start_ap(ssid, "", Security::OPEN, channel).await; + } + + pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) { + self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await; + } + + async fn start_ap(&mut self, ssid: &str, passphrase: &str, security: Security, channel: u8) { + if security != Security::OPEN + && (passphrase.as_bytes().len() < MIN_PSK_LEN || passphrase.as_bytes().len() > MAX_PSK_LEN) + { + panic!("Passphrase is too short or too long"); + } + + // Temporarily set wifi down + self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; + + // Turn off APSTA mode + self.set_iovar_u32("apsta", 0).await; + + // Set wifi up again + self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; + + // Turn on AP mode + self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await; + + // Set SSID + let mut i = SsidInfoWithIndex { + index: 0, + ssid_info: SsidInfo { + len: ssid.as_bytes().len() as _, + ssid: [0; 32], + }, + }; + i.ssid_info.ssid[..ssid.as_bytes().len()].copy_from_slice(ssid.as_bytes()); + self.set_iovar("bsscfg:ssid", &i.to_bytes()).await; + + // Set channel number + self.ioctl_set_u32(IOCTL_CMD_SET_CHANNEL, 0, channel as u32).await; + + // Set security + self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await; + + if security != Security::OPEN { + self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK + + Timer::after(Duration::from_millis(100)).await; + + // Set passphrase + let mut pfi = PassphraseInfo { + len: passphrase.as_bytes().len() as _, + flags: 1, // WSEC_PASSPHRASE + passphrase: [0; 64], + }; + pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) + .await; + } + + // Change mutlicast rate from 1 Mbps to 11 Mbps + self.set_iovar_u32("2g_mrate", 11000000 / 500000).await; + + // Start AP + self.set_iovar_u32x2("bss", 0, 1).await; // bss = BSS_UP + } + + async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) { + let mut buf = [0; 8]; + buf[0..4].copy_from_slice(&val1.to_le_bytes()); + buf[4..8].copy_from_slice(&val2.to_le_bytes()); + self.set_iovar(name, &buf).await + } + + async fn set_iovar_u32(&mut self, name: &str, val: u32) { + self.set_iovar(name, &val.to_le_bytes()).await + } + + async fn get_iovar_u32(&mut self, name: &str) -> u32 { + let mut buf = [0; 4]; + let len = self.get_iovar(name, &mut buf).await; + assert_eq!(len, 4); + u32::from_le_bytes(buf) + } + + async fn set_iovar(&mut self, name: &str, val: &[u8]) { + self.set_iovar_v::<64>(name, val).await + } + + async fn set_iovar_v(&mut self, name: &str, val: &[u8]) { + debug!("set {} = {:02x}", name, Bytes(val)); + + let mut buf = [0; BUFSIZE]; + buf[..name.len()].copy_from_slice(name.as_bytes()); + buf[name.len()] = 0; + buf[name.len() + 1..][..val.len()].copy_from_slice(val); + + let total_len = name.len() + 1 + val.len(); + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len]) + .await; + } + + // TODO this is not really working, it always returns all zeros. + async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize { + debug!("get {}", name); + + let mut buf = [0; 64]; + buf[..name.len()].copy_from_slice(name.as_bytes()); + buf[name.len()] = 0; + + let total_len = max(name.len() + 1, res.len()); + let res_len = self + .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len]) + .await; + + let out_len = min(res.len(), res_len); + res[..out_len].copy_from_slice(&buf[..out_len]); + out_len + } + + async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) { + let mut buf = val.to_le_bytes(); + self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await; + } + + async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { + struct CancelOnDrop<'a>(&'a IoctlState); + + impl CancelOnDrop<'_> { + fn defuse(self) { + core::mem::forget(self); + } + } + + impl Drop for CancelOnDrop<'_> { + fn drop(&mut self) { + self.0.cancel_ioctl(); + } + } + + let ioctl = CancelOnDrop(self.ioctl_state); + let resp_len = ioctl.0.do_ioctl(kind, cmd, iface, buf).await; + ioctl.defuse(); + + resp_len + } + + /// Start a wifi scan + /// + /// Returns a `Stream` of networks found by the device + /// + /// # Note + /// Device events are currently implemented using a bounded queue. + /// To not miss any events, you should make sure to always await the stream. + pub async fn scan(&mut self) -> Scanner<'_> { + const SCANTYPE_PASSIVE: u8 = 1; + + let scan_params = ScanParams { + version: 1, + action: 1, + sync_id: 1, + ssid_len: 0, + ssid: [0; 32], + bssid: [0xff; 6], + bss_type: 2, + scan_type: SCANTYPE_PASSIVE, + nprobes: !0, + active_time: !0, + passive_time: !0, + home_time: !0, + channel_num: 0, + channel_list: [0; 1], + }; + + self.events.mask.enable(&[Event::ESCAN_RESULT]); + let subscriber = self.events.queue.subscriber().unwrap(); + self.set_iovar_v::<256>("escan", &scan_params.to_bytes()).await; + + Scanner { + subscriber, + events: &self.events, + } + } +} + +pub struct Scanner<'a> { + subscriber: EventSubscriber<'a>, + events: &'a Events, +} + +impl Scanner<'_> { + /// wait for the next found network + pub async fn next(&mut self) -> Option { + let event = self.subscriber.next_message_pure().await; + if event.header.status != EStatus::PARTIAL { + self.events.mask.disable_all(); + return None; + } + + if let events::Payload::BssInfo(bss) = event.payload { + Some(bss) + } else { + None + } + } +} + +impl Drop for Scanner<'_> { + fn drop(&mut self) { + self.events.mask.disable_all(); + } +} diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs new file mode 100644 index 00000000..3171d61f --- /dev/null +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -0,0 +1,102 @@ +#![no_std] +#![no_main] +#![allow(incomplete_features)] +#![feature(async_fn_in_trait, type_alias_impl_trait, concat_bytes)] +#![deny(unused_must_use)] + +use core::slice; + +use embassy_net_driver_channel as ch; +use embedded_hal_1::digital::OutputPin; +use events::Events; +use ioctl::IoctlState; + +use crate::bus::Bus; +pub use crate::bus::SpiBusCyw43; +pub use crate::control::{Control, Error as ControlError}; +pub use crate::runner::Runner; +pub use crate::structs::BssInfo; + +const MTU: usize = 1514; + +pub struct State { + ioctl_state: IoctlState, + ch: ch::State, + events: Events, +} + +impl State { + pub fn new() -> Self { + Self { + ioctl_state: IoctlState::new(), + ch: ch::State::new(), + events: Events::new(), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PowerManagementMode { + /// Custom, officially unsupported mode. Use at your own risk. + /// All power-saving features set to their max at only a marginal decrease in power consumption + /// as oppposed to `Aggressive`. + SuperSave, + + /// Aggressive power saving mode. + Aggressive, + + /// The default mode. + PowerSave, + + /// Performance is prefered over power consumption but still some power is conserved as opposed to + /// `None`. + Performance, + + /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of + /// a much lower throughput. + ThroughputThrottling, + + /// No power management is configured. This consumes the most power. + None, +} + +impl Default for PowerManagementMode { + fn default() -> Self { + Self::PowerSave + } +} + +impl PowerManagementMode { + // TODO +} + +pub type NetDriver<'a> = ch::Device<'a, MTU>; + +pub async fn new<'a, PWR, SPI>( + state: &'a mut State, + pwr: PWR, + spi: SPI, + firmware: &[u8], +) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) +where + PWR: OutputPin, + SPI: SpiBusCyw43, +{ + 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); + + runner.init(firmware).await; + + ( + device, + Control::new(state_ch, &state.events, &state.ioctl_state), + runner, + ) +} + +fn slice8_mut(x: &mut [u32]) -> &mut [u8] { + let len = x.len() * 4; + unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } +} diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs index 1af8fe6b..e27f0ba7 100644 --- a/embassy-stm32-wpan/src/mac/mod.rs +++ b/embassy-stm32-wpan/src/mac/mod.rs @@ -1,9 +1,101 @@ pub mod commands; mod consts; +pub mod control; pub mod event; mod helpers; pub mod indications; mod macros; mod opcodes; pub mod responses; +pub mod runner; pub mod typedefs; + +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::sub::mac::Mac; + +const MTU: usize = 1514; + +pub struct State { + ioctl_state: IoctlState, + ch: ch::State, + events: Events, +} + +impl State { + pub fn new() -> Self { + Self { + ioctl_state: IoctlState::new(), + ch: ch::State::new(), + events: Events::new(), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PowerManagementMode { + /// Custom, officially unsupported mode. Use at your own risk. + /// All power-saving features set to their max at only a marginal decrease in power consumption + /// as oppposed to `Aggressive`. + SuperSave, + + /// Aggressive power saving mode. + Aggressive, + + /// The default mode. + PowerSave, + + /// Performance is prefered over power consumption but still some power is conserved as opposed to + /// `None`. + Performance, + + /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of + /// a much lower throughput. + ThroughputThrottling, + + /// No power management is configured. This consumes the most power. + None, +} + +impl Default for PowerManagementMode { + fn default() -> Self { + Self::PowerSave + } +} + +impl PowerManagementMode { + // TODO +} + +pub type NetDriver<'a> = ch::Device<'a, MTU>; + +pub async fn new<'a, PWR, SPI>( + state: &'a mut State, + mac_subsystem: Mac, + firmware: &[u8], +) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) { + 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); + + runner.init(firmware).await; + + ( + device, + Control::new(state_ch, &state.events, &state.ioctl_state), + runner, + ) +} + +fn slice8_mut(x: &mut [u32]) -> &mut [u8] { + let len = x.len() * 4; + unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } +} diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs new file mode 100644 index 00000000..7f0bbd67 --- /dev/null +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -0,0 +1,489 @@ +use embassy_futures::select::{select3, Either3}; +use embassy_net_driver_channel as ch; +use embassy_sync::pubsub::PubSubBehavior; + +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> { + ch: ch::Runner<'a, MTU>, + mac: Mac, + + ioctl_state: &'a IoctlState, + ioctl_id: u16, + sdpcm_seq: u8, + 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 { + Self { + ch, + bus, + ioctl_state, + ioctl_id: 0, + sdpcm_seq: 0, + sdpcm_seq_max: 1, + events, + #[cfg(feature = "firmware-logs")] + log: LogState::default(), + } + } + + pub(crate) async fn init(&mut self, firmware: &[u8]) { + self.bus.init().await; + + #[cfg(feature = "firmware-logs")] + self.log_init().await; + + 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 { + #[cfg(feature = "firmware-logs")] + self.log_read().await; + + if self.has_credit() { + let ioctl = self.ioctl_state.wait_pending(); + let tx = self.ch.tx_buf(); + let ev = self.bus.wait_for_event(); + + match select3(ioctl, tx, ev).await { + Either3::First(PendingIoctl { + buf: iobuf, + kind, + cmd, + iface, + }) => { + self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await; + self.check_status(&mut buf).await; + } + Either3::Second(packet) => { + trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); + + let mut buf = [0; 512]; + let buf8 = slice8_mut(&mut buf); + + // There MUST be 2 bytes of padding between the SDPCM and BDC headers. + // And ONLY for data packets! + // No idea why, but the firmware will append two zero bytes to the tx'd packets + // otherwise. If the packet is exactly 1514 bytes (the max MTU), this makes it + // be oversized and get dropped. + // WHD adds it here https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/include/whd_sdpcm.h#L90 + // and adds it to the header size her https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/whd_sdpcm.c#L597 + // ¯\_(ツ)_/¯ + const PADDING_SIZE: usize = 2; + let total_len = SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE + packet.len(); + + let seq = self.sdpcm_seq; + self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); + + let sdpcm_header = SdpcmHeader { + len: total_len as u16, // TODO does this len need to be rounded up to u32? + len_inv: !total_len as u16, + sequence: seq, + channel_and_flags: CHANNEL_TYPE_DATA, + next_length: 0, + header_length: (SdpcmHeader::SIZE + PADDING_SIZE) as _, + wireless_flow_control: 0, + bus_data_credit: 0, + reserved: [0, 0], + }; + + let bdc_header = BdcHeader { + flags: BDC_VERSION << BDC_VERSION_SHIFT, + priority: 0, + flags2: 0, + data_offset: 0, + }; + trace!("tx {:?}", sdpcm_header); + trace!(" {:?}", bdc_header); + + buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); + buf8[SdpcmHeader::SIZE + PADDING_SIZE..][..BdcHeader::SIZE] + .copy_from_slice(&bdc_header.to_bytes()); + buf8[SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE..][..packet.len()] + .copy_from_slice(packet); + + let total_len = (total_len + 3) & !3; // round up to 4byte + + trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)])); + + self.bus.wlan_write(&buf[..(total_len / 4)]).await; + self.ch.tx_done(); + self.check_status(&mut buf).await; + } + Either3::Third(()) => { + self.handle_irq(&mut buf).await; + } + } + } else { + warn!("TX stalled"); + self.bus.wait_for_event().await; + self.handle_irq(&mut buf).await; + } + } + } + + /// Wait for IRQ on F2 packet available + async fn handle_irq(&mut self, buf: &mut [u32; 512]) { + // Receive stuff + let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; + trace!("irq{}", FormatInterrupt(irq)); + + if irq & IRQ_F2_PACKET_AVAILABLE != 0 { + self.check_status(buf).await; + } + + if irq & IRQ_DATA_UNAVAILABLE != 0 { + // TODO what should we do here? + warn!("IRQ DATA_UNAVAILABLE, clearing..."); + self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await; + } + } + + /// Handle F2 events while status register is set + async fn check_status(&mut self, buf: &mut [u32; 512]) { + loop { + let status = self.bus.status(); + trace!("check status{}", FormatStatus(status)); + + if status & STATUS_F2_PKT_AVAILABLE != 0 { + let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT; + self.bus.wlan_read(buf, len).await; + trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)])); + self.rx(&mut slice8_mut(buf)[..len as usize]); + } else { + break; + } + } + } + + fn rx(&mut self, packet: &mut [u8]) { + let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else { + return; + }; + + self.update_credit(&sdpcm_header); + + let channel = sdpcm_header.channel_and_flags & 0x0f; + + match channel { + CHANNEL_TYPE_CONTROL => { + let Some((cdc_header, response)) = CdcHeader::parse(payload) else { + return; + }; + trace!(" {:?}", cdc_header); + + if cdc_header.id == self.ioctl_id { + if cdc_header.status != 0 { + // TODO: propagate error instead + panic!("IOCTL error {}", cdc_header.status as i32); + } + + self.ioctl_state.ioctl_done(response); + } + } + CHANNEL_TYPE_EVENT => { + let Some((_, bdc_packet)) = BdcHeader::parse(payload) else { + warn!("BDC event, incomplete header"); + return; + }; + + let Some((event_packet, evt_data)) = EventPacket::parse(bdc_packet) else { + warn!("BDC event, incomplete data"); + return; + }; + + const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h + if event_packet.eth.ether_type != ETH_P_LINK_CTL { + warn!( + "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}", + event_packet.eth.ether_type, ETH_P_LINK_CTL + ); + return; + } + const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18]; + if event_packet.hdr.oui != BROADCOM_OUI { + warn!( + "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}", + Bytes(&event_packet.hdr.oui), + Bytes(BROADCOM_OUI) + ); + return; + } + const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769; + if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG { + warn!("unexpected subtype {}", event_packet.hdr.subtype); + return; + } + + const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1; + if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT { + warn!("unexpected user_subtype {}", event_packet.hdr.subtype); + return; + } + + let evt_type = events::Event::from(event_packet.msg.event_type as u8); + debug!( + "=== EVENT {:?}: {:?} {:02x}", + evt_type, + event_packet.msg, + Bytes(evt_data) + ); + + if self.events.mask.is_enabled(evt_type) { + let status = event_packet.msg.status; + let event_payload = match evt_type { + Event::ESCAN_RESULT if status == EStatus::PARTIAL => { + let Some((_, bss_info)) = ScanResults::parse(evt_data) else { + return; + }; + let Some(bss_info) = BssInfo::parse(bss_info) else { + return; + }; + events::Payload::BssInfo(*bss_info) + } + Event::ESCAN_RESULT => events::Payload::None, + _ => events::Payload::None, + }; + + // this intentionally uses the non-blocking publish immediate + // publish() is a deadlock risk in the current design as awaiting here prevents ioctls + // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event + // (if they are actively awaiting the queue) + self.events.queue.publish_immediate(events::Message::new( + Status { + event_type: evt_type, + status, + }, + event_payload, + )); + } + } + CHANNEL_TYPE_DATA => { + let Some((_, packet)) = BdcHeader::parse(payload) else { + return; + }; + trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); + + match self.ch.try_rx_buf() { + Some(buf) => { + buf[..packet.len()].copy_from_slice(packet); + self.ch.rx_done(packet.len()) + } + None => warn!("failed to push rxd packet to the channel."), + } + } + _ => {} + } + } + + fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) { + if sdpcm_header.channel_and_flags & 0xf < 3 { + let mut sdpcm_seq_max = sdpcm_header.bus_data_credit; + if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 { + sdpcm_seq_max = self.sdpcm_seq + 2; + } + self.sdpcm_seq_max = sdpcm_seq_max; + } + } + + fn has_credit(&self) -> bool { + self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 + } + + async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) { + let mut buf = [0; 512]; + let buf8 = slice8_mut(&mut buf); + + let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); + + let sdpcm_seq = self.sdpcm_seq; + self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); + self.ioctl_id = self.ioctl_id.wrapping_add(1); + + let sdpcm_header = SdpcmHeader { + len: total_len as u16, // TODO does this len need to be rounded up to u32? + len_inv: !total_len as u16, + sequence: sdpcm_seq, + channel_and_flags: CHANNEL_TYPE_CONTROL, + next_length: 0, + header_length: SdpcmHeader::SIZE as _, + wireless_flow_control: 0, + bus_data_credit: 0, + reserved: [0, 0], + }; + + let cdc_header = CdcHeader { + cmd: cmd, + len: data.len() as _, + flags: kind as u16 | (iface as u16) << 12, + id: self.ioctl_id, + status: 0, + }; + trace!("tx {:?}", sdpcm_header); + trace!(" {:?}", cdc_header); + + buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); + buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes()); + buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data); + + let total_len = (total_len + 3) & !3; // round up to 4byte + + trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)])); + + 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 + } +} From 582006c75cdd7e9d819bcacc0f6724c05f161bee Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 16 Jul 2023 09:32:54 -0500 Subject: [PATCH 03/15] wpan/mac: further cleanup --- embassy-stm32-wpan/src/mac/event.rs | 119 ++++++++++++++++++++ embassy-stm32-wpan/src/mac/ioctl.rs | 124 +++++++++++++++++++++ embassy-stm32-wpan/src/mac/mod.rs | 14 +-- embassy-stm32-wpan/src/mac/runner.rs | 161 ++------------------------- 4 files changed, 257 insertions(+), 161 deletions(-) create mode 100644 embassy-stm32-wpan/src/mac/ioctl.rs 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 - } } From 8f23b6faa6f04f83ece119e94335f892d516f6b3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 17 Jul 2023 19:26:58 -0500 Subject: [PATCH 04/15] wpan: refactor control, driver --- embassy-stm32-wpan/src/mac/control.rs | 446 +------------------------- embassy-stm32-wpan/src/mac/driver.rs | 160 ++++----- embassy-stm32-wpan/src/mac/event.rs | 120 ------- embassy-stm32-wpan/src/mac/ioctl.rs | 124 ------- embassy-stm32-wpan/src/mac/mod.rs | 83 +---- embassy-stm32-wpan/src/mac/runner.rs | 329 +------------------ 6 files changed, 105 insertions(+), 1157 deletions(-) delete mode 100644 embassy-stm32-wpan/src/mac/ioctl.rs diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs index c67614dd..6e45e595 100644 --- a/embassy-stm32-wpan/src/mac/control.rs +++ b/embassy-stm32-wpan/src/mac/control.rs @@ -1,16 +1,4 @@ -use core::cmp::{max, min}; - -use ch::driver::LinkState; -use embassy_net_driver_channel as ch; -use embassy_time::{Duration, Timer}; - -pub use crate::bus::SpiBusCyw43; -use crate::consts::*; -use crate::events::{Event, EventSubscriber, Events}; -use crate::fmt::Bytes; -use crate::ioctl::{IoctlState, IoctlType}; -use crate::structs::*; -use crate::{countries, events, PowerManagementMode}; +use crate::mac::runner::Runner; #[derive(Debug)] pub struct Error { @@ -18,437 +6,15 @@ pub struct Error { } pub struct Control<'a> { - state_ch: ch::StateRunner<'a>, - events: &'a Events, - ioctl_state: &'a IoctlState, + runner: &'a Runner, } impl<'a> Control<'a> { - pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { - Self { - state_ch, - events: event_sub, - ioctl_state, - } - } - - pub async fn init(&mut self, clm: &[u8]) { - const CHUNK_SIZE: usize = 1024; - - debug!("Downloading CLM..."); - - let mut offs = 0; - for chunk in clm.chunks(CHUNK_SIZE) { - let mut flag = DOWNLOAD_FLAG_HANDLER_VER; - if offs == 0 { - flag |= DOWNLOAD_FLAG_BEGIN; - } - offs += chunk.len(); - if offs == clm.len() { - flag |= DOWNLOAD_FLAG_END; - } - - let header = DownloadHeader { - flag, - dload_type: DOWNLOAD_TYPE_CLM, - len: chunk.len() as _, - crc: 0, - }; - let mut buf = [0; 8 + 12 + CHUNK_SIZE]; - buf[0..8].copy_from_slice(b"clmload\x00"); - buf[8..20].copy_from_slice(&header.to_bytes()); - buf[20..][..chunk.len()].copy_from_slice(&chunk); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()]) - .await; + pub(crate) fn new(runner: &'a Runner) -> Self { + Self { runner: runner } } - // check clmload ok - assert_eq!(self.get_iovar_u32("clmload_status").await, 0); - - debug!("Configuring misc stuff..."); - - // Disable tx gloming which transfers multiple packets in one request. - // 'glom' is short for "conglomerate" which means "gather together into - // a compact mass". - self.set_iovar_u32("bus:txglom", 0).await; - self.set_iovar_u32("apsta", 1).await; - - // read MAC addr. - let mut mac_addr = [0; 6]; - assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6); - debug!("mac addr: {:02x}", Bytes(&mac_addr)); - - let country = countries::WORLD_WIDE_XX; - let country_info = CountryInfo { - country_abbrev: [country.code[0], country.code[1], 0, 0], - country_code: [country.code[0], country.code[1], 0, 0], - rev: if country.rev == 0 { -1 } else { country.rev as _ }, - }; - self.set_iovar("country", &country_info.to_bytes()).await; - - // set country takes some time, next ioctls fail if we don't wait. - Timer::after(Duration::from_millis(100)).await; - - // Set antenna to chip antenna - self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await; - - self.set_iovar_u32("bus:txglom", 0).await; - Timer::after(Duration::from_millis(100)).await; - //self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...?? - //Timer::after(Duration::from_millis(100)).await; - self.set_iovar_u32("ampdu_ba_wsize", 8).await; - Timer::after(Duration::from_millis(100)).await; - self.set_iovar_u32("ampdu_mpdu", 4).await; - Timer::after(Duration::from_millis(100)).await; - //self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes - - //Timer::after(Duration::from_millis(100)).await; - - // evts - let mut evts = EventMask { - iface: 0, - events: [0xFF; 24], - }; - - // Disable spammy uninteresting events. - evts.unset(Event::RADIO); - evts.unset(Event::IF); - evts.unset(Event::PROBREQ_MSG); - evts.unset(Event::PROBREQ_MSG_RX); - evts.unset(Event::PROBRESP_MSG); - evts.unset(Event::PROBRESP_MSG); - evts.unset(Event::ROAM); - - self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await; - - Timer::after(Duration::from_millis(100)).await; - - // set wifi up - self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; - - Timer::after(Duration::from_millis(100)).await; - - self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto - self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any - - Timer::after(Duration::from_millis(100)).await; - - self.state_ch.set_ethernet_address(mac_addr); - - debug!("INIT DONE"); - } - - pub async fn set_power_management(&mut self, mode: PowerManagementMode) { - // power save mode - let mode_num = mode.mode(); - if mode_num == 2 { - self.set_iovar_u32("pm2_sleep_ret", mode.sleep_ret_ms() as u32).await; - self.set_iovar_u32("bcn_li_bcn", mode.beacon_period() as u32).await; - self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await; - self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await; - } - self.ioctl_set_u32(86, 0, mode_num).await; - } - - pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { - self.set_iovar_u32("ampdu_ba_wsize", 8).await; - - self.ioctl_set_u32(134, 0, 0).await; // wsec = open - self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; - self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0) - - let mut i = SsidInfo { - len: ssid.len() as _, - ssid: [0; 32], - }; - i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); - - self.wait_for_join(i).await - } - - pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.set_iovar_u32("ampdu_ba_wsize", 8).await; - - self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2 - self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; - self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; - self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; - - Timer::after(Duration::from_millis(100)).await; - - let mut pfi = PassphraseInfo { - len: passphrase.len() as _, - flags: 1, - passphrase: [0; 64], - }; - pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes()); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) - .await; // WLC_SET_WSEC_PMK - - self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open) - self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth - - let mut i = SsidInfo { - len: ssid.len() as _, - ssid: [0; 32], - }; - i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); - - self.wait_for_join(i).await - } - - async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { - self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); - let mut subscriber = self.events.queue.subscriber().unwrap(); - // the actual join operation starts here - // we make sure to enable events before so we don't miss any - - // set_ssid - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes()) - .await; - - // to complete the join, we wait for a SET_SSID event - // we also save the AUTH status for the user, it may be interesting - let mut auth_status = 0; - let status = loop { - let msg = subscriber.next_message_pure().await; - if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS { - auth_status = msg.header.status; - } else if msg.header.event_type == Event::SET_SSID { - // join operation ends with SET_SSID event - break msg.header.status; - } - }; - - self.events.mask.disable_all(); - if status == EStatus::SUCCESS { - // successful join - self.state_ch.set_link_state(LinkState::Up); - debug!("JOINED"); - Ok(()) - } else { - warn!("JOIN failed with status={} auth={}", status, auth_status); - Err(Error { status }) - } - } - - pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) { - assert!(gpio_n < 3); - self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 }) - .await - } - - pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) { - self.start_ap(ssid, "", Security::OPEN, channel).await; - } - - pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) { - self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await; - } - - async fn start_ap(&mut self, ssid: &str, passphrase: &str, security: Security, channel: u8) { - if security != Security::OPEN - && (passphrase.as_bytes().len() < MIN_PSK_LEN || passphrase.as_bytes().len() > MAX_PSK_LEN) - { - panic!("Passphrase is too short or too long"); - } - - // Temporarily set wifi down - self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; - - // Turn off APSTA mode - self.set_iovar_u32("apsta", 0).await; - - // Set wifi up again - self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; - - // Turn on AP mode - self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await; - - // Set SSID - let mut i = SsidInfoWithIndex { - index: 0, - ssid_info: SsidInfo { - len: ssid.as_bytes().len() as _, - ssid: [0; 32], - }, - }; - i.ssid_info.ssid[..ssid.as_bytes().len()].copy_from_slice(ssid.as_bytes()); - self.set_iovar("bsscfg:ssid", &i.to_bytes()).await; - - // Set channel number - self.ioctl_set_u32(IOCTL_CMD_SET_CHANNEL, 0, channel as u32).await; - - // Set security - self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await; - - if security != Security::OPEN { - self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK - - Timer::after(Duration::from_millis(100)).await; - - // Set passphrase - let mut pfi = PassphraseInfo { - len: passphrase.as_bytes().len() as _, - flags: 1, // WSEC_PASSPHRASE - passphrase: [0; 64], - }; - pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) - .await; - } - - // Change mutlicast rate from 1 Mbps to 11 Mbps - self.set_iovar_u32("2g_mrate", 11000000 / 500000).await; - - // Start AP - self.set_iovar_u32x2("bss", 0, 1).await; // bss = BSS_UP - } - - async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) { - let mut buf = [0; 8]; - buf[0..4].copy_from_slice(&val1.to_le_bytes()); - buf[4..8].copy_from_slice(&val2.to_le_bytes()); - self.set_iovar(name, &buf).await - } - - async fn set_iovar_u32(&mut self, name: &str, val: u32) { - self.set_iovar(name, &val.to_le_bytes()).await - } - - async fn get_iovar_u32(&mut self, name: &str) -> u32 { - let mut buf = [0; 4]; - let len = self.get_iovar(name, &mut buf).await; - assert_eq!(len, 4); - u32::from_le_bytes(buf) - } - - async fn set_iovar(&mut self, name: &str, val: &[u8]) { - self.set_iovar_v::<64>(name, val).await - } - - async fn set_iovar_v(&mut self, name: &str, val: &[u8]) { - debug!("set {} = {:02x}", name, Bytes(val)); - - let mut buf = [0; BUFSIZE]; - buf[..name.len()].copy_from_slice(name.as_bytes()); - buf[name.len()] = 0; - buf[name.len() + 1..][..val.len()].copy_from_slice(val); - - let total_len = name.len() + 1 + val.len(); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len]) - .await; - } - - // TODO this is not really working, it always returns all zeros. - async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize { - debug!("get {}", name); - - let mut buf = [0; 64]; - buf[..name.len()].copy_from_slice(name.as_bytes()); - buf[name.len()] = 0; - - let total_len = max(name.len() + 1, res.len()); - let res_len = self - .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len]) - .await; - - let out_len = min(res.len(), res_len); - res[..out_len].copy_from_slice(&buf[..out_len]); - out_len - } - - async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) { - let mut buf = val.to_le_bytes(); - self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await; - } - - async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { - struct CancelOnDrop<'a>(&'a IoctlState); - - impl CancelOnDrop<'_> { - fn defuse(self) { - core::mem::forget(self); - } - } - - impl Drop for CancelOnDrop<'_> { - fn drop(&mut self) { - self.0.cancel_ioctl(); - } - } - - let ioctl = CancelOnDrop(self.ioctl_state); - let resp_len = ioctl.0.do_ioctl(kind, cmd, iface, buf).await; - ioctl.defuse(); - - resp_len - } - - /// Start a wifi scan - /// - /// Returns a `Stream` of networks found by the device - /// - /// # Note - /// Device events are currently implemented using a bounded queue. - /// To not miss any events, you should make sure to always await the stream. - pub async fn scan(&mut self) -> Scanner<'_> { - const SCANTYPE_PASSIVE: u8 = 1; - - let scan_params = ScanParams { - version: 1, - action: 1, - sync_id: 1, - ssid_len: 0, - ssid: [0; 32], - bssid: [0xff; 6], - bss_type: 2, - scan_type: SCANTYPE_PASSIVE, - nprobes: !0, - active_time: !0, - passive_time: !0, - home_time: !0, - channel_num: 0, - channel_list: [0; 1], - }; - - self.events.mask.enable(&[Event::ESCAN_RESULT]); - let subscriber = self.events.queue.subscriber().unwrap(); - self.set_iovar_v::<256>("escan", &scan_params.to_bytes()).await; - - Scanner { - subscriber, - events: &self.events, - } - } -} - -pub struct Scanner<'a> { - subscriber: EventSubscriber<'a>, - events: &'a Events, -} - -impl Scanner<'_> { - /// wait for the next found network - pub async fn next(&mut self) -> Option { - let event = self.subscriber.next_message_pure().await; - if event.header.status != EStatus::PARTIAL { - self.events.mask.disable_all(); - return None; - } - - if let events::Payload::BssInfo(bss) = event.payload { - Some(bss) - } else { - None - } - } -} - -impl Drop for Scanner<'_> { - fn drop(&mut self) { - self.events.mask.disable_all(); + pub async fn init(&mut self) { + // TODO } } diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index 3171d61f..00072749 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -1,102 +1,110 @@ -#![no_std] -#![no_main] #![allow(incomplete_features)] -#![feature(async_fn_in_trait, type_alias_impl_trait, concat_bytes)] #![deny(unused_must_use)] -use core::slice; +use core::task::Context; -use embassy_net_driver_channel as ch; -use embedded_hal_1::digital::OutputPin; -use events::Events; -use ioctl::IoctlState; +use embassy_net_driver::{Capabilities, LinkState, Medium}; -use crate::bus::Bus; -pub use crate::bus::SpiBusCyw43; -pub use crate::control::{Control, Error as ControlError}; -pub use crate::runner::Runner; -pub use crate::structs::BssInfo; +use crate::mac::runner::Runner; +use crate::mac::MTU; -const MTU: usize = 1514; - -pub struct State { - ioctl_state: IoctlState, - ch: ch::State, - events: Events, +pub struct Driver<'d> { + runner: &'d Runner, } -impl State { - pub fn new() -> Self { - Self { - ioctl_state: IoctlState::new(), - ch: ch::State::new(), - events: Events::new(), - } +impl<'d> Driver<'d> { + pub(crate) fn new(runner: &'d Runner) -> Self { + Self { runner: runner } } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PowerManagementMode { - /// Custom, officially unsupported mode. Use at your own risk. - /// All power-saving features set to their max at only a marginal decrease in power consumption - /// as oppposed to `Aggressive`. - SuperSave, +impl<'d> embassy_net_driver::Driver for Driver<'d> { + // type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; + // type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; + type RxToken<'a> = RxToken where Self: 'a; + type TxToken<'a> = TxToken where Self: 'a; - /// Aggressive power saving mode. - Aggressive, + fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { + // WAKER.register(cx.waker()); + // if self.rx.available().is_some() && self.tx.available().is_some() { + // Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx })) + // } else { + // None + // } - /// The default mode. - PowerSave, + None + } - /// Performance is prefered over power consumption but still some power is conserved as opposed to - /// `None`. - Performance, + fn transmit(&mut self, cx: &mut Context) -> Option> { + // WAKER.register(cx.waker()); + // / if self.tx.available().is_some() { + // / Some(TxToken { tx: &mut self.tx }) + // / } else { + // / None + // / } - /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of - /// a much lower throughput. - ThroughputThrottling, + None + } - /// No power management is configured. This consumes the most power. - None, -} + fn capabilities(&self) -> Capabilities { + let mut caps = Capabilities::default(); + caps.max_transmission_unit = MTU; + // caps.max_burst_size = Some(self.tx.len()); -impl Default for PowerManagementMode { - fn default() -> Self { - Self::PowerSave + caps.medium = Medium::Ieee802154; + caps + } + + fn link_state(&mut self, cx: &mut Context) -> LinkState { + // if self.phy.poll_link(&mut self.station_management, cx) { + // LinkState::Up + // } else { + // LinkState::Down + // } + + LinkState::Down + } + + fn ethernet_address(&self) -> [u8; 6] { + // self.mac_addr + + [0; 6] } } -impl PowerManagementMode { - // TODO +pub struct RxToken { + // rx: &'a mut RDesRing<'d>, } -pub type NetDriver<'a> = ch::Device<'a, MTU>; +impl embassy_net_driver::RxToken for RxToken { + fn consume(self, f: F) -> R + where + F: FnOnce(&mut [u8]) -> R, + { + // NOTE(unwrap): we checked the queue wasn't full when creating the token. + // let pkt = unwrap!(self.rx.available()); -pub async fn new<'a, PWR, SPI>( - state: &'a mut State, - pwr: PWR, - spi: SPI, - firmware: &[u8], -) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) -where - PWR: OutputPin, - SPI: SpiBusCyw43, -{ - 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); - - runner.init(firmware).await; - - ( - device, - Control::new(state_ch, &state.events, &state.ioctl_state), - runner, - ) + let pkt = &[]; + let r = f(&mut pkt[0..]); + // self.rx.pop_packet(); + r + } } -fn slice8_mut(x: &mut [u32]) -> &mut [u8] { - let len = x.len() * 4; - unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } +pub struct TxToken { + // tx: &'a mut TDesRing<'d>, +} + +impl embassy_net_driver::TxToken for TxToken { + fn consume(self, len: usize, f: F) -> R + where + F: FnOnce(&mut [u8]) -> R, + { + // NOTE(unwrap): we checked the queue wasn't full when creating the token. + // let pkt = unwrap!(self.tx.available()); + let pkt = &[]; + let r = f(&mut pkt[..len]); + // self.tx.transmit(len); + r + } } diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/mac/event.rs index 661c06ac..a2bb7922 100644 --- a/embassy-stm32-wpan/src/mac/event.rs +++ b/embassy-stm32-wpan/src/mac/event.rs @@ -1,9 +1,3 @@ -use core::cell::RefCell; - -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use embassy_sync::pubsub::{PubSubChannel, Subscriber}; - -use super::helpers::to_u16; use core::mem; use super::indications::{ @@ -80,7 +74,6 @@ impl Event { } } -#[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum MacEvent<'a> { MlmeAssociateCnf(&'a AssociateConfirm), @@ -109,116 +102,3 @@ pub enum MacEvent<'a> { McpsDataInd(&'a DataIndication), MlmePollInd(&'a PollIndication), } - -// 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 deleted file mode 100644 index 0fe55cd6..00000000 --- a/embassy-stm32-wpan/src/mac/ioctl.rs +++ /dev/null @@ -1,124 +0,0 @@ -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 df03e423..e024aeae 100644 --- a/embassy-stm32-wpan/src/mac/mod.rs +++ b/embassy-stm32-wpan/src/mac/mod.rs @@ -1,9 +1,9 @@ pub mod commands; mod consts; pub mod control; +mod driver; pub mod event; pub mod indications; -mod ioctl; mod macros; mod opcodes; pub mod responses; @@ -12,86 +12,19 @@ pub mod typedefs; use core::slice; -use embassy_net_driver_channel as ch; - pub use crate::mac::control::{Control, Error as ControlError}; -use crate::mac::event::Events; -use crate::mac::ioctl::IoctlState; +use crate::mac::driver::Driver; pub use crate::mac::runner::Runner; use crate::sub::mac::Mac; -const MTU: usize = 1514; +const MTU: usize = 127; -pub struct State { - ioctl_state: IoctlState, - ch: ch::State, - events: Events, -} +pub async fn new<'a>(mac: Mac) -> (Runner, Control<'a>, Driver<'a>) { + let runner = Runner::new(mac); + let control = Control::new(&runner); + let driver = Driver::new(&runner); -impl State { - pub fn new() -> Self { - Self { - ioctl_state: IoctlState::new(), - ch: ch::State::new(), - events: Events::new(), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PowerManagementMode { - /// Custom, officially unsupported mode. Use at your own risk. - /// All power-saving features set to their max at only a marginal decrease in power consumption - /// as oppposed to `Aggressive`. - SuperSave, - - /// Aggressive power saving mode. - Aggressive, - - /// The default mode. - PowerSave, - - /// Performance is prefered over power consumption but still some power is conserved as opposed to - /// `None`. - Performance, - - /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of - /// a much lower throughput. - ThroughputThrottling, - - /// No power management is configured. This consumes the most power. - None, -} - -impl Default for PowerManagementMode { - fn default() -> Self { - Self::PowerSave - } -} - -impl PowerManagementMode { - // TODO -} - -pub type NetDriver<'a> = ch::Device<'a, MTU>; - -pub async fn new<'a>( - state: &'a mut State, - mac_subsystem: Mac, - firmware: &[u8], -) -> (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, mac_subsystem, &state.ioctl_state, &state.events); - - runner.init(firmware).await; - - ( - device, - Control::new(state_ch, &state.events, &state.ioctl_state), - runner, - ) + (runner, control, driver) } fn slice8_mut(x: &mut [u32]) -> &mut [u8] { diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index fbb7cb74..e97c9c8e 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -1,342 +1,27 @@ 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; -pub struct Runner<'a> { - ch: ch::Runner<'a, MTU>, +pub struct Runner { mac: Mac, - - ioctl_state: &'a IoctlState, - ioctl_id: u16, - sdpcm_seq: u8, - sdpcm_seq_max: u8, - - events: &'a Events, + // TODO: tx_ring + // TODO: rx_buf } -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, - mac, - ioctl_state, - ioctl_id: 0, - sdpcm_seq: 0, - sdpcm_seq_max: 1, - events, - } +impl Runner { + pub(crate) fn new(mac: Mac) -> Self { + Self { mac } } pub(crate) async fn init(&mut self, firmware: &[u8]) { - self.bus.init().await; - - #[cfg(feature = "firmware-logs")] - self.log_init().await; - debug!("wifi init done"); } pub async fn run(mut self) -> ! { let mut buf = [0; 512]; loop { - #[cfg(feature = "firmware-logs")] - self.log_read().await; - - if self.has_credit() { - let ioctl = self.ioctl_state.wait_pending(); - let tx = self.ch.tx_buf(); - let ev = self.bus.wait_for_event(); - - match select3(ioctl, tx, ev).await { - Either3::First(PendingIoctl { - buf: iobuf, - kind, - cmd, - iface, - }) => { - self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await; - self.check_status(&mut buf).await; - } - Either3::Second(packet) => { - trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); - - let mut buf = [0; 512]; - let buf8 = slice8_mut(&mut buf); - - // There MUST be 2 bytes of padding between the SDPCM and BDC headers. - // And ONLY for data packets! - // No idea why, but the firmware will append two zero bytes to the tx'd packets - // otherwise. If the packet is exactly 1514 bytes (the max MTU), this makes it - // be oversized and get dropped. - // WHD adds it here https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/include/whd_sdpcm.h#L90 - // and adds it to the header size her https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/whd_sdpcm.c#L597 - // ¯\_(ツ)_/¯ - const PADDING_SIZE: usize = 2; - let total_len = SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE + packet.len(); - - let seq = self.sdpcm_seq; - self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); - - let sdpcm_header = SdpcmHeader { - len: total_len as u16, // TODO does this len need to be rounded up to u32? - len_inv: !total_len as u16, - sequence: seq, - channel_and_flags: CHANNEL_TYPE_DATA, - next_length: 0, - header_length: (SdpcmHeader::SIZE + PADDING_SIZE) as _, - wireless_flow_control: 0, - bus_data_credit: 0, - reserved: [0, 0], - }; - - let bdc_header = BdcHeader { - flags: BDC_VERSION << BDC_VERSION_SHIFT, - priority: 0, - flags2: 0, - data_offset: 0, - }; - trace!("tx {:?}", sdpcm_header); - trace!(" {:?}", bdc_header); - - buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); - buf8[SdpcmHeader::SIZE + PADDING_SIZE..][..BdcHeader::SIZE] - .copy_from_slice(&bdc_header.to_bytes()); - buf8[SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE..][..packet.len()] - .copy_from_slice(packet); - - let total_len = (total_len + 3) & !3; // round up to 4byte - - trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)])); - - self.bus.wlan_write(&buf[..(total_len / 4)]).await; - self.ch.tx_done(); - self.check_status(&mut buf).await; - } - Either3::Third(()) => { - self.handle_irq(&mut buf).await; - } - } - } else { - warn!("TX stalled"); - self.bus.wait_for_event().await; - self.handle_irq(&mut buf).await; - } + // TODO } } - - /// Wait for IRQ on F2 packet available - async fn handle_irq(&mut self, buf: &mut [u32; 512]) { - // Receive stuff - let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; - trace!("irq{}", FormatInterrupt(irq)); - - if irq & IRQ_F2_PACKET_AVAILABLE != 0 { - self.check_status(buf).await; - } - - if irq & IRQ_DATA_UNAVAILABLE != 0 { - // TODO what should we do here? - warn!("IRQ DATA_UNAVAILABLE, clearing..."); - self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await; - } - } - - /// Handle F2 events while status register is set - async fn check_status(&mut self, buf: &mut [u32; 512]) { - loop { - let status = self.bus.status(); - trace!("check status{}", FormatStatus(status)); - - if status & STATUS_F2_PKT_AVAILABLE != 0 { - let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT; - self.bus.wlan_read(buf, len).await; - trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)])); - self.rx(&mut slice8_mut(buf)[..len as usize]); - } else { - break; - } - } - } - - fn rx(&mut self, packet: &mut [u8]) { - let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else { - return; - }; - - self.update_credit(&sdpcm_header); - - let channel = sdpcm_header.channel_and_flags & 0x0f; - - match channel { - CHANNEL_TYPE_CONTROL => { - let Some((cdc_header, response)) = CdcHeader::parse(payload) else { - return; - }; - trace!(" {:?}", cdc_header); - - if cdc_header.id == self.ioctl_id { - if cdc_header.status != 0 { - // TODO: propagate error instead - panic!("IOCTL error {}", cdc_header.status as i32); - } - - self.ioctl_state.ioctl_done(response); - } - } - CHANNEL_TYPE_EVENT => { - let Some((_, bdc_packet)) = BdcHeader::parse(payload) else { - warn!("BDC event, incomplete header"); - return; - }; - - let Some((event_packet, evt_data)) = EventPacket::parse(bdc_packet) else { - warn!("BDC event, incomplete data"); - return; - }; - - const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h - if event_packet.eth.ether_type != ETH_P_LINK_CTL { - warn!( - "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}", - event_packet.eth.ether_type, ETH_P_LINK_CTL - ); - return; - } - const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18]; - if event_packet.hdr.oui != BROADCOM_OUI { - warn!( - "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}", - Bytes(&event_packet.hdr.oui), - Bytes(BROADCOM_OUI) - ); - return; - } - const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769; - if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG { - warn!("unexpected subtype {}", event_packet.hdr.subtype); - return; - } - - const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1; - if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT { - warn!("unexpected user_subtype {}", event_packet.hdr.subtype); - return; - } - - let evt_type = events::Event::from(event_packet.msg.event_type as u8); - debug!( - "=== EVENT {:?}: {:?} {:02x}", - evt_type, - event_packet.msg, - Bytes(evt_data) - ); - - if self.events.mask.is_enabled(evt_type) { - let status = event_packet.msg.status; - let event_payload = match evt_type { - Event::ESCAN_RESULT if status == EStatus::PARTIAL => { - let Some((_, bss_info)) = ScanResults::parse(evt_data) else { - return; - }; - let Some(bss_info) = BssInfo::parse(bss_info) else { - return; - }; - events::Payload::BssInfo(*bss_info) - } - Event::ESCAN_RESULT => events::Payload::None, - _ => events::Payload::None, - }; - - // this intentionally uses the non-blocking publish immediate - // publish() is a deadlock risk in the current design as awaiting here prevents ioctls - // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event - // (if they are actively awaiting the queue) - self.events.queue.publish_immediate(events::Message::new( - Status { - event_type: evt_type, - status, - }, - event_payload, - )); - } - } - CHANNEL_TYPE_DATA => { - let Some((_, packet)) = BdcHeader::parse(payload) else { - return; - }; - trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); - - match self.ch.try_rx_buf() { - Some(buf) => { - buf[..packet.len()].copy_from_slice(packet); - self.ch.rx_done(packet.len()) - } - None => warn!("failed to push rxd packet to the channel."), - } - } - _ => {} - } - } - - fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) { - if sdpcm_header.channel_and_flags & 0xf < 3 { - let mut sdpcm_seq_max = sdpcm_header.bus_data_credit; - if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 { - sdpcm_seq_max = self.sdpcm_seq + 2; - } - self.sdpcm_seq_max = sdpcm_seq_max; - } - } - - fn has_credit(&self) -> bool { - self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 - } - - async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) { - let mut buf = [0; 512]; - let buf8 = slice8_mut(&mut buf); - - let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); - - let sdpcm_seq = self.sdpcm_seq; - self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); - self.ioctl_id = self.ioctl_id.wrapping_add(1); - - let sdpcm_header = SdpcmHeader { - len: total_len as u16, // TODO does this len need to be rounded up to u32? - len_inv: !total_len as u16, - sequence: sdpcm_seq, - channel_and_flags: CHANNEL_TYPE_CONTROL, - next_length: 0, - header_length: SdpcmHeader::SIZE as _, - wireless_flow_control: 0, - bus_data_credit: 0, - reserved: [0, 0], - }; - - let cdc_header = CdcHeader { - cmd: cmd, - len: data.len() as _, - flags: kind as u16 | (iface as u16) << 12, - id: self.ioctl_id, - status: 0, - }; - trace!("tx {:?}", sdpcm_header); - trace!(" {:?}", cdc_header); - - buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); - buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes()); - buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data); - - let total_len = (total_len + 3) & !3; // round up to 4byte - - trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)])); - - self.bus.wlan_write(&buf[..total_len / 4]).await; - } } From d040871f7a078db94846305463c30a461f821d7f Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 17 Jul 2023 20:14:06 -0500 Subject: [PATCH 05/15] wpan: fix comp errors and impl. some of runner --- embassy-stm32-wpan/src/mac/driver.rs | 8 +- embassy-stm32-wpan/src/mac/mod.rs | 9 +- embassy-stm32-wpan/src/mac/runner.rs | 75 ++++++++-- examples/stm32wb/src/bin/mac_ffd_net.rs | 180 ++++++++++++++++++++++++ 4 files changed, 255 insertions(+), 17 deletions(-) create mode 100644 examples/stm32wb/src/bin/mac_ffd_net.rs diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index 00072749..118f6908 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -25,6 +25,8 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { type TxToken<'a> = TxToken where Self: 'a; fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { + self.runner.rx_waker.register(cx.waker()); + // WAKER.register(cx.waker()); // if self.rx.available().is_some() && self.tx.available().is_some() { // Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx })) @@ -36,6 +38,8 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { } fn transmit(&mut self, cx: &mut Context) -> Option> { + self.runner.tx_waker.register(cx.waker()); + // WAKER.register(cx.waker()); // / if self.tx.available().is_some() { // / Some(TxToken { tx: &mut self.tx }) @@ -84,7 +88,7 @@ impl embassy_net_driver::RxToken for RxToken { // NOTE(unwrap): we checked the queue wasn't full when creating the token. // let pkt = unwrap!(self.rx.available()); - let pkt = &[]; + let pkt = &mut []; let r = f(&mut pkt[0..]); // self.rx.pop_packet(); r @@ -102,7 +106,7 @@ impl embassy_net_driver::TxToken for TxToken { { // NOTE(unwrap): we checked the queue wasn't full when creating the token. // let pkt = unwrap!(self.tx.available()); - let pkt = &[]; + let pkt = &mut []; let r = f(&mut pkt[..len]); // self.tx.transmit(len); r diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs index e024aeae..2f9d1c81 100644 --- a/embassy-stm32-wpan/src/mac/mod.rs +++ b/embassy-stm32-wpan/src/mac/mod.rs @@ -15,16 +15,11 @@ use core::slice; pub use crate::mac::control::{Control, Error as ControlError}; use crate::mac::driver::Driver; pub use crate::mac::runner::Runner; -use crate::sub::mac::Mac; const MTU: usize = 127; -pub async fn new<'a>(mac: Mac) -> (Runner, Control<'a>, Driver<'a>) { - let runner = Runner::new(mac); - let control = Control::new(&runner); - let driver = Driver::new(&runner); - - (runner, control, driver) +pub async fn new<'a>(runner: &'a Runner) -> (Control<'a>, Driver<'a>) { + (Control::new(runner), Driver::new(runner)) } fn slice8_mut(x: &mut [u32]) -> &mut [u8] { diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index e97c9c8e..d545d6c9 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -1,27 +1,86 @@ use embassy_futures::select::{select3, Either3}; +use embassy_sync::waitqueue::AtomicWaker; +use crate::mac::event::{Event, MacEvent}; use crate::mac::MTU; use crate::sub::mac::Mac; +pub(crate) struct TxRing { + // stores n packets of up to mtu size + ring: [[u8; MTU]; 5], + pending: bool, + // start: u8, + // end: u8, +} + +impl TxRing { + pub(crate) fn new() -> Self { + Self { + ring: [[0; MTU]; 5], + pending: false, + } + } + + // wait for a free packet to become available + pub fn is_packet_free(&self) -> bool { + !self.pending + } + + // get the next available free packet + pub fn get_free_packet<'a>(&'a mut self) -> &'a mut [u8] { + self.pending = true; + + &mut self.ring[0] + } + + pub fn get_packet_to_transmit<'a>(&'a mut self) -> Option<&'a [u8]> { + if self.pending { + self.pending = false; + + Some(&self.ring[0]) + } else { + None + } + } +} + pub struct Runner { - mac: Mac, - // TODO: tx_ring - // TODO: rx_buf + mac_subsystem: Mac, + pub(crate) rx_ring: Option, + pub(crate) tx_ring: TxRing, + pub(crate) rx_waker: AtomicWaker, + pub(crate) tx_waker: AtomicWaker, } impl Runner { - pub(crate) fn new(mac: Mac) -> Self { - Self { mac } + pub fn new(mac: Mac) -> Self { + Self { + mac_subsystem: mac, + rx_ring: None, + tx_ring: TxRing::new(), + rx_waker: AtomicWaker::new(), + tx_waker: AtomicWaker::new(), + } } pub(crate) async fn init(&mut self, firmware: &[u8]) { debug!("wifi init done"); } - pub async fn run(mut self) -> ! { - let mut buf = [0; 512]; + pub async fn run(&self) -> ! { loop { - // TODO + let event = self.mac_subsystem.read().await; + if let Ok(evt) = event.mac_event() { + match evt { + MacEvent::McpsDataInd(data_ind) => { + // TODO: store mac_event in rx_ring + self.rx_waker.wake(); + } + _ => {} + } + } + + // TODO: select tx event } } } diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs new file mode 100644 index 00000000..b1cf051b --- /dev/null +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -0,0 +1,180 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::bind_interrupts; +use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; +use embassy_stm32_wpan::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest}; +use embassy_stm32_wpan::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel}; +use embassy_stm32_wpan::mac::{self, Runner}; +use embassy_stm32_wpan::sub::mm; +use embassy_stm32_wpan::TlMbox; +use static_cell::make_static; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs{ + IPCC_C1_RX => ReceiveInterruptHandler; + IPCC_C1_TX => TransmitInterruptHandler; +}); + +#[embassy_executor::task] +async fn run_mm_queue(memory_manager: mm::MemoryManager) { + memory_manager.run_queue().await; +} + +#[embassy_executor::task] +async fn run_mac(runner: &'static Runner) { + runner.run().await; +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + /* + How to make this work: + + - Obtain a NUCLEO-STM32WB55 from your preferred supplier. + - Download and Install STM32CubeProgrammer. + - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from + gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x + - Open STM32CubeProgrammer + - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. + - Once complete, click connect to connect to the device. + - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services". + - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file + - Select that file, the memory address, "verify download", and then "Firmware Upgrade". + - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the + stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. + - Select that file, the memory address, "verify download", and then "Firmware Upgrade". + - Select "Start Wireless Stack". + - Disconnect from the device. + - In the examples folder for stm32wb, modify the memory.x file to match your target device. + - Run this example. + + Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. + */ + + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let config = Config::default(); + let mbox = TlMbox::init(p.IPCC, Irqs, config); + + spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap(); + + let sys_event = mbox.sys_subsystem.read().await; + info!("sys event: {}", sys_event.payload()); + + core::mem::drop(sys_event); + + let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await; + info!("initialized mac: {}", result); + + info!("resetting"); + mbox.mac_subsystem + .send_command(&ResetRequest { + set_default_pib: true, + ..Default::default() + }) + .await + .unwrap(); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } + + info!("setting extended address"); + let extended_address: u64 = 0xACDE480000000001; + mbox.mac_subsystem + .send_command(&SetRequest { + pib_attribute_ptr: &extended_address as *const _ as *const u8, + pib_attribute: PibId::ExtendedAddress, + }) + .await + .unwrap(); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } + + info!("setting short address"); + let short_address: u16 = 0x1122; + mbox.mac_subsystem + .send_command(&SetRequest { + pib_attribute_ptr: &short_address as *const _ as *const u8, + pib_attribute: PibId::ShortAddress, + }) + .await + .unwrap(); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } + + info!("setting association permit"); + let association_permit: bool = true; + mbox.mac_subsystem + .send_command(&SetRequest { + pib_attribute_ptr: &association_permit as *const _ as *const u8, + pib_attribute: PibId::AssociationPermit, + }) + .await + .unwrap(); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } + + info!("setting TX power"); + let transmit_power: i8 = 2; + mbox.mac_subsystem + .send_command(&SetRequest { + pib_attribute_ptr: &transmit_power as *const _ as *const u8, + pib_attribute: PibId::TransmitPower, + }) + .await + .unwrap(); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } + + info!("starting FFD device"); + mbox.mac_subsystem + .send_command(&StartRequest { + pan_id: PanId([0x1A, 0xAA]), + channel_number: MacChannel::Channel16, + beacon_order: 0x0F, + superframe_order: 0x0F, + pan_coordinator: true, + battery_life_extension: false, + ..Default::default() + }) + .await + .unwrap(); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } + + info!("setting RX on when idle"); + let rx_on_while_idle: bool = true; + mbox.mac_subsystem + .send_command(&SetRequest { + pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8, + pib_attribute: PibId::RxOnWhenIdle, + }) + .await + .unwrap(); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } + + let runner = make_static!(Runner::new(mbox.mac_subsystem)); + + spawner.spawn(run_mac(runner)).unwrap(); + + let (driver, control) = mac::new(runner).await; +} From 890d113b855dc11be75a9716401c7703f4ce48e1 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 18 Jul 2023 18:28:12 -0500 Subject: [PATCH 06/15] wpan: fully implement initial draft concept --- embassy-stm32-wpan/src/mac/control.rs | 8 +-- embassy-stm32-wpan/src/mac/driver.rs | 75 ++++++++++++++----------- embassy-stm32-wpan/src/mac/mod.rs | 2 +- embassy-stm32-wpan/src/mac/runner.rs | 21 +++---- embassy-sync/src/channel.rs | 22 ++++++++ examples/stm32wb/src/bin/mac_ffd_net.rs | 2 +- 6 files changed, 80 insertions(+), 50 deletions(-) diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs index 6e45e595..2f8a7d07 100644 --- a/embassy-stm32-wpan/src/mac/control.rs +++ b/embassy-stm32-wpan/src/mac/control.rs @@ -6,13 +6,13 @@ pub struct Error { } pub struct Control<'a> { - runner: &'a Runner, + runner: &'a Runner<'a>, } impl<'a> Control<'a> { - pub(crate) fn new(runner: &'a Runner) -> Self { - Self { runner: runner } - } + pub(crate) fn new(runner: &'a Runner<'a>) -> Self { + Self { runner: runner } + } pub async fn init(&mut self) { // TODO diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index 118f6908..8ebfb2b7 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -4,16 +4,20 @@ use core::task::Context; use embassy_net_driver::{Capabilities, LinkState, Medium}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::channel::Channel; +use super::event::MacEvent; +use crate::mac::event::Event; use crate::mac::runner::Runner; use crate::mac::MTU; pub struct Driver<'d> { - runner: &'d Runner, + runner: &'d Runner<'d>, } impl<'d> Driver<'d> { - pub(crate) fn new(runner: &'d Runner) -> Self { + pub(crate) fn new(runner: &'d Runner<'d>) -> Self { Self { runner: runner } } } @@ -21,33 +25,32 @@ impl<'d> Driver<'d> { impl<'d> embassy_net_driver::Driver for Driver<'d> { // type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; // type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; - type RxToken<'a> = RxToken where Self: 'a; - type TxToken<'a> = TxToken where Self: 'a; + type RxToken<'a> = RxToken<'d> where Self: 'a; + type TxToken<'a> = TxToken<'d> where Self: 'a; fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { - self.runner.rx_waker.register(cx.waker()); - - // WAKER.register(cx.waker()); - // if self.rx.available().is_some() && self.tx.available().is_some() { - // Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx })) - // } else { - // None - // } - - None + if self.runner.rx_channel.poll_ready_to_receive(cx) && self.runner.tx_channel.poll_ready_to_receive(cx) { + Some(( + RxToken { + rx: &self.runner.rx_channel, + }, + TxToken { + tx: &self.runner.tx_channel, + }, + )) + } else { + None + } } fn transmit(&mut self, cx: &mut Context) -> Option> { - self.runner.tx_waker.register(cx.waker()); - - // WAKER.register(cx.waker()); - // / if self.tx.available().is_some() { - // / Some(TxToken { tx: &mut self.tx }) - // / } else { - // / None - // / } - - None + if self.runner.tx_channel.poll_ready_to_receive(cx) { + Some(TxToken { + tx: &self.runner.tx_channel, + }) + } else { + None + } } fn capabilities(&self) -> Capabilities { @@ -76,30 +79,38 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { } } -pub struct RxToken { - // rx: &'a mut RDesRing<'d>, +pub struct RxToken<'d> { + rx: &'d Channel, } -impl embassy_net_driver::RxToken for RxToken { +impl<'d> embassy_net_driver::RxToken for RxToken<'d> { fn consume(self, f: F) -> R where F: FnOnce(&mut [u8]) -> R, { - // NOTE(unwrap): we checked the queue wasn't full when creating the token. - // let pkt = unwrap!(self.rx.available()); + // Only valid data events should be put into the queue + + let event = self.rx.try_recv().unwrap(); + let mac_event = event.mac_event().unwrap(); + let data_event = match mac_event { + MacEvent::McpsDataInd(data_event) => data_event, + _ => unreachable!(), + }; let pkt = &mut []; let r = f(&mut pkt[0..]); - // self.rx.pop_packet(); + + // let r = f(&mut data_event.payload()); r } } -pub struct TxToken { +pub struct TxToken<'d> { + tx: &'d Channel, // tx: &'a mut TDesRing<'d>, } -impl embassy_net_driver::TxToken for TxToken { +impl<'d> embassy_net_driver::TxToken for TxToken<'d> { fn consume(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R, diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs index 2f9d1c81..3dcda17a 100644 --- a/embassy-stm32-wpan/src/mac/mod.rs +++ b/embassy-stm32-wpan/src/mac/mod.rs @@ -18,7 +18,7 @@ pub use crate::mac::runner::Runner; const MTU: usize = 127; -pub async fn new<'a>(runner: &'a Runner) -> (Control<'a>, Driver<'a>) { +pub async fn new<'a>(runner: &'a Runner<'a>) -> (Control<'a>, Driver<'a>) { (Control::new(runner), Driver::new(runner)) } diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index d545d6c9..911ff60b 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -1,4 +1,6 @@ use embassy_futures::select::{select3, Either3}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; use crate::mac::event::{Event, MacEvent}; @@ -44,22 +46,18 @@ impl TxRing { } } -pub struct Runner { +pub struct Runner<'a> { mac_subsystem: Mac, - pub(crate) rx_ring: Option, - pub(crate) tx_ring: TxRing, - pub(crate) rx_waker: AtomicWaker, - pub(crate) tx_waker: AtomicWaker, + pub(crate) rx_channel: Channel, + pub(crate) tx_channel: Channel, } -impl Runner { +impl<'a> Runner<'a> { pub fn new(mac: Mac) -> Self { Self { mac_subsystem: mac, - rx_ring: None, - tx_ring: TxRing::new(), - rx_waker: AtomicWaker::new(), - tx_waker: AtomicWaker::new(), + rx_channel: Channel::new(), + tx_channel: Channel::new(), } } @@ -73,8 +71,7 @@ impl Runner { if let Ok(evt) = event.mac_event() { match evt { MacEvent::McpsDataInd(data_ind) => { - // TODO: store mac_event in rx_ring - self.rx_waker.wake(); + self.rx_channel.try_send(event); } _ => {} } diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 77352874..f421af39 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -335,6 +335,12 @@ impl ChannelState { } } + fn poll_ready_to_receive(&mut self, cx: &mut Context<'_>) -> bool { + self.receiver_waker.register(cx.waker()); + + !self.queue.is_empty() + } + fn try_send(&mut self, message: T) -> Result<(), TrySendError> { self.try_send_with_context(message, None) } @@ -353,6 +359,12 @@ impl ChannelState { } } } + + fn poll_ready_to_send(&mut self, cx: &mut Context<'_>) -> bool { + self.senders_waker.register(cx.waker()); + + !self.queue.is_full() + } } /// A bounded channel for communicating between asynchronous tasks @@ -401,6 +413,16 @@ where self.lock(|c| c.try_send_with_context(m, cx)) } + /// Allows a poll_fn to poll until the channel is ready to receive + pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> bool { + self.lock(|c| c.poll_ready_to_receive(cx)) + } + + /// Allows a poll_fn to poll until the channel is ready to send + pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> bool { + self.lock(|c| c.poll_ready_to_send(cx)) + } + /// Get a sender for this channel. pub fn sender(&self) -> Sender<'_, M, T, N> { Sender { channel: self } diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index b1cf051b..6072f418 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -25,7 +25,7 @@ async fn run_mm_queue(memory_manager: mm::MemoryManager) { } #[embassy_executor::task] -async fn run_mac(runner: &'static Runner) { +async fn run_mac(runner: &'static Runner<'static>) { runner.run().await; } From ca1d4179a792d4a33b4f2b97b33002759fd28a21 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 18 Jul 2023 20:52:03 -0500 Subject: [PATCH 07/15] wpan: implement initial event loop --- embassy-stm32-wpan/Cargo.toml | 4 +- embassy-stm32-wpan/src/mac/driver.rs | 22 +++-- embassy-stm32-wpan/src/mac/runner.rs | 113 ++++++++++++------------ examples/stm32wb/Cargo.toml | 6 +- examples/stm32wb/src/bin/mac_ffd_net.rs | 10 ++- 5 files changed, 85 insertions(+), 70 deletions(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 082d00f1..ab58714d 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -18,6 +18,7 @@ embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" } embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel", optional=true } +embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver", optional=true } defmt = { version = "0.3", optional = true } cortex-m = "0.7.6" @@ -27,13 +28,14 @@ aligned = "0.4.1" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } stm32wb-hci = { version = "0.1.3", optional = true } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } bitflags = { version = "2.3.3", optional = true } [features] defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"] ble = ["dep:stm32wb-hci"] -mac = ["dep:bitflags", "dep:embassy-net-driver-channel"] +mac = ["dep:bitflags", "dep:embassy-net-driver-channel", "dep:embassy-net-driver"] stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index 8ebfb2b7..a41b7509 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -29,13 +29,14 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { type TxToken<'a> = TxToken<'d> where Self: 'a; fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { - if self.runner.rx_channel.poll_ready_to_receive(cx) && self.runner.tx_channel.poll_ready_to_receive(cx) { + if self.runner.rx_channel.poll_ready_to_receive(cx) && self.runner.tx_buf_channel.poll_ready_to_receive(cx) { Some(( RxToken { rx: &self.runner.rx_channel, }, TxToken { tx: &self.runner.tx_channel, + tx_buf: &self.runner.tx_buf_channel, }, )) } else { @@ -44,9 +45,10 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { } fn transmit(&mut self, cx: &mut Context) -> Option> { - if self.runner.tx_channel.poll_ready_to_receive(cx) { + if self.runner.tx_buf_channel.poll_ready_to_receive(cx) { Some(TxToken { tx: &self.runner.tx_channel, + tx_buf: &self.runner.tx_buf_channel, }) } else { None @@ -106,8 +108,8 @@ impl<'d> embassy_net_driver::RxToken for RxToken<'d> { } pub struct TxToken<'d> { - tx: &'d Channel, - // tx: &'a mut TDesRing<'d>, + tx: &'d Channel, + tx_buf: &'d Channel, } impl<'d> embassy_net_driver::TxToken for TxToken<'d> { @@ -115,11 +117,13 @@ impl<'d> embassy_net_driver::TxToken for TxToken<'d> { where F: FnOnce(&mut [u8]) -> R, { - // NOTE(unwrap): we checked the queue wasn't full when creating the token. - // let pkt = unwrap!(self.tx.available()); - let pkt = &mut []; - let r = f(&mut pkt[..len]); - // self.tx.transmit(len); + // Only valid tx buffers should be put into the queue + let buf = self.tx_buf.try_recv().unwrap(); + let r = f(&mut buf[..len]); + + // The tx channel should always be of equal capacity to the tx_buf channel + self.tx.try_send(buf).unwrap(); + r } } diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index 911ff60b..9edcff9b 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -1,83 +1,80 @@ -use embassy_futures::select::{select3, Either3}; +use embassy_futures::join; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; -use embassy_sync::waitqueue::AtomicWaker; +use crate::mac::commands::DataRequest; use crate::mac::event::{Event, MacEvent}; +use crate::mac::typedefs::{AddressMode, MacAddress, PanId, SecurityLevel}; use crate::mac::MTU; use crate::sub::mac::Mac; -pub(crate) struct TxRing { - // stores n packets of up to mtu size - ring: [[u8; MTU]; 5], - pending: bool, - // start: u8, - // end: u8, -} - -impl TxRing { - pub(crate) fn new() -> Self { - Self { - ring: [[0; MTU]; 5], - pending: false, - } - } - - // wait for a free packet to become available - pub fn is_packet_free(&self) -> bool { - !self.pending - } - - // get the next available free packet - pub fn get_free_packet<'a>(&'a mut self) -> &'a mut [u8] { - self.pending = true; - - &mut self.ring[0] - } - - pub fn get_packet_to_transmit<'a>(&'a mut self) -> Option<&'a [u8]> { - if self.pending { - self.pending = false; - - Some(&self.ring[0]) - } else { - None - } - } -} - pub struct Runner<'a> { mac_subsystem: Mac, pub(crate) rx_channel: Channel, - pub(crate) tx_channel: Channel, + pub(crate) tx_channel: Channel, + pub(crate) tx_buf_channel: Channel, } impl<'a> Runner<'a> { - pub fn new(mac: Mac) -> Self { - Self { + pub fn new(mac: Mac, tx_buf_queue: [&'a mut [u8; MTU]; 5]) -> Self { + let this = Self { mac_subsystem: mac, rx_channel: Channel::new(), tx_channel: Channel::new(), - } - } + tx_buf_channel: Channel::new(), + }; - pub(crate) async fn init(&mut self, firmware: &[u8]) { - debug!("wifi init done"); + for buf in tx_buf_queue { + this.tx_buf_channel.try_send(buf).unwrap(); + } + + this } pub async fn run(&self) -> ! { - loop { - let event = self.mac_subsystem.read().await; - if let Ok(evt) = event.mac_event() { - match evt { - MacEvent::McpsDataInd(data_ind) => { - self.rx_channel.try_send(event); + join::join( + async { + loop { + let event = self.mac_subsystem.read().await; + if let Ok(evt) = event.mac_event() { + match evt { + MacEvent::McpsDataInd(_) => { + self.rx_channel.send(event).await; + } + _ => {} + } } - _ => {} } - } + }, + async { + loop { + let buf = self.tx_channel.recv().await; - // TODO: select tx event - } + self.mac_subsystem + .send_command( + DataRequest { + src_addr_mode: AddressMode::Short, + dst_addr_mode: AddressMode::Short, + dst_pan_id: PanId([0x1A, 0xAA]), + dst_address: MacAddress::BROADCAST, + msdu_handle: 0x02, + ack_tx: 0x00, + gts_tx: false, + security_level: SecurityLevel::Unsecure, + ..Default::default() + } + .set_buffer(&buf), + ) + .await + .unwrap(); + + // The tx channel should always be of equal capacity to the tx_buf channel + self.tx_buf_channel.try_send(buf).unwrap(); + } + }, + ) + .await; + + loop {} } } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 8585b99f..7c0b83e6 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -21,7 +21,7 @@ embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } - +static_cell = { version = "1.1", features = ["nightly"]} [features] default = ["ble", "mac"] @@ -40,6 +40,10 @@ required-features = ["mac"] name = "mac_ffd" required-features = ["mac"] +[[bin]] +name = "mac_ffd_net" +required-features = ["mac"] + [[bin]] name = "eddystone_beacon" required-features = ["ble"] diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index 6072f418..7b8c4b9d 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -172,7 +172,15 @@ async fn main(spawner: Spawner) { defmt::info!("{:#x}", evt.mac_event()); } - let runner = make_static!(Runner::new(mbox.mac_subsystem)); + let tx_queue = [ + make_static!([0u8; 127]), + make_static!([0u8; 127]), + make_static!([0u8; 127]), + make_static!([0u8; 127]), + make_static!([0u8; 127]), + ]; + + let runner = make_static!(Runner::new(mbox.mac_subsystem, tx_queue)); spawner.spawn(run_mac(runner)).unwrap(); From 28254842db645bc961d19fa2287610b7b1d3447c Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 19 Jul 2023 17:49:08 -0500 Subject: [PATCH 08/15] - optimize event to parse opcode only once - optimze channels - return mut ref for smoltcp rx --- embassy-stm32-wpan/Cargo.toml | 3 +- embassy-stm32-wpan/src/mac/control.rs | 1 + embassy-stm32-wpan/src/mac/driver.rs | 23 ++-- embassy-stm32-wpan/src/mac/event.rs | 123 +++++++++++++++------- embassy-stm32-wpan/src/mac/indications.rs | 4 +- embassy-stm32-wpan/src/mac/mod.rs | 7 -- embassy-stm32-wpan/src/mac/runner.rs | 19 ++-- embassy-stm32-wpan/src/sub/mac.rs | 2 +- examples/stm32wb/src/bin/mac_ffd.rs | 34 +++--- examples/stm32wb/src/bin/mac_ffd_net.rs | 28 ++--- examples/stm32wb/src/bin/mac_rfd.rs | 34 +++--- tests/stm32/src/bin/wpan_mac.rs | 33 +++--- 12 files changed, 178 insertions(+), 133 deletions(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index ab58714d..6cd12220 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -17,7 +17,6 @@ embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" } embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } -embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel", optional=true } embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver", optional=true } defmt = { version = "0.3", optional = true } @@ -35,7 +34,7 @@ bitflags = { version = "2.3.3", optional = true } defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"] ble = ["dep:stm32wb-hci"] -mac = ["dep:bitflags", "dep:embassy-net-driver-channel", "dep:embassy-net-driver"] +mac = ["dep:bitflags", "dep:embassy-net-driver" ] stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs index 2f8a7d07..c45f6407 100644 --- a/embassy-stm32-wpan/src/mac/control.rs +++ b/embassy-stm32-wpan/src/mac/control.rs @@ -6,6 +6,7 @@ pub struct Error { } pub struct Control<'a> { + #[allow(dead_code)] runner: &'a Runner<'a>, } diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index a41b7509..3017808f 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -7,8 +7,7 @@ use embassy_net_driver::{Capabilities, LinkState, Medium}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; -use super::event::MacEvent; -use crate::mac::event::Event; +use crate::mac::event::{Event, MacEvent}; use crate::mac::runner::Runner; use crate::mac::MTU; @@ -64,7 +63,7 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { caps } - fn link_state(&mut self, cx: &mut Context) -> LinkState { + fn link_state(&mut self, _cx: &mut Context) -> LinkState { // if self.phy.poll_link(&mut self.station_management, cx) { // LinkState::Up // } else { @@ -82,7 +81,7 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { } pub struct RxToken<'d> { - rx: &'d Channel, + rx: &'d Channel, 1>, } impl<'d> embassy_net_driver::RxToken for RxToken<'d> { @@ -92,24 +91,18 @@ impl<'d> embassy_net_driver::RxToken for RxToken<'d> { { // Only valid data events should be put into the queue - let event = self.rx.try_recv().unwrap(); - let mac_event = event.mac_event().unwrap(); - let data_event = match mac_event { + let data_event = match *self.rx.try_recv().unwrap() { MacEvent::McpsDataInd(data_event) => data_event, _ => unreachable!(), }; - let pkt = &mut []; - let r = f(&mut pkt[0..]); - - // let r = f(&mut data_event.payload()); - r + f(&mut data_event.payload()) } } pub struct TxToken<'d> { - tx: &'d Channel, - tx_buf: &'d Channel, + tx: &'d Channel, + tx_buf: &'d Channel, } impl<'d> embassy_net_driver::TxToken for TxToken<'d> { @@ -122,7 +115,7 @@ impl<'d> embassy_net_driver::TxToken for TxToken<'d> { let r = f(&mut buf[..len]); // The tx channel should always be of equal capacity to the tx_buf channel - self.tx.try_send(buf).unwrap(); + self.tx.try_send((buf, len)).unwrap(); r } diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/mac/event.rs index a2bb7922..d975c5bd 100644 --- a/embassy-stm32-wpan/src/mac/event.rs +++ b/embassy-stm32-wpan/src/mac/event.rs @@ -1,4 +1,4 @@ -use core::mem; +use core::{mem, ops}; use super::indications::{ AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication, @@ -22,55 +22,104 @@ pub(crate) trait ParseableMacEvent: Sized { } } -pub struct Event { +pub struct Event<'a> { + #[allow(dead_code)] event_box: EvtBox, + mac_event: MacEvent<'a>, } -impl Event { - pub(crate) fn new(event_box: EvtBox) -> Self { - Self { event_box } - } - - pub fn mac_event<'a>(&'a self) -> Result, ()> { - let payload = self.event_box.payload(); +impl<'a> Event<'a> { + pub(crate) fn new(event_box: EvtBox) -> Result { + let payload = event_box.payload(); let opcode = u16::from_le_bytes(payload[0..2].try_into().unwrap()); let opcode = OpcodeM0ToM4::try_from(opcode)?; let buf = &payload[2..]; - match opcode { - OpcodeM0ToM4::MlmeAssociateCnf => Ok(MacEvent::MlmeAssociateCnf(AssociateConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeDisassociateCnf => { - Ok(MacEvent::MlmeDisassociateCnf(DisassociateConfirm::from_buffer(buf)?)) + // To avoid re-parsing the opcode, we store the result of the parse + // this requires use of unsafe because rust cannot assume that a reference will become + // invalid when the underlying result is moved. However, because we refer to a "heap" + // allocation, the underlying reference will not move until the struct is dropped. + + let mac_event = match opcode { + OpcodeM0ToM4::MlmeAssociateCnf => { + MacEvent::MlmeAssociateCnf(unsafe { &*(AssociateConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeDisassociateCnf => { + MacEvent::MlmeDisassociateCnf(unsafe { &*(DisassociateConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeGetCnf => MacEvent::MlmeGetCnf(unsafe { &*(GetConfirm::from_buffer(buf)? as *const _) }), + OpcodeM0ToM4::MlmeGtsCnf => MacEvent::MlmeGtsCnf(unsafe { &*(GtsConfirm::from_buffer(buf)? as *const _) }), + OpcodeM0ToM4::MlmeResetCnf => { + MacEvent::MlmeResetCnf(unsafe { &*(ResetConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeRxEnableCnf => { + MacEvent::MlmeRxEnableCnf(unsafe { &*(RxEnableConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeScanCnf => { + MacEvent::MlmeScanCnf(unsafe { &*(ScanConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeSetCnf => MacEvent::MlmeSetCnf(unsafe { &*(SetConfirm::from_buffer(buf)? as *const _) }), + OpcodeM0ToM4::MlmeStartCnf => { + MacEvent::MlmeStartCnf(unsafe { &*(StartConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmePollCnf => { + MacEvent::MlmePollCnf(unsafe { &*(PollConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeDpsCnf => MacEvent::MlmeDpsCnf(unsafe { &*(DpsConfirm::from_buffer(buf)? as *const _) }), + OpcodeM0ToM4::MlmeSoundingCnf => { + MacEvent::MlmeSoundingCnf(unsafe { &*(SoundingConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeCalibrateCnf => { + MacEvent::MlmeCalibrateCnf(unsafe { &*(CalibrateConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::McpsDataCnf => { + MacEvent::McpsDataCnf(unsafe { &*(DataConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::McpsPurgeCnf => { + MacEvent::McpsPurgeCnf(unsafe { &*(PurgeConfirm::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeAssociateInd => { + MacEvent::MlmeAssociateInd(unsafe { &*(AssociateIndication::from_buffer(buf)? as *const _) }) } - OpcodeM0ToM4::MlmeGetCnf => Ok(MacEvent::MlmeGetCnf(GetConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeGtsCnf => Ok(MacEvent::MlmeGtsCnf(GtsConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeResetCnf => Ok(MacEvent::MlmeResetCnf(ResetConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeRxEnableCnf => Ok(MacEvent::MlmeRxEnableCnf(RxEnableConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeScanCnf => Ok(MacEvent::MlmeScanCnf(ScanConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeSetCnf => Ok(MacEvent::MlmeSetCnf(SetConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeStartCnf => Ok(MacEvent::MlmeStartCnf(StartConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmePollCnf => Ok(MacEvent::MlmePollCnf(PollConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeDpsCnf => Ok(MacEvent::MlmeDpsCnf(DpsConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeSoundingCnf => Ok(MacEvent::MlmeSoundingCnf(SoundingConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeCalibrateCnf => Ok(MacEvent::MlmeCalibrateCnf(CalibrateConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::McpsDataCnf => Ok(MacEvent::McpsDataCnf(DataConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::McpsPurgeCnf => Ok(MacEvent::McpsPurgeCnf(PurgeConfirm::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeAssociateInd => Ok(MacEvent::MlmeAssociateInd(AssociateIndication::from_buffer(buf)?)), OpcodeM0ToM4::MlmeDisassociateInd => { - Ok(MacEvent::MlmeDisassociateInd(DisassociateIndication::from_buffer(buf)?)) + MacEvent::MlmeDisassociateInd(unsafe { &*(DisassociateIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeBeaconNotifyInd => { - Ok(MacEvent::MlmeBeaconNotifyInd(BeaconNotifyIndication::from_buffer(buf)?)) + MacEvent::MlmeBeaconNotifyInd(unsafe { &*(BeaconNotifyIndication::from_buffer(buf)? as *const _) }) } - OpcodeM0ToM4::MlmeCommStatusInd => Ok(MacEvent::MlmeCommStatusInd(CommStatusIndication::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeGtsInd => Ok(MacEvent::MlmeGtsInd(GtsIndication::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeOrphanInd => Ok(MacEvent::MlmeOrphanInd(OrphanIndication::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeSyncLossInd => Ok(MacEvent::MlmeSyncLossInd(SyncLossIndication::from_buffer(buf)?)), - OpcodeM0ToM4::MlmeDpsInd => Ok(MacEvent::MlmeDpsInd(DpsIndication::from_buffer(buf)?)), - OpcodeM0ToM4::McpsDataInd => Ok(MacEvent::McpsDataInd(DataIndication::from_buffer(buf)?)), - OpcodeM0ToM4::MlmePollInd => Ok(MacEvent::MlmePollInd(PollIndication::from_buffer(buf)?)), - } + OpcodeM0ToM4::MlmeCommStatusInd => { + MacEvent::MlmeCommStatusInd(unsafe { &*(CommStatusIndication::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeGtsInd => { + MacEvent::MlmeGtsInd(unsafe { &*(GtsIndication::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeOrphanInd => { + MacEvent::MlmeOrphanInd(unsafe { &*(OrphanIndication::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeSyncLossInd => { + MacEvent::MlmeSyncLossInd(unsafe { &*(SyncLossIndication::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmeDpsInd => { + MacEvent::MlmeDpsInd(unsafe { &*(DpsIndication::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::McpsDataInd => { + MacEvent::McpsDataInd(unsafe { &*(DataIndication::from_buffer(buf)? as *const _) }) + } + OpcodeM0ToM4::MlmePollInd => { + MacEvent::MlmePollInd(unsafe { &*(PollIndication::from_buffer(buf)? as *const _) }) + } + }; + + Ok(Self { event_box, mac_event }) + } +} + +impl<'a> ops::Deref for Event<'a> { + type Target = MacEvent<'a>; + + fn deref(&self) -> &Self::Target { + &self.mac_event } } diff --git a/embassy-stm32-wpan/src/mac/indications.rs b/embassy-stm32-wpan/src/mac/indications.rs index 5445fb4a..4349af9c 100644 --- a/embassy-stm32-wpan/src/mac/indications.rs +++ b/embassy-stm32-wpan/src/mac/indications.rs @@ -236,8 +236,8 @@ pub struct DataIndication { impl ParseableMacEvent for DataIndication {} impl DataIndication { - pub fn payload<'a>(&'a self) -> &'a [u8] { - unsafe { slice::from_raw_parts(self.msdu_ptr, self.msdu_length as usize) } + pub fn payload<'a>(&'a self) -> &'a mut [u8] { + unsafe { slice::from_raw_parts_mut(self.msdu_ptr as *mut _, self.msdu_length as usize) } } } diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs index 3dcda17a..a93f7a69 100644 --- a/embassy-stm32-wpan/src/mac/mod.rs +++ b/embassy-stm32-wpan/src/mac/mod.rs @@ -10,8 +10,6 @@ pub mod responses; pub mod runner; pub mod typedefs; -use core::slice; - pub use crate::mac::control::{Control, Error as ControlError}; use crate::mac::driver::Driver; pub use crate::mac::runner::Runner; @@ -21,8 +19,3 @@ const MTU: usize = 127; pub async fn new<'a>(runner: &'a Runner<'a>) -> (Control<'a>, Driver<'a>) { (Control::new(runner), Driver::new(runner)) } - -fn slice8_mut(x: &mut [u32]) -> &mut [u8] { - let len = x.len() * 4; - unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } -} diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index 9edcff9b..779712cd 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -10,9 +10,9 @@ use crate::sub::mac::Mac; pub struct Runner<'a> { mac_subsystem: Mac, - pub(crate) rx_channel: Channel, - pub(crate) tx_channel: Channel, - pub(crate) tx_buf_channel: Channel, + pub(crate) rx_channel: Channel, 1>, + pub(crate) tx_channel: Channel, + pub(crate) tx_buf_channel: Channel, } impl<'a> Runner<'a> { @@ -31,15 +31,14 @@ impl<'a> Runner<'a> { this } - pub async fn run(&self) -> ! { + pub async fn run(&'a self) -> ! { join::join( async { loop { - let event = self.mac_subsystem.read().await; - if let Ok(evt) = event.mac_event() { - match evt { + if let Ok(mac_event) = self.mac_subsystem.read().await { + match *mac_event { MacEvent::McpsDataInd(_) => { - self.rx_channel.send(event).await; + self.rx_channel.send(mac_event).await; } _ => {} } @@ -48,7 +47,7 @@ impl<'a> Runner<'a> { }, async { loop { - let buf = self.tx_channel.recv().await; + let (buf, len) = self.tx_channel.recv().await; self.mac_subsystem .send_command( @@ -63,7 +62,7 @@ impl<'a> Runner<'a> { security_level: SecurityLevel::Unsecure, ..Default::default() } - .set_buffer(&buf), + .set_buffer(&buf[..len]), ) .await .unwrap(); diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs index d9bf4c90..5ecbfe8c 100644 --- a/embassy-stm32-wpan/src/sub/mac.rs +++ b/embassy-stm32-wpan/src/sub/mac.rs @@ -94,7 +94,7 @@ impl Mac { } } - pub async fn read(&self) -> Event { + pub async fn read(&self) -> Result, ()> { Event::new(self.tl_read().await) } } diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index bc71e29a..7de30778 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs @@ -74,8 +74,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting extended address"); @@ -88,8 +88,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting short address"); @@ -102,8 +102,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting association permit"); @@ -116,8 +116,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting TX power"); @@ -130,8 +130,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("starting FFD device"); @@ -148,8 +148,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting RX on when idle"); @@ -162,17 +162,17 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } loop { let evt = mbox.mac_subsystem.read().await; - if let Ok(evt) = evt.mac_event() { + if let Ok(evt) = evt { defmt::info!("parsed mac event"); - defmt::info!("{:#x}", evt); + defmt::info!("{:#x}", *evt); - match evt { + match *evt { MacEvent::MlmeAssociateInd(association) => mbox .mac_subsystem .send_command(&AssociateResponse { diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index 7b8c4b9d..16c33e14 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -80,8 +80,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting extended address"); @@ -94,8 +94,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting short address"); @@ -108,8 +108,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting association permit"); @@ -122,8 +122,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting TX power"); @@ -136,8 +136,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("starting FFD device"); @@ -154,8 +154,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting RX on when idle"); @@ -168,8 +168,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } let tx_queue = [ diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs index 7cb401d8..d1307a84 100644 --- a/examples/stm32wb/src/bin/mac_rfd.rs +++ b/examples/stm32wb/src/bin/mac_rfd.rs @@ -76,8 +76,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("setting extended address"); @@ -90,8 +90,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + defmt::info!("{:#x}", *evt); } info!("getting extended address"); @@ -104,10 +104,10 @@ async fn main(spawner: Spawner) { .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + info!("{:#x}", *evt); - if let Ok(MacEvent::MlmeGetCnf(evt)) = evt.mac_event() { + if let MacEvent::MlmeGetCnf(evt) = *evt { if evt.pib_attribute_value_len == 8 { let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) }; @@ -132,10 +132,10 @@ async fn main(spawner: Spawner) { info!("{}", a); mbox.mac_subsystem.send_command(&a).await.unwrap(); let short_addr = { - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + info!("{:#x}", *evt); - if let Ok(MacEvent::MlmeAssociateCnf(conf)) = evt.mac_event() { + if let MacEvent::MlmeAssociateCnf(conf) = *evt { conf.assoc_short_address } else { defmt::panic!() @@ -151,8 +151,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + info!("{:#x}", *evt); } info!("sending data"); @@ -175,12 +175,14 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + info!("{:#x}", *evt); } loop { - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt.mac_event()); + match mbox.mac_subsystem.read().await { + Ok(evt) => info!("{:#x}", *evt), + _ => continue, + }; } } diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs index d64a5ef8..2b0d67bb 100644 --- a/tests/stm32/src/bin/wpan_mac.rs +++ b/tests/stm32/src/bin/wpan_mac.rs @@ -56,8 +56,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + info!("{:#x}", *evt); } info!("setting extended address"); @@ -70,8 +70,8 @@ async fn main(spawner: Spawner) { .await .unwrap(); { - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt.mac_event()); + let evt = mbox.mac_subsystem.read().await.unwrap(); + info!("{:#x}", *evt); } info!("getting extended address"); @@ -82,11 +82,12 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt.mac_event()); - if let Ok(MacEvent::MlmeGetCnf(evt)) = evt.mac_event() { + { + let evt = mbox.mac_subsystem.read().await.unwrap(); + info!("{:#x}", *evt); + + if let MacEvent::MlmeGetCnf(evt) = *evt { if evt.pib_attribute_value_len == 8 { let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) }; @@ -110,10 +111,18 @@ async fn main(spawner: Spawner) { }; info!("{}", a); mbox.mac_subsystem.send_command(&a).await.unwrap(); - { - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt.mac_event()); - } + let short_addr = { + let evt = mbox.mac_subsystem.read().await.unwrap(); + info!("{:#x}", *evt); + + if let MacEvent::MlmeAssociateCnf(conf) = *evt { + conf.assoc_short_address + } else { + defmt::panic!() + } + }; + + _ = short_addr; info!("Test OK"); cortex_m::asm::bkpt(); From 02d57afd51451fe9e7d224a0ea665a665ba2b72f Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 19 Jul 2023 17:52:07 -0500 Subject: [PATCH 09/15] rustfmt --- examples/stm32wb/src/bin/mac_ffd_net.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index 16c33e14..a55b1fc7 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -6,8 +6,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; -use embassy_stm32_wpan::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest}; -use embassy_stm32_wpan::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel}; +use embassy_stm32_wpan::mac::commands::{ResetRequest, SetRequest, StartRequest}; +use embassy_stm32_wpan::mac::typedefs::{MacChannel, PanId, PibId}; use embassy_stm32_wpan::mac::{self, Runner}; use embassy_stm32_wpan::sub::mm; use embassy_stm32_wpan::TlMbox; @@ -185,4 +185,7 @@ async fn main(spawner: Spawner) { spawner.spawn(run_mac(runner)).unwrap(); let (driver, control) = mac::new(runner).await; + + let _ = driver; + let _ = control; } From 809d3476aac88ddba01cd16f0df3565e35beddea Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 20 Jul 2023 16:45:04 -0500 Subject: [PATCH 10/15] wpan: further optimize mac event --- embassy-stm32-wpan/src/mac/driver.rs | 6 +- embassy-stm32-wpan/src/mac/event.rs | 83 ++++++++++++------------- embassy-stm32-wpan/src/mac/runner.rs | 6 +- embassy-stm32-wpan/src/sub/mac.rs | 10 +-- examples/stm32wb/src/bin/mac_ffd.rs | 39 +++--------- examples/stm32wb/src/bin/mac_ffd_net.rs | 35 +++-------- examples/stm32wb/src/bin/mac_rfd.rs | 24 +++---- tests/stm32/src/bin/wpan_mac.rs | 23 +++---- 8 files changed, 86 insertions(+), 140 deletions(-) diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index 3017808f..fffbb9ed 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -7,7 +7,7 @@ use embassy_net_driver::{Capabilities, LinkState, Medium}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; -use crate::mac::event::{Event, MacEvent}; +use crate::mac::event::MacEvent; use crate::mac::runner::Runner; use crate::mac::MTU; @@ -81,7 +81,7 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { } pub struct RxToken<'d> { - rx: &'d Channel, 1>, + rx: &'d Channel, 1>, } impl<'d> embassy_net_driver::RxToken for RxToken<'d> { @@ -91,7 +91,7 @@ impl<'d> embassy_net_driver::RxToken for RxToken<'d> { { // Only valid data events should be put into the queue - let data_event = match *self.rx.try_recv().unwrap() { + let data_event = match self.rx.try_recv().unwrap() { MacEvent::McpsDataInd(data_event) => data_event, _ => unreachable!(), }; diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/mac/event.rs index d975c5bd..b6f57fda 100644 --- a/embassy-stm32-wpan/src/mac/event.rs +++ b/embassy-stm32-wpan/src/mac/event.rs @@ -1,4 +1,4 @@ -use core::{mem, ops}; +use core::{mem, ptr}; use super::indications::{ AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication, @@ -8,9 +8,9 @@ use super::responses::{ AssociateConfirm, CalibrateConfirm, DataConfirm, DisassociateConfirm, DpsConfirm, GetConfirm, GtsConfirm, PollConfirm, PurgeConfirm, ResetConfirm, RxEnableConfirm, ScanConfirm, SetConfirm, SoundingConfirm, StartConfirm, }; -use crate::evt::EvtBox; +use crate::evt::{EvtBox, MemoryManager}; use crate::mac::opcodes::OpcodeM0ToM4; -use crate::sub::mac::Mac; +use crate::sub::mac::{self, Mac}; pub(crate) trait ParseableMacEvent: Sized { fn from_buffer<'a>(buf: &'a [u8]) -> Result<&'a Self, ()> { @@ -22,13 +22,36 @@ pub(crate) trait ParseableMacEvent: Sized { } } -pub struct Event<'a> { - #[allow(dead_code)] - event_box: EvtBox, - mac_event: MacEvent<'a>, +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum MacEvent<'a> { + MlmeAssociateCnf(&'a AssociateConfirm), + MlmeDisassociateCnf(&'a DisassociateConfirm), + MlmeGetCnf(&'a GetConfirm), + MlmeGtsCnf(&'a GtsConfirm), + MlmeResetCnf(&'a ResetConfirm), + MlmeRxEnableCnf(&'a RxEnableConfirm), + MlmeScanCnf(&'a ScanConfirm), + MlmeSetCnf(&'a SetConfirm), + MlmeStartCnf(&'a StartConfirm), + MlmePollCnf(&'a PollConfirm), + MlmeDpsCnf(&'a DpsConfirm), + MlmeSoundingCnf(&'a SoundingConfirm), + MlmeCalibrateCnf(&'a CalibrateConfirm), + McpsDataCnf(&'a DataConfirm), + McpsPurgeCnf(&'a PurgeConfirm), + MlmeAssociateInd(&'a AssociateIndication), + MlmeDisassociateInd(&'a DisassociateIndication), + MlmeBeaconNotifyInd(&'a BeaconNotifyIndication), + MlmeCommStatusInd(&'a CommStatusIndication), + MlmeGtsInd(&'a GtsIndication), + MlmeOrphanInd(&'a OrphanIndication), + MlmeSyncLossInd(&'a SyncLossIndication), + MlmeDpsInd(&'a DpsIndication), + McpsDataInd(&'a DataIndication), + MlmePollInd(&'a PollIndication), } -impl<'a> Event<'a> { +impl<'a> MacEvent<'a> { pub(crate) fn new(event_box: EvtBox) -> Result { let payload = event_box.payload(); let opcode = u16::from_le_bytes(payload[0..2].try_into().unwrap()); @@ -111,43 +134,17 @@ impl<'a> Event<'a> { } }; - Ok(Self { event_box, mac_event }) + // Forget the event box so that drop isn't called + // We want to handle the lifetime ourselves + + mem::forget(event_box); + + Ok(mac_event) } } -impl<'a> ops::Deref for Event<'a> { - type Target = MacEvent<'a>; - - fn deref(&self) -> &Self::Target { - &self.mac_event +impl<'a> Drop for MacEvent<'a> { + fn drop(&mut self) { + unsafe { mac::Mac::drop_event_packet(ptr::null_mut()) }; } } - -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum MacEvent<'a> { - MlmeAssociateCnf(&'a AssociateConfirm), - MlmeDisassociateCnf(&'a DisassociateConfirm), - MlmeGetCnf(&'a GetConfirm), - MlmeGtsCnf(&'a GtsConfirm), - MlmeResetCnf(&'a ResetConfirm), - MlmeRxEnableCnf(&'a RxEnableConfirm), - MlmeScanCnf(&'a ScanConfirm), - MlmeSetCnf(&'a SetConfirm), - MlmeStartCnf(&'a StartConfirm), - MlmePollCnf(&'a PollConfirm), - MlmeDpsCnf(&'a DpsConfirm), - MlmeSoundingCnf(&'a SoundingConfirm), - MlmeCalibrateCnf(&'a CalibrateConfirm), - McpsDataCnf(&'a DataConfirm), - McpsPurgeCnf(&'a PurgeConfirm), - MlmeAssociateInd(&'a AssociateIndication), - MlmeDisassociateInd(&'a DisassociateIndication), - MlmeBeaconNotifyInd(&'a BeaconNotifyIndication), - MlmeCommStatusInd(&'a CommStatusIndication), - MlmeGtsInd(&'a GtsIndication), - MlmeOrphanInd(&'a OrphanIndication), - MlmeSyncLossInd(&'a SyncLossIndication), - MlmeDpsInd(&'a DpsIndication), - McpsDataInd(&'a DataIndication), - MlmePollInd(&'a PollIndication), -} diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index 779712cd..a0090012 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -3,14 +3,14 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use crate::mac::commands::DataRequest; -use crate::mac::event::{Event, MacEvent}; +use crate::mac::event::MacEvent; use crate::mac::typedefs::{AddressMode, MacAddress, PanId, SecurityLevel}; use crate::mac::MTU; use crate::sub::mac::Mac; pub struct Runner<'a> { mac_subsystem: Mac, - pub(crate) rx_channel: Channel, 1>, + pub(crate) rx_channel: Channel, 1>, pub(crate) tx_channel: Channel, pub(crate) tx_buf_channel: Channel, } @@ -36,7 +36,7 @@ impl<'a> Runner<'a> { async { loop { if let Ok(mac_event) = self.mac_subsystem.read().await { - match *mac_event { + match mac_event { MacEvent::McpsDataInd(_) => { self.rx_channel.send(mac_event).await; } diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs index 5ecbfe8c..b0cf0248 100644 --- a/embassy-stm32-wpan/src/sub/mac.rs +++ b/embassy-stm32-wpan/src/sub/mac.rs @@ -12,7 +12,7 @@ use crate::cmd::CmdPacket; use crate::consts::TlPacketType; use crate::evt::{EvtBox, EvtPacket}; use crate::mac::commands::MacCommand; -use crate::mac::event::Event; +use crate::mac::event::MacEvent; use crate::mac::typedefs::MacError; use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER}; use crate::{channels, evt}; @@ -94,14 +94,16 @@ impl Mac { } } - pub async fn read(&self) -> Result, ()> { - Event::new(self.tl_read().await) + pub async fn read(&self) -> Result, ()> { + MacEvent::new(self.tl_read().await) } } impl evt::MemoryManager for Mac { /// SAFETY: passing a pointer to something other than a managed event packet is UB unsafe fn drop_event_packet(_: *mut EvtPacket) { + trace!("mac drop event"); + // Write the ack CmdPacket::write_into( MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, @@ -111,7 +113,7 @@ impl evt::MemoryManager for Mac { ); // Clear the rx flag - let _ = poll_once(Ipcc::receive::( + let _ = poll_once(Ipcc::receive::<()>( channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || None, )); diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index 7de30778..1379ac6b 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs @@ -73,10 +73,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting extended address"); let extended_address: u64 = 0xACDE480000000001; @@ -87,10 +84,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting short address"); let short_address: u16 = 0x1122; @@ -101,10 +95,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting association permit"); let association_permit: bool = true; @@ -115,10 +106,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting TX power"); let transmit_power: i8 = 2; @@ -129,10 +117,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("starting FFD device"); mbox.mac_subsystem @@ -147,10 +132,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting RX on when idle"); let rx_on_while_idle: bool = true; @@ -161,18 +143,15 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); loop { let evt = mbox.mac_subsystem.read().await; if let Ok(evt) = evt { defmt::info!("parsed mac event"); - defmt::info!("{:#x}", *evt); + defmt::info!("{:#x}", evt); - match *evt { + match evt { MacEvent::MlmeAssociateInd(association) => mbox .mac_subsystem .send_command(&AssociateResponse { diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index a55b1fc7..bbcd0a70 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -79,10 +79,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting extended address"); let extended_address: u64 = 0xACDE480000000001; @@ -93,10 +90,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting short address"); let short_address: u16 = 0x1122; @@ -107,10 +101,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting association permit"); let association_permit: bool = true; @@ -121,10 +112,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting TX power"); let transmit_power: i8 = 2; @@ -135,10 +123,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("starting FFD device"); mbox.mac_subsystem @@ -153,10 +138,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting RX on when idle"); let rx_on_while_idle: bool = true; @@ -167,10 +149,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); let tx_queue = [ make_static!([0u8; 127]), diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs index d1307a84..4d8b6601 100644 --- a/examples/stm32wb/src/bin/mac_rfd.rs +++ b/examples/stm32wb/src/bin/mac_rfd.rs @@ -75,10 +75,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("setting extended address"); let extended_address: u64 = 0xACDE480000000002; @@ -89,10 +86,7 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - { - let evt = mbox.mac_subsystem.read().await.unwrap(); - defmt::info!("{:#x}", *evt); - } + defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); info!("getting extended address"); mbox.mac_subsystem @@ -105,9 +99,9 @@ async fn main(spawner: Spawner) { { let evt = mbox.mac_subsystem.read().await.unwrap(); - info!("{:#x}", *evt); + info!("{:#x}", evt); - if let MacEvent::MlmeGetCnf(evt) = *evt { + if let MacEvent::MlmeGetCnf(evt) = evt { if evt.pib_attribute_value_len == 8 { let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) }; @@ -133,9 +127,9 @@ async fn main(spawner: Spawner) { mbox.mac_subsystem.send_command(&a).await.unwrap(); let short_addr = { let evt = mbox.mac_subsystem.read().await.unwrap(); - info!("{:#x}", *evt); + info!("{:#x}", evt); - if let MacEvent::MlmeAssociateCnf(conf) = *evt { + if let MacEvent::MlmeAssociateCnf(conf) = evt { conf.assoc_short_address } else { defmt::panic!() @@ -152,7 +146,7 @@ async fn main(spawner: Spawner) { .unwrap(); { let evt = mbox.mac_subsystem.read().await.unwrap(); - info!("{:#x}", *evt); + info!("{:#x}", evt); } info!("sending data"); @@ -176,12 +170,12 @@ async fn main(spawner: Spawner) { .unwrap(); { let evt = mbox.mac_subsystem.read().await.unwrap(); - info!("{:#x}", *evt); + info!("{:#x}", evt); } loop { match mbox.mac_subsystem.read().await { - Ok(evt) => info!("{:#x}", *evt), + Ok(evt) => info!("{:#x}", evt), _ => continue, }; } diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs index 2b0d67bb..b04a19ee 100644 --- a/tests/stm32/src/bin/wpan_mac.rs +++ b/tests/stm32/src/bin/wpan_mac.rs @@ -57,7 +57,7 @@ async fn main(spawner: Spawner) { .unwrap(); { let evt = mbox.mac_subsystem.read().await.unwrap(); - info!("{:#x}", *evt); + info!("{:#x}", evt); } info!("setting extended address"); @@ -71,7 +71,7 @@ async fn main(spawner: Spawner) { .unwrap(); { let evt = mbox.mac_subsystem.read().await.unwrap(); - info!("{:#x}", *evt); + info!("{:#x}", evt); } info!("getting extended address"); @@ -85,9 +85,9 @@ async fn main(spawner: Spawner) { { let evt = mbox.mac_subsystem.read().await.unwrap(); - info!("{:#x}", *evt); + info!("{:#x}", evt); - if let MacEvent::MlmeGetCnf(evt) = *evt { + if let MacEvent::MlmeGetCnf(evt) = evt { if evt.pib_attribute_value_len == 8 { let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) }; @@ -111,18 +111,13 @@ async fn main(spawner: Spawner) { }; info!("{}", a); mbox.mac_subsystem.send_command(&a).await.unwrap(); - let short_addr = { - let evt = mbox.mac_subsystem.read().await.unwrap(); - info!("{:#x}", *evt); - - if let MacEvent::MlmeAssociateCnf(conf) = *evt { - conf.assoc_short_address - } else { - defmt::panic!() - } + let short_addr = if let MacEvent::MlmeAssociateCnf(conf) = mbox.mac_subsystem.read().await.unwrap() { + conf.assoc_short_address + } else { + defmt::panic!() }; - _ = short_addr; + info!("{}", short_addr); info!("Test OK"); cortex_m::asm::bkpt(); From 83ff626c4745d73def4e0cf88ea64c21a19d6d1f Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 20 Jul 2023 17:00:03 -0500 Subject: [PATCH 11/15] wpan/mac: incr. runner msdu handle --- embassy-stm32-wpan/src/mac/runner.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index a0090012..007544c6 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -46,6 +46,8 @@ impl<'a> Runner<'a> { } }, async { + let mut msdu_handle = 0x02; + loop { let (buf, len) = self.tx_channel.recv().await; @@ -56,7 +58,7 @@ impl<'a> Runner<'a> { dst_addr_mode: AddressMode::Short, dst_pan_id: PanId([0x1A, 0xAA]), dst_address: MacAddress::BROADCAST, - msdu_handle: 0x02, + msdu_handle: msdu_handle, ack_tx: 0x00, gts_tx: false, security_level: SecurityLevel::Unsecure, @@ -67,6 +69,8 @@ impl<'a> Runner<'a> { .await .unwrap(); + msdu_handle += 1; + // The tx channel should always be of equal capacity to the tx_buf channel self.tx_buf_channel.try_send(buf).unwrap(); } From c80c232a72a561c3d89c8292437996bc07bfb689 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 20 Jul 2023 19:52:36 -0500 Subject: [PATCH 12/15] wpan: impl. debug for structs --- embassy-stm32-wpan/src/mac/event.rs | 1 + embassy-stm32-wpan/src/mac/indications.rs | 10 +++++++ embassy-stm32-wpan/src/mac/responses.rs | 15 +++++++++++ embassy-stm32-wpan/src/mac/typedefs.rs | 32 +++++++++++++++++------ 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/mac/event.rs index b6f57fda..8415bc11 100644 --- a/embassy-stm32-wpan/src/mac/event.rs +++ b/embassy-stm32-wpan/src/mac/event.rs @@ -23,6 +23,7 @@ pub(crate) trait ParseableMacEvent: Sized { } #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug)] pub enum MacEvent<'a> { MlmeAssociateCnf(&'a AssociateConfirm), MlmeDisassociateCnf(&'a DisassociateConfirm), diff --git a/embassy-stm32-wpan/src/mac/indications.rs b/embassy-stm32-wpan/src/mac/indications.rs index 4349af9c..c0b86d74 100644 --- a/embassy-stm32-wpan/src/mac/indications.rs +++ b/embassy-stm32-wpan/src/mac/indications.rs @@ -10,6 +10,7 @@ use super::typedefs::{ /// MLME ASSOCIATE Indication which will be used by the MAC /// to indicate the reception of an association request command #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct AssociateIndication { /// Extended address of the device requesting association @@ -31,6 +32,7 @@ impl ParseableMacEvent for AssociateIndication {} /// MLME DISASSOCIATE indication which will be used to send /// disassociation indication to the application. #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DisassociateIndication { /// Extended address of the device requesting association @@ -52,6 +54,7 @@ impl ParseableMacEvent for DisassociateIndication {} /// MLME BEACON NOTIIFY Indication which is used to send parameters contained /// within a beacon frame received by the MAC to the application #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct BeaconNotifyIndication { /// he set of octets comprising the beacon payload to be transferred @@ -73,6 +76,7 @@ impl ParseableMacEvent for BeaconNotifyIndication {} /// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CommStatusIndication { /// The 16-bit PAN identifier of the device from which the frame @@ -103,6 +107,7 @@ impl ParseableMacEvent for CommStatusIndication {} /// MLME GTS Indication indicates that a GTS has been allocated or that a /// previously allocated GTS has been deallocated #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct GtsIndication { /// The short address of the device that has been allocated or deallocated a GTS @@ -126,6 +131,7 @@ impl ParseableMacEvent for GtsIndication {} /// MLME ORPHAN Indication which is used by the coordinator to notify the /// application of the presence of an orphaned device #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct OrphanIndication { /// Extended address of the orphaned device @@ -147,6 +153,7 @@ impl ParseableMacEvent for OrphanIndication {} /// MLME SYNC LOSS Indication which is used by the MAC to indicate the loss /// of synchronization with the coordinator #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SyncLossIndication { /// The PAN identifier with which the device lost synchronization or to which it was realigned @@ -172,6 +179,7 @@ impl ParseableMacEvent for SyncLossIndication {} /// MLME DPS Indication which indicates the expiration of the DPSIndexDuration /// and the resetting of the DPS values in the PHY #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DpsIndication { /// byte stuffing to keep 32 bit alignment @@ -181,6 +189,7 @@ pub struct DpsIndication { impl ParseableMacEvent for DpsIndication {} #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DataIndication { /// Pointer to the set of octets forming the MSDU being indicated @@ -244,6 +253,7 @@ impl DataIndication { /// MLME POLL Indication which will be used for indicating the Data Request /// reception to upper layer as defined in Zigbee r22 - D.8.2 #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PollIndication { /// addressing mode used diff --git a/embassy-stm32-wpan/src/mac/responses.rs b/embassy-stm32-wpan/src/mac/responses.rs index 5d203084..9c407a36 100644 --- a/embassy-stm32-wpan/src/mac/responses.rs +++ b/embassy-stm32-wpan/src/mac/responses.rs @@ -8,6 +8,7 @@ use super::typedefs::{ /// MLME ASSOCIATE Confirm used to inform of the initiating device whether /// its request to associate was successful or unsuccessful #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct AssociateConfirm { /// short address allocated by the coordinator on successful association @@ -30,6 +31,7 @@ impl ParseableMacEvent for AssociateConfirm {} /// MLME DISASSOCIATE Confirm used to send disassociation Confirmation to the application. #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DisassociateConfirm { /// status of the disassociation attempt @@ -46,6 +48,7 @@ impl ParseableMacEvent for DisassociateConfirm {} /// MLME GET Confirm which requests information about a given PIB attribute #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct GetConfirm { /// The pointer to the value of the PIB attribute attempted to read @@ -65,6 +68,7 @@ impl ParseableMacEvent for GetConfirm {} /// MLME GTS Confirm which eports the results of a request to allocate a new GTS /// or to deallocate an existing GTS #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct GtsConfirm { /// The characteristics of the GTS @@ -79,6 +83,7 @@ impl ParseableMacEvent for GtsConfirm {} /// MLME RESET Confirm which is used to report the results of the reset operation #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ResetConfirm { /// The result of the reset operation @@ -92,6 +97,7 @@ impl ParseableMacEvent for ResetConfirm {} /// MLME RX ENABLE Confirm which is used to report the results of the attempt /// to enable or disable the receiver #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct RxEnableConfirm { /// Result of the request to enable or disable the receiver @@ -104,6 +110,7 @@ impl ParseableMacEvent for RxEnableConfirm {} /// MLME SCAN Confirm which is used to report the result of the channel scan request #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ScanConfirm { /// Status of the scan request @@ -130,6 +137,7 @@ impl ParseableMacEvent for ScanConfirm {} /// MLME SET Confirm which reports the result of an attempt to write a value to a PIB attribute #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SetConfirm { /// The result of the set operation @@ -145,6 +153,7 @@ impl ParseableMacEvent for SetConfirm {} /// MLME START Confirm which is used to report the results of the attempt to /// start using a new superframe configuration #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct StartConfirm { /// Result of the attempt to start using an updated superframe configuration @@ -157,6 +166,7 @@ impl ParseableMacEvent for StartConfirm {} /// MLME POLL Confirm which is used to report the result of a request to poll the coordinator for data #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PollConfirm { /// The status of the data request @@ -169,6 +179,7 @@ impl ParseableMacEvent for PollConfirm {} /// MLME DPS Confirm which reports the results of the attempt to enable or disable the DPS #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DpsConfirm { /// The status of the DPS request @@ -182,6 +193,7 @@ impl ParseableMacEvent for DpsConfirm {} /// MLME SOUNDING Confirm which reports the result of a request to the PHY to provide /// channel sounding information #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SoundingConfirm { /// Results of the sounding measurement @@ -195,6 +207,7 @@ impl ParseableMacEvent for SoundingConfirm {} /// MLME CALIBRATE Confirm which reports the result of a request to the PHY /// to provide internal propagation path information #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CalibrateConfirm { /// The status of the attempt to return sounding data @@ -214,6 +227,7 @@ impl ParseableMacEvent for CalibrateConfirm {} /// MCPS DATA Confirm which will be used for reporting the results of /// MAC data related requests from the application #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DataConfirm { /// The handle associated with the MSDU being confirmed @@ -245,6 +259,7 @@ impl ParseableMacEvent for DataConfirm {} /// MCPS PURGE Confirm which will be used by the MAC to notify the application of /// the status of its request to purge an MSDU from the transaction queue #[repr(C)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PurgeConfirm { /// Handle associated with the MSDU requested to be purged from the transaction queue diff --git a/embassy-stm32-wpan/src/mac/typedefs.rs b/embassy-stm32-wpan/src/mac/typedefs.rs index 98c67c86..0552b8ea 100644 --- a/embassy-stm32-wpan/src/mac/typedefs.rs +++ b/embassy-stm32-wpan/src/mac/typedefs.rs @@ -1,3 +1,5 @@ +use core::fmt::Debug; + use crate::numeric_enum; #[derive(Debug)] @@ -37,7 +39,7 @@ numeric_enum! { numeric_enum! { #[repr(u8)] /// this enum contains all the MAC PIB Ids - #[derive(Default)] + #[derive(Default, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum PibId { // PHY @@ -96,7 +98,7 @@ numeric_enum! { numeric_enum! { #[repr(u8)] - #[derive(Default, Clone, Copy)] + #[derive(Default, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AddressMode { #[default] @@ -113,6 +115,18 @@ pub union MacAddress { pub extended: [u8; 8], } +impl Debug for MacAddress { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + unsafe { + write!( + fmt, + "MacAddress {{ short: {:?}, extended: {:?} }}", + self.short, self.extended + ) + } + } +} + #[cfg(feature = "defmt")] impl defmt::Format for MacAddress { fn format(&self, fmt: defmt::Formatter) { @@ -159,7 +173,7 @@ pub struct GtsCharacteristics { /// MAC PAN Descriptor which contains the network details of the device from /// which the beacon is received -#[derive(Default, Clone, Copy)] +#[derive(Default, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PanDescriptor { /// PAN identifier of the coordinator @@ -223,7 +237,7 @@ impl TryFrom<&[u8]> for PanDescriptor { numeric_enum! { #[repr(u8)] - #[derive(Default, Clone, Copy)] + #[derive(Default, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// Building wireless applications with STM32WB series MCUs - Application note 13.10.3 pub enum MacChannel { @@ -289,7 +303,7 @@ defmt::bitflags! { numeric_enum! { #[repr(u8)] - #[derive(Default, Clone, Copy)] + #[derive(Default, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum KeyIdMode { #[default] @@ -306,6 +320,7 @@ numeric_enum! { numeric_enum! { #[repr(u8)] + #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AssociationStatus { /// Association successful @@ -319,7 +334,7 @@ numeric_enum! { numeric_enum! { #[repr(u8)] - #[derive(Clone, Copy)] + #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum DisassociationReason { /// The coordinator wishes the device to leave the PAN. @@ -331,7 +346,7 @@ numeric_enum! { numeric_enum! { #[repr(u8)] - #[derive(Default, Clone, Copy)] + #[derive(Default, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SecurityLevel { /// MAC Unsecured Mode Security @@ -346,6 +361,7 @@ numeric_enum! { numeric_enum! { #[repr(u8)] + #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ScanType { EdScan = 0x00, @@ -356,7 +372,7 @@ numeric_enum! { } /// newtype for Pan Id -#[derive(Default, Clone, Copy)] +#[derive(Default, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PanId(pub [u8; 2]); From 899a68325c322a813155c7ba9c6e43c79be99bd8 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 20 Jul 2023 20:51:49 -0500 Subject: [PATCH 13/15] wpan: impl. draft control scheme --- embassy-stm32-wpan/src/mac/control.rs | 86 ++++++++++++++++++++++++--- embassy-stm32-wpan/src/mac/event.rs | 2 + embassy-stm32-wpan/src/mac/mod.rs | 2 +- embassy-stm32-wpan/src/mac/runner.rs | 31 +++++++++- 4 files changed, 109 insertions(+), 12 deletions(-) diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs index c45f6407..fd8c22b2 100644 --- a/embassy-stm32-wpan/src/mac/control.rs +++ b/embassy-stm32-wpan/src/mac/control.rs @@ -1,12 +1,16 @@ +use core::future::Future; +use core::task; + +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::mutex::MutexGuard; +use embassy_sync::signal::Signal; +use futures::FutureExt; + +use super::commands::MacCommand; +use super::typedefs::MacError; use crate::mac::runner::Runner; -#[derive(Debug)] -pub struct Error { - pub status: u32, -} - pub struct Control<'a> { - #[allow(dead_code)] runner: &'a Runner<'a>, } @@ -15,7 +19,73 @@ impl<'a> Control<'a> { Self { runner: runner } } - pub async fn init(&mut self) { - // TODO + pub async fn send_command(&self, cmd: &T) -> Result<(), MacError> + where + T: MacCommand, + { + let _wm = self.runner.write_mutex.lock().await; + + self.runner.mac_subsystem.send_command(cmd).await + } + + pub async fn send_command_and_get_response(&self, cmd: &T) -> Result, MacError> + where + T: MacCommand, + { + let _wm = self.runner.write_mutex.lock().await; + let rm = self.runner.read_mutex.lock().await; + let token = EventToken::new(self.runner, rm); + + self.runner.mac_subsystem.send_command(cmd).await?; + + Ok(token) + } +} + +pub struct EventToken<'a> { + runner: &'a Runner<'a>, + _mutex_guard: MutexGuard<'a, CriticalSectionRawMutex, ()>, +} + +impl<'a> EventToken<'a> { + pub(crate) fn new(runner: &'a Runner<'a>, mutex_guard: MutexGuard<'a, CriticalSectionRawMutex, ()>) -> Self { + // Enable event receiving + runner.rx_event_channel.lock(|s| { + *s.borrow_mut() = Some(Signal::new()); + }); + + Self { + runner: runner, + _mutex_guard: mutex_guard, + } + } +} + +impl<'a> Future for EventToken<'a> { + // TODO: output something + type Output = (); + + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll { + self.get_mut().runner.rx_event_channel.lock(|s| { + let signal = s.borrow_mut(); + let signal = match &*signal { + Some(s) => s, + _ => unreachable!(), + }; + + let _ = signal.wait().poll_unpin(cx); + }); + + todo!() + } +} + +impl<'a> Drop for EventToken<'a> { + fn drop(&mut self) { + // Disable event receiving + // This will also drop the contained event, if it exists, and will free up receiving the next event + self.runner.rx_event_channel.lock(|s| { + *s.borrow_mut() = None; + }); } } diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/mac/event.rs index 8415bc11..9ca4f5a2 100644 --- a/embassy-stm32-wpan/src/mac/event.rs +++ b/embassy-stm32-wpan/src/mac/event.rs @@ -144,6 +144,8 @@ impl<'a> MacEvent<'a> { } } +unsafe impl<'a> Send for MacEvent<'a> {} + impl<'a> Drop for MacEvent<'a> { fn drop(&mut self) { unsafe { mac::Mac::drop_event_packet(ptr::null_mut()) }; diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs index a93f7a69..c847a5cc 100644 --- a/embassy-stm32-wpan/src/mac/mod.rs +++ b/embassy-stm32-wpan/src/mac/mod.rs @@ -10,7 +10,7 @@ pub mod responses; pub mod runner; pub mod typedefs; -pub use crate::mac::control::{Control, Error as ControlError}; +pub use crate::mac::control::Control; use crate::mac::driver::Driver; pub use crate::mac::runner::Runner; diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index 007544c6..f964d6b3 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -1,6 +1,11 @@ +use core::cell::RefCell; + use embassy_futures::join; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex; +use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; use embassy_sync::channel::Channel; +use embassy_sync::mutex::Mutex; +use embassy_sync::signal::Signal; use crate::mac::commands::DataRequest; use crate::mac::event::MacEvent; @@ -9,7 +14,13 @@ use crate::mac::MTU; use crate::sub::mac::Mac; pub struct Runner<'a> { - mac_subsystem: Mac, + pub(crate) mac_subsystem: Mac, + + // rx event backpressure is already provided through the MacEvent drop mechanism + pub(crate) rx_event_channel: + blocking_mutex::Mutex>>>>, + pub(crate) read_mutex: Mutex, + pub(crate) write_mutex: Mutex, pub(crate) rx_channel: Channel, 1>, pub(crate) tx_channel: Channel, pub(crate) tx_buf_channel: Channel, @@ -19,6 +30,9 @@ impl<'a> Runner<'a> { pub fn new(mac: Mac, tx_buf_queue: [&'a mut [u8; MTU]; 5]) -> Self { let this = Self { mac_subsystem: mac, + rx_event_channel: blocking_mutex::Mutex::new(RefCell::new(None)), + read_mutex: Mutex::new(()), + write_mutex: Mutex::new(()), rx_channel: Channel::new(), tx_channel: Channel::new(), tx_buf_channel: Channel::new(), @@ -40,7 +54,16 @@ impl<'a> Runner<'a> { MacEvent::McpsDataInd(_) => { self.rx_channel.send(mac_event).await; } - _ => {} + _ => { + self.rx_event_channel.lock(|s| { + match &*s.borrow() { + Some(signal) => { + signal.signal(mac_event); + } + None => {} + }; + }); + } } } } @@ -50,7 +73,9 @@ impl<'a> Runner<'a> { loop { let (buf, len) = self.tx_channel.recv().await; + let _wm = self.write_mutex.lock().await; + // The mutex should be dropped on the next loop iteration self.mac_subsystem .send_command( DataRequest { From c675208b8a90bee39e99c8cd3bb620b99c439482 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 21 Jul 2023 16:10:34 -0500 Subject: [PATCH 14/15] wpan: complete prelim. command impl. --- embassy-stm32-wpan/src/mac/control.rs | 16 ++++++++++------ embassy-stm32-wpan/src/mac/runner.rs | 7 ++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs index fd8c22b2..ded41920 100644 --- a/embassy-stm32-wpan/src/mac/control.rs +++ b/embassy-stm32-wpan/src/mac/control.rs @@ -1,5 +1,6 @@ use core::future::Future; use core::task; +use core::task::Poll; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::MutexGuard; @@ -7,6 +8,7 @@ use embassy_sync::signal::Signal; use futures::FutureExt; use super::commands::MacCommand; +use super::event::MacEvent; use super::typedefs::MacError; use crate::mac::runner::Runner; @@ -62,10 +64,9 @@ impl<'a> EventToken<'a> { } impl<'a> Future for EventToken<'a> { - // TODO: output something - type Output = (); + type Output = MacEvent<'a>; - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll { + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { self.get_mut().runner.rx_event_channel.lock(|s| { let signal = s.borrow_mut(); let signal = match &*signal { @@ -73,10 +74,13 @@ impl<'a> Future for EventToken<'a> { _ => unreachable!(), }; - let _ = signal.wait().poll_unpin(cx); - }); + let result = match signal.wait().poll_unpin(cx) { + Poll::Ready(mac_event) => Poll::Ready(mac_event), + Poll::Pending => Poll::Pending, + }; - todo!() + result + }) } } diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index f964d6b3..482321b9 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -13,12 +13,13 @@ use crate::mac::typedefs::{AddressMode, MacAddress, PanId, SecurityLevel}; use crate::mac::MTU; use crate::sub::mac::Mac; +type ZeroCopyPubSub = blocking_mutex::Mutex>>>; + pub struct Runner<'a> { pub(crate) mac_subsystem: Mac, - // rx event backpressure is already provided through the MacEvent drop mechanism - pub(crate) rx_event_channel: - blocking_mutex::Mutex>>>>, + // therefore, we don't need to worry about overwriting events + pub(crate) rx_event_channel: ZeroCopyPubSub>, pub(crate) read_mutex: Mutex, pub(crate) write_mutex: Mutex, pub(crate) rx_channel: Channel, 1>, From f4d6a23f92c8f6d3eb97a09e5bc51bac5e8d6837 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 21 Jul 2023 17:02:36 -0500 Subject: [PATCH 15/15] wpan/mac: misc fixes --- embassy-stm32-wpan/src/mac/control.rs | 2 +- embassy-stm32-wpan/src/mac/responses.rs | 6 +++--- embassy-stm32-wpan/src/mac/runner.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs index ded41920..8a13de81 100644 --- a/embassy-stm32-wpan/src/mac/control.rs +++ b/embassy-stm32-wpan/src/mac/control.rs @@ -34,8 +34,8 @@ impl<'a> Control<'a> { where T: MacCommand, { - let _wm = self.runner.write_mutex.lock().await; let rm = self.runner.read_mutex.lock().await; + let _wm = self.runner.write_mutex.lock().await; let token = EventToken::new(self.runner, rm); self.runner.mac_subsystem.send_command(cmd).await?; diff --git a/embassy-stm32-wpan/src/mac/responses.rs b/embassy-stm32-wpan/src/mac/responses.rs index 9c407a36..544fdaae 100644 --- a/embassy-stm32-wpan/src/mac/responses.rs +++ b/embassy-stm32-wpan/src/mac/responses.rs @@ -87,7 +87,7 @@ impl ParseableMacEvent for GtsConfirm {} #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ResetConfirm { /// The result of the reset operation - status: MacStatus, + pub status: MacStatus, /// byte stuffing to keep 32 bit alignment a_stuffing: [u8; 3], } @@ -101,7 +101,7 @@ impl ParseableMacEvent for ResetConfirm {} #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct RxEnableConfirm { /// Result of the request to enable or disable the receiver - status: MacStatus, + pub status: MacStatus, /// byte stuffing to keep 32 bit alignment a_stuffing: [u8; 3], } @@ -197,7 +197,7 @@ impl ParseableMacEvent for DpsConfirm {} #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SoundingConfirm { /// Results of the sounding measurement - sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED], + pub sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED], status: u8, } diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index 482321b9..1be6df8a 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -95,7 +95,7 @@ impl<'a> Runner<'a> { .await .unwrap(); - msdu_handle += 1; + msdu_handle = msdu_handle.wrapping_add(1); // The tx channel should always be of equal capacity to the tx_buf channel self.tx_buf_channel.try_send(buf).unwrap();