• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 use std::collections::HashMap;
16 
17 use log::{error, warn};
18 
19 use crate::uci::params::{AppConfigTlv, AppConfigTlvType};
20 use crate::utils::builder_field;
21 
22 // The default value of each parameters.
23 const DEFAULT_RANGING_ROUND_USAGE: RangingRoundUsage = RangingRoundUsage::DsTwr;
24 const DEFAULT_STS_CONFIG: StsConfig = StsConfig::Static;
25 const DEFAULT_CHANNEL_NUMBER: UwbChannel = UwbChannel::Channel9;
26 const DEFAULT_SLOT_DURATION_RSTU: u16 = 2400;
27 const DEFAULT_RANGING_INTERVAL_MS: u32 = 200;
28 const DEFAULT_MAC_FCS_TYPE: MacFcsType = MacFcsType::Crc16;
29 const DEFAULT_RANGING_ROUND_CONTROL: RangingRoundControl = RangingRoundControl {
30     ranging_result_report_message: true,
31     control_message: true,
32     measurement_report_message: false,
33 };
34 const DEFAULT_AOA_RESULT_REQUEST: AoaResultRequest = AoaResultRequest::ReqAoaResults;
35 const DEFAULT_RANGE_DATA_NTF_CONFIG: RangeDataNtfConfig = RangeDataNtfConfig::Enable;
36 const DEFAULT_RANGE_DATA_NTF_PROXIMITY_NEAR_CM: u16 = 0;
37 const DEFAULT_RANGE_DATA_NTF_PROXIMITY_FAR_CM: u16 = 20000;
38 const DEFAULT_RFRAME_CONFIG: RframeConfig = RframeConfig::SP3;
39 const DEFAULT_PREAMBLE_CODE_INDEX: u8 = 10;
40 const DEFAULT_SFD_ID: u8 = 2;
41 const DEFAULT_PSDU_DATA_RATE: PsduDataRate = PsduDataRate::Rate6m81;
42 const DEFAULT_PREAMBLE_DURATION: PreambleDuration = PreambleDuration::T64Symbols;
43 const DEFAULT_RANGING_TIME_STRUCT: RangingTimeStruct = RangingTimeStruct::BlockBasedScheduling;
44 const DEFAULT_SLOTS_PER_RR: u8 = 25;
45 const DEFAULT_TX_ADAPTIVE_PAYLOAD_POWER: TxAdaptivePayloadPower = TxAdaptivePayloadPower::Disable;
46 const DEFAULT_RESPONDER_SLOT_INDEX: u8 = 1;
47 const DEFAULT_PRF_MODE: PrfMode = PrfMode::Bprf;
48 const DEFAULT_SCHEDULED_MODE: ScheduledMode = ScheduledMode::TimeScheduledRanging;
49 const DEFAULT_KEY_ROTATION: KeyRotation = KeyRotation::Disable;
50 const DEFAULT_KEY_ROTATION_RATE: u8 = 0;
51 const DEFAULT_SESSION_PRIORITY: u8 = 50;
52 const DEFAULT_MAC_ADDRESS_MODE: MacAddressMode = MacAddressMode::MacAddress2Bytes;
53 const DEFAULT_NUMBER_OF_STS_SEGMENTS: u8 = 1;
54 const DEFAULT_MAX_RR_RETRY: u16 = 0;
55 const DEFAULT_UWB_INITIATION_TIME_MS: u32 = 0;
56 const DEFAULT_HOPPING_MODE: HoppingMode = HoppingMode::Disable;
57 const DEFAULT_BLOCK_STRIDE_LENGTH: u8 = 0;
58 const DEFAULT_RESULT_REPORT_CONFIG: ResultReportConfig =
59     ResultReportConfig { tof: true, aoa_azimuth: false, aoa_elevation: false, aoa_fom: false };
60 const DEFAULT_IN_BAND_TERMINATION_ATTEMPT_COUNT: u8 = 1;
61 const DEFAULT_SUB_SESSION_ID: u32 = 0;
62 const DEFAULT_BPRF_PHR_DATA_RATE: BprfPhrDataRate = BprfPhrDataRate::Rate850k;
63 const DEFAULT_MAX_NUMBER_OF_MEASUREMENTS: u16 = 0;
64 const DEFAULT_STS_LENGTH: StsLength = StsLength::Length64;
65 const DEFAULT_NUMBER_OF_RANGE_MEASUREMENTS: u8 = 0;
66 const DEFAULT_NUMBER_OF_AOA_AZIMUTH_MEASUREMENTS: u8 = 0;
67 const DEFAULT_NUMBER_OF_AOA_ELEVATION_MEASUREMENTS: u8 = 0;
68 
69 /// The FiRa's application configuration parameters.
70 /// Ref: FiRa Consortium UWB Command Interface Generic Techinal Specification Version 1.1.0.
71 #[derive(Debug, Clone, PartialEq, Eq)]
72 pub struct FiraAppConfigParams {
73     // FiRa standard config.
74     device_type: DeviceType,
75     ranging_round_usage: RangingRoundUsage,
76     sts_config: StsConfig,
77     multi_node_mode: MultiNodeMode,
78     channel_number: UwbChannel,
79     device_mac_address: UwbAddress,
80     dst_mac_address: Vec<UwbAddress>,
81     slot_duration_rstu: u16,
82     ranging_interval_ms: u32,
83     mac_fcs_type: MacFcsType,
84     ranging_round_control: RangingRoundControl,
85     aoa_result_request: AoaResultRequest,
86     range_data_ntf_config: RangeDataNtfConfig,
87     range_data_ntf_proximity_near_cm: u16,
88     range_data_ntf_proximity_far_cm: u16,
89     device_role: DeviceRole,
90     rframe_config: RframeConfig,
91     preamble_code_index: u8,
92     sfd_id: u8,
93     psdu_data_rate: PsduDataRate,
94     preamble_duration: PreambleDuration,
95     ranging_time_struct: RangingTimeStruct,
96     slots_per_rr: u8,
97     tx_adaptive_payload_power: TxAdaptivePayloadPower,
98     responder_slot_index: u8,
99     prf_mode: PrfMode,
100     scheduled_mode: ScheduledMode,
101     key_rotation: KeyRotation,
102     key_rotation_rate: u8,
103     session_priority: u8,
104     mac_address_mode: MacAddressMode,
105     vendor_id: [u8; 2],
106     static_sts_iv: [u8; 6],
107     number_of_sts_segments: u8,
108     max_rr_retry: u16,
109     uwb_initiation_time_ms: u32,
110     hopping_mode: HoppingMode,
111     block_stride_length: u8,
112     result_report_config: ResultReportConfig,
113     in_band_termination_attempt_count: u8,
114     sub_session_id: u32,
115     bprf_phr_data_rate: BprfPhrDataRate,
116     max_number_of_measurements: u16,
117     sts_length: StsLength,
118 
119     // Android-specific app config.
120     number_of_range_measurements: u8,
121     number_of_aoa_azimuth_measurements: u8,
122     number_of_aoa_elevation_measurements: u8,
123 }
124 
125 impl FiraAppConfigParams {
126     /// validate if the params are valid.
is_valid(&self) -> Option<()>127     fn is_valid(&self) -> Option<()> {
128         if self.device_type == DeviceType::Controlee {
129             if self.ranging_round_control.ranging_result_report_message {
130                 warn!("The RRRM bit is ignored by a controlee");
131             }
132             if self.ranging_round_control.measurement_report_message {
133                 warn!("The MRM bit is ignored by a controlee");
134             }
135             if self.hopping_mode != HoppingMode::Disable {
136                 warn!("hopping_mode is ignored by a controlee");
137             }
138             if self.block_stride_length != 0 {
139                 warn!("block_stride_length is ignored by a controlee");
140             }
141         }
142         if self.ranging_time_struct != RangingTimeStruct::BlockBasedScheduling
143             && self.block_stride_length != 0
144         {
145             warn!(
146                 "block_stride_length is ignored when ranging_time_struct not BlockBasedScheduling"
147             );
148         }
149         if self.prf_mode != PrfMode::Bprf && self.bprf_phr_data_rate != BprfPhrDataRate::Rate850k {
150             warn!("BPRF_PHR_DATA_RATE is ignored when prf_mode not BPRF");
151         }
152 
153         validate(
154             (1..=8).contains(&self.dst_mac_address.len()),
155             "The length of dst_mac_address should be between 1 to 8",
156         )?;
157         validate(
158             (0..=15).contains(&self.key_rotation_rate),
159             "key_rotation_rate should be between 0 to 15",
160         )?;
161         validate(
162             (1..=100).contains(&self.session_priority),
163             "session_priority should be between 1 to 100",
164         )?;
165         validate(
166             (0..=10000).contains(&self.uwb_initiation_time_ms),
167             "uwb_initiation_time_ms should be between 0 to 10000",
168         )?;
169         validate(
170             (1..=10).contains(&self.in_band_termination_attempt_count),
171             "in_band_termination_attempt_count should be between 1 to 10",
172         )?;
173 
174         match self.mac_address_mode {
175             MacAddressMode::MacAddress2Bytes | MacAddressMode::MacAddress8Bytes2BytesHeader => {
176                 validate(
177                     matches!(self.device_mac_address, UwbAddress::Short(_)),
178                     "device_mac_address should be short address",
179                 )?;
180                 validate(
181                     self.dst_mac_address.iter().all(|addr| matches!(addr, UwbAddress::Short(_))),
182                     "dst_mac_address should be short address",
183                 )?;
184             }
185             MacAddressMode::MacAddress8Bytes => {
186                 validate(
187                     matches!(self.device_mac_address, UwbAddress::Extended(_)),
188                     "device_mac_address should be extended address",
189                 )?;
190                 validate(
191                     self.dst_mac_address.iter().all(|addr| matches!(addr, UwbAddress::Extended(_))),
192                     "dst_mac_address should be extended address",
193                 )?;
194             }
195         }
196 
197         match self.prf_mode {
198             PrfMode::Bprf => {
199                 validate(
200                     (9..=12).contains(&self.preamble_code_index),
201                     "preamble_code_index should be between 9 to 12 when BPRF",
202                 )?;
203                 validate([0, 2].contains(&self.sfd_id), "sfd_id should be 0 or 2 when BPRF")?;
204                 validate(
205                     self.preamble_duration == PreambleDuration::T64Symbols,
206                     "preamble_duration should be 64 symbols when BPRF",
207                 )?;
208             }
209             _ => {
210                 validate(
211                     (25..=32).contains(&self.preamble_code_index),
212                     "preamble_code_index should be between 25 to 32 when HPRF",
213                 )?;
214                 validate(
215                     (1..=4).contains(&self.sfd_id),
216                     "sfd_id should be between 1 to 4 when HPRF",
217                 )?;
218             }
219         }
220 
221         match self.rframe_config {
222             RframeConfig::SP0 => {
223                 validate(
224                     self.number_of_sts_segments == 0,
225                     "number_of_sts_segments should be 0 when SP0",
226                 )?;
227             }
228             RframeConfig::SP1 | RframeConfig::SP3 => match self.prf_mode {
229                 PrfMode::Bprf => {
230                     validate(
231                         self.number_of_sts_segments == 1,
232                         "number_of_sts_segments should be 1 when SP1/SP3 and BPRF",
233                     )?;
234                 }
235                 _ => {
236                     validate(
237                         [1, 2, 3, 4].contains(&self.number_of_sts_segments),
238                         "number_of_sts_segments should be between 1 to 4 when SP1/SP3 and HPRF",
239                     )?;
240                 }
241             },
242         }
243 
244         match self.aoa_result_request {
245             AoaResultRequest::ReqAoaResultsInterleaved => {
246                 validate(
247                     self.is_any_number_of_measurement_set(),
248                     "At least one of the ratio params should be set for interleaving mode",
249                 );
250             }
251             _ => {
252                 validate(
253                     !self.is_any_number_of_measurement_set(),
254                     "All of the ratio params should not be set for non-interleaving mode",
255                 );
256             }
257         }
258 
259         Some(())
260     }
261 
is_any_number_of_measurement_set(&self) -> bool262     fn is_any_number_of_measurement_set(&self) -> bool {
263         self.number_of_range_measurements != DEFAULT_NUMBER_OF_RANGE_MEASUREMENTS
264             || self.number_of_aoa_azimuth_measurements != DEFAULT_NUMBER_OF_AOA_AZIMUTH_MEASUREMENTS
265             || self.number_of_aoa_elevation_measurements
266                 != DEFAULT_NUMBER_OF_AOA_ELEVATION_MEASUREMENTS
267     }
268 
269     /// Generate the TLV list from the params.
generate_tlvs(&self) -> Vec<AppConfigTlv>270     pub fn generate_tlvs(&self) -> Vec<AppConfigTlv> {
271         Self::config_map_to_tlvs(self.generate_config_map())
272     }
273 
274     /// Generate the updated TLV list from the difference between this and the previous params.
generate_updated_tlvs(&self, prev_params: &Self) -> Vec<AppConfigTlv>275     pub fn generate_updated_tlvs(&self, prev_params: &Self) -> Vec<AppConfigTlv> {
276         Self::config_map_to_tlvs(self.generate_updated_config_map(prev_params))
277     }
278 
generate_config_map(&self) -> HashMap<AppConfigTlvType, Vec<u8>>279     fn generate_config_map(&self) -> HashMap<AppConfigTlvType, Vec<u8>> {
280         debug_assert!(self.is_valid().is_some());
281 
282         HashMap::from([
283             (AppConfigTlvType::DeviceType, u8_to_bytes(self.device_type as u8)),
284             (AppConfigTlvType::RangingRoundUsage, u8_to_bytes(self.ranging_round_usage as u8)),
285             (AppConfigTlvType::StsConfig, u8_to_bytes(self.sts_config as u8)),
286             (AppConfigTlvType::MultiNodeMode, u8_to_bytes(self.multi_node_mode as u8)),
287             (AppConfigTlvType::ChannelNumber, u8_to_bytes(self.channel_number as u8)),
288             (AppConfigTlvType::NoOfControlee, u8_to_bytes(self.dst_mac_address.len() as u8)),
289             (AppConfigTlvType::DeviceMacAddress, self.device_mac_address.clone().into()),
290             (AppConfigTlvType::DstMacAddress, addresses_to_bytes(self.dst_mac_address.clone())),
291             (AppConfigTlvType::SlotDuration, u16_to_bytes(self.slot_duration_rstu)),
292             (AppConfigTlvType::RangingInterval, u32_to_bytes(self.ranging_interval_ms)),
293             (AppConfigTlvType::MacFcsType, u8_to_bytes(self.mac_fcs_type as u8)),
294             (
295                 AppConfigTlvType::RangingRoundControl,
296                 u8_to_bytes(self.ranging_round_control.as_u8()),
297             ),
298             (AppConfigTlvType::AoaResultReq, u8_to_bytes(self.aoa_result_request as u8)),
299             (AppConfigTlvType::RngDataNtf, u8_to_bytes(self.range_data_ntf_config as u8)),
300             (
301                 AppConfigTlvType::RngDataNtfProximityNear,
302                 u16_to_bytes(self.range_data_ntf_proximity_near_cm),
303             ),
304             (
305                 AppConfigTlvType::RngDataNtfProximityFar,
306                 u16_to_bytes(self.range_data_ntf_proximity_far_cm),
307             ),
308             (AppConfigTlvType::DeviceRole, u8_to_bytes(self.device_role as u8)),
309             (AppConfigTlvType::RframeConfig, u8_to_bytes(self.rframe_config as u8)),
310             (AppConfigTlvType::PreambleCodeIndex, u8_to_bytes(self.preamble_code_index)),
311             (AppConfigTlvType::SfdId, u8_to_bytes(self.sfd_id)),
312             (AppConfigTlvType::PsduDataRate, u8_to_bytes(self.psdu_data_rate as u8)),
313             (AppConfigTlvType::PreambleDuration, u8_to_bytes(self.preamble_duration as u8)),
314             (AppConfigTlvType::RangingTimeStruct, u8_to_bytes(self.ranging_time_struct as u8)),
315             (AppConfigTlvType::SlotsPerRr, u8_to_bytes(self.slots_per_rr)),
316             (
317                 AppConfigTlvType::TxAdaptivePayloadPower,
318                 u8_to_bytes(self.tx_adaptive_payload_power as u8),
319             ),
320             (AppConfigTlvType::ResponderSlotIndex, u8_to_bytes(self.responder_slot_index)),
321             (AppConfigTlvType::PrfMode, u8_to_bytes(self.prf_mode as u8)),
322             (AppConfigTlvType::ScheduledMode, u8_to_bytes(self.scheduled_mode as u8)),
323             (AppConfigTlvType::KeyRotation, u8_to_bytes(self.key_rotation as u8)),
324             (AppConfigTlvType::KeyRotationRate, u8_to_bytes(self.key_rotation_rate)),
325             (AppConfigTlvType::SessionPriority, u8_to_bytes(self.session_priority)),
326             (AppConfigTlvType::MacAddressMode, u8_to_bytes(self.mac_address_mode as u8)),
327             (AppConfigTlvType::VendorId, self.vendor_id.to_vec()),
328             (AppConfigTlvType::StaticStsIv, self.static_sts_iv.to_vec()),
329             (AppConfigTlvType::NumberOfStsSegments, u8_to_bytes(self.number_of_sts_segments)),
330             (AppConfigTlvType::MaxRrRetry, u16_to_bytes(self.max_rr_retry)),
331             (AppConfigTlvType::UwbInitiationTime, u32_to_bytes(self.uwb_initiation_time_ms)),
332             (AppConfigTlvType::HoppingMode, u8_to_bytes(self.hopping_mode as u8)),
333             (AppConfigTlvType::BlockStrideLength, u8_to_bytes(self.block_stride_length)),
334             (AppConfigTlvType::ResultReportConfig, u8_to_bytes(self.result_report_config.as_u8())),
335             (
336                 AppConfigTlvType::InBandTerminationAttemptCount,
337                 u8_to_bytes(self.in_band_termination_attempt_count),
338             ),
339             (AppConfigTlvType::SubSessionId, u32_to_bytes(self.sub_session_id)),
340             (AppConfigTlvType::BprfPhrDataRate, u8_to_bytes(self.bprf_phr_data_rate as u8)),
341             (
342                 AppConfigTlvType::MaxNumberOfMeasurements,
343                 u16_to_bytes(self.max_number_of_measurements),
344             ),
345             (AppConfigTlvType::StsLength, u8_to_bytes(self.sts_length as u8)),
346             (
347                 AppConfigTlvType::NbOfRangeMeasurements,
348                 u8_to_bytes(self.number_of_range_measurements),
349             ),
350             (
351                 AppConfigTlvType::NbOfAzimuthMeasurements,
352                 u8_to_bytes(self.number_of_aoa_azimuth_measurements),
353             ),
354             (
355                 AppConfigTlvType::NbOfElevationMeasurements,
356                 u8_to_bytes(self.number_of_aoa_elevation_measurements),
357             ),
358         ])
359     }
360 
generate_updated_config_map( &self, prev_params: &Self, ) -> HashMap<AppConfigTlvType, Vec<u8>>361     fn generate_updated_config_map(
362         &self,
363         prev_params: &Self,
364     ) -> HashMap<AppConfigTlvType, Vec<u8>> {
365         let config_map = self.generate_config_map();
366         let prev_config_map = prev_params.generate_config_map();
367 
368         let mut updated_config_map = HashMap::new();
369         for (key, value) in config_map.into_iter() {
370             if !matches!(prev_config_map.get(&key), Some(prev_value) if prev_value == &value) {
371                 updated_config_map.insert(key, value);
372             }
373         }
374         updated_config_map
375     }
376 
config_map_to_tlvs(config_map: HashMap<AppConfigTlvType, Vec<u8>>) -> Vec<AppConfigTlv>377     fn config_map_to_tlvs(config_map: HashMap<AppConfigTlvType, Vec<u8>>) -> Vec<AppConfigTlv> {
378         config_map.into_iter().map(|(cfg_id, v)| AppConfigTlv { cfg_id, v }).collect()
379     }
380 }
381 
382 pub struct FiraAppConfigParamsBuilder {
383     device_type: Option<DeviceType>,
384     ranging_round_usage: RangingRoundUsage,
385     sts_config: StsConfig,
386     multi_node_mode: Option<MultiNodeMode>,
387     channel_number: UwbChannel,
388     device_mac_address: Option<UwbAddress>,
389     dst_mac_address: Vec<UwbAddress>,
390     slot_duration_rstu: u16,
391     ranging_interval_ms: u32,
392     mac_fcs_type: MacFcsType,
393     ranging_round_control: RangingRoundControl,
394     aoa_result_request: AoaResultRequest,
395     range_data_ntf_config: RangeDataNtfConfig,
396     range_data_ntf_proximity_near_cm: u16,
397     range_data_ntf_proximity_far_cm: u16,
398     device_role: Option<DeviceRole>,
399     rframe_config: RframeConfig,
400     preamble_code_index: u8,
401     sfd_id: u8,
402     psdu_data_rate: PsduDataRate,
403     preamble_duration: PreambleDuration,
404     ranging_time_struct: RangingTimeStruct,
405     slots_per_rr: u8,
406     tx_adaptive_payload_power: TxAdaptivePayloadPower,
407     responder_slot_index: u8,
408     prf_mode: PrfMode,
409     scheduled_mode: ScheduledMode,
410     key_rotation: KeyRotation,
411     key_rotation_rate: u8,
412     session_priority: u8,
413     mac_address_mode: MacAddressMode,
414     vendor_id: Option<[u8; 2]>,
415     static_sts_iv: Option<[u8; 6]>,
416     number_of_sts_segments: u8,
417     max_rr_retry: u16,
418     uwb_initiation_time_ms: u32,
419     hopping_mode: HoppingMode,
420     block_stride_length: u8,
421     result_report_config: ResultReportConfig,
422     in_band_termination_attempt_count: u8,
423     sub_session_id: u32,
424     bprf_phr_data_rate: BprfPhrDataRate,
425     max_number_of_measurements: u16,
426     sts_length: StsLength,
427     number_of_range_measurements: u8,
428     number_of_aoa_azimuth_measurements: u8,
429     number_of_aoa_elevation_measurements: u8,
430 }
431 
432 impl FiraAppConfigParamsBuilder {
433     /// Fill the default value of each field if exists, otherwise put None.
new() -> Self434     pub fn new() -> Self {
435         Self {
436             device_type: None,
437             ranging_round_usage: DEFAULT_RANGING_ROUND_USAGE,
438             sts_config: DEFAULT_STS_CONFIG,
439             multi_node_mode: None,
440             channel_number: DEFAULT_CHANNEL_NUMBER,
441             device_mac_address: None,
442             dst_mac_address: vec![],
443             slot_duration_rstu: DEFAULT_SLOT_DURATION_RSTU,
444             ranging_interval_ms: DEFAULT_RANGING_INTERVAL_MS,
445             mac_fcs_type: DEFAULT_MAC_FCS_TYPE,
446             ranging_round_control: DEFAULT_RANGING_ROUND_CONTROL,
447             aoa_result_request: DEFAULT_AOA_RESULT_REQUEST,
448             range_data_ntf_config: DEFAULT_RANGE_DATA_NTF_CONFIG,
449             range_data_ntf_proximity_near_cm: DEFAULT_RANGE_DATA_NTF_PROXIMITY_NEAR_CM,
450             range_data_ntf_proximity_far_cm: DEFAULT_RANGE_DATA_NTF_PROXIMITY_FAR_CM,
451             device_role: None,
452             rframe_config: DEFAULT_RFRAME_CONFIG,
453             preamble_code_index: DEFAULT_PREAMBLE_CODE_INDEX,
454             sfd_id: DEFAULT_SFD_ID,
455             psdu_data_rate: DEFAULT_PSDU_DATA_RATE,
456             preamble_duration: DEFAULT_PREAMBLE_DURATION,
457             ranging_time_struct: DEFAULT_RANGING_TIME_STRUCT,
458             slots_per_rr: DEFAULT_SLOTS_PER_RR,
459             tx_adaptive_payload_power: DEFAULT_TX_ADAPTIVE_PAYLOAD_POWER,
460             responder_slot_index: DEFAULT_RESPONDER_SLOT_INDEX,
461             prf_mode: DEFAULT_PRF_MODE,
462             scheduled_mode: DEFAULT_SCHEDULED_MODE,
463             key_rotation: DEFAULT_KEY_ROTATION,
464             key_rotation_rate: DEFAULT_KEY_ROTATION_RATE,
465             session_priority: DEFAULT_SESSION_PRIORITY,
466             mac_address_mode: DEFAULT_MAC_ADDRESS_MODE,
467             vendor_id: None,
468             static_sts_iv: None,
469             number_of_sts_segments: DEFAULT_NUMBER_OF_STS_SEGMENTS,
470             max_rr_retry: DEFAULT_MAX_RR_RETRY,
471             uwb_initiation_time_ms: DEFAULT_UWB_INITIATION_TIME_MS,
472             hopping_mode: DEFAULT_HOPPING_MODE,
473             block_stride_length: DEFAULT_BLOCK_STRIDE_LENGTH,
474             result_report_config: DEFAULT_RESULT_REPORT_CONFIG,
475             in_band_termination_attempt_count: DEFAULT_IN_BAND_TERMINATION_ATTEMPT_COUNT,
476             sub_session_id: DEFAULT_SUB_SESSION_ID,
477             bprf_phr_data_rate: DEFAULT_BPRF_PHR_DATA_RATE,
478             max_number_of_measurements: DEFAULT_MAX_NUMBER_OF_MEASUREMENTS,
479             sts_length: DEFAULT_STS_LENGTH,
480             number_of_range_measurements: DEFAULT_NUMBER_OF_RANGE_MEASUREMENTS,
481             number_of_aoa_azimuth_measurements: DEFAULT_NUMBER_OF_AOA_AZIMUTH_MEASUREMENTS,
482             number_of_aoa_elevation_measurements: DEFAULT_NUMBER_OF_AOA_ELEVATION_MEASUREMENTS,
483         }
484     }
485 
from_params(params: &FiraAppConfigParams) -> Self486     pub fn from_params(params: &FiraAppConfigParams) -> Self {
487         Self {
488             device_type: Some(params.device_type),
489             ranging_round_usage: params.ranging_round_usage,
490             sts_config: params.sts_config,
491             multi_node_mode: Some(params.multi_node_mode),
492             channel_number: params.channel_number,
493             device_mac_address: Some(params.device_mac_address.clone()),
494             dst_mac_address: params.dst_mac_address.clone(),
495             slot_duration_rstu: params.slot_duration_rstu,
496             ranging_interval_ms: params.ranging_interval_ms,
497             mac_fcs_type: params.mac_fcs_type,
498             ranging_round_control: params.ranging_round_control.clone(),
499             aoa_result_request: params.aoa_result_request,
500             range_data_ntf_config: params.range_data_ntf_config,
501             range_data_ntf_proximity_near_cm: params.range_data_ntf_proximity_near_cm,
502             range_data_ntf_proximity_far_cm: params.range_data_ntf_proximity_far_cm,
503             device_role: Some(params.device_role),
504             rframe_config: params.rframe_config,
505             preamble_code_index: params.preamble_code_index,
506             sfd_id: params.sfd_id,
507             psdu_data_rate: params.psdu_data_rate,
508             preamble_duration: params.preamble_duration,
509             ranging_time_struct: params.ranging_time_struct,
510             slots_per_rr: params.slots_per_rr,
511             tx_adaptive_payload_power: params.tx_adaptive_payload_power,
512             responder_slot_index: params.responder_slot_index,
513             prf_mode: params.prf_mode,
514             scheduled_mode: params.scheduled_mode,
515             key_rotation: params.key_rotation,
516             key_rotation_rate: params.key_rotation_rate,
517             session_priority: params.session_priority,
518             mac_address_mode: params.mac_address_mode,
519             vendor_id: Some(params.vendor_id),
520             static_sts_iv: Some(params.static_sts_iv),
521             number_of_sts_segments: params.number_of_sts_segments,
522             max_rr_retry: params.max_rr_retry,
523             uwb_initiation_time_ms: params.uwb_initiation_time_ms,
524             hopping_mode: params.hopping_mode,
525             block_stride_length: params.block_stride_length,
526             result_report_config: params.result_report_config.clone(),
527             in_band_termination_attempt_count: params.in_band_termination_attempt_count,
528             sub_session_id: params.sub_session_id,
529             bprf_phr_data_rate: params.bprf_phr_data_rate,
530             max_number_of_measurements: params.max_number_of_measurements,
531             sts_length: params.sts_length,
532             number_of_range_measurements: params.number_of_range_measurements,
533             number_of_aoa_azimuth_measurements: params.number_of_aoa_azimuth_measurements,
534             number_of_aoa_elevation_measurements: params.number_of_aoa_elevation_measurements,
535         }
536     }
537 
build(&self) -> Option<FiraAppConfigParams>538     pub fn build(&self) -> Option<FiraAppConfigParams> {
539         let params = FiraAppConfigParams {
540             device_type: self.device_type?,
541             ranging_round_usage: self.ranging_round_usage,
542             sts_config: self.sts_config,
543             multi_node_mode: self.multi_node_mode?,
544             channel_number: self.channel_number,
545             device_mac_address: self.device_mac_address.clone()?,
546             dst_mac_address: self.dst_mac_address.clone(),
547             slot_duration_rstu: self.slot_duration_rstu,
548             ranging_interval_ms: self.ranging_interval_ms,
549             mac_fcs_type: self.mac_fcs_type,
550             ranging_round_control: self.ranging_round_control.clone(),
551             aoa_result_request: self.aoa_result_request,
552             range_data_ntf_config: self.range_data_ntf_config,
553             range_data_ntf_proximity_near_cm: self.range_data_ntf_proximity_near_cm,
554             range_data_ntf_proximity_far_cm: self.range_data_ntf_proximity_far_cm,
555             device_role: self.device_role?,
556             rframe_config: self.rframe_config,
557             preamble_code_index: self.preamble_code_index,
558             sfd_id: self.sfd_id,
559             psdu_data_rate: self.psdu_data_rate,
560             preamble_duration: self.preamble_duration,
561             ranging_time_struct: self.ranging_time_struct,
562             slots_per_rr: self.slots_per_rr,
563             tx_adaptive_payload_power: self.tx_adaptive_payload_power,
564             responder_slot_index: self.responder_slot_index,
565             prf_mode: self.prf_mode,
566             scheduled_mode: self.scheduled_mode,
567             key_rotation: self.key_rotation,
568             key_rotation_rate: self.key_rotation_rate,
569             session_priority: self.session_priority,
570             mac_address_mode: self.mac_address_mode,
571             vendor_id: self.vendor_id?,
572             static_sts_iv: self.static_sts_iv?,
573             number_of_sts_segments: self.number_of_sts_segments,
574             max_rr_retry: self.max_rr_retry,
575             uwb_initiation_time_ms: self.uwb_initiation_time_ms,
576             hopping_mode: self.hopping_mode,
577             block_stride_length: self.block_stride_length,
578             result_report_config: self.result_report_config.clone(),
579             in_band_termination_attempt_count: self.in_band_termination_attempt_count,
580             sub_session_id: self.sub_session_id,
581             bprf_phr_data_rate: self.bprf_phr_data_rate,
582             max_number_of_measurements: self.max_number_of_measurements,
583             sts_length: self.sts_length,
584             number_of_range_measurements: self.number_of_range_measurements,
585             number_of_aoa_azimuth_measurements: self.number_of_aoa_azimuth_measurements,
586             number_of_aoa_elevation_measurements: self.number_of_aoa_elevation_measurements,
587         };
588 
589         params.is_valid()?;
590         Some(params)
591     }
592 
593     // Generate the setter methods for all the fields.
594     builder_field!(device_type, DeviceType, Some);
595     builder_field!(ranging_round_usage, RangingRoundUsage);
596     builder_field!(sts_config, StsConfig);
597     builder_field!(multi_node_mode, MultiNodeMode, Some);
598     builder_field!(channel_number, UwbChannel);
599     builder_field!(device_mac_address, UwbAddress, Some);
600     builder_field!(dst_mac_address, Vec<UwbAddress>);
601     builder_field!(slot_duration_rstu, u16);
602     builder_field!(ranging_interval_ms, u32);
603     builder_field!(mac_fcs_type, MacFcsType);
604     builder_field!(ranging_round_control, RangingRoundControl);
605     builder_field!(aoa_result_request, AoaResultRequest);
606     builder_field!(range_data_ntf_config, RangeDataNtfConfig);
607     builder_field!(range_data_ntf_proximity_near_cm, u16);
608     builder_field!(range_data_ntf_proximity_far_cm, u16);
609     builder_field!(device_role, DeviceRole, Some);
610     builder_field!(rframe_config, RframeConfig);
611     builder_field!(preamble_code_index, u8);
612     builder_field!(sfd_id, u8);
613     builder_field!(psdu_data_rate, PsduDataRate);
614     builder_field!(preamble_duration, PreambleDuration);
615     builder_field!(ranging_time_struct, RangingTimeStruct);
616     builder_field!(slots_per_rr, u8);
617     builder_field!(tx_adaptive_payload_power, TxAdaptivePayloadPower);
618     builder_field!(responder_slot_index, u8);
619     builder_field!(prf_mode, PrfMode);
620     builder_field!(scheduled_mode, ScheduledMode);
621     builder_field!(key_rotation, KeyRotation);
622     builder_field!(key_rotation_rate, u8);
623     builder_field!(session_priority, u8);
624     builder_field!(mac_address_mode, MacAddressMode);
625     builder_field!(vendor_id, [u8; 2], Some);
626     builder_field!(static_sts_iv, [u8; 6], Some);
627     builder_field!(number_of_sts_segments, u8);
628     builder_field!(max_rr_retry, u16);
629     builder_field!(uwb_initiation_time_ms, u32);
630     builder_field!(hopping_mode, HoppingMode);
631     builder_field!(block_stride_length, u8);
632     builder_field!(result_report_config, ResultReportConfig);
633     builder_field!(in_band_termination_attempt_count, u8);
634     builder_field!(sub_session_id, u32);
635     builder_field!(bprf_phr_data_rate, BprfPhrDataRate);
636     builder_field!(max_number_of_measurements, u16);
637     builder_field!(sts_length, StsLength);
638     builder_field!(number_of_range_measurements, u8);
639     builder_field!(number_of_aoa_azimuth_measurements, u8);
640     builder_field!(number_of_aoa_elevation_measurements, u8);
641 }
642 
643 #[repr(u8)]
644 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
645 pub enum DeviceType {
646     Controlee = 0,
647     Controller = 1,
648 }
649 
650 #[repr(u8)]
651 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
652 pub enum RangingRoundUsage {
653     SsTwr = 1,
654     DsTwr = 2,
655     SsTwrNon = 3,
656     DsTwrNon = 4,
657 }
658 
659 #[repr(u8)]
660 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
661 pub enum StsConfig {
662     Static = 0,
663     Dynamic = 1,
664     DynamicForControleeIndividualKey = 2,
665 }
666 
667 #[repr(u8)]
668 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
669 pub enum MultiNodeMode {
670     Unicast = 0,
671     OneToMany = 1,
672     ManyToMany = 2,
673 }
674 
675 #[repr(u8)]
676 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
677 pub enum UwbChannel {
678     Channel5 = 5,
679     Channel6 = 6,
680     Channel8 = 8,
681     Channel9 = 9,
682     Channel10 = 10,
683     Channel12 = 12,
684     Channel13 = 13,
685     Channel14 = 14,
686 }
687 
688 #[derive(Debug, Clone, PartialEq, Eq)]
689 pub enum UwbAddress {
690     Short([u8; 2]),
691     Extended([u8; 8]),
692 }
693 
694 impl From<UwbAddress> for Vec<u8> {
from(item: UwbAddress) -> Self695     fn from(item: UwbAddress) -> Self {
696         match item {
697             UwbAddress::Short(addr) => addr.to_vec(),
698             UwbAddress::Extended(addr) => addr.to_vec(),
699         }
700     }
701 }
702 
addresses_to_bytes(addresses: Vec<UwbAddress>) -> Vec<u8>703 fn addresses_to_bytes(addresses: Vec<UwbAddress>) -> Vec<u8> {
704     addresses.into_iter().flat_map(Into::<Vec<u8>>::into).collect()
705 }
706 
707 #[repr(u8)]
708 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
709 pub enum MacFcsType {
710     Crc16 = 0,
711     Crc32 = 1,
712 }
713 
714 #[derive(Debug, Clone, PartialEq, Eq)]
715 pub struct RangingRoundControl {
716     pub ranging_result_report_message: bool,
717     pub control_message: bool,
718     pub measurement_report_message: bool,
719 }
720 
721 impl RangingRoundControl {
722     const RANGING_RESULT_REPORT_MESSAGE_BIT_OFFSET: u8 = 0;
723     const CONTROL_MESSAGE_BIT_OFFSET: u8 = 1;
724     const MEASUREMENT_REPORT_MESSAGE_BIT_OFFSET: u8 = 7;
725 
as_u8(&self) -> u8726     fn as_u8(&self) -> u8 {
727         let mut value = 0_u8;
728         if self.ranging_result_report_message {
729             value |= 1 << Self::RANGING_RESULT_REPORT_MESSAGE_BIT_OFFSET;
730         }
731         if self.control_message {
732             value |= 1 << Self::CONTROL_MESSAGE_BIT_OFFSET;
733         }
734         if self.measurement_report_message {
735             value |= 1 << Self::MEASUREMENT_REPORT_MESSAGE_BIT_OFFSET;
736         }
737         value
738     }
739 }
740 
741 #[repr(u8)]
742 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
743 pub enum AoaResultRequest {
744     NoAoaReport = 0,
745     ReqAoaResults = 1,
746     ReqAoaResultsAzimuthOnly = 2,
747     ReqAoaResultsElevationOnly = 3,
748     ReqAoaResultsInterleaved = 0xF0,
749 }
750 
751 #[repr(u8)]
752 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
753 pub enum RangeDataNtfConfig {
754     Disable = 0,
755     Enable = 1,
756     EnableProximity = 2,
757 }
758 
759 #[repr(u8)]
760 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
761 pub enum DeviceRole {
762     Responder = 0,
763     Initiator = 1,
764 }
765 
766 #[repr(u8)]
767 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
768 pub enum RframeConfig {
769     SP0 = 0,
770     SP1 = 1,
771     SP3 = 3,
772 }
773 
774 #[repr(u8)]
775 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
776 pub enum PsduDataRate {
777     Rate6m81 = 0,
778     Rate7m80 = 1,
779     Rate27m2 = 2,
780     Rate31m2 = 3,
781 }
782 
783 #[repr(u8)]
784 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
785 pub enum PreambleDuration {
786     T32Symbols = 0,
787     T64Symbols = 1,
788 }
789 
790 #[repr(u8)]
791 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
792 pub enum RangingTimeStruct {
793     IntervalBasedScheduling = 0,
794     BlockBasedScheduling = 1,
795 }
796 
797 #[repr(u8)]
798 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
799 pub enum TxAdaptivePayloadPower {
800     Disable = 0,
801     Enable = 1,
802 }
803 
804 #[repr(u8)]
805 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
806 pub enum PrfMode {
807     Bprf = 0,
808     HprfWith124_8MHz = 1,
809     HprfWith249_6MHz = 2,
810 }
811 
812 #[repr(u8)]
813 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
814 pub enum ScheduledMode {
815     TimeScheduledRanging = 1,
816 }
817 
818 #[repr(u8)]
819 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
820 pub enum KeyRotation {
821     Disable = 0,
822     Enable = 1,
823 }
824 
825 #[repr(u8)]
826 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
827 pub enum MacAddressMode {
828     MacAddress2Bytes = 0,
829     MacAddress8Bytes2BytesHeader = 1,
830     MacAddress8Bytes = 2,
831 }
832 
833 #[repr(u8)]
834 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
835 pub enum HoppingMode {
836     Disable = 0,
837     FiraHoppingEnable = 1,
838 }
839 
840 #[derive(Debug, Clone, PartialEq, Eq)]
841 pub struct ResultReportConfig {
842     pub tof: bool,
843     pub aoa_azimuth: bool,
844     pub aoa_elevation: bool,
845     pub aoa_fom: bool,
846 }
847 
848 impl ResultReportConfig {
849     const TOF_BIT_OFFSET: u8 = 0;
850     const AOA_AZIMUTH_BIT_OFFSET: u8 = 1;
851     const AOA_ELEVATION_BIT_OFFSET: u8 = 2;
852     const AOA_FOM_BIT_OFFSET: u8 = 3;
853 
as_u8(&self) -> u8854     fn as_u8(&self) -> u8 {
855         let mut value = 0_u8;
856         if self.tof {
857             value |= 1 << Self::TOF_BIT_OFFSET;
858         }
859         if self.aoa_azimuth {
860             value |= 1 << Self::AOA_AZIMUTH_BIT_OFFSET;
861         }
862         if self.aoa_elevation {
863             value |= 1 << Self::AOA_ELEVATION_BIT_OFFSET;
864         }
865         if self.aoa_fom {
866             value |= 1 << Self::AOA_FOM_BIT_OFFSET;
867         }
868 
869         value
870     }
871 }
872 
873 #[repr(u8)]
874 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
875 pub enum BprfPhrDataRate {
876     Rate850k = 0,
877     Rate6m81 = 1,
878 }
879 
880 #[repr(u8)]
881 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
882 pub enum StsLength {
883     Length32 = 0,
884     Length64 = 1,
885     Length128 = 2,
886 }
887 
u8_to_bytes(value: u8) -> Vec<u8>888 fn u8_to_bytes(value: u8) -> Vec<u8> {
889     value.to_le_bytes().to_vec()
890 }
u16_to_bytes(value: u16) -> Vec<u8>891 fn u16_to_bytes(value: u16) -> Vec<u8> {
892     value.to_le_bytes().to_vec()
893 }
u32_to_bytes(value: u32) -> Vec<u8>894 fn u32_to_bytes(value: u32) -> Vec<u8> {
895     value.to_le_bytes().to_vec()
896 }
897 
validate(value: bool, err_msg: &str) -> Option<()>898 fn validate(value: bool, err_msg: &str) -> Option<()> {
899     match value {
900         true => Some(()),
901         false => {
902             error!("{}", err_msg);
903             None
904         }
905     }
906 }
907 
908 #[cfg(test)]
909 mod tests {
910     use super::*;
911 
912     use crate::utils::init_test_logging;
913 
914     #[test]
test_ok()915     fn test_ok() {
916         init_test_logging();
917 
918         let device_type = DeviceType::Controlee;
919         let ranging_round_usage = RangingRoundUsage::SsTwr;
920         let sts_config = StsConfig::DynamicForControleeIndividualKey;
921         let multi_node_mode = MultiNodeMode::ManyToMany;
922         let channel_number = UwbChannel::Channel10;
923         let device_mac_address = [1, 2, 3, 4, 5, 6, 7, 8];
924         let dst_mac_address1 = [2, 2, 3, 4, 5, 6, 7, 8];
925         let dst_mac_address2 = [3, 2, 3, 4, 5, 6, 7, 8];
926         let slot_duration_rstu = 0x0A28;
927         let ranging_interval_ms = 100;
928         let mac_fcs_type = MacFcsType::Crc32;
929         let ranging_round_control = RangingRoundControl {
930             ranging_result_report_message: false,
931             control_message: true,
932             measurement_report_message: false,
933         };
934         let aoa_result_request = AoaResultRequest::ReqAoaResultsInterleaved;
935         let range_data_ntf_config = RangeDataNtfConfig::EnableProximity;
936         let range_data_ntf_proximity_near_cm = 50;
937         let range_data_ntf_proximity_far_cm = 200;
938         let device_role = DeviceRole::Initiator;
939         let rframe_config = RframeConfig::SP1;
940         let preamble_code_index = 25;
941         let sfd_id = 3;
942         let psdu_data_rate = PsduDataRate::Rate7m80;
943         let preamble_duration = PreambleDuration::T32Symbols;
944         let slots_per_rr = 10;
945         let tx_adaptive_payload_power = TxAdaptivePayloadPower::Enable;
946         let prf_mode = PrfMode::HprfWith124_8MHz;
947         let key_rotation = KeyRotation::Enable;
948         let key_rotation_rate = 15;
949         let session_priority = 100;
950         let mac_address_mode = MacAddressMode::MacAddress8Bytes;
951         let vendor_id = [0xFE, 0xDC];
952         let static_sts_iv = [0xDF, 0xCE, 0xAB, 0x12, 0x34, 0x56];
953         let number_of_sts_segments = 2;
954         let max_rr_retry = 3;
955         let uwb_initiation_time_ms = 100;
956         let result_report_config =
957             ResultReportConfig { tof: true, aoa_azimuth: true, aoa_elevation: true, aoa_fom: true };
958         let in_band_termination_attempt_count = 8;
959         let sub_session_id = 24;
960         let sts_length = StsLength::Length128;
961         let number_of_range_measurements = 1;
962         let number_of_aoa_azimuth_measurements = 2;
963         let number_of_aoa_elevation_measurements = 3;
964 
965         let mut builder = FiraAppConfigParamsBuilder::new();
966         builder
967             .device_type(device_type)
968             .ranging_round_usage(ranging_round_usage)
969             .sts_config(sts_config)
970             .multi_node_mode(multi_node_mode)
971             .channel_number(channel_number)
972             .device_mac_address(UwbAddress::Extended(device_mac_address))
973             .dst_mac_address(vec![
974                 UwbAddress::Extended(dst_mac_address1),
975                 UwbAddress::Extended(dst_mac_address2),
976             ])
977             .slot_duration_rstu(slot_duration_rstu)
978             .ranging_interval_ms(ranging_interval_ms)
979             .mac_fcs_type(mac_fcs_type)
980             .ranging_round_control(ranging_round_control.clone())
981             .aoa_result_request(aoa_result_request)
982             .range_data_ntf_config(range_data_ntf_config)
983             .range_data_ntf_proximity_near_cm(range_data_ntf_proximity_near_cm)
984             .range_data_ntf_proximity_far_cm(range_data_ntf_proximity_far_cm)
985             .device_role(device_role)
986             .rframe_config(rframe_config)
987             .preamble_code_index(preamble_code_index)
988             .sfd_id(sfd_id)
989             .psdu_data_rate(psdu_data_rate)
990             .preamble_duration(preamble_duration)
991             .slots_per_rr(slots_per_rr)
992             .tx_adaptive_payload_power(tx_adaptive_payload_power)
993             .prf_mode(prf_mode)
994             .key_rotation(key_rotation)
995             .key_rotation_rate(key_rotation_rate)
996             .session_priority(session_priority)
997             .mac_address_mode(mac_address_mode)
998             .vendor_id(vendor_id)
999             .static_sts_iv(static_sts_iv)
1000             .number_of_sts_segments(number_of_sts_segments)
1001             .max_rr_retry(max_rr_retry)
1002             .uwb_initiation_time_ms(uwb_initiation_time_ms)
1003             .result_report_config(result_report_config.clone())
1004             .in_band_termination_attempt_count(in_band_termination_attempt_count)
1005             .sub_session_id(sub_session_id)
1006             .sts_length(sts_length)
1007             .number_of_range_measurements(number_of_range_measurements)
1008             .number_of_aoa_azimuth_measurements(number_of_aoa_azimuth_measurements)
1009             .number_of_aoa_elevation_measurements(number_of_aoa_elevation_measurements);
1010         let params = builder.build().unwrap();
1011 
1012         // Verify the generated TLV.
1013         let config_map = params.generate_config_map();
1014         let expected_config_map = HashMap::from([
1015             (AppConfigTlvType::DeviceType, vec![device_type as u8]),
1016             (AppConfigTlvType::RangingRoundUsage, vec![ranging_round_usage as u8]),
1017             (AppConfigTlvType::StsConfig, vec![sts_config as u8]),
1018             (AppConfigTlvType::MultiNodeMode, vec![multi_node_mode as u8]),
1019             (AppConfigTlvType::ChannelNumber, vec![channel_number as u8]),
1020             (AppConfigTlvType::NoOfControlee, vec![2]),
1021             (AppConfigTlvType::DeviceMacAddress, device_mac_address.to_vec()),
1022             (
1023                 AppConfigTlvType::DstMacAddress,
1024                 [dst_mac_address1, dst_mac_address2].concat().to_vec(),
1025             ),
1026             (AppConfigTlvType::SlotDuration, slot_duration_rstu.to_le_bytes().to_vec()),
1027             (AppConfigTlvType::RangingInterval, ranging_interval_ms.to_le_bytes().to_vec()),
1028             (AppConfigTlvType::MacFcsType, vec![mac_fcs_type as u8]),
1029             (AppConfigTlvType::RangingRoundControl, vec![ranging_round_control.as_u8()]),
1030             (AppConfigTlvType::AoaResultReq, vec![aoa_result_request as u8]),
1031             (AppConfigTlvType::RngDataNtf, vec![range_data_ntf_config as u8]),
1032             (
1033                 AppConfigTlvType::RngDataNtfProximityNear,
1034                 range_data_ntf_proximity_near_cm.to_le_bytes().to_vec(),
1035             ),
1036             (
1037                 AppConfigTlvType::RngDataNtfProximityFar,
1038                 range_data_ntf_proximity_far_cm.to_le_bytes().to_vec(),
1039             ),
1040             (AppConfigTlvType::DeviceRole, vec![device_role as u8]),
1041             (AppConfigTlvType::RframeConfig, vec![rframe_config as u8]),
1042             (AppConfigTlvType::PreambleCodeIndex, vec![preamble_code_index as u8]),
1043             (AppConfigTlvType::SfdId, vec![sfd_id as u8]),
1044             (AppConfigTlvType::PsduDataRate, vec![psdu_data_rate as u8]),
1045             (AppConfigTlvType::PreambleDuration, vec![preamble_duration as u8]),
1046             (AppConfigTlvType::RangingTimeStruct, vec![DEFAULT_RANGING_TIME_STRUCT as u8]),
1047             (AppConfigTlvType::SlotsPerRr, vec![slots_per_rr]),
1048             (AppConfigTlvType::TxAdaptivePayloadPower, vec![tx_adaptive_payload_power as u8]),
1049             (AppConfigTlvType::ResponderSlotIndex, vec![DEFAULT_RESPONDER_SLOT_INDEX]),
1050             (AppConfigTlvType::PrfMode, vec![prf_mode as u8]),
1051             (AppConfigTlvType::ScheduledMode, vec![DEFAULT_SCHEDULED_MODE as u8]),
1052             (AppConfigTlvType::KeyRotation, vec![key_rotation as u8]),
1053             (AppConfigTlvType::KeyRotationRate, vec![key_rotation_rate]),
1054             (AppConfigTlvType::SessionPriority, vec![session_priority]),
1055             (AppConfigTlvType::MacAddressMode, vec![mac_address_mode as u8]),
1056             (AppConfigTlvType::VendorId, vendor_id.to_vec()),
1057             (AppConfigTlvType::StaticStsIv, static_sts_iv.to_vec()),
1058             (AppConfigTlvType::NumberOfStsSegments, vec![number_of_sts_segments]),
1059             (AppConfigTlvType::MaxRrRetry, max_rr_retry.to_le_bytes().to_vec()),
1060             (AppConfigTlvType::UwbInitiationTime, uwb_initiation_time_ms.to_le_bytes().to_vec()),
1061             (AppConfigTlvType::HoppingMode, vec![DEFAULT_HOPPING_MODE as u8]),
1062             (AppConfigTlvType::BlockStrideLength, vec![DEFAULT_BLOCK_STRIDE_LENGTH]),
1063             (AppConfigTlvType::ResultReportConfig, vec![result_report_config.as_u8()]),
1064             (
1065                 AppConfigTlvType::InBandTerminationAttemptCount,
1066                 vec![in_band_termination_attempt_count as u8],
1067             ),
1068             (AppConfigTlvType::BprfPhrDataRate, vec![DEFAULT_BPRF_PHR_DATA_RATE as u8]),
1069             (
1070                 AppConfigTlvType::MaxNumberOfMeasurements,
1071                 DEFAULT_MAX_NUMBER_OF_MEASUREMENTS.to_le_bytes().to_vec(),
1072             ),
1073             (AppConfigTlvType::StsLength, vec![sts_length as u8]),
1074             (AppConfigTlvType::SubSessionId, sub_session_id.to_le_bytes().to_vec()),
1075             (AppConfigTlvType::NbOfRangeMeasurements, vec![number_of_range_measurements]),
1076             (AppConfigTlvType::NbOfAzimuthMeasurements, vec![number_of_aoa_azimuth_measurements]),
1077             (
1078                 AppConfigTlvType::NbOfElevationMeasurements,
1079                 vec![number_of_aoa_elevation_measurements],
1080             ),
1081         ]);
1082         assert_eq!(config_map, expected_config_map);
1083 
1084         // Update the value from the original builder.
1085         let updated_key_rotation_rate = 10;
1086         assert_ne!(key_rotation_rate, updated_key_rotation_rate);
1087         let expected_updated_config_map =
1088             HashMap::from([(AppConfigTlvType::KeyRotationRate, vec![updated_key_rotation_rate])]);
1089 
1090         let updated_params1 = builder.key_rotation_rate(updated_key_rotation_rate).build().unwrap();
1091         let updated_config_map1 = updated_params1.generate_updated_config_map(&params);
1092         assert_eq!(updated_config_map1, expected_updated_config_map);
1093 
1094         // Update the value from the params.
1095         let updated_params2 = FiraAppConfigParamsBuilder::from_params(&params)
1096             .key_rotation_rate(updated_key_rotation_rate)
1097             .build()
1098             .unwrap();
1099         let updated_config_map2 = updated_params2.generate_updated_config_map(&params);
1100         assert_eq!(updated_config_map2, expected_updated_config_map);
1101     }
1102 }
1103