aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32-wpan/src/mac/commands.rs
blob: a3a40f377dcb7f13cd9f103625af6996c15e9585 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
#![allow(unused)]

use core::{mem, slice};

use smoltcp::wire::ieee802154::Frame;

use super::opcodes::OpcodeM4ToM0;
use super::typedefs::{
    AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus,
    PanId, PibId, ScanType, SecurityLevel,
};

pub trait MacCommand: Sized {
    const OPCODE: OpcodeM4ToM0;

    fn payload<'a>(&'a self) -> &'a [u8] {
        unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::<Self>()) }
    }
}

/// MLME ASSOCIATE Request used to request an association
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AssociateRequest {
    /// the logical channel on which to attempt association
    pub channel_number: MacChannel,
    /// the channel page on which to attempt association
    pub channel_page: u8,
    /// coordinator addressing mode
    pub coord_addr_mode: AddressMode,
    /// operational capabilities of the associating device
    pub capability_information: Capabilities,
    /// the identifier of the PAN with which to associate
    pub coord_pan_id: PanId,
    /// the security level to be used
    pub security_level: SecurityLevel,
    /// the mode used to identify the key to be used
    pub key_id_mode: KeyIdMode,
    /// the originator of the key to be used
    pub key_source: [u8; 8],
    /// Coordinator address
    pub coord_address: MacAddress,
    /// the index of the key to be used
    pub key_index: u8,
}

impl MacCommand for AssociateRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateReq;
}

/// MLME DISASSOCIATE Request sed to request a disassociation
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DisassociateRequest {
    /// device addressing mode used
    pub device_addr_mode: AddressMode,
    /// the identifier of the PAN of the device
    pub device_pan_id: PanId,
    /// the reason for the disassociation
    pub disassociation_reason: DisassociationReason,
    /// device address
    pub device_address: MacAddress,
    /// `true` if the disassociation notification command is to be sent indirectly
    pub tx_indirect: bool,
    /// the security level to be used
    pub security_level: SecurityLevel,
    /// the mode to be used to indetify the key to be used
    pub key_id_mode: KeyIdMode,
    /// the index of the key to be used
    pub key_index: u8,
    /// the originator of the key to be used
    pub key_source: [u8; 8],
}

impl MacCommand for DisassociateRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDisassociateReq;
}

/// MLME GET Request used to request a PIB value
#[repr(C)]
#[derive(Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GetRequest {
    /// the name of the PIB attribute to read
    pub pib_attribute: PibId,

    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 3],
}

impl MacCommand for GetRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
}

/// MLME GTS Request used to request and maintain GTSs
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GtsRequest {
    /// the characteristics of the GTS
    pub characteristics: GtsCharacteristics,
    /// the security level to be used
    pub security_level: SecurityLevel,
    /// the mode used to identify the key to be used
    pub key_id_mode: KeyIdMode,
    /// the index of the key to be used
    pub key_index: u8,
    /// the originator of the key to be used
    pub key_source: [u8; 8],
}

impl MacCommand for GtsRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
}

#[repr(C)]
#[derive(Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ResetRequest {
    /// MAC PIB attributes are set to their default values or not during reset
    pub set_default_pib: bool,
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 3],
}

impl MacCommand for ResetRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeResetReq;
}

/// MLME RX ENABLE Request used to request that the receiver is either enabled
/// for a finite period of time or disabled
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RxEnableRequest {
    /// the request operation can be deferred or not
    pub defer_permit: bool,
    /// configure the transceiver to RX with ranging for a value of
    /// RANGING_ON or to not enable ranging for RANGING_OFF
    pub ranging_rx_control: u8,
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 2],
    /// number of symbols measured before the receiver is to be enabled or disabled
    pub rx_on_time: [u8; 4],
    /// number of symbols for which the receiver is to be enabled
    pub rx_on_duration: [u8; 4],
}

impl MacCommand for RxEnableRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeRxEnableReq;
}

/// MLME SCAN Request used to initiate a channel scan over a given list of channels
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ScanRequest {
    /// the type of scan to be performed
    pub scan_type: ScanType,
    /// the time spent on scanning each channel
    pub scan_duration: u8,
    /// channel page on which to perform the scan
    pub channel_page: u8,
    /// security level to be used
    pub security_level: SecurityLevel,
    /// indicate which channels are to be scanned
    pub scan_channels: [u8; 4],
    /// originator the key to be used
    pub key_source: [u8; 8],
    /// mode used to identify the key to be used
    pub key_id_mode: KeyIdMode,
    /// index of the key to be used
    pub key_index: u8,
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 2],
}

impl MacCommand for ScanRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeScanReq;
}

