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 parameters or responses of the UciManager's methods. Most of them are
16 //! re-exported from the uwb_uci_packets crate.
17
18 use std::collections::{hash_map::RandomState, HashMap};
19 use std::iter::FromIterator;
20
21 use num_derive::{FromPrimitive, ToPrimitive};
22
23 // Re-export enums and structs from uwb_uci_packets.
24 pub use uwb_uci_packets::{
25 AppConfigStatus, AppConfigTlv as RawAppConfigTlv, AppConfigTlvType, BitsPerSample, CapTlv,
26 CapTlvType, Controlee, ControleePhaseList, ControleeStatusV1, ControleeStatusV2, Controlees,
27 ControllerPhaseList, CreditAvailability, DataRcvStatusCode, DataTransferNtfStatusCode,
28 DataTransferPhaseConfigUpdateStatusCode, DeviceConfigId, DeviceConfigStatus, DeviceConfigTlv,
29 DeviceState, ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
30 ExtendedAddressTwoWayRangingMeasurement, GroupId, MacAddressIndicator, MessageType,
31 MulticastUpdateStatusCode, PowerStats, RadarConfigStatus, RadarConfigTlv, RadarConfigTlvType,
32 RadarDataType, RangingMeasurementType, ReasonCode, ResetConfig, RfTestConfigStatus,
33 RfTestConfigTlv, RfTestConfigTlvType, SessionState, SessionType,
34 SessionUpdateControllerMulticastListNtfV1Payload,
35 SessionUpdateControllerMulticastListNtfV2Payload,
36 SessionUpdateControllerMulticastListRspV1Payload,
37 SessionUpdateControllerMulticastListRspV2Payload, ShortAddressDlTdoaRangingMeasurement,
38 ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode,
39 UpdateMulticastListAction,
40 };
41 pub(crate) use uwb_uci_packets::{UciControlPacket, UciDataPacket, UciDataPacketHal};
42
43 use crate::error::Error;
44
45 /// The type of the session identifier.
46 pub type SessionId = u32;
47 /// The type of the sub-session identifier.
48 pub type SubSessionId = u32;
49 /// The type of the session handle.
50 pub type SessionHandle = u32;
51 /// Generic type used to represent either a session id or session handle.
52 pub type SessionToken = u32;
53
54 /// Wrap the original AppConfigTlv type to redact the PII fields when logging.
55 #[derive(Clone, PartialEq)]
56 pub struct AppConfigTlv {
57 tlv: RawAppConfigTlv,
58 }
59
60 /// Controlee Status Enum compatible with different Fira version.
61 pub enum ControleeStatusList {
62 /// Controlee status defined in Fira 1.x.
63 V1(Vec<ControleeStatusV1>),
64 /// Controlee status defined in Fira 2.0.
65 V2(Vec<ControleeStatusV2>),
66 }
67
68 /// UCI major version
69 #[derive(FromPrimitive, ToPrimitive, PartialEq, Clone, PartialOrd, Ord, Eq)]
70 #[repr(u8)]
71 pub enum UCIMajorVersion {
72 /// Version 1.x
73 V1 = 1,
74 /// Version 2.0
75 V2 = 2,
76 /// Version 3.0
77 V3 = 3,
78 }
79
80 impl std::fmt::Debug for AppConfigTlv {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error>81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
82 static REDACTED_STR: &str = "redacted";
83
84 let mut ds = f.debug_struct("AppConfigTlv");
85 ds.field("cfg_id", &self.tlv.cfg_id);
86 if self.tlv.cfg_id == AppConfigTlvType::VendorId
87 || self.tlv.cfg_id == AppConfigTlvType::StaticStsIv
88 {
89 ds.field("v", &REDACTED_STR);
90 } else {
91 ds.field("v", &self.tlv.v);
92 }
93 ds.finish()
94 }
95 }
96
97 impl AppConfigTlv {
98 /// Create a wrapper of uwb_uci_packets::AppConfigTlv.
99 ///
100 /// The argument is the same as the uwb_uci_packets::AppConfigTlv's struct.
new(cfg_id: AppConfigTlvType, v: Vec<u8>) -> Self101 pub fn new(cfg_id: AppConfigTlvType, v: Vec<u8>) -> Self {
102 Self { tlv: RawAppConfigTlv { cfg_id, v } }
103 }
104
105 /// Consumes the outter wrapper type, returning the wrapped uwb_uci_packets::AppConfigTlv.
into_inner(self) -> RawAppConfigTlv106 pub fn into_inner(self) -> RawAppConfigTlv {
107 self.tlv
108 }
109 }
110
111 impl From<RawAppConfigTlv> for AppConfigTlv {
from(tlv: RawAppConfigTlv) -> Self112 fn from(tlv: RawAppConfigTlv) -> Self {
113 Self { tlv }
114 }
115 }
116
117 impl std::ops::Deref for AppConfigTlv {
118 type Target = RawAppConfigTlv;
deref(&self) -> &Self::Target119 fn deref(&self) -> &Self::Target {
120 &self.tlv
121 }
122 }
123
124 impl std::ops::DerefMut for AppConfigTlv {
deref_mut(&mut self) -> &mut Self::Target125 fn deref_mut(&mut self) -> &mut Self::Target {
126 &mut self.tlv
127 }
128 }
129
130 /// Compare if two AppConfigTlv array are equal. Convert the array to HashMap before comparing
131 /// because the order of TLV elements doesn't matter.
132 #[allow(dead_code)]
app_config_tlvs_eq(a: &[AppConfigTlv], b: &[AppConfigTlv]) -> bool133 pub fn app_config_tlvs_eq(a: &[AppConfigTlv], b: &[AppConfigTlv]) -> bool {
134 app_config_tlvs_to_map(a) == app_config_tlvs_to_map(b)
135 }
136
app_config_tlvs_to_map( tlvs: &[AppConfigTlv], ) -> HashMap<AppConfigTlvType, &Vec<u8>, RandomState>137 fn app_config_tlvs_to_map(
138 tlvs: &[AppConfigTlv],
139 ) -> HashMap<AppConfigTlvType, &Vec<u8>, RandomState> {
140 HashMap::from_iter(tlvs.iter().map(|config| (config.cfg_id, &config.v)))
141 }
142
143 /// Compare if two DeviceConfigTlv array are equal. Convert the array to HashMap before comparing
144 /// because the order of TLV elements doesn't matter.
145 #[allow(dead_code)]
device_config_tlvs_eq(a: &[DeviceConfigTlv], b: &[DeviceConfigTlv]) -> bool146 pub fn device_config_tlvs_eq(a: &[DeviceConfigTlv], b: &[DeviceConfigTlv]) -> bool {
147 device_config_tlvs_to_map(a) == device_config_tlvs_to_map(b)
148 }
149
device_config_tlvs_to_map( tlvs: &[DeviceConfigTlv], ) -> HashMap<DeviceConfigId, &Vec<u8>, RandomState>150 fn device_config_tlvs_to_map(
151 tlvs: &[DeviceConfigTlv],
152 ) -> HashMap<DeviceConfigId, &Vec<u8>, RandomState> {
153 HashMap::from_iter(tlvs.iter().map(|config| (config.cfg_id, &config.v)))
154 }
155
156 /// Compare if two RadarConfigTlv array are equal. Convert the array to HashMap before comparing
157 /// because the order of TLV elements doesn't matter.
158 #[allow(dead_code)]
radar_config_tlvs_eq(a: &[RadarConfigTlv], b: &[RadarConfigTlv]) -> bool159 pub fn radar_config_tlvs_eq(a: &[RadarConfigTlv], b: &[RadarConfigTlv]) -> bool {
160 radar_config_tlvs_to_map(a) == radar_config_tlvs_to_map(b)
161 }
162
radar_config_tlvs_to_map( tlvs: &[RadarConfigTlv], ) -> HashMap<RadarConfigTlvType, &Vec<u8>, RandomState>163 fn radar_config_tlvs_to_map(
164 tlvs: &[RadarConfigTlv],
165 ) -> HashMap<RadarConfigTlvType, &Vec<u8>, RandomState> {
166 HashMap::from_iter(tlvs.iter().map(|config| (config.cfg_id, &config.v)))
167 }
168
169 /// Compare if two RfTestConfigTlv array are equal. Convert the array to HashMap before comparing
170 /// because the order of TLV elements doesn't matter.
171 #[allow(dead_code)]
rf_test_config_tlvs_eq(a: &[RfTestConfigTlv], b: &[RfTestConfigTlv]) -> bool172 pub fn rf_test_config_tlvs_eq(a: &[RfTestConfigTlv], b: &[RfTestConfigTlv]) -> bool {
173 rf_test_config_tlvs_to_map(a) == rf_test_config_tlvs_to_map(b)
174 }
175
rf_test_config_tlvs_to_map( tlvs: &[RfTestConfigTlv], ) -> HashMap<RfTestConfigTlvType, &Vec<u8>, RandomState>176 fn rf_test_config_tlvs_to_map(
177 tlvs: &[RfTestConfigTlv],
178 ) -> HashMap<RfTestConfigTlvType, &Vec<u8>, RandomState> {
179 HashMap::from_iter(tlvs.iter().map(|config| (config.cfg_id, &config.v)))
180 }
181
182 /// The response of the UciManager::core_set_config() method.
183 #[derive(Debug, Clone, PartialEq)]
184 pub struct CoreSetConfigResponse {
185 /// The status code of the response.
186 pub status: StatusCode,
187 /// The status of each config TLV.
188 pub config_status: Vec<DeviceConfigStatus>,
189 }
190
191 /// The response of the UciManager::session_set_app_config() method.
192 #[derive(Debug, Clone, PartialEq)]
193 pub struct SetAppConfigResponse {
194 /// The status code of the response.
195 pub status: StatusCode,
196 /// The status of each config TLV.
197 pub config_status: Vec<AppConfigStatus>,
198 }
199
200 /// The response of the UciManager::android_set_radar_config() method.
201 #[derive(Debug, Clone, PartialEq)]
202 pub struct AndroidRadarConfigResponse {
203 /// The status code of the response.
204 pub status: StatusCode,
205 /// The status of each config TLV.
206 pub config_status: Vec<RadarConfigStatus>,
207 }
208
209 /// The response from UciManager::(session_update_controller_multicast_list() method.
210 #[derive(Debug, Clone, PartialEq, Eq)]
211 pub struct SessionUpdateControllerMulticastResponse {
212 /// The status code of the response.
213 pub status: StatusCode,
214 /// Controlee Status
215 pub status_list: Vec<ControleeStatusV2>,
216 }
217
218 /// The response from UciManager::session_update_dt_tag_ranging_rounds() method.
219 #[derive(Debug, Clone, PartialEq, Eq)]
220 pub struct SessionUpdateDtTagRangingRoundsResponse {
221 /// The status code of the response.
222 pub status: StatusCode,
223 /// Indexes of unsuccessful ranging rounds.
224 pub ranging_round_indexes: Vec<u8>,
225 }
226
227 /// The response of the UciManager::android_set_rf_test_config() method.
228 #[derive(Debug, Clone, PartialEq)]
229 pub struct RfTestConfigResponse {
230 /// The status code of the response.
231 pub status: StatusCode,
232 /// The status of each config TLV.
233 pub config_status: Vec<RfTestConfigStatus>,
234 }
235
236 /// The country code struct that contains 2 uppercase ASCII characters.
237 #[derive(Debug, Clone, PartialEq, Eq)]
238 pub struct CountryCode([u8; 2]);
239
240 impl CountryCode {
241 const UNKNOWN_COUNTRY_CODE: &'static [u8] = "00".as_bytes();
242
243 /// Create a CountryCode instance.
new(code: &[u8; 2]) -> Option<Self>244 pub fn new(code: &[u8; 2]) -> Option<Self> {
245 if code != CountryCode::UNKNOWN_COUNTRY_CODE
246 && !code.iter().all(|x| (*x as char).is_ascii_alphabetic())
247 {
248 None
249 } else {
250 Some(Self((*code).to_ascii_uppercase().try_into().ok()?))
251 }
252 }
253 }
254
255 impl From<CountryCode> for [u8; 2] {
from(item: CountryCode) -> [u8; 2]256 fn from(item: CountryCode) -> [u8; 2] {
257 item.0
258 }
259 }
260
261 impl TryFrom<String> for CountryCode {
262 type Error = Error;
try_from(item: String) -> Result<Self, Self::Error>263 fn try_from(item: String) -> Result<Self, Self::Error> {
264 let code = item.as_bytes().try_into().map_err(|_| Error::BadParameters)?;
265 Self::new(code).ok_or(Error::BadParameters)
266 }
267 }
268
269 /// The response of the UciManager::core_get_device_info() method.
270 #[derive(Debug, Clone, PartialEq, Eq)]
271 pub struct GetDeviceInfoResponse {
272 /// Status
273 pub status: StatusCode,
274 /// The UCI version.
275 pub uci_version: u16,
276 /// The MAC version.
277 pub mac_version: u16,
278 /// The physical version.
279 pub phy_version: u16,
280 /// The UCI test version.
281 pub uci_test_version: u16,
282 /// The vendor spec info.
283 pub vendor_spec_info: Vec<u8>,
284 }
285
286 /// The raw UCI message for the vendor commands.
287 #[derive(Debug, Clone, PartialEq, Eq)]
288 pub struct RawUciMessage {
289 /// The group id of the message.
290 pub gid: u32,
291 /// The opcode of the message.
292 pub oid: u32,
293 /// The payload of the message.
294 pub payload: Vec<u8>,
295 }
296
297 impl From<UciControlPacket> for RawUciMessage {
from(packet: UciControlPacket) -> Self298 fn from(packet: UciControlPacket) -> Self {
299 Self {
300 gid: packet.get_group_id().into(),
301 oid: packet.get_opcode() as u32,
302 payload: packet.to_raw_payload(),
303 }
304 }
305 }
306
307 #[cfg(test)]
308 mod tests {
309 use super::*;
310
311 #[test]
test_redacted_app_config_tlv()312 fn test_redacted_app_config_tlv() {
313 // The value of VendorId and StaticStsIv should be redacted.
314 let tlv = AppConfigTlv::new(AppConfigTlvType::VendorId, vec![12, 34]);
315 let format_str = format!("{tlv:?}");
316 assert!(format_str.contains("v: \"redacted\""));
317
318 let tlv = AppConfigTlv::new(AppConfigTlvType::StaticStsIv, vec![12, 34]);
319 let format_str = format!("{tlv:?}");
320 assert!(format_str.contains("v: \"redacted\""));
321
322 // The value of DeviceType should be printed normally.
323 let tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![12, 34]);
324 let format_str = format!("{tlv:?}");
325 assert_eq!(format_str, "AppConfigTlv { cfg_id: DeviceType, v: [12, 34] }");
326 }
327
328 #[test]
test_country_code()329 fn test_country_code() {
330 let _country_code_ascii: CountryCode = String::from("US").try_into().unwrap();
331 let _country_code_unknown: CountryCode = String::from("00").try_into().unwrap();
332 let country_code_invalid_1: Result<CountryCode, Error> = String::from("0S").try_into();
333 country_code_invalid_1.unwrap_err();
334 let country_code_invalid_2: Result<CountryCode, Error> = String::from("ÀÈ").try_into();
335 country_code_invalid_2.unwrap_err();
336 }
337
338 #[test]
test_rf_test_config_tlvs_eq()339 fn test_rf_test_config_tlvs_eq() {
340 let tlv1 = RfTestConfigTlv { cfg_id: RfTestConfigTlvType::NumPackets, v: vec![10, 20] };
341 let tlv2 = RfTestConfigTlv { cfg_id: RfTestConfigTlvType::TStart, v: vec![30, 40] };
342
343 let array1 = vec![tlv1.clone(), tlv2.clone()];
344 let array2 = vec![tlv2.clone(), tlv1.clone()]; // Different order
345
346 // Test that arrays with the same elements in different orders are equal.
347 assert!(rf_test_config_tlvs_eq(&array1, &array2));
348
349 let tlv3 = RfTestConfigTlv {
350 cfg_id: RfTestConfigTlvType::TWin,
351 v: vec![70, 80], // Different value
352 };
353
354 let array3 = vec![tlv1.clone(), tlv3.clone()];
355
356 // Test that arrays with different elements are not equal.
357 assert!(!rf_test_config_tlvs_eq(&array1, &array3));
358 }
359 }
360