commit
758862f4b1
@ -26,12 +26,13 @@ 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.3", optional = true }
|
stm32wb-hci = { version = "0.1.3", optional = true }
|
||||||
|
bitflags = { version = "2.3.3", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"]
|
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/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" ]
|
||||||
|
@ -6,6 +6,8 @@ use crate::PacketHeader;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub enum TlPacketType {
|
pub enum TlPacketType {
|
||||||
|
MacCmd = 0x00,
|
||||||
|
|
||||||
BleCmd = 0x01,
|
BleCmd = 0x01,
|
||||||
AclData = 0x02,
|
AclData = 0x02,
|
||||||
BleEvt = 0x04,
|
BleEvt = 0x04,
|
||||||
|
467
embassy-stm32-wpan/src/sub/mac/commands.rs
Normal file
467
embassy-stm32-wpan/src/sub/mac/commands.rs
Normal file
@ -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;
|
||||||
|
}
|
4
embassy-stm32-wpan/src/sub/mac/consts.rs
Normal file
4
embassy-stm32-wpan/src/sub/mac/consts.rs
Normal file
@ -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;
|
94
embassy-stm32-wpan/src/sub/mac/event.rs
Normal file
94
embassy-stm32-wpan/src/sub/mac/event.rs
Normal 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)?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
embassy-stm32-wpan/src/sub/mac/helpers.rs
Normal file
7
embassy-stm32-wpan/src/sub/mac/helpers.rs
Normal 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)
|
||||||
|
}
|
470
embassy-stm32-wpan/src/sub/mac/indications.rs
Normal file
470
embassy-stm32-wpan/src/sub/mac/indications.rs
Normal file
@ -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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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<Self, ()> {
|
||||||
|
// 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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
32
embassy-stm32-wpan/src/sub/mac/macros.rs
Normal file
32
embassy-stm32-wpan/src/sub/mac/macros.rs
Normal 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,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,12 +8,25 @@ use embassy_futures::poll_once;
|
|||||||
use embassy_stm32::ipcc::Ipcc;
|
use embassy_stm32::ipcc::Ipcc;
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
use self::commands::MacCommand;
|
||||||
|
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};
|
||||||
use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER};
|
use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER};
|
||||||
use crate::{channels, evt};
|
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_WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
|
static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
@ -29,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());
|
||||||
@ -53,9 +66,9 @@ 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_SYSTEM_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;
|
||||||
@ -66,19 +79,46 @@ impl Mac {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `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(),
|
||||||
TlPacketType::OtCmd,
|
TlPacketType::MacCmd,
|
||||||
opcode,
|
opcode,
|
||||||
payload,
|
payload,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_command<T>(&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<MacEvent, ()> {
|
||||||
|
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 {
|
impl evt::MemoryManager for Mac {
|
||||||
/// SAFETY: passing a pointer to something other than a managed event packet is UB
|
/// SAFETY: passing a pointer to something other than a managed event packet is UB
|
||||||
unsafe fn drop_event_packet(_: *mut EvtPacket) {
|
unsafe fn drop_event_packet(_: *mut EvtPacket) {
|
92
embassy-stm32-wpan/src/sub/mac/opcodes.rs
Normal file
92
embassy-stm32-wpan/src/sub/mac/opcodes.rs
Normal file
@ -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<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(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
433
embassy-stm32-wpan/src/sub/mac/responses.rs
Normal file
433
embassy-stm32-wpan/src/sub/mac/responses.rs
Normal file
@ -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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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<Self, ()> {
|
||||||
|
// 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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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
|
||||||
|
/// 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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
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, ()> {
|
||||||
|
Self::validate(buf)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
msdu_handle: buf[0],
|
||||||
|
status: MacStatus::try_from(buf[1])?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
363
embassy-stm32-wpan/src/sub/mac/typedefs.rs
Normal file
363
embassy-stm32-wpan/src/sub/mac/typedefs.rs
Normal file
@ -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<u8> 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<Self, Self::Error> {
|
||||||
|
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<Self, Self::Error> {
|
||||||
|
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]);
|
||||||
|
}
|
@ -50,7 +50,7 @@ impl Sys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `HW_IPCC_SYS_CmdEvtNot`
|
/// `HW_IPCC_SYS_CmdEvtNot`
|
||||||
pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> SchiCommandStatus {
|
pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> Result<SchiCommandStatus, ()> {
|
||||||
self.write(opcode, payload).await;
|
self.write(opcode, payload).await;
|
||||||
Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
|
Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
|
||||||
|
|
||||||
@ -59,12 +59,12 @@ impl Sys {
|
|||||||
let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt;
|
let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt;
|
||||||
let p_payload = &((*p_command_event).payload) as *const u8;
|
let p_payload = &((*p_command_event).payload) as *const u8;
|
||||||
|
|
||||||
ptr::read_volatile(p_payload).try_into().unwrap()
|
ptr::read_volatile(p_payload).try_into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "mac")]
|
#[cfg(feature = "mac")]
|
||||||
pub async fn shci_c2_mac_802_15_4_init(&self) -> SchiCommandStatus {
|
pub async fn shci_c2_mac_802_15_4_init(&self) -> Result<SchiCommandStatus, ()> {
|
||||||
use crate::tables::{
|
use crate::tables::{
|
||||||
Mac802_15_4Table, TracesTable, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER,
|
Mac802_15_4Table, TracesTable, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER,
|
||||||
TL_MAC_802_15_4_TABLE, TL_TRACES_TABLE, TRACES_EVT_QUEUE,
|
TL_MAC_802_15_4_TABLE, TL_TRACES_TABLE, TRACES_EVT_QUEUE,
|
||||||
@ -88,7 +88,7 @@ impl Sys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ble")]
|
#[cfg(feature = "ble")]
|
||||||
pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> SchiCommandStatus {
|
pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result<SchiCommandStatus, ()> {
|
||||||
self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
|
self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
|
# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
|
||||||
# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
|
# runner = "probe-run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
|
||||||
runner = "teleprobe local run --chip STM32WB55RG --elf"
|
runner = "teleprobe local run --chip STM32WB55RG --elf"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
|
@ -23,7 +23,7 @@ heapless = { version = "0.7.5", default-features = false }
|
|||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["ble"]
|
default = ["ble", "mac"]
|
||||||
mac = ["embassy-stm32-wpan/mac"]
|
mac = ["embassy-stm32-wpan/mac"]
|
||||||
ble = ["embassy-stm32-wpan/ble"]
|
ble = ["embassy-stm32-wpan/ble"]
|
||||||
|
|
||||||
@ -35,6 +35,10 @@ required-features = ["ble"]
|
|||||||
name = "tl_mbox_mac"
|
name = "tl_mbox_mac"
|
||||||
required-features = ["mac"]
|
required-features = ["mac"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "mac_ffd"
|
||||||
|
required-features = ["mac"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "eddystone_beacon"
|
name = "eddystone_beacon"
|
||||||
required-features = ["ble"]
|
required-features = ["ble"]
|
||||||
|
@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let sys_event = mbox.sys_subsystem.read().await;
|
let sys_event = mbox.sys_subsystem.read().await;
|
||||||
info!("sys event: {}", sys_event.payload());
|
info!("sys event: {}", sys_event.payload());
|
||||||
|
|
||||||
mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
||||||
|
|
||||||
info!("resetting BLE...");
|
info!("resetting BLE...");
|
||||||
mbox.ble_subsystem.reset().await;
|
mbox.ble_subsystem.reset().await;
|
||||||
|
@ -71,7 +71,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let sys_event = mbox.sys_subsystem.read().await;
|
let sys_event = mbox.sys_subsystem.read().await;
|
||||||
info!("sys event: {}", sys_event.payload());
|
info!("sys event: {}", sys_event.payload());
|
||||||
|
|
||||||
mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
||||||
|
|
||||||
info!("resetting BLE...");
|
info!("resetting BLE...");
|
||||||
mbox.ble_subsystem.reset().await;
|
mbox.ble_subsystem.reset().await;
|
||||||
|
183
examples/stm32wb/src/bin/mac_ffd.rs
Normal file
183
examples/stm32wb/src/bin/mac_ffd.rs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::*;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::bind_interrupts;
|
||||||
|
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
|
||||||
|
use embassy_stm32_wpan::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::sub::mm;
|
||||||
|
use embassy_stm32_wpan::TlMbox;
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs{
|
||||||
|
IPCC_C1_RX => ReceiveInterruptHandler;
|
||||||
|
IPCC_C1_TX => TransmitInterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn run_mm_queue(memory_manager: mm::MemoryManager) {
|
||||||
|
memory_manager.run_queue().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(spawner: Spawner) {
|
||||||
|
/*
|
||||||
|
How to make this work:
|
||||||
|
|
||||||
|
- Obtain a NUCLEO-STM32WB55 from your preferred supplier.
|
||||||
|
- Download and Install STM32CubeProgrammer.
|
||||||
|
- Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
|
||||||
|
gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
|
||||||
|
- Open STM32CubeProgrammer
|
||||||
|
- On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
|
||||||
|
- Once complete, click connect to connect to the device.
|
||||||
|
- On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
|
||||||
|
- In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
|
||||||
|
- Select that file, the memory address, "verify download", and then "Firmware Upgrade".
|
||||||
|
- Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
|
||||||
|
stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
|
||||||
|
- Select that file, the memory address, "verify download", and then "Firmware Upgrade".
|
||||||
|
- Select "Start Wireless Stack".
|
||||||
|
- Disconnect from the device.
|
||||||
|
- In the examples folder for stm32wb, modify the memory.x file to match your target device.
|
||||||
|
- Run this example.
|
||||||
|
|
||||||
|
Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
let p = embassy_stm32::init(Default::default());
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let config = Config::default();
|
||||||
|
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
||||||
|
|
||||||
|
spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
|
||||||
|
|
||||||
|
let sys_event = mbox.sys_subsystem.read().await;
|
||||||
|
info!("sys event: {}", sys_event.payload());
|
||||||
|
|
||||||
|
core::mem::drop(sys_event);
|
||||||
|
|
||||||
|
let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
|
||||||
|
info!("initialized mac: {}", result);
|
||||||
|
|
||||||
|
info!("resetting");
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&ResetRequest { set_default_pib: true })
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
defmt::info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("setting extended address");
|
||||||
|
let extended_address: u64 = 0xACDE480000000001;
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&SetRequest {
|
||||||
|
pib_attribute_ptr: &extended_address as *const _ as *const u8,
|
||||||
|
pib_attribute: PibId::ExtendedAddress,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
defmt::info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("setting short address");
|
||||||
|
let short_address: u16 = 0x1122;
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&SetRequest {
|
||||||
|
pib_attribute_ptr: &short_address as *const _ as *const u8,
|
||||||
|
pib_attribute: PibId::ShortAddress,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
defmt::info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("setting association permit");
|
||||||
|
let association_permit: bool = true;
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&SetRequest {
|
||||||
|
pib_attribute_ptr: &association_permit as *const _ as *const u8,
|
||||||
|
pib_attribute: PibId::AssociationPermit,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
defmt::info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("setting TX power");
|
||||||
|
let transmit_power: i8 = 2;
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&SetRequest {
|
||||||
|
pib_attribute_ptr: &transmit_power as *const _ as *const u8,
|
||||||
|
pib_attribute: PibId::TransmitPower,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
defmt::info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("starting FFD device");
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&StartRequest {
|
||||||
|
pan_id: PanId([0x1A, 0xAA]),
|
||||||
|
channel_number: MacChannel::Channel16,
|
||||||
|
beacon_order: 0x0F,
|
||||||
|
superframe_order: 0x0F,
|
||||||
|
pan_coordinator: true,
|
||||||
|
battery_life_extension: false,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
defmt::info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("setting RX on when idle");
|
||||||
|
let rx_on_while_idle: bool = true;
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&SetRequest {
|
||||||
|
pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8,
|
||||||
|
pib_attribute: PibId::RxOnWhenIdle,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
defmt::info!("{:#x}", evt);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
defmt::info!("{:#x}", evt);
|
||||||
|
|
||||||
|
if let Ok(evt) = evt {
|
||||||
|
match evt {
|
||||||
|
MacEvent::MlmeAssociateInd(association) => mbox
|
||||||
|
.mac_subsystem
|
||||||
|
.send_command(&AssociateResponse {
|
||||||
|
device_address: association.device_address,
|
||||||
|
assoc_short_address: [0x33, 0x44],
|
||||||
|
status: MacStatus::Success,
|
||||||
|
security_level: SecurityLevel::Unsecure,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
MacEvent::McpsDataInd(data_ind) => {
|
||||||
|
let data_addr = data_ind.msdu_ptr;
|
||||||
|
let mut data = [0u8; 256];
|
||||||
|
unsafe { data_addr.copy_to(&mut data as *mut _, data_ind.msdu_length as usize) }
|
||||||
|
info!("{}", data[..data_ind.msdu_length as usize]);
|
||||||
|
|
||||||
|
if &data[..data_ind.msdu_length as usize] == b"Hello from embassy!" {
|
||||||
|
info!("success");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
170
examples/stm32wb/src/bin/mac_rfd.rs
Normal file
170
examples/stm32wb/src/bin/mac_rfd.rs
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::*;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::bind_interrupts;
|
||||||
|
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
|
||||||
|
use embassy_stm32_wpan::sub::mac::commands::{AssociateRequest, DataRequest, GetRequest, ResetRequest, SetRequest};
|
||||||
|
use embassy_stm32_wpan::sub::mac::event::MacEvent;
|
||||||
|
use embassy_stm32_wpan::sub::mac::typedefs::{
|
||||||
|
AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel,
|
||||||
|
};
|
||||||
|
use embassy_stm32_wpan::sub::mm;
|
||||||
|
use embassy_stm32_wpan::TlMbox;
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs{
|
||||||
|
IPCC_C1_RX => ReceiveInterruptHandler;
|
||||||
|
IPCC_C1_TX => TransmitInterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn run_mm_queue(memory_manager: mm::MemoryManager) {
|
||||||
|
memory_manager.run_queue().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(spawner: Spawner) {
|
||||||
|
/*
|
||||||
|
How to make this work:
|
||||||
|
|
||||||
|
- Obtain a NUCLEO-STM32WB55 from your preferred supplier.
|
||||||
|
- Download and Install STM32CubeProgrammer.
|
||||||
|
- Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
|
||||||
|
gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
|
||||||
|
- Open STM32CubeProgrammer
|
||||||
|
- On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
|
||||||
|
- Once complete, click connect to connect to the device.
|
||||||
|
- On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
|
||||||
|
- In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
|
||||||
|
- Select that file, the memory address, "verify download", and then "Firmware Upgrade".
|
||||||
|
- Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
|
||||||
|
stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
|
||||||
|
- Select that file, the memory address, "verify download", and then "Firmware Upgrade".
|
||||||
|
- Select "Start Wireless Stack".
|
||||||
|
- Disconnect from the device.
|
||||||
|
- In the examples folder for stm32wb, modify the memory.x file to match your target device.
|
||||||
|
- Run this example.
|
||||||
|
|
||||||
|
Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
let p = embassy_stm32::init(Default::default());
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let config = Config::default();
|
||||||
|
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
||||||
|
|
||||||
|
spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
|
||||||
|
|
||||||
|
let sys_event = mbox.sys_subsystem.read().await;
|
||||||
|
info!("sys event: {}", sys_event.payload());
|
||||||
|
|
||||||
|
core::mem::drop(sys_event);
|
||||||
|
|
||||||
|
let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
|
||||||
|
info!("initialized mac: {}", result);
|
||||||
|
|
||||||
|
info!("resetting");
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&ResetRequest { set_default_pib: true })
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("setting extended address");
|
||||||
|
let extended_address: u64 = 0xACDE480000000002;
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&SetRequest {
|
||||||
|
pib_attribute_ptr: &extended_address as *const _ as *const u8,
|
||||||
|
pib_attribute: PibId::ExtendedAddress,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("getting extended address");
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&GetRequest {
|
||||||
|
pib_attribute: PibId::ExtendedAddress,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
if let Ok(MacEvent::MlmeGetCnf(evt)) = evt {
|
||||||
|
if evt.pib_attribute_value_len == 8 {
|
||||||
|
let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
|
||||||
|
|
||||||
|
info!("value {:#x}", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("assocation request");
|
||||||
|
let a = AssociateRequest {
|
||||||
|
channel_number: MacChannel::Channel16,
|
||||||
|
channel_page: 0,
|
||||||
|
coord_addr_mode: AddressMode::Short,
|
||||||
|
coord_address: MacAddress { short: [34, 17] },
|
||||||
|
capability_information: Capabilities::ALLOCATE_ADDRESS,
|
||||||
|
coord_pan_id: PanId([0x1A, 0xAA]),
|
||||||
|
security_level: SecurityLevel::Unsecure,
|
||||||
|
key_id_mode: KeyIdMode::Implicite,
|
||||||
|
key_source: [0; 8],
|
||||||
|
key_index: 152,
|
||||||
|
};
|
||||||
|
info!("{}", a);
|
||||||
|
mbox.mac_subsystem.send_command(&a).await.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
let short_addr = if let Ok(MacEvent::MlmeAssociateCnf(conf)) = evt {
|
||||||
|
conf.assoc_short_address
|
||||||
|
} else {
|
||||||
|
defmt::panic!()
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("setting short address");
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&SetRequest {
|
||||||
|
pib_attribute_ptr: &short_addr as *const _ as *const u8,
|
||||||
|
pib_attribute: PibId::ShortAddress,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("sending data");
|
||||||
|
let mut data_buffer = [0u8; 256];
|
||||||
|
let data = b"Hello from embassy!";
|
||||||
|
data_buffer[..data.len()].copy_from_slice(data);
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&DataRequest {
|
||||||
|
src_addr_mode: AddressMode::Short,
|
||||||
|
dst_addr_mode: AddressMode::Short,
|
||||||
|
dst_pan_id: PanId([0x1A, 0xAA]),
|
||||||
|
dst_address: MacAddress::BROADCAST,
|
||||||
|
msdu_handle: 0x02,
|
||||||
|
ack_tx: 0x00,
|
||||||
|
gts_tx: false,
|
||||||
|
msdu_ptr: &data_buffer as *const _ as *const u8,
|
||||||
|
msdu_length: data.len() as u8,
|
||||||
|
security_level: SecurityLevel::Unsecure,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
}
|
||||||
|
}
|
@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let sys_event = mbox.sys_subsystem.read().await;
|
let sys_event = mbox.sys_subsystem.read().await;
|
||||||
info!("sys event: {}", sys_event.payload());
|
info!("sys event: {}", sys_event.payload());
|
||||||
|
|
||||||
mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
||||||
|
|
||||||
info!("starting ble...");
|
info!("starting ble...");
|
||||||
mbox.ble_subsystem.tl_write(0x0c, &[]).await;
|
mbox.ble_subsystem.tl_write(0x0c, &[]).await;
|
||||||
|
@ -11,4 +11,4 @@ targets = [
|
|||||||
"thumbv8m.main-none-eabihf",
|
"thumbv8m.main-none-eabihf",
|
||||||
"riscv32imac-unknown-none-elf",
|
"riscv32imac-unknown-none-elf",
|
||||||
"wasm32-unknown-unknown",
|
"wasm32-unknown-unknown",
|
||||||
]
|
]
|
@ -12,14 +12,16 @@ stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo
|
|||||||
stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
|
stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
|
||||||
stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo
|
stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo
|
||||||
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo
|
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo
|
||||||
stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble" ] # Nucleo
|
stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo
|
||||||
stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
|
stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
|
||||||
stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
|
stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
|
||||||
|
|
||||||
sdmmc = []
|
sdmmc = []
|
||||||
chrono = ["embassy-stm32/chrono", "dep:chrono"]
|
chrono = ["embassy-stm32/chrono", "dep:chrono"]
|
||||||
can = []
|
can = []
|
||||||
ble = ["dep:embassy-stm32-wpan"]
|
ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
|
||||||
|
mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
|
||||||
|
embassy-stm32-wpan = []
|
||||||
not-gpdma = []
|
not-gpdma = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -48,11 +50,6 @@ chrono = { version = "^0.4", default-features = false, optional = true}
|
|||||||
|
|
||||||
# BEGIN TESTS
|
# BEGIN TESTS
|
||||||
# Generated by gen_test.py. DO NOT EDIT.
|
# Generated by gen_test.py. DO NOT EDIT.
|
||||||
[[bin]]
|
|
||||||
name = "tl_mbox"
|
|
||||||
path = "src/bin/tl_mbox.rs"
|
|
||||||
required-features = [ "ble",]
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "can"
|
name = "can"
|
||||||
path = "src/bin/can.rs"
|
path = "src/bin/can.rs"
|
||||||
@ -103,6 +100,16 @@ name = "usart_rx_ringbuffered"
|
|||||||
path = "src/bin/usart_rx_ringbuffered.rs"
|
path = "src/bin/usart_rx_ringbuffered.rs"
|
||||||
required-features = [ "not-gpdma",]
|
required-features = [ "not-gpdma",]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "wpan_ble"
|
||||||
|
path = "src/bin/wpan_ble.rs"
|
||||||
|
required-features = [ "ble",]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "wpan_mac"
|
||||||
|
path = "src/bin/wpan_mac.rs"
|
||||||
|
required-features = [ "mac",]
|
||||||
|
|
||||||
# END TESTS
|
# END TESTS
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// required-features: chrono
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
@ -64,7 +64,7 @@ async fn main(spawner: Spawner) {
|
|||||||
version_major, version_minor, subversion, sram2a_size, sram2b_size
|
version_major, version_minor, subversion, sram2a_size, sram2b_size
|
||||||
);
|
);
|
||||||
|
|
||||||
mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
||||||
|
|
||||||
info!("resetting BLE...");
|
info!("resetting BLE...");
|
||||||
mbox.ble_subsystem.reset().await;
|
mbox.ble_subsystem.reset().await;
|
108
tests/stm32/src/bin/wpan_mac.rs
Normal file
108
tests/stm32/src/bin/wpan_mac.rs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// required-features: mac
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
#[path = "../common.rs"]
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
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::{
|
||||||
|
AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel,
|
||||||
|
};
|
||||||
|
use embassy_stm32_wpan::sub::mm;
|
||||||
|
use embassy_stm32_wpan::TlMbox;
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs{
|
||||||
|
IPCC_C1_RX => ReceiveInterruptHandler;
|
||||||
|
IPCC_C1_TX => TransmitInterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn run_mm_queue(memory_manager: mm::MemoryManager) {
|
||||||
|
memory_manager.run_queue().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(spawner: Spawner) {
|
||||||
|
let p = embassy_stm32::init(config());
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let config = Config::default();
|
||||||
|
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
||||||
|
|
||||||
|
spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
|
||||||
|
|
||||||
|
let sys_event = mbox.sys_subsystem.read().await;
|
||||||
|
info!("sys event: {}", sys_event.payload());
|
||||||
|
|
||||||
|
core::mem::drop(sys_event);
|
||||||
|
|
||||||
|
let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
|
||||||
|
info!("initialized mac: {}", result);
|
||||||
|
|
||||||
|
info!("resetting");
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&ResetRequest { set_default_pib: true })
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("setting extended address");
|
||||||
|
let extended_address: u64 = 0xACDE480000000002;
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&SetRequest {
|
||||||
|
pib_attribute_ptr: &extended_address as *const _ as *const u8,
|
||||||
|
pib_attribute: PibId::ExtendedAddress,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("getting extended address");
|
||||||
|
mbox.mac_subsystem
|
||||||
|
.send_command(&GetRequest {
|
||||||
|
pib_attribute: PibId::ExtendedAddress,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
if let Ok(MacEvent::MlmeGetCnf(evt)) = evt {
|
||||||
|
if evt.pib_attribute_value_len == 8 {
|
||||||
|
let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
|
||||||
|
|
||||||
|
info!("value {:#x}", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("assocation request");
|
||||||
|
let a = AssociateRequest {
|
||||||
|
channel_number: MacChannel::Channel16,
|
||||||
|
channel_page: 0,
|
||||||
|
coord_addr_mode: AddressMode::Short,
|
||||||
|
coord_address: MacAddress { short: [34, 17] },
|
||||||
|
capability_information: Capabilities::ALLOCATE_ADDRESS,
|
||||||
|
coord_pan_id: PanId([0x1A, 0xAA]),
|
||||||
|
security_level: SecurityLevel::Unsecure,
|
||||||
|
key_id_mode: KeyIdMode::Implicite,
|
||||||
|
key_source: [0; 8],
|
||||||
|
key_index: 152,
|
||||||
|
};
|
||||||
|
info!("{}", a);
|
||||||
|
mbox.mac_subsystem.send_command(&a).await.unwrap();
|
||||||
|
let evt = mbox.mac_subsystem.read().await;
|
||||||
|
info!("{:#x}", evt);
|
||||||
|
|
||||||
|
info!("Test OK");
|
||||||
|
cortex_m::asm::bkpt();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user