/// MLME SET Request used to attempt to write the given value to the indicated PIB attribute
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SetRequest {
    /// the pointer to the value of the PIB attribute to set
    pub pib_attribute_ptr: *const u8,
    /// the name of the PIB attribute to set
    pub pib_attribute: PibId,
}

impl MacCommand for SetRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSetReq;
}

/// MLME START Request used by the FFDs to intiate a new PAN or to begin using a new superframe
/// configuration
#[repr(C)]
#[derive(Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StartRequest {
    /// PAN indentifier to used by the device
    pub pan_id: PanId,
    /// logical channel on which to begin
    pub channel_number: MacChannel,
    /// channel page on which to begin
    pub channel_page: u8,
    /// time at which to begin transmitting beacons
    pub start_time: [u8; 4],
    /// indicated how often the beacon is to be transmitted
    pub beacon_order: u8,
    /// length of the active portion of the superframe
    pub superframe_order: u8,
    /// indicated wheter the device is a PAN coordinator or not
    pub pan_coordinator: bool,
    /// indicates if the receiver of the beaconing device is disabled or not
    pub battery_life_extension: bool,
    /// indicated if the coordinator realignment command is to be trasmitted
    pub coord_realignment: u8,
    /// indicated if the coordinator realignment command is to be trasmitted
    pub coord_realign_security_level: SecurityLevel,
    /// index of the key to be used
    pub coord_realign_key_id_index: u8,
    /// originator of the key to be used
    pub coord_realign_key_source: [u8; 8],
    /// security level to be used for beacon frames
    pub beacon_security_level: SecurityLevel,
    /// mode used to identify the key to be used
    pub beacon_key_id_mode: KeyIdMode,
    /// index of the key to be used
    pub beacon_key_index: u8,
    /// originator of the key to be used
    pub beacon_key_source: [u8; 8],
}

impl MacCommand for StartRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeStartReq;
}

/// MLME SYNC Request used to synchronize with the coordinator by acquiring and, if
/// specified, tracking its beacons
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SyncRequest {
    /// the channel number on which to attempt coordinator synchronization
    pub channel_number: MacChannel,
    /// the channel page on which to attempt coordinator synchronization
    pub channel_page: u8,
    /// `true` if the MLME is to synchronize with the next beacon and attempts
    /// to track all future beacons.
    ///
    /// `false` if the MLME is to synchronize with only the next beacon
    pub track_beacon: bool,
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 1],
}

impl MacCommand for SyncRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSyncReq;
}

/// MLME POLL Request propmts the device to request data from the coordinator
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PollRequest {
    /// addressing mode of the coordinator
    pub coord_addr_mode: AddressMode,
    /// security level to be used
    pub security_level: SecurityLevel,
    /// mode used to identify the key to be used
    pub key_id_mode: KeyIdMode,
    /// index of the key to be used
    pub key_index: u8,
    /// coordinator address
    pub coord_address: MacAddress,
    /// originator of the key to be used
    pub key_source: [u8; 8],
    /// PAN identifier of the coordinator
    pub coord_pan_id: PanId,
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 2],
}

impl MacCommand for PollRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmePollReq;
}

/// MLME DPS Request allows the next higher layer to request that the PHY utilize a
/// given pair of preamble codes for a single use pending expiration of the DPSIndexDuration
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DpsRequest {
    /// the index value for the transmitter
    tx_dps_index: u8,
    /// the index value of the receiver
    rx_dps_index: u8,
    /// the number of symbols for which the transmitter and receiver will utilize the
    /// respective DPS indices
    dps_index_duration: u8,
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 1],
}

impl MacCommand for DpsRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDpsReq;
}

/// MLME SOUNDING request primitive which is used by the next higher layer to request that
/// the PHY respond with channel sounding information
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SoundingRequest {
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 4],
}

impl MacCommand for SoundingRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSoundingReq;
}

/// MLME CALIBRATE request primitive which used  to obtain the results of a ranging
/// calibration request from an RDEV
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CalibrateRequest {
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 4],
}

impl MacCommand for CalibrateRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeCalibrateReq;
}

