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(¶ms);
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(¶ms)
1096 .key_rotation_rate(updated_key_rotation_rate)
1097 .build()
1098 .unwrap();
1099 let updated_config_map2 = updated_params2.generate_updated_config_map(¶ms);
1100 assert_eq!(updated_config_map2, expected_updated_config_map);
1101 }
1102 }
1103