From 4db4200c37c191f4ec018dd318e805aa805d9cc3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 15 Jul 2023 14:47:34 -0500 Subject: wpan: factor mac logic into other mod --- embassy-stm32-wpan/src/lib.rs | 3 + embassy-stm32-wpan/src/mac/commands.rs | 467 +++++++++++++++++++++++++ embassy-stm32-wpan/src/mac/consts.rs | 4 + embassy-stm32-wpan/src/mac/event.rs | 94 ++++++ embassy-stm32-wpan/src/mac/helpers.rs | 7 + embassy-stm32-wpan/src/mac/indications.rs | 470 ++++++++++++++++++++++++++ embassy-stm32-wpan/src/mac/macros.rs | 32 ++ embassy-stm32-wpan/src/mac/mod.rs | 9 + embassy-stm32-wpan/src/mac/opcodes.rs | 92 +++++ embassy-stm32-wpan/src/mac/responses.rs | 433 ++++++++++++++++++++++++ embassy-stm32-wpan/src/mac/typedefs.rs | 363 ++++++++++++++++++++ embassy-stm32-wpan/src/sub/mac.rs | 133 ++++++++ embassy-stm32-wpan/src/sub/mac/commands.rs | 467 ------------------------- embassy-stm32-wpan/src/sub/mac/consts.rs | 4 - embassy-stm32-wpan/src/sub/mac/event.rs | 94 ------ embassy-stm32-wpan/src/sub/mac/helpers.rs | 7 - embassy-stm32-wpan/src/sub/mac/indications.rs | 470 -------------------------- embassy-stm32-wpan/src/sub/mac/macros.rs | 32 -- embassy-stm32-wpan/src/sub/mac/mod.rs | 143 -------- embassy-stm32-wpan/src/sub/mac/opcodes.rs | 92 ----- embassy-stm32-wpan/src/sub/mac/responses.rs | 433 ------------------------ embassy-stm32-wpan/src/sub/mac/typedefs.rs | 363 -------------------- examples/stm32wb/src/bin/mac_ffd.rs | 6 +- examples/stm32wb/src/bin/mac_rfd.rs | 6 +- tests/stm32/src/bin/wpan_mac.rs | 6 +- 25 files changed, 2116 insertions(+), 2114 deletions(-) create mode 100644 embassy-stm32-wpan/src/mac/commands.rs create mode 100644 embassy-stm32-wpan/src/mac/consts.rs create mode 100644 embassy-stm32-wpan/src/mac/event.rs create mode 100644 embassy-stm32-wpan/src/mac/helpers.rs create mode 100644 embassy-stm32-wpan/src/mac/indications.rs create mode 100644 embassy-stm32-wpan/src/mac/macros.rs create mode 100644 embassy-stm32-wpan/src/mac/mod.rs create mode 100644 embassy-stm32-wpan/src/mac/opcodes.rs create mode 100644 embassy-stm32-wpan/src/mac/responses.rs create mode 100644 embassy-stm32-wpan/src/mac/typedefs.rs create mode 100644 embassy-stm32-wpan/src/sub/mac.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/commands.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/consts.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/event.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/helpers.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/indications.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/macros.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/mod.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/opcodes.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/responses.rs delete mode 100644 embassy-stm32-wpan/src/sub/mac/typedefs.rs diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 3a45c5978..57f0dc4fa 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -26,6 +26,9 @@ pub mod sub; pub mod tables; pub mod unsafe_linked_list; +#[cfg(feature = "mac")] +pub mod mac; + #[cfg(feature = "ble")] pub use crate::sub::ble::hci; diff --git a/embassy-stm32-wpan/src/mac/commands.rs b/embassy-stm32-wpan/src/mac/commands.rs new file mode 100644 index 000000000..8cfa0a054 --- /dev/null +++ b/embassy-stm32-wpan/src/mac/commands.rs @@ -0,0 +1,467 @@ +use super::opcodes::OpcodeM4ToM0; +use super::typedefs::{ + AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus, + PanId, PibId, ScanType, SecurityLevel, +}; + +pub trait MacCommand { + const OPCODE: OpcodeM4ToM0; + const SIZE: usize; + + fn copy_into_slice(&self, buf: &mut [u8]) { + unsafe { core::ptr::copy(self as *const _ as *const u8, buf as *mut _ as *mut u8, Self::SIZE) }; + } +} + +/// MLME ASSOCIATE Request used to request an association +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct AssociateRequest { + /// the logical channel on which to attempt association + pub channel_number: MacChannel, + /// the channel page on which to attempt association + pub channel_page: u8, + /// coordinator addressing mode + pub coord_addr_mode: AddressMode, + /// operational capabilities of the associating device + pub capability_information: Capabilities, + /// the identifier of the PAN with which to associate + pub coord_pan_id: PanId, + /// the security level to be used + pub security_level: SecurityLevel, + /// the mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// the originator of the key to be used + pub key_source: [u8; 8], + /// Coordinator address + pub coord_address: MacAddress, + /// the index of the key to be used + pub key_index: u8, +} + +impl MacCommand for AssociateRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateReq; + const SIZE: usize = 25; +} + +/// MLME DISASSOCIATE Request sed to request a disassociation +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DisassociateRequest { + /// device addressing mode used + pub device_addr_mode: AddressMode, + /// the identifier of the PAN of the device + pub device_pan_id: PanId, + /// the reason for the disassociation + pub disassociation_reason: DisassociationReason, + /// device address + pub device_address: MacAddress, + /// `true` if the disassociation notification command is to be sent indirectly + pub tx_indirect: bool, + /// the security level to be used + pub security_level: SecurityLevel, + /// the mode to be used to indetify the key to be used + pub key_id_mode: KeyIdMode, + /// the index of the key to be used + pub key_index: u8, + /// the originator of the key to be used + pub key_source: [u8; 8], +} + +impl MacCommand for DisassociateRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDisassociateReq; + const SIZE: usize = 24; +} + +/// MLME GET Request used to request a PIB value +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct GetRequest { + /// the name of the PIB attribute to read + pub pib_attribute: PibId, +} + +impl MacCommand for GetRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq; + const SIZE: usize = 4; +} + +/// MLME GTS Request used to request and maintain GTSs +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct GtsRequest { + /// the characteristics of the GTS + pub characteristics: GtsCharacteristics, + /// the security level to be used + pub security_level: SecurityLevel, + /// the mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// the index of the key to be used + pub key_index: u8, + /// the originator of the key to be used + pub key_source: [u8; 8], +} + +impl MacCommand for GtsRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq; + const SIZE: usize = 12; +} + +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ResetRequest { + /// MAC PIB attributes are set to their default values or not during reset + pub set_default_pib: bool, +} + +impl MacCommand for ResetRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeResetReq; + const SIZE: usize = 4; +} + +/// MLME RX ENABLE Request used to request that the receiver is either enabled +/// for a finite period of time or disabled +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct RxEnableRequest { + /// the request operation can be deferred or not + pub defer_permit: bool, + /// configure the transceiver to RX with ranging for a value of + /// RANGING_ON or to not enable ranging for RANGING_OFF + pub ranging_rx_control: u8, + /// number of symbols measured before the receiver is to be enabled or disabled + pub rx_on_time: [u8; 4], + /// number of symbols for which the receiver is to be enabled + pub rx_on_duration: [u8; 4], +} + +impl MacCommand for RxEnableRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeRxEnableReq; + const SIZE: usize = 12; + + fn copy_into_slice(&self, buf: &mut [u8]) { + buf[0] = self.defer_permit as u8; + buf[1] = self.ranging_rx_control as u8; + + // stuffing to keep 32bit alignment + buf[2] = 0; + buf[3] = 0; + + buf[4..8].copy_from_slice(&self.rx_on_time); + buf[8..12].copy_from_slice(&self.rx_on_duration); + } +} + +/// MLME SCAN Request used to initiate a channel scan over a given list of channels +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ScanRequest { + /// the type of scan to be performed + pub scan_type: ScanType, + /// the time spent on scanning each channel + pub scan_duration: u8, + /// channel page on which to perform the scan + pub channel_page: u8, + /// security level to be used + pub security_level: SecurityLevel, + /// indicate which channels are to be scanned + pub scan_channels: [u8; 4], + /// originator the key to be used + pub key_source: [u8; 8], + /// mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// index of the key to be used + pub key_index: u8, +} + +impl MacCommand for ScanRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeScanReq; + const SIZE: usize = 20; +} + +/// MLME SET Request used to attempt to write the given value to the indicated PIB attribute +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct SetRequest { + /// the pointer to the value of the PIB attribute to set + pub pib_attribute_ptr: *const u8, + /// the name of the PIB attribute to set + pub pib_attribute: PibId, +} + +impl MacCommand for SetRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSetReq; + const SIZE: usize = 8; +} + +/// MLME START Request used by the FFDs to intiate a new PAN or to begin using a new superframe +/// configuration +#[derive(Default)] +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct StartRequest { + /// PAN indentifier to used by the device + pub pan_id: PanId, + /// logical channel on which to begin + pub channel_number: MacChannel, + /// channel page on which to begin + pub channel_page: u8, + /// time at which to begin transmitting beacons + pub start_time: [u8; 4], + /// indicated how often the beacon is to be transmitted + pub beacon_order: u8, + /// length of the active portion of the superframe + pub superframe_order: u8, + /// indicated wheter the device is a PAN coordinator or not + pub pan_coordinator: bool, + /// indicates if the receiver of the beaconing device is disabled or not + pub battery_life_extension: bool, + /// indicated if the coordinator realignment command is to be trasmitted + pub coord_realignment: u8, + /// indicated if the coordinator realignment command is to be trasmitted + pub coord_realign_security_level: SecurityLevel, + /// index of the key to be used + pub coord_realign_key_id_index: u8, + /// originator of the key to be used + pub coord_realign_key_source: [u8; 8], + /// security level to be used for beacon frames + pub beacon_security_level: SecurityLevel, + /// mode used to identify the key to be used + pub beacon_key_id_mode: KeyIdMode, + /// index of the key to be used + pub beacon_key_index: u8, + /// originator of the key to be used + pub beacon_key_source: [u8; 8], +} + +impl MacCommand for StartRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeStartReq; + const SIZE: usize = 35; +} + +/// MLME SYNC Request used to synchronize with the coordinator by acquiring and, if +/// specified, tracking its beacons +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct SyncRequest { + /// the channel number on which to attempt coordinator synchronization + pub channel_number: MacChannel, + /// the channel page on which to attempt coordinator synchronization + pub channel_page: u8, + /// `true` if the MLME is to synchronize with the next beacon and attempts + /// to track all future beacons. + /// + /// `false` if the MLME is to synchronize with only the next beacon + pub track_beacon: bool, +} + +impl MacCommand for SyncRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSyncReq; + const SIZE: usize = 4; +} + +/// MLME POLL Request propmts the device to request data from the coordinator +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PollRequest { + /// addressing mode of the coordinator + pub coord_addr_mode: AddressMode, + /// security level to be used + pub security_level: SecurityLevel, + /// mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// index of the key to be used + pub key_index: u8, + /// coordinator address + pub coord_address: MacAddress, + /// originator of the key to be used + pub key_source: [u8; 8], + /// PAN identifier of the coordinator + pub coord_pan_id: PanId, +} + +impl MacCommand for PollRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmePollReq; + const SIZE: usize = 24; +} + +/// MLME DPS Request allows the next higher layer to request that the PHY utilize a +/// given pair of preamble codes for a single use pending expiration of the DPSIndexDuration +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DpsRequest { + /// the index value for the transmitter + tx_dps_index: u8, + /// the index value of the receiver + rx_dps_index: u8, + /// the number of symbols for which the transmitter and receiver will utilize the + /// respective DPS indices + dps_index_duration: u8, +} + +impl MacCommand for DpsRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDpsReq; + const SIZE: usize = 4; +} + +/// MLME SOUNDING request primitive which is used by the next higher layer to request that +/// the PHY respond with channel sounding information +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct SoundingRequest; + +impl MacCommand for SoundingRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSoundingReq; + const SIZE: usize = 4; +} + +/// MLME CALIBRATE request primitive which used to obtain the results of a ranging +/// calibration request from an RDEV +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct CalibrateRequest; + +impl MacCommand for CalibrateRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeCalibrateReq; + const SIZE: usize = 4; +} + +/// MCPS DATA Request used for MAC data related requests from the application +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DataRequest { + /// the handle assocated with the MSDU to be transmitted + pub msdu_ptr: *const u8, + /// source addressing mode used + pub src_addr_mode: AddressMode, + /// destination addressing mode used + pub dst_addr_mode: AddressMode, + /// destination PAN Id + pub dst_pan_id: PanId, + /// destination address + pub dst_address: MacAddress, + /// the number of octets contained in the MSDU + pub msdu_length: u8, + /// the handle assocated with the MSDU to be transmitted + pub msdu_handle: u8, + /// the ACK transmittion options for the MSDU + pub ack_tx: u8, + /// `true` if a GTS is to be used for transmission + /// + /// `false` indicates that the CAP will be used + pub gts_tx: bool, + /// the pending bit transmission options for the MSDU + pub indirect_tx: u8, + /// the security level to be used + pub security_level: SecurityLevel, + /// the mode used to indentify the key to be used + pub key_id_mode: KeyIdMode, + /// the index of the key to be used + pub key_index: u8, + /// the originator of the key to be used + pub key_source: [u8; 8], + /// 2011 - the pulse repitition value + pub uwbprf: u8, + /// 2011 - the ranging configuration + pub ranging: u8, + /// 2011 - the preamble symbol repititions + pub uwb_preamble_symbol_repetitions: u8, + /// 2011 - indicates the data rate + pub datrate: u8, +} + +impl Default for DataRequest { + fn default() -> Self { + Self { + msdu_ptr: 0 as *const u8, + src_addr_mode: AddressMode::NoAddress, + dst_addr_mode: AddressMode::NoAddress, + dst_pan_id: PanId([0, 0]), + dst_address: MacAddress { short: [0, 0] }, + msdu_length: 0, + msdu_handle: 0, + ack_tx: 0, + gts_tx: false, + indirect_tx: 0, + security_level: SecurityLevel::Unsecure, + key_id_mode: KeyIdMode::Implicite, + key_index: 0, + key_source: [0u8; 8], + uwbprf: 0, + ranging: 0, + uwb_preamble_symbol_repetitions: 0, + datrate: 0, + } + } +} + +impl MacCommand for DataRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsDataReq; + const SIZE: usize = 40; +} + +/// for MCPS PURGE Request used to purge an MSDU from the transaction queue +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PurgeRequest { + /// the handle associated with the MSDU to be purged from the transaction + /// queue + pub msdu_handle: u8, +} + +impl MacCommand for PurgeRequest { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsPurgeReq; + const SIZE: usize = 4; +} + +/// MLME ASSOCIATE Response used to initiate a response to an MLME-ASSOCIATE.indication +#[repr(C)] +#[derive(Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct AssociateResponse { + /// extended address of the device requesting association + pub device_address: [u8; 8], + /// 16-bitshort device address allocated by the coordinator on successful + /// association + pub assoc_short_address: [u8; 2], + /// status of the association attempt + pub status: MacStatus, + /// security level to be used + pub security_level: SecurityLevel, + /// the originator of the key to be used + pub key_source: [u8; 8], + /// the mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// the index of the key to be used + pub key_index: u8, +} + +impl MacCommand for AssociateResponse { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateRes; + const SIZE: usize = 24; +} + +/// MLME ORPHAN Response used to respond to the MLME ORPHAN Indication +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OrphanResponse { + /// extended address of the orphaned device + pub orphan_address: [u8; 8], + /// short address allocated to the orphaned device + pub short_address: [u8; 2], + /// if the orphaned device is associated with coordinator or not + pub associated_member: bool, + /// security level to be used + pub security_level: SecurityLevel, + /// the originator of the key to be used + pub key_source: [u8; 8], + /// the mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// the index of the key to be used + pub key_index: u8, +} + +impl MacCommand for OrphanResponse { + const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeOrphanRes; + const SIZE: usize = 24; +} diff --git a/embassy-stm32-wpan/src/mac/consts.rs b/embassy-stm32-wpan/src/mac/consts.rs new file mode 100644 index 000000000..56903d980 --- /dev/null +++ b/embassy-stm32-wpan/src/mac/consts.rs @@ -0,0 +1,4 @@ +pub const MAX_PAN_DESC_SUPPORTED: usize = 6; +pub const MAX_SOUNDING_LIST_SUPPORTED: usize = 6; +pub const MAX_PENDING_ADDRESS: usize = 7; +pub const MAX_ED_SCAN_RESULTS_SUPPORTED: usize = 16; diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/mac/event.rs new file mode 100644 index 000000000..dfce21fea --- /dev/null +++ b/embassy-stm32-wpan/src/mac/event.rs @@ -0,0 +1,94 @@ +use super::helpers::to_u16; +use super::indications::{ + AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication, + DpsIndication, GtsIndication, OrphanIndication, PollIndication, SyncLossIndication, +}; +use super::responses::{ + AssociateConfirm, CalibrateConfirm, DataConfirm, DisassociateConfirm, DpsConfirm, GetConfirm, GtsConfirm, + PollConfirm, PurgeConfirm, ResetConfirm, RxEnableConfirm, ScanConfirm, SetConfirm, SoundingConfirm, StartConfirm, +}; +use crate::mac::opcodes::OpcodeM0ToM4; + +pub trait ParseableMacEvent { + const SIZE: usize; + + fn validate(buf: &[u8]) -> Result<(), ()> { + if buf.len() < Self::SIZE { + return Err(()); + } + + Ok(()) + } + + fn try_parse(buf: &[u8]) -> Result + where + Self: Sized; +} + +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum MacEvent { + MlmeAssociateCnf(AssociateConfirm), + MlmeDisassociateCnf(DisassociateConfirm), + MlmeGetCnf(GetConfirm), + MlmeGtsCnf(GtsConfirm), + MlmeResetCnf(ResetConfirm), + MlmeRxEnableCnf(RxEnableConfirm), + MlmeScanCnf(ScanConfirm), + MlmeSetCnf(SetConfirm), + MlmeStartCnf(StartConfirm), + MlmePollCnf(PollConfirm), + MlmeDpsCnf(DpsConfirm), + MlmeSoundingCnf(SoundingConfirm), + MlmeCalibrateCnf(CalibrateConfirm), + McpsDataCnf(DataConfirm), + McpsPurgeCnf(PurgeConfirm), + MlmeAssociateInd(AssociateIndication), + MlmeDisassociateInd(DisassociateIndication), + MlmeBeaconNotifyInd(BeaconNotifyIndication), + MlmeCommStatusInd(CommStatusIndication), + MlmeGtsInd(GtsIndication), + MlmeOrphanInd(OrphanIndication), + MlmeSyncLossInd(SyncLossIndication), + MlmeDpsInd(DpsIndication), + McpsDataInd(DataIndication), + MlmePollInd(PollIndication), +} + +impl TryFrom<&[u8]> for MacEvent { + type Error = (); + + fn try_from(value: &[u8]) -> Result { + let opcode = to_u16(&value[0..2]); + let opcode = OpcodeM0ToM4::try_from(opcode)?; + + let buf = &value[2..]; + + match opcode { + OpcodeM0ToM4::MlmeAssociateCnf => Ok(Self::MlmeAssociateCnf(AssociateConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeDisassociateCnf => Ok(Self::MlmeDisassociateCnf(DisassociateConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeGetCnf => Ok(Self::MlmeGetCnf(GetConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeGtsCnf => Ok(Self::MlmeGtsCnf(GtsConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeResetCnf => Ok(Self::MlmeResetCnf(ResetConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeRxEnableCnf => Ok(Self::MlmeRxEnableCnf(RxEnableConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeScanCnf => Ok(Self::MlmeScanCnf(ScanConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeSetCnf => Ok(Self::MlmeSetCnf(SetConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeStartCnf => Ok(Self::MlmeStartCnf(StartConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmePollCnf => Ok(Self::MlmePollCnf(PollConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeDpsCnf => Ok(Self::MlmeDpsCnf(DpsConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeSoundingCnf => Ok(Self::MlmeSoundingCnf(SoundingConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeCalibrateCnf => Ok(Self::MlmeCalibrateCnf(CalibrateConfirm::try_parse(buf)?)), + OpcodeM0ToM4::McpsDataCnf => Ok(Self::McpsDataCnf(DataConfirm::try_parse(buf)?)), + OpcodeM0ToM4::McpsPurgeCnf => Ok(Self::McpsPurgeCnf(PurgeConfirm::try_parse(buf)?)), + OpcodeM0ToM4::MlmeAssociateInd => Ok(Self::MlmeAssociateInd(AssociateIndication::try_parse(buf)?)), + OpcodeM0ToM4::MlmeDisassociateInd => Ok(Self::MlmeDisassociateInd(DisassociateIndication::try_parse(buf)?)), + OpcodeM0ToM4::MlmeBeaconNotifyInd => Ok(Self::MlmeBeaconNotifyInd(BeaconNotifyIndication::try_parse(buf)?)), + OpcodeM0ToM4::MlmeCommStatusInd => Ok(Self::MlmeCommStatusInd(CommStatusIndication::try_parse(buf)?)), + OpcodeM0ToM4::MlmeGtsInd => Ok(Self::MlmeGtsInd(GtsIndication::try_parse(buf)?)), + OpcodeM0ToM4::MlmeOrphanInd => Ok(Self::MlmeOrphanInd(OrphanIndication::try_parse(buf)?)), + OpcodeM0ToM4::MlmeSyncLossInd => Ok(Self::MlmeSyncLossInd(SyncLossIndication::try_parse(buf)?)), + OpcodeM0ToM4::MlmeDpsInd => Ok(Self::MlmeDpsInd(DpsIndication::try_parse(buf)?)), + OpcodeM0ToM4::McpsDataInd => Ok(Self::McpsDataInd(DataIndication::try_parse(buf)?)), + OpcodeM0ToM4::MlmePollInd => Ok(Self::MlmePollInd(PollIndication::try_parse(buf)?)), + } + } +} diff --git a/embassy-stm32-wpan/src/mac/helpers.rs b/embassy-stm32-wpan/src/mac/helpers.rs new file mode 100644 index 000000000..5a5bf8a85 --- /dev/null +++ b/embassy-stm32-wpan/src/mac/helpers.rs @@ -0,0 +1,7 @@ +pub fn to_u16(buf: &[u8]) -> u16 { + ((buf[1] as u16) << 8) | buf[0] as u16 +} + +pub fn to_u32(buf: &[u8]) -> u32 { + ((buf[0] as u32) << 0) + ((buf[1] as u32) << 8) + ((buf[2] as u32) << 16) + ((buf[3] as u32) << 24) +} diff --git a/embassy-stm32-wpan/src/mac/indications.rs b/embassy-stm32-wpan/src/mac/indications.rs new file mode 100644 index 000000000..6df4aa23a --- /dev/null +++ b/embassy-stm32-wpan/src/mac/indications.rs @@ -0,0 +1,470 @@ +use super::consts::MAX_PENDING_ADDRESS; +use super::event::ParseableMacEvent; +use super::helpers::to_u32; +use super::typedefs::{ + AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor, + PanId, SecurityLevel, +}; + +/// MLME ASSOCIATE Indication which will be used by the MAC +/// to indicate the reception of an association request command +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct AssociateIndication { + /// Extended address of the device requesting association + pub device_address: [u8; 8], + /// Operational capabilities of the device requesting association + pub capability_information: Capabilities, + /// Security level purportedly used by the received MAC command frame + pub security_level: SecurityLevel, + /// The mode used to identify the key used by the originator of frame + pub key_id_mode: KeyIdMode, + /// Index of the key used by the originator of the received frame + pub key_index: u8, + /// The originator of the key used by the originator of the received frame + pub key_source: [u8; 8], +} + +impl ParseableMacEvent for AssociateIndication { + const SIZE: usize = 20; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]], + capability_information: Capabilities::from_bits(buf[8]).ok_or(())?, + security_level: SecurityLevel::try_from(buf[9])?, + key_id_mode: KeyIdMode::try_from(buf[10])?, + key_index: buf[11], + key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]], + }) + } +} + +/// MLME DISASSOCIATE indication which will be used to send +/// disassociation indication to the application. +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DisassociateIndication { + /// Extended address of the device requesting association + pub device_address: [u8; 8], + /// The reason for the disassociation + pub disassociation_reason: DisassociationReason, + /// The security level to be used + pub security_level: SecurityLevel, + /// The mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// The index of the key to be used + pub key_index: u8, + /// The originator of the key to be used + pub key_source: [u8; 8], +} + +impl ParseableMacEvent for DisassociateIndication { + const SIZE: usize = 20; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]], + disassociation_reason: DisassociationReason::try_from(buf[8])?, + security_level: SecurityLevel::try_from(buf[9])?, + key_id_mode: KeyIdMode::try_from(buf[10])?, + key_index: buf[11], + key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]], + }) + } +} + +/// MLME BEACON NOTIIFY Indication which is used to send parameters contained +/// within a beacon frame received by the MAC to the application +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct BeaconNotifyIndication { + /// he set of octets comprising the beacon payload to be transferred + /// from the MAC sublayer entity to the next higher layer + pub sdu_ptr: *const u8, + /// The PAN Descriptor for the received beacon + pub pan_descriptor: PanDescriptor, + /// The list of addresses of the devices + pub addr_list: [MacAddress; MAX_PENDING_ADDRESS], + /// Beacon Sequence Number + pub bsn: u8, + /// The beacon pending address specification + pub pend_addr_spec: u8, + /// Number of octets contained in the beacon payload of the beacon frame + pub sdu_length: u8, +} + +impl ParseableMacEvent for BeaconNotifyIndication { + const SIZE: usize = 88; + + fn try_parse(buf: &[u8]) -> Result { + // TODO: this is unchecked + + Self::validate(buf)?; + + let addr_list = [ + MacAddress::try_from(&buf[26..34])?, + MacAddress::try_from(&buf[34..42])?, + MacAddress::try_from(&buf[42..50])?, + MacAddress::try_from(&buf[50..58])?, + MacAddress::try_from(&buf[58..66])?, + MacAddress::try_from(&buf[66..74])?, + MacAddress::try_from(&buf[74..82])?, + ]; + + Ok(Self { + sdu_ptr: to_u32(&buf[0..4]) as *const u8, + pan_descriptor: PanDescriptor::try_from(&buf[4..26])?, + addr_list, + bsn: buf[82], + pend_addr_spec: buf[83], + sdu_length: buf[83], + }) + } +} + +/// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct CommStatusIndication { + /// The 16-bit PAN identifier of the device from which the frame + /// was received or to which the frame was being sent + pub pan_id: PanId, + /// Source addressing mode + pub src_addr_mode: AddressMode, + /// Destination addressing mode + pub dst_addr_mode: AddressMode, + /// Source address + pub src_address: MacAddress, + /// Destination address + pub dst_address: MacAddress, + /// The communications status + pub status: MacStatus, + /// Security level to be used + pub security_level: SecurityLevel, + /// Mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// Index of the key to be used + pub key_index: u8, + /// Originator of the key to be used + pub key_source: [u8; 8], +} + +impl ParseableMacEvent for CommStatusIndication { + const SIZE: usize = 32; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + let src_addr_mode = AddressMode::try_from(buf[2])?; + let dst_addr_mode = AddressMode::try_from(buf[3])?; + + let src_address = match src_addr_mode { + AddressMode::NoAddress => MacAddress { short: [0, 0] }, + AddressMode::Reserved => MacAddress { short: [0, 0] }, + AddressMode::Short => MacAddress { + short: [buf[4], buf[5]], + }, + AddressMode::Extended => MacAddress { + extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]], + }, + }; + + let dst_address = match dst_addr_mode { + AddressMode::NoAddress => MacAddress { short: [0, 0] }, + AddressMode::Reserved => MacAddress { short: [0, 0] }, + AddressMode::Short => MacAddress { + short: [buf[12], buf[13]], + }, + AddressMode::Extended => MacAddress { + extended: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]], + }, + }; + + Ok(Self { + pan_id: PanId([buf[0], buf[1]]), + src_addr_mode, + dst_addr_mode, + src_address, + dst_address, + status: MacStatus::try_from(buf[20])?, + security_level: SecurityLevel::try_from(buf[21])?, + key_id_mode: KeyIdMode::try_from(buf[22])?, + key_index: buf[23], + key_source: [buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]], + }) + } +} + +/// MLME GTS Indication indicates that a GTS has been allocated or that a +/// previously allocated GTS has been deallocated +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct GtsIndication { + /// The short address of the device that has been allocated or deallocated a GTS + pub device_address: [u8; 2], + /// The characteristics of the GTS + pub gts_characteristics: u8, + /// Security level to be used + pub security_level: SecurityLevel, + /// Mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// Index of the key to be used + pub key_index: u8, + /// Originator of the key to be used + pub key_source: [u8; 8], +} + +impl ParseableMacEvent for GtsIndication { + const SIZE: usize = 16; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + device_address: [buf[0], buf[1]], + gts_characteristics: buf[2], + security_level: SecurityLevel::try_from(buf[3])?, + key_id_mode: KeyIdMode::try_from(buf[4])?, + key_index: buf[5], + // 2 byte stuffing + key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]], + }) + } +} + +/// MLME ORPHAN Indication which is used by the coordinator to notify the +/// application of the presence of an orphaned device +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OrphanIndication { + /// Extended address of the orphaned device + pub orphan_address: [u8; 8], + /// Originator of the key used by the originator of the received frame + pub key_source: [u8; 8], + /// Security level purportedly used by the received MAC command frame + pub security_level: SecurityLevel, + /// Mode used to identify the key used by originator of received frame + pub key_id_mode: KeyIdMode, + /// Index of the key used by the originator of the received frame + pub key_index: u8, +} + +impl ParseableMacEvent for OrphanIndication { + const SIZE: usize = 20; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + orphan_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]], + key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]], + security_level: SecurityLevel::try_from(buf[16])?, + key_id_mode: KeyIdMode::try_from(buf[17])?, + key_index: buf[18], + // 1 byte stuffing + }) + } +} + +/// MLME SYNC LOSS Indication which is used by the MAC to indicate the loss +/// of synchronization with the coordinator +#[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 + pub pan_id: PanId, + /// The reason that synchronization was lost + pub loss_reason: u8, + /// The logical channel on which the device lost synchronization or to whi + pub channel_number: MacChannel, + /// The channel page on which the device lost synchronization or to which + pub channel_page: u8, + /// The security level used by the received MAC frame + pub security_level: SecurityLevel, + /// Mode used to identify the key used by originator of received frame + pub key_id_mode: KeyIdMode, + /// Index of the key used by the originator of the received frame + pub key_index: u8, + /// Originator of the key used by the originator of the received frame + pub key_source: [u8; 8], +} + +impl ParseableMacEvent for SyncLossIndication { + const SIZE: usize = 16; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + pan_id: PanId([buf[0], buf[1]]), + loss_reason: buf[2], + channel_number: MacChannel::try_from(buf[3])?, + channel_page: buf[4], + security_level: SecurityLevel::try_from(buf[5])?, + key_id_mode: KeyIdMode::try_from(buf[6])?, + key_index: buf[7], + key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]], + }) + } +} + +/// MLME DPS Indication which indicates the expiration of the DPSIndexDuration +/// and the resetting of the DPS values in the PHY +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DpsIndication; + +impl ParseableMacEvent for DpsIndication { + const SIZE: usize = 4; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self) + } +} + +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C, align(8))] +pub struct DataIndication { + /// Pointer to the set of octets forming the MSDU being indicated + pub msdu_ptr: *const u8, + /// Source addressing mode used + pub src_addr_mode: AddressMode, + /// Source PAN ID + pub src_pan_id: PanId, + /// Source address + pub src_address: MacAddress, + /// Destination addressing mode used + pub dst_addr_mode: AddressMode, + /// Destination PAN ID + pub dst_pan_id: PanId, + /// Destination address + pub dst_address: MacAddress, + /// The number of octets contained in the MSDU being indicated + pub msdu_length: u8, + /// QI value measured during reception of the MPDU + pub mpdu_link_quality: u8, + /// The data sequence number of the received data frame + pub dsn: u8, + /// The time, in symbols, at which the data were received + pub time_stamp: [u8; 4], + /// The security level purportedly used by the received data frame + pub security_level: SecurityLevel, + /// Mode used to identify the key used by originator of received frame + pub key_id_mode: KeyIdMode, + /// The originator of the key + pub key_source: [u8; 8], + /// The index of the key + pub key_index: u8, + /// he pulse repetition value of the received PPDU + pub uwbprf: u8, + /// The preamble symbol repetitions of the UWB PHY frame + pub uwn_preamble_symbol_repetitions: u8, + /// Indicates the data rate + pub datrate: u8, + /// time units corresponding to an RMARKER at the antenna at the end of a ranging exchange, + pub ranging_received: u8, + pub ranging_counter_start: u32, + pub ranging_counter_stop: u32, + /// ime units in a message exchange over which the tracking offset was measured + pub ranging_tracking_interval: u32, + /// time units slipped or advanced by the radio tracking system + pub ranging_offset: u32, + /// The FoM characterizing the ranging measurement + pub ranging_fom: u8, + /// The Received Signal Strength Indicator measured + pub rssi: u8, +} + +impl ParseableMacEvent for DataIndication { + const SIZE: usize = 68; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + let src_addr_mode = AddressMode::try_from(buf[4])?; + let src_address = match src_addr_mode { + AddressMode::NoAddress => MacAddress { short: [0, 0] }, + AddressMode::Reserved => MacAddress { short: [0, 0] }, + AddressMode::Short => MacAddress { + short: [buf[7], buf[8]], + }, + AddressMode::Extended => MacAddress { + extended: [buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14]], + }, + }; + + let dst_addr_mode = AddressMode::try_from(buf[15])?; + let dst_address = match dst_addr_mode { + AddressMode::NoAddress => MacAddress { short: [0, 0] }, + AddressMode::Reserved => MacAddress { short: [0, 0] }, + AddressMode::Short => MacAddress { + short: [buf[18], buf[19]], + }, + AddressMode::Extended => MacAddress { + extended: [buf[18], buf[19], buf[20], buf[21], buf[22], buf[23], buf[24], buf[25]], + }, + }; + + Ok(Self { + msdu_ptr: to_u32(&buf[0..4]) as *const u8, + src_addr_mode, + src_pan_id: PanId([buf[5], buf[6]]), + src_address, + dst_addr_mode, + dst_pan_id: PanId([buf[16], buf[17]]), + dst_address, + msdu_length: buf[26], + mpdu_link_quality: buf[27], + dsn: buf[28], + time_stamp: [buf[29], buf[30], buf[31], buf[32]], + security_level: SecurityLevel::try_from(buf[33]).unwrap_or(SecurityLevel::Unsecure), // TODO: this is totaly wrong, but I'm too smol brain to fix it + key_id_mode: KeyIdMode::try_from(buf[34]).unwrap_or(KeyIdMode::Implicite), // TODO: this is totaly wrong, but I'm too smol brain to fix it + key_source: [buf[35], buf[36], buf[37], buf[38], buf[39], buf[40], buf[41], buf[42]], + key_index: buf[43], + uwbprf: buf[44], + uwn_preamble_symbol_repetitions: buf[45], + datrate: buf[46], + ranging_received: buf[47], + ranging_counter_start: to_u32(&buf[48..52]), + ranging_counter_stop: to_u32(&buf[52..56]), + ranging_tracking_interval: to_u32(&buf[56..60]), + ranging_offset: to_u32(&buf[60..64]), + ranging_fom: buf[65], + rssi: buf[66], + }) + } +} + +/// MLME POLL Indication which will be used for indicating the Data Request +/// reception to upper layer as defined in Zigbee r22 - D.8.2 +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PollIndication { + /// addressing mode used + pub addr_mode: AddressMode, + /// Poll requester address + pub request_address: MacAddress, +} + +impl ParseableMacEvent for PollIndication { + const SIZE: usize = 9; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + let addr_mode = AddressMode::try_from(buf[0])?; + let request_address = match addr_mode { + AddressMode::NoAddress => MacAddress { short: [0, 0] }, + AddressMode::Reserved => MacAddress { short: [0, 0] }, + AddressMode::Short => MacAddress { + short: [buf[1], buf[2]], + }, + AddressMode::Extended => MacAddress { + extended: [buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]], + }, + }; + + Ok(Self { + addr_mode, + request_address, + }) + } +} diff --git a/embassy-stm32-wpan/src/mac/macros.rs b/embassy-stm32-wpan/src/mac/macros.rs new file mode 100644 index 000000000..1a988a779 --- /dev/null +++ b/embassy-stm32-wpan/src/mac/macros.rs @@ -0,0 +1,32 @@ +#[macro_export] +macro_rules! numeric_enum { + (#[repr($repr:ident)] + $(#$attrs:tt)* $vis:vis enum $name:ident { + $($(#$enum_attrs:tt)* $enum:ident = $constant:expr),* $(,)? + } ) => { + #[repr($repr)] + $(#$attrs)* + $vis enum $name { + $($(#$enum_attrs)* $enum = $constant),* + } + + impl ::core::convert::TryFrom<$repr> for $name { + type Error = (); + + fn try_from(value: $repr) -> ::core::result::Result { + match value { + $($constant => Ok( $name :: $enum ),)* + _ => Err(()) + } + } + } + + impl ::core::convert::From<$name> for $repr { + fn from(value: $name) -> $repr { + match value { + $($name :: $enum => $constant,)* + } + } + } + } +} diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs new file mode 100644 index 000000000..1af8fe6ba --- /dev/null +++ b/embassy-stm32-wpan/src/mac/mod.rs @@ -0,0 +1,9 @@ +pub mod commands; +mod consts; +pub mod event; +mod helpers; +pub mod indications; +mod macros; +mod opcodes; +pub mod responses; +pub mod typedefs; diff --git a/embassy-stm32-wpan/src/mac/opcodes.rs b/embassy-stm32-wpan/src/mac/opcodes.rs new file mode 100644 index 000000000..fd7011873 --- /dev/null +++ b/embassy-stm32-wpan/src/mac/opcodes.rs @@ -0,0 +1,92 @@ +const ST_VENDOR_OGF: u16 = 0x3F; +const MAC_802_15_4_CMD_OPCODE_OFFSET: u16 = 0x280; + +const fn opcode(ocf: u16) -> isize { + ((ST_VENDOR_OGF << 9) | (MAC_802_15_4_CMD_OPCODE_OFFSET + ocf)) as isize +} + +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum OpcodeM4ToM0 { + MlmeAssociateReq = opcode(0x00), + MlmeAssociateRes = opcode(0x01), + MlmeDisassociateReq = opcode(0x02), + MlmeGetReq = opcode(0x03), + MlmeGtsReq = opcode(0x04), + MlmeOrphanRes = opcode(0x05), + MlmeResetReq = opcode(0x06), + MlmeRxEnableReq = opcode(0x07), + MlmeScanReq = opcode(0x08), + MlmeSetReq = opcode(0x09), + MlmeStartReq = opcode(0x0A), + MlmeSyncReq = opcode(0x0B), + MlmePollReq = opcode(0x0C), + MlmeDpsReq = opcode(0x0D), + MlmeSoundingReq = opcode(0x0E), + MlmeCalibrateReq = opcode(0x0F), + McpsDataReq = opcode(0x10), + McpsPurgeReq = opcode(0x11), +} + +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum OpcodeM0ToM4 { + MlmeAssociateCnf = 0x00, + MlmeDisassociateCnf, + MlmeGetCnf, + MlmeGtsCnf, + MlmeResetCnf, + MlmeRxEnableCnf, + MlmeScanCnf, + MlmeSetCnf, + MlmeStartCnf, + MlmePollCnf, + MlmeDpsCnf, + MlmeSoundingCnf, + MlmeCalibrateCnf, + McpsDataCnf, + McpsPurgeCnf, + MlmeAssociateInd, + MlmeDisassociateInd, + MlmeBeaconNotifyInd, + MlmeCommStatusInd, + MlmeGtsInd, + MlmeOrphanInd, + MlmeSyncLossInd, + MlmeDpsInd, + McpsDataInd, + MlmePollInd, +} + +impl TryFrom for OpcodeM0ToM4 { + type Error = (); + + fn try_from(value: u16) -> Result { + match value { + 0 => Ok(Self::MlmeAssociateCnf), + 1 => Ok(Self::MlmeDisassociateCnf), + 2 => Ok(Self::MlmeGetCnf), + 3 => Ok(Self::MlmeGtsCnf), + 4 => Ok(Self::MlmeResetCnf), + 5 => Ok(Self::MlmeRxEnableCnf), + 6 => Ok(Self::MlmeScanCnf), + 7 => Ok(Self::MlmeSetCnf), + 8 => Ok(Self::MlmeStartCnf), + 9 => Ok(Self::MlmePollCnf), + 10 => Ok(Self::MlmeDpsCnf), + 11 => Ok(Self::MlmeSoundingCnf), + 12 => Ok(Self::MlmeCalibrateCnf), + 13 => Ok(Self::McpsDataCnf), + 14 => Ok(Self::McpsPurgeCnf), + 15 => Ok(Self::MlmeAssociateInd), + 16 => Ok(Self::MlmeDisassociateInd), + 17 => Ok(Self::MlmeBeaconNotifyInd), + 18 => Ok(Self::MlmeCommStatusInd), + 19 => Ok(Self::MlmeGtsInd), + 20 => Ok(Self::MlmeOrphanInd), + 21 => Ok(Self::MlmeSyncLossInd), + 22 => Ok(Self::MlmeDpsInd), + 23 => Ok(Self::McpsDataInd), + 24 => Ok(Self::MlmePollInd), + _ => Err(()), + } + } +} diff --git a/embassy-stm32-wpan/src/mac/responses.rs b/embassy-stm32-wpan/src/mac/responses.rs new file mode 100644 index 000000000..2f6f5bf58 --- /dev/null +++ b/embassy-stm32-wpan/src/mac/responses.rs @@ -0,0 +1,433 @@ +use super::consts::{MAX_ED_SCAN_RESULTS_SUPPORTED, MAX_PAN_DESC_SUPPORTED, MAX_SOUNDING_LIST_SUPPORTED}; +use super::event::ParseableMacEvent; +use super::helpers::to_u32; +use super::typedefs::{ + AddressMode, AssociationStatus, KeyIdMode, MacAddress, MacStatus, PanDescriptor, PanId, PibId, ScanType, + SecurityLevel, +}; + +/// MLME ASSOCIATE Confirm used to inform of the initiating device whether +/// its request to associate was successful or unsuccessful +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct AssociateConfirm { + /// short address allocated by the coordinator on successful association + pub assoc_short_address: [u8; 2], + /// status of the association request + pub status: AssociationStatus, + /// security level to be used + pub security_level: SecurityLevel, + /// the originator of the key to be used + pub key_source: [u8; 8], + /// the mode used to identify the key to be used + pub key_id_mode: KeyIdMode, + /// the index of the key to be used + pub key_index: u8, +} + +impl ParseableMacEvent for AssociateConfirm { + const SIZE: usize = 16; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + assoc_short_address: [buf[0], buf[1]], + status: AssociationStatus::try_from(buf[2])?, + security_level: SecurityLevel::try_from(buf[3])?, + key_source: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]], + key_id_mode: KeyIdMode::try_from(buf[12])?, + key_index: buf[13], + }) + } +} + +/// MLME DISASSOCIATE Confirm used to send disassociation Confirmation to the application. +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DisassociateConfirm { + /// status of the disassociation attempt + pub status: MacStatus, + /// device addressing mode used + pub device_addr_mode: AddressMode, + /// the identifier of the PAN of the device + pub device_pan_id: PanId, + /// device address + pub device_address: MacAddress, +} + +impl ParseableMacEvent for DisassociateConfirm { + const SIZE: usize = 12; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + let device_addr_mode = AddressMode::try_from(buf[1])?; + let device_address = match device_addr_mode { + AddressMode::NoAddress => MacAddress { short: [0, 0] }, + AddressMode::Reserved => MacAddress { short: [0, 0] }, + AddressMode::Short => MacAddress { + short: [buf[4], buf[5]], + }, + AddressMode::Extended => MacAddress { + extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]], + }, + }; + + Ok(Self { + status: MacStatus::try_from(buf[0])?, + device_addr_mode, + device_pan_id: PanId([buf[2], buf[3]]), + device_address, + }) + } +} + +/// MLME GET Confirm which requests information about a given PIB attribute +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct GetConfirm { + /// The pointer to the value of the PIB attribute attempted to read + pub pib_attribute_value_ptr: *const u8, + /// Status of the GET attempt + pub status: MacStatus, + /// The name of the PIB attribute attempted to read + pub pib_attribute: PibId, + /// The lenght of the PIB attribute Value return + pub pib_attribute_value_len: u8, +} + +impl ParseableMacEvent for GetConfirm { + const SIZE: usize = 8; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + let address = to_u32(&buf[0..4]); + + Ok(Self { + pib_attribute_value_ptr: address as *const u8, + status: MacStatus::try_from(buf[4])?, + pib_attribute: PibId::try_from(buf[5])?, + pib_attribute_value_len: buf[6], + }) + } +} + +/// MLME GTS Confirm which eports the results of a request to allocate a new GTS +/// or to deallocate an existing GTS +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct GtsConfirm { + /// The characteristics of the GTS + pub gts_characteristics: u8, + /// The status of the GTS reques + pub status: MacStatus, +} + +impl ParseableMacEvent for GtsConfirm { + const SIZE: usize = 4; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + gts_characteristics: buf[0], + status: MacStatus::try_from(buf[1])?, + }) + } +} + +/// MLME RESET Confirm which is used to report the results of the reset operation +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ResetConfirm { + /// The result of the reset operation + status: MacStatus, +} + +impl ParseableMacEvent for ResetConfirm { + const SIZE: usize = 4; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + status: MacStatus::try_from(buf[0])?, + }) + } +} + +/// MLME RX ENABLE Confirm which is used to report the results of the attempt +/// to enable or disable the receiver +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct RxEnableConfirm { + /// Result of the request to enable or disable the receiver + status: MacStatus, +} + +impl ParseableMacEvent for RxEnableConfirm { + const SIZE: usize = 4; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + status: MacStatus::try_from(buf[0])?, + }) + } +} + +/// MLME SCAN Confirm which is used to report the result of the channel scan request +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ScanConfirm { + /// Status of the scan request + pub status: MacStatus, + /// The type of scan performed + pub scan_type: ScanType, + /// Channel page on which the scan was performed + pub channel_page: u8, + /// Channels given in the request which were not scanned + pub unscanned_channels: [u8; 4], + /// Number of elements returned in the appropriate result lists + pub result_list_size: u8, + /// List of energy measurements + pub energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED], + /// List of PAN descriptors + pub pan_descriptor_list: [PanDescriptor; MAX_PAN_DESC_SUPPORTED], + /// Categorization of energy detected in channel + pub detected_category: u8, + /// For UWB PHYs, the list of energy measurements taken + pub uwb_energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED], +} + +impl ParseableMacEvent for ScanConfirm { + const SIZE: usize = 185; + + fn try_parse(buf: &[u8]) -> Result { + // TODO: this is unchecked + + Self::validate(buf)?; + + let mut energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED]; + energy_detect_list.copy_from_slice(&buf[8..24]); + + let pan_descriptor_list = [ + PanDescriptor::try_from(&buf[24..46])?, + PanDescriptor::try_from(&buf[46..68])?, + PanDescriptor::try_from(&buf[68..90])?, + PanDescriptor::try_from(&buf[90..102])?, + PanDescriptor::try_from(&buf[102..124])?, + PanDescriptor::try_from(&buf[124..146])?, + ]; + + let mut uwb_energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED]; + uwb_energy_detect_list.copy_from_slice(&buf[147..163]); + + Ok(Self { + status: MacStatus::try_from(buf[0])?, + scan_type: ScanType::try_from(buf[1])?, + channel_page: buf[2], + unscanned_channels: [buf[3], buf[4], buf[5], buf[6]], + result_list_size: buf[7], + energy_detect_list, + pan_descriptor_list, + detected_category: buf[146], + uwb_energy_detect_list, + }) + } +} + +/// MLME SET Confirm which reports the result of an attempt to write a value to a PIB attribute +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct SetConfirm { + /// The result of the set operation + pub status: MacStatus, + /// The name of the PIB attribute that was written + pub pin_attribute: PibId, +} + +impl ParseableMacEvent for SetConfirm { + const SIZE: usize = 4; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + status: MacStatus::try_from(buf[0])?, + pin_attribute: PibId::try_from(buf[1])?, + }) + } +} + +/// MLME START Confirm which is used to report the results of the attempt to +/// start using a new superframe configuration +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct StartConfirm { + /// Result of the attempt to start using an updated superframe configuration + pub status: MacStatus, +} + +impl ParseableMacEvent for StartConfirm { + const SIZE: usize = 4; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + status: MacStatus::try_from(buf[0])?, + }) + } +} + +/// MLME POLL Confirm which is used to report the result of a request to poll the coordinator for data +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PollConfirm { + /// The status of the data request + pub status: MacStatus, +} + +impl ParseableMacEvent for PollConfirm { + const SIZE: usize = 4; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + status: MacStatus::try_from(buf[0])?, + }) + } +} + +/// MLME DPS Confirm which reports the results of the attempt to enable or disable the DPS +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DpsConfirm { + /// The status of the DPS request + pub status: MacStatus, +} + +impl ParseableMacEvent for DpsConfirm { + const SIZE: usize = 4; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + status: MacStatus::try_from(buf[0])?, + }) + } +} + +/// MLME SOUNDING Confirm which reports the result of a request to the PHY to provide +/// channel sounding information +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct SoundingConfirm { + /// Results of the sounding measurement + sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED], +} + +impl ParseableMacEvent for SoundingConfirm { + const SIZE: usize = 1; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + let mut sounding_list = [0u8; MAX_SOUNDING_LIST_SUPPORTED]; + sounding_list[..buf.len()].copy_from_slice(buf); + + Ok(Self { sounding_list }) + } +} + +/// MLME CALIBRATE Confirm which reports the result of a request to the PHY +/// to provide internal propagation path information +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct CalibrateConfirm { + /// The status of the attempt to return sounding data + pub status: MacStatus, + /// A count of the propagation time from the ranging counter + /// to the transmit antenna + pub cal_tx_rmaker_offset: u32, + /// A count of the propagation time from the receive antenna + /// to the ranging counter + pub cal_rx_rmaker_offset: u32, +} + +impl ParseableMacEvent for CalibrateConfirm { + const SIZE: usize = 12; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + status: MacStatus::try_from(buf[0])?, + // 3 byte stuffing + cal_tx_rmaker_offset: to_u32(&buf[4..8]), + cal_rx_rmaker_offset: to_u32(&buf[8..12]), + }) + } +} + +/// MCPS DATA Confirm which will be used for reporting the results of +/// MAC data related requests from the application +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DataConfirm { + /// The handle associated with the MSDU being confirmed + pub msdu_handle: u8, + /// The time, in symbols, at which the data were transmitted + pub time_stamp: [u8; 4], + /// ranging status + pub ranging_received: u8, + /// The status of the last MSDU transmission + pub status: MacStatus, + /// time units corresponding to an RMARKER at the antenna at + /// the beginning of a ranging exchange + pub ranging_counter_start: u32, + /// time units corresponding to an RMARKER at the antenna + /// at the end of a ranging exchange + pub ranging_counter_stop: u32, + /// time units in a message exchange over which the tracking offset was measured + pub ranging_tracking_interval: u32, + /// time units slipped or advanced by the radio tracking system + pub ranging_offset: u32, + /// The FoM characterizing the ranging measurement + pub ranging_fom: u8, +} + +impl ParseableMacEvent for DataConfirm { + const SIZE: usize = 28; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + msdu_handle: buf[0], + time_stamp: [buf[1], buf[2], buf[3], buf[4]], + ranging_received: buf[5], + status: MacStatus::try_from(buf[6])?, + ranging_counter_start: to_u32(&buf[7..11]), + ranging_counter_stop: to_u32(&buf[11..15]), + ranging_tracking_interval: to_u32(&buf[15..19]), + ranging_offset: to_u32(&buf[19..23]), + ranging_fom: buf[24], + }) + } +} + +/// 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 +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PurgeConfirm { + /// Handle associated with the MSDU requested to be purged from the transaction queue + pub msdu_handle: u8, + /// The status of the request + pub status: MacStatus, +} + +impl ParseableMacEvent for PurgeConfirm { + const SIZE: usize = 4; + + fn try_parse(buf: &[u8]) -> Result { + Self::validate(buf)?; + + Ok(Self { + msdu_handle: buf[0], + status: MacStatus::try_from(buf[1])?, + }) + } +} diff --git a/embassy-stm32-wpan/src/mac/typedefs.rs b/embassy-stm32-wpan/src/mac/typedefs.rs new file mode 100644 index 000000000..30c7731b2 --- /dev/null +++ b/embassy-stm32-wpan/src/mac/typedefs.rs @@ -0,0 +1,363 @@ +use crate::numeric_enum; + +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum MacError { + Error = 0x01, + NotImplemented = 0x02, + NotSupported = 0x03, + HardwareNotSupported = 0x04, + Undefined = 0x05, +} + +impl From for MacError { + fn from(value: u8) -> Self { + match value { + 0x01 => Self::Error, + 0x02 => Self::NotImplemented, + 0x03 => Self::NotSupported, + 0x04 => Self::HardwareNotSupported, + 0x05 => Self::Undefined, + _ => Self::Undefined, + } + } +} + +numeric_enum! { + #[repr(u8)] + #[derive(Debug, Default)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum MacStatus { + #[default] + Success = 0x00, + Failure = 0xFF + } +} + +numeric_enum! { + #[repr(u8)] + /// this enum contains all the MAC PIB Ids + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum PibId { + // PHY + CurrentChannel = 0x00, + ChannelsSupported = 0x01, + TransmitPower = 0x02, + CCAMode = 0x03, + CurrentPage = 0x04, + MaxFrameDuration = 0x05, + SHRDuration = 0x06, + SymbolsPerOctet = 0x07, + + // MAC + AckWaitDuration = 0x40, + AssociationPermit = 0x41, + AutoRequest = 0x42, + BeaconPayload = 0x45, + BeaconPayloadLength = 0x46, + BeaconOrder = 0x47, + Bsn = 0x49, + CoordExtendedAdddress = 0x4A, + CoordShortAddress = 0x4B, + Dsn = 0x4C, + MaxFrameTotalWaitTime = 0x58, + MaxFrameRetries = 0x59, + PanId = 0x50, + ResponseWaitTime = 0x5A, + RxOnWhenIdle = 0x52, + SecurityEnabled = 0x5D, + ShortAddress = 0x53, + SuperframeOrder = 0x54, + TimestampSupported = 0x5C, + TransactionPersistenceTime = 0x55, + MaxBe = 0x57, + LifsPeriod = 0x5E, + SifsPeriod = 0x5F, + MaxCsmaBackoffs = 0x4E, + MinBe = 0x4F, + PanCoordinator = 0x10, + AssocPanCoordinator = 0x11, + ExtendedAddress = 0x6F, + AclEntryDescriptor = 0x70, + AclEntryDescriptorSize = 0x71, + DefaultSecurity = 0x72, + DefaultSecurityMaterialLength = 0x73, + DefaultSecurityMaterial = 0x74, + DefaultSecuritySuite = 0x75, + SecurityMode = 0x76, + CurrentAclEntries = 0x80, + DefaultSecurityExtendedAddress = 0x81, + AssociatedPanCoordinator = 0x56, + PromiscuousMode = 0x51, + } +} + +numeric_enum! { + #[repr(u8)] + #[derive(Default, Clone, Copy)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum AddressMode { + #[default] + NoAddress = 0x00, + Reserved = 0x01, + Short = 0x02, + Extended = 0x03, +} +} + +#[derive(Clone, Copy)] +pub union MacAddress { + pub short: [u8; 2], + pub extended: [u8; 8], +} + +#[cfg(feature = "defmt")] +impl defmt::Format for MacAddress { + fn format(&self, fmt: defmt::Formatter) { + unsafe { + defmt::write!( + fmt, + "MacAddress {{ short: {}, extended: {} }}", + self.short, + self.extended + ) + } + } +} + +impl Default for MacAddress { + fn default() -> Self { + Self { short: [0, 0] } + } +} + +impl MacAddress { + pub const BROADCAST: Self = Self { short: [0xFF, 0xFF] }; +} + +impl TryFrom<&[u8]> for MacAddress { + type Error = (); + + fn try_from(buf: &[u8]) -> Result { + const SIZE: usize = 8; + if buf.len() < SIZE { + return Err(()); + } + + Ok(Self { + extended: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]], + }) + } +} + +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct GtsCharacteristics { + pub fields: u8, +} + +/// MAC PAN Descriptor which contains the network details of the device from +/// which the beacon is received +#[derive(Default, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PanDescriptor { + /// PAN identifier of the coordinator + pub coord_pan_id: PanId, + /// Coordinator addressing mode + pub coord_addr_mode: AddressMode, + /// The current logical channel occupied by the network + pub logical_channel: MacChannel, + /// Coordinator address + pub coord_addr: MacAddress, + /// The current channel page occupied by the network + pub channel_page: u8, + /// PAN coordinator is accepting GTS requests or not + pub gts_permit: bool, + /// Superframe specification as specified in the received beacon frame + pub superframe_spec: [u8; 2], + /// The time at which the beacon frame was received, in symbols + pub time_stamp: [u8; 4], + /// The LQI at which the network beacon was received + pub link_quality: u8, + /// Security level purportedly used by the received beacon frame + pub security_level: u8, +} + +impl TryFrom<&[u8]> for PanDescriptor { + type Error = (); + + fn try_from(buf: &[u8]) -> Result { + const SIZE: usize = 22; + if buf.len() < SIZE { + return Err(()); + } + + let coord_addr_mode = AddressMode::try_from(buf[2])?; + let coord_addr = match coord_addr_mode { + AddressMode::NoAddress => MacAddress { short: [0, 0] }, + AddressMode::Reserved => MacAddress { short: [0, 0] }, + AddressMode::Short => MacAddress { + short: [buf[4], buf[5]], + }, + AddressMode::Extended => MacAddress { + extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]], + }, + }; + + Ok(Self { + coord_pan_id: PanId([buf[0], buf[1]]), + coord_addr_mode, + logical_channel: MacChannel::try_from(buf[3])?, + coord_addr, + channel_page: buf[12], + gts_permit: buf[13] != 0, + superframe_spec: [buf[14], buf[15]], + time_stamp: [buf[16], buf[17], buf[18], buf[19]], + link_quality: buf[20], + security_level: buf[21], + // 2 byte stuffing + }) + } +} + +numeric_enum! { + #[repr(u8)] + #[derive(Default, Clone, Copy)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + /// Building wireless applications with STM32WB series MCUs - Application note 13.10.3 + pub enum MacChannel { + Channel11 = 0x0B, + Channel12 = 0x0C, + Channel13 = 0x0D, + Channel14 = 0x0E, + Channel15 = 0x0F, + #[default] + Channel16 = 0x10, + Channel17 = 0x11, + Channel18 = 0x12, + Channel19 = 0x13, + Channel20 = 0x14, + Channel21 = 0x15, + Channel22 = 0x16, + Channel23 = 0x17, + Channel24 = 0x18, + Channel25 = 0x19, + Channel26 = 0x1A, + } +} + +#[cfg(not(feature = "defmt"))] +bitflags::bitflags! { + pub struct Capabilities: u8 { + /// 1 if the device is capabaleof becoming a PAN coordinator + const IS_COORDINATOR_CAPABLE = 0b00000001; + /// 1 if the device is an FFD, 0 if it is an RFD + const IS_FFD = 0b00000010; + /// 1 if the device is receiving power from mains, 0 if it is battery-powered + const IS_MAINS_POWERED = 0b00000100; + /// 1 if the device does not disable its receiver to conserver power during idle periods + const RECEIVER_ON_WHEN_IDLE = 0b00001000; + // 0b00010000 reserved + // 0b00100000 reserved + /// 1 if the device is capable of sending and receiving secured MAC frames + const IS_SECURE = 0b01000000; + /// 1 if the device wishes the coordinator to allocate a short address as a result of the association + const ALLOCATE_ADDRESS = 0b10000000; + } +} + +#[cfg(feature = "defmt")] +defmt::bitflags! { + pub struct Capabilities: u8 { + /// 1 if the device is capabaleof becoming a PAN coordinator + const IS_COORDINATOR_CAPABLE = 0b00000001; + /// 1 if the device is an FFD, 0 if it is an RFD + const IS_FFD = 0b00000010; + /// 1 if the device is receiving power from mains, 0 if it is battery-powered + const IS_MAINS_POWERED = 0b00000100; + /// 1 if the device does not disable its receiver to conserver power during idle periods + const RECEIVER_ON_WHEN_IDLE = 0b00001000; + // 0b00010000 reserved + // 0b00100000 reserved + /// 1 if the device is capable of sending and receiving secured MAC frames + const IS_SECURE = 0b01000000; + /// 1 if the device wishes the coordinator to allocate a short address as a result of the association + const ALLOCATE_ADDRESS = 0b10000000; + } +} + +numeric_enum! { + #[repr(u8)] + #[derive(Default, Clone, Copy)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum KeyIdMode { + #[default] + /// the key is determined implicitly from the originator and recipient(s) of the frame + Implicite = 0x00, + /// the key is determined explicitly using a 1 bytes key source and a 1 byte key index + Explicite1Byte = 0x01, + /// the key is determined explicitly using a 4 bytes key source and a 1 byte key index + Explicite4Byte = 0x02, + /// the key is determined explicitly using a 8 bytes key source and a 1 byte key index + Explicite8Byte = 0x03, + } +} + +numeric_enum! { + #[repr(u8)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum AssociationStatus { + /// Association successful + Success = 0x00, + /// PAN at capacity + PanAtCapacity = 0x01, + /// PAN access denied + PanAccessDenied = 0x02 + } +} + +numeric_enum! { + #[repr(u8)] + #[derive(Clone, Copy)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum DisassociationReason { + /// The coordinator wishes the device to leave the PAN. + CoordRequested = 0x01, + /// The device wishes to leave the PAN. + DeviceRequested = 0x02, + } +} + +numeric_enum! { + #[repr(u8)] + #[derive(Default, Clone, Copy)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum SecurityLevel { + /// MAC Unsecured Mode Security + #[default] + Unsecure = 0x00, + /// MAC ACL Mode Security + AclMode = 0x01, + /// MAC Secured Mode Security + Secured = 0x02, + } +} + +numeric_enum! { + #[repr(u8)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum ScanType { + EdScan = 0x00, + Active = 0x01, + Passive = 0x02, + Orphan = 0x03 + } +} + +/// newtype for Pan Id +#[derive(Default, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PanId(pub [u8; 2]); + +impl PanId { + pub const BROADCAST: Self = Self([0xFF, 0xFF]); +} diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs new file mode 100644 index 000000000..4893cb47b --- /dev/null +++ b/embassy-stm32-wpan/src/sub/mac.rs @@ -0,0 +1,133 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::ptr; +use core::sync::atomic::{AtomicBool, Ordering}; +use core::task::Poll; + +use embassy_futures::poll_once; +use embassy_stm32::ipcc::Ipcc; +use embassy_sync::waitqueue::AtomicWaker; + +use crate::cmd::CmdPacket; +use crate::consts::TlPacketType; +use crate::evt::{EvtBox, EvtPacket}; +use crate::mac::commands::MacCommand; +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}; + +static MAC_WAKER: AtomicWaker = AtomicWaker::new(); +static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); + +pub struct Mac { + phantom: PhantomData, +} + +impl Mac { + pub(crate) fn new() -> Self { + Self { phantom: PhantomData } + } + + /// `HW_IPCC_MAC_802_15_4_EvtNot` + /// + /// This function will stall if the previous `EvtBox` has not been dropped + pub async fn tl_read(&self) -> EvtBox { + // Wait for the last event box to be dropped + poll_fn(|cx| { + MAC_WAKER.register(cx.waker()); + if MAC_EVT_OUT.load(Ordering::SeqCst) { + Poll::Pending + } else { + Poll::Ready(()) + } + }) + .await; + + // Return a new event box + Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe { + // The closure is not async, therefore the closure must execute to completion (cannot be dropped) + // Therefore, the event box is guaranteed to be cleaned up if it's not leaked + MAC_EVT_OUT.store(true, Ordering::SeqCst); + + Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _)) + }) + .await + } + + /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` + pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { + self.tl_write(opcode, payload).await; + Ipcc::flush(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL).await; + + unsafe { + let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket; + let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8; + + ptr::read_volatile(p_mac_rsp_evt) + } + } + + /// `TL_MAC_802_15_4_SendCmd` + pub async fn tl_write(&self, opcode: u16, payload: &[u8]) { + Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe { + CmdPacket::write_into( + MAC_802_15_4_CMD_BUFFER.as_mut_ptr(), + TlPacketType::MacCmd, + opcode, + payload, + ); + }) + .await; + } + + pub async fn send_command(&self, cmd: &T) -> Result<(), MacError> + where + T: MacCommand, + { + let mut payload = [0u8; MAX_PACKET_SIZE]; + cmd.copy_into_slice(&mut payload); + + let response = self + .tl_write_and_get_response(T::OPCODE as u16, &payload[..T::SIZE]) + .await; + + if response == 0x00 { + Ok(()) + } else { + Err(MacError::from(response)) + } + } + + pub async fn read(&self) -> Result { + let evt_box = self.tl_read().await; + let payload = evt_box.payload(); + + MacEvent::try_from(payload) + } +} + +const MAX_PACKET_SIZE: usize = 255; + +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) { + // Write the ack + CmdPacket::write_into( + MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, + TlPacketType::OtAck, + 0, + &[], + ); + + // Clear the rx flag + let _ = poll_once(Ipcc::receive::( + channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, + || None, + )); + + // Allow a new read call + MAC_EVT_OUT.store(false, Ordering::SeqCst); + MAC_WAKER.wake(); + } +} diff --git a/embassy-stm32-wpan/src/sub/mac/commands.rs b/embassy-stm32-wpan/src/sub/mac/commands.rs deleted file mode 100644 index 8cfa0a054..000000000 --- a/embassy-stm32-wpan/src/sub/mac/commands.rs +++ /dev/null @@ -1,467 +0,0 @@ -use super::opcodes::OpcodeM4ToM0; -use super::typedefs::{ - AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus, - PanId, PibId, ScanType, SecurityLevel, -}; - -pub trait MacCommand { - const OPCODE: OpcodeM4ToM0; - const SIZE: usize; - - fn copy_into_slice(&self, buf: &mut [u8]) { - unsafe { core::ptr::copy(self as *const _ as *const u8, buf as *mut _ as *mut u8, Self::SIZE) }; - } -} - -/// MLME ASSOCIATE Request used to request an association -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct AssociateRequest { - /// the logical channel on which to attempt association - pub channel_number: MacChannel, - /// the channel page on which to attempt association - pub channel_page: u8, - /// coordinator addressing mode - pub coord_addr_mode: AddressMode, - /// operational capabilities of the associating device - pub capability_information: Capabilities, - /// the identifier of the PAN with which to associate - pub coord_pan_id: PanId, - /// the security level to be used - pub security_level: SecurityLevel, - /// the mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// the originator of the key to be used - pub key_source: [u8; 8], - /// Coordinator address - pub coord_address: MacAddress, - /// the index of the key to be used - pub key_index: u8, -} - -impl MacCommand for AssociateRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateReq; - const SIZE: usize = 25; -} - -/// MLME DISASSOCIATE Request sed to request a disassociation -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DisassociateRequest { - /// device addressing mode used - pub device_addr_mode: AddressMode, - /// the identifier of the PAN of the device - pub device_pan_id: PanId, - /// the reason for the disassociation - pub disassociation_reason: DisassociationReason, - /// device address - pub device_address: MacAddress, - /// `true` if the disassociation notification command is to be sent indirectly - pub tx_indirect: bool, - /// the security level to be used - pub security_level: SecurityLevel, - /// the mode to be used to indetify the key to be used - pub key_id_mode: KeyIdMode, - /// the index of the key to be used - pub key_index: u8, - /// the originator of the key to be used - pub key_source: [u8; 8], -} - -impl MacCommand for DisassociateRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDisassociateReq; - const SIZE: usize = 24; -} - -/// MLME GET Request used to request a PIB value -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct GetRequest { - /// the name of the PIB attribute to read - pub pib_attribute: PibId, -} - -impl MacCommand for GetRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq; - const SIZE: usize = 4; -} - -/// MLME GTS Request used to request and maintain GTSs -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct GtsRequest { - /// the characteristics of the GTS - pub characteristics: GtsCharacteristics, - /// the security level to be used - pub security_level: SecurityLevel, - /// the mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// the index of the key to be used - pub key_index: u8, - /// the originator of the key to be used - pub key_source: [u8; 8], -} - -impl MacCommand for GtsRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq; - const SIZE: usize = 12; -} - -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ResetRequest { - /// MAC PIB attributes are set to their default values or not during reset - pub set_default_pib: bool, -} - -impl MacCommand for ResetRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeResetReq; - const SIZE: usize = 4; -} - -/// MLME RX ENABLE Request used to request that the receiver is either enabled -/// for a finite period of time or disabled -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct RxEnableRequest { - /// the request operation can be deferred or not - pub defer_permit: bool, - /// configure the transceiver to RX with ranging for a value of - /// RANGING_ON or to not enable ranging for RANGING_OFF - pub ranging_rx_control: u8, - /// number of symbols measured before the receiver is to be enabled or disabled - pub rx_on_time: [u8; 4], - /// number of symbols for which the receiver is to be enabled - pub rx_on_duration: [u8; 4], -} - -impl MacCommand for RxEnableRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeRxEnableReq; - const SIZE: usize = 12; - - fn copy_into_slice(&self, buf: &mut [u8]) { - buf[0] = self.defer_permit as u8; - buf[1] = self.ranging_rx_control as u8; - - // stuffing to keep 32bit alignment - buf[2] = 0; - buf[3] = 0; - - buf[4..8].copy_from_slice(&self.rx_on_time); - buf[8..12].copy_from_slice(&self.rx_on_duration); - } -} - -/// MLME SCAN Request used to initiate a channel scan over a given list of channels -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ScanRequest { - /// the type of scan to be performed - pub scan_type: ScanType, - /// the time spent on scanning each channel - pub scan_duration: u8, - /// channel page on which to perform the scan - pub channel_page: u8, - /// security level to be used - pub security_level: SecurityLevel, - /// indicate which channels are to be scanned - pub scan_channels: [u8; 4], - /// originator the key to be used - pub key_source: [u8; 8], - /// mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// index of the key to be used - pub key_index: u8, -} - -impl MacCommand for ScanRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeScanReq; - const SIZE: usize = 20; -} - -/// MLME SET Request used to attempt to write the given value to the indicated PIB attribute -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct SetRequest { - /// the pointer to the value of the PIB attribute to set - pub pib_attribute_ptr: *const u8, - /// the name of the PIB attribute to set - pub pib_attribute: PibId, -} - -impl MacCommand for SetRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSetReq; - const SIZE: usize = 8; -} - -/// MLME START Request used by the FFDs to intiate a new PAN or to begin using a new superframe -/// configuration -#[derive(Default)] -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct StartRequest { - /// PAN indentifier to used by the device - pub pan_id: PanId, - /// logical channel on which to begin - pub channel_number: MacChannel, - /// channel page on which to begin - pub channel_page: u8, - /// time at which to begin transmitting beacons - pub start_time: [u8; 4], - /// indicated how often the beacon is to be transmitted - pub beacon_order: u8, - /// length of the active portion of the superframe - pub superframe_order: u8, - /// indicated wheter the device is a PAN coordinator or not - pub pan_coordinator: bool, - /// indicates if the receiver of the beaconing device is disabled or not - pub battery_life_extension: bool, - /// indicated if the coordinator realignment command is to be trasmitted - pub coord_realignment: u8, - /// indicated if the coordinator realignment command is to be trasmitted - pub coord_realign_security_level: SecurityLevel, - /// index of the key to be used - pub coord_realign_key_id_index: u8, - /// originator of the key to be used - pub coord_realign_key_source: [u8; 8], - /// security level to be used for beacon frames - pub beacon_security_level: SecurityLevel, - /// mode used to identify the key to be used - pub beacon_key_id_mode: KeyIdMode, - /// index of the key to be used - pub beacon_key_index: u8, - /// originator of the key to be used - pub beacon_key_source: [u8; 8], -} - -impl MacCommand for StartRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeStartReq; - const SIZE: usize = 35; -} - -/// MLME SYNC Request used to synchronize with the coordinator by acquiring and, if -/// specified, tracking its beacons -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct SyncRequest { - /// the channel number on which to attempt coordinator synchronization - pub channel_number: MacChannel, - /// the channel page on which to attempt coordinator synchronization - pub channel_page: u8, - /// `true` if the MLME is to synchronize with the next beacon and attempts - /// to track all future beacons. - /// - /// `false` if the MLME is to synchronize with only the next beacon - pub track_beacon: bool, -} - -impl MacCommand for SyncRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSyncReq; - const SIZE: usize = 4; -} - -/// MLME POLL Request propmts the device to request data from the coordinator -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PollRequest { - /// addressing mode of the coordinator - pub coord_addr_mode: AddressMode, - /// security level to be used - pub security_level: SecurityLevel, - /// mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// index of the key to be used - pub key_index: u8, - /// coordinator address - pub coord_address: MacAddress, - /// originator of the key to be used - pub key_source: [u8; 8], - /// PAN identifier of the coordinator - pub coord_pan_id: PanId, -} - -impl MacCommand for PollRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmePollReq; - const SIZE: usize = 24; -} - -/// MLME DPS Request allows the next higher layer to request that the PHY utilize a -/// given pair of preamble codes for a single use pending expiration of the DPSIndexDuration -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DpsRequest { - /// the index value for the transmitter - tx_dps_index: u8, - /// the index value of the receiver - rx_dps_index: u8, - /// the number of symbols for which the transmitter and receiver will utilize the - /// respective DPS indices - dps_index_duration: u8, -} - -impl MacCommand for DpsRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDpsReq; - const SIZE: usize = 4; -} - -/// MLME SOUNDING request primitive which is used by the next higher layer to request that -/// the PHY respond with channel sounding information -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct SoundingRequest; - -impl MacCommand for SoundingRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSoundingReq; - const SIZE: usize = 4; -} - -/// MLME CALIBRATE request primitive which used to obtain the results of a ranging -/// calibration request from an RDEV -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CalibrateRequest; - -impl MacCommand for CalibrateRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeCalibrateReq; - const SIZE: usize = 4; -} - -/// MCPS DATA Request used for MAC data related requests from the application -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DataRequest { - /// the handle assocated with the MSDU to be transmitted - pub msdu_ptr: *const u8, - /// source addressing mode used - pub src_addr_mode: AddressMode, - /// destination addressing mode used - pub dst_addr_mode: AddressMode, - /// destination PAN Id - pub dst_pan_id: PanId, - /// destination address - pub dst_address: MacAddress, - /// the number of octets contained in the MSDU - pub msdu_length: u8, - /// the handle assocated with the MSDU to be transmitted - pub msdu_handle: u8, - /// the ACK transmittion options for the MSDU - pub ack_tx: u8, - /// `true` if a GTS is to be used for transmission - /// - /// `false` indicates that the CAP will be used - pub gts_tx: bool, - /// the pending bit transmission options for the MSDU - pub indirect_tx: u8, - /// the security level to be used - pub security_level: SecurityLevel, - /// the mode used to indentify the key to be used - pub key_id_mode: KeyIdMode, - /// the index of the key to be used - pub key_index: u8, - /// the originator of the key to be used - pub key_source: [u8; 8], - /// 2011 - the pulse repitition value - pub uwbprf: u8, - /// 2011 - the ranging configuration - pub ranging: u8, - /// 2011 - the preamble symbol repititions - pub uwb_preamble_symbol_repetitions: u8, - /// 2011 - indicates the data rate - pub datrate: u8, -} - -impl Default for DataRequest { - fn default() -> Self { - Self { - msdu_ptr: 0 as *const u8, - src_addr_mode: AddressMode::NoAddress, - dst_addr_mode: AddressMode::NoAddress, - dst_pan_id: PanId([0, 0]), - dst_address: MacAddress { short: [0, 0] }, - msdu_length: 0, - msdu_handle: 0, - ack_tx: 0, - gts_tx: false, - indirect_tx: 0, - security_level: SecurityLevel::Unsecure, - key_id_mode: KeyIdMode::Implicite, - key_index: 0, - key_source: [0u8; 8], - uwbprf: 0, - ranging: 0, - uwb_preamble_symbol_repetitions: 0, - datrate: 0, - } - } -} - -impl MacCommand for DataRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsDataReq; - const SIZE: usize = 40; -} - -/// for MCPS PURGE Request used to purge an MSDU from the transaction queue -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PurgeRequest { - /// the handle associated with the MSDU to be purged from the transaction - /// queue - pub msdu_handle: u8, -} - -impl MacCommand for PurgeRequest { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsPurgeReq; - const SIZE: usize = 4; -} - -/// MLME ASSOCIATE Response used to initiate a response to an MLME-ASSOCIATE.indication -#[repr(C)] -#[derive(Default)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct AssociateResponse { - /// extended address of the device requesting association - pub device_address: [u8; 8], - /// 16-bitshort device address allocated by the coordinator on successful - /// association - pub assoc_short_address: [u8; 2], - /// status of the association attempt - pub status: MacStatus, - /// security level to be used - pub security_level: SecurityLevel, - /// the originator of the key to be used - pub key_source: [u8; 8], - /// the mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// the index of the key to be used - pub key_index: u8, -} - -impl MacCommand for AssociateResponse { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateRes; - const SIZE: usize = 24; -} - -/// MLME ORPHAN Response used to respond to the MLME ORPHAN Indication -#[repr(C)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OrphanResponse { - /// extended address of the orphaned device - pub orphan_address: [u8; 8], - /// short address allocated to the orphaned device - pub short_address: [u8; 2], - /// if the orphaned device is associated with coordinator or not - pub associated_member: bool, - /// security level to be used - pub security_level: SecurityLevel, - /// the originator of the key to be used - pub key_source: [u8; 8], - /// the mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// the index of the key to be used - pub key_index: u8, -} - -impl MacCommand for OrphanResponse { - const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeOrphanRes; - const SIZE: usize = 24; -} diff --git a/embassy-stm32-wpan/src/sub/mac/consts.rs b/embassy-stm32-wpan/src/sub/mac/consts.rs deleted file mode 100644 index 56903d980..000000000 --- a/embassy-stm32-wpan/src/sub/mac/consts.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub const MAX_PAN_DESC_SUPPORTED: usize = 6; -pub const MAX_SOUNDING_LIST_SUPPORTED: usize = 6; -pub const MAX_PENDING_ADDRESS: usize = 7; -pub const MAX_ED_SCAN_RESULTS_SUPPORTED: usize = 16; diff --git a/embassy-stm32-wpan/src/sub/mac/event.rs b/embassy-stm32-wpan/src/sub/mac/event.rs deleted file mode 100644 index aaf965565..000000000 --- a/embassy-stm32-wpan/src/sub/mac/event.rs +++ /dev/null @@ -1,94 +0,0 @@ -use super::helpers::to_u16; -use super::indications::{ - AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication, - DpsIndication, GtsIndication, OrphanIndication, PollIndication, SyncLossIndication, -}; -use super::responses::{ - AssociateConfirm, CalibrateConfirm, DataConfirm, DisassociateConfirm, DpsConfirm, GetConfirm, GtsConfirm, - PollConfirm, PurgeConfirm, ResetConfirm, RxEnableConfirm, ScanConfirm, SetConfirm, SoundingConfirm, StartConfirm, -}; -use crate::sub::mac::opcodes::OpcodeM0ToM4; - -pub trait ParseableMacEvent { - const SIZE: usize; - - fn validate(buf: &[u8]) -> Result<(), ()> { - if buf.len() < Self::SIZE { - return Err(()); - } - - Ok(()) - } - - fn try_parse(buf: &[u8]) -> Result - where - Self: Sized; -} - -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum MacEvent { - MlmeAssociateCnf(AssociateConfirm), - MlmeDisassociateCnf(DisassociateConfirm), - MlmeGetCnf(GetConfirm), - MlmeGtsCnf(GtsConfirm), - MlmeResetCnf(ResetConfirm), - MlmeRxEnableCnf(RxEnableConfirm), - MlmeScanCnf(ScanConfirm), - MlmeSetCnf(SetConfirm), - MlmeStartCnf(StartConfirm), - MlmePollCnf(PollConfirm), - MlmeDpsCnf(DpsConfirm), - MlmeSoundingCnf(SoundingConfirm), - MlmeCalibrateCnf(CalibrateConfirm), - McpsDataCnf(DataConfirm), - McpsPurgeCnf(PurgeConfirm), - MlmeAssociateInd(AssociateIndication), - MlmeDisassociateInd(DisassociateIndication), - MlmeBeaconNotifyInd(BeaconNotifyIndication), - MlmeCommStatusInd(CommStatusIndication), - MlmeGtsInd(GtsIndication), - MlmeOrphanInd(OrphanIndication), - MlmeSyncLossInd(SyncLossIndication), - MlmeDpsInd(DpsIndication), - McpsDataInd(DataIndication), - MlmePollInd(PollIndication), -} - -impl TryFrom<&[u8]> for MacEvent { - type Error = (); - - fn try_from(value: &[u8]) -> Result { - let opcode = to_u16(&value[0..2]); - let opcode = OpcodeM0ToM4::try_from(opcode)?; - - let buf = &value[2..]; - - match opcode { - OpcodeM0ToM4::MlmeAssociateCnf => Ok(Self::MlmeAssociateCnf(AssociateConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeDisassociateCnf => Ok(Self::MlmeDisassociateCnf(DisassociateConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeGetCnf => Ok(Self::MlmeGetCnf(GetConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeGtsCnf => Ok(Self::MlmeGtsCnf(GtsConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeResetCnf => Ok(Self::MlmeResetCnf(ResetConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeRxEnableCnf => Ok(Self::MlmeRxEnableCnf(RxEnableConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeScanCnf => Ok(Self::MlmeScanCnf(ScanConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeSetCnf => Ok(Self::MlmeSetCnf(SetConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeStartCnf => Ok(Self::MlmeStartCnf(StartConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmePollCnf => Ok(Self::MlmePollCnf(PollConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeDpsCnf => Ok(Self::MlmeDpsCnf(DpsConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeSoundingCnf => Ok(Self::MlmeSoundingCnf(SoundingConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeCalibrateCnf => Ok(Self::MlmeCalibrateCnf(CalibrateConfirm::try_parse(buf)?)), - OpcodeM0ToM4::McpsDataCnf => Ok(Self::McpsDataCnf(DataConfirm::try_parse(buf)?)), - OpcodeM0ToM4::McpsPurgeCnf => Ok(Self::McpsPurgeCnf(PurgeConfirm::try_parse(buf)?)), - OpcodeM0ToM4::MlmeAssociateInd => Ok(Self::MlmeAssociateInd(AssociateIndication::try_parse(buf)?)), - OpcodeM0ToM4::MlmeDisassociateInd => Ok(Self::MlmeDisassociateInd(DisassociateIndication::try_parse(buf)?)), - OpcodeM0ToM4::MlmeBeaconNotifyInd => Ok(Self::MlmeBeaconNotifyInd(BeaconNotifyIndication::try_parse(buf)?)), - OpcodeM0ToM4::MlmeCommStatusInd => Ok(Self::MlmeCommStatusInd(CommStatusIndication::try_parse(buf)?)), - OpcodeM0ToM4::MlmeGtsInd => Ok(Self::MlmeGtsInd(GtsIndication::try_parse(buf)?)), - OpcodeM0ToM4::MlmeOrphanInd => Ok(Self::MlmeOrphanInd(OrphanIndication::try_parse(buf)?)), - OpcodeM0ToM4::MlmeSyncLossInd => Ok(Self::MlmeSyncLossInd(SyncLossIndication::try_parse(buf)?)), - OpcodeM0ToM4::MlmeDpsInd => Ok(Self::MlmeDpsInd(DpsIndication::try_parse(buf)?)), - OpcodeM0ToM4::McpsDataInd => Ok(Self::McpsDataInd(DataIndication::try_parse(buf)?)), - OpcodeM0ToM4::MlmePollInd => Ok(Self::MlmePollInd(PollIndication::try_parse(buf)?)), - } - } -} diff --git a/embassy-stm32-wpan/src/sub/mac/helpers.rs b/embassy-stm32-wpan/src/sub/mac/helpers.rs deleted file mode 100644 index 5a5bf8a85..000000000 --- a/embassy-stm32-wpan/src/sub/mac/helpers.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub fn to_u16(buf: &[u8]) -> u16 { - ((buf[1] as u16) << 8) | buf[0] as u16 -} - -pub fn to_u32(buf: &[u8]) -> u32 { - ((buf[0] as u32) << 0) + ((buf[1] as u32) << 8) + ((buf[2] as u32) << 16) + ((buf[3] as u32) << 24) -} diff --git a/embassy-stm32-wpan/src/sub/mac/indications.rs b/embassy-stm32-wpan/src/sub/mac/indications.rs deleted file mode 100644 index 6df4aa23a..000000000 --- a/embassy-stm32-wpan/src/sub/mac/indications.rs +++ /dev/null @@ -1,470 +0,0 @@ -use super::consts::MAX_PENDING_ADDRESS; -use super::event::ParseableMacEvent; -use super::helpers::to_u32; -use super::typedefs::{ - AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor, - PanId, SecurityLevel, -}; - -/// MLME ASSOCIATE Indication which will be used by the MAC -/// to indicate the reception of an association request command -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct AssociateIndication { - /// Extended address of the device requesting association - pub device_address: [u8; 8], - /// Operational capabilities of the device requesting association - pub capability_information: Capabilities, - /// Security level purportedly used by the received MAC command frame - pub security_level: SecurityLevel, - /// The mode used to identify the key used by the originator of frame - pub key_id_mode: KeyIdMode, - /// Index of the key used by the originator of the received frame - pub key_index: u8, - /// The originator of the key used by the originator of the received frame - pub key_source: [u8; 8], -} - -impl ParseableMacEvent for AssociateIndication { - const SIZE: usize = 20; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]], - capability_information: Capabilities::from_bits(buf[8]).ok_or(())?, - security_level: SecurityLevel::try_from(buf[9])?, - key_id_mode: KeyIdMode::try_from(buf[10])?, - key_index: buf[11], - key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]], - }) - } -} - -/// MLME DISASSOCIATE indication which will be used to send -/// disassociation indication to the application. -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DisassociateIndication { - /// Extended address of the device requesting association - pub device_address: [u8; 8], - /// The reason for the disassociation - pub disassociation_reason: DisassociationReason, - /// The security level to be used - pub security_level: SecurityLevel, - /// The mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// The index of the key to be used - pub key_index: u8, - /// The originator of the key to be used - pub key_source: [u8; 8], -} - -impl ParseableMacEvent for DisassociateIndication { - const SIZE: usize = 20; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]], - disassociation_reason: DisassociationReason::try_from(buf[8])?, - security_level: SecurityLevel::try_from(buf[9])?, - key_id_mode: KeyIdMode::try_from(buf[10])?, - key_index: buf[11], - key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]], - }) - } -} - -/// MLME BEACON NOTIIFY Indication which is used to send parameters contained -/// within a beacon frame received by the MAC to the application -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct BeaconNotifyIndication { - /// he set of octets comprising the beacon payload to be transferred - /// from the MAC sublayer entity to the next higher layer - pub sdu_ptr: *const u8, - /// The PAN Descriptor for the received beacon - pub pan_descriptor: PanDescriptor, - /// The list of addresses of the devices - pub addr_list: [MacAddress; MAX_PENDING_ADDRESS], - /// Beacon Sequence Number - pub bsn: u8, - /// The beacon pending address specification - pub pend_addr_spec: u8, - /// Number of octets contained in the beacon payload of the beacon frame - pub sdu_length: u8, -} - -impl ParseableMacEvent for BeaconNotifyIndication { - const SIZE: usize = 88; - - fn try_parse(buf: &[u8]) -> Result { - // TODO: this is unchecked - - Self::validate(buf)?; - - let addr_list = [ - MacAddress::try_from(&buf[26..34])?, - MacAddress::try_from(&buf[34..42])?, - MacAddress::try_from(&buf[42..50])?, - MacAddress::try_from(&buf[50..58])?, - MacAddress::try_from(&buf[58..66])?, - MacAddress::try_from(&buf[66..74])?, - MacAddress::try_from(&buf[74..82])?, - ]; - - Ok(Self { - sdu_ptr: to_u32(&buf[0..4]) as *const u8, - pan_descriptor: PanDescriptor::try_from(&buf[4..26])?, - addr_list, - bsn: buf[82], - pend_addr_spec: buf[83], - sdu_length: buf[83], - }) - } -} - -/// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CommStatusIndication { - /// The 16-bit PAN identifier of the device from which the frame - /// was received or to which the frame was being sent - pub pan_id: PanId, - /// Source addressing mode - pub src_addr_mode: AddressMode, - /// Destination addressing mode - pub dst_addr_mode: AddressMode, - /// Source address - pub src_address: MacAddress, - /// Destination address - pub dst_address: MacAddress, - /// The communications status - pub status: MacStatus, - /// Security level to be used - pub security_level: SecurityLevel, - /// Mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// Index of the key to be used - pub key_index: u8, - /// Originator of the key to be used - pub key_source: [u8; 8], -} - -impl ParseableMacEvent for CommStatusIndication { - const SIZE: usize = 32; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - let src_addr_mode = AddressMode::try_from(buf[2])?; - let dst_addr_mode = AddressMode::try_from(buf[3])?; - - let src_address = match src_addr_mode { - AddressMode::NoAddress => MacAddress { short: [0, 0] }, - AddressMode::Reserved => MacAddress { short: [0, 0] }, - AddressMode::Short => MacAddress { - short: [buf[4], buf[5]], - }, - AddressMode::Extended => MacAddress { - extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]], - }, - }; - - let dst_address = match dst_addr_mode { - AddressMode::NoAddress => MacAddress { short: [0, 0] }, - AddressMode::Reserved => MacAddress { short: [0, 0] }, - AddressMode::Short => MacAddress { - short: [buf[12], buf[13]], - }, - AddressMode::Extended => MacAddress { - extended: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]], - }, - }; - - Ok(Self { - pan_id: PanId([buf[0], buf[1]]), - src_addr_mode, - dst_addr_mode, - src_address, - dst_address, - status: MacStatus::try_from(buf[20])?, - security_level: SecurityLevel::try_from(buf[21])?, - key_id_mode: KeyIdMode::try_from(buf[22])?, - key_index: buf[23], - key_source: [buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]], - }) - } -} - -/// MLME GTS Indication indicates that a GTS has been allocated or that a -/// previously allocated GTS has been deallocated -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct GtsIndication { - /// The short address of the device that has been allocated or deallocated a GTS - pub device_address: [u8; 2], - /// The characteristics of the GTS - pub gts_characteristics: u8, - /// Security level to be used - pub security_level: SecurityLevel, - /// Mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// Index of the key to be used - pub key_index: u8, - /// Originator of the key to be used - pub key_source: [u8; 8], -} - -impl ParseableMacEvent for GtsIndication { - const SIZE: usize = 16; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - device_address: [buf[0], buf[1]], - gts_characteristics: buf[2], - security_level: SecurityLevel::try_from(buf[3])?, - key_id_mode: KeyIdMode::try_from(buf[4])?, - key_index: buf[5], - // 2 byte stuffing - key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]], - }) - } -} - -/// MLME ORPHAN Indication which is used by the coordinator to notify the -/// application of the presence of an orphaned device -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OrphanIndication { - /// Extended address of the orphaned device - pub orphan_address: [u8; 8], - /// Originator of the key used by the originator of the received frame - pub key_source: [u8; 8], - /// Security level purportedly used by the received MAC command frame - pub security_level: SecurityLevel, - /// Mode used to identify the key used by originator of received frame - pub key_id_mode: KeyIdMode, - /// Index of the key used by the originator of the received frame - pub key_index: u8, -} - -impl ParseableMacEvent for OrphanIndication { - const SIZE: usize = 20; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - orphan_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]], - key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]], - security_level: SecurityLevel::try_from(buf[16])?, - key_id_mode: KeyIdMode::try_from(buf[17])?, - key_index: buf[18], - // 1 byte stuffing - }) - } -} - -/// MLME SYNC LOSS Indication which is used by the MAC to indicate the loss -/// of synchronization with the coordinator -#[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 - pub pan_id: PanId, - /// The reason that synchronization was lost - pub loss_reason: u8, - /// The logical channel on which the device lost synchronization or to whi - pub channel_number: MacChannel, - /// The channel page on which the device lost synchronization or to which - pub channel_page: u8, - /// The security level used by the received MAC frame - pub security_level: SecurityLevel, - /// Mode used to identify the key used by originator of received frame - pub key_id_mode: KeyIdMode, - /// Index of the key used by the originator of the received frame - pub key_index: u8, - /// Originator of the key used by the originator of the received frame - pub key_source: [u8; 8], -} - -impl ParseableMacEvent for SyncLossIndication { - const SIZE: usize = 16; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - pan_id: PanId([buf[0], buf[1]]), - loss_reason: buf[2], - channel_number: MacChannel::try_from(buf[3])?, - channel_page: buf[4], - security_level: SecurityLevel::try_from(buf[5])?, - key_id_mode: KeyIdMode::try_from(buf[6])?, - key_index: buf[7], - key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]], - }) - } -} - -/// MLME DPS Indication which indicates the expiration of the DPSIndexDuration -/// and the resetting of the DPS values in the PHY -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DpsIndication; - -impl ParseableMacEvent for DpsIndication { - const SIZE: usize = 4; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self) - } -} - -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C, align(8))] -pub struct DataIndication { - /// Pointer to the set of octets forming the MSDU being indicated - pub msdu_ptr: *const u8, - /// Source addressing mode used - pub src_addr_mode: AddressMode, - /// Source PAN ID - pub src_pan_id: PanId, - /// Source address - pub src_address: MacAddress, - /// Destination addressing mode used - pub dst_addr_mode: AddressMode, - /// Destination PAN ID - pub dst_pan_id: PanId, - /// Destination address - pub dst_address: MacAddress, - /// The number of octets contained in the MSDU being indicated - pub msdu_length: u8, - /// QI value measured during reception of the MPDU - pub mpdu_link_quality: u8, - /// The data sequence number of the received data frame - pub dsn: u8, - /// The time, in symbols, at which the data were received - pub time_stamp: [u8; 4], - /// The security level purportedly used by the received data frame - pub security_level: SecurityLevel, - /// Mode used to identify the key used by originator of received frame - pub key_id_mode: KeyIdMode, - /// The originator of the key - pub key_source: [u8; 8], - /// The index of the key - pub key_index: u8, - /// he pulse repetition value of the received PPDU - pub uwbprf: u8, - /// The preamble symbol repetitions of the UWB PHY frame - pub uwn_preamble_symbol_repetitions: u8, - /// Indicates the data rate - pub datrate: u8, - /// time units corresponding to an RMARKER at the antenna at the end of a ranging exchange, - pub ranging_received: u8, - pub ranging_counter_start: u32, - pub ranging_counter_stop: u32, - /// ime units in a message exchange over which the tracking offset was measured - pub ranging_tracking_interval: u32, - /// time units slipped or advanced by the radio tracking system - pub ranging_offset: u32, - /// The FoM characterizing the ranging measurement - pub ranging_fom: u8, - /// The Received Signal Strength Indicator measured - pub rssi: u8, -} - -impl ParseableMacEvent for DataIndication { - const SIZE: usize = 68; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - let src_addr_mode = AddressMode::try_from(buf[4])?; - let src_address = match src_addr_mode { - AddressMode::NoAddress => MacAddress { short: [0, 0] }, - AddressMode::Reserved => MacAddress { short: [0, 0] }, - AddressMode::Short => MacAddress { - short: [buf[7], buf[8]], - }, - AddressMode::Extended => MacAddress { - extended: [buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14]], - }, - }; - - let dst_addr_mode = AddressMode::try_from(buf[15])?; - let dst_address = match dst_addr_mode { - AddressMode::NoAddress => MacAddress { short: [0, 0] }, - AddressMode::Reserved => MacAddress { short: [0, 0] }, - AddressMode::Short => MacAddress { - short: [buf[18], buf[19]], - }, - AddressMode::Extended => MacAddress { - extended: [buf[18], buf[19], buf[20], buf[21], buf[22], buf[23], buf[24], buf[25]], - }, - }; - - Ok(Self { - msdu_ptr: to_u32(&buf[0..4]) as *const u8, - src_addr_mode, - src_pan_id: PanId([buf[5], buf[6]]), - src_address, - dst_addr_mode, - dst_pan_id: PanId([buf[16], buf[17]]), - dst_address, - msdu_length: buf[26], - mpdu_link_quality: buf[27], - dsn: buf[28], - time_stamp: [buf[29], buf[30], buf[31], buf[32]], - security_level: SecurityLevel::try_from(buf[33]).unwrap_or(SecurityLevel::Unsecure), // TODO: this is totaly wrong, but I'm too smol brain to fix it - key_id_mode: KeyIdMode::try_from(buf[34]).unwrap_or(KeyIdMode::Implicite), // TODO: this is totaly wrong, but I'm too smol brain to fix it - key_source: [buf[35], buf[36], buf[37], buf[38], buf[39], buf[40], buf[41], buf[42]], - key_index: buf[43], - uwbprf: buf[44], - uwn_preamble_symbol_repetitions: buf[45], - datrate: buf[46], - ranging_received: buf[47], - ranging_counter_start: to_u32(&buf[48..52]), - ranging_counter_stop: to_u32(&buf[52..56]), - ranging_tracking_interval: to_u32(&buf[56..60]), - ranging_offset: to_u32(&buf[60..64]), - ranging_fom: buf[65], - rssi: buf[66], - }) - } -} - -/// MLME POLL Indication which will be used for indicating the Data Request -/// reception to upper layer as defined in Zigbee r22 - D.8.2 -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PollIndication { - /// addressing mode used - pub addr_mode: AddressMode, - /// Poll requester address - pub request_address: MacAddress, -} - -impl ParseableMacEvent for PollIndication { - const SIZE: usize = 9; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - let addr_mode = AddressMode::try_from(buf[0])?; - let request_address = match addr_mode { - AddressMode::NoAddress => MacAddress { short: [0, 0] }, - AddressMode::Reserved => MacAddress { short: [0, 0] }, - AddressMode::Short => MacAddress { - short: [buf[1], buf[2]], - }, - AddressMode::Extended => MacAddress { - extended: [buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]], - }, - }; - - Ok(Self { - addr_mode, - request_address, - }) - } -} diff --git a/embassy-stm32-wpan/src/sub/mac/macros.rs b/embassy-stm32-wpan/src/sub/mac/macros.rs deleted file mode 100644 index 1a988a779..000000000 --- a/embassy-stm32-wpan/src/sub/mac/macros.rs +++ /dev/null @@ -1,32 +0,0 @@ -#[macro_export] -macro_rules! numeric_enum { - (#[repr($repr:ident)] - $(#$attrs:tt)* $vis:vis enum $name:ident { - $($(#$enum_attrs:tt)* $enum:ident = $constant:expr),* $(,)? - } ) => { - #[repr($repr)] - $(#$attrs)* - $vis enum $name { - $($(#$enum_attrs)* $enum = $constant),* - } - - impl ::core::convert::TryFrom<$repr> for $name { - type Error = (); - - fn try_from(value: $repr) -> ::core::result::Result { - match value { - $($constant => Ok( $name :: $enum ),)* - _ => Err(()) - } - } - } - - impl ::core::convert::From<$name> for $repr { - fn from(value: $name) -> $repr { - match value { - $($name :: $enum => $constant,)* - } - } - } - } -} diff --git a/embassy-stm32-wpan/src/sub/mac/mod.rs b/embassy-stm32-wpan/src/sub/mac/mod.rs deleted file mode 100644 index ab39f89c2..000000000 --- a/embassy-stm32-wpan/src/sub/mac/mod.rs +++ /dev/null @@ -1,143 +0,0 @@ -use core::future::poll_fn; -use core::marker::PhantomData; -use core::ptr; -use core::sync::atomic::{AtomicBool, Ordering}; -use core::task::Poll; - -use embassy_futures::poll_once; -use embassy_stm32::ipcc::Ipcc; -use embassy_sync::waitqueue::AtomicWaker; - -use self::commands::MacCommand; -use self::event::MacEvent; -use self::typedefs::MacError; -use crate::cmd::CmdPacket; -use crate::consts::TlPacketType; -use crate::evt::{EvtBox, EvtPacket}; -use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER}; -use crate::{channels, evt}; - -pub mod commands; -mod consts; -pub mod event; -mod helpers; -pub mod indications; -mod macros; -mod opcodes; -pub mod responses; -pub mod typedefs; - -static MAC_WAKER: AtomicWaker = AtomicWaker::new(); -static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); - -pub struct Mac { - phantom: PhantomData, -} - -impl Mac { - pub(crate) fn new() -> Self { - Self { phantom: PhantomData } - } - - /// `HW_IPCC_MAC_802_15_4_EvtNot` - /// - /// This function will stall if the previous `EvtBox` has not been dropped - pub async fn tl_read(&self) -> EvtBox { - // Wait for the last event box to be dropped - poll_fn(|cx| { - MAC_WAKER.register(cx.waker()); - if MAC_EVT_OUT.load(Ordering::SeqCst) { - Poll::Pending - } else { - Poll::Ready(()) - } - }) - .await; - - // Return a new event box - Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe { - // The closure is not async, therefore the closure must execute to completion (cannot be dropped) - // Therefore, the event box is guaranteed to be cleaned up if it's not leaked - MAC_EVT_OUT.store(true, Ordering::SeqCst); - - Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _)) - }) - .await - } - - /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` - pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { - self.tl_write(opcode, payload).await; - Ipcc::flush(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL).await; - - unsafe { - let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket; - let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8; - - ptr::read_volatile(p_mac_rsp_evt) - } - } - - /// `TL_MAC_802_15_4_SendCmd` - pub async fn tl_write(&self, opcode: u16, payload: &[u8]) { - Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe { - CmdPacket::write_into( - MAC_802_15_4_CMD_BUFFER.as_mut_ptr(), - TlPacketType::MacCmd, - opcode, - payload, - ); - }) - .await; - } - - pub async fn send_command(&self, cmd: &T) -> Result<(), MacError> - where - T: MacCommand, - { - let mut payload = [0u8; MAX_PACKET_SIZE]; - cmd.copy_into_slice(&mut payload); - - let response = self - .tl_write_and_get_response(T::OPCODE as u16, &payload[..T::SIZE]) - .await; - - if response == 0x00 { - Ok(()) - } else { - Err(MacError::from(response)) - } - } - - pub async fn read(&self) -> Result { - let evt_box = self.tl_read().await; - let payload = evt_box.payload(); - - MacEvent::try_from(payload) - } -} - -const MAX_PACKET_SIZE: usize = 255; - -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) { - // Write the ack - CmdPacket::write_into( - MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, - TlPacketType::OtAck, - 0, - &[], - ); - - // Clear the rx flag - let _ = poll_once(Ipcc::receive::( - channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, - || None, - )); - - // Allow a new read call - MAC_EVT_OUT.store(false, Ordering::SeqCst); - MAC_WAKER.wake(); - } -} diff --git a/embassy-stm32-wpan/src/sub/mac/opcodes.rs b/embassy-stm32-wpan/src/sub/mac/opcodes.rs deleted file mode 100644 index fd7011873..000000000 --- a/embassy-stm32-wpan/src/sub/mac/opcodes.rs +++ /dev/null @@ -1,92 +0,0 @@ -const ST_VENDOR_OGF: u16 = 0x3F; -const MAC_802_15_4_CMD_OPCODE_OFFSET: u16 = 0x280; - -const fn opcode(ocf: u16) -> isize { - ((ST_VENDOR_OGF << 9) | (MAC_802_15_4_CMD_OPCODE_OFFSET + ocf)) as isize -} - -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum OpcodeM4ToM0 { - MlmeAssociateReq = opcode(0x00), - MlmeAssociateRes = opcode(0x01), - MlmeDisassociateReq = opcode(0x02), - MlmeGetReq = opcode(0x03), - MlmeGtsReq = opcode(0x04), - MlmeOrphanRes = opcode(0x05), - MlmeResetReq = opcode(0x06), - MlmeRxEnableReq = opcode(0x07), - MlmeScanReq = opcode(0x08), - MlmeSetReq = opcode(0x09), - MlmeStartReq = opcode(0x0A), - MlmeSyncReq = opcode(0x0B), - MlmePollReq = opcode(0x0C), - MlmeDpsReq = opcode(0x0D), - MlmeSoundingReq = opcode(0x0E), - MlmeCalibrateReq = opcode(0x0F), - McpsDataReq = opcode(0x10), - McpsPurgeReq = opcode(0x11), -} - -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum OpcodeM0ToM4 { - MlmeAssociateCnf = 0x00, - MlmeDisassociateCnf, - MlmeGetCnf, - MlmeGtsCnf, - MlmeResetCnf, - MlmeRxEnableCnf, - MlmeScanCnf, - MlmeSetCnf, - MlmeStartCnf, - MlmePollCnf, - MlmeDpsCnf, - MlmeSoundingCnf, - MlmeCalibrateCnf, - McpsDataCnf, - McpsPurgeCnf, - MlmeAssociateInd, - MlmeDisassociateInd, - MlmeBeaconNotifyInd, - MlmeCommStatusInd, - MlmeGtsInd, - MlmeOrphanInd, - MlmeSyncLossInd, - MlmeDpsInd, - McpsDataInd, - MlmePollInd, -} - -impl TryFrom for OpcodeM0ToM4 { - type Error = (); - - fn try_from(value: u16) -> Result { - match value { - 0 => Ok(Self::MlmeAssociateCnf), - 1 => Ok(Self::MlmeDisassociateCnf), - 2 => Ok(Self::MlmeGetCnf), - 3 => Ok(Self::MlmeGtsCnf), - 4 => Ok(Self::MlmeResetCnf), - 5 => Ok(Self::MlmeRxEnableCnf), - 6 => Ok(Self::MlmeScanCnf), - 7 => Ok(Self::MlmeSetCnf), - 8 => Ok(Self::MlmeStartCnf), - 9 => Ok(Self::MlmePollCnf), - 10 => Ok(Self::MlmeDpsCnf), - 11 => Ok(Self::MlmeSoundingCnf), - 12 => Ok(Self::MlmeCalibrateCnf), - 13 => Ok(Self::McpsDataCnf), - 14 => Ok(Self::McpsPurgeCnf), - 15 => Ok(Self::MlmeAssociateInd), - 16 => Ok(Self::MlmeDisassociateInd), - 17 => Ok(Self::MlmeBeaconNotifyInd), - 18 => Ok(Self::MlmeCommStatusInd), - 19 => Ok(Self::MlmeGtsInd), - 20 => Ok(Self::MlmeOrphanInd), - 21 => Ok(Self::MlmeSyncLossInd), - 22 => Ok(Self::MlmeDpsInd), - 23 => Ok(Self::McpsDataInd), - 24 => Ok(Self::MlmePollInd), - _ => Err(()), - } - } -} diff --git a/embassy-stm32-wpan/src/sub/mac/responses.rs b/embassy-stm32-wpan/src/sub/mac/responses.rs deleted file mode 100644 index 2f6f5bf58..000000000 --- a/embassy-stm32-wpan/src/sub/mac/responses.rs +++ /dev/null @@ -1,433 +0,0 @@ -use super::consts::{MAX_ED_SCAN_RESULTS_SUPPORTED, MAX_PAN_DESC_SUPPORTED, MAX_SOUNDING_LIST_SUPPORTED}; -use super::event::ParseableMacEvent; -use super::helpers::to_u32; -use super::typedefs::{ - AddressMode, AssociationStatus, KeyIdMode, MacAddress, MacStatus, PanDescriptor, PanId, PibId, ScanType, - SecurityLevel, -}; - -/// MLME ASSOCIATE Confirm used to inform of the initiating device whether -/// its request to associate was successful or unsuccessful -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct AssociateConfirm { - /// short address allocated by the coordinator on successful association - pub assoc_short_address: [u8; 2], - /// status of the association request - pub status: AssociationStatus, - /// security level to be used - pub security_level: SecurityLevel, - /// the originator of the key to be used - pub key_source: [u8; 8], - /// the mode used to identify the key to be used - pub key_id_mode: KeyIdMode, - /// the index of the key to be used - pub key_index: u8, -} - -impl ParseableMacEvent for AssociateConfirm { - const SIZE: usize = 16; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - assoc_short_address: [buf[0], buf[1]], - status: AssociationStatus::try_from(buf[2])?, - security_level: SecurityLevel::try_from(buf[3])?, - key_source: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]], - key_id_mode: KeyIdMode::try_from(buf[12])?, - key_index: buf[13], - }) - } -} - -/// MLME DISASSOCIATE Confirm used to send disassociation Confirmation to the application. -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DisassociateConfirm { - /// status of the disassociation attempt - pub status: MacStatus, - /// device addressing mode used - pub device_addr_mode: AddressMode, - /// the identifier of the PAN of the device - pub device_pan_id: PanId, - /// device address - pub device_address: MacAddress, -} - -impl ParseableMacEvent for DisassociateConfirm { - const SIZE: usize = 12; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - let device_addr_mode = AddressMode::try_from(buf[1])?; - let device_address = match device_addr_mode { - AddressMode::NoAddress => MacAddress { short: [0, 0] }, - AddressMode::Reserved => MacAddress { short: [0, 0] }, - AddressMode::Short => MacAddress { - short: [buf[4], buf[5]], - }, - AddressMode::Extended => MacAddress { - extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]], - }, - }; - - Ok(Self { - status: MacStatus::try_from(buf[0])?, - device_addr_mode, - device_pan_id: PanId([buf[2], buf[3]]), - device_address, - }) - } -} - -/// MLME GET Confirm which requests information about a given PIB attribute -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct GetConfirm { - /// The pointer to the value of the PIB attribute attempted to read - pub pib_attribute_value_ptr: *const u8, - /// Status of the GET attempt - pub status: MacStatus, - /// The name of the PIB attribute attempted to read - pub pib_attribute: PibId, - /// The lenght of the PIB attribute Value return - pub pib_attribute_value_len: u8, -} - -impl ParseableMacEvent for GetConfirm { - const SIZE: usize = 8; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - let address = to_u32(&buf[0..4]); - - Ok(Self { - pib_attribute_value_ptr: address as *const u8, - status: MacStatus::try_from(buf[4])?, - pib_attribute: PibId::try_from(buf[5])?, - pib_attribute_value_len: buf[6], - }) - } -} - -/// MLME GTS Confirm which eports the results of a request to allocate a new GTS -/// or to deallocate an existing GTS -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct GtsConfirm { - /// The characteristics of the GTS - pub gts_characteristics: u8, - /// The status of the GTS reques - pub status: MacStatus, -} - -impl ParseableMacEvent for GtsConfirm { - const SIZE: usize = 4; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - gts_characteristics: buf[0], - status: MacStatus::try_from(buf[1])?, - }) - } -} - -/// MLME RESET Confirm which is used to report the results of the reset operation -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ResetConfirm { - /// The result of the reset operation - status: MacStatus, -} - -impl ParseableMacEvent for ResetConfirm { - const SIZE: usize = 4; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - status: MacStatus::try_from(buf[0])?, - }) - } -} - -/// MLME RX ENABLE Confirm which is used to report the results of the attempt -/// to enable or disable the receiver -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct RxEnableConfirm { - /// Result of the request to enable or disable the receiver - status: MacStatus, -} - -impl ParseableMacEvent for RxEnableConfirm { - const SIZE: usize = 4; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - status: MacStatus::try_from(buf[0])?, - }) - } -} - -/// MLME SCAN Confirm which is used to report the result of the channel scan request -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ScanConfirm { - /// Status of the scan request - pub status: MacStatus, - /// The type of scan performed - pub scan_type: ScanType, - /// Channel page on which the scan was performed - pub channel_page: u8, - /// Channels given in the request which were not scanned - pub unscanned_channels: [u8; 4], - /// Number of elements returned in the appropriate result lists - pub result_list_size: u8, - /// List of energy measurements - pub energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED], - /// List of PAN descriptors - pub pan_descriptor_list: [PanDescriptor; MAX_PAN_DESC_SUPPORTED], - /// Categorization of energy detected in channel - pub detected_category: u8, - /// For UWB PHYs, the list of energy measurements taken - pub uwb_energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED], -} - -impl ParseableMacEvent for ScanConfirm { - const SIZE: usize = 185; - - fn try_parse(buf: &[u8]) -> Result { - // TODO: this is unchecked - - Self::validate(buf)?; - - let mut energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED]; - energy_detect_list.copy_from_slice(&buf[8..24]); - - let pan_descriptor_list = [ - PanDescriptor::try_from(&buf[24..46])?, - PanDescriptor::try_from(&buf[46..68])?, - PanDescriptor::try_from(&buf[68..90])?, - PanDescriptor::try_from(&buf[90..102])?, - PanDescriptor::try_from(&buf[102..124])?, - PanDescriptor::try_from(&buf[124..146])?, - ]; - - let mut uwb_energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED]; - uwb_energy_detect_list.copy_from_slice(&buf[147..163]); - - Ok(Self { - status: MacStatus::try_from(buf[0])?, - scan_type: ScanType::try_from(buf[1])?, - channel_page: buf[2], - unscanned_channels: [buf[3], buf[4], buf[5], buf[6]], - result_list_size: buf[7], - energy_detect_list, - pan_descriptor_list, - detected_category: buf[146], - uwb_energy_detect_list, - }) - } -} - -/// MLME SET Confirm which reports the result of an attempt to write a value to a PIB attribute -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct SetConfirm { - /// The result of the set operation - pub status: MacStatus, - /// The name of the PIB attribute that was written - pub pin_attribute: PibId, -} - -impl ParseableMacEvent for SetConfirm { - const SIZE: usize = 4; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - status: MacStatus::try_from(buf[0])?, - pin_attribute: PibId::try_from(buf[1])?, - }) - } -} - -/// MLME START Confirm which is used to report the results of the attempt to -/// start using a new superframe configuration -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct StartConfirm { - /// Result of the attempt to start using an updated superframe configuration - pub status: MacStatus, -} - -impl ParseableMacEvent for StartConfirm { - const SIZE: usize = 4; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - status: MacStatus::try_from(buf[0])?, - }) - } -} - -/// MLME POLL Confirm which is used to report the result of a request to poll the coordinator for data -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PollConfirm { - /// The status of the data request - pub status: MacStatus, -} - -impl ParseableMacEvent for PollConfirm { - const SIZE: usize = 4; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - status: MacStatus::try_from(buf[0])?, - }) - } -} - -/// MLME DPS Confirm which reports the results of the attempt to enable or disable the DPS -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DpsConfirm { - /// The status of the DPS request - pub status: MacStatus, -} - -impl ParseableMacEvent for DpsConfirm { - const SIZE: usize = 4; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - status: MacStatus::try_from(buf[0])?, - }) - } -} - -/// MLME SOUNDING Confirm which reports the result of a request to the PHY to provide -/// channel sounding information -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct SoundingConfirm { - /// Results of the sounding measurement - sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED], -} - -impl ParseableMacEvent for SoundingConfirm { - const SIZE: usize = 1; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - let mut sounding_list = [0u8; MAX_SOUNDING_LIST_SUPPORTED]; - sounding_list[..buf.len()].copy_from_slice(buf); - - Ok(Self { sounding_list }) - } -} - -/// MLME CALIBRATE Confirm which reports the result of a request to the PHY -/// to provide internal propagation path information -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CalibrateConfirm { - /// The status of the attempt to return sounding data - pub status: MacStatus, - /// A count of the propagation time from the ranging counter - /// to the transmit antenna - pub cal_tx_rmaker_offset: u32, - /// A count of the propagation time from the receive antenna - /// to the ranging counter - pub cal_rx_rmaker_offset: u32, -} - -impl ParseableMacEvent for CalibrateConfirm { - const SIZE: usize = 12; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - status: MacStatus::try_from(buf[0])?, - // 3 byte stuffing - cal_tx_rmaker_offset: to_u32(&buf[4..8]), - cal_rx_rmaker_offset: to_u32(&buf[8..12]), - }) - } -} - -/// MCPS DATA Confirm which will be used for reporting the results of -/// MAC data related requests from the application -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DataConfirm { - /// The handle associated with the MSDU being confirmed - pub msdu_handle: u8, - /// The time, in symbols, at which the data were transmitted - pub time_stamp: [u8; 4], - /// ranging status - pub ranging_received: u8, - /// The status of the last MSDU transmission - pub status: MacStatus, - /// time units corresponding to an RMARKER at the antenna at - /// the beginning of a ranging exchange - pub ranging_counter_start: u32, - /// time units corresponding to an RMARKER at the antenna - /// at the end of a ranging exchange - pub ranging_counter_stop: u32, - /// time units in a message exchange over which the tracking offset was measured - pub ranging_tracking_interval: u32, - /// time units slipped or advanced by the radio tracking system - pub ranging_offset: u32, - /// The FoM characterizing the ranging measurement - pub ranging_fom: u8, -} - -impl ParseableMacEvent for DataConfirm { - const SIZE: usize = 28; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - msdu_handle: buf[0], - time_stamp: [buf[1], buf[2], buf[3], buf[4]], - ranging_received: buf[5], - status: MacStatus::try_from(buf[6])?, - ranging_counter_start: to_u32(&buf[7..11]), - ranging_counter_stop: to_u32(&buf[11..15]), - ranging_tracking_interval: to_u32(&buf[15..19]), - ranging_offset: to_u32(&buf[19..23]), - ranging_fom: buf[24], - }) - } -} - -/// 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 -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PurgeConfirm { - /// Handle associated with the MSDU requested to be purged from the transaction queue - pub msdu_handle: u8, - /// The status of the request - pub status: MacStatus, -} - -impl ParseableMacEvent for PurgeConfirm { - const SIZE: usize = 4; - - fn try_parse(buf: &[u8]) -> Result { - Self::validate(buf)?; - - Ok(Self { - msdu_handle: buf[0], - status: MacStatus::try_from(buf[1])?, - }) - } -} diff --git a/embassy-stm32-wpan/src/sub/mac/typedefs.rs b/embassy-stm32-wpan/src/sub/mac/typedefs.rs deleted file mode 100644 index 30c7731b2..000000000 --- a/embassy-stm32-wpan/src/sub/mac/typedefs.rs +++ /dev/null @@ -1,363 +0,0 @@ -use crate::numeric_enum; - -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum MacError { - Error = 0x01, - NotImplemented = 0x02, - NotSupported = 0x03, - HardwareNotSupported = 0x04, - Undefined = 0x05, -} - -impl From for MacError { - fn from(value: u8) -> Self { - match value { - 0x01 => Self::Error, - 0x02 => Self::NotImplemented, - 0x03 => Self::NotSupported, - 0x04 => Self::HardwareNotSupported, - 0x05 => Self::Undefined, - _ => Self::Undefined, - } - } -} - -numeric_enum! { - #[repr(u8)] - #[derive(Debug, Default)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum MacStatus { - #[default] - Success = 0x00, - Failure = 0xFF - } -} - -numeric_enum! { - #[repr(u8)] - /// this enum contains all the MAC PIB Ids - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum PibId { - // PHY - CurrentChannel = 0x00, - ChannelsSupported = 0x01, - TransmitPower = 0x02, - CCAMode = 0x03, - CurrentPage = 0x04, - MaxFrameDuration = 0x05, - SHRDuration = 0x06, - SymbolsPerOctet = 0x07, - - // MAC - AckWaitDuration = 0x40, - AssociationPermit = 0x41, - AutoRequest = 0x42, - BeaconPayload = 0x45, - BeaconPayloadLength = 0x46, - BeaconOrder = 0x47, - Bsn = 0x49, - CoordExtendedAdddress = 0x4A, - CoordShortAddress = 0x4B, - Dsn = 0x4C, - MaxFrameTotalWaitTime = 0x58, - MaxFrameRetries = 0x59, - PanId = 0x50, - ResponseWaitTime = 0x5A, - RxOnWhenIdle = 0x52, - SecurityEnabled = 0x5D, - ShortAddress = 0x53, - SuperframeOrder = 0x54, - TimestampSupported = 0x5C, - TransactionPersistenceTime = 0x55, - MaxBe = 0x57, - LifsPeriod = 0x5E, - SifsPeriod = 0x5F, - MaxCsmaBackoffs = 0x4E, - MinBe = 0x4F, - PanCoordinator = 0x10, - AssocPanCoordinator = 0x11, - ExtendedAddress = 0x6F, - AclEntryDescriptor = 0x70, - AclEntryDescriptorSize = 0x71, - DefaultSecurity = 0x72, - DefaultSecurityMaterialLength = 0x73, - DefaultSecurityMaterial = 0x74, - DefaultSecuritySuite = 0x75, - SecurityMode = 0x76, - CurrentAclEntries = 0x80, - DefaultSecurityExtendedAddress = 0x81, - AssociatedPanCoordinator = 0x56, - PromiscuousMode = 0x51, - } -} - -numeric_enum! { - #[repr(u8)] - #[derive(Default, Clone, Copy)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum AddressMode { - #[default] - NoAddress = 0x00, - Reserved = 0x01, - Short = 0x02, - Extended = 0x03, -} -} - -#[derive(Clone, Copy)] -pub union MacAddress { - pub short: [u8; 2], - pub extended: [u8; 8], -} - -#[cfg(feature = "defmt")] -impl defmt::Format for MacAddress { - fn format(&self, fmt: defmt::Formatter) { - unsafe { - defmt::write!( - fmt, - "MacAddress {{ short: {}, extended: {} }}", - self.short, - self.extended - ) - } - } -} - -impl Default for MacAddress { - fn default() -> Self { - Self { short: [0, 0] } - } -} - -impl MacAddress { - pub const BROADCAST: Self = Self { short: [0xFF, 0xFF] }; -} - -impl TryFrom<&[u8]> for MacAddress { - type Error = (); - - fn try_from(buf: &[u8]) -> Result { - const SIZE: usize = 8; - if buf.len() < SIZE { - return Err(()); - } - - Ok(Self { - extended: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]], - }) - } -} - -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct GtsCharacteristics { - pub fields: u8, -} - -/// MAC PAN Descriptor which contains the network details of the device from -/// which the beacon is received -#[derive(Default, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PanDescriptor { - /// PAN identifier of the coordinator - pub coord_pan_id: PanId, - /// Coordinator addressing mode - pub coord_addr_mode: AddressMode, - /// The current logical channel occupied by the network - pub logical_channel: MacChannel, - /// Coordinator address - pub coord_addr: MacAddress, - /// The current channel page occupied by the network - pub channel_page: u8, - /// PAN coordinator is accepting GTS requests or not - pub gts_permit: bool, - /// Superframe specification as specified in the received beacon frame - pub superframe_spec: [u8; 2], - /// The time at which the beacon frame was received, in symbols - pub time_stamp: [u8; 4], - /// The LQI at which the network beacon was received - pub link_quality: u8, - /// Security level purportedly used by the received beacon frame - pub security_level: u8, -} - -impl TryFrom<&[u8]> for PanDescriptor { - type Error = (); - - fn try_from(buf: &[u8]) -> Result { - const SIZE: usize = 22; - if buf.len() < SIZE { - return Err(()); - } - - let coord_addr_mode = AddressMode::try_from(buf[2])?; - let coord_addr = match coord_addr_mode { - AddressMode::NoAddress => MacAddress { short: [0, 0] }, - AddressMode::Reserved => MacAddress { short: [0, 0] }, - AddressMode::Short => MacAddress { - short: [buf[4], buf[5]], - }, - AddressMode::Extended => MacAddress { - extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]], - }, - }; - - Ok(Self { - coord_pan_id: PanId([buf[0], buf[1]]), - coord_addr_mode, - logical_channel: MacChannel::try_from(buf[3])?, - coord_addr, - channel_page: buf[12], - gts_permit: buf[13] != 0, - superframe_spec: [buf[14], buf[15]], - time_stamp: [buf[16], buf[17], buf[18], buf[19]], - link_quality: buf[20], - security_level: buf[21], - // 2 byte stuffing - }) - } -} - -numeric_enum! { - #[repr(u8)] - #[derive(Default, Clone, Copy)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - /// Building wireless applications with STM32WB series MCUs - Application note 13.10.3 - pub enum MacChannel { - Channel11 = 0x0B, - Channel12 = 0x0C, - Channel13 = 0x0D, - Channel14 = 0x0E, - Channel15 = 0x0F, - #[default] - Channel16 = 0x10, - Channel17 = 0x11, - Channel18 = 0x12, - Channel19 = 0x13, - Channel20 = 0x14, - Channel21 = 0x15, - Channel22 = 0x16, - Channel23 = 0x17, - Channel24 = 0x18, - Channel25 = 0x19, - Channel26 = 0x1A, - } -} - -#[cfg(not(feature = "defmt"))] -bitflags::bitflags! { - pub struct Capabilities: u8 { - /// 1 if the device is capabaleof becoming a PAN coordinator - const IS_COORDINATOR_CAPABLE = 0b00000001; - /// 1 if the device is an FFD, 0 if it is an RFD - const IS_FFD = 0b00000010; - /// 1 if the device is receiving power from mains, 0 if it is battery-powered - const IS_MAINS_POWERED = 0b00000100; - /// 1 if the device does not disable its receiver to conserver power during idle periods - const RECEIVER_ON_WHEN_IDLE = 0b00001000; - // 0b00010000 reserved - // 0b00100000 reserved - /// 1 if the device is capable of sending and receiving secured MAC frames - const IS_SECURE = 0b01000000; - /// 1 if the device wishes the coordinator to allocate a short address as a result of the association - const ALLOCATE_ADDRESS = 0b10000000; - } -} - -#[cfg(feature = "defmt")] -defmt::bitflags! { - pub struct Capabilities: u8 { - /// 1 if the device is capabaleof becoming a PAN coordinator - const IS_COORDINATOR_CAPABLE = 0b00000001; - /// 1 if the device is an FFD, 0 if it is an RFD - const IS_FFD = 0b00000010; - /// 1 if the device is receiving power from mains, 0 if it is battery-powered - const IS_MAINS_POWERED = 0b00000100; - /// 1 if the device does not disable its receiver to conserver power during idle periods - const RECEIVER_ON_WHEN_IDLE = 0b00001000; - // 0b00010000 reserved - // 0b00100000 reserved - /// 1 if the device is capable of sending and receiving secured MAC frames - const IS_SECURE = 0b01000000; - /// 1 if the device wishes the coordinator to allocate a short address as a result of the association - const ALLOCATE_ADDRESS = 0b10000000; - } -} - -numeric_enum! { - #[repr(u8)] - #[derive(Default, Clone, Copy)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum KeyIdMode { - #[default] - /// the key is determined implicitly from the originator and recipient(s) of the frame - Implicite = 0x00, - /// the key is determined explicitly using a 1 bytes key source and a 1 byte key index - Explicite1Byte = 0x01, - /// the key is determined explicitly using a 4 bytes key source and a 1 byte key index - Explicite4Byte = 0x02, - /// the key is determined explicitly using a 8 bytes key source and a 1 byte key index - Explicite8Byte = 0x03, - } -} - -numeric_enum! { - #[repr(u8)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum AssociationStatus { - /// Association successful - Success = 0x00, - /// PAN at capacity - PanAtCapacity = 0x01, - /// PAN access denied - PanAccessDenied = 0x02 - } -} - -numeric_enum! { - #[repr(u8)] - #[derive(Clone, Copy)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum DisassociationReason { - /// The coordinator wishes the device to leave the PAN. - CoordRequested = 0x01, - /// The device wishes to leave the PAN. - DeviceRequested = 0x02, - } -} - -numeric_enum! { - #[repr(u8)] - #[derive(Default, Clone, Copy)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum SecurityLevel { - /// MAC Unsecured Mode Security - #[default] - Unsecure = 0x00, - /// MAC ACL Mode Security - AclMode = 0x01, - /// MAC Secured Mode Security - Secured = 0x02, - } -} - -numeric_enum! { - #[repr(u8)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum ScanType { - EdScan = 0x00, - Active = 0x01, - Passive = 0x02, - Orphan = 0x03 - } -} - -/// newtype for Pan Id -#[derive(Default, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PanId(pub [u8; 2]); - -impl PanId { - pub const BROADCAST: Self = Self([0xFF, 0xFF]); -} diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index 689a28353..e4d81997e 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs @@ -6,9 +6,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; -use embassy_stm32_wpan::sub::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest}; -use embassy_stm32_wpan::sub::mac::event::MacEvent; -use embassy_stm32_wpan::sub::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel}; +use embassy_stm32_wpan::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest}; +use embassy_stm32_wpan::mac::event::MacEvent; +use embassy_stm32_wpan::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel}; use embassy_stm32_wpan::sub::mm; use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs index ea349f9a8..b2dac72cc 100644 --- a/examples/stm32wb/src/bin/mac_rfd.rs +++ b/examples/stm32wb/src/bin/mac_rfd.rs @@ -6,9 +6,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; -use embassy_stm32_wpan::sub::mac::commands::{AssociateRequest, DataRequest, GetRequest, ResetRequest, SetRequest}; -use embassy_stm32_wpan::sub::mac::event::MacEvent; -use embassy_stm32_wpan::sub::mac::typedefs::{ +use embassy_stm32_wpan::mac::commands::{AssociateRequest, DataRequest, GetRequest, ResetRequest, SetRequest}; +use embassy_stm32_wpan::mac::event::MacEvent; +use embassy_stm32_wpan::mac::typedefs::{ AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel, }; use embassy_stm32_wpan::sub::mm; diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs index d97a4d404..cfa0aca3b 100644 --- a/tests/stm32/src/bin/wpan_mac.rs +++ b/tests/stm32/src/bin/wpan_mac.rs @@ -10,9 +10,9 @@ use common::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; -use embassy_stm32_wpan::sub::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest}; -use embassy_stm32_wpan::sub::mac::event::MacEvent; -use embassy_stm32_wpan::sub::mac::typedefs::{ +use embassy_stm32_wpan::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest}; +use embassy_stm32_wpan::mac::event::MacEvent; +use embassy_stm32_wpan::mac::typedefs::{ AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel, }; use embassy_stm32_wpan::sub::mm; -- cgit