• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! 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 // Re-export enums and structs from uwb_uci_packets.
22 pub use uwb_uci_packets::{
23     AppConfigStatus, AppConfigTlv as RawAppConfigTlv, AppConfigTlvType, CapTlv, CapTlvType,
24     Controlee, ControleeStatus, Controlees, CreditAvailability, DataRcvStatusCode,
25     DataTransferNtfStatusCode, DeviceConfigId, DeviceConfigStatus, DeviceConfigTlv, DeviceState,
26     ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
27     ExtendedAddressTwoWayRangingMeasurement, FiraComponent, GroupId, MessageType,
28     MulticastUpdateStatusCode, PowerStats, RangingMeasurementType, ReasonCode, ResetConfig,
29     SessionState, SessionType, ShortAddressDlTdoaRangingMeasurement,
30     ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode,
31     UpdateMulticastListAction,
32 };
33 pub(crate) use uwb_uci_packets::{UciControlPacket, UciDataPacket, UciDataPacketHal};
34 
35 use crate::error::Error;
36 
37 /// The type of the session identifier.
38 pub type SessionId = u32;
39 /// The type of the sub-session identifier.
40 pub type SubSessionId = u32;
41 /// The type of the session handle.
42 pub type SessionHandle = u32;
43 /// Generic type used to represent either a session id or session handle.
44 pub type SessionToken = u32;
45 
46 /// Wrap the original AppConfigTlv type to redact the PII fields when logging.
47 #[derive(Clone, PartialEq)]
48 pub struct AppConfigTlv {
49     tlv: RawAppConfigTlv,
50 }
51 
52 impl std::fmt::Debug for AppConfigTlv {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error>53     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
54         static REDACTED_STR: &str = "redacted";
55 
56         let mut ds = f.debug_struct("AppConfigTlv");
57         ds.field("cfg_id", &self.tlv.cfg_id);
58         if self.tlv.cfg_id == AppConfigTlvType::VendorId
59             || self.tlv.cfg_id == AppConfigTlvType::StaticStsIv
60         {
61             ds.field("v", &REDACTED_STR);
62         } else {
63             ds.field("v", &self.tlv.v);
64         }
65         ds.finish()
66     }
67 }
68 
69 impl AppConfigTlv {
70     /// Create a wrapper of uwb_uci_packets::AppConfigTlv.
71     ///
72     /// The argument is the same as the uwb_uci_packets::AppConfigTlv's struct.
new(cfg_id: AppConfigTlvType, v: Vec<u8>) -> Self73     pub fn new(cfg_id: AppConfigTlvType, v: Vec<u8>) -> Self {
74         Self { tlv: RawAppConfigTlv { cfg_id, v } }
75     }
76 
77     /// Consumes the outter wrapper type, returning the wrapped uwb_uci_packets::AppConfigTlv.
into_inner(self) -> RawAppConfigTlv78     pub fn into_inner(self) -> RawAppConfigTlv {
79         self.tlv
80     }
81 }
82 
83 impl From<RawAppConfigTlv> for AppConfigTlv {
from(tlv: RawAppConfigTlv) -> Self84     fn from(tlv: RawAppConfigTlv) -> Self {
85         Self { tlv }
86     }
87 }
88 
89 impl std::ops::Deref for AppConfigTlv {
90     type Target = RawAppConfigTlv;
deref(&self) -> &Self::Target91     fn deref(&self) -> &Self::Target {
92         &self.tlv
93     }
94 }
95 
96 impl std::ops::DerefMut for AppConfigTlv {
deref_mut(&mut self) -> &mut Self::Target97     fn deref_mut(&mut self) -> &mut Self::Target {
98         &mut self.tlv
99     }
100 }
101 
102 /// Compare if two AppConfigTlv array are equal. Convert the array to HashMap before comparing
103 /// because the order of TLV elements doesn't matter.
104 #[allow(dead_code)]
app_config_tlvs_eq(a: &[AppConfigTlv], b: &[AppConfigTlv]) -> bool105 pub fn app_config_tlvs_eq(a: &[AppConfigTlv], b: &[AppConfigTlv]) -> bool {
106     app_config_tlvs_to_map(a) == app_config_tlvs_to_map(b)
107 }
108 
app_config_tlvs_to_map( tlvs: &[AppConfigTlv], ) -> HashMap<AppConfigTlvType, &Vec<u8>, RandomState>109 fn app_config_tlvs_to_map(
110     tlvs: &[AppConfigTlv],
111 ) -> HashMap<AppConfigTlvType, &Vec<u8>, RandomState> {
112     HashMap::from_iter(tlvs.iter().map(|config| (config.cfg_id, &config.v)))
113 }
114 
115 /// Compare if two DeviceConfigTlv array are equal. Convert the array to HashMap before comparing
116 /// because the order of TLV elements doesn't matter.
117 #[allow(dead_code)]
device_config_tlvs_eq(a: &[DeviceConfigTlv], b: &[DeviceConfigTlv]) -> bool118 pub fn device_config_tlvs_eq(a: &[DeviceConfigTlv], b: &[DeviceConfigTlv]) -> bool {
119     device_config_tlvs_to_map(a) == device_config_tlvs_to_map(b)
120 }
121 
device_config_tlvs_to_map( tlvs: &[DeviceConfigTlv], ) -> HashMap<DeviceConfigId, &Vec<u8>, RandomState>122 fn device_config_tlvs_to_map(
123     tlvs: &[DeviceConfigTlv],
124 ) -> HashMap<DeviceConfigId, &Vec<u8>, RandomState> {
125     HashMap::from_iter(tlvs.iter().map(|config| (config.cfg_id, &config.v)))
126 }
127 
128 /// The response of the UciManager::core_set_config() method.
129 #[derive(Debug, Clone, PartialEq)]
130 pub struct CoreSetConfigResponse {
131     /// The status code of the response.
132     pub status: StatusCode,
133     /// The status of each config TLV.
134     pub config_status: Vec<DeviceConfigStatus>,
135 }
136 
137 /// The response of the UciManager::session_set_app_config() method.
138 #[derive(Debug, Clone, PartialEq)]
139 pub struct SetAppConfigResponse {
140     /// The status code of the response.
141     pub status: StatusCode,
142     /// The status of each config TLV.
143     pub config_status: Vec<AppConfigStatus>,
144 }
145 
146 /// The response from UciManager::session_update_dt_tag_ranging_rounds() method.
147 #[derive(Debug, Clone, PartialEq, Eq)]
148 pub struct SessionUpdateDtTagRangingRoundsResponse {
149     /// The status code of the response.
150     pub status: StatusCode,
151     /// Indexes of unsuccessful ranging rounds.
152     pub ranging_round_indexes: Vec<u8>,
153 }
154 
155 /// The country code struct that contains 2 uppercase ASCII characters.
156 #[derive(Debug, Clone, PartialEq, Eq)]
157 pub struct CountryCode([u8; 2]);
158 
159 impl CountryCode {
160     const UNKNOWN_COUNTRY_CODE: &'static [u8] = "00".as_bytes();
161 
162     /// Create a CountryCode instance.
new(code: &[u8; 2]) -> Option<Self>163     pub fn new(code: &[u8; 2]) -> Option<Self> {
164         if code != CountryCode::UNKNOWN_COUNTRY_CODE
165             && !code.iter().all(|x| (*x as char).is_ascii_alphabetic())
166         {
167             None
168         } else {
169             Some(Self((*code).to_ascii_uppercase().try_into().ok()?))
170         }
171     }
172 }
173 
174 impl From<CountryCode> for [u8; 2] {
from(item: CountryCode) -> [u8; 2]175     fn from(item: CountryCode) -> [u8; 2] {
176         item.0
177     }
178 }
179 
180 impl TryFrom<String> for CountryCode {
181     type Error = Error;
try_from(item: String) -> Result<Self, Self::Error>182     fn try_from(item: String) -> Result<Self, Self::Error> {
183         let code = item.as_bytes().try_into().map_err(|_| Error::BadParameters)?;
184         Self::new(code).ok_or(Error::BadParameters)
185     }
186 }
187 
188 /// The response of the UciManager::core_get_device_info() method.
189 #[derive(Debug, Clone, PartialEq, Eq)]
190 pub struct GetDeviceInfoResponse {
191     /// The UCI version.
192     pub uci_version: u16,
193     /// The MAC version.
194     pub mac_version: u16,
195     /// The physical version.
196     pub phy_version: u16,
197     /// The UCI test version.
198     pub uci_test_version: u16,
199     /// The vendor spec info.
200     pub vendor_spec_info: Vec<u8>,
201 }
202 
203 /// The raw UCI message for the vendor commands.
204 #[derive(Debug, Clone, PartialEq, Eq)]
205 pub struct RawUciMessage {
206     /// The group id of the message.
207     pub gid: u32,
208     /// The opcode of the message.
209     pub oid: u32,
210     /// The payload of the message.
211     pub payload: Vec<u8>,
212 }
213 
214 impl From<UciControlPacket> for RawUciMessage {
from(packet: UciControlPacket) -> Self215     fn from(packet: UciControlPacket) -> Self {
216         Self {
217             gid: packet.get_group_id().into(),
218             oid: packet.get_opcode() as u32,
219             payload: packet.to_raw_payload(),
220         }
221     }
222 }
223 
224 #[cfg(test)]
225 mod tests {
226     use super::*;
227 
228     #[test]
test_redacted_app_config_tlv()229     fn test_redacted_app_config_tlv() {
230         // The value of VendorId and StaticStsIv should be redacted.
231         let tlv = AppConfigTlv::new(AppConfigTlvType::VendorId, vec![12, 34]);
232         let format_str = format!("{tlv:?}");
233         assert!(format_str.contains("v: \"redacted\""));
234 
235         let tlv = AppConfigTlv::new(AppConfigTlvType::StaticStsIv, vec![12, 34]);
236         let format_str = format!("{tlv:?}");
237         assert!(format_str.contains("v: \"redacted\""));
238 
239         // The value of DeviceType should be printed normally.
240         let tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![12, 34]);
241         let format_str = format!("{tlv:?}");
242         assert_eq!(format_str, "AppConfigTlv { cfg_id: DeviceType, v: [12, 34] }");
243     }
244 
245     #[test]
test_country_code()246     fn test_country_code() {
247         let _country_code_ascii: CountryCode = String::from("US").try_into().unwrap();
248         let _country_code_unknown: CountryCode = String::from("00").try_into().unwrap();
249         let country_code_invalid_1: Result<CountryCode, Error> = String::from("0S").try_into();
250         country_code_invalid_1.unwrap_err();
251         let country_code_invalid_2: Result<CountryCode, Error> = String::from("ÀÈ").try_into();
252         country_code_invalid_2.unwrap_err();
253     }
254 }
255