/// MCPS DATA Request used for MAC data related requests from the application
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DataRequest {
    /// the handle assocated with the MSDU to be transmitted
    pub msdu_ptr: *const u8,
    /// source addressing mode used
    pub src_addr_mode: AddressMode,
    /// destination addressing mode used
    pub dst_addr_mode: AddressMode,
    /// destination PAN Id
    pub dst_pan_id: PanId,
    /// destination address
    pub dst_address: MacAddress,
    /// the number of octets contained in the MSDU
    pub msdu_length: u8,
    /// the handle assocated with the MSDU to be transmitted
    pub msdu_handle: u8,
    /// the ACK transmittion options for the MSDU
    pub ack_tx: u8,
    /// `true` if a GTS is to be used for transmission
    ///
    /// `false` indicates that the CAP will be used
    pub gts_tx: bool,
    /// the pending bit transmission options for the MSDU
    pub indirect_tx: u8,
    /// the security level to be used
    pub security_level: SecurityLevel,
    /// the mode used to indentify the key to be used
    pub key_id_mode: KeyIdMode,
    /// the index of the key to be used
    pub key_index: u8,
    /// the originator of the key to be used
    pub key_source: [u8; 8],
    /// 2011 - the pulse repitition value
    pub uwbprf: u8,
    /// 2011 - the ranging configuration
    pub ranging: u8,
    /// 2011 - the preamble symbol repititions
    pub uwb_preamble_symbol_repetitions: u8,
    /// 2011 - indicates the data rate
    pub datrate: u8,
}

impl DataRequest {
    pub fn set_buffer<'a>(&'a mut self, buf: &'a [u8]) -> &'a mut Self {
        self.msdu_ptr = buf as *const _ as *const u8;
        self.msdu_length = buf.len() as u8;

        self
    }
}

impl<'a, T: AsRef<[u8]>> TryFrom<Frame<&'a T>> for DataRequest {
    type Error = ();

    fn try_from(frame: Frame<&'a T>) -> Result<Self, Self::Error> {
        // TODO: map the rest of these

        let mut request = DataRequest {
            src_addr_mode: frame.src_addressing_mode().try_into()?,
            dst_addr_mode: frame.dst_addressing_mode().try_into()?,
            dst_pan_id: frame.dst_pan_id().ok_or(())?.into(),
            dst_address: frame.dst_addr().ok_or(())?.into(),
            msdu_handle: frame.sequence_number().ok_or(())?,
            ack_tx: 0x00,
            gts_tx: false,
            security_level: SecurityLevel::Unsecure,
            ..Default::default()
        };

        request.set_buffer(frame.payload().ok_or(())?);

        Ok(request)
    }
}

impl Default for DataRequest {
    fn default() -> Self {
        Self {
            msdu_ptr: 0 as *const u8,
            src_addr_mode: AddressMode::NoAddress,
            dst_addr_mode: AddressMode::NoAddress,
            dst_pan_id: PanId([0, 0]),
            dst_address: MacAddress { short: [0, 0] },
            msdu_length: 0,
            msdu_handle: 0,
            ack_tx: 0,
            gts_tx: false,
            indirect_tx: 0,
            security_level: SecurityLevel::Unsecure,
            key_id_mode: KeyIdMode::Implicite,
            key_index: 0,
            key_source: [0u8; 8],
            uwbprf: 0,
            ranging: 0,
            uwb_preamble_symbol_repetitions: 0,
            datrate: 0,
        }
    }
}

impl MacCommand for DataRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsDataReq;
}

/// for MCPS PURGE Request used to purge an MSDU from the transaction queue
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PurgeRequest {
    /// the handle associated with the MSDU to be purged from the transaction
    /// queue
    pub msdu_handle: u8,
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 3],
}

impl MacCommand for PurgeRequest {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsPurgeReq;
}

/// MLME ASSOCIATE Response used to initiate a response to an MLME-ASSOCIATE.indication
#[repr(C)]
#[derive(Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AssociateResponse {
    /// extended address of the device requesting association
    pub device_address: [u8; 8],
    /// 16-bitshort device address allocated by the coordinator on successful
    /// association
    pub assoc_short_address: [u8; 2],
    /// status of the association attempt
    pub status: MacStatus,
    /// security level to be used
    pub security_level: SecurityLevel,
    /// the originator of the key to be used
    pub key_source: [u8; 8],
    /// the mode used to identify the key to be used
    pub key_id_mode: KeyIdMode,
    /// the index of the key to be used
    pub key_index: u8,
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 2],
}

impl MacCommand for AssociateResponse {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateRes;
}

/// MLME ORPHAN Response used to respond to the MLME ORPHAN Indication
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct OrphanResponse {
    /// extended address of the orphaned device
    pub orphan_address: [u8; 8],
    /// short address allocated to the orphaned device
    pub short_address: [u8; 2],
    /// if the orphaned device is associated with coordinator or not
    pub associated_member: bool,
    /// security level to be used
    pub security_level: SecurityLevel,
    /// the originator of the key to be used
    pub key_source: [u8; 8],
    /// the mode used to identify the key to be used
    pub key_id_mode: KeyIdMode,
    /// the index of the key to be used
    pub key_index: u8,
    /// byte stuffing to keep 32 bit alignment
    pub a_stuffing: [u8; 2],
}

impl MacCommand for OrphanResponse {
    const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeOrphanRes;
}