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