diff options
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" | |||
| 26 | bit_field = "0.10.2" | 26 | bit_field = "0.10.2" |
| 27 | stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } | 27 | stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } |
| 28 | stm32wb-hci = { version = "0.1.3", optional = true } | 28 | stm32wb-hci = { version = "0.1.3", optional = true } |
| 29 | bitflags = { version = "2.3.3", optional = true } | ||
| 29 | 30 | ||
| 30 | [features] | 31 | [features] |
| 31 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"] | 32 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"] |
| 32 | 33 | ||
| 33 | ble = ["dep:stm32wb-hci"] | 34 | ble = ["dep:stm32wb-hci"] |
| 34 | mac = [] | 35 | mac = ["dep:bitflags"] |
| 35 | 36 | ||
| 36 | stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] | 37 | stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] |
| 37 | stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] | 38 | stm32wb15cc = [ "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)] |
| 8 | pub enum TlPacketType { | 8 | pub 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 @@ | |||
| 1 | use super::opcodes::OpcodeM4ToM0; | ||
| 2 | use super::typedefs::{ | ||
| 3 | AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus, | ||
| 4 | PanId, PibId, ScanType, SecurityLevel, | ||
| 5 | }; | ||
| 6 | |||
| 7 | pub 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))] | ||
| 19 | pub 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 | |||
| 42 | impl 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))] | ||
| 50 | pub 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 | |||
| 71 | impl 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))] | ||
| 79 | pub struct GetRequest { | ||
| 80 | /// the name of the PIB attribute to read | ||
| 81 | pub pib_attribute: PibId, | ||
| 82 | } | ||
| 83 | |||
| 84 | impl 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))] | ||
| 92 | pub 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 | |||
| 105 | impl 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))] | ||
| 112 | pub struct ResetRequest { | ||
| 113 | /// MAC PIB attributes are set to their default values or not during reset | ||
| 114 | pub set_default_pib: bool, | ||
| 115 | } | ||
| 116 | |||
| 117 | impl 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))] | ||
| 126 | pub 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 | |||
| 138 | impl 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))] | ||
| 158 | pub 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 | |||
| 177 | impl 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))] | ||
| 185 | pub 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 | |||
| 192 | impl 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))] | ||
| 202 | pub 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 | |||
| 237 | impl 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))] | ||
| 246 | pub 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 | |||
| 258 | impl 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))] | ||
| 266 | pub 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 | |||
| 283 | impl 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))] | ||
| 292 | pub 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 | |||
| 302 | impl 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))] | ||
| 311 | pub struct SoundingRequest; | ||
| 312 | |||
| 313 | impl 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))] | ||
| 322 | pub struct CalibrateRequest; | ||
| 323 | |||
| 324 | impl 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))] | ||
| 332 | pub 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 | |||
| 373 | impl 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 | |||
| 398 | impl 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))] | ||
| 406 | pub struct PurgeRequest { | ||
| 407 | /// the handle associated with the MSDU to be purged from the transaction | ||
| 408 | /// queue | ||
| 409 | pub msdu_handle: u8, | ||
| 410 | } | ||
| 411 | |||
| 412 | impl 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))] | ||
| 421 | pub 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 | |||
| 439 | impl 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))] | ||
| 447 | pub 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 | |||
| 464 | impl 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 @@ | |||
| 1 | pub const MAX_PAN_DESC_SUPPORTED: usize = 6; | ||
| 2 | pub const MAX_SOUNDING_LIST_SUPPORTED: usize = 6; | ||
| 3 | pub const MAX_PENDING_ADDRESS: usize = 7; | ||
| 4 | pub const MAX_ED_SCAN_RESULTS_SUPPORTED: usize = 16; | ||
diff --git a/embassy-stm32-wpan/src/sub/mac/event.rs b/embassy-stm32-wpan/src/sub/mac/event.rs new file mode 100644 index 000000000..aaf965565 --- /dev/null +++ b/embassy-stm32-wpan/src/sub/mac/event.rs | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | use super::helpers::to_u16; | ||
| 2 | use super::indications::{ | ||
| 3 | AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication, | ||
| 4 | DpsIndication, GtsIndication, OrphanIndication, PollIndication, SyncLossIndication, | ||
| 5 | }; | ||
| 6 | use super::responses::{ | ||
| 7 | AssociateConfirm, CalibrateConfirm, DataConfirm, DisassociateConfirm, DpsConfirm, GetConfirm, GtsConfirm, | ||
| 8 | PollConfirm, PurgeConfirm, ResetConfirm, RxEnableConfirm, ScanConfirm, SetConfirm, SoundingConfirm, StartConfirm, | ||
| 9 | }; | ||
| 10 | use crate::sub::mac::opcodes::OpcodeM0ToM4; | ||
| 11 | |||
| 12 | pub 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))] | ||
| 29 | pub 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 | |||
| 57 | impl 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 @@ | |||
| 1 | pub fn to_u16(buf: &[u8]) -> u16 { | ||
| 2 | ((buf[1] as u16) << 8) | buf[0] as u16 | ||
| 3 | } | ||
| 4 | |||
| 5 | pub 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 @@ | |||
| 1 | use super::consts::MAX_PENDING_ADDRESS; | ||
| 2 | use super::event::ParseableMacEvent; | ||
| 3 | use super::helpers::to_u32; | ||
| 4 | use 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))] | ||
| 12 | pub 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 | |||
| 27 | impl 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))] | ||
| 47 | pub 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 | |||
| 62 | impl 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))] | ||
| 82 | pub 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 | |||
| 98 | impl 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))] | ||
| 129 | pub 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 | |||
| 153 | impl 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))] | ||
| 202 | pub 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 | |||
| 217 | impl 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))] | ||
| 238 | pub 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 | |||
| 251 | impl 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))] | ||
| 271 | pub 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 | |||
| 290 | impl 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))] | ||
| 312 | pub struct DpsIndication; | ||
| 313 | |||
| 314 | impl 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))] | ||
| 326 | pub 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 | |||
| 377 | impl 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))] | ||
| 440 | pub struct PollIndication { | ||
| 441 | /// addressing mode used | ||
| 442 | pub addr_mode: AddressMode, | ||
| 443 | /// Poll requester address | ||
| 444 | pub request_address: MacAddress, | ||
| 445 | } | ||
| 446 | |||
| 447 | impl 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] | ||
| 2 | macro_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; | |||
| 8 | use embassy_stm32::ipcc::Ipcc; | 8 | use embassy_stm32::ipcc::Ipcc; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | 10 | ||
| 11 | use self::commands::MacCommand; | ||
| 12 | use self::event::MacEvent; | ||
| 13 | use self::typedefs::MacError; | ||
| 11 | use crate::cmd::CmdPacket; | 14 | use crate::cmd::CmdPacket; |
| 12 | use crate::consts::TlPacketType; | 15 | use crate::consts::TlPacketType; |
| 13 | use crate::evt::{EvtBox, EvtPacket}; | 16 | use crate::evt::{EvtBox, EvtPacket}; |
| 14 | use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER}; | 17 | use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER}; |
| 15 | use crate::{channels, evt}; | 18 | use crate::{channels, evt}; |
| 16 | 19 | ||
| 20 | pub mod commands; | ||
| 21 | mod consts; | ||
| 22 | pub mod event; | ||
| 23 | mod helpers; | ||
| 24 | pub mod indications; | ||
| 25 | mod macros; | ||
| 26 | mod opcodes; | ||
| 27 | pub mod responses; | ||
| 28 | pub mod typedefs; | ||
| 29 | |||
| 17 | static MAC_WAKER: AtomicWaker = AtomicWaker::new(); | 30 | static MAC_WAKER: AtomicWaker = AtomicWaker::new(); |
| 18 | static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); | 31 | static 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 | ||
| 120 | const MAX_PACKET_SIZE: usize = 255; | ||
| 121 | |||
| 82 | impl evt::MemoryManager for Mac { | 122 | impl 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 @@ | |||
| 1 | const ST_VENDOR_OGF: u16 = 0x3F; | ||
| 2 | const MAC_802_15_4_CMD_OPCODE_OFFSET: u16 = 0x280; | ||
| 3 | |||
| 4 | const 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))] | ||
| 9 | pub 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))] | ||
| 31 | pub 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 | |||
| 59 | impl 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 @@ | |||
| 1 | use super::consts::{MAX_ED_SCAN_RESULTS_SUPPORTED, MAX_PAN_DESC_SUPPORTED, MAX_SOUNDING_LIST_SUPPORTED}; | ||
| 2 | use super::event::ParseableMacEvent; | ||
| 3 | use super::helpers::to_u32; | ||
| 4 | use 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))] | ||
| 12 | pub 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 | |||
| 27 | impl 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))] | ||
| 46 | pub 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 | |||
| 57 | impl 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))] | ||
| 86 | pub 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 | |||
| 97 | impl 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))] | ||
| 117 | pub 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 | |||
| 124 | impl 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))] | ||
| 139 | pub struct ResetConfirm { | ||
| 140 | /// The result of the reset operation | ||
| 141 | status: MacStatus, | ||
| 142 | } | ||
| 143 | |||
| 144 | impl 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))] | ||
| 159 | pub struct RxEnableConfirm { | ||
| 160 | /// Result of the request to enable or disable the receiver | ||
| 161 | status: MacStatus, | ||
| 162 | } | ||
| 163 | |||
| 164 | impl 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))] | ||
| 178 | pub 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 | |||
| 199 | impl 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))] | ||
| 238 | pub 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 | |||
| 245 | impl 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))] | ||
| 261 | pub struct StartConfirm { | ||
| 262 | /// Result of the attempt to start using an updated superframe configuration | ||
| 263 | pub status: MacStatus, | ||
| 264 | } | ||
| 265 | |||
| 266 | impl 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))] | ||
| 280 | pub struct PollConfirm { | ||
| 281 | /// The status of the data request | ||
| 282 | pub status: MacStatus, | ||
| 283 | } | ||
| 284 | |||
| 285 | impl 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))] | ||
| 299 | pub struct DpsConfirm { | ||
| 300 | /// The status of the DPS request | ||
| 301 | pub status: MacStatus, | ||
| 302 | } | ||
| 303 | |||
| 304 | impl 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))] | ||
| 319 | pub struct SoundingConfirm { | ||
| 320 | /// Results of the sounding measurement | ||
| 321 | sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED], | ||
| 322 | } | ||
| 323 | |||
| 324 | impl 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))] | ||
| 340 | pub 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 | |||
| 351 | impl 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))] | ||
| 369 | pub 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 | |||
| 392 | impl 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))] | ||
| 415 | pub 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 | |||
| 422 | impl 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 @@ | |||
| 1 | use crate::numeric_enum; | ||
| 2 | |||
| 3 | #[derive(Debug)] | ||
| 4 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 5 | pub enum MacError { | ||
| 6 | Error = 0x01, | ||
| 7 | NotImplemented = 0x02, | ||
| 8 | NotSupported = 0x03, | ||
| 9 | HardwareNotSupported = 0x04, | ||
| 10 | Undefined = 0x05, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl 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 | |||
| 26 | numeric_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 | |||
| 37 | numeric_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 | |||
| 95 | numeric_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)] | ||
| 109 | pub union MacAddress { | ||
| 110 | pub short: [u8; 2], | ||
| 111 | pub extended: [u8; 8], | ||
| 112 | } | ||
| 113 | |||
| 114 | #[cfg(feature = "defmt")] | ||
| 115 | impl 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 | |||
| 128 | impl Default for MacAddress { | ||
| 129 | fn default() -> Self { | ||
| 130 | Self { short: [0, 0] } | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | impl MacAddress { | ||
| 135 | pub const BROADCAST: Self = Self { short: [0xFF, 0xFF] }; | ||
| 136 | } | ||
| 137 | |||
| 138 | impl 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))] | ||
| 154 | pub 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))] | ||
| 162 | pub 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 | |||
| 185 | impl 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 | |||
| 222 | numeric_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"))] | ||
| 249 | bitflags::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")] | ||
| 269 | defmt::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 | |||
| 288 | numeric_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 | |||
| 305 | numeric_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 | |||
| 318 | numeric_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 | |||
| 330 | numeric_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 | |||
| 345 | numeric_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))] | ||
| 359 | pub struct PanId(pub [u8; 2]); | ||
| 360 | |||
| 361 | impl 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" |
| 4 | runner = "teleprobe local run --chip STM32WB55RG --elf" | 4 | runner = "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] |
| 26 | default = ["ble"] | 26 | default = ["ble", "mac"] |
| 27 | mac = ["embassy-stm32-wpan/mac"] | 27 | mac = ["embassy-stm32-wpan/mac"] |
| 28 | ble = ["embassy-stm32-wpan/ble"] | 28 | ble = ["embassy-stm32-wpan/ble"] |
| 29 | 29 | ||
| @@ -36,6 +36,10 @@ name = "tl_mbox_mac" | |||
| 36 | required-features = ["mac"] | 36 | required-features = ["mac"] |
| 37 | 37 | ||
| 38 | [[bin]] | 38 | [[bin]] |
| 39 | name = "mac_ffd" | ||
| 40 | required-features = ["mac"] | ||
| 41 | |||
| 42 | [[bin]] | ||
| 39 | name = "eddystone_beacon" | 43 | name = "eddystone_beacon" |
| 40 | required-features = ["ble"] | 44 | required-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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::bind_interrupts; | ||
| 8 | use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; | ||
| 9 | use embassy_stm32_wpan::sub::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest}; | ||
| 10 | use embassy_stm32_wpan::sub::mac::event::MacEvent; | ||
| 11 | use embassy_stm32_wpan::sub::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel}; | ||
| 12 | use embassy_stm32_wpan::sub::mm; | ||
| 13 | use embassy_stm32_wpan::TlMbox; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | bind_interrupts!(struct Irqs{ | ||
| 17 | IPCC_C1_RX => ReceiveInterruptHandler; | ||
| 18 | IPCC_C1_TX => TransmitInterruptHandler; | ||
| 19 | }); | ||
| 20 | |||
| 21 | #[embassy_executor::task] | ||
| 22 | async fn run_mm_queue(memory_manager: mm::MemoryManager) { | ||
| 23 | memory_manager.run_queue().await; | ||
| 24 | } | ||
| 25 | |||
| 26 | #[embassy_executor::main] | ||
| 27 | async 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::bind_interrupts; | ||
| 8 | use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; | ||
| 9 | use embassy_stm32_wpan::sub::mac::commands::{AssociateRequest, DataRequest, GetRequest, ResetRequest, SetRequest}; | ||
| 10 | use embassy_stm32_wpan::sub::mac::event::MacEvent; | ||
| 11 | use embassy_stm32_wpan::sub::mac::typedefs::{ | ||
| 12 | AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel, | ||
| 13 | }; | ||
| 14 | use embassy_stm32_wpan::sub::mm; | ||
| 15 | use embassy_stm32_wpan::TlMbox; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | bind_interrupts!(struct Irqs{ | ||
| 19 | IPCC_C1_RX => ReceiveInterruptHandler; | ||
| 20 | IPCC_C1_TX => TransmitInterruptHandler; | ||
| 21 | }); | ||
| 22 | |||
| 23 | #[embassy_executor::task] | ||
| 24 | async fn run_mm_queue(memory_manager: mm::MemoryManager) { | ||
| 25 | memory_manager.run_queue().await; | ||
| 26 | } | ||
| 27 | |||
| 28 | #[embassy_executor::main] | ||
| 29 | async 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 | |||
| 12 | stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo | 12 | stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo |
| 13 | stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo | 13 | stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo |
| 14 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo | 14 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo |
| 15 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble" ] # Nucleo | 15 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo |
| 16 | stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo | 16 | stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo |
| 17 | stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board | 17 | stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board |
| 18 | 18 | ||
| 19 | sdmmc = [] | 19 | sdmmc = [] |
| 20 | chrono = ["embassy-stm32/chrono", "dep:chrono"] | 20 | chrono = ["embassy-stm32/chrono", "dep:chrono"] |
| 21 | can = [] | 21 | can = [] |
| 22 | ble = ["dep:embassy-stm32-wpan"] | 22 | ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] |
| 23 | mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] | ||
| 24 | embassy-stm32-wpan = [] | ||
| 23 | not-gpdma = [] | 25 | not-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]] |
| 52 | name = "tl_mbox" | ||
| 53 | path = "src/bin/tl_mbox.rs" | ||
| 54 | required-features = [ "ble",] | ||
| 55 | |||
| 56 | [[bin]] | ||
| 57 | name = "can" | 54 | name = "can" |
| 58 | path = "src/bin/can.rs" | 55 | path = "src/bin/can.rs" |
| 59 | required-features = [ "can",] | 56 | required-features = [ "can",] |
| @@ -103,6 +100,16 @@ name = "usart_rx_ringbuffered" | |||
| 103 | path = "src/bin/usart_rx_ringbuffered.rs" | 100 | path = "src/bin/usart_rx_ringbuffered.rs" |
| 104 | required-features = [ "not-gpdma",] | 101 | required-features = [ "not-gpdma",] |
| 105 | 102 | ||
| 103 | [[bin]] | ||
| 104 | name = "wpan_ble" | ||
| 105 | path = "src/bin/wpan_ble.rs" | ||
| 106 | required-features = [ "ble",] | ||
| 107 | |||
| 108 | [[bin]] | ||
| 109 | name = "wpan_mac" | ||
| 110 | path = "src/bin/wpan_mac.rs" | ||
| 111 | required-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"] | ||
| 7 | mod common; | ||
| 8 | |||
| 9 | use common::*; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_stm32::bind_interrupts; | ||
| 12 | use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; | ||
| 13 | use embassy_stm32_wpan::sub::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest}; | ||
| 14 | use embassy_stm32_wpan::sub::mac::event::MacEvent; | ||
| 15 | use embassy_stm32_wpan::sub::mac::typedefs::{ | ||
| 16 | AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel, | ||
| 17 | }; | ||
| 18 | use embassy_stm32_wpan::sub::mm; | ||
| 19 | use embassy_stm32_wpan::TlMbox; | ||
| 20 | use {defmt_rtt as _, panic_probe as _}; | ||
| 21 | |||
| 22 | bind_interrupts!(struct Irqs{ | ||
| 23 | IPCC_C1_RX => ReceiveInterruptHandler; | ||
| 24 | IPCC_C1_TX => TransmitInterruptHandler; | ||
| 25 | }); | ||
| 26 | |||
| 27 | #[embassy_executor::task] | ||
| 28 | async fn run_mm_queue(memory_manager: mm::MemoryManager) { | ||
| 29 | memory_manager.run_queue().await; | ||
| 30 | } | ||
| 31 | |||
| 32 | #[embassy_executor::main] | ||
| 33 | async 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 | } | ||
