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