Merge pull request #1658 from xoviat/mac

implement most infra for wpan mac
This commit is contained in:
xoviat 2023-07-21 22:29:15 +00:00 committed by GitHub
commit 4db63677f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 765 additions and 138 deletions

View File

@ -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 {

View File

@ -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]

View File

@ -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.",

View File

@ -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<D: Driver + 'static> Stack<D> {
resources: &'static mut StackResources<SOCK>,
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<D: Driver + 'static> Stack<D> {
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<D: Driver + 'static> Stack<D> {
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<D: Driver + 'static> Stack<D> {
next_local_port,
};
#[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))]
let mut inner = Inner {
device,
link_up: false,
@ -287,6 +295,9 @@ impl<D: Driver + 'static> Stack<D> {
dns_waker: WakerRegistration::new(),
};
#[cfg(feature = "medium-ieee802154")]
let _ = config;
#[cfg(feature = "proto-ipv4")]
match config.ipv4 {
ConfigV4::Static(config) => {

View File

@ -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 = { version = "0.1.0", path = "../embassy-net-driver", optional=true }
defmt = { version = "0.3", optional = true }
cortex-m = "0.7.6"
@ -26,13 +27,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"]
mac = ["dep:bitflags", "dep:embassy-net-driver" ]
stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]

View File

@ -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;

View File

@ -0,0 +1,95 @@
use core::future::Future;
use core::task;
use core::task::Poll;
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::event::MacEvent;
use super::typedefs::MacError;
use crate::mac::runner::Runner;
pub struct Control<'a> {
runner: &'a Runner<'a>,
}
impl<'a> Control<'a> {
pub(crate) fn new(runner: &'a Runner<'a>) -> Self {
Self { runner: runner }
}
pub async fn send_command<T>(&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<T>(&self, cmd: &T) -> Result<EventToken<'a>, MacError>
where
T: MacCommand,
{
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?;
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> {
type Output = MacEvent<'a>;
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
self.get_mut().runner.rx_event_channel.lock(|s| {
let signal = s.borrow_mut();
let signal = match &*signal {
Some(s) => s,
_ => unreachable!(),
};
let result = match signal.wait().poll_unpin(cx) {
Poll::Ready(mac_event) => Poll::Ready(mac_event),
Poll::Pending => Poll::Pending,
};
result
})
}
}
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;
});
}
}

View File

@ -0,0 +1,122 @@
#![allow(incomplete_features)]
#![deny(unused_must_use)]
use core::task::Context;
use embassy_net_driver::{Capabilities, LinkState, Medium};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use crate::mac::event::MacEvent;
use crate::mac::runner::Runner;
use crate::mac::MTU;
pub struct Driver<'d> {
runner: &'d Runner<'d>,
}
impl<'d> Driver<'d> {
pub(crate) fn new(runner: &'d Runner<'d>) -> Self {
Self { runner: runner }
}
}
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<'d> where Self: 'a;
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_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 {
None
}
}
fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
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
}
}
fn capabilities(&self) -> Capabilities {
let mut caps = Capabilities::default();
caps.max_transmission_unit = MTU;
// caps.max_burst_size = Some(self.tx.len());
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]
}
}
pub struct RxToken<'d> {
rx: &'d Channel<CriticalSectionRawMutex, MacEvent<'d>, 1>,
}
impl<'d> embassy_net_driver::RxToken for RxToken<'d> {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
// Only valid data events should be put into the queue
let data_event = match self.rx.try_recv().unwrap() {
MacEvent::McpsDataInd(data_event) => data_event,
_ => unreachable!(),
};
f(&mut data_event.payload())
}
}
pub struct TxToken<'d> {
tx: &'d Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), 5>,
tx_buf: &'d Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], 5>,
}
impl<'d> embassy_net_driver::TxToken for TxToken<'d> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
// 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, len)).unwrap();
r
}
}

View File

@ -1,4 +1,4 @@
use core::mem;
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,59 +22,8 @@ pub(crate) trait ParseableMacEvent: Sized {
}
}
pub struct Event {
event_box: EvtBox<Mac>,
}
impl Event {
pub(crate) fn new(event_box: EvtBox<Mac>) -> Self {
Self { event_box }
}
pub fn mac_event<'a>(&'a self) -> Result<MacEvent<'a>, ()> {
let payload = self.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)?))
}
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)?))
}
OpcodeM0ToM4::MlmeBeaconNotifyInd => {
Ok(MacEvent::MlmeBeaconNotifyInd(BeaconNotifyIndication::from_buffer(buf)?))
}
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)?)),
}
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug)]
pub enum MacEvent<'a> {
MlmeAssociateCnf(&'a AssociateConfirm),
MlmeDisassociateCnf(&'a DisassociateConfirm),
@ -102,3 +51,103 @@ pub enum MacEvent<'a> {
McpsDataInd(&'a DataIndication),
MlmePollInd(&'a PollIndication),
}
impl<'a> MacEvent<'a> {
pub(crate) fn new(event_box: EvtBox<Mac>) -> Result<Self, ()> {
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..];
// 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::MlmeDisassociateInd => {
MacEvent::MlmeDisassociateInd(unsafe { &*(DisassociateIndication::from_buffer(buf)? as *const _) })
}
OpcodeM0ToM4::MlmeBeaconNotifyInd => {
MacEvent::MlmeBeaconNotifyInd(unsafe { &*(BeaconNotifyIndication::from_buffer(buf)? as *const _) })
}
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 _) })
}
};
// Forget the event box so that drop isn't called
// We want to handle the lifetime ourselves
mem::forget(event_box);
Ok(mac_event)
}
}
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()) };
}
}

View File

@ -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
@ -236,14 +245,15 @@ 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) }
}
}
/// 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

