aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-07-15 19:39:06 +0000
committerGitHub <[email protected]>2023-07-15 19:39:06 +0000
commit758862f4b119ec3d701f8a82a623eaa838ac04a3 (patch)
tree7891001a5eb75b1eeed59bc86bb7523c88eb0e45
parent0bde4992ea1b9f662fecaf062b1f6e09dd909112 (diff)
parent3705b4f40d206490a5165a287791206ac70573d9 (diff)
Merge pull request #1655 from xoviat/mac-3
wpan: add mac
-rw-r--r--embassy-stm32-wpan/Cargo.toml3
-rw-r--r--embassy-stm32-wpan/src/consts.rs2
-rw-r--r--embassy-stm32-wpan/src/sub/mac/commands.rs467
-rw-r--r--embassy-stm32-wpan/src/sub/mac/consts.rs4
-rw-r--r--embassy-stm32-wpan/src/sub/mac/event.rs94
-rw-r--r--embassy-stm32-wpan/src/sub/mac/helpers.rs7
-rw-r--r--embassy-stm32-wpan/src/sub/mac/indications.rs470
-rw-r--r--embassy-stm32-wpan/src/sub/mac/macros.rs32
-rw-r--r--embassy-stm32-wpan/src/sub/mac/mod.rs (renamed from embassy-stm32-wpan/src/sub/mac.rs)52
-rw-r--r--embassy-stm32-wpan/src/sub/mac/opcodes.rs92
-rw-r--r--embassy-stm32-wpan/src/sub/mac/responses.rs433
-rw-r--r--embassy-stm32-wpan/src/sub/mac/typedefs.rs363
-rw-r--r--embassy-stm32-wpan/src/sub/sys.rs8
-rw-r--r--examples/stm32wb/.cargo/config.toml2
-rw-r--r--examples/stm32wb/Cargo.toml6
-rw-r--r--examples/stm32wb/src/bin/eddystone_beacon.rs2
-rw-r--r--examples/stm32wb/src/bin/gatt_server.rs2
-rw-r--r--examples/stm32wb/src/bin/mac_ffd.rs183
-rw-r--r--examples/stm32wb/src/bin/mac_rfd.rs170
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_ble.rs2
-rw-r--r--rust-toolchain.toml2
-rw-r--r--tests/stm32/Cargo.toml21
-rw-r--r--tests/stm32/src/bin/rtc.rs2
-rw-r--r--tests/stm32/src/bin/wpan_ble.rs (renamed from tests/stm32/src/bin/tl_mbox.rs)2
-rw-r--r--tests/stm32/src/bin/wpan_mac.rs108
25 files changed, 2504 insertions, 25 deletions
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index f1242ea10..868bffe74 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -26,12 +26,13 @@ aligned = "0.4.1"
26bit_field = "0.10.2" 26bit_field = "0.10.2"
27stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } 27stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
28stm32wb-hci = { version = "0.1.3", optional = true } 28stm32wb-hci = { version = "0.1.3", optional = true }
29bitflags = { version = "2.3.3", optional = true }
29 30
30[features] 31[features]
31defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"] 32defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"]
32 33
33ble = ["dep:stm32wb-hci"] 34ble = ["dep:stm32wb-hci"]
34mac = [] 35mac = ["dep:bitflags"]
35 36
36stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] 37stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
37stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] 38stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs
index 1c84addb1..bd70851ea 100644
--- a/embassy-stm32-wpan/src/consts.rs
+++ b/embassy-stm32-wpan/src/consts.rs
@@ -6,6 +6,8 @@ use crate::PacketHeader;
6#[derive(Debug)] 6#[derive(Debug)]
7#[repr(C)] 7#[repr(C)]
8pub enum TlPacketType { 8pub enum TlPacketType {
9 MacCmd = 0x00,
10
9 BleCmd = 0x01, 11 BleCmd = 0x01,
10 AclData = 0x02, 12 AclData = 0x02,
11 BleEvt = 0x04, 13 BleEvt = 0x04,
diff --git a/embassy-stm32-wpan/src/sub/mac/commands.rs b/embassy-stm32-wpan/src/sub/mac/commands.rs
new file mode 100644
index 000000000..8cfa0a054
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac/commands.rs
@@ -0,0 +1,467 @@
1use super::opcodes::OpcodeM4ToM0;
2use super::typedefs::{
3 AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus,
4 PanId, PibId, ScanType, SecurityLevel,
5};
6
7pub trait MacCommand {
8 const OPCODE: OpcodeM4ToM0;
9 const SIZE: usize;
10
11 fn copy_into_slice(&self, buf: &mut [u8]) {
12 unsafe { core::ptr::copy(self as *const _ as *const u8, buf as *mut _ as *mut u8, Self::SIZE) };
13 }
14}
15
16/// MLME ASSOCIATE Request used to request an association
17#[repr(C)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19pub struct AssociateRequest {
20 /// the logical channel on which to attempt association
21 pub channel_number: MacChannel,
22 /// the channel page on which to attempt association
23 pub channel_page: u8,
24 /// coordinator addressing mode
25 pub coord_addr_mode: AddressMode,
26 /// operational capabilities of the associating device
27 pub capability_information: Capabilities,
28 /// the identifier of the PAN with which to associate
29 pub coord_pan_id: PanId,
30 /// the security level to be used
31 pub security_level: SecurityLevel,
32 /// the mode used to identify the key to be used
33 pub key_id_mode: KeyIdMode,
34 /// the originator of the key to be used
35 pub key_source: [u8; 8],
36 /// Coordinator address
37 pub coord_address: MacAddress,
38 /// the index of the key to be used
39 pub key_index: u8,
40}
41
42impl MacCommand for AssociateRequest {
43 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateReq;
44 const SIZE: usize = 25;
45}
46
47/// MLME DISASSOCIATE Request sed to request a disassociation
48#[repr(C)]
49#[cfg_attr(feature = "defmt", derive(defmt::Format))]
50pub struct DisassociateRequest {
51 /// device addressing mode used
52 pub device_addr_mode: AddressMode,
53 /// the identifier of the PAN of the device
54 pub device_pan_id: PanId,
55 /// the reason for the disassociation
56 pub disassociation_reason: DisassociationReason,
57 /// device address
58 pub device_address: MacAddress,
59 /// `true` if the disassociation notification command is to be sent indirectly
60 pub tx_indirect: bool,
61 /// the security level to be used
62 pub security_level: SecurityLevel,
63 /// the mode to be used to indetify the key to be used
64 pub key_id_mode: KeyIdMode,
65 /// the index of the key to be used
66 pub key_index: u8,
67 /// the originator of the key to be used
68 pub key_source: [u8; 8],
69}
70
71impl MacCommand for DisassociateRequest {
72 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDisassociateReq;
73 const SIZE: usize = 24;
74}
75
76/// MLME GET Request used to request a PIB value
77#[repr(C)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
79pub struct GetRequest {
80 /// the name of the PIB attribute to read
81 pub pib_attribute: PibId,
82}
83
84impl MacCommand for GetRequest {
85 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
86 const SIZE: usize = 4;
87}
88
89/// MLME GTS Request used to request and maintain GTSs
90#[repr(C)]
91#[cfg_attr(feature = "defmt", derive(defmt::Format))]
92pub struct GtsRequest {
93 /// the characteristics of the GTS
94 pub characteristics: GtsCharacteristics,
95 /// the security level to be used
96 pub security_level: SecurityLevel,
97 /// the mode used to identify the key to be used
98 pub key_id_mode: KeyIdMode,
99 /// the index of the key to be used
100 pub key_index: u8,
101 /// the originator of the key to be used
102 pub key_source: [u8; 8],
103}
104
105impl MacCommand for GtsRequest {
106 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
107 const SIZE: usize = 12;
108}
109
110#[repr(C)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub struct ResetRequest {
113 /// MAC PIB attributes are set to their default values or not during reset
114 pub set_default_pib: bool,
115}
116
117impl MacCommand for ResetRequest {
118 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeResetReq;
119 const SIZE: usize = 4;
120}
121
122/// MLME RX ENABLE Request used to request that the receiver is either enabled
123/// for a finite period of time or disabled
124#[repr(C)]
125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
126pub struct RxEnableRequest {
127 /// the request operation can be deferred or not
128 pub defer_permit: bool,
129 /// configure the transceiver to RX with ranging for a value of
130 /// RANGING_ON or to not enable ranging for RANGING_OFF
131 pub ranging_rx_control: u8,
132 /// number of symbols measured before the receiver is to be enabled or disabled
133 pub rx_on_time: [u8; 4],
134 /// number of symbols for which the receiver is to be enabled
135 pub rx_on_duration: [u8; 4],
136}
137
138impl MacCommand for RxEnableRequest {
139 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeRxEnableReq;
140 const SIZE: usize = 12;
141
142 fn copy_into_slice(&self, buf: &mut [u8]) {
143 buf[0] = self.defer_permit as u8;
144 buf[1] = self.ranging_rx_control as u8;
145
146 // stuffing to keep 32bit alignment
147 buf[2] = 0;
148 buf[3] = 0;
149
150 buf[4..8].copy_from_slice(&self.rx_on_time);
151 buf[8..12].copy_from_slice(&self.rx_on_duration);
152 }
153}
154
155/// MLME SCAN Request used to initiate a channel scan over a given list of channels
156#[repr(C)]
157#[cfg_attr(feature = "defmt", derive(defmt::Format))]
158pub struct ScanRequest {
159 /// the type of scan to be performed
160 pub scan_type: ScanType,
161 /// the time spent on scanning each channel
162 pub scan_duration: u8,
163 /// channel page on which to perform the scan
164 pub channel_page: u8,
165 /// security level to be used
166 pub security_level: SecurityLevel,
167 /// indicate which channels are to be scanned
168 pub scan_channels: [u8; 4],
169 /// originator the key to be used
170 pub key_source: [u8; 8],
171 /// mode used to identify the key to be used
172 pub key_id_mode: KeyIdMode,
173 /// index of the key to be used
174 pub key_index: u8,
175}
176
177impl MacCommand for ScanRequest {
178 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeScanReq;
179 const SIZE: usize = 20;
180}
181
182/// MLME SET Request used to attempt to write the given value to the indicated PIB attribute
183#[repr(C)]
184#[cfg_attr(feature = "defmt", derive(defmt::Format))]
185pub struct SetRequest {
186 /// the pointer to the value of the PIB attribute to set
187 pub pib_attribute_ptr: *const u8,
188 /// the name of the PIB attribute to set
189 pub pib_attribute: PibId,
190}
191
192impl MacCommand for SetRequest {
193 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSetReq;
194 const SIZE: usize = 8;
195}
196
197/// MLME START Request used by the FFDs to intiate a new PAN or to begin using a new superframe
198/// configuration
199#[derive(Default)]
200#[repr(C)]
201#[cfg_attr(feature = "defmt", derive(defmt::Format))]
202pub struct StartRequest {
203 /// PAN indentifier to used by the device
204 pub pan_id: PanId,
205 /// logical channel on which to begin
206 pub channel_number: MacChannel,
207 /// channel page on which to begin
208 pub channel_page: u8,
209 /// time at which to begin transmitting beacons
210 pub start_time: [u8; 4],
211 /// indicated how often the beacon is to be transmitted
212 pub beacon_order: u8,
213 /// length of the active portion of the superframe
214 pub superframe_order: u8,
215 /// indicated wheter the device is a PAN coordinator or not
216 pub pan_coordinator: bool,
217 /// indicates if the receiver of the beaconing device is disabled or not
218 pub battery_life_extension: bool,
219 /// indicated if the coordinator realignment command is to be trasmitted
220 pub coord_realignment: u8,
221 /// indicated if the coordinator realignment command is to be trasmitted
222 pub coord_realign_security_level: SecurityLevel,
223 /// index of the key to be used
224 pub coord_realign_key_id_index: u8,
225 /// originator of the key to be used
226 pub coord_realign_key_source: [u8; 8],
227 /// security level to be used for beacon frames
228 pub beacon_security_level: SecurityLevel,
229 /// mode used to identify the key to be used
230 pub beacon_key_id_mode: KeyIdMode,
231 /// index of the key to be used
232 pub beacon_key_index: u8,
233 /// originator of the key to be used
234 pub beacon_key_source: [u8; 8],
235}
236
237impl MacCommand for StartRequest {
238 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeStartReq;
239 const SIZE: usize = 35;
240}
241
242/// MLME SYNC Request used to synchronize with the coordinator by acquiring and, if
243/// specified, tracking its beacons
244#[repr(C)]
245#[cfg_attr(feature = "defmt", derive(defmt::Format))]
246pub struct SyncRequest {
247 /// the channel number on which to attempt coordinator synchronization
248 pub channel_number: MacChannel,
249 /// the channel page on which to attempt coordinator synchronization
250 pub channel_page: u8,
251 /// `true` if the MLME is to synchronize with the next beacon and attempts
252 /// to track all future beacons.
253 ///
254 /// `false` if the MLME is to synchronize with only the next beacon
255 pub track_beacon: bool,
256}
257
258impl MacCommand for SyncRequest {
259 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSyncReq;
260 const SIZE: usize = 4;
261}
262
263/// MLME POLL Request propmts the device to request data from the coordinator
264#[repr(C)]
265#[cfg_attr(feature = "defmt", derive(defmt::Format))]
266pub struct PollRequest {
267 /// addressing mode of the coordinator
268 pub coord_addr_mode: AddressMode,
269 /// security level to be used
270 pub security_level: SecurityLevel,
271 /// mode used to identify the key to be used
272 pub key_id_mode: KeyIdMode,
273 /// index of the key to be used
274 pub key_index: u8,
275 /// coordinator address
276 pub coord_address: MacAddress,
277 /// originator of the key to be used
278 pub key_source: [u8; 8],
279 /// PAN identifier of the coordinator
280 pub coord_pan_id: PanId,
281}
282
283impl MacCommand for PollRequest {
284 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmePollReq;
285 const SIZE: usize = 24;
286}
287
288/// MLME DPS Request allows the next higher layer to request that the PHY utilize a
289/// given pair of preamble codes for a single use pending expiration of the DPSIndexDuration
290#[repr(C)]
291#[cfg_attr(feature = "defmt", derive(defmt::Format))]
292pub struct DpsRequest {
293 /// the index value for the transmitter
294 tx_dps_index: u8,
295 /// the index value of the receiver
296 rx_dps_index: u8,
297 /// the number of symbols for which the transmitter and receiver will utilize the
298 /// respective DPS indices
299 dps_index_duration: u8,
300}
301
302impl MacCommand for DpsRequest {
303 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDpsReq;
304 const SIZE: usize = 4;
305}
306
307/// MLME SOUNDING request primitive which is used by the next higher layer to request that
308/// the PHY respond with channel sounding information
309#[repr(C)]
310#[cfg_attr(feature = "defmt", derive(defmt::Format))]
311pub struct SoundingRequest;
312
313impl MacCommand for SoundingRequest {
314 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSoundingReq;
315 const SIZE: usize = 4;
316}
317
318/// MLME CALIBRATE request primitive which used to obtain the results of a ranging
319/// calibration request from an RDEV
320#[repr(C)]
321#[cfg_attr(feature = "defmt", derive(defmt::Format))]
322pub struct CalibrateRequest;
323
324impl MacCommand for CalibrateRequest {
325 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeCalibrateReq;
326 const SIZE: usize = 4;
327}
328
329/// MCPS DATA Request used for MAC data related requests from the application
330#[repr(C)]
331#[cfg_attr(feature = "defmt", derive(defmt::Format))]
332pub struct DataRequest {
333 /// the handle assocated with the MSDU to be transmitted
334 pub msdu_ptr: *const u8,
335 /// source addressing mode used
336 pub src_addr_mode: AddressMode,
337 /// destination addressing mode used
338 pub dst_addr_mode: AddressMode,
339 /// destination PAN Id
340 pub dst_pan_id: PanId,
341 /// destination address
342 pub dst_address: MacAddress,
343 /// the number of octets contained in the MSDU
344 pub msdu_length: u8,
345 /// the handle assocated with the MSDU to be transmitted
346 pub msdu_handle: u8,
347 /// the ACK transmittion options for the MSDU
348 pub ack_tx: u8,
349 /// `true` if a GTS is to be used for transmission
350 ///
351 /// `false` indicates that the CAP will be used
352 pub gts_tx: bool,
353 /// the pending bit transmission options for the MSDU
354 pub indirect_tx: u8,
355 /// the security level to be used
356 pub security_level: SecurityLevel,
357 /// the mode used to indentify the key to be used
358 pub key_id_mode: KeyIdMode,
359 /// the index of the key to be used
360 pub key_index: u8,
361 /// the originator of the key to be used
362 pub key_source: [u8; 8],
363 /// 2011 - the pulse repitition value
364 pub uwbprf: u8,
365 /// 2011 - the ranging configuration
366 pub ranging: u8,
367 /// 2011 - the preamble symbol repititions
368 pub uwb_preamble_symbol_repetitions: u8,
369 /// 2011 - indicates the data rate
370 pub datrate: u8,
371}
372
373impl Default for DataRequest {
374 fn default() -> Self {
375 Self {
376 msdu_ptr: 0 as *const u8,
377 src_addr_mode: AddressMode::NoAddress,
378 dst_addr_mode: AddressMode::NoAddress,
379 dst_pan_id: PanId([0, 0]),
380 dst_address: MacAddress { short: [0, 0] },
381 msdu_length: 0,
382 msdu_handle: 0,
383 ack_tx: 0,
384 gts_tx: false,
385 indirect_tx: 0,
386 security_level: SecurityLevel::Unsecure,
387 key_id_mode: KeyIdMode::Implicite,
388 key_index: 0,
389 key_source: [0u8; 8],
390 uwbprf: 0,
391 ranging: 0,
392 uwb_preamble_symbol_repetitions: 0,
393 datrate: 0,
394 }
395 }
396}
397
398impl MacCommand for DataRequest {
399 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsDataReq;
400 const SIZE: usize = 40;
401}
402
403/// for MCPS PURGE Request used to purge an MSDU from the transaction queue
404#[repr(C)]
405#[cfg_attr(feature = "defmt", derive(defmt::Format))]
406pub struct PurgeRequest {
407 /// the handle associated with the MSDU to be purged from the transaction
408 /// queue
409 pub msdu_handle: u8,
410}
411
412impl MacCommand for PurgeRequest {
413 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsPurgeReq;
414 const SIZE: usize = 4;
415}
416
417/// MLME ASSOCIATE Response used to initiate a response to an MLME-ASSOCIATE.indication
418#[repr(C)]
419#[derive(Default)]
420#[cfg_attr(feature = "defmt", derive(defmt::Format))]
421pub struct AssociateResponse {
422 /// extended address of the device requesting association
423 pub device_address: [u8; 8],
424 /// 16-bitshort device address allocated by the coordinator on successful
425 /// association
426 pub assoc_short_address: [u8; 2],
427 /// status of the association attempt
428 pub status: MacStatus,
429 /// security level to be used
430 pub security_level: SecurityLevel,
431 /// the originator of the key to be used
432 pub key_source: [u8; 8],
433 /// the mode used to identify the key to be used
434 pub key_id_mode: KeyIdMode,
435 /// the index of the key to be used
436 pub key_index: u8,
437}
438
439impl MacCommand for AssociateResponse {
440 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateRes;
441 const SIZE: usize = 24;
442}
443
444/// MLME ORPHAN Response used to respond to the MLME ORPHAN Indication
445#[repr(C)]
446#[cfg_attr(feature = "defmt", derive(defmt::Format))]
447pub struct OrphanResponse {
448 /// extended address of the orphaned device
449 pub orphan_address: [u8; 8],
450 /// short address allocated to the orphaned device
451 pub short_address: [u8; 2],
452 /// if the orphaned device is associated with coordinator or not
453 pub associated_member: bool,
454 /// security level to be used
455 pub security_level: SecurityLevel,
456 /// the originator of the key to be used
457 pub key_source: [u8; 8],
458 /// the mode used to identify the key to be used
459 pub key_id_mode: KeyIdMode,
460 /// the index of the key to be used
461 pub key_index: u8,
462}
463
464impl MacCommand for OrphanResponse {
465 const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeOrphanRes;
466 const SIZE: usize = 24;
467}
diff --git a/embassy-stm32-wpan/src/sub/mac/consts.rs b/embassy-stm32-wpan/src/sub/mac/consts.rs
new file mode 100644
index 000000000..56903d980
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac/consts.rs
@@ -0,0 +1,4 @@
1pub const MAX_PAN_DESC_SUPPORTED: usize = 6;
2pub const MAX_SOUNDING_LIST_SUPPORTED: usize = 6;
3pub const MAX_PENDING_ADDRESS: usize = 7;
4pub const MAX_ED_SCAN_RESULTS_SUPPORTED: usize = 16;
diff --git a/embassy-stm32-wpan/src/sub/mac/event.rs b/embassy-stm32-wpan/src/sub/mac/event.rs
new file mode 100644
index 000000000..aaf965565
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac/event.rs
@@ -0,0 +1,94 @@
1use super::helpers::to_u16;
2use super::indications::{
3 AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication,
4 DpsIndication, GtsIndication, OrphanIndication, PollIndication, SyncLossIndication,
5};
6use super::responses::{
7 AssociateConfirm, CalibrateConfirm, DataConfirm, DisassociateConfirm, DpsConfirm, GetConfirm, GtsConfirm,
8 PollConfirm, PurgeConfirm, ResetConfirm, RxEnableConfirm, ScanConfirm, SetConfirm, SoundingConfirm, StartConfirm,
9};
10use crate::sub::mac::opcodes::OpcodeM0ToM4;
11
12pub trait ParseableMacEvent {
13 const SIZE: usize;
14
15 fn validate(buf: &[u8]) -> Result<(), ()> {
16 if buf.len() < Self::SIZE {
17 return Err(());
18 }
19
20 Ok(())
21 }
22
23 fn try_parse(buf: &[u8]) -> Result<Self, ()>
24 where
25 Self: Sized;
26}
27
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub enum MacEvent {
30 MlmeAssociateCnf(AssociateConfirm),
31 MlmeDisassociateCnf(DisassociateConfirm),
32 MlmeGetCnf(GetConfirm),
33 MlmeGtsCnf(GtsConfirm),
34 MlmeResetCnf(ResetConfirm),
35 MlmeRxEnableCnf(RxEnableConfirm),
36 MlmeScanCnf(ScanConfirm),
37 MlmeSetCnf(SetConfirm),
38 MlmeStartCnf(StartConfirm),
39 MlmePollCnf(PollConfirm),
40 MlmeDpsCnf(DpsConfirm),
41 MlmeSoundingCnf(SoundingConfirm),
42 MlmeCalibrateCnf(CalibrateConfirm),
43 McpsDataCnf(DataConfirm),
44 McpsPurgeCnf(PurgeConfirm),
45 MlmeAssociateInd(AssociateIndication),
46 MlmeDisassociateInd(DisassociateIndication),
47 MlmeBeaconNotifyInd(BeaconNotifyIndication),
48 MlmeCommStatusInd(CommStatusIndication),
49 MlmeGtsInd(GtsIndication),
50 MlmeOrphanInd(OrphanIndication),
51 MlmeSyncLossInd(SyncLossIndication),
52 MlmeDpsInd(DpsIndication),
53 McpsDataInd(DataIndication),
54 MlmePollInd(PollIndication),
55}
56
57impl TryFrom<&[u8]> for MacEvent {
58 type Error = ();
59
60 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
61 let opcode = to_u16(&value[0..2]);
62 let opcode = OpcodeM0ToM4::try_from(opcode)?;
63
64 let buf = &value[2..];
65
66 match opcode {
67 OpcodeM0ToM4::MlmeAssociateCnf => Ok(Self::MlmeAssociateCnf(AssociateConfirm::try_parse(buf)?)),
68 OpcodeM0ToM4::MlmeDisassociateCnf => Ok(Self::MlmeDisassociateCnf(DisassociateConfirm::try_parse(buf)?)),
69 OpcodeM0ToM4::MlmeGetCnf => Ok(Self::MlmeGetCnf(GetConfirm::try_parse(buf)?)),
70 OpcodeM0ToM4::MlmeGtsCnf => Ok(Self::MlmeGtsCnf(GtsConfirm::try_parse(buf)?)),
71 OpcodeM0ToM4::MlmeResetCnf => Ok(Self::MlmeResetCnf(ResetConfirm::try_parse(buf)?)),
72 OpcodeM0ToM4::MlmeRxEnableCnf => Ok(Self::MlmeRxEnableCnf(RxEnableConfirm::try_parse(buf)?)),
73 OpcodeM0ToM4::MlmeScanCnf => Ok(Self::MlmeScanCnf(ScanConfirm::try_parse(buf)?)),
74 OpcodeM0ToM4::MlmeSetCnf => Ok(Self::MlmeSetCnf(SetConfirm::try_parse(buf)?)),
75 OpcodeM0ToM4::MlmeStartCnf => Ok(Self::MlmeStartCnf(StartConfirm::try_parse(buf)?)),
76 OpcodeM0ToM4::MlmePollCnf => Ok(Self::MlmePollCnf(PollConfirm::try_parse(buf)?)),
77 OpcodeM0ToM4::MlmeDpsCnf => Ok(Self::MlmeDpsCnf(DpsConfirm::try_parse(buf)?)),
78 OpcodeM0ToM4::MlmeSoundingCnf => Ok(Self::MlmeSoundingCnf(SoundingConfirm::try_parse(buf)?)),
79 OpcodeM0ToM4::MlmeCalibrateCnf => Ok(Self::MlmeCalibrateCnf(CalibrateConfirm::try_parse(buf)?)),
80 OpcodeM0ToM4::McpsDataCnf => Ok(Self::McpsDataCnf(DataConfirm::try_parse(buf)?)),
81 OpcodeM0ToM4::McpsPurgeCnf => Ok(Self::McpsPurgeCnf(PurgeConfirm::try_parse(buf)?)),
82 OpcodeM0ToM4::MlmeAssociateInd => Ok(Self::MlmeAssociateInd(AssociateIndication::try_parse(buf)?)),
83 OpcodeM0ToM4::MlmeDisassociateInd => Ok(Self::MlmeDisassociateInd(DisassociateIndication::try_parse(buf)?)),
84 OpcodeM0ToM4::MlmeBeaconNotifyInd => Ok(Self::MlmeBeaconNotifyInd(BeaconNotifyIndication::try_parse(buf)?)),
85 OpcodeM0ToM4::MlmeCommStatusInd => Ok(Self::MlmeCommStatusInd(CommStatusIndication::try_parse(buf)?)),
86 OpcodeM0ToM4::MlmeGtsInd => Ok(Self::MlmeGtsInd(GtsIndication::try_parse(buf)?)),
87 OpcodeM0ToM4::MlmeOrphanInd => Ok(Self::MlmeOrphanInd(OrphanIndication::try_parse(buf)?)),
88 OpcodeM0ToM4::MlmeSyncLossInd => Ok(Self::MlmeSyncLossInd(SyncLossIndication::try_parse(buf)?)),
89 OpcodeM0ToM4::MlmeDpsInd => Ok(Self::MlmeDpsInd(DpsIndication::try_parse(buf)?)),
90 OpcodeM0ToM4::McpsDataInd => Ok(Self::McpsDataInd(DataIndication::try_parse(buf)?)),
91 OpcodeM0ToM4::MlmePollInd => Ok(Self::MlmePollInd(PollIndication::try_parse(buf)?)),
92 }
93 }
94}
diff --git a/embassy-stm32-wpan/src/sub/mac/helpers.rs b/embassy-stm32-wpan/src/sub/mac/helpers.rs
new file mode 100644
index 000000000..5a5bf8a85
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac/helpers.rs
@@ -0,0 +1,7 @@
1pub fn to_u16(buf: &[u8]) -> u16 {
2 ((buf[1] as u16) << 8) | buf[0] as u16
3}
4
5pub fn to_u32(buf: &[u8]) -> u32 {
6 ((buf[0] as u32) << 0) + ((buf[1] as u32) << 8) + ((buf[2] as u32) << 16) + ((buf[3] as u32) << 24)
7}
diff --git a/embassy-stm32-wpan/src/sub/mac/indications.rs b/embassy-stm32-wpan/src/sub/mac/indications.rs
new file mode 100644
index 000000000..6df4aa23a
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac/indications.rs
@@ -0,0 +1,470 @@
1use super::consts::MAX_PENDING_ADDRESS;
2use super::event::ParseableMacEvent;
3use super::helpers::to_u32;
4use super::typedefs::{
5 AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor,
6 PanId, SecurityLevel,
7};
8
9/// MLME ASSOCIATE Indication which will be used by the MAC
10/// to indicate the reception of an association request command
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub struct AssociateIndication {
13 /// Extended address of the device requesting association
14 pub device_address: [u8; 8],
15 /// Operational capabilities of the device requesting association
16 pub capability_information: Capabilities,
17 /// Security level purportedly used by the received MAC command frame
18 pub security_level: SecurityLevel,
19 /// The mode used to identify the key used by the originator of frame
20 pub key_id_mode: KeyIdMode,
21 /// Index of the key used by the originator of the received frame
22 pub key_index: u8,
23 /// The originator of the key used by the originator of the received frame
24 pub key_source: [u8; 8],
25}
26
27impl ParseableMacEvent for AssociateIndication {
28 const SIZE: usize = 20;
29
30 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
31 Self::validate(buf)?;
32
33 Ok(Self {
34 device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
35 capability_information: Capabilities::from_bits(buf[8]).ok_or(())?,
36 security_level: SecurityLevel::try_from(buf[9])?,
37 key_id_mode: KeyIdMode::try_from(buf[10])?,
38 key_index: buf[11],
39 key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]],
40 })
41 }
42}
43
44/// MLME DISASSOCIATE indication which will be used to send
45/// disassociation indication to the application.
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub struct DisassociateIndication {
48 /// Extended address of the device requesting association
49 pub device_address: [u8; 8],
50 /// The reason for the disassociation
51 pub disassociation_reason: DisassociationReason,
52 /// The security level to be used
53 pub security_level: SecurityLevel,
54 /// The mode used to identify the key to be used
55 pub key_id_mode: KeyIdMode,
56 /// The index of the key to be used
57 pub key_index: u8,
58 /// The originator of the key to be used
59 pub key_source: [u8; 8],
60}
61
62impl ParseableMacEvent for DisassociateIndication {
63 const SIZE: usize = 20;
64
65 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
66 Self::validate(buf)?;
67
68 Ok(Self {
69 device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
70 disassociation_reason: DisassociationReason::try_from(buf[8])?,
71 security_level: SecurityLevel::try_from(buf[9])?,
72 key_id_mode: KeyIdMode::try_from(buf[10])?,
73 key_index: buf[11],
74 key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]],
75 })
76 }
77}
78
79/// MLME BEACON NOTIIFY Indication which is used to send parameters contained
80/// within a beacon frame received by the MAC to the application
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub struct BeaconNotifyIndication {
83 /// he set of octets comprising the beacon payload to be transferred
84 /// from the MAC sublayer entity to the next higher layer
85 pub sdu_ptr: *const u8,
86 /// The PAN Descriptor for the received beacon
87 pub pan_descriptor: PanDescriptor,
88 /// The list of addresses of the devices
89 pub addr_list: [MacAddress; MAX_PENDING_ADDRESS],
90 /// Beacon Sequence Number
91 pub bsn: u8,
92 /// The beacon pending address specification
93 pub pend_addr_spec: u8,
94 /// Number of octets contained in the beacon payload of the beacon frame
95 pub sdu_length: u8,
96}
97
98impl ParseableMacEvent for BeaconNotifyIndication {
99 const SIZE: usize = 88;
100
101 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
102 // TODO: this is unchecked
103
104 Self::validate(buf)?;
105
106 let addr_list = [
107 MacAddress::try_from(&buf[26..34])?,
108 MacAddress::try_from(&buf[34..42])?,
109 MacAddress::try_from(&buf[42..50])?,
110 MacAddress::try_from(&buf[50..58])?,
111 MacAddress::try_from(&buf[58..66])?,
112 MacAddress::try_from(&buf[66..74])?,
113 MacAddress::try_from(&buf[74..82])?,
114 ];
115
116 Ok(Self {
117 sdu_ptr: to_u32(&buf[0..4]) as *const u8,
118 pan_descriptor: PanDescriptor::try_from(&buf[4..26])?,
119 addr_list,
120 bsn: buf[82],
121 pend_addr_spec: buf[83],
122 sdu_length: buf[83],
123 })
124 }
125}
126
127/// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status
128#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub struct CommStatusIndication {
130 /// The 16-bit PAN identifier of the device from which the frame
131 /// was received or to which the frame was being sent
132 pub pan_id: PanId,
133 /// Source addressing mode
134 pub src_addr_mode: AddressMode,
135 /// Destination addressing mode
136 pub dst_addr_mode: AddressMode,
137 /// Source address
138 pub src_address: MacAddress,
139 /// Destination address
140 pub dst_address: MacAddress,
141 /// The communications status
142 pub status: MacStatus,
143 /// Security level to be used
144 pub security_level: SecurityLevel,
145 /// Mode used to identify the key to be used
146 pub key_id_mode: KeyIdMode,
147 /// Index of the key to be used
148 pub key_index: u8,
149 /// Originator of the key to be used
150 pub key_source: [u8; 8],
151}
152
153impl ParseableMacEvent for CommStatusIndication {
154 const SIZE: usize = 32;
155
156 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
157 Self::validate(buf)?;
158
159 let src_addr_mode = AddressMode::try_from(buf[2])?;
160 let dst_addr_mode = AddressMode::try_from(buf[3])?;
161
162 let src_address = match src_addr_mode {
163 AddressMode::NoAddress => MacAddress { short: [0, 0] },
164 AddressMode::Reserved => MacAddress { short: [0, 0] },
165 AddressMode::Short => MacAddress {
166 short: [buf[4], buf[5]],
167 },
168 AddressMode::Extended => MacAddress {
169 extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
170 },
171 };
172
173 let dst_address = match dst_addr_mode {
174 AddressMode::NoAddress => MacAddress { short: [0, 0] },
175 AddressMode::Reserved => MacAddress { short: [0, 0] },
176 AddressMode::Short => MacAddress {
177 short: [buf[12], buf[13]],
178 },
179 AddressMode::Extended => MacAddress {
180 extended: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]],
181 },
182 };
183
184 Ok(Self {
185 pan_id: PanId([buf[0], buf[1]]),
186 src_addr_mode,
187 dst_addr_mode,
188 src_address,
189 dst_address,
190 status: MacStatus::try_from(buf[20])?,
191 security_level: SecurityLevel::try_from(buf[21])?,
192 key_id_mode: KeyIdMode::try_from(buf[22])?,
193 key_index: buf[23],
194 key_source: [buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]],
195 })
196 }
197}
198
199/// MLME GTS Indication indicates that a GTS has been allocated or that a
200/// previously allocated GTS has been deallocated
201#[cfg_attr(feature = "defmt", derive(defmt::Format))]
202pub struct GtsIndication {
203 /// The short address of the device that has been allocated or deallocated a GTS
204 pub device_address: [u8; 2],
205 /// The characteristics of the GTS
206 pub gts_characteristics: u8,
207 /// Security level to be used
208 pub security_level: SecurityLevel,
209 /// Mode used to identify the key to be used
210 pub key_id_mode: KeyIdMode,
211 /// Index of the key to be used
212 pub key_index: u8,
213 /// Originator of the key to be used
214 pub key_source: [u8; 8],
215}
216
217impl ParseableMacEvent for GtsIndication {
218 const SIZE: usize = 16;
219
220 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
221 Self::validate(buf)?;
222
223 Ok(Self {
224 device_address: [buf[0], buf[1]],
225 gts_characteristics: buf[2],
226 security_level: SecurityLevel::try_from(buf[3])?,
227 key_id_mode: KeyIdMode::try_from(buf[4])?,
228 key_index: buf[5],
229 // 2 byte stuffing
230 key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]],
231 })
232 }
233}
234
235/// MLME ORPHAN Indication which is used by the coordinator to notify the
236/// application of the presence of an orphaned device
237#[cfg_attr(feature = "defmt", derive(defmt::Format))]
238pub struct OrphanIndication {
239 /// Extended address of the orphaned device
240 pub orphan_address: [u8; 8],
241 /// Originator of the key used by the originator of the received frame
242 pub key_source: [u8; 8],
243 /// Security level purportedly used by the received MAC command frame
244 pub security_level: SecurityLevel,
245 /// Mode used to identify the key used by originator of received frame
246 pub key_id_mode: KeyIdMode,
247 /// Index of the key used by the originator of the received frame
248 pub key_index: u8,
249}
250
251impl ParseableMacEvent for OrphanIndication {
252 const SIZE: usize = 20;
253
254 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
255 Self::validate(buf)?;
256
257 Ok(Self {
258 orphan_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
259 key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]],
260 security_level: SecurityLevel::try_from(buf[16])?,
261 key_id_mode: KeyIdMode::try_from(buf[17])?,
262 key_index: buf[18],
263 // 1 byte stuffing
264 })
265 }
266}
267
268/// MLME SYNC LOSS Indication which is used by the MAC to indicate the loss
269/// of synchronization with the coordinator
270#[cfg_attr(feature = "defmt", derive(defmt::Format))]
271pub struct SyncLossIndication {
272 /// The PAN identifier with which the device lost synchronization or to which it was realigned
273 pub pan_id: PanId,
274 /// The reason that synchronization was lost
275 pub loss_reason: u8,
276 /// The logical channel on which the device lost synchronization or to whi
277 pub channel_number: MacChannel,
278 /// The channel page on which the device lost synchronization or to which
279 pub channel_page: u8,
280 /// The security level used by the received MAC frame
281 pub security_level: SecurityLevel,
282 /// Mode used to identify the key used by originator of received frame
283 pub key_id_mode: KeyIdMode,
284 /// Index of the key used by the originator of the received frame
285 pub key_index: u8,
286 /// Originator of the key used by the originator of the received frame
287 pub key_source: [u8; 8],
288}
289
290impl ParseableMacEvent for SyncLossIndication {
291 const SIZE: usize = 16;
292
293 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
294 Self::validate(buf)?;
295
296 Ok(Self {
297 pan_id: PanId([buf[0], buf[1]]),
298 loss_reason: buf[2],
299 channel_number: MacChannel::try_from(buf[3])?,
300 channel_page: buf[4],
301 security_level: SecurityLevel::try_from(buf[5])?,
302 key_id_mode: KeyIdMode::try_from(buf[6])?,
303 key_index: buf[7],
304 key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]],
305 })
306 }
307}
308
309/// MLME DPS Indication which indicates the expiration of the DPSIndexDuration
310/// and the resetting of the DPS values in the PHY
311#[cfg_attr(feature = "defmt", derive(defmt::Format))]
312pub struct DpsIndication;
313
314impl ParseableMacEvent for DpsIndication {
315 const SIZE: usize = 4;
316
317 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
318 Self::validate(buf)?;
319
320 Ok(Self)
321 }
322}
323
324#[cfg_attr(feature = "defmt", derive(defmt::Format))]
325#[repr(C, align(8))]
326pub struct DataIndication {
327 /// Pointer to the set of octets forming the MSDU being indicated
328 pub msdu_ptr: *const u8,
329 /// Source addressing mode used
330 pub src_addr_mode: AddressMode,
331 /// Source PAN ID
332 pub src_pan_id: PanId,
333 /// Source address
334 pub src_address: MacAddress,
335 /// Destination addressing mode used
336 pub dst_addr_mode: AddressMode,
337 /// Destination PAN ID
338 pub dst_pan_id: PanId,
339 /// Destination address
340 pub dst_address: MacAddress,
341 /// The number of octets contained in the MSDU being indicated
342 pub msdu_length: u8,
343 /// QI value measured during reception of the MPDU
344 pub mpdu_link_quality: u8,
345 /// The data sequence number of the received data frame
346 pub dsn: u8,
347 /// The time, in symbols, at which the data were received
348 pub time_stamp: [u8; 4],
349 /// The security level purportedly used by the received data frame
350 pub security_level: SecurityLevel,
351 /// Mode used to identify the key used by originator of received frame
352 pub key_id_mode: KeyIdMode,
353 /// The originator of the key
354 pub key_source: [u8; 8],
355 /// The index of the key
356 pub key_index: u8,
357 /// he pulse repetition value of the received PPDU
358 pub uwbprf: u8,
359 /// The preamble symbol repetitions of the UWB PHY frame
360 pub uwn_preamble_symbol_repetitions: u8,
361 /// Indicates the data rate
362 pub datrate: u8,
363 /// time units corresponding to an RMARKER at the antenna at the end of a ranging exchange,
364 pub ranging_received: u8,
365 pub ranging_counter_start: u32,
366 pub ranging_counter_stop: u32,
367 /// ime units in a message exchange over which the tracking offset was measured
368 pub ranging_tracking_interval: u32,
369 /// time units slipped or advanced by the radio tracking system
370 pub ranging_offset: u32,
371 /// The FoM characterizing the ranging measurement
372 pub ranging_fom: u8,
373 /// The Received Signal Strength Indicator measured
374 pub rssi: u8,
375}
376
377impl ParseableMacEvent for DataIndication {
378 const SIZE: usize = 68;
379
380 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
381 Self::validate(buf)?;
382
383 let src_addr_mode = AddressMode::try_from(buf[4])?;
384 let src_address = match src_addr_mode {
385 AddressMode::NoAddress => MacAddress { short: [0, 0] },
386 AddressMode::Reserved => MacAddress { short: [0, 0] },
387 AddressMode::Short => MacAddress {
388 short: [buf[7], buf[8]],
389 },
390 AddressMode::Extended => MacAddress {
391 extended: [buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14]],
392 },
393 };
394
395 let dst_addr_mode = AddressMode::try_from(buf[15])?;
396 let dst_address = match dst_addr_mode {
397 AddressMode::NoAddress => MacAddress { short: [0, 0] },
398 AddressMode::Reserved => MacAddress { short: [0, 0] },
399 AddressMode::Short => MacAddress {
400 short: [buf[18], buf[19]],
401 },
402 AddressMode::Extended => MacAddress {
403 extended: [buf[18], buf[19], buf[20], buf[21], buf[22], buf[23], buf[24], buf[25]],
404 },
405 };
406
407 Ok(Self {
408 msdu_ptr: to_u32(&buf[0..4]) as *const u8,
409 src_addr_mode,
410 src_pan_id: PanId([buf[5], buf[6]]),
411 src_address,
412 dst_addr_mode,
413 dst_pan_id: PanId([buf[16], buf[17]]),
414 dst_address,
415 msdu_length: buf[26],
416 mpdu_link_quality: buf[27],
417 dsn: buf[28],
418 time_stamp: [buf[29], buf[30], buf[31], buf[32]],
419 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
420 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
421 key_source: [buf[35], buf[36], buf[37], buf[38], buf[39], buf[40], buf[41], buf[42]],
422 key_index: buf[43],
423 uwbprf: buf[44],
424 uwn_preamble_symbol_repetitions: buf[45],
425 datrate: buf[46],
426 ranging_received: buf[47],
427 ranging_counter_start: to_u32(&buf[48..52]),
428 ranging_counter_stop: to_u32(&buf[52..56]),
429 ranging_tracking_interval: to_u32(&buf[56..60]),
430 ranging_offset: to_u32(&buf[60..64]),
431 ranging_fom: buf[65],
432 rssi: buf[66],
433 })
434 }
435}
436
437/// MLME POLL Indication which will be used for indicating the Data Request
438/// reception to upper layer as defined in Zigbee r22 - D.8.2
439#[cfg_attr(feature = "defmt", derive(defmt::Format))]
440pub struct PollIndication {
441 /// addressing mode used
442 pub addr_mode: AddressMode,
443 /// Poll requester address
444 pub request_address: MacAddress,
445}
446
447impl ParseableMacEvent for PollIndication {
448 const SIZE: usize = 9;
449
450 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
451 Self::validate(buf)?;
452
453 let addr_mode = AddressMode::try_from(buf[0])?;
454 let request_address = match addr_mode {
455 AddressMode::NoAddress => MacAddress { short: [0, 0] },
456 AddressMode::Reserved => MacAddress { short: [0, 0] },
457 AddressMode::Short => MacAddress {
458 short: [buf[1], buf[2]],
459 },
460 AddressMode::Extended => MacAddress {
461 extended: [buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]],
462 },
463 };
464
465 Ok(Self {
466 addr_mode,
467 request_address,
468 })
469 }
470}
diff --git a/embassy-stm32-wpan/src/sub/mac/macros.rs b/embassy-stm32-wpan/src/sub/mac/macros.rs
new file mode 100644
index 000000000..1a988a779
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac/macros.rs
@@ -0,0 +1,32 @@
1#[macro_export]
2macro_rules! numeric_enum {
3 (#[repr($repr:ident)]
4 $(#$attrs:tt)* $vis:vis enum $name:ident {
5 $($(#$enum_attrs:tt)* $enum:ident = $constant:expr),* $(,)?
6 } ) => {
7 #[repr($repr)]
8 $(#$attrs)*
9 $vis enum $name {
10 $($(#$enum_attrs)* $enum = $constant),*
11 }
12
13 impl ::core::convert::TryFrom<$repr> for $name {
14 type Error = ();
15
16 fn try_from(value: $repr) -> ::core::result::Result<Self, ()> {
17 match value {
18 $($constant => Ok( $name :: $enum ),)*
19 _ => Err(())
20 }
21 }
22 }
23
24 impl ::core::convert::From<$name> for $repr {
25 fn from(value: $name) -> $repr {
26 match value {
27 $($name :: $enum => $constant,)*
28 }
29 }
30 }
31 }
32}
diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac/mod.rs
index f7a59b0e4..ab39f89c2 100644
--- a/embassy-stm32-wpan/src/sub/mac.rs
+++ b/embassy-stm32-wpan/src/sub/mac/mod.rs
@@ -8,12 +8,25 @@ use embassy_futures::poll_once;
8use embassy_stm32::ipcc::Ipcc; 8use embassy_stm32::ipcc::Ipcc;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use self::commands::MacCommand;
12use self::event::MacEvent;
13use self::typedefs::MacError;
11use crate::cmd::CmdPacket; 14use crate::cmd::CmdPacket;
12use crate::consts::TlPacketType; 15use crate::consts::TlPacketType;
13use crate::evt::{EvtBox, EvtPacket}; 16use crate::evt::{EvtBox, EvtPacket};
14use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER}; 17use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER};
15use crate::{channels, evt}; 18use crate::{channels, evt};
16 19
20pub mod commands;
21mod consts;
22pub mod event;
23mod helpers;
24pub mod indications;
25mod macros;
26mod opcodes;
27pub mod responses;
28pub mod typedefs;
29
17static MAC_WAKER: AtomicWaker = AtomicWaker::new(); 30static MAC_WAKER: AtomicWaker = AtomicWaker::new();
18static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); 31static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
19 32
@@ -29,7 +42,7 @@ impl Mac {
29 /// `HW_IPCC_MAC_802_15_4_EvtNot` 42 /// `HW_IPCC_MAC_802_15_4_EvtNot`
30 /// 43 ///
31 /// This function will stall if the previous `EvtBox` has not been dropped 44 /// This function will stall if the previous `EvtBox` has not been dropped
32 pub async fn read(&self) -> EvtBox<Self> { 45 pub async fn tl_read(&self) -> EvtBox<Self> {
33 // Wait for the last event box to be dropped 46 // Wait for the last event box to be dropped
34 poll_fn(|cx| { 47 poll_fn(|cx| {
35 MAC_WAKER.register(cx.waker()); 48 MAC_WAKER.register(cx.waker());
@@ -53,9 +66,9 @@ impl Mac {
53 } 66 }
54 67
55 /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` 68 /// `HW_IPCC_MAC_802_15_4_CmdEvtNot`
56 pub async fn write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { 69 pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 {
57 self.write(opcode, payload).await; 70 self.tl_write(opcode, payload).await;
58 Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await; 71 Ipcc::flush(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL).await;
59 72
60 unsafe { 73 unsafe {
61 let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket; 74 let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket;
@@ -66,19 +79,46 @@ impl Mac {
66 } 79 }
67 80
68 /// `TL_MAC_802_15_4_SendCmd` 81 /// `TL_MAC_802_15_4_SendCmd`
69 pub async fn write(&self, opcode: u16, payload: &[u8]) { 82 pub async fn tl_write(&self, opcode: u16, payload: &[u8]) {
70 Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe { 83 Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe {
71 CmdPacket::write_into( 84 CmdPacket::write_into(
72 MAC_802_15_4_CMD_BUFFER.as_mut_ptr(), 85 MAC_802_15_4_CMD_BUFFER.as_mut_ptr(),
73 TlPacketType::OtCmd, 86 TlPacketType::MacCmd,
74 opcode, 87 opcode,
75 payload, 88 payload,
76 ); 89 );
77 }) 90 })
78 .await; 91 .await;
79 } 92 }
93
94 pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError>
95 where
96 T: MacCommand,
97 {
98 let mut payload = [0u8; MAX_PACKET_SIZE];
99 cmd.copy_into_slice(&mut payload);
100
101 let response = self
102 .tl_write_and_get_response(T::OPCODE as u16, &payload[..T::SIZE])
103 .await;
104
105 if response == 0x00 {
106 Ok(())
107 } else {
108 Err(MacError::from(response))
109 }
110 }
111
112 pub async fn read(&self) -> Result<MacEvent, ()> {
113 let evt_box = self.tl_read().await;
114 let payload = evt_box.payload();
115
116 MacEvent::try_from(payload)
117 }
80} 118}
81 119
120const MAX_PACKET_SIZE: usize = 255;
121
82impl evt::MemoryManager for Mac { 122impl evt::MemoryManager for Mac {
83 /// SAFETY: passing a pointer to something other than a managed event packet is UB 123 /// SAFETY: passing a pointer to something other than a managed event packet is UB
84 unsafe fn drop_event_packet(_: *mut EvtPacket) { 124 unsafe fn drop_event_packet(_: *mut EvtPacket) {
diff --git a/embassy-stm32-wpan/src/sub/mac/opcodes.rs b/embassy-stm32-wpan/src/sub/mac/opcodes.rs
new file mode 100644
index 000000000..fd7011873
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac/opcodes.rs
@@ -0,0 +1,92 @@
1const ST_VENDOR_OGF: u16 = 0x3F;
2const MAC_802_15_4_CMD_OPCODE_OFFSET: u16 = 0x280;
3
4const fn opcode(ocf: u16) -> isize {
5 ((ST_VENDOR_OGF << 9) | (MAC_802_15_4_CMD_OPCODE_OFFSET + ocf)) as isize
6}
7
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub enum OpcodeM4ToM0 {
10 MlmeAssociateReq = opcode(0x00),
11 MlmeAssociateRes = opcode(0x01),
12 MlmeDisassociateReq = opcode(0x02),
13 MlmeGetReq = opcode(0x03),
14 MlmeGtsReq = opcode(0x04),
15 MlmeOrphanRes = opcode(0x05),
16 MlmeResetReq = opcode(0x06),
17 MlmeRxEnableReq = opcode(0x07),
18 MlmeScanReq = opcode(0x08),
19 MlmeSetReq = opcode(0x09),
20 MlmeStartReq = opcode(0x0A),
21 MlmeSyncReq = opcode(0x0B),
22 MlmePollReq = opcode(0x0C),
23 MlmeDpsReq = opcode(0x0D),
24 MlmeSoundingReq = opcode(0x0E),
25 MlmeCalibrateReq = opcode(0x0F),
26 McpsDataReq = opcode(0x10),
27 McpsPurgeReq = opcode(0x11),
28}
29
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub enum OpcodeM0ToM4 {
32 MlmeAssociateCnf = 0x00,
33 MlmeDisassociateCnf,
34 MlmeGetCnf,
35 MlmeGtsCnf,
36 MlmeResetCnf,
37 MlmeRxEnableCnf,
38 MlmeScanCnf,
39 MlmeSetCnf,
40 MlmeStartCnf,
41 MlmePollCnf,
42 MlmeDpsCnf,
43 MlmeSoundingCnf,
44 MlmeCalibrateCnf,
45 McpsDataCnf,
46 McpsPurgeCnf,
47 MlmeAssociateInd,
48 MlmeDisassociateInd,
49 MlmeBeaconNotifyInd,
50 MlmeCommStatusInd,
51 MlmeGtsInd,
52 MlmeOrphanInd,
53 MlmeSyncLossInd,
54 MlmeDpsInd,
55 McpsDataInd,
56 MlmePollInd,
57}
58
59impl TryFrom<u16> for OpcodeM0ToM4 {
60 type Error = ();
61
62 fn try_from(value: u16) -> Result<Self, Self::Error> {
63 match value {
64 0 => Ok(Self::MlmeAssociateCnf),
65 1 => Ok(Self::MlmeDisassociateCnf),
66 2 => Ok(Self::MlmeGetCnf),
67 3 => Ok(Self::MlmeGtsCnf),
68 4 => Ok(Self::MlmeResetCnf),
69 5 => Ok(Self::MlmeRxEnableCnf),
70 6 => Ok(Self::MlmeScanCnf),
71 7 => Ok(Self::MlmeSetCnf),
72 8 => Ok(Self::MlmeStartCnf),
73 9 => Ok(Self::MlmePollCnf),
74 10 => Ok(Self::MlmeDpsCnf),
75 11 => Ok(Self::MlmeSoundingCnf),
76 12 => Ok(Self::MlmeCalibrateCnf),
77 13 => Ok(Self::McpsDataCnf),
78 14 => Ok(Self::McpsPurgeCnf),
79 15 => Ok(Self::MlmeAssociateInd),
80 16 => Ok(Self::MlmeDisassociateInd),
81 17 => Ok(Self::MlmeBeaconNotifyInd),
82 18 => Ok(Self::MlmeCommStatusInd),
83 19 => Ok(Self::MlmeGtsInd),
84 20 => Ok(Self::MlmeOrphanInd),
85 21 => Ok(Self::MlmeSyncLossInd),
86 22 => Ok(Self::MlmeDpsInd),
87 23 => Ok(Self::McpsDataInd),
88 24 => Ok(Self::MlmePollInd),
89 _ => Err(()),
90 }
91 }
92}
diff --git a/embassy-stm32-wpan/src/sub/mac/responses.rs b/embassy-stm32-wpan/src/sub/mac/responses.rs
new file mode 100644
index 000000000..2f6f5bf58
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac/responses.rs
@@ -0,0 +1,433 @@
1use super::consts::{MAX_ED_SCAN_RESULTS_SUPPORTED, MAX_PAN_DESC_SUPPORTED, MAX_SOUNDING_LIST_SUPPORTED};
2use super::event::ParseableMacEvent;
3use super::helpers::to_u32;
4use super::typedefs::{
5 AddressMode, AssociationStatus, KeyIdMode, MacAddress, MacStatus, PanDescriptor, PanId, PibId, ScanType,
6 SecurityLevel,
7};
8
9/// MLME ASSOCIATE Confirm used to inform of the initiating device whether
10/// its request to associate was successful or unsuccessful
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub struct AssociateConfirm {
13 /// short address allocated by the coordinator on successful association
14 pub assoc_short_address: [u8; 2],
15 /// status of the association request
16 pub status: AssociationStatus,
17 /// security level to be used
18 pub security_level: SecurityLevel,
19 /// the originator of the key to be used
20 pub key_source: [u8; 8],
21 /// the mode used to identify the key to be used
22 pub key_id_mode: KeyIdMode,
23 /// the index of the key to be used
24 pub key_index: u8,
25}
26
27impl ParseableMacEvent for AssociateConfirm {
28 const SIZE: usize = 16;
29
30 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
31 Self::validate(buf)?;
32
33 Ok(Self {
34 assoc_short_address: [buf[0], buf[1]],
35 status: AssociationStatus::try_from(buf[2])?,
36 security_level: SecurityLevel::try_from(buf[3])?,
37 key_source: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
38 key_id_mode: KeyIdMode::try_from(buf[12])?,
39 key_index: buf[13],
40 })
41 }
42}
43
44/// MLME DISASSOCIATE Confirm used to send disassociation Confirmation to the application.
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46pub struct DisassociateConfirm {
47 /// status of the disassociation attempt
48 pub status: MacStatus,
49 /// device addressing mode used
50 pub device_addr_mode: AddressMode,
51 /// the identifier of the PAN of the device
52 pub device_pan_id: PanId,
53 /// device address
54 pub device_address: MacAddress,
55}
56
57impl ParseableMacEvent for DisassociateConfirm {
58 const SIZE: usize = 12;
59
60 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
61 Self::validate(buf)?;
62
63 let device_addr_mode = AddressMode::try_from(buf[1])?;
64 let device_address = match device_addr_mode {
65 AddressMode::NoAddress => MacAddress { short: [0, 0] },
66 AddressMode::Reserved => MacAddress { short: [0, 0] },
67 AddressMode::Short => MacAddress {
68 short: [buf[4], buf[5]],
69 },
70 AddressMode::Extended => MacAddress {
71 extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
72 },
73 };
74
75 Ok(Self {
76 status: MacStatus::try_from(buf[0])?,
77 device_addr_mode,
78 device_pan_id: PanId([buf[2], buf[3]]),
79 device_address,
80 })
81 }
82}
83
84/// MLME GET Confirm which requests information about a given PIB attribute
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub struct GetConfirm {
87 /// The pointer to the value of the PIB attribute attempted to read
88 pub pib_attribute_value_ptr: *const u8,
89 /// Status of the GET attempt
90 pub status: MacStatus,
91 /// The name of the PIB attribute attempted to read
92 pub pib_attribute: PibId,
93 /// The lenght of the PIB attribute Value return
94 pub pib_attribute_value_len: u8,
95}
96
97impl ParseableMacEvent for GetConfirm {
98 const SIZE: usize = 8;
99
100 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
101 Self::validate(buf)?;
102
103 let address = to_u32(&buf[0..4]);
104
105 Ok(Self {
106 pib_attribute_value_ptr: address as *const u8,
107 status: MacStatus::try_from(buf[4])?,
108 pib_attribute: PibId::try_from(buf[5])?,
109 pib_attribute_value_len: buf[6],
110 })
111 }
112}
113
114/// MLME GTS Confirm which eports the results of a request to allocate a new GTS
115/// or to deallocate an existing GTS
116#[cfg_attr(feature = "defmt", derive(defmt::Format))]
117pub struct GtsConfirm {
118 /// The characteristics of the GTS
119 pub gts_characteristics: u8,
120 /// The status of the GTS reques
121 pub status: MacStatus,
122}
123
124impl ParseableMacEvent for GtsConfirm {
125 const SIZE: usize = 4;
126
127 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
128 Self::validate(buf)?;
129
130 Ok(Self {
131 gts_characteristics: buf[0],
132 status: MacStatus::try_from(buf[1])?,
133 })
134 }
135}
136
137/// MLME RESET Confirm which is used to report the results of the reset operation
138#[cfg_attr(feature = "defmt", derive(defmt::Format))]
139pub struct ResetConfirm {
140 /// The result of the reset operation
141 status: MacStatus,
142}
143
144impl ParseableMacEvent for ResetConfirm {
145 const SIZE: usize = 4;
146
147 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
148 Self::validate(buf)?;
149
150 Ok(Self {
151 status: MacStatus::try_from(buf[0])?,
152 })
153 }
154}
155
156/// MLME RX ENABLE Confirm which is used to report the results of the attempt
157/// to enable or disable the receiver
158#[cfg_attr(feature = "defmt", derive(defmt::Format))]
159pub struct RxEnableConfirm {
160 /// Result of the request to enable or disable the receiver
161 status: MacStatus,
162}
163
164impl ParseableMacEvent for RxEnableConfirm {
165 const SIZE: usize = 4;
166
167 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
168 Self::validate(buf)?;
169
170 Ok(Self {
171 status: MacStatus::try_from(buf[0])?,
172 })
173 }
174}
175
176/// MLME SCAN Confirm which is used to report the result of the channel scan request
177#[cfg_attr(feature = "defmt", derive(defmt::Format))]
178pub struct ScanConfirm {
179 /// Status of the scan request
180 pub status: MacStatus,
181 /// The type of scan performed
182 pub scan_type: ScanType,
183 /// Channel page on which the scan was performed
184 pub channel_page: u8,
185 /// Channels given in the request which were not scanned
186 pub unscanned_channels: [u8; 4],
187 /// Number of elements returned in the appropriate result lists
188 pub result_list_size: u8,
189 /// List of energy measurements
190 pub energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED],
191 /// List of PAN descriptors
192 pub pan_descriptor_list: [PanDescriptor; MAX_PAN_DESC_SUPPORTED],
193 /// Categorization of energy detected in channel
194 pub detected_category: u8,
195 /// For UWB PHYs, the list of energy measurements taken
196 pub uwb_energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED],
197}
198
199impl ParseableMacEvent for ScanConfirm {
200 const SIZE: usize = 185;
201
202 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
203 // TODO: this is unchecked
204
205 Self::validate(buf)?;
206
207 let mut energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED];
208 energy_detect_list.copy_from_slice(&buf[8..24]);
209
210 let pan_descriptor_list = [
211 PanDescriptor::try_from(&buf[24..46])?,
212 PanDescriptor::try_from(&buf[46..68])?,
213 PanDescriptor::try_from(&buf[68..90])?,
214 PanDescriptor::try_from(&buf[90..102])?,
215 PanDescriptor::try_from(&buf[102..124])?,
216 PanDescriptor::try_from(&buf[124..146])?,
217 ];
218
219 let mut uwb_energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED];
220 uwb_energy_detect_list.copy_from_slice(&buf[147..163]);
221
222 Ok(Self {
223 status: MacStatus::try_from(buf[0])?,
224 scan_type: ScanType::try_from(buf[1])?,
225 channel_page: buf[2],
226 unscanned_channels: [buf[3], buf[4], buf[5], buf[6]],
227 result_list_size: buf[7],
228 energy_detect_list,
229 pan_descriptor_list,
230 detected_category: buf[146],
231 uwb_energy_detect_list,
232 })
233 }
234}
235
236/// MLME SET Confirm which reports the result of an attempt to write a value to a PIB attribute
237#[cfg_attr(feature = "defmt", derive(defmt::Format))]
238pub struct SetConfirm {
239 /// The result of the set operation
240 pub status: MacStatus,
241 /// The name of the PIB attribute that was written
242 pub pin_attribute: PibId,
243}
244
245impl ParseableMacEvent for SetConfirm {
246 const SIZE: usize = 4;
247
248 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
249 Self::validate(buf)?;
250
251 Ok(Self {
252 status: MacStatus::try_from(buf[0])?,
253 pin_attribute: PibId::try_from(buf[1])?,
254 })
255 }
256}
257
258/// MLME START Confirm which is used to report the results of the attempt to
259/// start using a new superframe configuration
260#[cfg_attr(feature = "defmt", derive(defmt::Format))]
261pub struct StartConfirm {
262 /// Result of the attempt to start using an updated superframe configuration
263 pub status: MacStatus,
264}
265
266impl ParseableMacEvent for StartConfirm {
267 const SIZE: usize = 4;
268
269 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
270 Self::validate(buf)?;
271
272 Ok(Self {
273 status: MacStatus::try_from(buf[0])?,
274 })
275 }
276}
277
278/// MLME POLL Confirm which is used to report the result of a request to poll the coordinator for data
279#[cfg_attr(feature = "defmt", derive(defmt::Format))]
280pub struct PollConfirm {
281 /// The status of the data request
282 pub status: MacStatus,
283}
284
285impl ParseableMacEvent for PollConfirm {
286 const SIZE: usize = 4;
287
288 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
289 Self::validate(buf)?;
290
291 Ok(Self {
292 status: MacStatus::try_from(buf[0])?,
293 })
294 }
295}
296
297/// MLME DPS Confirm which reports the results of the attempt to enable or disable the DPS
298#[cfg_attr(feature = "defmt", derive(defmt::Format))]
299pub struct DpsConfirm {
300 /// The status of the DPS request
301 pub status: MacStatus,
302}
303
304impl ParseableMacEvent for DpsConfirm {
305 const SIZE: usize = 4;
306
307 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
308 Self::validate(buf)?;
309
310 Ok(Self {
311 status: MacStatus::try_from(buf[0])?,
312 })
313 }
314}
315
316/// MLME SOUNDING Confirm which reports the result of a request to the PHY to provide
317/// channel sounding information
318#[cfg_attr(feature = "defmt", derive(defmt::Format))]
319pub struct SoundingConfirm {
320 /// Results of the sounding measurement
321 sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED],
322}
323
324impl ParseableMacEvent for SoundingConfirm {
325 const SIZE: usize = 1;
326
327 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
328 Self::validate(buf)?;
329
330 let mut sounding_list = [0u8; MAX_SOUNDING_LIST_SUPPORTED];
331 sounding_list[..buf.len()].copy_from_slice(buf);
332
333 Ok(Self { sounding_list })
334 }
335}
336
337/// MLME CALIBRATE Confirm which reports the result of a request to the PHY
338/// to provide internal propagation path information
339#[cfg_attr(feature = "defmt", derive(defmt::Format))]
340pub struct CalibrateConfirm {
341 /// The status of the attempt to return sounding data
342 pub status: MacStatus,
343 /// A count of the propagation time from the ranging counter
344 /// to the transmit antenna
345 pub cal_tx_rmaker_offset: u32,
346 /// A count of the propagation time from the receive antenna
347 /// to the ranging counter
348 pub cal_rx_rmaker_offset: u32,
349}
350
351impl ParseableMacEvent for CalibrateConfirm {
352 const SIZE: usize = 12;
353
354 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
355 Self::validate(buf)?;
356
357 Ok(Self {
358 status: MacStatus::try_from(buf[0])?,
359 // 3 byte stuffing
360 cal_tx_rmaker_offset: to_u32(&buf[4..8]),
361 cal_rx_rmaker_offset: to_u32(&buf[8..12]),
362 })
363 }
364}
365
366/// MCPS DATA Confirm which will be used for reporting the results of
367/// MAC data related requests from the application
368#[cfg_attr(feature = "defmt", derive(defmt::Format))]
369pub struct DataConfirm {
370 /// The handle associated with the MSDU being confirmed
371 pub msdu_handle: u8,
372 /// The time, in symbols, at which the data were transmitted
373 pub time_stamp: [u8; 4],
374 /// ranging status
375 pub ranging_received: u8,
376 /// The status of the last MSDU transmission
377 pub status: MacStatus,
378 /// time units corresponding to an RMARKER at the antenna at
379 /// the beginning of a ranging exchange
380 pub ranging_counter_start: u32,
381 /// time units corresponding to an RMARKER at the antenna
382 /// at the end of a ranging exchange
383 pub ranging_counter_stop: u32,
384 /// time units in a message exchange over which the tracking offset was measured
385 pub ranging_tracking_interval: u32,
386 /// time units slipped or advanced by the radio tracking system
387 pub ranging_offset: u32,
388 /// The FoM characterizing the ranging measurement
389 pub ranging_fom: u8,
390}
391
392impl ParseableMacEvent for DataConfirm {
393 const SIZE: usize = 28;
394
395 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
396 Self::validate(buf)?;
397
398 Ok(Self {
399 msdu_handle: buf[0],
400 time_stamp: [buf[1], buf[2], buf[3], buf[4]],
401 ranging_received: buf[5],
402 status: MacStatus::try_from(buf[6])?,
403 ranging_counter_start: to_u32(&buf[7..11]),
404 ranging_counter_stop: to_u32(&buf[11..15]),
405 ranging_tracking_interval: to_u32(&buf[15..19]),
406 ranging_offset: to_u32(&buf[19..23]),
407 ranging_fom: buf[24],
408 })
409 }
410}
411
412/// MCPS PURGE Confirm which will be used by the MAC to notify the application of
413/// the status of its request to purge an MSDU from the transaction queue
414#[cfg_attr(feature = "defmt", derive(defmt::Format))]
415pub struct PurgeConfirm {
416 /// Handle associated with the MSDU requested to be purged from the transaction queue
417 pub msdu_handle: u8,
418 /// The status of the request
419 pub status: MacStatus,
420}
421
422impl ParseableMacEvent for PurgeConfirm {
423 const SIZE: usize = 4;
424
425 fn try_parse(buf: &[u8]) -> Result<Self, ()> {
426 Self::validate(buf)?;
427
428 Ok(Self {
429 msdu_handle: buf[0],
430 status: MacStatus::try_from(buf[1])?,
431 })
432 }
433}
diff --git a/embassy-stm32-wpan/src/sub/mac/typedefs.rs b/embassy-stm32-wpan/src/sub/mac/typedefs.rs
new file mode 100644
index 000000000..30c7731b2
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac/typedefs.rs
@@ -0,0 +1,363 @@
1use crate::numeric_enum;
2
3#[derive(Debug)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
5pub enum MacError {
6 Error = 0x01,
7 NotImplemented = 0x02,
8 NotSupported = 0x03,
9 HardwareNotSupported = 0x04,
10 Undefined = 0x05,
11}
12
13impl From<u8> for MacError {
14 fn from(value: u8) -> Self {
15 match value {
16 0x01 => Self::Error,
17 0x02 => Self::NotImplemented,
18 0x03 => Self::NotSupported,
19 0x04 => Self::HardwareNotSupported,
20 0x05 => Self::Undefined,
21 _ => Self::Undefined,
22 }
23 }
24}
25
26numeric_enum! {
27 #[repr(u8)]
28 #[derive(Debug, Default)]
29 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
30 pub enum MacStatus {
31 #[default]
32 Success = 0x00,
33 Failure = 0xFF
34 }
35}
36
37numeric_enum! {
38 #[repr(u8)]
39 /// this enum contains all the MAC PIB Ids
40 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
41 pub enum PibId {
42 // PHY
43 CurrentChannel = 0x00,
44 ChannelsSupported = 0x01,
45 TransmitPower = 0x02,
46 CCAMode = 0x03,
47 CurrentPage = 0x04,
48 MaxFrameDuration = 0x05,
49 SHRDuration = 0x06,
50 SymbolsPerOctet = 0x07,
51
52 // MAC
53 AckWaitDuration = 0x40,
54 AssociationPermit = 0x41,
55 AutoRequest = 0x42,
56 BeaconPayload = 0x45,
57 BeaconPayloadLength = 0x46,
58 BeaconOrder = 0x47,
59 Bsn = 0x49,
60 CoordExtendedAdddress = 0x4A,
61 CoordShortAddress = 0x4B,
62 Dsn = 0x4C,
63 MaxFrameTotalWaitTime = 0x58,
64 MaxFrameRetries = 0x59,
65 PanId = 0x50,
66 ResponseWaitTime = 0x5A,
67 RxOnWhenIdle = 0x52,
68 SecurityEnabled = 0x5D,
69 ShortAddress = 0x53,
70 SuperframeOrder = 0x54,
71 TimestampSupported = 0x5C,
72 TransactionPersistenceTime = 0x55,
73 MaxBe = 0x57,
74 LifsPeriod = 0x5E,
75 SifsPeriod = 0x5F,
76 MaxCsmaBackoffs = 0x4E,
77 MinBe = 0x4F,
78 PanCoordinator = 0x10,
79 AssocPanCoordinator = 0x11,
80 ExtendedAddress = 0x6F,
81 AclEntryDescriptor = 0x70,
82 AclEntryDescriptorSize = 0x71,
83 DefaultSecurity = 0x72,
84 DefaultSecurityMaterialLength = 0x73,
85 DefaultSecurityMaterial = 0x74,
86 DefaultSecuritySuite = 0x75,
87 SecurityMode = 0x76,
88 CurrentAclEntries = 0x80,
89 DefaultSecurityExtendedAddress = 0x81,
90 AssociatedPanCoordinator = 0x56,
91 PromiscuousMode = 0x51,
92 }
93}
94
95numeric_enum! {
96 #[repr(u8)]
97 #[derive(Default, Clone, Copy)]
98 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
99 pub enum AddressMode {
100 #[default]
101 NoAddress = 0x00,
102 Reserved = 0x01,
103 Short = 0x02,
104 Extended = 0x03,
105}
106}
107
108#[derive(Clone, Copy)]
109pub union MacAddress {
110 pub short: [u8; 2],
111 pub extended: [u8; 8],
112}
113
114#[cfg(feature = "defmt")]
115impl defmt::Format for MacAddress {
116 fn format(&self, fmt: defmt::Formatter) {
117 unsafe {
118 defmt::write!(
119 fmt,
120 "MacAddress {{ short: {}, extended: {} }}",
121 self.short,
122 self.extended
123 )
124 }
125 }
126}
127
128impl Default for MacAddress {
129 fn default() -> Self {
130 Self { short: [0, 0] }
131 }
132}
133
134impl MacAddress {
135 pub const BROADCAST: Self = Self { short: [0xFF, 0xFF] };
136}
137
138impl TryFrom<&[u8]> for MacAddress {
139 type Error = ();
140
141 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
142 const SIZE: usize = 8;
143 if buf.len() < SIZE {
144 return Err(());
145 }
146
147 Ok(Self {
148 extended: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
149 })
150 }
151}
152
153#[cfg_attr(feature = "defmt", derive(defmt::Format))]
154pub struct GtsCharacteristics {
155 pub fields: u8,
156}
157
158/// MAC PAN Descriptor which contains the network details of the device from
159/// which the beacon is received
160#[derive(Default, Clone, Copy)]
161#[cfg_attr(feature = "defmt", derive(defmt::Format))]
162pub struct PanDescriptor {
163 /// PAN identifier of the coordinator
164 pub coord_pan_id: PanId,
165 /// Coordinator addressing mode
166 pub coord_addr_mode: AddressMode,
167 /// The current logical channel occupied by the network
168 pub logical_channel: MacChannel,
169 /// Coordinator address
170 pub coord_addr: MacAddress,
171 /// The current channel page occupied by the network
172 pub channel_page: u8,
173 /// PAN coordinator is accepting GTS requests or not
174 pub gts_permit: bool,
175 /// Superframe specification as specified in the received beacon frame
176 pub superframe_spec: [u8; 2],
177 /// The time at which the beacon frame was received, in symbols
178 pub time_stamp: [u8; 4],
179 /// The LQI at which the network beacon was received
180 pub link_quality: u8,
181 /// Security level purportedly used by the received beacon frame
182 pub security_level: u8,
183}
184
185impl TryFrom<&[u8]> for PanDescriptor {
186 type Error = ();
187
188 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
189 const SIZE: usize = 22;
190 if buf.len() < SIZE {
191 return Err(());
192 }
193
194 let coord_addr_mode = AddressMode::try_from(buf[2])?;
195 let coord_addr = match coord_addr_mode {
196 AddressMode::NoAddress => MacAddress { short: [0, 0] },
197 AddressMode::Reserved => MacAddress { short: [0, 0] },
198 AddressMode::Short => MacAddress {
199 short: [buf[4], buf[5]],
200 },
201 AddressMode::Extended => MacAddress {
202 extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
203 },
204 };
205
206 Ok(Self {
207 coord_pan_id: PanId([buf[0], buf[1]]),
208 coord_addr_mode,
209 logical_channel: MacChannel::try_from(buf[3])?,
210 coord_addr,
211 channel_page: buf[12],
212 gts_permit: buf[13] != 0,
213 superframe_spec: [buf[14], buf[15]],
214 time_stamp: [buf[16], buf[17], buf[18], buf[19]],
215 link_quality: buf[20],
216 security_level: buf[21],
217 // 2 byte stuffing
218 })
219 }
220}
221
222numeric_enum! {
223 #[repr(u8)]
224 #[derive(Default, Clone, Copy)]
225 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
226 /// Building wireless applications with STM32WB series MCUs - Application note 13.10.3
227 pub enum MacChannel {
228 Channel11 = 0x0B,
229 Channel12 = 0x0C,
230 Channel13 = 0x0D,
231 Channel14 = 0x0E,
232 Channel15 = 0x0F,
233 #[default]
234 Channel16 = 0x10,
235 Channel17 = 0x11,
236 Channel18 = 0x12,
237 Channel19 = 0x13,
238 Channel20 = 0x14,
239 Channel21 = 0x15,
240 Channel22 = 0x16,
241 Channel23 = 0x17,
242 Channel24 = 0x18,
243 Channel25 = 0x19,
244 Channel26 = 0x1A,
245 }
246}
247
248#[cfg(not(feature = "defmt"))]
249bitflags::bitflags! {
250 pub struct Capabilities: u8 {
251 /// 1 if the device is capabaleof becoming a PAN coordinator
252 const IS_COORDINATOR_CAPABLE = 0b00000001;
253 /// 1 if the device is an FFD, 0 if it is an RFD
254 const IS_FFD = 0b00000010;
255 /// 1 if the device is receiving power from mains, 0 if it is battery-powered
256 const IS_MAINS_POWERED = 0b00000100;
257 /// 1 if the device does not disable its receiver to conserver power during idle periods
258 const RECEIVER_ON_WHEN_IDLE = 0b00001000;
259 // 0b00010000 reserved
260 // 0b00100000 reserved
261 /// 1 if the device is capable of sending and receiving secured MAC frames
262 const IS_SECURE = 0b01000000;
263 /// 1 if the device wishes the coordinator to allocate a short address as a result of the association
264 const ALLOCATE_ADDRESS = 0b10000000;
265 }
266}
267
268#[cfg(feature = "defmt")]
269defmt::bitflags! {
270 pub struct Capabilities: u8 {
271 /// 1 if the device is capabaleof becoming a PAN coordinator
272 const IS_COORDINATOR_CAPABLE = 0b00000001;
273 /// 1 if the device is an FFD, 0 if it is an RFD
274 const IS_FFD = 0b00000010;
275 /// 1 if the device is receiving power from mains, 0 if it is battery-powered
276 const IS_MAINS_POWERED = 0b00000100;
277 /// 1 if the device does not disable its receiver to conserver power during idle periods
278 const RECEIVER_ON_WHEN_IDLE = 0b00001000;
279 // 0b00010000 reserved
280 // 0b00100000 reserved
281 /// 1 if the device is capable of sending and receiving secured MAC frames
282 const IS_SECURE = 0b01000000;
283 /// 1 if the device wishes the coordinator to allocate a short address as a result of the association
284 const ALLOCATE_ADDRESS = 0b10000000;
285 }
286}
287
288numeric_enum! {
289 #[repr(u8)]
290 #[derive(Default, Clone, Copy)]
291 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
292 pub enum KeyIdMode {
293 #[default]
294 /// the key is determined implicitly from the originator and recipient(s) of the frame
295 Implicite = 0x00,
296 /// the key is determined explicitly using a 1 bytes key source and a 1 byte key index
297 Explicite1Byte = 0x01,
298 /// the key is determined explicitly using a 4 bytes key source and a 1 byte key index
299 Explicite4Byte = 0x02,
300 /// the key is determined explicitly using a 8 bytes key source and a 1 byte key index
301 Explicite8Byte = 0x03,
302 }
303}
304
305numeric_enum! {
306 #[repr(u8)]
307 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
308 pub enum AssociationStatus {
309 /// Association successful
310 Success = 0x00,
311 /// PAN at capacity
312 PanAtCapacity = 0x01,
313 /// PAN access denied
314 PanAccessDenied = 0x02
315 }
316}
317
318numeric_enum! {
319 #[repr(u8)]
320 #[derive(Clone, Copy)]
321 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
322 pub enum DisassociationReason {
323 /// The coordinator wishes the device to leave the PAN.
324 CoordRequested = 0x01,
325 /// The device wishes to leave the PAN.
326 DeviceRequested = 0x02,
327 }
328}
329
330numeric_enum! {
331 #[repr(u8)]
332 #[derive(Default, Clone, Copy)]
333 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
334 pub enum SecurityLevel {
335 /// MAC Unsecured Mode Security
336 #[default]
337 Unsecure = 0x00,
338 /// MAC ACL Mode Security
339 AclMode = 0x01,
340 /// MAC Secured Mode Security
341 Secured = 0x02,
342 }
343}
344
345numeric_enum! {
346 #[repr(u8)]
347 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
348 pub enum ScanType {
349 EdScan = 0x00,
350 Active = 0x01,
351 Passive = 0x02,
352 Orphan = 0x03
353 }
354}
355
356/// newtype for Pan Id
357#[derive(Default, Clone, Copy)]
358#[cfg_attr(feature = "defmt", derive(defmt::Format))]
359pub struct PanId(pub [u8; 2]);
360
361impl PanId {
362 pub const BROADCAST: Self = Self([0xFF, 0xFF]);
363}
diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs
index caa4845f2..c17fd531d 100644
--- a/embassy-stm32-wpan/src/sub/sys.rs
+++ b/embassy-stm32-wpan/src/sub/sys.rs
@@ -50,7 +50,7 @@ impl Sys {
50 } 50 }
51 51
52 /// `HW_IPCC_SYS_CmdEvtNot` 52 /// `HW_IPCC_SYS_CmdEvtNot`
53 pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> SchiCommandStatus { 53 pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> Result<SchiCommandStatus, ()> {
54 self.write(opcode, payload).await; 54 self.write(opcode, payload).await;
55 Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await; 55 Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
56 56
@@ -59,12 +59,12 @@ impl Sys {
59 let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt; 59 let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt;
60 let p_payload = &((*p_command_event).payload) as *const u8; 60 let p_payload = &((*p_command_event).payload) as *const u8;
61 61
62 ptr::read_volatile(p_payload).try_into().unwrap() 62 ptr::read_volatile(p_payload).try_into()
63 } 63 }
64 } 64 }
65 65
66 #[cfg(feature = "mac")] 66 #[cfg(feature = "mac")]
67 pub async fn shci_c2_mac_802_15_4_init(&self) -> SchiCommandStatus { 67 pub async fn shci_c2_mac_802_15_4_init(&self) -> Result<SchiCommandStatus, ()> {
68 use crate::tables::{ 68 use crate::tables::{
69 Mac802_15_4Table, TracesTable, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, 69 Mac802_15_4Table, TracesTable, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER,
70 TL_MAC_802_15_4_TABLE, TL_TRACES_TABLE, TRACES_EVT_QUEUE, 70 TL_MAC_802_15_4_TABLE, TL_TRACES_TABLE, TRACES_EVT_QUEUE,
@@ -88,7 +88,7 @@ impl Sys {
88 } 88 }
89 89
90 #[cfg(feature = "ble")] 90 #[cfg(feature = "ble")]
91 pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> SchiCommandStatus { 91 pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result<SchiCommandStatus, ()> {
92 self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await 92 self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
93 } 93 }
94 94
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml
index 8b6d6d754..51c499ee7 100644
--- a/examples/stm32wb/.cargo/config.toml
+++ b/examples/stm32wb/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list` 2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
3# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" 3# runner = "probe-run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
4runner = "teleprobe local run --chip STM32WB55RG --elf" 4runner = "teleprobe local run --chip STM32WB55RG --elf"
5 5
6[build] 6[build]
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index d8d5f0ec7..becf2d3fb 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -23,7 +23,7 @@ heapless = { version = "0.7.5", default-features = false }
23 23
24 24
25[features] 25[features]
26default = ["ble"] 26default = ["ble", "mac"]
27mac = ["embassy-stm32-wpan/mac"] 27mac = ["embassy-stm32-wpan/mac"]
28ble = ["embassy-stm32-wpan/ble"] 28ble = ["embassy-stm32-wpan/ble"]
29 29
@@ -36,6 +36,10 @@ name = "tl_mbox_mac"
36required-features = ["mac"] 36required-features = ["mac"]
37 37
38[[bin]] 38[[bin]]
39name = "mac_ffd"
40required-features = ["mac"]
41
42[[bin]]
39name = "eddystone_beacon" 43name = "eddystone_beacon"
40required-features = ["ble"] 44required-features = ["ble"]
41 45
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
index b99f8cb2e..451bd7d29 100644
--- a/examples/stm32wb/src/bin/eddystone_beacon.rs
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) {
63 let sys_event = mbox.sys_subsystem.read().await; 63 let sys_event = mbox.sys_subsystem.read().await;
64 info!("sys event: {}", sys_event.payload()); 64 info!("sys event: {}", sys_event.payload());
65 65
66 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; 66 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
67 67
68 info!("resetting BLE..."); 68 info!("resetting BLE...");
69 mbox.ble_subsystem.reset().await; 69 mbox.ble_subsystem.reset().await;
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs
index 7621efb11..0f6419d45 100644
--- a/examples/stm32wb/src/bin/gatt_server.rs
+++ b/examples/stm32wb/src/bin/gatt_server.rs
@@ -71,7 +71,7 @@ async fn main(_spawner: Spawner) {
71 let sys_event = mbox.sys_subsystem.read().await; 71 let sys_event = mbox.sys_subsystem.read().await;
72 info!("sys event: {}", sys_event.payload()); 72 info!("sys event: {}", sys_event.payload());
73 73
74 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; 74 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
75 75
76 info!("resetting BLE..."); 76 info!("resetting BLE...");
77 mbox.ble_subsystem.reset().await; 77 mbox.ble_subsystem.reset().await;
diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs
new file mode 100644
index 000000000..689a28353
--- /dev/null
+++ b/examples/stm32wb/src/bin/mac_ffd.rs
@@ -0,0 +1,183 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::sub::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest};
10use embassy_stm32_wpan::sub::mac::event::MacEvent;
11use embassy_stm32_wpan::sub::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel};
12use embassy_stm32_wpan::sub::mm;
13use embassy_stm32_wpan::TlMbox;
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs{
17 IPCC_C1_RX => ReceiveInterruptHandler;
18 IPCC_C1_TX => TransmitInterruptHandler;
19});
20
21#[embassy_executor::task]
22async fn run_mm_queue(memory_manager: mm::MemoryManager) {
23 memory_manager.run_queue().await;
24}
25
26#[embassy_executor::main]
27async fn main(spawner: Spawner) {
28 /*
29 How to make this work:
30
31 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
32 - Download and Install STM32CubeProgrammer.
33 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
34 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
35 - Open STM32CubeProgrammer
36 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
37 - Once complete, click connect to connect to the device.
38 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
39 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
40 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
41 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
42 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
43 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
44 - Select "Start Wireless Stack".
45 - Disconnect from the device.
46 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
47 - Run this example.
48
49 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
50 */
51
52 let p = embassy_stm32::init(Default::default());
53 info!("Hello World!");
54
55 let config = Config::default();
56 let mbox = TlMbox::init(p.IPCC, Irqs, config);
57
58 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
59
60 let sys_event = mbox.sys_subsystem.read().await;
61 info!("sys event: {}", sys_event.payload());
62
63 core::mem::drop(sys_event);
64
65 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
66 info!("initialized mac: {}", result);
67
68 info!("resetting");
69 mbox.mac_subsystem
70 .send_command(&ResetRequest { set_default_pib: true })
71 .await
72 .unwrap();
73 let evt = mbox.mac_subsystem.read().await;
74 defmt::info!("{:#x}", evt);
75
76 info!("setting extended address");
77 let extended_address: u64 = 0xACDE480000000001;
78 mbox.mac_subsystem
79 .send_command(&SetRequest {
80 pib_attribute_ptr: &extended_address as *const _ as *const u8,
81 pib_attribute: PibId::ExtendedAddress,
82 })
83 .await
84 .unwrap();
85 let evt = mbox.mac_subsystem.read().await;
86 defmt::info!("{:#x}", evt);
87
88 info!("setting short address");
89 let short_address: u16 = 0x1122;
90 mbox.mac_subsystem
91 .send_command(&SetRequest {
92 pib_attribute_ptr: &short_address as *const _ as *const u8,
93 pib_attribute: PibId::ShortAddress,
94 })
95 .await
96 .unwrap();
97 let evt = mbox.mac_subsystem.read().await;
98 defmt::info!("{:#x}", evt);
99
100 info!("setting association permit");
101 let association_permit: bool = true;
102 mbox.mac_subsystem
103 .send_command(&SetRequest {
104 pib_attribute_ptr: &association_permit as *const _ as *const u8,
105 pib_attribute: PibId::AssociationPermit,
106 })
107 .await
108 .unwrap();
109 let evt = mbox.mac_subsystem.read().await;
110 defmt::info!("{:#x}", evt);
111
112 info!("setting TX power");
113 let transmit_power: i8 = 2;
114 mbox.mac_subsystem
115 .send_command(&SetRequest {
116 pib_attribute_ptr: &transmit_power as *const _ as *const u8,
117 pib_attribute: PibId::TransmitPower,
118 })
119 .await
120 .unwrap();
121 let evt = mbox.mac_subsystem.read().await;
122 defmt::info!("{:#x}", evt);
123
124 info!("starting FFD device");
125 mbox.mac_subsystem
126 .send_command(&StartRequest {
127 pan_id: PanId([0x1A, 0xAA]),
128 channel_number: MacChannel::Channel16,
129 beacon_order: 0x0F,
130 superframe_order: 0x0F,
131 pan_coordinator: true,
132 battery_life_extension: false,
133 ..Default::default()
134 })
135 .await
136 .unwrap();
137 let evt = mbox.mac_subsystem.read().await;
138 defmt::info!("{:#x}", evt);
139
140 info!("setting RX on when idle");
141 let rx_on_while_idle: bool = true;
142 mbox.mac_subsystem
143 .send_command(&SetRequest {
144 pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8,
145 pib_attribute: PibId::RxOnWhenIdle,
146 })
147 .await
148 .unwrap();
149 let evt = mbox.mac_subsystem.read().await;
150 defmt::info!("{:#x}", evt);
151
152 loop {
153 let evt = mbox.mac_subsystem.read().await;
154 defmt::info!("{:#x}", evt);
155
156 if let Ok(evt) = evt {
157 match evt {
158 MacEvent::MlmeAssociateInd(association) => mbox
159 .mac_subsystem
160 .send_command(&AssociateResponse {
161 device_address: association.device_address,
162 assoc_short_address: [0x33, 0x44],
163 status: MacStatus::Success,
164 security_level: SecurityLevel::Unsecure,
165 ..Default::default()
166 })
167 .await
168 .unwrap(),
169 MacEvent::McpsDataInd(data_ind) => {
170 let data_addr = data_ind.msdu_ptr;
171 let mut data = [0u8; 256];
172 unsafe { data_addr.copy_to(&mut data as *mut _, data_ind.msdu_length as usize) }
173 info!("{}", data[..data_ind.msdu_length as usize]);
174
175 if &data[..data_ind.msdu_length as usize] == b"Hello from embassy!" {
176 info!("success");
177 }
178 }
179 _ => {}
180 }
181 }
182 }
183}
diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs
new file mode 100644
index 000000000..ea349f9a8
--- /dev/null
+++ b/examples/stm32wb/src/bin/mac_rfd.rs
@@ -0,0 +1,170 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::sub::mac::commands::{AssociateRequest, DataRequest, GetRequest, ResetRequest, SetRequest};
10use embassy_stm32_wpan::sub::mac::event::MacEvent;
11use embassy_stm32_wpan::sub::mac::typedefs::{
12 AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel,
13};
14use embassy_stm32_wpan::sub::mm;
15use embassy_stm32_wpan::TlMbox;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs{
19 IPCC_C1_RX => ReceiveInterruptHandler;
20 IPCC_C1_TX => TransmitInterruptHandler;
21});
22
23#[embassy_executor::task]
24async fn run_mm_queue(memory_manager: mm::MemoryManager) {
25 memory_manager.run_queue().await;
26}
27
28#[embassy_executor::main]
29async fn main(spawner: Spawner) {
30 /*
31 How to make this work:
32
33 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
34 - Download and Install STM32CubeProgrammer.
35 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
36 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
37 - Open STM32CubeProgrammer
38 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
39 - Once complete, click connect to connect to the device.
40 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
41 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
42 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
43 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
44 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
45 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
46 - Select "Start Wireless Stack".
47 - Disconnect from the device.
48 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
49 - Run this example.
50
51 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
52 */
53
54 let p = embassy_stm32::init(Default::default());
55 info!("Hello World!");
56
57 let config = Config::default();
58 let mbox = TlMbox::init(p.IPCC, Irqs, config);
59
60 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
61
62 let sys_event = mbox.sys_subsystem.read().await;
63 info!("sys event: {}", sys_event.payload());
64
65 core::mem::drop(sys_event);
66
67 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
68 info!("initialized mac: {}", result);
69
70 info!("resetting");
71 mbox.mac_subsystem
72 .send_command(&ResetRequest { set_default_pib: true })
73 .await
74 .unwrap();
75 let evt = mbox.mac_subsystem.read().await;
76 info!("{:#x}", evt);
77
78 info!("setting extended address");
79 let extended_address: u64 = 0xACDE480000000002;
80 mbox.mac_subsystem
81 .send_command(&SetRequest {
82 pib_attribute_ptr: &extended_address as *const _ as *const u8,
83 pib_attribute: PibId::ExtendedAddress,
84 })
85 .await
86 .unwrap();
87 let evt = mbox.mac_subsystem.read().await;
88 info!("{:#x}", evt);
89
90 info!("getting extended address");
91 mbox.mac_subsystem
92 .send_command(&GetRequest {
93 pib_attribute: PibId::ExtendedAddress,
94 })
95 .await
96 .unwrap();
97 let evt = mbox.mac_subsystem.read().await;
98 info!("{:#x}", evt);
99
100 if let Ok(MacEvent::MlmeGetCnf(evt)) = evt {
101 if evt.pib_attribute_value_len == 8 {
102 let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
103
104 info!("value {:#x}", value)
105 }
106 }
107
108 info!("assocation request");
109 let a = AssociateRequest {
110 channel_number: MacChannel::Channel16,
111 channel_page: 0,
112 coord_addr_mode: AddressMode::Short,
113 coord_address: MacAddress { short: [34, 17] },
114 capability_information: Capabilities::ALLOCATE_ADDRESS,
115 coord_pan_id: PanId([0x1A, 0xAA]),
116 security_level: SecurityLevel::Unsecure,
117 key_id_mode: KeyIdMode::Implicite,
118 key_source: [0; 8],
119 key_index: 152,
120 };
121 info!("{}", a);
122 mbox.mac_subsystem.send_command(&a).await.unwrap();
123 let evt = mbox.mac_subsystem.read().await;
124 info!("{:#x}", evt);
125
126 let short_addr = if let Ok(MacEvent::MlmeAssociateCnf(conf)) = evt {
127 conf.assoc_short_address
128 } else {
129 defmt::panic!()
130 };
131
132 info!("setting short address");
133 mbox.mac_subsystem
134 .send_command(&SetRequest {
135 pib_attribute_ptr: &short_addr as *const _ as *const u8,
136 pib_attribute: PibId::ShortAddress,
137 })
138 .await
139 .unwrap();
140 let evt = mbox.mac_subsystem.read().await;
141 info!("{:#x}", evt);
142
143 info!("sending data");
144 let mut data_buffer = [0u8; 256];
145 let data = b"Hello from embassy!";
146 data_buffer[..data.len()].copy_from_slice(data);
147 mbox.mac_subsystem
148 .send_command(&DataRequest {
149 src_addr_mode: AddressMode::Short,
150 dst_addr_mode: AddressMode::Short,
151 dst_pan_id: PanId([0x1A, 0xAA]),
152 dst_address: MacAddress::BROADCAST,
153 msdu_handle: 0x02,
154 ack_tx: 0x00,
155 gts_tx: false,
156 msdu_ptr: &data_buffer as *const _ as *const u8,
157 msdu_length: data.len() as u8,
158 security_level: SecurityLevel::Unsecure,
159 ..Default::default()
160 })
161 .await
162 .unwrap();
163 let evt = mbox.mac_subsystem.read().await;
164 info!("{:#x}", evt);
165
166 loop {
167 let evt = mbox.mac_subsystem.read().await;
168 info!("{:#x}", evt);
169 }
170}
diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs
index a511e89aa..90349422e 100644
--- a/examples/stm32wb/src/bin/tl_mbox_ble.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs
@@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) {
49 let sys_event = mbox.sys_subsystem.read().await; 49 let sys_event = mbox.sys_subsystem.read().await;
50 info!("sys event: {}", sys_event.payload()); 50 info!("sys event: {}", sys_event.payload());
51 51
52 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; 52 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
53 53
54 info!("starting ble..."); 54 info!("starting ble...");
55 mbox.ble_subsystem.tl_write(0x0c, &[]).await; 55 mbox.ble_subsystem.tl_write(0x0c, &[]).await;
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 5db74c7a9..179ed1d6a 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -11,4 +11,4 @@ targets = [
11 "thumbv8m.main-none-eabihf", 11 "thumbv8m.main-none-eabihf",
12 "riscv32imac-unknown-none-elf", 12 "riscv32imac-unknown-none-elf",
13 "wasm32-unknown-unknown", 13 "wasm32-unknown-unknown",
14] 14] \ No newline at end of file
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index d94bd730b..3007cd1e6 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -12,14 +12,16 @@ stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo
12stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo 12stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
13stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo 13stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo
14stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo 14stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo
15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble" ] # Nucleo 15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo
16stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo 16stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
17stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board 17stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
18 18
19sdmmc = [] 19sdmmc = []
20chrono = ["embassy-stm32/chrono", "dep:chrono"] 20chrono = ["embassy-stm32/chrono", "dep:chrono"]
21can = [] 21can = []
22ble = ["dep:embassy-stm32-wpan"] 22ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
23mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
24embassy-stm32-wpan = []
23not-gpdma = [] 25not-gpdma = []
24 26
25[dependencies] 27[dependencies]
@@ -49,11 +51,6 @@ chrono = { version = "^0.4", default-features = false, optional = true}
49# BEGIN TESTS 51# BEGIN TESTS
50# Generated by gen_test.py. DO NOT EDIT. 52# Generated by gen_test.py. DO NOT EDIT.
51[[bin]] 53[[bin]]
52name = "tl_mbox"
53path = "src/bin/tl_mbox.rs"
54required-features = [ "ble",]
55
56[[bin]]
57name = "can" 54name = "can"
58path = "src/bin/can.rs" 55path = "src/bin/can.rs"
59required-features = [ "can",] 56required-features = [ "can",]
@@ -103,6 +100,16 @@ name = "usart_rx_ringbuffered"
103path = "src/bin/usart_rx_ringbuffered.rs" 100path = "src/bin/usart_rx_ringbuffered.rs"
104required-features = [ "not-gpdma",] 101required-features = [ "not-gpdma",]
105 102
103[[bin]]
104name = "wpan_ble"
105path = "src/bin/wpan_ble.rs"
106required-features = [ "ble",]
107
108[[bin]]
109name = "wpan_mac"
110path = "src/bin/wpan_mac.rs"
111required-features = [ "mac",]
112
106# END TESTS 113# END TESTS
107 114
108[profile.dev] 115[profile.dev]
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs
index 582df5753..194b153d5 100644
--- a/tests/stm32/src/bin/rtc.rs
+++ b/tests/stm32/src/bin/rtc.rs
@@ -1,3 +1,5 @@
1// required-features: chrono
2
1#![no_std] 3#![no_std]
2#![no_main] 4#![no_main]
3#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/wpan_ble.rs
index af3832709..3ad8aca4e 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/wpan_ble.rs
@@ -64,7 +64,7 @@ async fn main(spawner: Spawner) {
64 version_major, version_minor, subversion, sram2a_size, sram2b_size 64 version_major, version_minor, subversion, sram2a_size, sram2b_size
65 ); 65 );
66 66
67 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; 67 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
68 68
69 info!("resetting BLE..."); 69 info!("resetting BLE...");
70 mbox.ble_subsystem.reset().await; 70 mbox.ble_subsystem.reset().await;
diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs
new file mode 100644
index 000000000..d97a4d404
--- /dev/null
+++ b/tests/stm32/src/bin/wpan_mac.rs
@@ -0,0 +1,108 @@
1// required-features: mac
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"]
7mod common;
8
9use common::*;
10use embassy_executor::Spawner;
11use embassy_stm32::bind_interrupts;
12use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
13use embassy_stm32_wpan::sub::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest};
14use embassy_stm32_wpan::sub::mac::event::MacEvent;
15use embassy_stm32_wpan::sub::mac::typedefs::{
16 AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel,
17};
18use embassy_stm32_wpan::sub::mm;
19use embassy_stm32_wpan::TlMbox;
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(struct Irqs{
23 IPCC_C1_RX => ReceiveInterruptHandler;
24 IPCC_C1_TX => TransmitInterruptHandler;
25});
26
27#[embassy_executor::task]
28async fn run_mm_queue(memory_manager: mm::MemoryManager) {
29 memory_manager.run_queue().await;
30}
31
32#[embassy_executor::main]
33async fn main(spawner: Spawner) {
34 let p = embassy_stm32::init(config());
35 info!("Hello World!");
36
37 let config = Config::default();
38 let mbox = TlMbox::init(p.IPCC, Irqs, config);
39
40 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
41
42 let sys_event = mbox.sys_subsystem.read().await;
43 info!("sys event: {}", sys_event.payload());
44
45 core::mem::drop(sys_event);
46
47 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
48 info!("initialized mac: {}", result);
49
50 info!("resetting");
51 mbox.mac_subsystem
52 .send_command(&ResetRequest { set_default_pib: true })
53 .await
54 .unwrap();
55 let evt = mbox.mac_subsystem.read().await;
56 info!("{:#x}", evt);
57
58 info!("setting extended address");
59 let extended_address: u64 = 0xACDE480000000002;
60 mbox.mac_subsystem
61 .send_command(&SetRequest {
62 pib_attribute_ptr: &extended_address as *const _ as *const u8,
63 pib_attribute: PibId::ExtendedAddress,
64 })
65 .await
66 .unwrap();
67 let evt = mbox.mac_subsystem.read().await;
68 info!("{:#x}", evt);
69
70 info!("getting extended address");
71 mbox.mac_subsystem
72 .send_command(&GetRequest {
73 pib_attribute: PibId::ExtendedAddress,
74 })
75 .await
76 .unwrap();
77 let evt = mbox.mac_subsystem.read().await;
78 info!("{:#x}", evt);
79
80 if let Ok(MacEvent::MlmeGetCnf(evt)) = evt {
81 if evt.pib_attribute_value_len == 8 {
82 let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
83
84 info!("value {:#x}", value)
85 }
86 }
87
88 info!("assocation request");
89 let a = AssociateRequest {
90 channel_number: MacChannel::Channel16,
91 channel_page: 0,
92 coord_addr_mode: AddressMode::Short,
93 coord_address: MacAddress { short: [34, 17] },
94 capability_information: Capabilities::ALLOCATE_ADDRESS,
95 coord_pan_id: PanId([0x1A, 0xAA]),
96 security_level: SecurityLevel::Unsecure,
97 key_id_mode: KeyIdMode::Implicite,
98 key_source: [0; 8],
99 key_index: 152,
100 };
101 info!("{}", a);
102 mbox.mac_subsystem.send_command(&a).await.unwrap();
103 let evt = mbox.mac_subsystem.read().await;
104 info!("{:#x}", evt);
105
106 info!("Test OK");
107 cortex_m::asm::bkpt();
108}