xref: /aosp_15_r20/external/uwb/src/rust/uwb_core/src/params/fira_app_config_params.rs (revision e0df40009cb5d71e642272d38ba1bb7ffccfce41)
1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This module defines the UCI application config parameters for the FiRa ranging session.
16 
17 use std::collections::{HashMap, HashSet};
18 use std::convert::{TryFrom, TryInto};
19 
20 use log::warn;
21 use num_derive::{FromPrimitive, ToPrimitive};
22 use zeroize::Zeroize;
23 
24 use crate::params::app_config_params::{AppConfigParams, AppConfigTlvMap};
25 use crate::params::uci_packets::{AppConfigTlvType, SessionState, SubSessionId};
26 use crate::params::utils::{u16_to_bytes, u32_to_bytes, u8_to_bytes, validate};
27 use crate::utils::{builder_field, getter_field};
28 
29 // The default value of each parameters.
30 const DEFAULT_RANGING_ROUND_USAGE: RangingRoundUsage = RangingRoundUsage::DsTwr;
31 const DEFAULT_STS_CONFIG: StsConfig = StsConfig::Static;
32 const DEFAULT_CHANNEL_NUMBER: UwbChannel = UwbChannel::Channel9;
33 const DEFAULT_SLOT_DURATION_RSTU: u16 = 2400;
34 const DEFAULT_RANGING_DURATION_MS: u32 = 200;
35 const DEFAULT_MAC_FCS_TYPE: MacFcsType = MacFcsType::Crc16;
36 const DEFAULT_RANGING_ROUND_CONTROL: RangingRoundControl = RangingRoundControl {
37     ranging_result_report_message: true,
38     control_message: true,
39     measurement_report_message: false,
40 };
41 const DEFAULT_AOA_RESULT_REQUEST: AoaResultRequest = AoaResultRequest::ReqAoaResults;
42 const DEFAULT_RANGE_DATA_NTF_CONFIG: RangeDataNtfConfig = RangeDataNtfConfig::Enable;
43 const DEFAULT_RANGE_DATA_NTF_PROXIMITY_NEAR_CM: u16 = 0;
44 const DEFAULT_RANGE_DATA_NTF_PROXIMITY_FAR_CM: u16 = 20000;
45 const DEFAULT_RFRAME_CONFIG: RframeConfig = RframeConfig::SP3;
46 const DEFAULT_PREAMBLE_CODE_INDEX: u8 = 10;
47 const DEFAULT_SFD_ID: u8 = 2;
48 const DEFAULT_PSDU_DATA_RATE: PsduDataRate = PsduDataRate::Rate6m81;
49 const DEFAULT_PREAMBLE_DURATION: PreambleDuration = PreambleDuration::T64Symbols;
50 const DEFAULT_RANGING_TIME_STRUCT: RangingTimeStruct = RangingTimeStruct::BlockBasedScheduling;
51 const DEFAULT_SLOTS_PER_RR: u8 = 25;
52 const DEFAULT_TX_ADAPTIVE_PAYLOAD_POWER: TxAdaptivePayloadPower = TxAdaptivePayloadPower::Disable;
53 const DEFAULT_RESPONDER_SLOT_INDEX: u8 = 1;
54 const DEFAULT_PRF_MODE: PrfMode = PrfMode::Bprf;
55 const DEFAULT_SCHEDULED_MODE: ScheduledMode = ScheduledMode::TimeScheduledRanging;
56 const DEFAULT_KEY_ROTATION: KeyRotation = KeyRotation::Disable;
57 const DEFAULT_KEY_ROTATION_RATE: u8 = 0;
58 const DEFAULT_SESSION_PRIORITY: u8 = 50;
59 const DEFAULT_MAC_ADDRESS_MODE: MacAddressMode = MacAddressMode::MacAddress2Bytes;
60 const DEFAULT_NUMBER_OF_STS_SEGMENTS: u8 = 1;
61 const DEFAULT_MAX_RR_RETRY: u16 = 0;
62 const DEFAULT_UWB_INITIATION_TIME_MS: u32 = 0;
63 const DEFAULT_HOPPING_MODE: HoppingMode = HoppingMode::Disable;
64 const DEFAULT_BLOCK_STRIDE_LENGTH: u8 = 0;
65 const DEFAULT_RESULT_REPORT_CONFIG: ResultReportConfig =
66     ResultReportConfig { tof: true, aoa_azimuth: false, aoa_elevation: false, aoa_fom: false };
67 const DEFAULT_IN_BAND_TERMINATION_ATTEMPT_COUNT: u8 = 1;
68 const DEFAULT_SUB_SESSION_ID: u32 = 0;
69 const DEFAULT_BPRF_PHR_DATA_RATE: BprfPhrDataRate = BprfPhrDataRate::Rate850k;
70 const DEFAULT_MAX_NUMBER_OF_MEASUREMENTS: u16 = 0;
71 const DEFAULT_STS_LENGTH: StsLength = StsLength::Length64;
72 const DEFAULT_NUMBER_OF_RANGE_MEASUREMENTS: u8 = 0;
73 const DEFAULT_NUMBER_OF_AOA_AZIMUTH_MEASUREMENTS: u8 = 0;
74 const DEFAULT_NUMBER_OF_AOA_ELEVATION_MEASUREMENTS: u8 = 0;
75 
76 /// The FiRa's application configuration parameters.
77 /// Ref: FiRa Consortium UWB Command Interface Generic Techinal Specification Version 1.1.0.
78 #[derive(Clone, PartialEq, Eq)]
79 pub struct FiraAppConfigParams {
80     // FiRa standard config.
81     device_type: DeviceType,
82     ranging_round_usage: RangingRoundUsage,
83     sts_config: StsConfig,
84     multi_node_mode: MultiNodeMode,
85     channel_number: UwbChannel,
86     device_mac_address: UwbAddress,
87     dst_mac_address: Vec<UwbAddress>,
88     slot_duration_rstu: u16,
89     ranging_duration_ms: u32,
90     mac_fcs_type: MacFcsType,
91     ranging_round_control: RangingRoundControl,
92     aoa_result_request: AoaResultRequest,
93     range_data_ntf_config: RangeDataNtfConfig,
94     range_data_ntf_proximity_near_cm: u16,
95     range_data_ntf_proximity_far_cm: u16,
96     device_role: DeviceRole,
97     rframe_config: RframeConfig,
98     preamble_code_index: u8,
99     sfd_id: u8,
100     psdu_data_rate: PsduDataRate,
101     preamble_duration: PreambleDuration,
102     ranging_time_struct: RangingTimeStruct,
103     slots_per_rr: u8,
104     tx_adaptive_payload_power: TxAdaptivePayloadPower,
105     responder_slot_index: u8,
106     prf_mode: PrfMode,
107     scheduled_mode: ScheduledMode,
108     key_rotation: KeyRotation,
109     key_rotation_rate: u8,
110     session_priority: u8,
111     mac_address_mode: MacAddressMode,
112     vendor_id: [u8; 2],
113     static_sts_iv: [u8; 6],
114     number_of_sts_segments: u8,
115     max_rr_retry: u16,
116     uwb_initiation_time_ms: u32,
117     hopping_mode: HoppingMode,
118     block_stride_length: u8,
119     result_report_config: ResultReportConfig,
120     in_band_termination_attempt_count: u8,
121     sub_session_id: SubSessionId,
122     bprf_phr_data_rate: BprfPhrDataRate,
123     max_number_of_measurements: u16,
124     sts_length: StsLength,
125 
126     // Android-specific app config.
127     number_of_range_measurements: u8,
128     number_of_aoa_azimuth_measurements: u8,
129     number_of_aoa_elevation_measurements: u8,
130 }
131 
132 /// Explicitly implement Debug trait to prevent logging PII data.
133 impl std::fmt::Debug for FiraAppConfigParams {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error>134     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
135         static REDACTED_STR: &str = "redacted";
136 
137         f.debug_struct("FiraAppConfigParams")
138             .field("device_type", &self.device_type)
139             .field("ranging_round_usage", &self.ranging_round_usage)
140             .field("sts_config", &self.sts_config)
141             .field("multi_node_mode", &self.multi_node_mode)
142             .field("channel_number", &self.channel_number)
143             .field("device_mac_address", &self.device_mac_address)
144             .field("dst_mac_address", &self.dst_mac_address)
145             .field("slot_duration_rstu", &self.slot_duration_rstu)
146             .field("ranging_duration_ms", &self.ranging_duration_ms)
147             .field("mac_fcs_type", &self.mac_fcs_type)
148             .field("ranging_round_control", &self.ranging_round_control)
149             .field("aoa_result_request", &self.aoa_result_request)
150             .field("range_data_ntf_config", &self.range_data_ntf_config)
151             .field("range_data_ntf_proximity_near_cm", &self.range_data_ntf_proximity_near_cm)
152             .field("range_data_ntf_proximity_far_cm", &self.range_data_ntf_proximity_far_cm)
153             .field("device_role", &self.device_role)
154             .field("rframe_config", &self.rframe_config)
155             .field("preamble_code_index", &self.preamble_code_index)
156             .field("sfd_id", &self.sfd_id)
157             .field("psdu_data_rate", &self.psdu_data_rate)
158             .field("preamble_duration", &self.preamble_duration)
159             .field("ranging_time_struct", &self.ranging_time_struct)
160             .field("slots_per_rr", &self.slots_per_rr)
161             .field("tx_adaptive_payload_power", &self.tx_adaptive_payload_power)
162             .field("responder_slot_index", &self.responder_slot_index)
163             .field("prf_mode", &self.prf_mode)
164             .field("scheduled_mode", &self.scheduled_mode)
165             .field("key_rotation", &self.key_rotation)
166             .field("key_rotation_rate", &self.key_rotation_rate)
167             .field("session_priority", &self.session_priority)
168             .field("mac_address_mode", &self.mac_address_mode)
169             .field("vendor_id", &REDACTED_STR) // vendor_id field is PII.
170             .field("static_sts_iv", &REDACTED_STR) // static_sts_iv field is PII.
171             .field("number_of_sts_segments", &self.number_of_sts_segments)
172             .field("max_rr_retry", &self.max_rr_retry)
173             .field("uwb_initiation_time_ms", &self.uwb_initiation_time_ms)
174             .field("hopping_mode", &self.hopping_mode)
175             .field("block_stride_length", &self.block_stride_length)
176             .field("result_report_config", &self.result_report_config)
177             .field("in_band_termination_attempt_count", &self.in_band_termination_attempt_count)
178             .field("sub_session_id", &self.sub_session_id)
179             .field("bprf_phr_data_rate", &self.bprf_phr_data_rate)
180             .field("max_number_of_measurements", &self.max_number_of_measurements)
181             .field("sts_length", &self.sts_length)
182             .field("number_of_range_measurements", &self.number_of_range_measurements)
183             .field("number_of_aoa_azimuth_measurements", &self.number_of_aoa_azimuth_measurements)
184             .field(
185                 "number_of_aoa_elevation_measurements",
186                 &self.number_of_aoa_elevation_measurements,
187             )
188             .finish()
189     }
190 }
191 
192 impl Drop for FiraAppConfigParams {
drop(&mut self)193     fn drop(&mut self) {
194         self.vendor_id.zeroize();
195         self.static_sts_iv.zeroize();
196         self.sub_session_id.zeroize();
197     }
198 }
199 
200 #[allow(missing_docs)]
201 impl FiraAppConfigParams {
202     // Generate the getter methods for all the fields.
203     getter_field!(device_type, DeviceType);
204     getter_field!(ranging_round_usage, RangingRoundUsage);
205     getter_field!(sts_config, StsConfig);
206     getter_field!(multi_node_mode, MultiNodeMode);
207     getter_field!(channel_number, UwbChannel);
208     getter_field!(device_mac_address, UwbAddress);
209     getter_field!(dst_mac_address, Vec<UwbAddress>);
210     getter_field!(slot_duration_rstu, u16);
211     getter_field!(ranging_duration_ms, u32);
212     getter_field!(mac_fcs_type, MacFcsType);
213     getter_field!(ranging_round_control, RangingRoundControl);
214     getter_field!(aoa_result_request, AoaResultRequest);
215     getter_field!(range_data_ntf_config, RangeDataNtfConfig);
216     getter_field!(range_data_ntf_proximity_near_cm, u16);
217     getter_field!(range_data_ntf_proximity_far_cm, u16);
218     getter_field!(device_role, DeviceRole);
219     getter_field!(rframe_config, RframeConfig);
220     getter_field!(preamble_code_index, u8);
221     getter_field!(sfd_id, u8);
222     getter_field!(psdu_data_rate, PsduDataRate);
223     getter_field!(preamble_duration, PreambleDuration);
224     getter_field!(ranging_time_struct, RangingTimeStruct);
225     getter_field!(slots_per_rr, u8);
226     getter_field!(tx_adaptive_payload_power, TxAdaptivePayloadPower);
227     getter_field!(responder_slot_index, u8);
228     getter_field!(prf_mode, PrfMode);
229     getter_field!(scheduled_mode, ScheduledMode);
230     getter_field!(key_rotation, KeyRotation);
231     getter_field!(key_rotation_rate, u8);
232     getter_field!(session_priority, u8);
233     getter_field!(mac_address_mode, MacAddressMode);
234     getter_field!(vendor_id, [u8; 2]);
235     getter_field!(static_sts_iv, [u8; 6]);
236     getter_field!(number_of_sts_segments, u8);
237     getter_field!(max_rr_retry, u16);
238     getter_field!(uwb_initiation_time_ms, u32);
239     getter_field!(hopping_mode, HoppingMode);
240     getter_field!(block_stride_length, u8);
241     getter_field!(result_report_config, ResultReportConfig);
242     getter_field!(in_band_termination_attempt_count, u8);
243     getter_field!(sub_session_id, u32);
244     getter_field!(bprf_phr_data_rate, BprfPhrDataRate);
245     getter_field!(max_number_of_measurements, u16);
246     getter_field!(sts_length, StsLength);
247     getter_field!(number_of_range_measurements, u8);
248     getter_field!(number_of_aoa_azimuth_measurements, u8);
249     getter_field!(number_of_aoa_elevation_measurements, u8);
250 
251     /// validate if the params are valid.
is_valid(&self) -> Option<()>252     fn is_valid(&self) -> Option<()> {
253         if self.device_type == DeviceType::Controlee {
254             if self.ranging_round_control.ranging_result_report_message {
255                 warn!("The RRRM bit is ignored by a controlee");
256             }
257             if self.ranging_round_control.measurement_report_message {
258                 warn!("The MRM bit is ignored by a controlee");
259             }
260             if self.hopping_mode != HoppingMode::Disable {
261                 warn!("hopping_mode is ignored by a controlee");
262             }
263             if self.block_stride_length != 0 {
264                 warn!("block_stride_length is ignored by a controlee");
265             }
266         }
267         if self.ranging_time_struct != RangingTimeStruct::BlockBasedScheduling
268             && self.block_stride_length != 0
269         {
270             warn!(
271                 "block_stride_length is ignored when ranging_time_struct not BlockBasedScheduling"
272             );
273         }
274         if self.prf_mode != PrfMode::Bprf && self.bprf_phr_data_rate != BprfPhrDataRate::Rate850k {
275             warn!("BPRF_PHR_DATA_RATE is ignored when prf_mode not BPRF");
276         }
277 
278         validate(
279             (1..=8).contains(&self.dst_mac_address.len()),
280             "The length of dst_mac_address should be between 1 to 8",
281         )?;
282         validate(
283             (0..=15).contains(&self.key_rotation_rate),
284             "key_rotation_rate should be between 0 to 15",
285         )?;
286         validate(
287             (1..=100).contains(&self.session_priority),
288             "session_priority should be between 1 to 100",
289         )?;
290         validate(
291             (0..=10000).contains(&self.uwb_initiation_time_ms),
292             "uwb_initiation_time_ms should be between 0 to 10000",
293         )?;
294         validate(
295             (1..=10).contains(&self.in_band_termination_attempt_count),
296             "in_band_termination_attempt_count should be between 1 to 10",
297         )?;
298 
299         match self.mac_address_mode {
300             MacAddressMode::MacAddress2Bytes | MacAddressMode::MacAddress8Bytes2BytesHeader => {
301                 validate(
302                     matches!(self.device_mac_address, UwbAddress::Short(_)),
303                     "device_mac_address should be short address",
304                 )?;
305                 validate(
306                     self.dst_mac_address.iter().all(|addr| matches!(addr, UwbAddress::Short(_))),
307                     "dst_mac_address should be short address",
308                 )?;
309             }
310             MacAddressMode::MacAddress8Bytes => {
311                 validate(
312                     matches!(self.device_mac_address, UwbAddress::Extended(_)),
313                     "device_mac_address should be extended address",
314                 )?;
315                 validate(
316                     self.dst_mac_address.iter().all(|addr| matches!(addr, UwbAddress::Extended(_))),
317                     "dst_mac_address should be extended address",
318                 )?;
319             }
320         }
321 
322         match self.prf_mode {
323             PrfMode::Bprf => {
324                 validate(
325                     (9..=12).contains(&self.preamble_code_index),
326                     "preamble_code_index should be between 9 to 12 when BPRF",
327                 )?;
328                 validate([0, 2].contains(&self.sfd_id), "sfd_id should be 0 or 2 when BPRF")?;
329                 validate(
330                     self.preamble_duration == PreambleDuration::T64Symbols,
331                     "preamble_duration should be 64 symbols when BPRF",
332                 )?;
333             }
334             _ => {
335                 validate(
336                     (25..=32).contains(&self.preamble_code_index),
337                     "preamble_code_index should be between 25 to 32 when HPRF",
338                 )?;
339                 validate(
340                     (1..=4).contains(&self.sfd_id),
341                     "sfd_id should be between 1 to 4 when HPRF",
342                 )?;
343             }
344         }
345 
346         match self.rframe_config {
347             RframeConfig::SP0 => {
348                 validate(
349                     self.number_of_sts_segments == 0,
350                     "number_of_sts_segments should be 0 when SP0",
351                 )?;
352             }
353             RframeConfig::SP1 | RframeConfig::SP3 => match self.prf_mode {
354                 PrfMode::Bprf => {
355                     validate(
356                         self.number_of_sts_segments == 1,
357                         "number_of_sts_segments should be 1 when SP1/SP3 and BPRF",
358                     )?;
359                 }
360                 _ => {
361                     validate(
362                         [1, 2, 3, 4].contains(&self.number_of_sts_segments),
363                         "number_of_sts_segments should be between 1 to 4 when SP1/SP3 and HPRF",
364                     )?;
365                 }
366             },
367         }
368 
369         match self.aoa_result_request {
370             AoaResultRequest::ReqAoaResultsInterleaved => {
371                 validate(
372                     self.is_any_number_of_measurement_set(),
373                     "At least one of the ratio params should be set for interleaving mode",
374                 );
375             }
376             _ => {
377                 validate(
378                     !self.is_any_number_of_measurement_set(),
379                     "All of the ratio params should not be set for non-interleaving mode",
380                 );
381             }
382         }
383 
384         Some(())
385     }
386 
is_any_number_of_measurement_set(&self) -> bool387     fn is_any_number_of_measurement_set(&self) -> bool {
388         self.number_of_range_measurements != DEFAULT_NUMBER_OF_RANGE_MEASUREMENTS
389             || self.number_of_aoa_azimuth_measurements != DEFAULT_NUMBER_OF_AOA_AZIMUTH_MEASUREMENTS
390             || self.number_of_aoa_elevation_measurements
391                 != DEFAULT_NUMBER_OF_AOA_ELEVATION_MEASUREMENTS
392     }
393 
394     /// Determine if the |config_map| is updatable in the state |session_state|.
is_config_updatable(config_map: &AppConfigTlvMap, session_state: SessionState) -> bool395     pub fn is_config_updatable(config_map: &AppConfigTlvMap, session_state: SessionState) -> bool {
396         match session_state {
397             SessionState::SessionStateActive => {
398                 let avalible_list = HashSet::from([
399                     AppConfigTlvType::RangingDuration,
400                     AppConfigTlvType::RngDataNtf,
401                     AppConfigTlvType::RngDataNtfProximityNear,
402                     AppConfigTlvType::RngDataNtfProximityFar,
403                     AppConfigTlvType::BlockStrideLength,
404                 ]);
405                 config_map.keys().all(|key| avalible_list.contains(key))
406             }
407             SessionState::SessionStateIdle => true,
408             _ => false,
409         }
410     }
411 
412     /// Generate the AppConfigTlv HashMap from the FiraAppConfigParams instance.
generate_config_map(&self) -> AppConfigTlvMap413     pub fn generate_config_map(&self) -> AppConfigTlvMap {
414         debug_assert!(self.is_valid().is_some());
415 
416         HashMap::from([
417             (AppConfigTlvType::DeviceType, u8_to_bytes(self.device_type as u8)),
418             (AppConfigTlvType::RangingRoundUsage, u8_to_bytes(self.ranging_round_usage as u8)),
419             (AppConfigTlvType::StsConfig, u8_to_bytes(self.sts_config as u8)),
420             (AppConfigTlvType::MultiNodeMode, u8_to_bytes(self.multi_node_mode as u8)),
421             (AppConfigTlvType::ChannelNumber, u8_to_bytes(self.channel_number as u8)),
422             (AppConfigTlvType::NoOfControlee, u8_to_bytes(self.dst_mac_address.len() as u8)),
423             (AppConfigTlvType::DeviceMacAddress, self.device_mac_address.clone().into()),
424             (AppConfigTlvType::DstMacAddress, addresses_to_bytes(self.dst_mac_address.clone())),
425             (AppConfigTlvType::SlotDuration, u16_to_bytes(self.slot_duration_rstu)),
426             (AppConfigTlvType::RangingDuration, u32_to_bytes(self.ranging_duration_ms)),
427             (AppConfigTlvType::MacFcsType, u8_to_bytes(self.mac_fcs_type as u8)),
428             (
429                 AppConfigTlvType::RangingRoundControl,
430                 u8_to_bytes(self.ranging_round_control.as_u8()),
431             ),
432             (AppConfigTlvType::AoaResultReq, u8_to_bytes(self.aoa_result_request as u8)),
433             (AppConfigTlvType::RngDataNtf, u8_to_bytes(self.range_data_ntf_config as u8)),
434             (
435                 AppConfigTlvType::RngDataNtfProximityNear,
436                 u16_to_bytes(self.range_data_ntf_proximity_near_cm),
437             ),
438             (
439                 AppConfigTlvType::RngDataNtfProximityFar,
440                 u16_to_bytes(self.range_data_ntf_proximity_far_cm),
441             ),
442             (AppConfigTlvType::DeviceRole, u8_to_bytes(self.device_role as u8)),
443             (AppConfigTlvType::RframeConfig, u8_to_bytes(self.rframe_config as u8)),
444             (AppConfigTlvType::PreambleCodeIndex, u8_to_bytes(self.preamble_code_index)),
445             (AppConfigTlvType::SfdId, u8_to_bytes(self.sfd_id)),
446             (AppConfigTlvType::PsduDataRate, u8_to_bytes(self.psdu_data_rate as u8)),
447             (AppConfigTlvType::PreambleDuration, u8_to_bytes(self.preamble_duration as u8)),
448             (AppConfigTlvType::RangingTimeStruct, u8_to_bytes(self.ranging_time_struct as u8)),
449             (AppConfigTlvType::SlotsPerRr, u8_to_bytes(self.slots_per_rr)),
450             (
451                 AppConfigTlvType::TxAdaptivePayloadPower,
452                 u8_to_bytes(self.tx_adaptive_payload_power as u8),
453             ),
454             (AppConfigTlvType::ResponderSlotIndex, u8_to_bytes(self.responder_slot_index)),
455             (AppConfigTlvType::PrfMode, u8_to_bytes(self.prf_mode as u8)),
456             (AppConfigTlvType::ScheduledMode, u8_to_bytes(self.scheduled_mode as u8)),
457             (AppConfigTlvType::KeyRotation, u8_to_bytes(self.key_rotation as u8)),
458             (AppConfigTlvType::KeyRotationRate, u8_to_bytes(self.key_rotation_rate)),
459             (AppConfigTlvType::SessionPriority, u8_to_bytes(self.session_priority)),
460             (AppConfigTlvType::MacAddressMode, u8_to_bytes(self.mac_address_mode as u8)),
461             (AppConfigTlvType::VendorId, self.vendor_id.to_vec()),
462             (AppConfigTlvType::StaticStsIv, self.static_sts_iv.to_vec()),
463             (AppConfigTlvType::NumberOfStsSegments, u8_to_bytes(self.number_of_sts_segments)),
464             (AppConfigTlvType::MaxRrRetry, u16_to_bytes(self.max_rr_retry)),
465             (AppConfigTlvType::UwbInitiationTime, u32_to_bytes(self.uwb_initiation_time_ms)),
466             (AppConfigTlvType::HoppingMode, u8_to_bytes(self.hopping_mode as u8)),
467             (AppConfigTlvType::BlockStrideLength, u8_to_bytes(self.block_stride_length)),
468             (AppConfigTlvType::ResultReportConfig, u8_to_bytes(self.result_report_config.as_u8())),
469             (
470                 AppConfigTlvType::InBandTerminationAttemptCount,
471                 u8_to_bytes(self.in_band_termination_attempt_count),
472             ),
473             (AppConfigTlvType::SubSessionId, u32_to_bytes(self.sub_session_id)),
474             (AppConfigTlvType::BprfPhrDataRate, u8_to_bytes(self.bprf_phr_data_rate as u8)),
475             (
476                 AppConfigTlvType::MaxNumberOfMeasurements,
477                 u16_to_bytes(self.max_number_of_measurements),
478             ),
479             (AppConfigTlvType::StsLength, u8_to_bytes(self.sts_length as u8)),
480             (
481                 AppConfigTlvType::NbOfRangeMeasurements,
482                 u8_to_bytes(self.number_of_range_measurements),
483             ),
484             (
485                 AppConfigTlvType::NbOfAzimuthMeasurements,
486                 u8_to_bytes(self.number_of_aoa_azimuth_measurements),
487             ),
488             (
489                 AppConfigTlvType::NbOfElevationMeasurements,
490                 u8_to_bytes(self.number_of_aoa_elevation_measurements),
491             ),
492         ])
493     }
494 }
495 
496 /// The builder pattern for the FiraAppConfigParams.
497 pub struct FiraAppConfigParamsBuilder {
498     device_type: Option<DeviceType>,
499     ranging_round_usage: RangingRoundUsage,
500     sts_config: StsConfig,
501     multi_node_mode: Option<MultiNodeMode>,
502     channel_number: UwbChannel,
503     device_mac_address: Option<UwbAddress>,
504     dst_mac_address: Vec<UwbAddress>,
505     slot_duration_rstu: u16,
506     ranging_duration_ms: u32,
507     mac_fcs_type: MacFcsType,
508     ranging_round_control: RangingRoundControl,
509     aoa_result_request: AoaResultRequest,
510     range_data_ntf_config: RangeDataNtfConfig,
511     range_data_ntf_proximity_near_cm: u16,
512     range_data_ntf_proximity_far_cm: u16,
513     device_role: Option<DeviceRole>,
514     rframe_config: RframeConfig,
515     preamble_code_index: u8,
516     sfd_id: u8,
517     psdu_data_rate: PsduDataRate,
518     preamble_duration: PreambleDuration,
519     ranging_time_struct: RangingTimeStruct,
520     slots_per_rr: u8,
521     tx_adaptive_payload_power: TxAdaptivePayloadPower,
522     responder_slot_index: u8,
523     prf_mode: PrfMode,
524     scheduled_mode: ScheduledMode,
525     key_rotation: KeyRotation,
526     key_rotation_rate: u8,
527     session_priority: u8,
528     mac_address_mode: MacAddressMode,
529     vendor_id: Option<[u8; 2]>,
530     static_sts_iv: Option<[u8; 6]>,
531     number_of_sts_segments: u8,
532     max_rr_retry: u16,
533     uwb_initiation_time_ms: u32,
534     hopping_mode: HoppingMode,
535     block_stride_length: u8,
536     result_report_config: ResultReportConfig,
537     in_band_termination_attempt_count: u8,
538     sub_session_id: u32,
539     bprf_phr_data_rate: BprfPhrDataRate,
540     max_number_of_measurements: u16,
541     sts_length: StsLength,
542     number_of_range_measurements: u8,
543     number_of_aoa_azimuth_measurements: u8,
544     number_of_aoa_elevation_measurements: u8,
545 }
546 
547 #[allow(clippy::new_without_default)]
548 #[allow(missing_docs)]
549 impl FiraAppConfigParamsBuilder {
550     /// Fill the default value of each field if exists, otherwise put None.
new() -> Self551     pub fn new() -> Self {
552         Self {
553             device_type: None,
554             ranging_round_usage: DEFAULT_RANGING_ROUND_USAGE,
555             sts_config: DEFAULT_STS_CONFIG,
556             multi_node_mode: None,
557             channel_number: DEFAULT_CHANNEL_NUMBER,
558             device_mac_address: None,
559             dst_mac_address: vec![],
560             slot_duration_rstu: DEFAULT_SLOT_DURATION_RSTU,
561             ranging_duration_ms: DEFAULT_RANGING_DURATION_MS,
562             mac_fcs_type: DEFAULT_MAC_FCS_TYPE,
563             ranging_round_control: DEFAULT_RANGING_ROUND_CONTROL,
564             aoa_result_request: DEFAULT_AOA_RESULT_REQUEST,
565             range_data_ntf_config: DEFAULT_RANGE_DATA_NTF_CONFIG,
566             range_data_ntf_proximity_near_cm: DEFAULT_RANGE_DATA_NTF_PROXIMITY_NEAR_CM,
567             range_data_ntf_proximity_far_cm: DEFAULT_RANGE_DATA_NTF_PROXIMITY_FAR_CM,
568             device_role: None,
569             rframe_config: DEFAULT_RFRAME_CONFIG,
570             preamble_code_index: DEFAULT_PREAMBLE_CODE_INDEX,
571             sfd_id: DEFAULT_SFD_ID,
572             psdu_data_rate: DEFAULT_PSDU_DATA_RATE,
573             preamble_duration: DEFAULT_PREAMBLE_DURATION,
574             ranging_time_struct: DEFAULT_RANGING_TIME_STRUCT,
575             slots_per_rr: DEFAULT_SLOTS_PER_RR,
576             tx_adaptive_payload_power: DEFAULT_TX_ADAPTIVE_PAYLOAD_POWER,
577             responder_slot_index: DEFAULT_RESPONDER_SLOT_INDEX,
578             prf_mode: DEFAULT_PRF_MODE,
579             scheduled_mode: DEFAULT_SCHEDULED_MODE,
580             key_rotation: DEFAULT_KEY_ROTATION,
581             key_rotation_rate: DEFAULT_KEY_ROTATION_RATE,
582             session_priority: DEFAULT_SESSION_PRIORITY,
583             mac_address_mode: DEFAULT_MAC_ADDRESS_MODE,
584             vendor_id: None,
585             static_sts_iv: None,
586             number_of_sts_segments: DEFAULT_NUMBER_OF_STS_SEGMENTS,
587             max_rr_retry: DEFAULT_MAX_RR_RETRY,
588             uwb_initiation_time_ms: DEFAULT_UWB_INITIATION_TIME_MS,
589             hopping_mode: DEFAULT_HOPPING_MODE,
590             block_stride_length: DEFAULT_BLOCK_STRIDE_LENGTH,
591             result_report_config: DEFAULT_RESULT_REPORT_CONFIG,
592             in_band_termination_attempt_count: DEFAULT_IN_BAND_TERMINATION_ATTEMPT_COUNT,
593             sub_session_id: DEFAULT_SUB_SESSION_ID,
594             bprf_phr_data_rate: DEFAULT_BPRF_PHR_DATA_RATE,
595             max_number_of_measurements: DEFAULT_MAX_NUMBER_OF_MEASUREMENTS,
596             sts_length: DEFAULT_STS_LENGTH,
597             number_of_range_measurements: DEFAULT_NUMBER_OF_RANGE_MEASUREMENTS,
598             number_of_aoa_azimuth_measurements: DEFAULT_NUMBER_OF_AOA_AZIMUTH_MEASUREMENTS,
599             number_of_aoa_elevation_measurements: DEFAULT_NUMBER_OF_AOA_ELEVATION_MEASUREMENTS,
600         }
601     }
602 
from_params(params: &AppConfigParams) -> Option<Self>603     pub fn from_params(params: &AppConfigParams) -> Option<Self> {
604         match params {
605             AppConfigParams::Fira(params) => Some(Self {
606                 device_type: Some(params.device_type),
607                 ranging_round_usage: params.ranging_round_usage,
608                 sts_config: params.sts_config,
609                 multi_node_mode: Some(params.multi_node_mode),
610                 channel_number: params.channel_number,
611                 device_mac_address: Some(params.device_mac_address.clone()),
612                 dst_mac_address: params.dst_mac_address.clone(),
613                 slot_duration_rstu: params.slot_duration_rstu,
614                 ranging_duration_ms: params.ranging_duration_ms,
615                 mac_fcs_type: params.mac_fcs_type,
616                 ranging_round_control: params.ranging_round_control.clone(),
617                 aoa_result_request: params.aoa_result_request,
618                 range_data_ntf_config: params.range_data_ntf_config,
619                 range_data_ntf_proximity_near_cm: params.range_data_ntf_proximity_near_cm,
620                 range_data_ntf_proximity_far_cm: params.range_data_ntf_proximity_far_cm,
621                 device_role: Some(params.device_role),
622                 rframe_config: params.rframe_config,
623                 preamble_code_index: params.preamble_code_index,
624                 sfd_id: params.sfd_id,
625                 psdu_data_rate: params.psdu_data_rate,
626                 preamble_duration: params.preamble_duration,
627                 ranging_time_struct: params.ranging_time_struct,
628                 slots_per_rr: params.slots_per_rr,
629                 tx_adaptive_payload_power: params.tx_adaptive_payload_power,
630                 responder_slot_index: params.responder_slot_index,
631                 prf_mode: params.prf_mode,
632                 scheduled_mode: params.scheduled_mode,
633                 key_rotation: params.key_rotation,
634                 key_rotation_rate: params.key_rotation_rate,
635                 session_priority: params.session_priority,
636                 mac_address_mode: params.mac_address_mode,
637                 vendor_id: Some(params.vendor_id),
638                 static_sts_iv: Some(params.static_sts_iv),
639                 number_of_sts_segments: params.number_of_sts_segments,
640                 max_rr_retry: params.max_rr_retry,
641                 uwb_initiation_time_ms: params.uwb_initiation_time_ms,
642                 hopping_mode: params.hopping_mode,
643                 block_stride_length: params.block_stride_length,
644                 result_report_config: params.result_report_config.clone(),
645                 in_band_termination_attempt_count: params.in_band_termination_attempt_count,
646                 sub_session_id: params.sub_session_id,
647                 bprf_phr_data_rate: params.bprf_phr_data_rate,
648                 max_number_of_measurements: params.max_number_of_measurements,
649                 sts_length: params.sts_length,
650                 number_of_range_measurements: params.number_of_range_measurements,
651                 number_of_aoa_azimuth_measurements: params.number_of_aoa_azimuth_measurements,
652                 number_of_aoa_elevation_measurements: params.number_of_aoa_elevation_measurements,
653             }),
654             _ => None,
655         }
656     }
657 
build(&self) -> Option<AppConfigParams>658     pub fn build(&self) -> Option<AppConfigParams> {
659         let params = FiraAppConfigParams {
660             device_type: self.device_type?,
661             ranging_round_usage: self.ranging_round_usage,
662             sts_config: self.sts_config,
663             multi_node_mode: self.multi_node_mode?,
664             channel_number: self.channel_number,
665             device_mac_address: self.device_mac_address.clone()?,
666             dst_mac_address: self.dst_mac_address.clone(),
667             slot_duration_rstu: self.slot_duration_rstu,
668             ranging_duration_ms: self.ranging_duration_ms,
669             mac_fcs_type: self.mac_fcs_type,
670             ranging_round_control: self.ranging_round_control.clone(),
671             aoa_result_request: self.aoa_result_request,
672             range_data_ntf_config: self.range_data_ntf_config,
673             range_data_ntf_proximity_near_cm: self.range_data_ntf_proximity_near_cm,
674             range_data_ntf_proximity_far_cm: self.range_data_ntf_proximity_far_cm,
675             device_role: self.device_role?,
676             rframe_config: self.rframe_config,
677             preamble_code_index: self.preamble_code_index,
678             sfd_id: self.sfd_id,
679             psdu_data_rate: self.psdu_data_rate,
680             preamble_duration: self.preamble_duration,
681             ranging_time_struct: self.ranging_time_struct,
682             slots_per_rr: self.slots_per_rr,
683             tx_adaptive_payload_power: self.tx_adaptive_payload_power,
684             responder_slot_index: self.responder_slot_index,
685             prf_mode: self.prf_mode,
686             scheduled_mode: self.scheduled_mode,
687             key_rotation: self.key_rotation,
688             key_rotation_rate: self.key_rotation_rate,
689             session_priority: self.session_priority,
690             mac_address_mode: self.mac_address_mode,
691             vendor_id: self.vendor_id?,
692             static_sts_iv: self.static_sts_iv?,
693             number_of_sts_segments: self.number_of_sts_segments,
694             max_rr_retry: self.max_rr_retry,
695             uwb_initiation_time_ms: self.uwb_initiation_time_ms,
696             hopping_mode: self.hopping_mode,
697             block_stride_length: self.block_stride_length,
698             result_report_config: self.result_report_config.clone(),
699             in_band_termination_attempt_count: self.in_band_termination_attempt_count,
700             sub_session_id: self.sub_session_id,
701             bprf_phr_data_rate: self.bprf_phr_data_rate,
702             max_number_of_measurements: self.max_number_of_measurements,
703             sts_length: self.sts_length,
704             number_of_range_measurements: self.number_of_range_measurements,
705             number_of_aoa_azimuth_measurements: self.number_of_aoa_azimuth_measurements,
706             number_of_aoa_elevation_measurements: self.number_of_aoa_elevation_measurements,
707         };
708 
709         params.is_valid()?;
710         Some(AppConfigParams::Fira(params))
711     }
712 
713     // Generate the setter methods for all the fields.
714     builder_field!(device_type, DeviceType, Some);
715     builder_field!(ranging_round_usage, RangingRoundUsage);
716     builder_field!(sts_config, StsConfig);
717     builder_field!(multi_node_mode, MultiNodeMode, Some);
718     builder_field!(channel_number, UwbChannel);
719     builder_field!(device_mac_address, UwbAddress, Some);
720     builder_field!(dst_mac_address, Vec<UwbAddress>);
721     builder_field!(slot_duration_rstu, u16);
722     builder_field!(ranging_duration_ms, u32);
723     builder_field!(mac_fcs_type, MacFcsType);
724     builder_field!(ranging_round_control, RangingRoundControl);
725     builder_field!(aoa_result_request, AoaResultRequest);
726     builder_field!(range_data_ntf_config, RangeDataNtfConfig);
727     builder_field!(range_data_ntf_proximity_near_cm, u16);
728     builder_field!(range_data_ntf_proximity_far_cm, u16);
729     builder_field!(device_role, DeviceRole, Some);
730     builder_field!(rframe_config, RframeConfig);
731     builder_field!(preamble_code_index, u8);
732     builder_field!(sfd_id, u8);
733     builder_field!(psdu_data_rate, PsduDataRate);
734     builder_field!(preamble_duration, PreambleDuration);
735     builder_field!(ranging_time_struct, RangingTimeStruct);
736     builder_field!(slots_per_rr, u8);
737     builder_field!(tx_adaptive_payload_power, TxAdaptivePayloadPower);
738     builder_field!(responder_slot_index, u8);
739     builder_field!(prf_mode, PrfMode);
740     builder_field!(scheduled_mode, ScheduledMode);
741     builder_field!(key_rotation, KeyRotation);
742     builder_field!(key_rotation_rate, u8);
743     builder_field!(session_priority, u8);
744     builder_field!(mac_address_mode, MacAddressMode);
745     builder_field!(vendor_id, [u8; 2], Some);
746     builder_field!(static_sts_iv, [u8; 6], Some);
747     builder_field!(number_of_sts_segments, u8);
748     builder_field!(max_rr_retry, u16);
749     builder_field!(uwb_initiation_time_ms, u32);
750     builder_field!(hopping_mode, HoppingMode);
751     builder_field!(block_stride_length, u8);
752     builder_field!(result_report_config, ResultReportConfig);
753     builder_field!(in_band_termination_attempt_count, u8);
754     builder_field!(sub_session_id, u32);
755     builder_field!(bprf_phr_data_rate, BprfPhrDataRate);
756     builder_field!(max_number_of_measurements, u16);
757     builder_field!(sts_length, StsLength);
758     builder_field!(number_of_range_measurements, u8);
759     builder_field!(number_of_aoa_azimuth_measurements, u8);
760     builder_field!(number_of_aoa_elevation_measurements, u8);
761 }
762 
763 /// The device type.
764 #[repr(u8)]
765 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
766 pub enum DeviceType {
767     /// Controlee
768     Controlee = 0,
769     /// Controller
770     Controller = 1,
771 }
772 
773 /// The mode of ranging round usage.
774 #[repr(u8)]
775 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
776 pub enum RangingRoundUsage {
777     /// SS-TWR with Deferred Mode
778     SsTwr = 1,
779     /// DS-TWR with Deferred Mode (default)
780     DsTwr = 2,
781     /// SS-TWR with Non-deferred Mode
782     SsTwrNon = 3,
783     /// DS-TWR with Non-deferred Mode
784     DsTwrNon = 4,
785 }
786 
787 /// This parameter indicates how the system shall generate the STS.
788 #[repr(u8)]
789 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
790 pub enum StsConfig {
791     /// Static STS (default)
792     Static = 0,
793     /// Dynamic STS
794     Dynamic = 1,
795     /// Dynamic STS for Responder specific Sub-session Key
796     DynamicForControleeIndividualKey = 2,
797 }
798 
799 /// The mode of multi node.
800 #[repr(u8)]
801 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
802 pub enum MultiNodeMode {
803     /// Single device to Single device (Unicast)
804     Unicast = 0,
805     /// One to Many
806     OneToMany = 1,
807     /// Many to Many
808     ManyToMany = 2,
809 }
810 
811 /// The UWB channel number. (default = 9)
812 #[allow(missing_docs)]
813 #[repr(u8)]
814 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
815 pub enum UwbChannel {
816     Channel5 = 5,
817     Channel6 = 6,
818     Channel8 = 8,
819     Channel9 = 9,
820     Channel10 = 10,
821     Channel12 = 12,
822     Channel13 = 13,
823     Channel14 = 14,
824 }
825 
826 /// The UWB address.
827 #[derive(Debug, Clone, PartialEq, Eq)]
828 pub enum UwbAddress {
829     /// The short MAC address (2 bytes)
830     Short([u8; 2]),
831     /// The extended MAC address (8 bytes)
832     Extended([u8; 8]),
833 }
834 
835 impl From<UwbAddress> for Vec<u8> {
from(item: UwbAddress) -> Self836     fn from(item: UwbAddress) -> Self {
837         match item {
838             UwbAddress::Short(addr) => addr.to_vec(),
839             UwbAddress::Extended(addr) => addr.to_vec(),
840         }
841     }
842 }
843 
844 impl TryFrom<Vec<u8>> for UwbAddress {
845     type Error = &'static str;
try_from(value: Vec<u8>) -> Result<Self, Self::Error>846     fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
847         match value.len() {
848             2 => Ok(UwbAddress::Short(value.try_into().unwrap())),
849             8 => Ok(UwbAddress::Extended(value.try_into().unwrap())),
850             _ => Err("Invalid address length"),
851         }
852     }
853 }
854 
addresses_to_bytes(addresses: Vec<UwbAddress>) -> Vec<u8>855 fn addresses_to_bytes(addresses: Vec<UwbAddress>) -> Vec<u8> {
856     addresses.into_iter().flat_map(Into::<Vec<u8>>::into).collect()
857 }
858 
859 /// CRC type in MAC footer.
860 #[repr(u8)]
861 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
862 pub enum MacFcsType {
863     /// CRC 16 (default)
864     Crc16 = 0,
865     /// CRC 32
866     Crc32 = 1,
867 }
868 
869 /// This parameter is used to tell the UWBS which messages will be included in a Ranging Round.
870 #[derive(Debug, Clone, PartialEq, Eq)]
871 pub struct RangingRoundControl {
872     /// Ranging Result Report Message (RRRM)
873     ///
874     /// If set to true (default), a Controller shall schedule an RRRM in the Ranging Device
875     /// Management List (RDML).
876     /// If set to false, a Controller shall not schedule an RRRM in the RDML.
877     /// This field shall be ignored by a Controlee; Controlees shall follow the message sequence
878     /// provided in the RDML.
879     pub ranging_result_report_message: bool,
880     /// Control Message (CM)
881     ///
882     /// If set to true (default), a Controller shall send a separate CM and a Controlee shall expect
883     /// a separate CM.
884     /// If set to false, a Controller shall not send a separate CM and a Controlee shall not expect
885     /// a separate CM.
886     pub control_message: bool,
887     /// Measurement Report Message (MRM)
888     ///
889     /// If set to false (default), the controller shall schedule the MRM to be sent from the
890     /// initiator to the Responder(s) in the RDML.
891     /// If set to true, the controller shall schedule the MRM to be sent from the responder(s) to
892     /// the initiator in the RDML.
893     /// This field shall be ignored by a controlee. The controlees shall follow the message sequence
894     /// provided in the RDML
895     pub measurement_report_message: bool,
896 }
897 
898 impl RangingRoundControl {
899     const RANGING_RESULT_REPORT_MESSAGE_BIT_OFFSET: u8 = 0;
900     const CONTROL_MESSAGE_BIT_OFFSET: u8 = 1;
901     const MEASUREMENT_REPORT_MESSAGE_BIT_OFFSET: u8 = 7;
902 
as_u8(&self) -> u8903     fn as_u8(&self) -> u8 {
904         let mut value = 0_u8;
905         if self.ranging_result_report_message {
906             value |= 1 << Self::RANGING_RESULT_REPORT_MESSAGE_BIT_OFFSET;
907         }
908         if self.control_message {
909             value |= 1 << Self::CONTROL_MESSAGE_BIT_OFFSET;
910         }
911         if self.measurement_report_message {
912             value |= 1 << Self::MEASUREMENT_REPORT_MESSAGE_BIT_OFFSET;
913         }
914         value
915     }
916 }
917 
918 /// This parameter is used to configure AOA results in the range data notification.
919 #[repr(u8)]
920 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
921 pub enum AoaResultRequest {
922     /// Disable AOA
923     NoAoaReport = 0,
924     /// Enable AOA (default)
925     ReqAoaResults = 1,
926     /// Enable only AOA Azimuth
927     ReqAoaResultsAzimuthOnly = 2,
928     /// Enable only AOA Elevation
929     ReqAoaResultsElevationOnly = 3,
930     /// Enable AOA interleaved
931     ReqAoaResultsInterleaved = 0xF0,
932 }
933 
934 /// This config is used to enable/disable the range data notification.
935 #[repr(u8)]
936 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
937 pub enum RangeDataNtfConfig {
938     /// Disable range data notification
939     Disable = 0,
940     /// Enable range data notification (default)
941     Enable = 1,
942     /// Enable range data notification while in proximity range
943     EnableProximity = 2,
944 }
945 
946 /// The device role.
947 #[repr(u8)]
948 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
949 pub enum DeviceRole {
950     /// Responder of the session
951     Responder = 0,
952     /// Initiator of the session
953     Initiator = 1,
954 }
955 
956 /// Rframe config.
957 #[repr(u8)]
958 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
959 pub enum RframeConfig {
960     /// SP0
961     SP0 = 0,
962     /// SP1
963     SP1 = 1,
964     /// SP3 (default)
965     SP3 = 3,
966 }
967 
968 /// This value configures the data rate.
969 #[repr(u8)]
970 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
971 pub enum PsduDataRate {
972     /// 6.81 Mbps (default)
973     Rate6m81 = 0,
974     /// 7.80 Mbps
975     Rate7m80 = 1,
976     /// 27.2 Mbps
977     Rate27m2 = 2,
978     /// 31.2 Mbps
979     Rate31m2 = 3,
980     /// 850Kbps
981     Rate850k = 4,
982 }
983 
984 /// Preamble duration is same as Preamble Symbol Repetitions (PSR).
985 ///
986 /// Two configurations are possible. BPRF uses only 64 symbols. HPRF can use both.
987 #[repr(u8)]
988 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
989 pub enum PreambleDuration {
990     /// 32 symbols
991     T32Symbols = 0,
992     /// 64 symbols (default)
993     T64Symbols = 1,
994 }
995 
996 /// The type of ranging time scheduling.
997 #[repr(u8)]
998 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
999 pub enum RangingTimeStruct {
1000     /// Interval Based Scheduling
1001     IntervalBasedScheduling = 0,
1002     /// Block Based Scheduling (default)
1003     BlockBasedScheduling = 1,
1004 }
1005 
1006 /// This configuration is used to enable/disable adaptive payload power for TX.
1007 #[repr(u8)]
1008 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
1009 pub enum TxAdaptivePayloadPower {
1010     /// Disable (default)
1011     Disable = 0,
1012     /// Enable
1013     Enable = 1,
1014 }
1015 
1016 /// This parameter is used to configure the mean PRF.
1017 #[repr(u8)]
1018 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
1019 pub enum PrfMode {
1020     /// 62.4 MHz PRF. BPRF mode (default)
1021     Bprf = 0,
1022     /// 124.8 MHz PRF. HPRF mode
1023     HprfWith124_8MHz = 1,
1024     /// 249.6 MHz PRF. HPRF mode with data rate 27.2 and 31.2 Mbps
1025     HprfWith249_6MHz = 2,
1026 }
1027 
1028 /// This parameter is used to set the Multinode Ranging Type.
1029 #[repr(u8)]
1030 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
1031 pub enum ScheduledMode {
1032     /// Time scheduled ranging (default)
1033     TimeScheduledRanging = 1,
1034 }
1035 
1036 /// This configuration is used to enable/disable the key rotation feature during Dynamic STS
1037 /// ranging.
1038 #[repr(u8)]
1039 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
1040 pub enum KeyRotation {
1041     /// Disable (default)
1042     Disable = 0,
1043     /// Enable
1044     Enable = 1,
1045 }
1046 
1047 /// MAC Addressing mode to be used in UWBS.
1048 #[repr(u8)]
1049 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
1050 pub enum MacAddressMode {
1051     /// MAC address is 2 bytes and 2 bytes to be used in MAC header (default)
1052     MacAddress2Bytes = 0,
1053     /// MAC address is 8 bytes and 2 bytes to be used in MAC header
1054     MacAddress8Bytes2BytesHeader = 1,
1055     /// MAC address is 8 bytes and 8 bytes to be used in MAC header
1056     MacAddress8Bytes = 2,
1057 }
1058 
1059 /// This parameter is used to enable/disable the hopping.
1060 ///
1061 /// Note: This config is applicable only for controller and ignored in case of controlee.
1062 #[repr(u8)]
1063 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
1064 pub enum HoppingMode {
1065     /// Hopping Diable (default)
1066     Disable = 0,
1067     /// FiRa Hopping Enable
1068     FiraHoppingEnable = 1,
1069 }
1070 
1071 /// This config is used to enable/disable the result reports to be included in the RRRM.
1072 ///
1073 /// The ToF Report, AoA Azimuth Report and AoA Elevation Report parameters from the FiRa UWB MAC are
1074 /// negotiated OOB.
1075 #[derive(Debug, Clone, PartialEq, Eq)]
1076 pub struct ResultReportConfig {
1077     /// TOF report (false: Disable, true: Enable)
1078     pub tof: bool,
1079     /// AOA azimuth report (false: Disable, true: Enable)
1080     pub aoa_azimuth: bool,
1081     /// AOA elevation report (false: Disable, true: Enable)
1082     pub aoa_elevation: bool,
1083     /// AOA FOM report (false: Disable, true: Enable)
1084     pub aoa_fom: bool,
1085 }
1086 
1087 impl ResultReportConfig {
1088     const TOF_BIT_OFFSET: u8 = 0;
1089     const AOA_AZIMUTH_BIT_OFFSET: u8 = 1;
1090     const AOA_ELEVATION_BIT_OFFSET: u8 = 2;
1091     const AOA_FOM_BIT_OFFSET: u8 = 3;
1092 
as_u8(&self) -> u81093     fn as_u8(&self) -> u8 {
1094         let mut value = 0_u8;
1095         if self.tof {
1096             value |= 1 << Self::TOF_BIT_OFFSET;
1097         }
1098         if self.aoa_azimuth {
1099             value |= 1 << Self::AOA_AZIMUTH_BIT_OFFSET;
1100         }
1101         if self.aoa_elevation {
1102             value |= 1 << Self::AOA_ELEVATION_BIT_OFFSET;
1103         }
1104         if self.aoa_fom {
1105             value |= 1 << Self::AOA_FOM_BIT_OFFSET;
1106         }
1107 
1108         value
1109     }
1110 }
1111 
1112 /// The data rate for BPRF mode.
1113 #[repr(u8)]
1114 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
1115 pub enum BprfPhrDataRate {
1116     /// 850 kbps (default)
1117     Rate850k = 0,
1118     /// 6.81 Mbps
1119     Rate6m81 = 1,
1120 }
1121 
1122 /// The number of symbols in an STS segment.
1123 #[repr(u8)]
1124 #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
1125 pub enum StsLength {
1126     /// 32 symbols
1127     Length32 = 0,
1128     /// 64 symbols (default)
1129     Length64 = 1,
1130     /// 128 symbols
1131     Length128 = 2,
1132 }
1133 
1134 #[cfg(test)]
1135 mod tests {
1136     use super::*;
1137 
1138     use crate::utils::init_test_logging;
1139 
1140     #[test]
test_ok()1141     fn test_ok() {
1142         init_test_logging();
1143 
1144         let device_type = DeviceType::Controlee;
1145         let ranging_round_usage = RangingRoundUsage::SsTwr;
1146         let sts_config = StsConfig::DynamicForControleeIndividualKey;
1147         let multi_node_mode = MultiNodeMode::ManyToMany;
1148         let channel_number = UwbChannel::Channel10;
1149         let device_mac_address = [1, 2, 3, 4, 5, 6, 7, 8];
1150         let dst_mac_address1 = [2, 2, 3, 4, 5, 6, 7, 8];
1151         let dst_mac_address2 = [3, 2, 3, 4, 5, 6, 7, 8];
1152         let slot_duration_rstu = 0x0A28;
1153         let ranging_duration_ms = 100;
1154         let mac_fcs_type = MacFcsType::Crc32;
1155         let ranging_round_control = RangingRoundControl {
1156             ranging_result_report_message: false,
1157             control_message: true,
1158             measurement_report_message: false,
1159         };
1160         let aoa_result_request = AoaResultRequest::ReqAoaResultsInterleaved;
1161         let range_data_ntf_config = RangeDataNtfConfig::EnableProximity;
1162         let range_data_ntf_proximity_near_cm = 50;
1163         let range_data_ntf_proximity_far_cm = 200;
1164         let device_role = DeviceRole::Initiator;
1165         let rframe_config = RframeConfig::SP1;
1166         let preamble_code_index = 25;
1167         let sfd_id = 3;
1168         let psdu_data_rate = PsduDataRate::Rate7m80;
1169         let preamble_duration = PreambleDuration::T32Symbols;
1170         let slots_per_rr = 10;
1171         let tx_adaptive_payload_power = TxAdaptivePayloadPower::Enable;
1172         let prf_mode = PrfMode::HprfWith124_8MHz;
1173         let key_rotation = KeyRotation::Enable;
1174         let key_rotation_rate = 15;
1175         let session_priority = 100;
1176         let mac_address_mode = MacAddressMode::MacAddress8Bytes;
1177         let vendor_id = [0xFE, 0xDC];
1178         let static_sts_iv = [0xDF, 0xCE, 0xAB, 0x12, 0x34, 0x56];
1179         let number_of_sts_segments = 2;
1180         let max_rr_retry = 3;
1181         let uwb_initiation_time_ms = 100;
1182         let result_report_config =
1183             ResultReportConfig { tof: true, aoa_azimuth: true, aoa_elevation: true, aoa_fom: true };
1184         let in_band_termination_attempt_count = 8;
1185         let sub_session_id = 24;
1186         let sts_length = StsLength::Length128;
1187         let number_of_range_measurements = 1;
1188         let number_of_aoa_azimuth_measurements = 2;
1189         let number_of_aoa_elevation_measurements = 3;
1190 
1191         let mut builder = FiraAppConfigParamsBuilder::new();
1192         builder
1193             .device_type(device_type)
1194             .ranging_round_usage(ranging_round_usage)
1195             .sts_config(sts_config)
1196             .multi_node_mode(multi_node_mode)
1197             .channel_number(channel_number)
1198             .device_mac_address(UwbAddress::Extended(device_mac_address))
1199             .dst_mac_address(vec![
1200                 UwbAddress::Extended(dst_mac_address1),
1201                 UwbAddress::Extended(dst_mac_address2),
1202             ])
1203             .slot_duration_rstu(slot_duration_rstu)
1204             .ranging_duration_ms(ranging_duration_ms)
1205             .mac_fcs_type(mac_fcs_type)
1206             .ranging_round_control(ranging_round_control.clone())
1207             .aoa_result_request(aoa_result_request)
1208             .range_data_ntf_config(range_data_ntf_config)
1209             .range_data_ntf_proximity_near_cm(range_data_ntf_proximity_near_cm)
1210             .range_data_ntf_proximity_far_cm(range_data_ntf_proximity_far_cm)
1211             .device_role(device_role)
1212             .rframe_config(rframe_config)
1213             .preamble_code_index(preamble_code_index)
1214             .sfd_id(sfd_id)
1215             .psdu_data_rate(psdu_data_rate)
1216             .preamble_duration(preamble_duration)
1217             .slots_per_rr(slots_per_rr)
1218             .tx_adaptive_payload_power(tx_adaptive_payload_power)
1219             .prf_mode(prf_mode)
1220             .key_rotation(key_rotation)
1221             .key_rotation_rate(key_rotation_rate)
1222             .session_priority(session_priority)
1223             .mac_address_mode(mac_address_mode)
1224             .vendor_id(vendor_id)
1225             .static_sts_iv(static_sts_iv)
1226             .number_of_sts_segments(number_of_sts_segments)
1227             .max_rr_retry(max_rr_retry)
1228             .uwb_initiation_time_ms(uwb_initiation_time_ms)
1229             .result_report_config(result_report_config.clone())
1230             .in_band_termination_attempt_count(in_band_termination_attempt_count)
1231             .sub_session_id(sub_session_id)
1232             .sts_length(sts_length)
1233             .number_of_range_measurements(number_of_range_measurements)
1234             .number_of_aoa_azimuth_measurements(number_of_aoa_azimuth_measurements)
1235             .number_of_aoa_elevation_measurements(number_of_aoa_elevation_measurements);
1236         let params = builder.build().unwrap();
1237 
1238         // Verify the generated TLV.
1239         let config_map = params.generate_config_map();
1240         let expected_config_map = HashMap::from([
1241             (AppConfigTlvType::DeviceType, vec![device_type as u8]),
1242             (AppConfigTlvType::RangingRoundUsage, vec![ranging_round_usage as u8]),
1243             (AppConfigTlvType::StsConfig, vec![sts_config as u8]),
1244             (AppConfigTlvType::MultiNodeMode, vec![multi_node_mode as u8]),
1245             (AppConfigTlvType::ChannelNumber, vec![channel_number as u8]),
1246             (AppConfigTlvType::NoOfControlee, vec![2]),
1247             (AppConfigTlvType::DeviceMacAddress, device_mac_address.to_vec()),
1248             (
1249                 AppConfigTlvType::DstMacAddress,
1250                 [dst_mac_address1, dst_mac_address2].concat().to_vec(),
1251             ),
1252             (AppConfigTlvType::SlotDuration, slot_duration_rstu.to_le_bytes().to_vec()),
1253             (AppConfigTlvType::RangingDuration, ranging_duration_ms.to_le_bytes().to_vec()),
1254             (AppConfigTlvType::MacFcsType, vec![mac_fcs_type as u8]),
1255             (AppConfigTlvType::RangingRoundControl, vec![ranging_round_control.as_u8()]),
1256             (AppConfigTlvType::AoaResultReq, vec![aoa_result_request as u8]),
1257             (AppConfigTlvType::RngDataNtf, vec![range_data_ntf_config as u8]),
1258             (
1259                 AppConfigTlvType::RngDataNtfProximityNear,
1260                 range_data_ntf_proximity_near_cm.to_le_bytes().to_vec(),
1261             ),
1262             (
1263                 AppConfigTlvType::RngDataNtfProximityFar,
1264                 range_data_ntf_proximity_far_cm.to_le_bytes().to_vec(),
1265             ),
1266             (AppConfigTlvType::DeviceRole, vec![device_role as u8]),
1267             (AppConfigTlvType::RframeConfig, vec![rframe_config as u8]),
1268             (AppConfigTlvType::PreambleCodeIndex, vec![preamble_code_index]),
1269             (AppConfigTlvType::SfdId, vec![sfd_id]),
1270             (AppConfigTlvType::PsduDataRate, vec![psdu_data_rate as u8]),
1271             (AppConfigTlvType::PreambleDuration, vec![preamble_duration as u8]),
1272             (AppConfigTlvType::RangingTimeStruct, vec![DEFAULT_RANGING_TIME_STRUCT as u8]),
1273             (AppConfigTlvType::SlotsPerRr, vec![slots_per_rr]),
1274             (AppConfigTlvType::TxAdaptivePayloadPower, vec![tx_adaptive_payload_power as u8]),
1275             (AppConfigTlvType::ResponderSlotIndex, vec![DEFAULT_RESPONDER_SLOT_INDEX]),
1276             (AppConfigTlvType::PrfMode, vec![prf_mode as u8]),
1277             (AppConfigTlvType::ScheduledMode, vec![DEFAULT_SCHEDULED_MODE as u8]),
1278             (AppConfigTlvType::KeyRotation, vec![key_rotation as u8]),
1279             (AppConfigTlvType::KeyRotationRate, vec![key_rotation_rate]),
1280             (AppConfigTlvType::SessionPriority, vec![session_priority]),
1281             (AppConfigTlvType::MacAddressMode, vec![mac_address_mode as u8]),
1282             (AppConfigTlvType::VendorId, vendor_id.to_vec()),
1283             (AppConfigTlvType::StaticStsIv, static_sts_iv.to_vec()),
1284             (AppConfigTlvType::NumberOfStsSegments, vec![number_of_sts_segments]),
1285             (AppConfigTlvType::MaxRrRetry, max_rr_retry.to_le_bytes().to_vec()),
1286             (AppConfigTlvType::UwbInitiationTime, uwb_initiation_time_ms.to_le_bytes().to_vec()),
1287             (AppConfigTlvType::HoppingMode, vec![DEFAULT_HOPPING_MODE as u8]),
1288             (AppConfigTlvType::BlockStrideLength, vec![DEFAULT_BLOCK_STRIDE_LENGTH]),
1289             (AppConfigTlvType::ResultReportConfig, vec![result_report_config.as_u8()]),
1290             (
1291                 AppConfigTlvType::InBandTerminationAttemptCount,
1292                 vec![in_band_termination_attempt_count],
1293             ),
1294             (AppConfigTlvType::BprfPhrDataRate, vec![DEFAULT_BPRF_PHR_DATA_RATE as u8]),
1295             (
1296                 AppConfigTlvType::MaxNumberOfMeasurements,
1297                 DEFAULT_MAX_NUMBER_OF_MEASUREMENTS.to_le_bytes().to_vec(),
1298             ),
1299             (AppConfigTlvType::StsLength, vec![sts_length as u8]),
1300             (AppConfigTlvType::SubSessionId, sub_session_id.to_le_bytes().to_vec()),
1301             (AppConfigTlvType::NbOfRangeMeasurements, vec![number_of_range_measurements]),
1302             (AppConfigTlvType::NbOfAzimuthMeasurements, vec![number_of_aoa_azimuth_measurements]),
1303             (
1304                 AppConfigTlvType::NbOfElevationMeasurements,
1305                 vec![number_of_aoa_elevation_measurements],
1306             ),
1307         ]);
1308         assert_eq!(config_map, expected_config_map);
1309 
1310         // Update the value from the original builder.
1311         let updated_key_rotation_rate = 10;
1312         assert_ne!(key_rotation_rate, updated_key_rotation_rate);
1313         let expected_updated_config_map =
1314             HashMap::from([(AppConfigTlvType::KeyRotationRate, vec![updated_key_rotation_rate])]);
1315 
1316         let updated_params1 = builder.key_rotation_rate(updated_key_rotation_rate).build().unwrap();
1317         let updated_config_map1 = updated_params1
1318             .generate_updated_config_map(&params, SessionState::SessionStateIdle)
1319             .unwrap();
1320         assert_eq!(updated_config_map1, expected_updated_config_map);
1321 
1322         // Update the value from the params.
1323         let updated_params2 = FiraAppConfigParamsBuilder::from_params(&params)
1324             .unwrap()
1325             .key_rotation_rate(updated_key_rotation_rate)
1326             .build()
1327             .unwrap();
1328         let updated_config_map2 = updated_params2
1329             .generate_updated_config_map(&params, SessionState::SessionStateIdle)
1330             .unwrap();
1331         assert_eq!(updated_config_map2, expected_updated_config_map);
1332     }
1333 
1334     #[test]
test_update_config()1335     fn test_update_config() {
1336         let mut builder = FiraAppConfigParamsBuilder::new();
1337         builder
1338             .device_type(DeviceType::Controller)
1339             .multi_node_mode(MultiNodeMode::Unicast)
1340             .device_mac_address(UwbAddress::Short([1, 2]))
1341             .dst_mac_address(vec![UwbAddress::Short([3, 4])])
1342             .device_role(DeviceRole::Initiator)
1343             .vendor_id([0xFE, 0xDC])
1344             .static_sts_iv([0xDF, 0xCE, 0xAB, 0x12, 0x34, 0x56]);
1345         let params = builder.build().unwrap();
1346 
1347         builder.multi_node_mode(MultiNodeMode::OneToMany);
1348         let updated_params = builder.build().unwrap();
1349         // MultiNodeMode can be updated at idle state.
1350         assert!(updated_params
1351             .generate_updated_config_map(&params, SessionState::SessionStateIdle)
1352             .is_some());
1353         // MultiNodeMode cannot be updated at active state.
1354         assert!(updated_params
1355             .generate_updated_config_map(&params, SessionState::SessionStateActive)
1356             .is_none());
1357     }
1358 
1359     #[test]
test_redacted_pii_fields()1360     fn test_redacted_pii_fields() {
1361         let mut builder = FiraAppConfigParamsBuilder::new();
1362         builder
1363             .device_type(DeviceType::Controller)
1364             .multi_node_mode(MultiNodeMode::Unicast)
1365             .device_mac_address(UwbAddress::Short([1, 2]))
1366             .dst_mac_address(vec![UwbAddress::Short([3, 4])])
1367             .device_role(DeviceRole::Initiator)
1368             .vendor_id([0xFE, 0xDC])
1369             .static_sts_iv([0xDF, 0xCE, 0xAB, 0x12, 0x34, 0x56]);
1370         let params = builder.build().unwrap();
1371 
1372         let format_str = format!("{params:?}");
1373         assert!(format_str.contains("vendor_id: \"redacted\""));
1374         assert!(format_str.contains("static_sts_iv: \"redacted\""));
1375     }
1376 }
1377