View File

@ -1,8 +1,21 @@
pub mod commands;
mod consts;
pub mod control;
mod driver;
pub mod event;
pub mod indications;
mod macros;
mod opcodes;
pub mod responses;
pub mod runner;
pub mod typedefs;
pub use crate::mac::control::Control;
use crate::mac::driver::Driver;
pub use crate::mac::runner::Runner;
const MTU: usize = 127;
pub async fn new<'a>(runner: &'a Runner<'a>) -> (Control<'a>, Driver<'a>) {
(Control::new(runner), Driver::new(runner))
}

View File

@ -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,10 +83,11 @@ 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
status: MacStatus,
pub status: MacStatus,
/// byte stuffing to keep 32 bit alignment
a_stuffing: [u8; 3],
}
@ -92,10 +97,11 @@ 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
status: MacStatus,
pub status: MacStatus,
/// byte stuffing to keep 32 bit alignment
a_stuffing: [u8; 3],
}
@ -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,10 +193,11 @@ 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
sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED],
pub sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED],
status: u8,
}
@ -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

View File

@ -0,0 +1,109 @@
use core::cell::RefCell;
use embassy_futures::join;
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;
use crate::mac::typedefs::{AddressMode, MacAddress, PanId, SecurityLevel};
use crate::mac::MTU;
use crate::sub::mac::Mac;
type ZeroCopyPubSub<M, T> = blocking_mutex::Mutex<M, RefCell<Option<Signal<NoopRawMutex, T>>>>;
pub struct Runner<'a> {
pub(crate) mac_subsystem: Mac,
// rx event backpressure is already provided through the MacEvent drop mechanism
// therefore, we don't need to worry about overwriting events
pub(crate) rx_event_channel: ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>,
pub(crate) read_mutex: Mutex<CriticalSectionRawMutex, ()>,
pub(crate) write_mutex: Mutex<CriticalSectionRawMutex, ()>,
pub(crate) rx_channel: Channel<CriticalSectionRawMutex, MacEvent<'a>, 1>,
pub(crate) tx_channel: Channel<CriticalSectionRawMutex, (&'a mut [u8; MTU], usize), 5>,
pub(crate) tx_buf_channel: Channel<CriticalSectionRawMutex, &'a mut [u8; MTU], 5>,
}
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(),
};
for buf in tx_buf_queue {
this.tx_buf_channel.try_send(buf).unwrap();
}
this
}
pub async fn run(&'a self) -> ! {
join::join(
async {
loop {
if let Ok(mac_event) = self.mac_subsystem.read().await {
match mac_event {
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 => {}
};
});
}
}
}
}
},
async {
let mut msdu_handle = 0x02;
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 {
src_addr_mode: AddressMode::Short,
dst_addr_mode: AddressMode::Short,
dst_pan_id: PanId([0x1A, 0xAA]),
dst_address: MacAddress::BROADCAST,
msdu_handle: msdu_handle,
ack_tx: 0x00,
gts_tx: false,
security_level: SecurityLevel::Unsecure,
..Default::default()
}
.set_buffer(&buf[..len]),
)
.await
.unwrap();
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();
}
},
)
.await;
loop {}
}
}

View File

@ -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]);

View File

@ -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) -> Event {
Event::new(self.tl_read().await)
pub async fn read(&self) -> Result<MacEvent<'_>, ()> {
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::<bool>(
let _ = poll_once(Ipcc::receive::<()>(
channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL,
|| None,
));

View File

@ -335,6 +335,12 @@ impl<T, const N: usize> ChannelState<T, N> {
}
}
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<T>> {
self.try_send_with_context(message, None)
}
@ -353,6 +359,12 @@ impl<T, const N: usize> ChannelState<T, N> {
}
}
}
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 }

View File

@ -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"
@ -20,11 +21,11 @@ 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"]
mac = ["embassy-stm32-wpan/mac"]
mac = ["embassy-stm32-wpan/mac", "dep:embassy-net"]
ble = ["embassy-stm32-wpan/ble"]
[[bin]]
@ -39,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"]

View File

@ -73,10 +73,7 @@ async fn main(spawner: Spawner) {
})
.await
.unwrap();
{
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt.mac_event());
}
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;
defmt::info!("{:#x}", evt.mac_event());
}
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;
defmt::info!("{:#x}", evt.mac_event());
}
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;
defmt::info!("{:#x}", evt.mac_event());
}
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;
defmt::info!("{:#x}", evt.mac_event());
}
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;
defmt::info!("{:#x}", evt.mac_event());
}
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
info!("setting RX on when idle");
let rx_on_while_idle: bool = true;
@ -161,14 +143,11 @@ async fn main(spawner: Spawner) {
})
.await
.unwrap();
{
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt.mac_event());
}
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
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);

View File

@ -0,0 +1,170 @@
#![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::{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;
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<'static>) {
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();
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
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();
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
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();
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
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();
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
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();
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
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();
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
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();
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
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();
let (driver, control) = mac::new(runner).await;
let _ = driver;
let _ = control;
}

View File

@ -75,10 +75,7 @@ async fn main(spawner: Spawner) {
})
.await
.unwrap();
{
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt.mac_event());
}
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;
defmt::info!("{:#x}", evt.mac_event());
}
defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
info!("getting extended address");
mbox.mac_subsystem
@ -104,10 +98,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 +126,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 +145,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 +169,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,
};
}
}

View File

@ -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,13 @@ 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 = if let MacEvent::MlmeAssociateCnf(conf) = mbox.mac_subsystem.read().await.unwrap() {
conf.assoc_short_address
} else {
defmt::panic!()
};
info!("{}", short_addr);
info!("Test OK");
cortex_m::asm::bkpt();