parsing MAC structs

This commit is contained in:
goueslati 2023-07-12 15:06:56 +01:00
parent fbddfcbfb7
commit d5a4457b5e
12 changed files with 1107 additions and 283 deletions

View File

@ -26,13 +26,14 @@ aligned = "0.4.1"
bit_field = "0.10.2" bit_field = "0.10.2"
stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
stm32wb-hci = { version = "0.1.2", features = ["version-5-0"], optional = true } stm32wb-hci = { version = "0.1.2", features = ["version-5-0"], optional = true }
bitflags = { version = "2.3.3", optional = true }
[features] [features]
default = ["stm32wb55rg", "mac", "ble"] default = ["stm32wb55rg", "mac", "ble", "defmt"]
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
ble = ["dep:stm32wb-hci"] ble = ["dep:stm32wb-hci"]
mac = [] mac = ["dep:bitflags"]
stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]

View File

@ -1,5 +1,8 @@
use super::opcodes::OpcodeM4ToM0; use super::opcodes::OpcodeM4ToM0;
use super::typedefs::{AddressMode, GtsCharacteristics, MacAddress, PibId}; use super::typedefs::{
AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, PibId,
ScanType, SecurityLevel,
};
pub trait MacCommand { pub trait MacCommand {
const OPCODE: OpcodeM4ToM0; const OPCODE: OpcodeM4ToM0;
@ -14,19 +17,19 @@ pub trait MacCommand {
#[repr(C)] #[repr(C)]
pub struct AssociateRequest { pub struct AssociateRequest {
/// the logical channel on which to attempt association /// the logical channel on which to attempt association
pub channel_number: u8, pub channel_number: MacChannel,
/// the channel page on which to attempt association /// the channel page on which to attempt association
pub channel_page: u8, pub channel_page: u8,
/// coordinator addressing mode /// coordinator addressing mode
pub coord_addr_mode: AddressMode, pub coord_addr_mode: AddressMode,
/// operational capabilities of the associating device /// operational capabilities of the associating device
pub capability_information: u8, pub capability_information: Capabilities,
/// the identifier of the PAN with which to associate /// the identifier of the PAN with which to associate
pub coord_pan_id: [u8; 2], pub coord_pan_id: [u8; 2],
/// the security level to be used /// the security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// the mode used to identify the key to be used /// the mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// the originator of the key to be used /// the originator of the key to be used
pub key_source: [u8; 8], pub key_source: [u8; 8],
/// Coordinator address /// Coordinator address
@ -48,15 +51,15 @@ pub struct DisassociateRequest {
/// the identifier of the PAN of the device /// the identifier of the PAN of the device
pub device_pan_id: [u8; 2], pub device_pan_id: [u8; 2],
/// the reason for the disassociation /// the reason for the disassociation
pub disassociate_reason: u8, pub disassociation_reason: DisassociationReason,
/// device address /// device address
pub device_address: MacAddress, pub device_address: MacAddress,
/// `true` if the disassociation notification command is to be sent indirectly /// `true` if the disassociation notification command is to be sent indirectly
pub tx_indirect: bool, pub tx_indirect: bool,
/// the security level to be used /// the security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// the mode to be used to indetify the key to be used /// the mode to be used to indetify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// the index of the key to be used /// the index of the key to be used
pub key_index: u8, pub key_index: u8,
/// the originator of the key to be used /// the originator of the key to be used
@ -86,9 +89,9 @@ pub struct GtsRequest {
/// the characteristics of the GTS /// the characteristics of the GTS
pub characteristics: GtsCharacteristics, pub characteristics: GtsCharacteristics,
/// the security level to be used /// the security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// the mode used to identify the key to be used /// the mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// the index of the key to be used /// the index of the key to be used
pub key_index: u8, pub key_index: u8,
/// the originator of the key to be used /// the originator of the key to be used
@ -147,19 +150,19 @@ impl MacCommand for RxEnableRequest {
#[repr(C)] #[repr(C)]
pub struct ScanRequest { pub struct ScanRequest {
/// the type of scan to be performed /// the type of scan to be performed
pub scan_type: u8, pub scan_type: ScanType,
/// the time spent on scanning each channel /// the time spent on scanning each channel
pub scan_duration: u8, pub scan_duration: u8,
/// channel page on which to perform the scan /// channel page on which to perform the scan
pub channel_page: u8, pub channel_page: u8,
/// security level to be used /// security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// indicate which channels are to be scanned /// indicate which channels are to be scanned
pub scan_channels: [u8; 4], pub scan_channels: [u8; 4],
/// originator the key to be used /// originator the key to be used
pub key_source: [u8; 8], pub key_source: [u8; 8],
/// mode used to identify the key to be used /// mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// index of the key to be used /// index of the key to be used
pub key_index: u8, pub key_index: u8,
} }
@ -191,7 +194,7 @@ pub struct StartRequest {
/// PAN indentifier to used by the device /// PAN indentifier to used by the device
pub pan_id: [u8; 2], pub pan_id: [u8; 2],
/// logical channel on which to begin /// logical channel on which to begin
pub channel_number: u8, pub channel_number: MacChannel,
/// channel page on which to begin /// channel page on which to begin
pub channel_page: u8, pub channel_page: u8,
/// time at which to begin transmitting beacons /// time at which to begin transmitting beacons
@ -207,15 +210,15 @@ pub struct StartRequest {
/// indicated if the coordinator realignment command is to be trasmitted /// indicated if the coordinator realignment command is to be trasmitted
pub coord_realignment: u8, pub coord_realignment: u8,
/// indicated if the coordinator realignment command is to be trasmitted /// indicated if the coordinator realignment command is to be trasmitted
pub coord_realign_security_level: u8, pub coord_realign_security_level: SecurityLevel,
/// index of the key to be used /// index of the key to be used
pub coord_realign_key_id_index: u8, pub coord_realign_key_id_index: u8,
/// originator of the key to be used /// originator of the key to be used
pub coord_realign_key_source: [u8; 8], pub coord_realign_key_source: [u8; 8],
/// security level to be used for beacon frames /// security level to be used for beacon frames
pub beacon_security_level: u8, pub beacon_security_level: SecurityLevel,
/// mode used to identify the key to be used /// mode used to identify the key to be used
pub beacon_key_id_mode: u8, pub beacon_key_id_mode: KeyIdMode,
/// index of the key to be used /// index of the key to be used
pub beacon_key_index: u8, pub beacon_key_index: u8,
/// originator of the key to be used /// originator of the key to be used
@ -232,7 +235,7 @@ impl MacCommand for StartRequest {
#[repr(C)] #[repr(C)]
pub struct SyncRequest { pub struct SyncRequest {
/// the channel number on which to attempt coordinator synchronization /// the channel number on which to attempt coordinator synchronization
pub channel_number: u8, pub channel_number: MacChannel,
/// the channel page on which to attempt coordinator synchronization /// the channel page on which to attempt coordinator synchronization
pub channel_page: u8, pub channel_page: u8,
/// `true` if the MLME is to synchronize with the next beacon and attempts /// `true` if the MLME is to synchronize with the next beacon and attempts
@ -253,9 +256,9 @@ pub struct PollRequest {
/// addressing mode of the coordinator /// addressing mode of the coordinator
pub coord_addr_mode: AddressMode, pub coord_addr_mode: AddressMode,
/// security level to be used /// security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// mode used to identify the key to be used /// mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// index of the key to be used /// index of the key to be used
pub key_index: u8, pub key_index: u8,
/// coordinator address /// coordinator address
@ -335,9 +338,9 @@ pub struct DataRequest {
/// the pending bit transmission options for the MSDU /// the pending bit transmission options for the MSDU
pub indirect_tx: u8, pub indirect_tx: u8,
/// the security level to be used /// the security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// the mode used to indentify the key to be used /// the mode used to indentify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// the index of the key to be used /// the index of the key to be used
pub key_index: u8, pub key_index: u8,
/// the originator of the key to be used /// the originator of the key to be used
@ -381,11 +384,11 @@ pub struct AssociateResponse {
/// status of the association attempt /// status of the association attempt
pub status: u8, pub status: u8,
/// security level to be used /// security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// the originator of the key to be used /// the originator of the key to be used
pub key_source: [u8; 8], pub key_source: [u8; 8],
/// the mode used to identify the key to be used /// the mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// the index of the key to be used /// the index of the key to be used
pub key_index: u8, pub key_index: u8,
} }
@ -405,11 +408,11 @@ pub struct OrphanResponse {
/// if the orphaned device is associated with coordinator or not /// if the orphaned device is associated with coordinator or not
pub associated_member: bool, pub associated_member: bool,
/// security level to be used /// security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// the originator of the key to be used /// the originator of the key to be used
pub key_source: [u8; 8], pub key_source: [u8; 8],
/// the mode used to identify the key to be used /// the mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// the index of the key to be used /// the index of the key to be used
pub key_index: u8, pub key_index: u8,
} }

View File

@ -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::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<Self, ()>
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<Self, Self::Error> {
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)?)),
}
}
}

View File

@ -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)
}

View File

@ -1,45 +1,84 @@
use super::consts::MAX_PENDING_ADDRESS; use super::consts::MAX_PENDING_ADDRESS;
use super::typedefs::{AddressMode, MacAddress, PanDescriptor}; use super::event::ParseableMacEvent;
use super::helpers::to_u32;
use super::typedefs::{
AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor,
SecurityLevel,
};
/// MLME ASSOCIATE Indication which will be used by the MAC /// MLME ASSOCIATE Indication which will be used by the MAC
/// to indicate the reception of an association request command /// to indicate the reception of an association request command
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AssociateIndication { pub struct AssociateIndication {
/// Extended address of the device requesting association /// Extended address of the device requesting association
pub device_address: [u8; 8], pub device_address: [u8; 8],
/// Operational capabilities of the device requesting association /// Operational capabilities of the device requesting association
pub capability_information: u8, pub capability_information: Capabilities,
/// Security level purportedly used by the received MAC command frame /// Security level purportedly used by the received MAC command frame
pub security_level: u8, pub security_level: SecurityLevel,
/// The mode used to identify the key used by the originator of frame /// The mode used to identify the key used by the originator of frame
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// Index of the key used by the originator of the received frame /// Index of the key used by the originator of the received frame
pub key_index: u8, pub key_index: u8,
/// The originator of the key used by the originator of the received frame /// The originator of the key used by the originator of the received frame
pub key_source: [u8; 8], pub key_source: [u8; 8],
} }
impl ParseableMacEvent for AssociateIndication {
const SIZE: usize = 20;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME DISASSOCIATE indication which will be used to send
/// disassociation indication to the application. /// disassociation indication to the application.
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DisassociateIndication { pub struct DisassociateIndication {
/// Extended address of the device requesting association /// Extended address of the device requesting association
pub device_address: [u8; 8], pub device_address: [u8; 8],
/// The reason for the disassociation /// The reason for the disassociation
pub disassociate_reason: u8, pub disassociation_reason: DisassociationReason,
/// The security level to be used /// The security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// The mode used to identify the key to be used /// The mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// The index of the key to be used /// The index of the key to be used
pub key_index: u8, pub key_index: u8,
/// The originator of the key to be used /// The originator of the key to be used
pub key_source: [u8; 8], pub key_source: [u8; 8],
} }
impl ParseableMacEvent for DisassociateIndication {
const SIZE: usize = 20;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME BEACON NOTIIFY Indication which is used to send parameters contained
/// within a beacon frame received by the MAC to the application /// within a beacon frame received by the MAC to the application
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BeaconNotifyIndication { pub struct BeaconNotifyIndication {
/// he set of octets comprising the beacon payload to be transferred /// he set of octets comprising the beacon payload to be transferred
/// from the MAC sublayer entity to the next higher layer /// from the MAC sublayer entity to the next higher layer
@ -56,8 +95,18 @@ pub struct BeaconNotifyIndication {
pub sdu_length: u8, pub sdu_length: u8,
} }
impl ParseableMacEvent for BeaconNotifyIndication {
const SIZE: usize = 12;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
todo!()
}
}
/// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status /// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CommStatusIndication { pub struct CommStatusIndication {
/// The 16-bit PAN identifier of the device from which the frame /// The 16-bit PAN identifier of the device from which the frame
/// was received or to which the frame was being sent /// was received or to which the frame was being sent
@ -71,83 +120,190 @@ pub struct CommStatusIndication {
/// Destination address /// Destination address
pub dst_address: MacAddress, pub dst_address: MacAddress,
/// The communications status /// The communications status
pub status: u8, pub status: MacStatus,
/// Security level to be used /// Security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// Mode used to identify the key to be used /// Mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// Index of the key to be used /// Index of the key to be used
pub key_index: u8, pub key_index: u8,
/// Originator of the key to be used /// Originator of the key to be used
pub key_source: [u8; 8], pub key_source: [u8; 8],
} }
impl ParseableMacEvent for CommStatusIndication {
const SIZE: usize = 32;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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: [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 /// MLME GTS Indication indicates that a GTS has been allocated or that a
/// previously allocated GTS has been deallocated /// previously allocated GTS has been deallocated
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GtsIndication { pub struct GtsIndication {
/// The short address of the device that has been allocated or deallocated a GTS /// The short address of the device that has been allocated or deallocated a GTS
pub device_address: [u8; 2], pub device_address: [u8; 2],
/// The characteristics of the GTS /// The characteristics of the GTS
pub gts_characteristics: u8, pub gts_characteristics: u8,
/// Security level to be used /// Security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// Mode used to identify the key to be used /// Mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// Index of the key to be used /// Index of the key to be used
pub key_index: u8, pub key_index: u8,
/// Originator of the key to be used /// Originator of the key to be used
pub key_source: [u8; 8], pub key_source: [u8; 8],
} }
impl ParseableMacEvent for GtsIndication {
const SIZE: usize = 16;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME ORPHAN Indication which is used by the coordinator to notify the
/// application of the presence of an orphaned device /// application of the presence of an orphaned device
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct OrphanIndication { pub struct OrphanIndication {
/// Extended address of the orphaned device /// Extended address of the orphaned device
pub orphan_address: [u8; 8], pub orphan_address: [u8; 8],
/// Originator of the key used by the originator of the received frame /// Originator of the key used by the originator of the received frame
pub key_source: [u8; 8], pub key_source: [u8; 8],
/// Security level purportedly used by the received MAC command frame /// Security level purportedly used by the received MAC command frame
pub security_level: u8, pub security_level: SecurityLevel,
/// Mode used to identify the key used by originator of received frame /// Mode used to identify the key used by originator of received frame
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// Index of the key used by the originator of the received frame /// Index of the key used by the originator of the received frame
pub key_index: u8, pub key_index: u8,
} }
impl ParseableMacEvent for OrphanIndication {
const SIZE: usize = 20;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME SYNC LOSS Indication which is used by the MAC to indicate the loss
/// of synchronization with the coordinator /// of synchronization with the coordinator
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SyncLossIndication { pub struct SyncLossIndication {
/// The PAN identifier with which the device lost synchronization or to which it was realigned /// The PAN identifier with which the device lost synchronization or to which it was realigned
pub pan_id: [u8; 2], pub pan_id: [u8; 2],
/// The reason that synchronization was lost /// The reason that synchronization was lost
pub loss_reason: u8, pub loss_reason: u8,
/// The logical channel on which the device lost synchronization or to whi /// The logical channel on which the device lost synchronization or to whi
pub channel_number: u8, pub channel_number: MacChannel,
/// The channel page on which the device lost synchronization or to which /// The channel page on which the device lost synchronization or to which
pub channel_page: u8, pub channel_page: u8,
/// The security level used by the received MAC frame /// The security level used by the received MAC frame
pub security_level: u8, pub security_level: SecurityLevel,
/// Mode used to identify the key used by originator of received frame /// Mode used to identify the key used by originator of received frame
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// Index of the key used by the originator of the received frame /// Index of the key used by the originator of the received frame
pub key_index: u8, pub key_index: u8,
/// Originator of the key used by the originator of the received frame /// Originator of the key used by the originator of the received frame
pub key_source: [u8; 8], pub key_source: [u8; 8],
} }
impl ParseableMacEvent for SyncLossIndication {
const SIZE: usize = 16;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
pan_id: [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 /// MLME DPS Indication which indicates the expiration of the DPSIndexDuration
/// and the resetting of the DPS values in the PHY /// and the resetting of the DPS values in the PHY
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DpsIndication; pub struct DpsIndication;
#[repr(C)] impl ParseableMacEvent for DpsIndication {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self)
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DataIndication { pub struct DataIndication {
/// Pointer to the set of octets forming the MSDU being indicated /// Pointer to the set of octets forming the MSDU being indicated
pub msdu_ptr: *const u8, pub msdu_ptr: *const u8,
/// Source addressing mode used /// Source addressing mode used
pub src_addr_mode: u8, pub src_addr_mode: AddressMode,
/// Source PAN ID /// Source PAN ID
pub src_pan_id: [u8; 2], pub src_pan_id: [u8; 2],
/// Source address /// Source address
@ -167,9 +323,9 @@ pub struct DataIndication {
/// The time, in symbols, at which the data were received /// The time, in symbols, at which the data were received
pub time_stamp: [u8; 4], pub time_stamp: [u8; 4],
/// The security level purportedly used by the received data frame /// The security level purportedly used by the received data frame
pub security_level: u8, pub security_level: SecurityLevel,
/// Mode used to identify the key used by originator of received frame /// Mode used to identify the key used by originator of received frame
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// The originator of the key /// The originator of the key
pub key_source: [u8; 8], pub key_source: [u8; 8],
/// The index of the key /// The index of the key
@ -194,12 +350,91 @@ pub struct DataIndication {
pub rssi: u8, pub rssi: u8,
} }
impl ParseableMacEvent for DataIndication {
const SIZE: usize = 72;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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: [buf[5], buf[6]],
src_address,
dst_addr_mode,
dst_pan_id: [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])?,
key_id_mode: KeyIdMode::try_from(buf[34])?,
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[58..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 /// MLME POLL Indication which will be used for indicating the Data Request
/// reception to upper layer as defined in Zigbee r22 - D.8.2 /// reception to upper layer as defined in Zigbee r22 - D.8.2
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PollIndication { pub struct PollIndication {
/// addressing mode used /// addressing mode used
pub addr_mode: u8, pub addr_mode: AddressMode,
/// Poll requester address /// Poll requester address
pub request_address: MacAddress, pub request_address: MacAddress,
} }
impl ParseableMacEvent for PollIndication {
const SIZE: usize = 9;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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,
})
}
}

View File

@ -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<Self, ()> {
match value {
$($constant => Ok( $name :: $enum ),)*
_ => Err(())
}
}
}
impl ::core::convert::From<$name> for $repr {
fn from(value: $name) -> $repr {
match value {
$($name :: $enum => $constant,)*
}
}
}
}
}

View File

@ -9,7 +9,8 @@ use embassy_stm32::ipcc::Ipcc;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use self::commands::MacCommand; use self::commands::MacCommand;
use self::typedefs::MacStatus; use self::event::MacEvent;
use self::typedefs::MacError;
use crate::cmd::CmdPacket; use crate::cmd::CmdPacket;
use crate::consts::TlPacketType; use crate::consts::TlPacketType;
use crate::evt::{EvtBox, EvtPacket}; use crate::evt::{EvtBox, EvtPacket};
@ -18,7 +19,10 @@ use crate::{channels, evt};
pub mod commands; pub mod commands;
mod consts; mod consts;
pub mod event;
mod helpers;
pub mod indications; pub mod indications;
mod macros;
mod opcodes; mod opcodes;
pub mod responses; pub mod responses;
pub mod typedefs; pub mod typedefs;
@ -38,7 +42,7 @@ impl Mac {
/// `HW_IPCC_MAC_802_15_4_EvtNot` /// `HW_IPCC_MAC_802_15_4_EvtNot`
/// ///
/// This function will stall if the previous `EvtBox` has not been dropped /// This function will stall if the previous `EvtBox` has not been dropped
pub async fn read(&self) -> EvtBox<Self> { pub async fn tl_read(&self) -> EvtBox<Self> {
// Wait for the last event box to be dropped // Wait for the last event box to be dropped
poll_fn(|cx| { poll_fn(|cx| {
MAC_WAKER.register(cx.waker()); MAC_WAKER.register(cx.waker());
@ -62,33 +66,20 @@ impl Mac {
} }
/// `HW_IPCC_MAC_802_15_4_CmdEvtNot` /// `HW_IPCC_MAC_802_15_4_CmdEvtNot`
pub async fn write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 {
self.write(opcode, payload).await; self.tl_write(opcode, payload).await;
Ipcc::flush(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL).await; Ipcc::flush(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL).await;
unsafe { unsafe {
let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket; 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; let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8;
let evt_serial = (MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket)
.read_volatile()
.evt_serial;
let kind = (evt_serial).kind;
let evt_code = evt_serial.evt.evt_code;
let payload_len = evt_serial.evt.payload_len;
let payload = evt_serial.evt.payload;
debug!(
"evt kind {} evt_code {} len {} payload {}",
kind, evt_code, payload_len, payload
);
ptr::read_volatile(p_mac_rsp_evt) ptr::read_volatile(p_mac_rsp_evt)
} }
} }
/// `TL_MAC_802_15_4_SendCmd` /// `TL_MAC_802_15_4_SendCmd`
pub async fn write(&self, opcode: u16, payload: &[u8]) { pub async fn tl_write(&self, opcode: u16, payload: &[u8]) {
Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe { Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe {
CmdPacket::write_into( CmdPacket::write_into(
MAC_802_15_4_CMD_BUFFER.as_mut_ptr(), MAC_802_15_4_CMD_BUFFER.as_mut_ptr(),
@ -98,37 +89,31 @@ impl Mac {
); );
}) })
.await; .await;
unsafe {
let typ = MAC_802_15_4_CMD_BUFFER.as_ptr().read_volatile().cmdserial.ty;
let cmd_code = MAC_802_15_4_CMD_BUFFER.as_ptr().read_volatile().cmdserial.cmd.cmd_code;
let payload_len = MAC_802_15_4_CMD_BUFFER
.as_ptr()
.read_volatile()
.cmdserial
.cmd
.payload_len;
let payload = MAC_802_15_4_CMD_BUFFER.as_ptr().read_volatile().cmdserial.cmd.payload;
debug!(
"serial type {} cmd_code {} len {} payload {}",
typ, cmd_code, payload_len, payload
);
}
} }
pub async fn send_command<T>(&self, cmd: T) -> Result<MacStatus, ()> pub async fn send_command<T>(&self, cmd: T) -> Result<(), MacError>
where where
T: MacCommand, T: MacCommand,
{ {
let mut payload = [0u8; MAX_PACKET_SIZE]; let mut payload = [0u8; MAX_PACKET_SIZE];
cmd.copy_into_slice(&mut payload); cmd.copy_into_slice(&mut payload);
debug!("sending {:#x}", payload[..T::SIZE]); let response = self
.tl_write_and_get_response(T::OPCODE as u16, &payload[..T::SIZE])
.await;
let response = self.write_and_get_response(T::OPCODE as u16, &payload[..T::SIZE]).await; if response == 0x00 {
Ok(())
} else {
Err(MacError::from(response))
}
}
MacStatus::try_from(response) pub async fn read(&self) -> Result<MacEvent, ()> {
let evt_box = self.tl_read().await;
let payload = evt_box.payload();
MacEvent::try_from(payload)
} }
} }

View File

@ -25,3 +25,66 @@ pub enum OpcodeM4ToM0 {
McpsDataReq = opcode(0x10), McpsDataReq = opcode(0x10),
McpsPurgeReq = opcode(0x11), McpsPurgeReq = opcode(0x11),
} }
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<u16> for OpcodeM0ToM4 {
type Error = ();
fn try_from(value: u16) -> Result<Self, Self::Error> {
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(()),
}
}
}

View File

@ -1,35 +1,50 @@
use super::consts::{MAX_ED_SCAN_RESULTS_SUPPORTED, MAX_PAN_DESC_SUPPORTED, MAX_SOUNDING_LIST_SUPPORTED}; use super::consts::{MAX_ED_SCAN_RESULTS_SUPPORTED, MAX_PAN_DESC_SUPPORTED, MAX_SOUNDING_LIST_SUPPORTED};
use super::typedefs::{AddressMode, MacAddress, PanDescriptor}; use super::event::ParseableMacEvent;
use super::helpers::to_u32;
pub trait MacResponse { use super::typedefs::{
const SIZE: usize; AddressMode, AssociationStatus, KeyIdMode, MacAddress, MacStatus, PanDescriptor, PibId, ScanType, SecurityLevel,
};
fn parse(buf: &[u8]) -> Self;
}
/// MLME ASSOCIATE Confirm used to inform of the initiating device whether /// MLME ASSOCIATE Confirm used to inform of the initiating device whether
/// its request to associate was successful or unsuccessful /// its request to associate was successful or unsuccessful
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AssociateConfirm { pub struct AssociateConfirm {
/// short address allocated by the coordinator on successful association /// short address allocated by the coordinator on successful association
pub assoc_short_address: [u8; 2], pub assoc_short_address: [u8; 2],
/// status of the association request /// status of the association request
pub status: u8, pub status: AssociationStatus,
/// security level to be used /// security level to be used
pub security_level: u8, pub security_level: SecurityLevel,
/// the originator of the key to be used /// the originator of the key to be used
pub key_source: [u8; 8], pub key_source: [u8; 8],
/// the mode used to identify the key to be used /// the mode used to identify the key to be used
pub key_id_mode: u8, pub key_id_mode: KeyIdMode,
/// the index of the key to be used /// the index of the key to be used
pub key_index: u8, pub key_index: u8,
} }
impl ParseableMacEvent for AssociateConfirm {
const SIZE: usize = 16;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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. /// MLME DISASSOCIATE Confirm used to send disassociation Confirmation to the application.
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DisassociateConfirm { pub struct DisassociateConfirm {
/// status of the disassociation attempt /// status of the disassociation attempt
pub status: u8, pub status: MacStatus,
/// device addressing mode used /// device addressing mode used
pub device_addr_mode: AddressMode, pub device_addr_mode: AddressMode,
/// the identifier of the PAN of the device /// the identifier of the PAN of the device
@ -38,51 +53,130 @@ pub struct DisassociateConfirm {
pub device_address: MacAddress, pub device_address: MacAddress,
} }
impl ParseableMacEvent for DisassociateConfirm {
const SIZE: usize = 12;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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: [buf[2], buf[3]],
device_address,
})
}
}
/// MLME GET Confirm which requests information about a given PIB attribute /// MLME GET Confirm which requests information about a given PIB attribute
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GetConfirm { pub struct GetConfirm {
/// The pointer to the value of the PIB attribute attempted to read /// The pointer to the value of the PIB attribute attempted to read
pub pib_attribute_value_ptr: *const u8, pub pib_attribute_value_ptr: *const u8,
/// Status of the GET attempt /// Status of the GET attempt
pub status: u8, pub status: MacStatus,
/// The name of the PIB attribute attempted to read /// The name of the PIB attribute attempted to read
pub pib_attribute: u8, pub pib_attribute: PibId,
/// The lenght of the PIB attribute Value return /// The lenght of the PIB attribute Value return
pub pib_attribute_value_len: u8, pub pib_attribute_value_len: u8,
} }
impl ParseableMacEvent for GetConfirm {
const SIZE: usize = 8;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME GTS Confirm which eports the results of a request to allocate a new GTS
/// or to deallocate an existing GTS /// or to deallocate an existing GTS
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GtsConfirm { pub struct GtsConfirm {
/// The characteristics of the GTS /// The characteristics of the GTS
pub gts_characteristics: u8, pub gts_characteristics: u8,
/// The status of the GTS reques /// The status of the GTS reques
pub status: u8, pub status: MacStatus,
}
impl ParseableMacEvent for GtsConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME RESET Confirm which is used to report the results of the reset operation
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ResetConfirm { pub struct ResetConfirm {
/// The result of the reset operation /// The result of the reset operation
status: u8, status: MacStatus,
}
impl ParseableMacEvent for ResetConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME RX ENABLE Confirm which is used to report the results of the attempt
/// to enable or disable the receiver /// to enable or disable the receiver
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RxEnableConfirm { pub struct RxEnableConfirm {
/// Result of the request to enable or disable the receiver /// Result of the request to enable or disable the receiver
status: u8, status: MacStatus,
}
impl ParseableMacEvent for RxEnableConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME SCAN Confirm which is used to report the result of the channel scan request
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ScanConfirm { pub struct ScanConfirm {
/// Status of the scan request /// Status of the scan request
pub status: u8, pub status: MacStatus,
/// The type of scan performed /// The type of scan performed
pub scan_type: u8, pub scan_type: ScanType,
/// Channel page on which the scan was performed /// Channel page on which the scan was performed
pub channel_page: u8, pub channel_page: u8,
/// Channels given in the request which were not scanned /// Channels given in the request which were not scanned
@ -99,44 +193,124 @@ pub struct ScanConfirm {
pub uwb_energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED], pub uwb_energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED],
} }
impl ParseableMacEvent for ScanConfirm {
const SIZE: usize = 9;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
todo!()
}
}
/// MLME SET Confirm which reports the result of an attempt to write a value to a PIB attribute /// MLME SET Confirm which reports the result of an attempt to write a value to a PIB attribute
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SetConfirm { pub struct SetConfirm {
/// The result of the set operation /// The result of the set operation
pub status: u8, pub status: MacStatus,
/// The name of the PIB attribute that was written /// The name of the PIB attribute that was written
pub pin_attribute: u8, pub pin_attribute: PibId,
}
impl ParseableMacEvent for SetConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME START Confirm which is used to report the results of the attempt to
/// start using a new superframe configuration /// start using a new superframe configuration
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StartConfirm { pub struct StartConfirm {
/// Result of the attempt to start using an updated superframe configuration /// Result of the attempt to start using an updated superframe configuration
pub status: u8, pub status: MacStatus,
}
impl ParseableMacEvent for StartConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
debug!("{:#x}", 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 /// MLME POLL Confirm which is used to report the result of a request to poll the coordinator for data
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PollConfirm { pub struct PollConfirm {
/// The status of the data request /// The status of the data request
pub status: u8, pub status: MacStatus,
}
impl ParseableMacEvent for PollConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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, ()> {
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 /// MLME SOUNDING Confirm which reports the result of a request to the PHY to provide
/// channel sounding information /// channel sounding information
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SoundingConfirm { pub struct SoundingConfirm {
/// Results of the sounding measurement /// Results of the sounding measurement
sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED], sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED],
} }
impl ParseableMacEvent for SoundingConfirm {
const SIZE: usize = 1;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MLME CALIBRATE Confirm which reports the result of a request to the PHY
/// to provide internal propagation path information /// to provide internal propagation path information
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CalibrateConfirm { pub struct CalibrateConfirm {
/// The status of the attempt to return sounding data /// The status of the attempt to return sounding data
pub status: u8, pub status: MacStatus,
/// A count of the propagation time from the ranging counter /// A count of the propagation time from the ranging counter
/// to the transmit antenna /// to the transmit antenna
pub cal_tx_rmaker_offset: u32, pub cal_tx_rmaker_offset: u32,
@ -145,18 +319,33 @@ pub struct CalibrateConfirm {
pub cal_rx_rmaker_offset: u32, pub cal_rx_rmaker_offset: u32,
} }
impl ParseableMacEvent for CalibrateConfirm {
const SIZE: usize = 12;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// MCPS DATA Confirm which will be used for reporting the results of
/// MAC data related requests from the application /// MAC data related requests from the application
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DataConfirm { pub struct DataConfirm {
/// The handle associated with the MSDU being confirmed /// The handle associated with the MSDU being confirmed
pub msdu_handle: u8, pub msdu_handle: u8,
/// The time, in symbols, at which the data were transmitted /// The time, in symbols, at which the data were transmitted
pub a_time_stamp: [u8; 4], pub time_stamp: [u8; 4],
/// ranging status /// ranging status
pub ranging_received: u8, pub ranging_received: u8,
/// The status of the last MSDU transmission /// The status of the last MSDU transmission
pub status: u8, pub status: MacStatus,
/// time units corresponding to an RMARKER at the antenna at /// time units corresponding to an RMARKER at the antenna at
/// the beginning of a ranging exchange /// the beginning of a ranging exchange
pub ranging_counter_start: u32, pub ranging_counter_start: u32,
@ -171,12 +360,45 @@ pub struct DataConfirm {
pub ranging_fom: u8, pub ranging_fom: u8,
} }
impl ParseableMacEvent for DataConfirm {
const SIZE: usize = 28;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
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 /// 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 /// the status of its request to purge an MSDU from the transaction queue
#[repr(C)] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PurgeConfirm { pub struct PurgeConfirm {
/// Handle associated with the MSDU requested to be purged from the transaction queue /// Handle associated with the MSDU requested to be purged from the transaction queue
pub msdu_handle: u8, pub msdu_handle: u8,
/// The status of the request /// The status of the request
pub status: u8, pub status: MacStatus,
}
impl ParseableMacEvent for PurgeConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
msdu_handle: buf[0],
status: MacStatus::try_from(buf[1])?,
})
}
} }

View File

@ -1,6 +1,8 @@
use crate::numeric_enum;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MacStatus { pub enum MacError {
Success = 0x00,
Error = 0x01, Error = 0x01,
NotImplemented = 0x02, NotImplemented = 0x02,
NotSupported = 0x03, NotSupported = 0x03,
@ -8,88 +10,115 @@ pub enum MacStatus {
Undefined = 0x05, Undefined = 0x05,
} }
impl TryFrom<u8> for MacStatus { impl From<u8> for MacError {
type Error = (); fn from(value: u8) -> Self {
fn try_from(value: u8) -> Result<Self, <MacStatus as TryFrom<u8>>::Error> {
match value { match value {
0x00 => Ok(Self::Success), 0x01 => Self::Error,
0x01 => Ok(Self::Error), 0x02 => Self::NotImplemented,
0x02 => Ok(Self::NotImplemented), 0x03 => Self::NotSupported,
0x03 => Ok(Self::NotSupported), 0x04 => Self::HardwareNotSupported,
0x04 => Ok(Self::HardwareNotSupported), 0x05 => Self::Undefined,
0x05 => Ok(Self::Undefined), _ => Self::Undefined,
_ => Err(()),
} }
} }
} }
/// this enum contains all the MAC PIB Ids numeric_enum! {
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)]
pub enum PibId { #[derive(Debug)]
// PHY #[cfg_attr(feature = "defmt", derive(defmt::Format))]
CurrentChannel = 0x00, pub enum MacStatus {
ChannelsSupported = 0x01, Success = 0x00,
TransmitPower = 0x02, Error = 0x01,
CCAMode = 0x03, NotImplemented = 0x02,
CurrentPage = 0x04, NotSupported = 0x03,
MaxFrameDuration = 0x05, HardwareNotSupported = 0x04,
SHRDuration = 0x06, Undefined = 0x05,
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,
} }
#[cfg_attr(feature = "defmt", derive(defmt::Format))] numeric_enum! {
pub enum AddressMode { #[repr(u8)]
NoAddress = 0x00, /// this enum contains all the MAC PIB Ids
Reserved = 0x01, #[cfg_attr(feature = "defmt", derive(defmt::Format))]
Short = 0x02, pub enum PibId {
Extended = 0x03, // 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,
}
} }
pub union MacAddress { numeric_enum! {
pub short: [u8; 2], #[repr(u8)]
pub extended: [u8; 8], #[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)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MacAddress {
Short([u8; 2]),
Extended([u8; 8]),
}
impl Default for MacAddress {
fn default() -> Self {
Self::Short([0, 0])
}
} }
pub struct GtsCharacteristics { pub struct GtsCharacteristics {
@ -98,13 +127,15 @@ pub struct GtsCharacteristics {
/// MAC PAN Descriptor which contains the network details of the device from /// MAC PAN Descriptor which contains the network details of the device from
/// which the beacon is received /// which the beacon is received
#[derive(Default, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PanDescriptor { pub struct PanDescriptor {
/// PAN identifier of the coordinator /// PAN identifier of the coordinator
pub a_coord_pan_id: [u8; 2], pub coord_pan_id: [u8; 2],
/// Coordinator addressing mode /// Coordinator addressing mode
pub coord_addr_mode: AddressMode, pub coord_addr_mode: AddressMode,
/// The current logical channel occupied by the network /// The current logical channel occupied by the network
pub logical_channel: u8, pub logical_channel: MacChannel,
/// Coordinator address /// Coordinator address
pub coord_addr: MacAddress, pub coord_addr: MacAddress,
/// The current channel page occupied by the network /// The current channel page occupied by the network
@ -112,13 +143,179 @@ pub struct PanDescriptor {
/// PAN coordinator is accepting GTS requests or not /// PAN coordinator is accepting GTS requests or not
pub gts_permit: bool, pub gts_permit: bool,
/// Superframe specification as specified in the received beacon frame /// Superframe specification as specified in the received beacon frame
pub a_superframe_spec: [u8; 2], pub superframe_spec: [u8; 2],
/// The time at which the beacon frame was received, in symbols /// The time at which the beacon frame was received, in symbols
pub a_time_stamp: [u8; 4], pub time_stamp: [u8; 4],
/// The LQI at which the network beacon was received /// The LQI at which the network beacon was received
pub link_quality: u8, pub link_quality: u8,
/// Security level purportedly used by the received beacon frame /// Security level purportedly used by the received beacon frame
pub security_level: u8, pub security_level: u8,
/// Byte Stuffing to keep 32 bit alignment }
pub a_stuffing: [u8; 2],
impl TryFrom<&[u8]> for PanDescriptor {
type Error = ();
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
const SIZE: usize = 24;
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: [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)]
#[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)]
#[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)]
#[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
}
} }

View File

@ -7,7 +7,7 @@ use embassy_executor::Spawner;
use embassy_stm32::bind_interrupts; use embassy_stm32::bind_interrupts;
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
use embassy_stm32_wpan::sub::mac::commands::{ResetRequest, SetRequest, StartRequest}; use embassy_stm32_wpan::sub::mac::commands::{ResetRequest, SetRequest, StartRequest};
use embassy_stm32_wpan::sub::mac::typedefs::PibId; use embassy_stm32_wpan::sub::mac::typedefs::{MacChannel, PibId};
use embassy_stm32_wpan::sub::mm; use embassy_stm32_wpan::sub::mm;
use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::TlMbox;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -65,109 +65,92 @@ async fn main(spawner: Spawner) {
info!("initialized mac: {}", result); info!("initialized mac: {}", result);
info!("resetting"); info!("resetting");
let response = mbox mbox.mac_subsystem
.mac_subsystem
.send_command(ResetRequest { set_default_pib: true }) .send_command(ResetRequest { set_default_pib: true })
.await; .await
info!("{}", response); .unwrap();
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt);
info!("setting extended address"); info!("setting extended address");
let extended_address: u64 = 0xACDE480000000001; let extended_address: u64 = 0xACDE480000000001;
let response = mbox mbox.mac_subsystem
.mac_subsystem
.send_command(SetRequest { .send_command(SetRequest {
pib_attribute_ptr: &extended_address as *const _ as *const u8, pib_attribute_ptr: &extended_address as *const _ as *const u8,
pib_attribute: PibId::ExtendedAddress, pib_attribute: PibId::ExtendedAddress,
}) })
.await; .await
info!("{}", response); .unwrap();
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt);
info!("setting short address"); info!("setting short address");
let short_address: u16 = 0x1122; let short_address: u16 = 0x1122;
let response = mbox mbox.mac_subsystem
.mac_subsystem
.send_command(SetRequest { .send_command(SetRequest {
pib_attribute_ptr: &short_address as *const _ as *const u8, pib_attribute_ptr: &short_address as *const _ as *const u8,
pib_attribute: PibId::ShortAddress, pib_attribute: PibId::ShortAddress,
}) })
.await; .await
info!("{}", response); .unwrap();
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt);
info!("setting association permit"); info!("setting association permit");
let association_permit: bool = true; let association_permit: bool = true;
let response = mbox mbox.mac_subsystem
.mac_subsystem
.send_command(SetRequest { .send_command(SetRequest {
pib_attribute_ptr: &association_permit as *const _ as *const u8, pib_attribute_ptr: &association_permit as *const _ as *const u8,
pib_attribute: PibId::AssociationPermit, pib_attribute: PibId::AssociationPermit,
}) })
.await; .await
info!("{}", response); .unwrap();
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt);
info!("setting TX power"); info!("setting TX power");
let transmit_power: i8 = 2; let transmit_power: i8 = 2;
let response = mbox mbox.mac_subsystem
.mac_subsystem
.send_command(SetRequest { .send_command(SetRequest {
pib_attribute_ptr: &transmit_power as *const _ as *const u8, pib_attribute_ptr: &transmit_power as *const _ as *const u8,
pib_attribute: PibId::TransmitPower, pib_attribute: PibId::TransmitPower,
}) })
.await; .await
info!("{}", response); .unwrap();
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt);
info!("starting FFD device"); info!("starting FFD device");
let response = mbox mbox.mac_subsystem
.mac_subsystem
.send_command(StartRequest { .send_command(StartRequest {
channel_number: 16, channel_number: MacChannel::Channel16,
beacon_order: 0x0F, beacon_order: 0x0F,
superframe_order: 0x0F, superframe_order: 0x0F,
pan_coordinator: true, pan_coordinator: true,
battery_life_extension: false, battery_life_extension: false,
..Default::default() ..Default::default()
}) })
.await; .await
info!("{}", response); .unwrap();
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt);
info!("setting RX on when idle"); info!("setting RX on when idle");
let rx_on_while_idle: bool = true; let rx_on_while_idle: bool = true;
let response = mbox mbox.mac_subsystem
.mac_subsystem
.send_command(SetRequest { .send_command(SetRequest {
pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8, pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8,
pib_attribute: PibId::RxOnWhenIdle, pib_attribute: PibId::RxOnWhenIdle,
}) })
.await; .await
info!("{}", response); .unwrap();
let evt = mbox.mac_subsystem.read().await;
defmt::info!("{:#x}", evt);
// info!("association request"); loop {
// mbox.mac_subsystem let evt = mbox.mac_subsystem.read().await;
// .send_command(AssociateRequest { defmt::info!("{:#x}", evt);
// channel_number: 16, }
// channel_page: 0,
// coord_addr_mode: 2,
// coord_address: MacAddress { short: [0x22, 0x11] },
// capability_information: 0x80,
// coord_pan_id: [0xAA, 0x1A],
// security_level: 0,
// key_id_mode: 0,
// key_index: 0,
// key_source: [0; 8],
// })
// .await;
// info!("reading");
// let result = mbox.mac_subsystem.read().await;
// info!("{}", result.payload());
//
// info!("starting ble...");
// mbox.ble_subsystem.t_write(0x0c, &[]).await;
//
// info!("waiting for ble...");
// let ble_event = mbox.ble_subsystem.tl_read().await;
//
// info!("ble event: {}", ble_event.payload());
info!("Test OK"); info!("Test OK");
cortex_m::asm::bkpt(); cortex_m::asm::bkpt();

View File

@ -7,7 +7,9 @@ use embassy_executor::Spawner;
use embassy_stm32::bind_interrupts; use embassy_stm32::bind_interrupts;
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
use embassy_stm32_wpan::sub::mac::commands::{AssociateRequest, ResetRequest, SetRequest, StartRequest}; use embassy_stm32_wpan::sub::mac::commands::{AssociateRequest, ResetRequest, SetRequest, StartRequest};
use embassy_stm32_wpan::sub::mac::typedefs::{AddressMode, MacAddress, PibId}; use embassy_stm32_wpan::sub::mac::typedefs::{
AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PibId, SecurityLevel,
};
use embassy_stm32_wpan::sub::mm; use embassy_stm32_wpan::sub::mm;
use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::TlMbox;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -86,14 +88,14 @@ async fn main(spawner: Spawner) {
let response = mbox let response = mbox
.mac_subsystem .mac_subsystem
.send_command(AssociateRequest { .send_command(AssociateRequest {
channel_number: 16, channel_number: MacChannel::Channel16,
channel_page: 0, channel_page: 0,
coord_addr_mode: AddressMode::Short, coord_addr_mode: AddressMode::Short,
coord_address: MacAddress { short: [0x22, 0x11] }, coord_address: MacAddress::Short([0x22, 0x11]),
capability_information: 0x80, capability_information: Capabilities::ALLOCATE_ADDRESS,
coord_pan_id: [0xAA, 0x1A], coord_pan_id: [0xAA, 0x1A],
security_level: 0x00, security_level: SecurityLevel::Unsecure,
key_id_mode: 0, key_id_mode: KeyIdMode::Implicite,
key_source: [0; 8], key_source: [0; 8],
key_index: 0, key_index: 0,
}) })