1 // Copyright 2022, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 use std::convert::TryInto; 16 use std::sync::Arc; 17 use std::time::Duration; 18 19 use async_trait::async_trait; 20 use log::{debug, error, info, warn}; 21 use num_traits::FromPrimitive; 22 use tokio::sync::{mpsc, oneshot, Mutex}; 23 24 use crate::error::{Error, Result}; 25 use crate::params::uci_packets::{ 26 AndroidRadarConfigResponse, AppConfigTlv, AppConfigTlvType, CapTlv, CapTlvType, Controlees, 27 CoreSetConfigResponse, CountryCode, CreditAvailability, DeviceConfigId, DeviceConfigTlv, 28 DeviceState, GetDeviceInfoResponse, GroupId, MessageType, PowerStats, RadarConfigTlv, 29 RadarConfigTlvType, RawUciMessage, ResetConfig, RfTestConfigResponse, RfTestConfigTlv, 30 SessionId, SessionState, SessionToken, SessionType, SessionUpdateControllerMulticastResponse, 31 SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, UciDataPacket, UciDataPacketHal, 32 UpdateMulticastListAction, 33 }; 34 use crate::params::utils::{bytes_to_u16, bytes_to_u64}; 35 use crate::params::UCIMajorVersion; 36 use crate::uci::command::UciCommand; 37 use crate::uci::message::UciMessage; 38 use crate::uci::notification::{ 39 CoreNotification, DataRcvNotification, RadarDataRcvNotification, RfTestNotification, 40 SessionNotification, SessionRangeData, UciNotification, 41 }; 42 use crate::uci::response::UciResponse; 43 use crate::uci::timeout_uci_hal::TimeoutUciHal; 44 use crate::uci::uci_hal::{UciHal, UciHalPacket}; 45 use crate::uci::uci_logger::{UciLogger, UciLoggerMode, UciLoggerWrapper}; 46 use crate::utils::{clean_mpsc_receiver, PinSleep}; 47 use pdl_runtime::Packet; 48 use std::collections::{HashMap, VecDeque}; 49 use uwb_uci_packets::{ 50 fragment_data_msg_send, ControleePhaseList, ControllerPhaseList, RawUciControlPacket, 51 UciDataSnd, UciDefragPacket, 52 }; 53 54 const UCI_TIMEOUT_MS: u64 = 2000; 55 const MAX_RETRY_COUNT: usize = 3; 56 // Initialize to a safe (minimum) value for a Data packet fragment's payload size. 57 const MAX_DATA_PACKET_PAYLOAD_SIZE: usize = 255; 58 59 /// The UciManager organizes the state machine of the UWB HAL, and provides the interface which 60 /// abstracts the UCI commands, responses, and notifications. 61 #[async_trait] 62 pub trait UciManager: 'static + Send + Sync + Clone { set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>63 async fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>; 64 // Set the sendor of the UCI notificaions. set_core_notification_sender( &mut self, core_notf_sender: mpsc::UnboundedSender<CoreNotification>, )65 async fn set_core_notification_sender( 66 &mut self, 67 core_notf_sender: mpsc::UnboundedSender<CoreNotification>, 68 ); set_session_notification_sender( &mut self, session_notf_sender: mpsc::UnboundedSender<SessionNotification>, )69 async fn set_session_notification_sender( 70 &mut self, 71 session_notf_sender: mpsc::UnboundedSender<SessionNotification>, 72 ); set_vendor_notification_sender( &mut self, vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, )73 async fn set_vendor_notification_sender( 74 &mut self, 75 vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, 76 ); set_data_rcv_notification_sender( &mut self, data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, )77 async fn set_data_rcv_notification_sender( 78 &mut self, 79 data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, 80 ); set_radar_data_rcv_notification_sender( &mut self, radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, )81 async fn set_radar_data_rcv_notification_sender( 82 &mut self, 83 radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, 84 ); set_rf_test_notification_sender( &mut self, rf_test_notf_sender: mpsc::UnboundedSender<RfTestNotification>, )85 async fn set_rf_test_notification_sender( 86 &mut self, 87 rf_test_notf_sender: mpsc::UnboundedSender<RfTestNotification>, 88 ); 89 90 // Open the UCI HAL. 91 // All the UCI commands should be called after the open_hal() completes successfully. open_hal(&self) -> Result<GetDeviceInfoResponse>92 async fn open_hal(&self) -> Result<GetDeviceInfoResponse>; 93 94 // Close the UCI HAL. close_hal(&self, force: bool) -> Result<()>95 async fn close_hal(&self, force: bool) -> Result<()>; 96 97 // Send the standard UCI Commands. device_reset(&self, reset_config: ResetConfig) -> Result<()>98 async fn device_reset(&self, reset_config: ResetConfig) -> Result<()>; core_get_device_info(&self) -> Result<GetDeviceInfoResponse>99 async fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse>; core_get_caps_info(&self) -> Result<Vec<CapTlv>>100 async fn core_get_caps_info(&self) -> Result<Vec<CapTlv>>; core_set_config( &self, config_tlvs: Vec<DeviceConfigTlv>, ) -> Result<CoreSetConfigResponse>101 async fn core_set_config( 102 &self, 103 config_tlvs: Vec<DeviceConfigTlv>, 104 ) -> Result<CoreSetConfigResponse>; core_get_config( &self, config_ids: Vec<DeviceConfigId>, ) -> Result<Vec<DeviceConfigTlv>>105 async fn core_get_config( 106 &self, 107 config_ids: Vec<DeviceConfigId>, 108 ) -> Result<Vec<DeviceConfigTlv>>; core_query_uwb_timestamp(&self) -> Result<u64>109 async fn core_query_uwb_timestamp(&self) -> Result<u64>; session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>110 async fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>; session_deinit(&self, session_id: SessionId) -> Result<()>111 async fn session_deinit(&self, session_id: SessionId) -> Result<()>; session_set_app_config( &self, session_id: SessionId, config_tlvs: Vec<AppConfigTlv>, ) -> Result<SetAppConfigResponse>112 async fn session_set_app_config( 113 &self, 114 session_id: SessionId, 115 config_tlvs: Vec<AppConfigTlv>, 116 ) -> Result<SetAppConfigResponse>; session_get_app_config( &self, session_id: SessionId, config_ids: Vec<AppConfigTlvType>, ) -> Result<Vec<AppConfigTlv>>117 async fn session_get_app_config( 118 &self, 119 session_id: SessionId, 120 config_ids: Vec<AppConfigTlvType>, 121 ) -> Result<Vec<AppConfigTlv>>; session_get_count(&self) -> Result<u8>122 async fn session_get_count(&self) -> Result<u8>; session_get_state(&self, session_id: SessionId) -> Result<SessionState>123 async fn session_get_state(&self, session_id: SessionId) -> Result<SessionState>; session_update_controller_multicast_list( &self, session_id: SessionId, action: UpdateMulticastListAction, controlees: Controlees, is_multicast_list_ntf_v2_supported: bool, is_multicast_list_rsp_v2_supported: bool, ) -> Result<SessionUpdateControllerMulticastResponse>124 async fn session_update_controller_multicast_list( 125 &self, 126 session_id: SessionId, 127 action: UpdateMulticastListAction, 128 controlees: Controlees, 129 is_multicast_list_ntf_v2_supported: bool, 130 is_multicast_list_rsp_v2_supported: bool, 131 ) -> Result<SessionUpdateControllerMulticastResponse>; 132 133 // Update ranging rounds for DT Tag session_update_dt_tag_ranging_rounds( &self, session_id: u32, ranging_round_indexes: Vec<u8>, ) -> Result<SessionUpdateDtTagRangingRoundsResponse>134 async fn session_update_dt_tag_ranging_rounds( 135 &self, 136 session_id: u32, 137 ranging_round_indexes: Vec<u8>, 138 ) -> Result<SessionUpdateDtTagRangingRoundsResponse>; 139 session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>140 async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>; 141 range_start(&self, session_id: SessionId) -> Result<()>142 async fn range_start(&self, session_id: SessionId) -> Result<()>; range_stop(&self, session_id: SessionId) -> Result<()>143 async fn range_stop(&self, session_id: SessionId) -> Result<()>; range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>144 async fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>; 145 146 // Send the Android-specific UCI commands android_set_country_code(&self, country_code: CountryCode) -> Result<()>147 async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()>; android_get_power_stats(&self) -> Result<PowerStats>148 async fn android_get_power_stats(&self) -> Result<PowerStats>; android_set_radar_config( &self, session_id: SessionId, config_tlvs: Vec<RadarConfigTlv>, ) -> Result<AndroidRadarConfigResponse>149 async fn android_set_radar_config( 150 &self, 151 session_id: SessionId, 152 config_tlvs: Vec<RadarConfigTlv>, 153 ) -> Result<AndroidRadarConfigResponse>; android_get_radar_config( &self, session_id: SessionId, config_ids: Vec<RadarConfigTlvType>, ) -> Result<Vec<RadarConfigTlv>>154 async fn android_get_radar_config( 155 &self, 156 session_id: SessionId, 157 config_ids: Vec<RadarConfigTlvType>, 158 ) -> Result<Vec<RadarConfigTlv>>; 159 160 // Send a raw uci command. raw_uci_cmd( &self, mt: u32, gid: u32, oid: u32, payload: Vec<u8>, ) -> Result<RawUciMessage>161 async fn raw_uci_cmd( 162 &self, 163 mt: u32, 164 gid: u32, 165 oid: u32, 166 payload: Vec<u8>, 167 ) -> Result<RawUciMessage>; 168 169 // Send a Data packet. send_data_packet( &self, session_id: SessionId, address: Vec<u8>, uci_sequence_number: u16, app_payload_data: Vec<u8>, ) -> Result<()>170 async fn send_data_packet( 171 &self, 172 session_id: SessionId, 173 address: Vec<u8>, 174 uci_sequence_number: u16, 175 app_payload_data: Vec<u8>, 176 ) -> Result<()>; 177 178 // set Data transfer phase config 179 #[allow(clippy::too_many_arguments)] session_data_transfer_phase_config( &self, session_id: SessionId, dtpcm_repetition: u8, data_transfer_control: u8, dtpml_size: u8, mac_address: Vec<u8>, slot_bitmap: Vec<u8>, stop_data_transfer: Vec<u8>, ) -> Result<()>180 async fn session_data_transfer_phase_config( 181 &self, 182 session_id: SessionId, 183 dtpcm_repetition: u8, 184 data_transfer_control: u8, 185 dtpml_size: u8, 186 mac_address: Vec<u8>, 187 slot_bitmap: Vec<u8>, 188 stop_data_transfer: Vec<u8>, 189 ) -> Result<()>; 190 191 // Get Session token from session id get_session_token_from_session_id( &self, session_id: SessionId, ) -> Result<SessionToken>192 async fn get_session_token_from_session_id( 193 &self, 194 session_id: SessionId, 195 ) -> Result<SessionToken>; 196 197 /// Send UCI command for setting hybrid controller config session_set_hybrid_controller_config( &self, session_id: SessionId, number_of_phases: u8, phase_list: Vec<ControllerPhaseList>, ) -> Result<()>198 async fn session_set_hybrid_controller_config( 199 &self, 200 session_id: SessionId, 201 number_of_phases: u8, 202 phase_list: Vec<ControllerPhaseList>, 203 ) -> Result<()>; 204 205 /// Send UCI command for setting hybrid controlee config session_set_hybrid_controlee_config( &self, session_id: SessionId, controlee_phase_list: Vec<ControleePhaseList>, ) -> Result<()>206 async fn session_set_hybrid_controlee_config( 207 &self, 208 session_id: SessionId, 209 controlee_phase_list: Vec<ControleePhaseList>, 210 ) -> Result<()>; session_set_rf_test_config( &self, session_id: SessionId, config_tlvs: Vec<RfTestConfigTlv>, ) -> Result<RfTestConfigResponse>211 async fn session_set_rf_test_config( 212 &self, 213 session_id: SessionId, 214 config_tlvs: Vec<RfTestConfigTlv>, 215 ) -> Result<RfTestConfigResponse>; rf_test_periodic_tx(&self, psdu_data: Vec<u8>) -> Result<()>216 async fn rf_test_periodic_tx(&self, psdu_data: Vec<u8>) -> Result<()>; rf_test_per_rx(&self, psdu_data: Vec<u8>) -> Result<()>217 async fn rf_test_per_rx(&self, psdu_data: Vec<u8>) -> Result<()>; stop_rf_test(&self) -> Result<()>218 async fn stop_rf_test(&self) -> Result<()>; 219 } 220 221 /// UciManagerImpl is the main implementation of UciManager. Using the actor model, UciManagerImpl 222 /// delegates the requests to UciManagerActor. 223 #[derive(Clone)] 224 pub struct UciManagerImpl { 225 cmd_sender: mpsc::UnboundedSender<(UciManagerCmd, oneshot::Sender<Result<UciResponse>>)>, 226 227 // FIRA version 2 introduces a UWBS generated session handle to use as identifier for all 228 // session related commands. This map stores the app provided session id to UWBS generated 229 // session handle mapping if provided, else reuses session id. 230 session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>, 231 } 232 233 impl UciManagerImpl { 234 /// Constructor. Need to be called in an async context. new<T: UciHal, U: UciLogger>( hal: T, logger: U, logger_mode: UciLoggerMode, ) -> Self235 pub(crate) fn new<T: UciHal, U: UciLogger>( 236 hal: T, 237 logger: U, 238 logger_mode: UciLoggerMode, 239 ) -> Self { 240 let (cmd_sender, cmd_receiver) = mpsc::unbounded_channel(); 241 let session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>> = 242 Arc::new(Mutex::new(HashMap::new())); 243 let mut actor = UciManagerActor::new( 244 hal, 245 logger, 246 logger_mode, 247 cmd_receiver, 248 session_id_to_token_map.clone(), 249 ); 250 tokio::spawn(async move { actor.run().await }); 251 252 Self { cmd_sender, session_id_to_token_map } 253 } 254 255 // Send the |cmd| to the UciManagerActor. send_cmd(&self, cmd: UciManagerCmd) -> Result<UciResponse>256 async fn send_cmd(&self, cmd: UciManagerCmd) -> Result<UciResponse> { 257 let (result_sender, result_receiver) = oneshot::channel(); 258 match self.cmd_sender.send((cmd, result_sender)) { 259 Ok(()) => result_receiver.await.unwrap_or(Err(Error::Unknown)), 260 Err(cmd) => { 261 error!("Failed to send cmd: {:?}", cmd.0); 262 Err(Error::Unknown) 263 } 264 } 265 } 266 get_session_token(&self, session_id: &SessionId) -> Result<SessionToken>267 async fn get_session_token(&self, session_id: &SessionId) -> Result<SessionToken> { 268 self.session_id_to_token_map 269 .lock() 270 .await 271 .get(session_id) 272 .ok_or(Error::BadParameters) 273 .copied() 274 } 275 } 276 277 #[async_trait] 278 impl UciManager for UciManagerImpl { set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>279 async fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()> { 280 match self.send_cmd(UciManagerCmd::SetLoggerMode { logger_mode }).await { 281 Ok(UciResponse::SetLoggerMode) => Ok(()), 282 Ok(_) => Err(Error::Unknown), 283 Err(e) => Err(e), 284 } 285 } set_core_notification_sender( &mut self, core_notf_sender: mpsc::UnboundedSender<CoreNotification>, )286 async fn set_core_notification_sender( 287 &mut self, 288 core_notf_sender: mpsc::UnboundedSender<CoreNotification>, 289 ) { 290 let _ = self.send_cmd(UciManagerCmd::SetCoreNotificationSender { core_notf_sender }).await; 291 } set_session_notification_sender( &mut self, session_notf_sender: mpsc::UnboundedSender<SessionNotification>, )292 async fn set_session_notification_sender( 293 &mut self, 294 session_notf_sender: mpsc::UnboundedSender<SessionNotification>, 295 ) { 296 let _ = self 297 .send_cmd(UciManagerCmd::SetSessionNotificationSender { session_notf_sender }) 298 .await; 299 } set_vendor_notification_sender( &mut self, vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, )300 async fn set_vendor_notification_sender( 301 &mut self, 302 vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, 303 ) { 304 let _ = 305 self.send_cmd(UciManagerCmd::SetVendorNotificationSender { vendor_notf_sender }).await; 306 } set_data_rcv_notification_sender( &mut self, data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, )307 async fn set_data_rcv_notification_sender( 308 &mut self, 309 data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, 310 ) { 311 let _ = self 312 .send_cmd(UciManagerCmd::SetDataRcvNotificationSender { data_rcv_notf_sender }) 313 .await; 314 } set_radar_data_rcv_notification_sender( &mut self, radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, )315 async fn set_radar_data_rcv_notification_sender( 316 &mut self, 317 radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, 318 ) { 319 let _ = self 320 .send_cmd(UciManagerCmd::SetRadarDataRcvNotificationSender { 321 radar_data_rcv_notf_sender, 322 }) 323 .await; 324 } 325 set_rf_test_notification_sender( &mut self, rf_test_notf_sender: mpsc::UnboundedSender<RfTestNotification>, )326 async fn set_rf_test_notification_sender( 327 &mut self, 328 rf_test_notf_sender: mpsc::UnboundedSender<RfTestNotification>, 329 ) { 330 let _ = 331 self.send_cmd(UciManagerCmd::SetRfTestNotificationSender { rf_test_notf_sender }).await; 332 } 333 open_hal(&self) -> Result<GetDeviceInfoResponse>334 async fn open_hal(&self) -> Result<GetDeviceInfoResponse> { 335 match self.send_cmd(UciManagerCmd::OpenHal).await { 336 Ok(UciResponse::OpenHal) => { 337 // According to the UCI spec: "The Host shall send CORE_GET_DEVICE_INFO_CMD to 338 // retrieve the device information.", we call get_device_info() after successfully 339 // opening the HAL. 340 let device_info = match self.core_get_device_info().await { 341 Ok(resp) => resp, 342 Err(e) => { 343 return Err(e); 344 } 345 }; 346 debug!("UCI device info: {:?}", device_info); 347 348 Ok(device_info) 349 } 350 Ok(_) => Err(Error::Unknown), 351 Err(e) => Err(e), 352 } 353 } 354 close_hal(&self, force: bool) -> Result<()>355 async fn close_hal(&self, force: bool) -> Result<()> { 356 match self.send_cmd(UciManagerCmd::CloseHal { force }).await { 357 Ok(UciResponse::CloseHal) => Ok(()), 358 Ok(_) => Err(Error::Unknown), 359 Err(e) => Err(e), 360 } 361 } 362 device_reset(&self, reset_config: ResetConfig) -> Result<()>363 async fn device_reset(&self, reset_config: ResetConfig) -> Result<()> { 364 let cmd = UciCommand::DeviceReset { reset_config }; 365 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 366 Ok(UciResponse::DeviceReset(resp)) => resp, 367 Ok(_) => Err(Error::Unknown), 368 Err(e) => Err(e), 369 } 370 } 371 core_get_device_info(&self) -> Result<GetDeviceInfoResponse>372 async fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse> { 373 let cmd = UciCommand::CoreGetDeviceInfo; 374 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 375 Ok(UciResponse::CoreGetDeviceInfo(resp)) => resp, 376 Ok(_) => Err(Error::Unknown), 377 Err(e) => Err(e), 378 } 379 } 380 core_get_caps_info(&self) -> Result<Vec<CapTlv>>381 async fn core_get_caps_info(&self) -> Result<Vec<CapTlv>> { 382 let cmd = UciCommand::CoreGetCapsInfo; 383 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 384 Ok(UciResponse::CoreGetCapsInfo(resp)) => resp, 385 Ok(_) => Err(Error::Unknown), 386 Err(e) => Err(e), 387 } 388 } 389 core_set_config( &self, config_tlvs: Vec<DeviceConfigTlv>, ) -> Result<CoreSetConfigResponse>390 async fn core_set_config( 391 &self, 392 config_tlvs: Vec<DeviceConfigTlv>, 393 ) -> Result<CoreSetConfigResponse> { 394 let cmd = UciCommand::CoreSetConfig { config_tlvs }; 395 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 396 Ok(UciResponse::CoreSetConfig(resp)) => Ok(resp), 397 Ok(_) => Err(Error::Unknown), 398 Err(e) => Err(e), 399 } 400 } 401 core_get_config(&self, cfg_id: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>>402 async fn core_get_config(&self, cfg_id: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>> { 403 let cmd = UciCommand::CoreGetConfig { cfg_id }; 404 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 405 Ok(UciResponse::CoreGetConfig(resp)) => resp, 406 Ok(_) => Err(Error::Unknown), 407 Err(e) => Err(e), 408 } 409 } 410 core_query_uwb_timestamp(&self) -> Result<u64>411 async fn core_query_uwb_timestamp(&self) -> Result<u64> { 412 let cmd = UciCommand::CoreQueryTimeStamp; 413 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 414 Ok(UciResponse::CoreQueryTimeStamp(resp)) => resp, 415 Ok(_) => Err(Error::Unknown), 416 Err(e) => Err(e), 417 } 418 } 419 session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>420 async fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()> { 421 let cmd = UciCommand::SessionInit { session_id, session_type }; 422 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 423 Ok(UciResponse::SessionInit(resp)) => resp.map(|_| {}), 424 Ok(_) => Err(Error::Unknown), 425 Err(e) => Err(e), 426 } 427 } 428 session_deinit(&self, session_id: SessionId) -> Result<()>429 async fn session_deinit(&self, session_id: SessionId) -> Result<()> { 430 let cmd = 431 UciCommand::SessionDeinit { session_token: self.get_session_token(&session_id).await? }; 432 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 433 Ok(UciResponse::SessionDeinit(resp)) => resp, 434 Ok(_) => Err(Error::Unknown), 435 Err(e) => Err(e), 436 } 437 } 438 session_set_app_config( &self, session_id: SessionId, config_tlvs: Vec<AppConfigTlv>, ) -> Result<SetAppConfigResponse>439 async fn session_set_app_config( 440 &self, 441 session_id: SessionId, 442 config_tlvs: Vec<AppConfigTlv>, 443 ) -> Result<SetAppConfigResponse> { 444 let cmd = UciCommand::SessionSetAppConfig { 445 session_token: self.get_session_token(&session_id).await?, 446 config_tlvs, 447 }; 448 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 449 Ok(UciResponse::SessionSetAppConfig(resp)) => Ok(resp), 450 Ok(_) => Err(Error::Unknown), 451 Err(e) => Err(e), 452 } 453 } 454 session_get_app_config( &self, session_id: SessionId, app_cfg: Vec<AppConfigTlvType>, ) -> Result<Vec<AppConfigTlv>>455 async fn session_get_app_config( 456 &self, 457 session_id: SessionId, 458 app_cfg: Vec<AppConfigTlvType>, 459 ) -> Result<Vec<AppConfigTlv>> { 460 let cmd = UciCommand::SessionGetAppConfig { 461 session_token: self.get_session_token(&session_id).await?, 462 app_cfg, 463 }; 464 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 465 Ok(UciResponse::SessionGetAppConfig(resp)) => resp, 466 Ok(_) => Err(Error::Unknown), 467 Err(e) => Err(e), 468 } 469 } 470 session_get_count(&self) -> Result<u8>471 async fn session_get_count(&self) -> Result<u8> { 472 let cmd = UciCommand::SessionGetCount; 473 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 474 Ok(UciResponse::SessionGetCount(resp)) => resp, 475 Ok(_) => Err(Error::Unknown), 476 Err(e) => Err(e), 477 } 478 } 479 session_get_state(&self, session_id: SessionId) -> Result<SessionState>480 async fn session_get_state(&self, session_id: SessionId) -> Result<SessionState> { 481 let cmd = UciCommand::SessionGetState { 482 session_token: self.get_session_token(&session_id).await?, 483 }; 484 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 485 Ok(UciResponse::SessionGetState(resp)) => resp, 486 Ok(_) => Err(Error::Unknown), 487 Err(e) => Err(e), 488 } 489 } 490 session_update_controller_multicast_list( &self, session_id: SessionId, action: UpdateMulticastListAction, controlees: Controlees, is_multicast_list_ntf_v2_supported: bool, is_multicast_list_rsp_v2_supported: bool, ) -> Result<SessionUpdateControllerMulticastResponse>491 async fn session_update_controller_multicast_list( 492 &self, 493 session_id: SessionId, 494 action: UpdateMulticastListAction, 495 controlees: Controlees, 496 is_multicast_list_ntf_v2_supported: bool, 497 is_multicast_list_rsp_v2_supported: bool, 498 ) -> Result<SessionUpdateControllerMulticastResponse> { 499 let controlees_len = match controlees { 500 Controlees::NoSessionKey(ref controlee_vec) => controlee_vec.len(), 501 Controlees::ShortSessionKey(ref controlee_vec) => controlee_vec.len(), 502 Controlees::LongSessionKey(ref controlee_vec) => controlee_vec.len(), 503 }; 504 if !(1..=8).contains(&controlees_len) { 505 warn!("Number of controlees should be between 1 to 8"); 506 return Err(Error::BadParameters); 507 } 508 let cmd = UciCommand::SessionUpdateControllerMulticastList { 509 session_token: self.get_session_token(&session_id).await?, 510 action, 511 controlees, 512 is_multicast_list_ntf_v2_supported, 513 is_multicast_list_rsp_v2_supported, 514 }; 515 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 516 Ok(UciResponse::SessionUpdateControllerMulticastList(resp)) => resp, 517 Ok(_) => Err(Error::Unknown), 518 Err(e) => Err(e), 519 } 520 } 521 session_update_dt_tag_ranging_rounds( &self, session_id: u32, ranging_round_indexes: Vec<u8>, ) -> Result<SessionUpdateDtTagRangingRoundsResponse>522 async fn session_update_dt_tag_ranging_rounds( 523 &self, 524 session_id: u32, 525 ranging_round_indexes: Vec<u8>, 526 ) -> Result<SessionUpdateDtTagRangingRoundsResponse> { 527 let cmd = UciCommand::SessionUpdateDtTagRangingRounds { 528 session_token: self.get_session_token(&session_id).await?, 529 ranging_round_indexes, 530 }; 531 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 532 Ok(UciResponse::SessionUpdateDtTagRangingRounds(resp)) => resp, 533 Ok(_) => Err(Error::Unknown), 534 Err(e) => Err(e), 535 } 536 } 537 session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>538 async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16> { 539 let cmd = UciCommand::SessionQueryMaxDataSize { 540 session_token: self.get_session_token(&session_id).await?, 541 }; 542 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 543 Ok(UciResponse::SessionQueryMaxDataSize(resp)) => resp, 544 Ok(_) => Err(Error::Unknown), 545 Err(e) => Err(e), 546 } 547 } 548 range_start(&self, session_id: SessionId) -> Result<()>549 async fn range_start(&self, session_id: SessionId) -> Result<()> { 550 let cmd = 551 UciCommand::SessionStart { session_token: self.get_session_token(&session_id).await? }; 552 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 553 Ok(UciResponse::SessionStart(resp)) => resp, 554 Ok(_) => Err(Error::Unknown), 555 Err(e) => Err(e), 556 } 557 } 558 range_stop(&self, session_id: SessionId) -> Result<()>559 async fn range_stop(&self, session_id: SessionId) -> Result<()> { 560 let cmd = 561 UciCommand::SessionStop { session_token: self.get_session_token(&session_id).await? }; 562 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 563 Ok(UciResponse::SessionStop(resp)) => resp, 564 Ok(_) => Err(Error::Unknown), 565 Err(e) => Err(e), 566 } 567 } 568 range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>569 async fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize> { 570 let cmd = UciCommand::SessionGetRangingCount { 571 session_token: self.get_session_token(&session_id).await?, 572 }; 573 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 574 Ok(UciResponse::SessionGetRangingCount(resp)) => resp, 575 Ok(_) => Err(Error::Unknown), 576 Err(e) => Err(e), 577 } 578 } 579 android_set_country_code(&self, country_code: CountryCode) -> Result<()>580 async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()> { 581 let cmd = UciCommand::AndroidSetCountryCode { country_code }; 582 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 583 Ok(UciResponse::AndroidSetCountryCode(resp)) => resp, 584 Ok(_) => Err(Error::Unknown), 585 Err(e) => Err(e), 586 } 587 } 588 android_get_power_stats(&self) -> Result<PowerStats>589 async fn android_get_power_stats(&self) -> Result<PowerStats> { 590 let cmd = UciCommand::AndroidGetPowerStats; 591 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 592 Ok(UciResponse::AndroidGetPowerStats(resp)) => resp, 593 Ok(_) => Err(Error::Unknown), 594 Err(e) => Err(e), 595 } 596 } 597 android_set_radar_config( &self, session_id: SessionId, config_tlvs: Vec<RadarConfigTlv>, ) -> Result<AndroidRadarConfigResponse>598 async fn android_set_radar_config( 599 &self, 600 session_id: SessionId, 601 config_tlvs: Vec<RadarConfigTlv>, 602 ) -> Result<AndroidRadarConfigResponse> { 603 let cmd = UciCommand::AndroidSetRadarConfig { 604 session_token: self.get_session_token(&session_id).await?, 605 config_tlvs, 606 }; 607 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 608 Ok(UciResponse::AndroidSetRadarConfig(resp)) => Ok(resp), 609 Ok(_) => Err(Error::Unknown), 610 Err(e) => Err(e), 611 } 612 } 613 android_get_radar_config( &self, session_id: SessionId, radar_cfg: Vec<RadarConfigTlvType>, ) -> Result<Vec<RadarConfigTlv>>614 async fn android_get_radar_config( 615 &self, 616 session_id: SessionId, 617 radar_cfg: Vec<RadarConfigTlvType>, 618 ) -> Result<Vec<RadarConfigTlv>> { 619 let cmd = UciCommand::AndroidGetRadarConfig { 620 session_token: self.get_session_token(&session_id).await?, 621 radar_cfg, 622 }; 623 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 624 Ok(UciResponse::AndroidGetRadarConfig(resp)) => resp, 625 Ok(_) => Err(Error::Unknown), 626 Err(e) => Err(e), 627 } 628 } 629 raw_uci_cmd( &self, mt: u32, gid: u32, oid: u32, payload: Vec<u8>, ) -> Result<RawUciMessage>630 async fn raw_uci_cmd( 631 &self, 632 mt: u32, 633 gid: u32, 634 oid: u32, 635 payload: Vec<u8>, 636 ) -> Result<RawUciMessage> { 637 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload }; 638 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 639 Ok(UciResponse::RawUciCmd(resp)) => resp, 640 Ok(_) => Err(Error::Unknown), 641 Err(e) => Err(e), 642 } 643 } 644 645 // Send a data packet to the UWBS (use the UciManagerActor). send_data_packet( &self, session_id: SessionId, dest_mac_address_bytes: Vec<u8>, uci_sequence_number: u16, data: Vec<u8>, ) -> Result<()>646 async fn send_data_packet( 647 &self, 648 session_id: SessionId, 649 dest_mac_address_bytes: Vec<u8>, 650 uci_sequence_number: u16, 651 data: Vec<u8>, 652 ) -> Result<()> { 653 debug!( 654 "send_data_packet(): will Tx a data packet, session_id {}, sequence_number {}", 655 session_id, uci_sequence_number 656 ); 657 let dest_mac_address = bytes_to_u64(dest_mac_address_bytes).ok_or(Error::BadParameters)?; 658 let data_snd_packet = uwb_uci_packets::UciDataSndBuilder { 659 session_token: self.get_session_token(&session_id).await?, 660 dest_mac_address, 661 uci_sequence_number, 662 data, 663 } 664 .build(); 665 666 match self.send_cmd(UciManagerCmd::SendUciData { data_snd_packet }).await { 667 Ok(UciResponse::SendUciData(resp)) => resp, 668 Ok(_) => Err(Error::Unknown), 669 Err(e) => Err(e), 670 } 671 } 672 673 // set Data transfer phase config session_data_transfer_phase_config( &self, session_id: SessionId, dtpcm_repetition: u8, data_transfer_control: u8, dtpml_size: u8, mac_address: Vec<u8>, slot_bitmap: Vec<u8>, stop_data_transfer: Vec<u8>, ) -> Result<()>674 async fn session_data_transfer_phase_config( 675 &self, 676 session_id: SessionId, 677 dtpcm_repetition: u8, 678 data_transfer_control: u8, 679 dtpml_size: u8, 680 mac_address: Vec<u8>, 681 slot_bitmap: Vec<u8>, 682 stop_data_transfer: Vec<u8>, 683 ) -> Result<()> { 684 let cmd = UciCommand::SessionDataTransferPhaseConfig { 685 session_token: self.get_session_token(&session_id).await?, 686 dtpcm_repetition, 687 data_transfer_control, 688 dtpml_size, 689 mac_address, 690 slot_bitmap, 691 stop_data_transfer, 692 }; 693 694 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 695 Ok(UciResponse::SessionDataTransferPhaseConfig(resp)) => resp, 696 Ok(_) => Err(Error::Unknown), 697 Err(e) => Err(e), 698 } 699 } 700 701 // Get session token from session id (no uci call). get_session_token_from_session_id( &self, session_id: SessionId, ) -> Result<SessionToken>702 async fn get_session_token_from_session_id( 703 &self, 704 session_id: SessionId, 705 ) -> Result<SessionToken> { 706 Ok(self.get_session_token(&session_id).await?) 707 } 708 709 /// Send UCI command for setting hybrid controller config session_set_hybrid_controller_config( &self, session_id: SessionId, number_of_phases: u8, phase_list: Vec<ControllerPhaseList>, ) -> Result<()>710 async fn session_set_hybrid_controller_config( 711 &self, 712 session_id: SessionId, 713 number_of_phases: u8, 714 phase_list: Vec<ControllerPhaseList>, 715 ) -> Result<()> { 716 let cmd = UciCommand::SessionSetHybridControllerConfig { 717 session_token: self.get_session_token(&session_id).await?, 718 number_of_phases, 719 phase_list, 720 }; 721 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 722 Ok(UciResponse::SessionSetHybridControllerConfig(resp)) => resp, 723 Ok(_) => Err(Error::Unknown), 724 Err(e) => Err(e), 725 } 726 } 727 728 /// Send UCI command for setting hybrid controlee config session_set_hybrid_controlee_config( &self, session_id: SessionId, controlee_phase_list: Vec<ControleePhaseList>, ) -> Result<()>729 async fn session_set_hybrid_controlee_config( 730 &self, 731 session_id: SessionId, 732 controlee_phase_list: Vec<ControleePhaseList>, 733 ) -> Result<()> { 734 let cmd = UciCommand::SessionSetHybridControleeConfig { 735 session_token: self.get_session_token(&session_id).await?, 736 controlee_phase_list, 737 }; 738 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 739 Ok(UciResponse::SessionSetHybridControleeConfig(resp)) => resp, 740 Ok(_) => Err(Error::Unknown), 741 Err(e) => Err(e), 742 } 743 } 744 session_set_rf_test_config( &self, session_id: SessionId, config_tlvs: Vec<RfTestConfigTlv>, ) -> Result<RfTestConfigResponse>745 async fn session_set_rf_test_config( 746 &self, 747 session_id: SessionId, 748 config_tlvs: Vec<RfTestConfigTlv>, 749 ) -> Result<RfTestConfigResponse> { 750 let cmd = UciCommand::SessionSetRfTestConfig { 751 session_token: self.get_session_token(&session_id).await?, 752 config_tlvs, 753 }; 754 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 755 Ok(UciResponse::SessionSetRfTestConfig(resp)) => Ok(resp), 756 Ok(_) => Err(Error::Unknown), 757 Err(e) => Err(e), 758 } 759 } 760 rf_test_periodic_tx(&self, psdu_data: Vec<u8>) -> Result<()>761 async fn rf_test_periodic_tx(&self, psdu_data: Vec<u8>) -> Result<()> { 762 let cmd = UciCommand::TestPeriodicTx { psdu_data }; 763 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 764 Ok(UciResponse::RfTest(resp)) => resp, 765 Ok(_) => Err(Error::Unknown), 766 Err(e) => Err(e), 767 } 768 } 769 rf_test_per_rx(&self, psdu_data: Vec<u8>) -> Result<()>770 async fn rf_test_per_rx(&self, psdu_data: Vec<u8>) -> Result<()> { 771 let cmd = UciCommand::TestPerRx { psdu_data }; 772 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 773 Ok(UciResponse::RfTest(resp)) => resp, 774 Ok(_) => Err(Error::Unknown), 775 Err(e) => Err(e), 776 } 777 } 778 stop_rf_test(&self) -> Result<()>779 async fn stop_rf_test(&self) -> Result<()> { 780 let cmd = UciCommand::StopRfTest; 781 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 782 Ok(UciResponse::RfTest(resp)) => resp, 783 Ok(_) => Err(Error::Unknown), 784 Err(e) => Err(e), 785 } 786 } 787 } 788 789 struct UciManagerActor<T: UciHal, U: UciLogger> { 790 // The UCI HAL. 791 hal: TimeoutUciHal<T>, 792 // UCI Log. 793 logger: UciLoggerWrapper<U>, 794 // Receive the commands and the corresponding response senders from UciManager. 795 cmd_receiver: mpsc::UnboundedReceiver<(UciManagerCmd, oneshot::Sender<Result<UciResponse>>)>, 796 797 // Set to true when |hal| is opened successfully. 798 is_hal_opened: bool, 799 // Receive response, notification and data packets from |mut hal|. Only used when |hal| is opened 800 // successfully. 801 packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>, 802 // Defrag the UCI packets. 803 defrager: uwb_uci_packets::PacketDefrager, 804 805 // The response sender of UciManager's open_hal() method. Used to wait for the device ready 806 // notification. 807 open_hal_result_sender: Option<oneshot::Sender<Result<UciResponse>>>, 808 809 // Store per-session CreditAvailability. This should be initialized when a UWB session becomes 810 // ACTIVE, and updated every time a Data packet fragment is sent or a DataCreditNtf is received. 811 data_credit_map: HashMap<SessionToken, CreditAvailability>, 812 813 // Store the Uci Data packet fragments to be sent to the UWBS, keyed by the SessionId. This 814 // helps to retrieve the next packet fragment to be sent, when the UWBS is ready to accept it. 815 data_packet_fragments_map: HashMap<SessionToken, VecDeque<UciDataPacketHal>>, 816 817 // The timeout of waiting for the notification of device ready notification. 818 wait_device_status_timeout: PinSleep, 819 820 // Used for the logic of retrying the command. Only valid when waiting for the response of a 821 // UCI command. 822 uci_cmd_retryer: Option<UciCmdRetryer>, 823 // The timeout of waiting for the response. Only used when waiting for the response of a UCI 824 // command. 825 wait_resp_timeout: PinSleep, 826 827 // Used for the logic of retrying the DataSnd packet. Only valid when waiting for the 828 // DATA_TRANSFER_STATUS_NTF. 829 uci_data_snd_retryer: Option<UciDataSndRetryer>, 830 831 // Used to identify if response corresponds to the last vendor command, if so return 832 // a raw packet as a response to the sender. 833 last_raw_cmd: Option<RawUciControlPacket>, 834 835 // Send the notifications to the caller of UciManager. 836 core_notf_sender: mpsc::UnboundedSender<CoreNotification>, 837 session_notf_sender: mpsc::UnboundedSender<SessionNotification>, 838 vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, 839 data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, 840 radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, 841 rf_test_notf_sender: mpsc::UnboundedSender<RfTestNotification>, 842 843 // Used to store the last init session id to help map the session handle sent 844 // in session int response can be correctly mapped. 845 last_init_session_id: Option<SessionId>, 846 // FIRA version 2 introduces a UWBS generated session handle to use as identifier for all 847 // session related commands. This map stores the app provided session id to UWBS generated 848 // session handle mapping if provided, else reuses session id. 849 session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>, 850 851 // Used to store the UWBS response for the UCI CMD CORE_GET_DEVICE_INFO. This will help us 852 // identify the UWBS supported UCI version and change our behavior accordingly. 853 get_device_info_rsp: Option<GetDeviceInfoResponse>, 854 855 // The maximum payload size that can be sent in one Data packet fragment to the UWBS. The UCI 856 // DATA_MSG_SEND packets (from Host to UWBS), larger than this should be fragmented into 857 // multiple packets with this as the payload size. 858 max_data_packet_payload_size: usize, 859 860 // The flag that indicate whether multicast list ntf v2 is supported. 861 is_multicast_list_ntf_v2_supported: bool, 862 863 // The flag that indicate whether multicast list rsp v2 is supported. 864 is_multicast_list_rsp_v2_supported: bool, 865 } 866 867 impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> { new( hal: T, logger: U, logger_mode: UciLoggerMode, cmd_receiver: mpsc::UnboundedReceiver<( UciManagerCmd, oneshot::Sender<Result<UciResponse>>, )>, session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>, ) -> Self868 fn new( 869 hal: T, 870 logger: U, 871 logger_mode: UciLoggerMode, 872 cmd_receiver: mpsc::UnboundedReceiver<( 873 UciManagerCmd, 874 oneshot::Sender<Result<UciResponse>>, 875 )>, 876 session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>, 877 ) -> Self { 878 Self { 879 hal: TimeoutUciHal::new(hal), 880 logger: UciLoggerWrapper::new(logger, logger_mode), 881 cmd_receiver, 882 is_hal_opened: false, 883 packet_receiver: mpsc::unbounded_channel().1, 884 defrager: Default::default(), 885 open_hal_result_sender: None, 886 data_credit_map: HashMap::new(), 887 data_packet_fragments_map: HashMap::new(), 888 wait_device_status_timeout: PinSleep::new(Duration::MAX), 889 uci_cmd_retryer: None, 890 uci_data_snd_retryer: None, 891 wait_resp_timeout: PinSleep::new(Duration::MAX), 892 last_raw_cmd: None, 893 core_notf_sender: mpsc::unbounded_channel().0, 894 session_notf_sender: mpsc::unbounded_channel().0, 895 vendor_notf_sender: mpsc::unbounded_channel().0, 896 data_rcv_notf_sender: mpsc::unbounded_channel().0, 897 radar_data_rcv_notf_sender: mpsc::unbounded_channel().0, 898 rf_test_notf_sender: mpsc::unbounded_channel().0, 899 last_init_session_id: None, 900 session_id_to_token_map, 901 get_device_info_rsp: None, 902 max_data_packet_payload_size: MAX_DATA_PACKET_PAYLOAD_SIZE, 903 is_multicast_list_ntf_v2_supported: false, 904 is_multicast_list_rsp_v2_supported: false, 905 } 906 } 907 run(&mut self)908 async fn run(&mut self) { 909 loop { 910 tokio::select! { 911 // Handle the next command. Only when the previous command already received the 912 // response. 913 cmd = self.cmd_receiver.recv(), if !self.is_waiting_resp() => { 914 match cmd { 915 None => { 916 debug!("UciManager is about to drop."); 917 break; 918 }, 919 Some((cmd, result_sender)) => { 920 self.handle_cmd(cmd, result_sender).await; 921 } 922 } 923 } 924 925 // Handle the UCI response, notification or data packet from HAL. Only when HAL 926 // is opened. 927 packet = self.packet_receiver.recv(), if self.is_hal_opened => { 928 self.handle_hal_packet(packet).await; 929 } 930 931 // Timeout waiting for the response of the UCI command. 932 _ = &mut self.wait_resp_timeout, if self.is_waiting_resp() => { 933 if let Some(uci_cmd_retryer) = self.uci_cmd_retryer.take() { 934 uci_cmd_retryer.send_result(Err(Error::Timeout)); 935 } 936 } 937 938 // Timeout waiting for the notification of the device status. 939 _ = &mut self.wait_device_status_timeout, if self.is_waiting_device_status() => { 940 if let Some(result_sender) = self.open_hal_result_sender.take() { 941 let _ = result_sender.send(Err(Error::Timeout)); 942 } 943 } 944 } 945 } 946 947 if self.is_hal_opened { 948 debug!("The HAL is still opened when exit, close the HAL"); 949 let _ = self.hal.close().await; 950 self.on_hal_closed().await; 951 } 952 } 953 insert_session_token(&self, session_id: SessionId, session_token: SessionToken)954 async fn insert_session_token(&self, session_id: SessionId, session_token: SessionToken) { 955 self.session_id_to_token_map.lock().await.insert(session_id, session_token); 956 } 957 remove_session_token(&self, session_token: &SessionToken)958 async fn remove_session_token(&self, session_token: &SessionToken) { 959 self.session_id_to_token_map.lock().await.retain(|_, val| *val != *session_token); 960 } 961 get_session_id(&self, session_token: &SessionToken) -> Result<SessionId>962 async fn get_session_id(&self, session_token: &SessionToken) -> Result<SessionId> { 963 self.session_id_to_token_map 964 .lock() 965 .await 966 .iter() 967 .find_map(|(key, &val)| if val == *session_token { Some(key) } else { None }) 968 .ok_or(Error::BadParameters) 969 .copied() 970 } 971 save_session_id_if_init_cmd(&mut self, cmd: &UciCommand)972 fn save_session_id_if_init_cmd(&mut self, cmd: &UciCommand) { 973 // Store the last init session id to help map the session handle sent 974 // in session init response. 975 if let UciCommand::SessionInit { session_id, .. } = cmd { 976 self.last_init_session_id = Some(*session_id); 977 } 978 } 979 store_session_token_if_init_resp(&mut self, resp: &UciResponse) -> Result<()>980 async fn store_session_token_if_init_resp(&mut self, resp: &UciResponse) -> Result<()> { 981 // Store the session_id to session_token mapping for this new session. 982 if let UciResponse::SessionInit(session_init_resp) = resp { 983 let session_id = match self.last_init_session_id.take() { 984 Some(session_id) => session_id, 985 None => { 986 return Err(Error::Unknown); 987 } 988 }; 989 if let Ok(opt_session_handle) = session_init_resp { 990 let session_handle = match opt_session_handle { 991 // Session Handle provided by UWBS, use as token for further commands. 992 Some(session_handle) => { 993 info!( 994 "session handle: {:?} provided for session id: {:?}", 995 session_handle, session_id 996 ); 997 *session_handle 998 } 999 // Session Handle not provided by UWBS, reuse session id as token for further commands. 1000 None => session_id, 1001 }; 1002 self.insert_session_token(session_id, session_handle).await; 1003 } 1004 } 1005 Ok(()) 1006 } 1007 1008 // Store the GET_DEVICE_INFO RSP from UWBS. store_if_uwbs_device_info(&mut self, resp: &UciResponse)1009 fn store_if_uwbs_device_info(&mut self, resp: &UciResponse) { 1010 if let UciResponse::CoreGetDeviceInfo(Ok(get_device_info_rsp)) = resp { 1011 self.get_device_info_rsp = Some(get_device_info_rsp.clone()); 1012 } 1013 } 1014 get_uwbs_uci_major_version(&mut self) -> Option<u8>1015 fn get_uwbs_uci_major_version(&mut self) -> Option<u8> { 1016 if let Some(core_get_device_info_rsp) = &self.get_device_info_rsp { 1017 // Byte 0 : Major UCI version 1018 // Calling unwrap() will be safe here as with the bitmask, the value will be within u8. 1019 return Some((core_get_device_info_rsp.uci_version & 0xFF).try_into().unwrap()); 1020 } 1021 None 1022 } 1023 1024 #[allow(unknown_lints)] 1025 #[allow(clippy::unnecessary_fallible_conversions)] store_if_uwbs_caps_info(&mut self, resp: &UciResponse)1026 fn store_if_uwbs_caps_info(&mut self, resp: &UciResponse) { 1027 if let UciResponse::CoreGetCapsInfo(Ok(tlvs)) = resp { 1028 if let Some(core_get_device_info_rsp) = &self.get_device_info_rsp { 1029 let major_uci_version = core_get_device_info_rsp.uci_version & 0xFF; // Byte 0 1030 let tlvtag = if major_uci_version >= 2 { 1031 CapTlvType::SupportedV1FiraMacVersionRangeV2MaxDataPayloadSize 1032 } else { 1033 CapTlvType::SupportedV1MaxDataPacketPayloadSizeV2AoaSupport 1034 }; 1035 for tlv in tlvs { 1036 if tlv.t == tlvtag { 1037 // Convert the 2-byte UWBS capability value (stored as Vec<u8>) into usize. 1038 self.max_data_packet_payload_size = match bytes_to_u16(tlv.v.clone()) { 1039 Some(u16size) => match u16size.try_into() { 1040 Ok(size) => size, 1041 Err(_) => MAX_DATA_PACKET_PAYLOAD_SIZE, 1042 }, 1043 None => MAX_DATA_PACKET_PAYLOAD_SIZE, 1044 }; 1045 } 1046 } 1047 } 1048 } 1049 } 1050 handle_cmd( &mut self, cmd: UciManagerCmd, result_sender: oneshot::Sender<Result<UciResponse>>, )1051 async fn handle_cmd( 1052 &mut self, 1053 cmd: UciManagerCmd, 1054 result_sender: oneshot::Sender<Result<UciResponse>>, 1055 ) { 1056 debug!("Received cmd: {:?}", cmd); 1057 1058 match cmd { 1059 UciManagerCmd::SetLoggerMode { logger_mode } => { 1060 self.logger.set_logger_mode(logger_mode); 1061 let _ = result_sender.send(Ok(UciResponse::SetLoggerMode)); 1062 } 1063 UciManagerCmd::SetCoreNotificationSender { core_notf_sender } => { 1064 self.core_notf_sender = core_notf_sender; 1065 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 1066 } 1067 UciManagerCmd::SetSessionNotificationSender { session_notf_sender } => { 1068 self.session_notf_sender = session_notf_sender; 1069 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 1070 } 1071 UciManagerCmd::SetVendorNotificationSender { vendor_notf_sender } => { 1072 self.vendor_notf_sender = vendor_notf_sender; 1073 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 1074 } 1075 UciManagerCmd::SetDataRcvNotificationSender { data_rcv_notf_sender } => { 1076 self.data_rcv_notf_sender = data_rcv_notf_sender; 1077 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 1078 } 1079 UciManagerCmd::SetRadarDataRcvNotificationSender { radar_data_rcv_notf_sender } => { 1080 self.radar_data_rcv_notf_sender = radar_data_rcv_notf_sender; 1081 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 1082 } 1083 UciManagerCmd::SetRfTestNotificationSender { rf_test_notf_sender } => { 1084 self.rf_test_notf_sender = rf_test_notf_sender; 1085 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 1086 } 1087 UciManagerCmd::OpenHal => { 1088 if self.is_hal_opened { 1089 warn!("The UCI HAL is already opened, skip."); 1090 let _ = result_sender.send(Err(Error::BadParameters)); 1091 return; 1092 } 1093 1094 let (packet_sender, packet_receiver) = mpsc::unbounded_channel(); 1095 let result = self.hal.open(packet_sender).await; 1096 self.logger.log_hal_open(&result); 1097 match result { 1098 Ok(()) => { 1099 self.on_hal_open(packet_receiver); 1100 self.wait_device_status_timeout = 1101 PinSleep::new(Duration::from_millis(UCI_TIMEOUT_MS)); 1102 self.open_hal_result_sender.replace(result_sender); 1103 } 1104 Err(e) => { 1105 error!("Failed to open hal: {:?}", e); 1106 let _ = result_sender.send(Err(e)); 1107 } 1108 } 1109 } 1110 1111 UciManagerCmd::CloseHal { force } => { 1112 if force { 1113 debug!("Force closing the UCI HAL"); 1114 let close_result = self.hal.close().await; 1115 self.logger.log_hal_close(&close_result); 1116 self.on_hal_closed().await; 1117 let _ = result_sender.send(Ok(UciResponse::CloseHal)); 1118 } else { 1119 if !self.is_hal_opened { 1120 warn!("The UCI HAL is already closed, skip."); 1121 let _ = result_sender.send(Err(Error::BadParameters)); 1122 return; 1123 } 1124 1125 let result = self.hal.close().await; 1126 self.logger.log_hal_close(&result); 1127 if result.is_ok() { 1128 self.on_hal_closed().await; 1129 } 1130 let _ = result_sender.send(result.map(|_| UciResponse::CloseHal)); 1131 } 1132 } 1133 1134 UciManagerCmd::SendUciCommand { cmd } => { 1135 debug_assert!(self.uci_cmd_retryer.is_none()); 1136 1137 self.save_session_id_if_init_cmd(&cmd); 1138 1139 // Remember that this command is a raw UCI command, we'll use this later 1140 // to send a raw UCI response. 1141 if let UciCommand::RawUciCmd { mt: _, gid, oid, payload: _ } = cmd.clone() { 1142 let gid_u8 = u8::try_from(gid); 1143 if gid_u8.is_err() || GroupId::try_from(gid_u8.unwrap()).is_err() { 1144 error!("Received an invalid GID={} for RawUciCmd", gid); 1145 let _ = result_sender.send(Err(Error::BadParameters)); 1146 return; 1147 } 1148 1149 let oid_u8 = u8::try_from(oid); 1150 if oid_u8.is_err() { 1151 error!("Received an invalid OID={} for RawUciCmd", oid); 1152 let _ = result_sender.send(Err(Error::BadParameters)); 1153 return; 1154 } 1155 self.last_raw_cmd = Some(RawUciControlPacket { 1156 mt: u8::from(MessageType::Command), 1157 gid: gid_u8.unwrap(), // Safe as we check gid_u8.is_err() above. 1158 oid: oid_u8.unwrap(), // Safe as we check uid_i8.is_err() above. 1159 payload: Vec::new(), // There's no need to store the Raw UCI CMD's payload. 1160 }); 1161 } 1162 1163 if let UciCommand::SessionUpdateControllerMulticastList { 1164 session_token: _, 1165 action: _, 1166 controlees: _, 1167 is_multicast_list_ntf_v2_supported, 1168 is_multicast_list_rsp_v2_supported, 1169 } = cmd.clone() 1170 { 1171 self.is_multicast_list_ntf_v2_supported = is_multicast_list_ntf_v2_supported; 1172 self.is_multicast_list_rsp_v2_supported = is_multicast_list_rsp_v2_supported; 1173 } 1174 1175 self.uci_cmd_retryer = 1176 Some(UciCmdRetryer { cmd, result_sender, retry_count: MAX_RETRY_COUNT }); 1177 1178 // Reset DataSndRetryer so if a CORE_GENERIC_ERROR_NTF with STATUS_UCI_PACKET_RETRY 1179 // is received, only this UCI CMD packet will be retried. 1180 let _ = self.uci_data_snd_retryer.take(); 1181 1182 self.retry_uci_cmd().await; 1183 } 1184 1185 UciManagerCmd::SendUciData { data_snd_packet } => { 1186 let result = self.handle_data_snd_packet(data_snd_packet).await; 1187 let _ = result_sender.send(result); 1188 } 1189 } 1190 } 1191 retry_uci_cmd(&mut self)1192 async fn retry_uci_cmd(&mut self) { 1193 if let Some(mut uci_cmd_retryer) = self.uci_cmd_retryer.take() { 1194 if !uci_cmd_retryer.could_retry() { 1195 error!("Out of retries for Uci Cmd packet"); 1196 uci_cmd_retryer.send_result(Err(Error::Timeout)); 1197 return; 1198 } 1199 1200 match self.send_uci_command(uci_cmd_retryer.cmd.clone()).await { 1201 Ok(_) => { 1202 self.wait_resp_timeout = PinSleep::new(Duration::from_millis(UCI_TIMEOUT_MS)); 1203 self.uci_cmd_retryer = Some(uci_cmd_retryer); 1204 } 1205 Err(e) => { 1206 error!("Uci Cmd send resulted in error:{}", e); 1207 uci_cmd_retryer.send_result(Err(e)); 1208 } 1209 } 1210 } 1211 } 1212 retry_uci_data_snd(&mut self)1213 async fn retry_uci_data_snd(&mut self) { 1214 if let Some(mut uci_data_snd_retryer) = self.uci_data_snd_retryer.take() { 1215 let data_packet_session_token = uci_data_snd_retryer.data_packet_session_token; 1216 if !uci_data_snd_retryer.could_retry() { 1217 error!( 1218 "Out of retries for Uci DataSnd packet, last DataSnd packet session_id:{}", 1219 data_packet_session_token 1220 ); 1221 return; 1222 } 1223 1224 match self 1225 .hal 1226 .send_packet(uci_data_snd_retryer.data_packet.encode_to_vec().unwrap()) 1227 .await 1228 { 1229 Ok(_) => { 1230 self.uci_data_snd_retryer = Some(uci_data_snd_retryer); 1231 } 1232 Err(e) => { 1233 error!( 1234 "DataSnd packet fragment session_id:{} retry failed with error:{}", 1235 data_packet_session_token, e 1236 ); 1237 } 1238 } 1239 } 1240 } 1241 send_uci_command(&mut self, cmd: UciCommand) -> Result<()>1242 async fn send_uci_command(&mut self, cmd: UciCommand) -> Result<()> { 1243 if !self.is_hal_opened { 1244 warn!("The UCI HAL is already closed, skip."); 1245 return Err(Error::BadParameters); 1246 } 1247 let result = self.hal.send_command(cmd.clone()).await; 1248 if result.is_ok() { 1249 self.logger.log_uci_command(&cmd); 1250 } 1251 result 1252 } 1253 handle_data_snd_packet(&mut self, data_snd_packet: UciDataSnd) -> Result<UciResponse>1254 async fn handle_data_snd_packet(&mut self, data_snd_packet: UciDataSnd) -> Result<UciResponse> { 1255 // Verify that there's an entry for the Session in the CreditAvailability map. 1256 let data_packet_session_token = data_snd_packet.get_session_token(); 1257 let data_packet_sequence_number = data_snd_packet.get_uci_sequence_number(); 1258 1259 if !self.data_credit_map.contains_key(&data_packet_session_token) { 1260 error!( 1261 "DataSnd packet session_token:{}, sequence_number:{} cannot be sent as unknown \ 1262 credit availability for the session", 1263 data_packet_session_token, data_packet_sequence_number 1264 ); 1265 return Err(Error::PacketTxError); 1266 } 1267 1268 // Enqueue the data packet fragments, from the data packet to be sent to UWBS. 1269 let mut packet_fragments: Vec<UciDataPacketHal> = 1270 fragment_data_msg_send(data_snd_packet, self.max_data_packet_payload_size); 1271 if packet_fragments.is_empty() { 1272 error!( 1273 "DataSnd packet session_token:{}, sequence number:{} could not be split into fragments", 1274 data_packet_session_token, data_packet_sequence_number 1275 ); 1276 return Err(Error::PacketTxError); 1277 } 1278 1279 match self.data_packet_fragments_map.get_mut(&data_packet_session_token) { 1280 Some(q) => { 1281 for p in packet_fragments.drain(..) { 1282 q.push_back(p); 1283 } 1284 } 1285 None => { 1286 error!( 1287 "DataSnd packet fragments map not found for session_token:{}", 1288 data_packet_session_token 1289 ); 1290 return Err(Error::PacketTxError); 1291 } 1292 } 1293 1294 self.send_data_packet_fragment(data_packet_session_token).await 1295 } 1296 send_data_packet_fragment( &mut self, data_packet_session_token: SessionToken, ) -> Result<UciResponse>1297 async fn send_data_packet_fragment( 1298 &mut self, 1299 data_packet_session_token: SessionToken, 1300 ) -> Result<UciResponse> { 1301 // Check if a credit is available before sending this data packet fragment. If not, return 1302 // for now, and send this packet later when the credit becomes available (indicated by 1303 // receiving a DataCreditNtf). 1304 let credit = self.data_credit_map.get(&data_packet_session_token); 1305 if credit.is_none() { 1306 error!( 1307 "DataSnd packet fragment cannot be sent for session_token:{} as unknown \ 1308 credit availability for the session", 1309 data_packet_session_token 1310 ); 1311 return Err(Error::PacketTxError); 1312 } 1313 if credit == Some(&CreditAvailability::CreditNotAvailable) { 1314 return Ok(UciResponse::SendUciData(Ok(()))); 1315 } 1316 1317 // We have credit available, let's send the packet to UWBS. 1318 let hal_data_packet_fragment = 1319 match self.data_packet_fragments_map.get_mut(&data_packet_session_token) { 1320 Some(q) => { 1321 match q.pop_front() { 1322 Some(p) => p, 1323 None => { 1324 // No more packets left to send. 1325 return Ok(UciResponse::SendUciData(Ok(()))); 1326 } 1327 } 1328 } 1329 None => { 1330 return Err(Error::PacketTxError); 1331 } 1332 }; 1333 1334 // Create and save a retryer for sending this data packet fragment. 1335 self.uci_data_snd_retryer = Some(UciDataSndRetryer { 1336 data_packet: hal_data_packet_fragment.clone(), 1337 data_packet_session_token, 1338 retry_count: MAX_RETRY_COUNT, 1339 }); 1340 1341 let result = self.hal.send_packet(hal_data_packet_fragment.encode_to_vec().unwrap()).await; 1342 if result.is_err() { 1343 error!( 1344 "Result {:?} of sending data packet fragment SessionToken: {} to HAL", 1345 result, data_packet_session_token 1346 ); 1347 return Err(Error::PacketTxError); 1348 } 1349 1350 // Update the map after the successful write. 1351 self.data_credit_map 1352 .insert(data_packet_session_token, CreditAvailability::CreditNotAvailable); 1353 Ok(UciResponse::SendUciData(Ok(()))) 1354 } 1355 handle_hal_packet(&mut self, packet: Option<UciHalPacket>)1356 async fn handle_hal_packet(&mut self, packet: Option<UciHalPacket>) { 1357 let defrag_packet = match packet { 1358 Some(rx_packet) => { 1359 self.defrager.defragment_packet(&rx_packet, self.last_raw_cmd.clone()) 1360 } 1361 None => { 1362 warn!("UciHal dropped the packet_sender unexpectedly."); 1363 self.on_hal_closed().await; 1364 return; 1365 } 1366 }; 1367 let defrag_packet = match defrag_packet { 1368 Some(p) => p, 1369 None => return, 1370 }; 1371 1372 match defrag_packet { 1373 UciDefragPacket::Control(packet) => { 1374 self.logger.log_uci_response_or_notification(&packet); 1375 1376 // Use a safe value of Fira 1.x as the UWBS UCI version. 1377 let uci_fira_major_version = self.get_uwbs_uci_major_version().unwrap_or(1); 1378 match ( 1379 packet, 1380 UCIMajorVersion::from_u8(uci_fira_major_version) 1381 .map_or(UCIMajorVersion::V1, |v| v), 1382 self.is_multicast_list_ntf_v2_supported, 1383 self.is_multicast_list_rsp_v2_supported, 1384 ) 1385 .try_into() 1386 { 1387 Ok(UciMessage::Response(resp)) => { 1388 self.handle_response(resp).await; 1389 } 1390 Ok(UciMessage::Notification(notf)) => { 1391 self.handle_notification(notf).await; 1392 } 1393 Err(e) => { 1394 error!("Failed to parse received message: {:?}", e); 1395 } 1396 } 1397 } 1398 UciDefragPacket::Data(packet) => { 1399 self.logger.log_uci_data(&packet); 1400 self.handle_data_rcv(packet).await; 1401 } 1402 UciDefragPacket::Raw(result, raw_uci_control_packet) => { 1403 // Handle response to raw UCI cmd. We want to send it back as 1404 // raw UCI message instead of standard response message. 1405 let resp = match result { 1406 Ok(()) => { 1407 // We should receive only a valid UCI response packet here. 1408 UciResponse::RawUciCmd(Ok(RawUciMessage { 1409 gid: raw_uci_control_packet.gid.into(), 1410 oid: raw_uci_control_packet.oid.into(), 1411 payload: raw_uci_control_packet.payload, 1412 })) 1413 } 1414 // TODO: Implement conversion between Error::InvalidPacketError (returned by 1415 // lib.rs and defined in the PDL uci_packets.rs) and the uwb_core::Error enums. 1416 Err(_) => UciResponse::RawUciCmd(Err(Error::Unknown)), 1417 }; 1418 self.handle_response(resp).await; 1419 self.last_raw_cmd = None; 1420 } 1421 } 1422 } 1423 handle_response(&mut self, resp: UciResponse)1424 async fn handle_response(&mut self, resp: UciResponse) { 1425 if resp.need_retry() { 1426 self.retry_uci_cmd().await; 1427 return; 1428 } 1429 1430 if let Err(_e) = self.store_session_token_if_init_resp(&resp).await { 1431 error!("Session init response received without a sesson id stored! Something has gone badly wrong: {:?}", resp); 1432 return; 1433 } 1434 self.store_if_uwbs_device_info(&resp); 1435 self.store_if_uwbs_caps_info(&resp); 1436 1437 if let Some(uci_cmd_retryer) = self.uci_cmd_retryer.take() { 1438 uci_cmd_retryer.send_result(Ok(resp)); 1439 } else { 1440 warn!("Received an UCI response unexpectedly: {:?}", resp); 1441 } 1442 } 1443 handle_notification(&mut self, notf: UciNotification)1444 async fn handle_notification(&mut self, notf: UciNotification) { 1445 if notf.need_retry() { 1446 // Retry sending both last sent UCI CMD and UCI DataSnd packet since the notification 1447 // could be for either of them. 1448 self.retry_uci_cmd().await; 1449 self.retry_uci_data_snd().await; 1450 return; 1451 } 1452 1453 match notf { 1454 UciNotification::Core(core_notf) => { 1455 if let CoreNotification::DeviceStatus(status) = core_notf { 1456 if let Some(result_sender) = self.open_hal_result_sender.take() { 1457 let result = match status { 1458 DeviceState::DeviceStateReady | DeviceState::DeviceStateActive => { 1459 Ok(UciResponse::OpenHal) 1460 } 1461 _ => Err(Error::Unknown), 1462 }; 1463 let _ = result_sender.send(result); 1464 } 1465 } 1466 let _ = self.core_notf_sender.send(core_notf); 1467 } 1468 UciNotification::Session(orig_session_notf) => { 1469 let mod_session_notf = { 1470 match self.add_session_id_to_session_status_ntf(orig_session_notf.clone()).await 1471 { 1472 Ok(session_notf) => session_notf, 1473 Err(e) => { 1474 error!("Failed to find corresponding session id, discarding session notification {:?}: {:?}", orig_session_notf, e); 1475 return; 1476 } 1477 } 1478 }; 1479 match orig_session_notf { 1480 SessionNotification::Status { 1481 session_id: _, 1482 session_token, 1483 session_state, 1484 reason_code: _, 1485 } => self.handle_session_state_notification(session_token, session_state).await, 1486 SessionNotification::DataCredit { session_token, credit_availability } => { 1487 if !self.data_credit_map.contains_key(&session_token) { 1488 // Currently just log, as this is unexpected (the entry should exist once 1489 // the ranging session is Active and be removed once it is Idle). 1490 debug!( 1491 "Received a DataCreditNtf for non-existent session_token: {}", 1492 session_token 1493 ); 1494 } 1495 self.data_credit_map.insert(session_token, credit_availability); 1496 if credit_availability == CreditAvailability::CreditAvailable { 1497 if let Err(e) = self.send_data_packet_fragment(session_token).await { 1498 error!( 1499 "Sending data packet fragment failed with Err:{}, after a\ 1500 DataCreditNtf is received, for session_token:{}", 1501 e, session_token 1502 ); 1503 } 1504 } else { 1505 // Log as this should usually not happen (it's not an error). 1506 debug!( 1507 "Received a DataCreditNtf with no credit available for session_token:{}", 1508 session_token 1509 ); 1510 } 1511 return; // We consume these here and don't need to send to upper layer. 1512 } 1513 SessionNotification::DataTransferStatus { 1514 session_token: _, 1515 uci_sequence_number: _, 1516 status: _, 1517 tx_count: _, 1518 } => { 1519 // Reset the UciDataSnd Retryer since we received a DataTransferStatusNtf. 1520 let _ = self.uci_data_snd_retryer.take(); 1521 } 1522 _ => {} 1523 } 1524 let _ = self.session_notf_sender.send(mod_session_notf); 1525 } 1526 UciNotification::RfTest(rftest_notf) => { 1527 let _ = self.rf_test_notf_sender.send(rftest_notf); 1528 } 1529 UciNotification::Vendor(vendor_notf) => { 1530 let _ = self.vendor_notf_sender.send(vendor_notf); 1531 } 1532 } 1533 } 1534 1535 // Modify session_token field in all session related notifications with session id. 1536 // TODO: Sharing of structs across UCI (PDL) & JNI layer like this makes this ugly. Ideally 1537 // the struct sent to JNI layer should only contain |session_id| and at uci layer 1538 // it could be |session_id| or |session_handle|. add_session_id_to_session_status_ntf( &self, session_notification: SessionNotification, ) -> Result<SessionNotification>1539 async fn add_session_id_to_session_status_ntf( 1540 &self, 1541 session_notification: SessionNotification, 1542 ) -> Result<SessionNotification> { 1543 match session_notification { 1544 SessionNotification::Status { 1545 session_id: _, 1546 session_token, 1547 session_state, 1548 reason_code, 1549 } => Ok(SessionNotification::Status { 1550 session_id: self.get_session_id(&session_token).await?, 1551 session_token, 1552 session_state, 1553 reason_code, 1554 }), 1555 SessionNotification::UpdateControllerMulticastListV1 { 1556 session_token, 1557 remaining_multicast_list_size, 1558 status_list, 1559 } => Ok(SessionNotification::UpdateControllerMulticastListV1 { 1560 session_token: self.get_session_id(&session_token).await?, 1561 remaining_multicast_list_size, 1562 status_list, 1563 }), 1564 SessionNotification::UpdateControllerMulticastListV2 { session_token, status_list } => { 1565 Ok(SessionNotification::UpdateControllerMulticastListV2 { 1566 session_token: self.get_session_id(&session_token).await?, 1567 status_list, 1568 }) 1569 } 1570 SessionNotification::SessionInfo(session_range_data) => { 1571 Ok(SessionNotification::SessionInfo(SessionRangeData { 1572 sequence_number: session_range_data.sequence_number, 1573 session_token: self.get_session_id(&session_range_data.session_token).await?, 1574 current_ranging_interval_ms: session_range_data.current_ranging_interval_ms, 1575 ranging_measurement_type: session_range_data.ranging_measurement_type, 1576 hus_primary_session_id: session_range_data.hus_primary_session_id, 1577 ranging_measurements: session_range_data.ranging_measurements, 1578 rcr_indicator: session_range_data.rcr_indicator, 1579 raw_ranging_data: session_range_data.raw_ranging_data, 1580 })) 1581 } 1582 SessionNotification::DataTransferStatus { 1583 session_token, 1584 uci_sequence_number, 1585 status, 1586 tx_count, 1587 } => Ok(SessionNotification::DataTransferStatus { 1588 session_token: self.get_session_id(&session_token).await?, 1589 uci_sequence_number, 1590 status, 1591 tx_count, 1592 }), 1593 SessionNotification::DataCredit { session_token, credit_availability } => { 1594 Ok(SessionNotification::DataCredit { 1595 session_token: self.get_session_id(&session_token).await?, 1596 credit_availability, 1597 }) 1598 } 1599 SessionNotification::DataTransferPhaseConfig { session_token, status } => { 1600 Ok(SessionNotification::DataTransferPhaseConfig { 1601 session_token: self.get_session_id(&session_token).await?, 1602 status, 1603 }) 1604 } 1605 } 1606 } 1607 handle_session_state_notification( &mut self, session_token: SessionToken, session_state: SessionState, )1608 async fn handle_session_state_notification( 1609 &mut self, 1610 session_token: SessionToken, 1611 session_state: SessionState, 1612 ) { 1613 match session_state { 1614 SessionState::SessionStateInit => { 1615 if let Err(e) = self.hal.notify_session_initialized(session_token).await { 1616 warn!("notify_session_initialized() failed: {:?}", e); 1617 } 1618 } 1619 SessionState::SessionStateActive => { 1620 self.data_credit_map.insert(session_token, CreditAvailability::CreditAvailable); 1621 self.data_packet_fragments_map.insert(session_token, VecDeque::new()); 1622 } 1623 SessionState::SessionStateIdle => { 1624 self.data_credit_map.remove(&session_token); 1625 self.data_packet_fragments_map.remove(&session_token); 1626 } 1627 SessionState::SessionStateDeinit => { 1628 self.remove_session_token(&session_token).await; 1629 } 1630 } 1631 } 1632 handle_data_rcv(&mut self, packet: UciDataPacket)1633 async fn handle_data_rcv(&mut self, packet: UciDataPacket) { 1634 if let Ok(data) = DataRcvNotification::try_from(packet.clone()) { 1635 match self.get_session_id(&data.session_token).await { 1636 Ok(session_id) => { 1637 let _ = self.data_rcv_notf_sender.send(DataRcvNotification { 1638 session_token: session_id, 1639 status: data.status, 1640 uci_sequence_num: data.uci_sequence_num, 1641 source_address: data.source_address, 1642 payload: data.payload, 1643 }); 1644 } 1645 Err(e) => { 1646 error!("Unable to find session Id, error {:?}", e); 1647 } 1648 } 1649 } else if let Ok(data) = RadarDataRcvNotification::try_from(packet.clone()) { 1650 match self.get_session_id(&data.session_token).await { 1651 Ok(session_id) => { 1652 let _ = self.radar_data_rcv_notf_sender.send(RadarDataRcvNotification { 1653 session_token: session_id, 1654 status: data.status, 1655 radar_data_type: data.radar_data_type, 1656 number_of_sweeps: data.number_of_sweeps, 1657 samples_per_sweep: data.samples_per_sweep, 1658 bits_per_sample: data.bits_per_sample, 1659 sweep_offset: data.sweep_offset, 1660 sweep_data: data.sweep_data, 1661 }); 1662 } 1663 Err(e) => { 1664 error!("Unable to find session Id, error {:?}", e); 1665 } 1666 } 1667 } else { 1668 error!("Unable to parse incoming Data packet, packet {:?}", packet); 1669 } 1670 } 1671 on_hal_open(&mut self, packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>)1672 fn on_hal_open(&mut self, packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>) { 1673 self.is_hal_opened = true; 1674 self.packet_receiver = packet_receiver; 1675 } 1676 on_hal_closed(&mut self)1677 async fn on_hal_closed(&mut self) { 1678 self.session_id_to_token_map.lock().await.clear(); 1679 self.is_hal_opened = false; 1680 self.packet_receiver = mpsc::unbounded_channel().1; 1681 self.last_raw_cmd = None; 1682 } 1683 is_waiting_resp(&self) -> bool1684 fn is_waiting_resp(&self) -> bool { 1685 self.uci_cmd_retryer.is_some() 1686 } is_waiting_device_status(&self) -> bool1687 fn is_waiting_device_status(&self) -> bool { 1688 self.open_hal_result_sender.is_some() 1689 } 1690 } 1691 1692 impl<T: UciHal, U: UciLogger> Drop for UciManagerActor<T, U> { drop(&mut self)1693 fn drop(&mut self) { 1694 // mpsc receiver is about to be dropped. Clean shutdown the mpsc message. 1695 clean_mpsc_receiver(&mut self.packet_receiver); 1696 } 1697 } 1698 1699 struct UciCmdRetryer { 1700 cmd: UciCommand, 1701 result_sender: oneshot::Sender<Result<UciResponse>>, 1702 retry_count: usize, 1703 } 1704 1705 impl UciCmdRetryer { could_retry(&mut self) -> bool1706 fn could_retry(&mut self) -> bool { 1707 if self.retry_count == 0 { 1708 return false; 1709 } 1710 self.retry_count -= 1; 1711 true 1712 } 1713 send_result(self, result: Result<UciResponse>)1714 fn send_result(self, result: Result<UciResponse>) { 1715 let _ = self.result_sender.send(result); 1716 } 1717 } 1718 1719 struct UciDataSndRetryer { 1720 // Store the last-sent DataSnd packet fragment across all the active UWB session, as the UCI 1721 // spec states that the "last UCI packet should be re-transmitted from Host". 1722 // 1723 // TODO(b/273376343): The spec is open to a race condition in the scenario of multiple active 1724 // sessions, as there can be outstanding DataSnd packet fragments across them. We could do an 1725 // alternative implementation of sending all of them. 1726 data_packet: UciDataPacketHal, 1727 data_packet_session_token: SessionToken, 1728 retry_count: usize, 1729 } 1730 1731 impl UciDataSndRetryer { could_retry(&mut self) -> bool1732 fn could_retry(&mut self) -> bool { 1733 if self.retry_count == 0 { 1734 return false; 1735 } 1736 self.retry_count -= 1; 1737 true 1738 } 1739 } 1740 1741 #[derive(Debug)] 1742 enum UciManagerCmd { 1743 SetLoggerMode { 1744 logger_mode: UciLoggerMode, 1745 }, 1746 SetCoreNotificationSender { 1747 core_notf_sender: mpsc::UnboundedSender<CoreNotification>, 1748 }, 1749 SetSessionNotificationSender { 1750 session_notf_sender: mpsc::UnboundedSender<SessionNotification>, 1751 }, 1752 SetVendorNotificationSender { 1753 vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, 1754 }, 1755 SetDataRcvNotificationSender { 1756 data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, 1757 }, 1758 SetRadarDataRcvNotificationSender { 1759 radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, 1760 }, 1761 SetRfTestNotificationSender { 1762 rf_test_notf_sender: mpsc::UnboundedSender<RfTestNotification>, 1763 }, 1764 OpenHal, 1765 CloseHal { 1766 force: bool, 1767 }, 1768 SendUciCommand { 1769 cmd: UciCommand, 1770 }, 1771 SendUciData { 1772 data_snd_packet: UciDataSnd, 1773 }, 1774 } 1775 1776 #[cfg(test)] 1777 mod tests { 1778 use super::*; 1779 1780 use bytes::Bytes; 1781 use pdl_runtime::Packet; 1782 use tokio::macros::support::Future; 1783 use uwb_uci_packets::{ 1784 Controlee_V2_0_16_Byte_Version, Controlee_V2_0_32_Byte_Version, SessionGetCountCmdBuilder, 1785 SessionGetCountRspBuilder, 1786 }; 1787 1788 use crate::params::uci_packets::{ 1789 AppConfigStatus, AppConfigTlvType, BitsPerSample, CapTlvType, Controlee, DataRcvStatusCode, 1790 DataTransferNtfStatusCode, RadarDataType, RfTestConfigTlvType, StatusCode, 1791 }; 1792 use crate::params::UwbAddress; 1793 use crate::uci::mock_uci_hal::MockUciHal; 1794 use crate::uci::mock_uci_logger::{MockUciLogger, UciLogEvent}; 1795 use crate::uci::notification::CoreNotification; 1796 use crate::uci::notification::RadarSweepData; 1797 use crate::uci::uci_logger::NopUciLogger; 1798 use crate::utils::init_test_logging; 1799 use bytes::{BufMut, BytesMut}; 1800 use uwb_uci_packets::ControleeStatusV2; 1801 use uwb_uci_packets::SessionUpdateControllerMulticastListRspV1Payload; 1802 use uwb_uci_packets::SessionUpdateControllerMulticastListRspV2Payload; 1803 into_uci_hal_packets<T: Into<uwb_uci_packets::UciControlPacket>>( builder: T, ) -> Vec<UciHalPacket>1804 fn into_uci_hal_packets<T: Into<uwb_uci_packets::UciControlPacket>>( 1805 builder: T, 1806 ) -> Vec<UciHalPacket> { 1807 let packets: Vec<uwb_uci_packets::UciControlPacketHal> = builder.into().into(); 1808 packets.into_iter().map(|packet| packet.encode_to_vec().unwrap()).collect() 1809 } 1810 1811 // Construct a UCI packet, with the header fields and payload bytes. build_uci_packet(mt: u8, pbf: u8, gid: u8, oid: u8, mut payload: Vec<u8>) -> Vec<u8>1812 fn build_uci_packet(mt: u8, pbf: u8, gid: u8, oid: u8, mut payload: Vec<u8>) -> Vec<u8> { 1813 let len: u16 = payload.len() as u16; 1814 let mut bytes: Vec<u8> = vec![(mt & 0x7) << 5 | (pbf & 0x1) << 4 | (gid & 0xF), oid & 0x3F]; 1815 if mt == 0 { 1816 // UCI Data packet 1817 // Store 16-bit payload length in LSB format. 1818 bytes.push((len & 0xFF).try_into().unwrap()); 1819 bytes.push((len >> 8).try_into().unwrap()); 1820 } else { 1821 // One byte RFU, followed by one-byte payload length. 1822 bytes.push(0); 1823 bytes.push((len & 0xFF).try_into().unwrap()); 1824 } 1825 bytes.append(&mut payload); 1826 bytes 1827 } 1828 setup_hal_for_open(hal: &mut MockUciHal)1829 fn setup_hal_for_open(hal: &mut MockUciHal) { 1830 // Setup Open the hal. 1831 let notf = into_uci_hal_packets(uwb_uci_packets::DeviceStatusNtfBuilder { 1832 device_state: uwb_uci_packets::DeviceState::DeviceStateReady, 1833 }); 1834 hal.expected_open(Some(notf), Ok(())); 1835 1836 // Setup Get the device info. 1837 let cmd = UciCommand::CoreGetDeviceInfo; 1838 let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder { 1839 status: uwb_uci_packets::StatusCode::UciStatusOk, 1840 uci_version: 0x1234, 1841 mac_version: 0x5678, 1842 phy_version: 0x90ab, 1843 uci_test_version: 0x1357, 1844 vendor_spec_info: vec![0x1, 0x2], 1845 }); 1846 hal.expected_send_command(cmd, resp, Ok(())); 1847 } 1848 setup_uci_manager_with_open_hal<F, Fut>( setup_hal_fn: F, uci_logger_mode: UciLoggerMode, log_sender: mpsc::UnboundedSender<UciLogEvent>, ) -> (UciManagerImpl, MockUciHal) where F: FnOnce(MockUciHal) -> Fut, Fut: Future<Output = ()>,1849 async fn setup_uci_manager_with_open_hal<F, Fut>( 1850 setup_hal_fn: F, 1851 uci_logger_mode: UciLoggerMode, 1852 log_sender: mpsc::UnboundedSender<UciLogEvent>, 1853 ) -> (UciManagerImpl, MockUciHal) 1854 where 1855 F: FnOnce(MockUciHal) -> Fut, 1856 Fut: Future<Output = ()>, 1857 { 1858 init_test_logging(); 1859 1860 let mut hal = MockUciHal::new(); 1861 // Open the hal. 1862 setup_hal_for_open(&mut hal); 1863 1864 // Verify open_hal() is working. 1865 let uci_manager = 1866 UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode); 1867 let result = uci_manager.open_hal().await; 1868 assert!(result.is_ok()); 1869 assert!(hal.wait_expected_calls_done().await); 1870 1871 setup_hal_fn(hal.clone()).await; 1872 1873 (uci_manager, hal) 1874 } 1875 setup_uci_manager_with_open_hal_nop_logger<F, Fut>( setup_hal_fn: F, uci_logger_mode: UciLoggerMode, ) -> (UciManagerImpl, MockUciHal) where F: FnOnce(MockUciHal) -> Fut, Fut: Future<Output = ()>,1876 async fn setup_uci_manager_with_open_hal_nop_logger<F, Fut>( 1877 setup_hal_fn: F, 1878 uci_logger_mode: UciLoggerMode, 1879 ) -> (UciManagerImpl, MockUciHal) 1880 where 1881 F: FnOnce(MockUciHal) -> Fut, 1882 Fut: Future<Output = ()>, 1883 { 1884 init_test_logging(); 1885 1886 let mut hal = MockUciHal::new(); 1887 // Open the hal. 1888 setup_hal_for_open(&mut hal); 1889 1890 // Verify open_hal() is working. 1891 let uci_manager = 1892 UciManagerImpl::new(hal.clone(), NopUciLogger::default(), uci_logger_mode); 1893 let result = uci_manager.open_hal().await; 1894 assert!(result.is_ok()); 1895 assert!(hal.wait_expected_calls_done().await); 1896 1897 setup_hal_fn(hal.clone()).await; 1898 1899 (uci_manager, hal) 1900 } 1901 1902 #[tokio::test] test_open_hal_without_notification()1903 async fn test_open_hal_without_notification() { 1904 init_test_logging(); 1905 1906 let mut hal = MockUciHal::new(); 1907 hal.expected_open(None, Ok(())); 1908 let uci_manager = 1909 UciManagerImpl::new(hal.clone(), NopUciLogger::default(), UciLoggerMode::Disabled); 1910 1911 let result = uci_manager.open_hal().await; 1912 assert!(matches!(result, Err(Error::Timeout))); 1913 assert!(hal.wait_expected_calls_done().await); 1914 } 1915 1916 #[tokio::test] test_close_hal_explicitly()1917 async fn test_close_hal_explicitly() { 1918 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1919 |mut hal| async move { 1920 hal.expected_close(Ok(())); 1921 }, 1922 UciLoggerMode::Disabled, 1923 mpsc::unbounded_channel::<UciLogEvent>().0, 1924 ) 1925 .await; 1926 1927 let result = uci_manager.close_hal(false).await; 1928 assert!(result.is_ok()); 1929 assert!(mock_hal.wait_expected_calls_done().await); 1930 } 1931 1932 #[tokio::test] test_close_hal_when_exit()1933 async fn test_close_hal_when_exit() { 1934 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1935 |mut hal| async move { 1936 // UciManager should close the hal if the hal is still opened when exit. 1937 hal.expected_close(Ok(())); 1938 }, 1939 UciLoggerMode::Disabled, 1940 mpsc::unbounded_channel::<UciLogEvent>().0, 1941 ) 1942 .await; 1943 1944 drop(uci_manager); 1945 assert!(mock_hal.wait_expected_calls_done().await); 1946 } 1947 1948 #[tokio::test] test_close_hal_without_open_hal()1949 async fn test_close_hal_without_open_hal() { 1950 init_test_logging(); 1951 1952 let mut hal = MockUciHal::new(); 1953 let uci_manager = 1954 UciManagerImpl::new(hal.clone(), NopUciLogger::default(), UciLoggerMode::Disabled); 1955 1956 let result = uci_manager.close_hal(false).await; 1957 assert!(matches!(result, Err(Error::BadParameters))); 1958 assert!(hal.wait_expected_calls_done().await); 1959 } 1960 1961 #[tokio::test] test_device_reset_ok()1962 async fn test_device_reset_ok() { 1963 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1964 |mut hal| async move { 1965 let cmd = UciCommand::DeviceReset { reset_config: ResetConfig::UwbsReset }; 1966 let resp = into_uci_hal_packets(uwb_uci_packets::DeviceResetRspBuilder { 1967 status: uwb_uci_packets::StatusCode::UciStatusOk, 1968 }); 1969 hal.expected_send_command(cmd, resp, Ok(())); 1970 }, 1971 UciLoggerMode::Disabled, 1972 mpsc::unbounded_channel::<UciLogEvent>().0, 1973 ) 1974 .await; 1975 1976 let result = uci_manager.device_reset(ResetConfig::UwbsReset).await; 1977 assert!(result.is_ok()); 1978 assert!(mock_hal.wait_expected_calls_done().await); 1979 } 1980 1981 #[tokio::test] test_priority_device_status_error_ntf()1982 async fn test_priority_device_status_error_ntf() { 1983 // Send DEVICE_STATE_ERROR notification while waiting for remaining fragments, 1984 // verify that notification is processed on priority without waiting for the 1985 // further fragmen 1986 let mt: u8 = 0x3; 1987 let pbf_not_set: u8 = 0x00; 1988 let gid_core: u8 = 0x0; 1989 let oid_device_status: u8 = 0x1; 1990 let payload_1 = vec![0xFF]; 1991 let pbf_set: u8 = 0x1; 1992 let gid_session: u8 = 0x02; 1993 let oid_session_ntf: u8 = 0x03; 1994 let payload_range_dat = vec![0, 251]; 1995 let dev_state_err_packet = 1996 build_uci_packet(mt, pbf_not_set, gid_core, oid_device_status, payload_1); 1997 let range_data_ntf_packet = 1998 build_uci_packet(mt, pbf_set, gid_session, oid_session_ntf, payload_range_dat); 1999 let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2000 |_| async move {}, 2001 UciLoggerMode::Disabled, 2002 mpsc::unbounded_channel::<UciLogEvent>().0, 2003 ) 2004 .await; 2005 2006 let (session_notification_sender, mut session_notification_receiver) = 2007 mpsc::unbounded_channel::<SessionNotification>(); 2008 uci_manager.set_session_notification_sender(session_notification_sender).await; 2009 let result = mock_hal.receive_packet(range_data_ntf_packet); 2010 assert!(result.is_ok()); 2011 2012 let device_status_ntf_packet = uwb_uci_packets::DeviceStatusNtfBuilder { 2013 device_state: uwb_uci_packets::DeviceState::DeviceStateError, 2014 } 2015 .build(); 2016 let core_notification = 2017 uwb_uci_packets::CoreNotification::try_from(device_status_ntf_packet).unwrap(); 2018 let expected_uci_notification = CoreNotification::try_from(core_notification).unwrap(); 2019 2020 let (core_notification_sender, mut core_notification_receiver) = 2021 mpsc::unbounded_channel::<CoreNotification>(); 2022 uci_manager.set_core_notification_sender(core_notification_sender).await; 2023 2024 let result = mock_hal.receive_packet(dev_state_err_packet); 2025 assert!(result.is_ok()); 2026 2027 let result = 2028 tokio::time::timeout(Duration::from_millis(100), core_notification_receiver.recv()) 2029 .await; 2030 assert!(result.is_ok()); 2031 assert_eq!(result.unwrap(), Some(expected_uci_notification)); 2032 assert!(mock_hal.wait_expected_calls_done().await); 2033 2034 // DEVICE_STATE_ERROR is received in middle while waiting for the fragmented packet, 2035 // no fragmented packet will be processed 2036 assert!(session_notification_receiver.try_recv().is_err()); 2037 } 2038 2039 #[tokio::test] test_core_get_device_info_ok()2040 async fn test_core_get_device_info_ok() { 2041 let status = StatusCode::UciStatusOk; 2042 let uci_version = 0x1234; 2043 let mac_version = 0x5678; 2044 let phy_version = 0x90ab; 2045 let uci_test_version = 0x1357; 2046 let vendor_spec_info = vec![0x1, 0x2]; 2047 let vendor_spec_info_clone = vendor_spec_info.clone(); 2048 2049 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2050 |mut hal| async move { 2051 let cmd = UciCommand::CoreGetDeviceInfo; 2052 let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder { 2053 status, 2054 uci_version, 2055 mac_version, 2056 phy_version, 2057 uci_test_version, 2058 vendor_spec_info: vendor_spec_info_clone, 2059 }); 2060 2061 hal.expected_send_command(cmd, resp, Ok(())); 2062 }, 2063 UciLoggerMode::Disabled, 2064 mpsc::unbounded_channel::<UciLogEvent>().0, 2065 ) 2066 .await; 2067 2068 let expected_result = GetDeviceInfoResponse { 2069 status, 2070 uci_version, 2071 mac_version, 2072 phy_version, 2073 uci_test_version, 2074 vendor_spec_info, 2075 }; 2076 let result = uci_manager.core_get_device_info().await.unwrap(); 2077 assert_eq!(result, expected_result); 2078 assert!(mock_hal.wait_expected_calls_done().await); 2079 } 2080 2081 #[tokio::test] test_core_get_caps_info_fira_v1_0_ok()2082 async fn test_core_get_caps_info_fira_v1_0_ok() { 2083 let tlv = CapTlv { 2084 t: CapTlvType::SupportedV1FiraPhyVersionRangeV2MaxMessageSize, 2085 v: vec![0x12, 0x34, 0x56], 2086 }; 2087 let tlv_clone = tlv.clone(); 2088 2089 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2090 |mut hal| async move { 2091 let cmd = UciCommand::CoreGetCapsInfo; 2092 let resp = into_uci_hal_packets(uwb_uci_packets::GetCapsInfoRspBuilder { 2093 status: uwb_uci_packets::StatusCode::UciStatusOk, 2094 tlvs: vec![tlv_clone], 2095 }); 2096 2097 hal.expected_send_command(cmd, resp, Ok(())); 2098 }, 2099 UciLoggerMode::Disabled, 2100 mpsc::unbounded_channel::<UciLogEvent>().0, 2101 ) 2102 .await; 2103 2104 let result = uci_manager.core_get_caps_info().await.unwrap(); 2105 assert_eq!(result[0], tlv); 2106 assert!(mock_hal.wait_expected_calls_done().await); 2107 } 2108 2109 #[tokio::test] test_core_set_config_ok()2110 async fn test_core_set_config_ok() { 2111 let tlv = DeviceConfigTlv { 2112 cfg_id: uwb_uci_packets::DeviceConfigId::DeviceState, 2113 v: vec![0x12, 0x34, 0x56], 2114 }; 2115 let tlv_clone = tlv.clone(); 2116 let status = StatusCode::UciStatusOk; 2117 let config_status = vec![]; 2118 let config_status_clone = config_status.clone(); 2119 2120 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2121 |mut hal| async move { 2122 let cmd = UciCommand::CoreSetConfig { config_tlvs: vec![tlv_clone] }; 2123 let resp = into_uci_hal_packets(uwb_uci_packets::SetConfigRspBuilder { 2124 status, 2125 cfg_status: config_status_clone, 2126 }); 2127 2128 hal.expected_send_command(cmd, resp, Ok(())); 2129 }, 2130 UciLoggerMode::Disabled, 2131 mpsc::unbounded_channel::<UciLogEvent>().0, 2132 ) 2133 .await; 2134 2135 let expected_result = CoreSetConfigResponse { status, config_status }; 2136 let result = uci_manager.core_set_config(vec![tlv]).await.unwrap(); 2137 assert_eq!(result, expected_result); 2138 assert!(mock_hal.wait_expected_calls_done().await); 2139 } 2140 2141 #[tokio::test] test_core_get_config_ok()2142 async fn test_core_get_config_ok() { 2143 let cfg_id = DeviceConfigId::DeviceState; 2144 let tlv = DeviceConfigTlv { cfg_id, v: vec![0x12, 0x34, 0x56] }; 2145 let tlv_clone = tlv.clone(); 2146 2147 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2148 |mut hal| async move { 2149 let cmd = UciCommand::CoreGetConfig { cfg_id: vec![cfg_id] }; 2150 let resp = into_uci_hal_packets(uwb_uci_packets::GetConfigRspBuilder { 2151 status: uwb_uci_packets::StatusCode::UciStatusOk, 2152 tlvs: vec![tlv_clone], 2153 }); 2154 2155 hal.expected_send_command(cmd, resp, Ok(())); 2156 }, 2157 UciLoggerMode::Disabled, 2158 mpsc::unbounded_channel::<UciLogEvent>().0, 2159 ) 2160 .await; 2161 2162 let expected_result = vec![tlv]; 2163 let result = uci_manager.core_get_config(vec![cfg_id]).await.unwrap(); 2164 assert_eq!(result, expected_result); 2165 assert!(mock_hal.wait_expected_calls_done().await); 2166 } 2167 setup_hal_for_session_initialize( hal: &mut MockUciHal, session_type: SessionType, session_id: u32, session_token: u32, )2168 fn setup_hal_for_session_initialize( 2169 hal: &mut MockUciHal, 2170 session_type: SessionType, 2171 session_id: u32, 2172 session_token: u32, 2173 ) { 2174 // Setup for hal open. 2175 setup_hal_for_open(hal); 2176 2177 // Setup session init. 2178 let cmd = UciCommand::SessionInit { session_id, session_type }; 2179 let mut resp = if session_id == session_token { 2180 into_uci_hal_packets(uwb_uci_packets::SessionInitRspBuilder { 2181 status: uwb_uci_packets::StatusCode::UciStatusOk, 2182 }) 2183 } else { 2184 // This is testing FIRA v2 flow where a session handle is provided by UWBS. 2185 into_uci_hal_packets(uwb_uci_packets::SessionInitRsp_V2Builder { 2186 status: uwb_uci_packets::StatusCode::UciStatusOk, 2187 session_handle: session_token, 2188 }) 2189 }; 2190 let mut notf = into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder { 2191 session_token, 2192 session_state: uwb_uci_packets::SessionState::SessionStateInit, 2193 reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands 2194 .into(), 2195 }); 2196 resp.append(&mut notf); 2197 hal.expected_send_command(cmd, resp, Ok(())); 2198 hal.expected_notify_session_initialized(session_token, Ok(())); 2199 } 2200 setup_uci_manager_with_session_initialized<F, Fut>( setup_hal_fn: F, uci_logger_mode: UciLoggerMode, log_sender: mpsc::UnboundedSender<UciLogEvent>, session_id: u32, session_token: u32, ) -> (UciManagerImpl, MockUciHal) where F: FnOnce(MockUciHal) -> Fut, Fut: Future<Output = ()>,2201 async fn setup_uci_manager_with_session_initialized<F, Fut>( 2202 setup_hal_fn: F, 2203 uci_logger_mode: UciLoggerMode, 2204 log_sender: mpsc::UnboundedSender<UciLogEvent>, 2205 session_id: u32, 2206 session_token: u32, 2207 ) -> (UciManagerImpl, MockUciHal) 2208 where 2209 F: FnOnce(MockUciHal) -> Fut, 2210 Fut: Future<Output = ()>, 2211 { 2212 let session_type = SessionType::FiraRangingSession; 2213 2214 init_test_logging(); 2215 2216 let mut hal = MockUciHal::new(); 2217 setup_hal_for_session_initialize(&mut hal, session_type, session_id, session_token); 2218 2219 // Verify open_hal() is working. 2220 let uci_manager = 2221 UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode); 2222 let result = uci_manager.open_hal().await; 2223 assert!(result.is_ok()); 2224 2225 // Verify session is initialized. 2226 let result = uci_manager.session_init(session_id, session_type).await; 2227 assert!(result.is_ok()); 2228 assert!(hal.wait_expected_calls_done().await); 2229 2230 setup_hal_fn(hal.clone()).await; 2231 2232 (uci_manager, hal) 2233 } 2234 setup_uci_manager_with_session_initialized_nop_logger<F, Fut>( setup_hal_fn: F, uci_logger_mode: UciLoggerMode, session_id: u32, session_token: u32, ) -> (UciManagerImpl, MockUciHal) where F: FnOnce(MockUciHal) -> Fut, Fut: Future<Output = ()>,2235 async fn setup_uci_manager_with_session_initialized_nop_logger<F, Fut>( 2236 setup_hal_fn: F, 2237 uci_logger_mode: UciLoggerMode, 2238 session_id: u32, 2239 session_token: u32, 2240 ) -> (UciManagerImpl, MockUciHal) 2241 where 2242 F: FnOnce(MockUciHal) -> Fut, 2243 Fut: Future<Output = ()>, 2244 { 2245 let session_type = SessionType::FiraRangingSession; 2246 2247 init_test_logging(); 2248 2249 let mut hal = MockUciHal::new(); 2250 setup_hal_for_session_initialize(&mut hal, session_type, session_id, session_token); 2251 2252 // Verify open_hal() is working. 2253 let uci_manager = 2254 UciManagerImpl::new(hal.clone(), NopUciLogger::default(), uci_logger_mode); 2255 let result = uci_manager.open_hal().await; 2256 assert!(result.is_ok()); 2257 2258 // Verify session is initialized. 2259 let result = uci_manager.session_init(session_id, session_type).await; 2260 assert!(result.is_ok()); 2261 assert!(hal.wait_expected_calls_done().await); 2262 2263 setup_hal_fn(hal.clone()).await; 2264 2265 (uci_manager, hal) 2266 } 2267 2268 #[tokio::test] test_session_init_ok()2269 async fn test_session_init_ok() { 2270 let session_id = 0x123; 2271 let session_token = 0x123; 2272 let (_, mut mock_hal) = setup_uci_manager_with_session_initialized( 2273 |_hal| async move {}, 2274 UciLoggerMode::Disabled, 2275 mpsc::unbounded_channel::<UciLogEvent>().0, 2276 session_id, 2277 session_token, 2278 ) 2279 .await; 2280 assert!(mock_hal.wait_expected_calls_done().await); 2281 } 2282 2283 #[tokio::test] test_session_init_v2_ok()2284 async fn test_session_init_v2_ok() { 2285 let session_id = 0x123; 2286 let session_token = 0x321; // different session handle 2287 let (_, mut mock_hal) = setup_uci_manager_with_session_initialized_nop_logger( 2288 |_hal| async move {}, 2289 UciLoggerMode::Disabled, 2290 session_id, 2291 session_token, 2292 ) 2293 .await; 2294 assert!(mock_hal.wait_expected_calls_done().await); 2295 } 2296 2297 #[tokio::test] test_session_deinit_ok()2298 async fn test_session_deinit_ok() { 2299 let session_id = 0x123; 2300 let session_token = 0x123; 2301 2302 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2303 |mut hal| async move { 2304 let cmd = UciCommand::SessionDeinit { session_token }; 2305 let resp = into_uci_hal_packets(uwb_uci_packets::SessionDeinitRspBuilder { 2306 status: uwb_uci_packets::StatusCode::UciStatusOk, 2307 }); 2308 2309 hal.expected_send_command(cmd, resp, Ok(())); 2310 }, 2311 UciLoggerMode::Disabled, 2312 mpsc::unbounded_channel::<UciLogEvent>().0, 2313 session_id, 2314 session_token, 2315 ) 2316 .await; 2317 2318 let result = uci_manager.session_deinit(session_id).await; 2319 assert!(result.is_ok()); 2320 assert!(mock_hal.wait_expected_calls_done().await); 2321 } 2322 2323 #[tokio::test] test_session_deinit_v2_ok()2324 async fn test_session_deinit_v2_ok() { 2325 let session_id = 0x123; 2326 let session_token = 0x321; // different session handle 2327 2328 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized_nop_logger( 2329 |mut hal| async move { 2330 let cmd = UciCommand::SessionDeinit { session_token }; 2331 let resp = into_uci_hal_packets(uwb_uci_packets::SessionDeinitRspBuilder { 2332 status: uwb_uci_packets::StatusCode::UciStatusOk, 2333 }); 2334 2335 hal.expected_send_command(cmd, resp, Ok(())); 2336 }, 2337 UciLoggerMode::Disabled, 2338 session_id, 2339 session_token, 2340 ) 2341 .await; 2342 2343 let result = uci_manager.session_deinit(session_id).await; 2344 assert!(result.is_ok()); 2345 assert!(mock_hal.wait_expected_calls_done().await); 2346 } 2347 2348 #[tokio::test] test_session_set_app_config_ok()2349 async fn test_session_set_app_config_ok() { 2350 let session_id = 0x123; 2351 let session_token = 0x123; 2352 let config_tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]); 2353 let config_tlv_clone = config_tlv.clone(); 2354 2355 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2356 |mut hal| async move { 2357 let cmd = UciCommand::SessionSetAppConfig { 2358 session_token, 2359 config_tlvs: vec![config_tlv_clone], 2360 }; 2361 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 2362 status: uwb_uci_packets::StatusCode::UciStatusOk, 2363 cfg_status: vec![], 2364 }); 2365 2366 hal.expected_send_command(cmd, resp, Ok(())); 2367 }, 2368 UciLoggerMode::Disabled, 2369 mpsc::unbounded_channel::<UciLogEvent>().0, 2370 session_id, 2371 session_token, 2372 ) 2373 .await; 2374 2375 let expected_result = 2376 SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; 2377 let result = 2378 uci_manager.session_set_app_config(session_id, vec![config_tlv]).await.unwrap(); 2379 assert_eq!(result, expected_result); 2380 assert!(mock_hal.wait_expected_calls_done().await); 2381 } 2382 2383 #[tokio::test] test_session_set_app_config_v2_ok()2384 async fn test_session_set_app_config_v2_ok() { 2385 let session_id = 0x123; 2386 let session_token = 0x321; 2387 let config_tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]); 2388 let config_tlv_clone = config_tlv.clone(); 2389 2390 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized_nop_logger( 2391 |mut hal| async move { 2392 let cmd = UciCommand::SessionSetAppConfig { 2393 session_token, 2394 config_tlvs: vec![config_tlv_clone], 2395 }; 2396 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 2397 status: uwb_uci_packets::StatusCode::UciStatusOk, 2398 cfg_status: vec![], 2399 }); 2400 2401 hal.expected_send_command(cmd, resp, Ok(())); 2402 }, 2403 UciLoggerMode::Disabled, 2404 session_id, 2405 session_token, 2406 ) 2407 .await; 2408 2409 let expected_result = 2410 SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; 2411 let result = 2412 uci_manager.session_set_app_config(session_id, vec![config_tlv]).await.unwrap(); 2413 assert_eq!(result, expected_result); 2414 assert!(mock_hal.wait_expected_calls_done().await); 2415 } 2416 2417 #[tokio::test] test_session_get_app_config_ok()2418 async fn test_session_get_app_config_ok() { 2419 let session_id = 0x123; 2420 let session_token = 0x123; 2421 let config_id = AppConfigTlvType::DeviceType; 2422 let tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]); 2423 let tlv_clone = tlv.clone(); 2424 2425 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2426 |mut hal| async move { 2427 let cmd = 2428 UciCommand::SessionGetAppConfig { session_token, app_cfg: vec![config_id] }; 2429 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetAppConfigRspBuilder { 2430 status: uwb_uci_packets::StatusCode::UciStatusOk, 2431 tlvs: vec![tlv_clone.into_inner()], 2432 }); 2433 2434 hal.expected_send_command(cmd, resp, Ok(())); 2435 }, 2436 UciLoggerMode::Disabled, 2437 mpsc::unbounded_channel::<UciLogEvent>().0, 2438 session_id, 2439 session_token, 2440 ) 2441 .await; 2442 2443 let expected_result = vec![tlv]; 2444 let result = uci_manager.session_get_app_config(session_id, vec![config_id]).await.unwrap(); 2445 assert_eq!(result, expected_result); 2446 assert!(mock_hal.wait_expected_calls_done().await); 2447 } 2448 2449 #[tokio::test] test_session_set_hybrid_controller_config_ok()2450 async fn test_session_set_hybrid_controller_config_ok() { 2451 let session_id = 0x123; 2452 let session_token = 0x123; 2453 let number_of_phases = 0x02; 2454 let phase_list_short_mac_address = vec![ 2455 uwb_uci_packets::ControllerPhaseList { 2456 session_token: 0x11, 2457 start_slot_index: 0x12, 2458 end_slot_index: 0x13, 2459 control: 0x01, 2460 mac_address: [0x11, 0x22].to_vec(), 2461 }, 2462 uwb_uci_packets::ControllerPhaseList { 2463 session_token: 0x21, 2464 start_slot_index: 0x22, 2465 end_slot_index: 0x23, 2466 control: 0x01, 2467 mac_address: [0x11, 0x33].to_vec(), 2468 }, 2469 ]; 2470 let phase_list_extended_mac_address = vec![ 2471 uwb_uci_packets::ControllerPhaseList { 2472 session_token: 0x11, 2473 start_slot_index: 0x12, 2474 end_slot_index: 0x13, 2475 control: 0x01, 2476 mac_address: [0x11, 0x22, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38].to_vec(), 2477 }, 2478 uwb_uci_packets::ControllerPhaseList { 2479 session_token: 0x21, 2480 start_slot_index: 0x22, 2481 end_slot_index: 0x23, 2482 control: 0x01, 2483 mac_address: [0x11, 0x22, 0x33, 0x34, 0x35, 0x36, 0x37, 0x39].to_vec(), 2484 }, 2485 ]; 2486 let phase_list_clone_short = phase_list_short_mac_address.clone(); 2487 2488 // short mac address 2489 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 2490 |mut hal| async move { 2491 let cmd = UciCommand::SessionSetHybridControllerConfig { 2492 session_token, 2493 number_of_phases, 2494 phase_list: phase_list_clone_short, 2495 }; 2496 let resp = into_uci_hal_packets( 2497 uwb_uci_packets::SessionSetHybridControllerConfigRspBuilder { 2498 status: uwb_uci_packets::StatusCode::UciStatusOk, 2499 }, 2500 ); 2501 2502 hal.expected_send_command(cmd, resp, Ok(())); 2503 }, 2504 UciLoggerMode::Disabled, 2505 mpsc::unbounded_channel::<UciLogEvent>().0, 2506 session_id, 2507 session_token, 2508 ) 2509 .await; 2510 2511 let result = uci_manager 2512 .session_set_hybrid_controller_config( 2513 session_token, 2514 number_of_phases, 2515 phase_list_short_mac_address, 2516 ) 2517 .await; 2518 assert!(result.is_ok()); 2519 assert!(mock_hal.wait_expected_calls_done().await); 2520 2521 // extended mac address 2522 let phase_list_clone_extended = phase_list_extended_mac_address.clone(); 2523 //phase_list_clone.clone_from(&phase_list_extended_mac_address); 2524 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 2525 |mut hal| async move { 2526 let cmd = UciCommand::SessionSetHybridControllerConfig { 2527 session_token, 2528 number_of_phases, 2529 phase_list: phase_list_clone_extended, 2530 }; 2531 let resp = into_uci_hal_packets( 2532 uwb_uci_packets::SessionSetHybridControllerConfigRspBuilder { 2533 status: uwb_uci_packets::StatusCode::UciStatusOk, 2534 }, 2535 ); 2536 2537 hal.expected_send_command(cmd, resp, Ok(())); 2538 }, 2539 UciLoggerMode::Disabled, 2540 mpsc::unbounded_channel::<UciLogEvent>().0, 2541 session_id, 2542 session_token, 2543 ) 2544 .await; 2545 2546 let result = uci_manager 2547 .session_set_hybrid_controller_config( 2548 session_token, 2549 number_of_phases, 2550 phase_list_extended_mac_address, 2551 ) 2552 .await; 2553 assert!(result.is_ok()); 2554 assert!(mock_hal.wait_expected_calls_done().await); 2555 } 2556 2557 #[tokio::test] test_session_set_hybrid_controlee_config_ok()2558 async fn test_session_set_hybrid_controlee_config_ok() { 2559 let session_id = 0x123; 2560 let session_token = 0x123; 2561 let phase_list = vec![ 2562 ControleePhaseList { session_token: 0x12 }, 2563 ControleePhaseList { session_token: 0x14 }, 2564 ]; 2565 let phase_list_clone = phase_list.clone(); 2566 2567 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 2568 |mut hal| async move { 2569 let cmd = UciCommand::SessionSetHybridControleeConfig { 2570 session_token, 2571 controlee_phase_list: phase_list_clone, 2572 }; 2573 let resp = into_uci_hal_packets( 2574 uwb_uci_packets::SessionSetHybridControleeConfigRspBuilder { 2575 status: uwb_uci_packets::StatusCode::UciStatusOk, 2576 }, 2577 ); 2578 2579 hal.expected_send_command(cmd, resp, Ok(())); 2580 }, 2581 UciLoggerMode::Disabled, 2582 mpsc::unbounded_channel::<UciLogEvent>().0, 2583 session_id, 2584 session_token, 2585 ) 2586 .await; 2587 2588 let result = 2589 uci_manager.session_set_hybrid_controlee_config(session_token, phase_list).await; 2590 assert!(result.is_ok()); 2591 assert!(mock_hal.wait_expected_calls_done().await); 2592 } 2593 2594 #[tokio::test] test_session_data_transfer_phase_config_ok()2595 async fn test_session_data_transfer_phase_config_ok() { 2596 let session_id = 0x123; 2597 let session_token = 0x123; 2598 let dtpcm_repetition = 0x00; 2599 let data_transfer_control = 0x00; 2600 let dtpml_size = 0x02; 2601 let mac_address = vec![0x22, 0x11, 0x44, 0x33]; 2602 let slot_bitmap = vec![0xF0, 0x0F]; 2603 let stop_data_transfer = vec![0x00, 0x01]; 2604 let mac_address_clone = mac_address.clone(); 2605 let slot_bitmap_clone = slot_bitmap.clone(); 2606 let stop_data_transfer_clone = stop_data_transfer.clone(); 2607 2608 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 2609 |mut hal| async move { 2610 let cmd = UciCommand::SessionDataTransferPhaseConfig { 2611 session_token, 2612 dtpcm_repetition, 2613 data_transfer_control, 2614 dtpml_size, 2615 mac_address, 2616 slot_bitmap, 2617 stop_data_transfer, 2618 }; 2619 let resp = into_uci_hal_packets( 2620 uwb_uci_packets::SessionDataTransferPhaseConfigRspBuilder { 2621 status: uwb_uci_packets::StatusCode::UciStatusOk, 2622 }, 2623 ); 2624 2625 hal.expected_send_command(cmd, resp, Ok(())); 2626 }, 2627 UciLoggerMode::Disabled, 2628 mpsc::unbounded_channel::<UciLogEvent>().0, 2629 session_id, 2630 session_token, 2631 ) 2632 .await; 2633 2634 let result = uci_manager 2635 .session_data_transfer_phase_config( 2636 session_token, 2637 dtpcm_repetition, 2638 data_transfer_control, 2639 dtpml_size, 2640 mac_address_clone, 2641 slot_bitmap_clone, 2642 stop_data_transfer_clone, 2643 ) 2644 .await; 2645 assert!(result.is_ok()); 2646 assert!(mock_hal.wait_expected_calls_done().await); 2647 } 2648 2649 #[tokio::test] test_session_get_count_ok()2650 async fn test_session_get_count_ok() { 2651 let session_count = 5; 2652 2653 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2654 |mut hal| async move { 2655 let cmd = UciCommand::SessionGetCount; 2656 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 2657 status: uwb_uci_packets::StatusCode::UciStatusOk, 2658 session_count, 2659 }); 2660 2661 hal.expected_send_command(cmd, resp, Ok(())); 2662 }, 2663 UciLoggerMode::Disabled, 2664 mpsc::unbounded_channel::<UciLogEvent>().0, 2665 ) 2666 .await; 2667 2668 let result = uci_manager.session_get_count().await.unwrap(); 2669 assert_eq!(result, session_count); 2670 assert!(mock_hal.wait_expected_calls_done().await); 2671 } 2672 2673 #[tokio::test] test_session_get_state_ok()2674 async fn test_session_get_state_ok() { 2675 let session_id = 0x123; 2676 let session_token = 0x123; 2677 let session_state = SessionState::SessionStateActive; 2678 2679 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2680 |mut hal| async move { 2681 let cmd = UciCommand::SessionGetState { session_token }; 2682 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetStateRspBuilder { 2683 status: uwb_uci_packets::StatusCode::UciStatusOk, 2684 session_state, 2685 }); 2686 2687 hal.expected_send_command(cmd, resp, Ok(())); 2688 }, 2689 UciLoggerMode::Disabled, 2690 mpsc::unbounded_channel::<UciLogEvent>().0, 2691 session_id, 2692 session_token, 2693 ) 2694 .await; 2695 2696 let result = uci_manager.session_get_state(session_id).await.unwrap(); 2697 assert_eq!(result, session_state); 2698 assert!(mock_hal.wait_expected_calls_done().await); 2699 } 2700 write_multicast_rsp_v1_payload( payload: &SessionUpdateControllerMulticastListRspV1Payload, buffer: &mut BytesMut, )2701 fn write_multicast_rsp_v1_payload( 2702 payload: &SessionUpdateControllerMulticastListRspV1Payload, 2703 buffer: &mut BytesMut, 2704 ) { 2705 buffer.put_u8(payload.status.into()); 2706 } 2707 write_v2_controlee_status(status: &ControleeStatusV2, buffer: &mut BytesMut)2708 fn write_v2_controlee_status(status: &ControleeStatusV2, buffer: &mut BytesMut) { 2709 for elem in &status.mac_address { 2710 buffer.put_u8(*elem); 2711 } 2712 buffer.put_u8(u8::from(status.status)); 2713 } 2714 write_multicast_rsp_v2_payload( payload: &SessionUpdateControllerMulticastListRspV2Payload, buffer: &mut BytesMut, )2715 fn write_multicast_rsp_v2_payload( 2716 payload: &SessionUpdateControllerMulticastListRspV2Payload, 2717 buffer: &mut BytesMut, 2718 ) { 2719 buffer.put_u8(payload.status.into()); 2720 buffer.put_u8(payload.controlee_status.len() as u8); 2721 for elem in &payload.controlee_status { 2722 write_v2_controlee_status(elem, buffer); 2723 } 2724 } 2725 2726 #[tokio::test] test_session_update_controller_multicast_list_v1_ok()2727 async fn test_session_update_controller_multicast_list_v1_ok() { 2728 let session_id = 0x123; 2729 let session_token = 0x123; 2730 let action = UpdateMulticastListAction::AddControlee; 2731 let short_address: [u8; 2] = [0x45, 0x67]; 2732 let controlee = Controlee { short_address, subsession_id: 0x90ab }; 2733 let controlee_clone = controlee.clone(); 2734 2735 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2736 |mut hal| async move { 2737 let cmd = UciCommand::SessionUpdateControllerMulticastList { 2738 session_token, 2739 action, 2740 controlees: Controlees::NoSessionKey(vec![controlee_clone]), 2741 is_multicast_list_ntf_v2_supported: false, 2742 is_multicast_list_rsp_v2_supported: false, 2743 }; 2744 let pload = SessionUpdateControllerMulticastListRspV1Payload { 2745 status: StatusCode::UciStatusOk, 2746 }; 2747 let mut buf = BytesMut::new(); 2748 write_multicast_rsp_v1_payload(&pload, &mut buf); 2749 let resp = into_uci_hal_packets( 2750 uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder { 2751 payload: Some(buf.freeze()), 2752 }, 2753 ); 2754 2755 hal.expected_send_command(cmd, resp, Ok(())); 2756 }, 2757 UciLoggerMode::Disabled, 2758 mpsc::unbounded_channel::<UciLogEvent>().0, 2759 session_id, 2760 session_token, 2761 ) 2762 .await; 2763 2764 let result = uci_manager 2765 .session_update_controller_multicast_list( 2766 session_id, 2767 action, 2768 uwb_uci_packets::Controlees::NoSessionKey(vec![controlee]), 2769 false, 2770 false, 2771 ) 2772 .await; 2773 assert!(result.is_ok()); 2774 assert!(mock_hal.wait_expected_calls_done().await); 2775 } 2776 2777 #[tokio::test] test_session_update_controller_multicast_list_v2_short_subsession_key_ok()2778 async fn test_session_update_controller_multicast_list_v2_short_subsession_key_ok() { 2779 let session_id = 0x123; 2780 let session_token = 0x123; 2781 let action = UpdateMulticastListAction::AddControleeWithShortSubSessionKey; 2782 let short_address: [u8; 2] = [0x45, 0x67]; 2783 let controlee = Controlee_V2_0_16_Byte_Version { 2784 short_address, 2785 subsession_key: [ 2786 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 2787 0xcd, 0xef, 2788 ], 2789 subsession_id: 0x90ab, 2790 }; 2791 let controlee_clone = controlee.clone(); 2792 2793 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized_nop_logger( 2794 |mut hal| async move { 2795 let cmd = UciCommand::SessionUpdateControllerMulticastList { 2796 session_token, 2797 action, 2798 controlees: Controlees::ShortSessionKey(vec![controlee_clone]), 2799 is_multicast_list_ntf_v2_supported: true, 2800 is_multicast_list_rsp_v2_supported: true, 2801 }; 2802 let pload = SessionUpdateControllerMulticastListRspV2Payload { 2803 status: StatusCode::UciStatusOk, 2804 controlee_status: vec![], 2805 }; 2806 let mut buf = BytesMut::new(); 2807 write_multicast_rsp_v2_payload(&pload, &mut buf); 2808 let resp = into_uci_hal_packets( 2809 uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder { 2810 payload: Some(buf.freeze()), 2811 }, 2812 ); 2813 hal.expected_send_command(cmd, resp, Ok(())); 2814 }, 2815 UciLoggerMode::Disabled, 2816 session_id, 2817 session_token, 2818 ) 2819 .await; 2820 2821 let result = uci_manager 2822 .session_update_controller_multicast_list( 2823 session_id, 2824 action, 2825 uwb_uci_packets::Controlees::ShortSessionKey(vec![controlee]), 2826 true, 2827 true, 2828 ) 2829 .await; 2830 assert!(result.is_ok()); 2831 assert!(mock_hal.wait_expected_calls_done().await); 2832 } 2833 2834 #[tokio::test] test_session_update_controller_multicast_list_v2_long_subsession_key_ok()2835 async fn test_session_update_controller_multicast_list_v2_long_subsession_key_ok() { 2836 let session_id = 0x123; 2837 let session_token = 0x123; 2838 let action = UpdateMulticastListAction::AddControleeWithLongSubSessionKey; 2839 let short_address: [u8; 2] = [0x45, 0x67]; 2840 let controlee = Controlee_V2_0_32_Byte_Version { 2841 short_address, 2842 subsession_key: [ 2843 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 2844 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 2845 0x90, 0xab, 0xcd, 0xef, 2846 ], 2847 subsession_id: 0x90ab, 2848 }; 2849 let controlee_clone = controlee.clone(); 2850 2851 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2852 |mut hal| async move { 2853 let cmd = UciCommand::SessionUpdateControllerMulticastList { 2854 session_token, 2855 action, 2856 controlees: Controlees::LongSessionKey(vec![controlee_clone]), 2857 is_multicast_list_ntf_v2_supported: true, 2858 is_multicast_list_rsp_v2_supported: true, 2859 }; 2860 let pload = SessionUpdateControllerMulticastListRspV2Payload { 2861 status: StatusCode::UciStatusOk, 2862 controlee_status: vec![], 2863 }; 2864 let mut buf = BytesMut::new(); 2865 write_multicast_rsp_v2_payload(&pload, &mut buf); 2866 let resp = into_uci_hal_packets( 2867 uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder { 2868 payload: Some(buf.freeze()), 2869 }, 2870 ); 2871 2872 hal.expected_send_command(cmd, resp, Ok(())); 2873 }, 2874 UciLoggerMode::Disabled, 2875 mpsc::unbounded_channel::<UciLogEvent>().0, 2876 session_id, 2877 session_token, 2878 ) 2879 .await; 2880 2881 let result = uci_manager 2882 .session_update_controller_multicast_list( 2883 session_id, 2884 action, 2885 uwb_uci_packets::Controlees::LongSessionKey(vec![controlee]), 2886 true, 2887 true, 2888 ) 2889 .await; 2890 assert!(result.is_ok()); 2891 assert!(mock_hal.wait_expected_calls_done().await); 2892 } 2893 2894 #[tokio::test] test_session_query_max_data_size_ok()2895 async fn test_session_query_max_data_size_ok() { 2896 let session_id = 0x123; 2897 let session_token = 0x123; 2898 let max_data_size = 100; 2899 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2900 |mut hal| async move { 2901 let cmd = UciCommand::SessionQueryMaxDataSize { session_token }; 2902 let resp = 2903 into_uci_hal_packets(uwb_uci_packets::SessionQueryMaxDataSizeRspBuilder { 2904 max_data_size, 2905 session_token: 0x10, 2906 status: StatusCode::UciStatusOk, 2907 }); 2908 2909 hal.expected_send_command(cmd, resp, Ok(())); 2910 }, 2911 UciLoggerMode::Disabled, 2912 mpsc::unbounded_channel::<UciLogEvent>().0, 2913 session_id, 2914 session_token, 2915 ) 2916 .await; 2917 2918 let result = uci_manager.session_query_max_data_size(session_id).await.unwrap(); 2919 2920 assert_eq!(result, max_data_size); 2921 assert!(mock_hal.wait_expected_calls_done().await); 2922 } 2923 2924 #[tokio::test] test_core_query_uwb_timestamp_ok()2925 async fn test_core_query_uwb_timestamp_ok() { 2926 let session_id = 0x123; 2927 let session_token = 0x123; 2928 let time_stamp = 200; 2929 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2930 |mut hal| async move { 2931 let cmd = UciCommand::CoreQueryTimeStamp {}; 2932 let resp = into_uci_hal_packets(uwb_uci_packets::CoreQueryTimeStampRspBuilder { 2933 status: StatusCode::UciStatusOk, 2934 timeStamp: time_stamp, 2935 }); 2936 2937 hal.expected_send_command(cmd, resp, Ok(())); 2938 }, 2939 UciLoggerMode::Disabled, 2940 mpsc::unbounded_channel::<UciLogEvent>().0, 2941 session_id, 2942 session_token, 2943 ) 2944 .await; 2945 2946 let result = uci_manager.core_query_uwb_timestamp().await.unwrap(); 2947 2948 assert_eq!(result, time_stamp); 2949 assert!(mock_hal.wait_expected_calls_done().await); 2950 } 2951 2952 #[tokio::test] test_set_active_dt_tag_ranging_rounds()2953 async fn test_set_active_dt_tag_ranging_rounds() { 2954 let session_id = 0x123; 2955 let session_token = 0x123; 2956 2957 let ranging_rounds = SessionUpdateDtTagRangingRoundsResponse { 2958 status: StatusCode::UciStatusErrorRoundIndexNotActivated, 2959 ranging_round_indexes: vec![3], 2960 }; 2961 2962 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2963 |mut hal| async move { 2964 let cmd = UciCommand::SessionUpdateDtTagRangingRounds { 2965 session_token, 2966 ranging_round_indexes: vec![3, 5], 2967 }; 2968 let resp = into_uci_hal_packets( 2969 uwb_uci_packets::SessionUpdateDtTagRangingRoundsRspBuilder { 2970 status: StatusCode::UciStatusErrorRoundIndexNotActivated, 2971 ranging_round_indexes: vec![3], 2972 }, 2973 ); 2974 2975 hal.expected_send_command(cmd, resp, Ok(())); 2976 }, 2977 UciLoggerMode::Disabled, 2978 mpsc::unbounded_channel::<UciLogEvent>().0, 2979 session_id, 2980 session_token, 2981 ) 2982 .await; 2983 2984 let result = 2985 uci_manager.session_update_dt_tag_ranging_rounds(session_id, vec![3, 5]).await.unwrap(); 2986 2987 assert_eq!(result, ranging_rounds); 2988 assert!(mock_hal.wait_expected_calls_done().await); 2989 } 2990 2991 #[tokio::test] test_range_start_ok()2992 async fn test_range_start_ok() { 2993 let session_id = 0x123; 2994 let session_token = 0x123; 2995 2996 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2997 |mut hal| async move { 2998 let cmd = UciCommand::SessionStart { session_token }; 2999 let resp = into_uci_hal_packets(uwb_uci_packets::SessionStartRspBuilder { 3000 status: uwb_uci_packets::StatusCode::UciStatusOk, 3001 }); 3002 3003 hal.expected_send_command(cmd, resp, Ok(())); 3004 }, 3005 UciLoggerMode::Disabled, 3006 mpsc::unbounded_channel::<UciLogEvent>().0, 3007 session_id, 3008 session_token, 3009 ) 3010 .await; 3011 3012 let result = uci_manager.range_start(session_id).await; 3013 assert!(result.is_ok()); 3014 assert!(mock_hal.wait_expected_calls_done().await); 3015 } 3016 3017 #[tokio::test] test_range_stop_ok()3018 async fn test_range_stop_ok() { 3019 let session_id = 0x123; 3020 let session_token = 0x123; 3021 3022 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 3023 |mut hal| async move { 3024 let cmd = UciCommand::SessionStop { session_token }; 3025 let resp = into_uci_hal_packets(uwb_uci_packets::SessionStopRspBuilder { 3026 status: uwb_uci_packets::StatusCode::UciStatusOk, 3027 }); 3028 3029 hal.expected_send_command(cmd, resp, Ok(())); 3030 }, 3031 UciLoggerMode::Disabled, 3032 mpsc::unbounded_channel::<UciLogEvent>().0, 3033 session_id, 3034 session_token, 3035 ) 3036 .await; 3037 3038 let result = uci_manager.range_stop(session_id).await; 3039 assert!(result.is_ok()); 3040 assert!(mock_hal.wait_expected_calls_done().await); 3041 } 3042 3043 #[tokio::test] test_range_get_ranging_count_ok()3044 async fn test_range_get_ranging_count_ok() { 3045 let session_id = 0x123; 3046 let session_token = 0x123; 3047 let count = 3; 3048 3049 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 3050 |mut hal| async move { 3051 let cmd = UciCommand::SessionGetRangingCount { session_token }; 3052 let resp = 3053 into_uci_hal_packets(uwb_uci_packets::SessionGetRangingCountRspBuilder { 3054 status: uwb_uci_packets::StatusCode::UciStatusOk, 3055 count, 3056 }); 3057 3058 hal.expected_send_command(cmd, resp, Ok(())); 3059 }, 3060 UciLoggerMode::Disabled, 3061 mpsc::unbounded_channel::<UciLogEvent>().0, 3062 session_id, 3063 session_token, 3064 ) 3065 .await; 3066 3067 let result = uci_manager.range_get_ranging_count(session_id).await.unwrap(); 3068 assert_eq!(result, count as usize); 3069 assert!(mock_hal.wait_expected_calls_done().await); 3070 } 3071 3072 #[tokio::test] test_android_set_country_code_ok()3073 async fn test_android_set_country_code_ok() { 3074 let country_code = CountryCode::new(b"US").unwrap(); 3075 let country_code_clone = country_code.clone(); 3076 3077 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 3078 |mut hal| async move { 3079 let cmd = UciCommand::AndroidSetCountryCode { country_code: country_code_clone }; 3080 let resp = into_uci_hal_packets(uwb_uci_packets::AndroidSetCountryCodeRspBuilder { 3081 status: uwb_uci_packets::StatusCode::UciStatusOk, 3082 }); 3083 3084 hal.expected_send_command(cmd, resp, Ok(())); 3085 }, 3086 UciLoggerMode::Disabled, 3087 mpsc::unbounded_channel::<UciLogEvent>().0, 3088 ) 3089 .await; 3090 3091 let result = uci_manager.android_set_country_code(country_code).await; 3092 assert!(result.is_ok()); 3093 assert!(mock_hal.wait_expected_calls_done().await); 3094 } 3095 3096 #[tokio::test] test_android_get_power_stats_ok()3097 async fn test_android_get_power_stats_ok() { 3098 let power_stats = PowerStats { 3099 status: StatusCode::UciStatusOk, 3100 idle_time_ms: 123, 3101 tx_time_ms: 456, 3102 rx_time_ms: 789, 3103 total_wake_count: 5, 3104 }; 3105 let power_stats_clone = power_stats.clone(); 3106 3107 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 3108 |mut hal| async move { 3109 let cmd = UciCommand::AndroidGetPowerStats; 3110 let resp = into_uci_hal_packets(uwb_uci_packets::AndroidGetPowerStatsRspBuilder { 3111 stats: power_stats_clone, 3112 }); 3113 3114 hal.expected_send_command(cmd, resp, Ok(())); 3115 }, 3116 UciLoggerMode::Disabled, 3117 mpsc::unbounded_channel::<UciLogEvent>().0, 3118 ) 3119 .await; 3120 3121 let result = uci_manager.android_get_power_stats().await.unwrap(); 3122 assert_eq!(result, power_stats); 3123 assert!(mock_hal.wait_expected_calls_done().await); 3124 } 3125 3126 #[tokio::test] test_android_set_radar_config_ok()3127 async fn test_android_set_radar_config_ok() { 3128 let session_id = 0x123; 3129 let session_token = 0x123; 3130 let config_tlv = 3131 RadarConfigTlv { cfg_id: RadarConfigTlvType::SamplesPerSweep, v: vec![0x12, 0x34] }; 3132 let config_tlv_clone = config_tlv.clone(); 3133 3134 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 3135 |mut hal| async move { 3136 let cmd = UciCommand::AndroidSetRadarConfig { 3137 session_token, 3138 config_tlvs: vec![config_tlv_clone], 3139 }; 3140 let resp = into_uci_hal_packets(uwb_uci_packets::AndroidSetRadarConfigRspBuilder { 3141 status: uwb_uci_packets::StatusCode::UciStatusOk, 3142 cfg_status: vec![], 3143 }); 3144 3145 hal.expected_send_command(cmd, resp, Ok(())); 3146 }, 3147 UciLoggerMode::Disabled, 3148 mpsc::unbounded_channel::<UciLogEvent>().0, 3149 session_id, 3150 session_token, 3151 ) 3152 .await; 3153 3154 let expected_result = 3155 AndroidRadarConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; 3156 let result = 3157 uci_manager.android_set_radar_config(session_id, vec![config_tlv]).await.unwrap(); 3158 assert_eq!(result, expected_result); 3159 assert!(mock_hal.wait_expected_calls_done().await); 3160 } 3161 3162 #[tokio::test] test_android_get_radar_config_ok()3163 async fn test_android_get_radar_config_ok() { 3164 let session_id = 0x123; 3165 let session_token = 0x123; 3166 let config_id = RadarConfigTlvType::SamplesPerSweep; 3167 let tlv = 3168 RadarConfigTlv { cfg_id: RadarConfigTlvType::SamplesPerSweep, v: vec![0x12, 0x34] }; 3169 let tlv_clone = tlv.clone(); 3170 3171 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 3172 |mut hal| async move { 3173 let cmd = 3174 UciCommand::AndroidGetRadarConfig { session_token, radar_cfg: vec![config_id] }; 3175 let resp = into_uci_hal_packets(uwb_uci_packets::AndroidGetRadarConfigRspBuilder { 3176 status: uwb_uci_packets::StatusCode::UciStatusOk, 3177 tlvs: vec![tlv_clone], 3178 }); 3179 3180 hal.expected_send_command(cmd, resp, Ok(())); 3181 }, 3182 UciLoggerMode::Disabled, 3183 mpsc::unbounded_channel::<UciLogEvent>().0, 3184 session_id, 3185 session_token, 3186 ) 3187 .await; 3188 3189 let expected_result = vec![tlv]; 3190 let result = 3191 uci_manager.android_get_radar_config(session_id, vec![config_id]).await.unwrap(); 3192 assert_eq!(result, expected_result); 3193 assert!(mock_hal.wait_expected_calls_done().await); 3194 } 3195 3196 #[tokio::test] test_raw_uci_cmd_vendor_gid_ok()3197 async fn test_raw_uci_cmd_vendor_gid_ok() { 3198 let mt = 0x1; 3199 let gid = 0xF; // Vendor reserved GID. 3200 let oid = 0x3; 3201 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3202 let cmd_payload_clone = cmd_payload.clone(); 3203 let resp_payload = vec![0x55, 0x66, 0x77, 0x88]; 3204 let resp_payload_clone = resp_payload.clone(); 3205 3206 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 3207 |mut hal| async move { 3208 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone }; 3209 let resp = into_uci_hal_packets(uwb_uci_packets::UciVendor_F_ResponseBuilder { 3210 opcode: oid as u8, 3211 payload: Some(Bytes::from(resp_payload_clone)), 3212 }); 3213 3214 hal.expected_send_command(cmd, resp, Ok(())); 3215 }, 3216 UciLoggerMode::Disabled, 3217 mpsc::unbounded_channel::<UciLogEvent>().0, 3218 ) 3219 .await; 3220 3221 let expected_result = RawUciMessage { gid, oid, payload: resp_payload }; 3222 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap(); 3223 assert_eq!(result, expected_result); 3224 assert!(mock_hal.wait_expected_calls_done().await); 3225 } 3226 3227 #[tokio::test] test_raw_uci_cmd_fira_gid_ok()3228 async fn test_raw_uci_cmd_fira_gid_ok() { 3229 let mt = 0x1; 3230 let gid = 0x1; // SESSION_CONFIG GID. 3231 let oid = 0x3; 3232 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3233 let cmd_payload_clone = cmd_payload.clone(); 3234 let resp_payload = vec![0x00, 0x01, 0x07, 0x00]; 3235 let status = StatusCode::UciStatusOk; 3236 let cfg_id = AppConfigTlvType::DstMacAddress; 3237 let app_config = AppConfigStatus { cfg_id, status }; 3238 let cfg_status = vec![app_config]; 3239 3240 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal_nop_logger( 3241 |mut hal| async move { 3242 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone }; 3243 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 3244 status, 3245 cfg_status, 3246 }); 3247 3248 hal.expected_send_command(cmd, resp, Ok(())); 3249 }, 3250 UciLoggerMode::Disabled, 3251 ) 3252 .await; 3253 3254 let expected_result = RawUciMessage { gid, oid, payload: resp_payload }; 3255 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap(); 3256 assert_eq!(result, expected_result); 3257 assert!(mock_hal.wait_expected_calls_done().await); 3258 } 3259 3260 #[tokio::test] test_raw_uci_cmd_undefined_mt_ok()3261 async fn test_raw_uci_cmd_undefined_mt_ok() { 3262 let mt = 0x4; 3263 let gid = 0x1; // SESSION_CONFIG GID. 3264 let oid = 0x3; 3265 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3266 let cmd_payload_clone = cmd_payload.clone(); 3267 let resp_payload = vec![0x00, 0x01, 0x07, 0x00]; 3268 let status = StatusCode::UciStatusOk; 3269 let cfg_id = AppConfigTlvType::DstMacAddress; 3270 let app_config = AppConfigStatus { cfg_id, status }; 3271 let cfg_status = vec![app_config]; 3272 3273 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 3274 |mut hal| async move { 3275 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone }; 3276 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 3277 status, 3278 cfg_status, 3279 }); 3280 3281 hal.expected_send_command(cmd, resp, Ok(())); 3282 }, 3283 UciLoggerMode::Disabled, 3284 mpsc::unbounded_channel::<UciLogEvent>().0, 3285 ) 3286 .await; 3287 3288 let expected_result = RawUciMessage { gid, oid, payload: resp_payload }; 3289 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap(); 3290 assert_eq!(result, expected_result); 3291 assert!(mock_hal.wait_expected_calls_done().await); 3292 } 3293 3294 #[tokio::test] test_raw_uci_cmd_custom_payload_format()3295 async fn test_raw_uci_cmd_custom_payload_format() { 3296 // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the 3297 // UCI HAL returns a UCI response with a custom payload format. The UCI response packet 3298 // should still be successfully parsed and returned, since it's a Raw UCI RSP. 3299 let cmd_mt: u8 = 0x1; 3300 let gid: u8 = 0x1; // Session Config. 3301 let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG 3302 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3303 let cmd_payload_clone = cmd_payload.clone(); 3304 let resp_mt: u8 = 0x2; 3305 let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; 3306 let resp_payload_clone = resp_payload.clone(); 3307 3308 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 3309 |mut hal| async move { 3310 let cmd = UciCommand::RawUciCmd { 3311 mt: cmd_mt.into(), 3312 gid: gid.into(), 3313 oid: oid.into(), 3314 payload: cmd_payload_clone, 3315 }; 3316 let resp = build_uci_packet(resp_mt, 0, gid, oid, resp_payload_clone); 3317 hal.expected_send_command(cmd, vec![resp], Ok(())); 3318 }, 3319 UciLoggerMode::Disabled, 3320 mpsc::unbounded_channel::<UciLogEvent>().0, 3321 ) 3322 .await; 3323 3324 let expected_result = 3325 Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload }); 3326 let result = 3327 uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await; 3328 assert_eq!(result, expected_result); 3329 assert!(mock_hal.wait_expected_calls_done().await); 3330 } 3331 3332 #[tokio::test] test_raw_uci_cmd_fragmented_responses()3333 async fn test_raw_uci_cmd_fragmented_responses() { 3334 // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the 3335 // UCI HAL returns a UCI response with a custom payload format, in 2 UCI packet fragments. 3336 let cmd_mt: u8 = 0x1; 3337 let gid: u8 = 0x1; // Session Config. 3338 let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG 3339 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3340 let cmd_payload_clone = cmd_payload.clone(); 3341 let resp_mt: u8 = 0x2; 3342 let resp_payload_fragment_1 = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; 3343 let resp_payload_fragment_2 = vec![0x09, 0x0a, 0x0b]; 3344 let mut resp_payload_expected = resp_payload_fragment_1.clone(); 3345 resp_payload_expected.extend(resp_payload_fragment_2.clone()); 3346 3347 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 3348 |mut hal| async move { 3349 let cmd = UciCommand::RawUciCmd { 3350 mt: cmd_mt.into(), 3351 gid: gid.into(), 3352 oid: oid.into(), 3353 payload: cmd_payload_clone, 3354 }; 3355 let resp_fragment_1 = build_uci_packet( 3356 resp_mt, 3357 /* pbf = */ 1, 3358 gid, 3359 oid, 3360 resp_payload_fragment_1, 3361 ); 3362 let resp_fragment_2 = build_uci_packet( 3363 resp_mt, 3364 /* pbf = */ 0, 3365 gid, 3366 oid, 3367 resp_payload_fragment_2, 3368 ); 3369 hal.expected_send_command(cmd, vec![resp_fragment_1, resp_fragment_2], Ok(())); 3370 }, 3371 UciLoggerMode::Disabled, 3372 mpsc::unbounded_channel::<UciLogEvent>().0, 3373 ) 3374 .await; 3375 3376 let expected_result = 3377 Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload_expected }); 3378 let result = 3379 uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await; 3380 assert_eq!(result, expected_result); 3381 assert!(mock_hal.wait_expected_calls_done().await); 3382 } 3383 3384 #[tokio::test] test_raw_uci_cmd_wrong_gid()3385 async fn test_raw_uci_cmd_wrong_gid() { 3386 // Send a raw UCI command with CORE GID, but UCI HAL returns a UCI response with 3387 // SESSION_CONFIG GID. In this case, UciManager should return Error::Unknown, as the 3388 // RawUciSignature fields (GID, OID) of the CMD and RSP packets don't match. 3389 3390 let mt = 0x1; 3391 let gid = 0x0; // CORE GID. 3392 let oid = 0x1; 3393 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3394 let cmd_payload_clone = cmd_payload.clone(); 3395 let status = StatusCode::UciStatusOk; 3396 let cfg_id = AppConfigTlvType::DstMacAddress; 3397 let app_config = AppConfigStatus { cfg_id, status }; 3398 let cfg_status = vec![app_config]; 3399 3400 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 3401 |mut hal| async move { 3402 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone }; 3403 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 3404 status, 3405 cfg_status, 3406 }); 3407 3408 hal.expected_send_command(cmd, resp, Ok(())); 3409 }, 3410 UciLoggerMode::Disabled, 3411 mpsc::unbounded_channel::<UciLogEvent>().0, 3412 ) 3413 .await; 3414 3415 let expected_result = Err(Error::Unknown); 3416 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await; 3417 assert_eq!(result, expected_result); 3418 assert!(mock_hal.wait_expected_calls_done().await); 3419 } 3420 3421 #[tokio::test] test_raw_uci_cmd_out_of_range_gid()3422 async fn test_raw_uci_cmd_out_of_range_gid() { 3423 // Send a raw UCI command with a GID value outside it's 8-bit size. This should result in 3424 // an error since the input GID value cannot be encoded into the UCI packet. 3425 let mt = 0x1; 3426 let gid = 0x1FF; 3427 let oid = 0x1; 3428 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3429 3430 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal_nop_logger( 3431 move |_hal| async {}, 3432 UciLoggerMode::Disabled, 3433 ) 3434 .await; 3435 3436 let expected_result = Err(Error::BadParameters); 3437 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await; 3438 assert_eq!(result, expected_result); 3439 assert!(mock_hal.wait_expected_calls_done().await); 3440 } 3441 3442 #[tokio::test] test_raw_uci_cmd_out_of_range_oid()3443 async fn test_raw_uci_cmd_out_of_range_oid() { 3444 // Send a raw UCI command with a valid GID (CORE), but an OID value outside it's 8-bit 3445 // size. This should result in an error since the input OID value cannot be encoded into 3446 // the UCI packet. 3447 let mt = 0x1; 3448 let gid = 0x0; // CORE GID. 3449 let oid = 0x1FF; 3450 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3451 3452 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 3453 |_hal| async move {}, 3454 UciLoggerMode::Disabled, 3455 mpsc::unbounded_channel::<UciLogEvent>().0, 3456 ) 3457 .await; 3458 3459 let expected_result = Err(Error::BadParameters); 3460 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await; 3461 assert_eq!(result, expected_result); 3462 assert!(mock_hal.wait_expected_calls_done().await); 3463 } 3464 3465 #[tokio::test] test_raw_uci_cmd_uwbs_response_notification()3466 async fn test_raw_uci_cmd_uwbs_response_notification() { 3467 // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the 3468 // UCI HAL returns a valid UCI Notification packet before the raw UCI response. 3469 let cmd_mt: u8 = 0x1; 3470 let gid: u8 = 0x1; // Session Config. 3471 let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG 3472 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3473 let cmd_payload_clone = cmd_payload.clone(); 3474 let session_token = 0x123; 3475 let resp_mt: u8 = 0x2; 3476 let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; 3477 let resp_payload_clone = resp_payload.clone(); 3478 3479 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 3480 |mut hal| async move { 3481 let cmd = UciCommand::RawUciCmd { 3482 mt: cmd_mt.into(), 3483 gid: gid.into(), 3484 oid: oid.into(), 3485 payload: cmd_payload_clone, 3486 }; 3487 let raw_resp = build_uci_packet(resp_mt, 0, gid, oid, resp_payload_clone); 3488 let mut responses = 3489 into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder { 3490 session_token, 3491 session_state: uwb_uci_packets::SessionState::SessionStateInit, 3492 reason_code: 3493 uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands 3494 .into(), 3495 }); 3496 responses.push(raw_resp); 3497 hal.expected_send_command(cmd, responses, Ok(())); 3498 }, 3499 UciLoggerMode::Disabled, 3500 mpsc::unbounded_channel::<UciLogEvent>().0, 3501 ) 3502 .await; 3503 3504 let expected_result = 3505 Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload }); 3506 let result = 3507 uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await; 3508 assert_eq!(result, expected_result); 3509 assert!(mock_hal.wait_expected_calls_done().await); 3510 } 3511 3512 #[tokio::test] test_raw_uci_cmd_uwbs_response_undefined_mt()3513 async fn test_raw_uci_cmd_uwbs_response_undefined_mt() { 3514 // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the 3515 // UCI HAL returns a UCI packet with an undefined MessageType in response. 3516 let cmd_mt: u8 = 0x1; 3517 let gid: u8 = 0x1; // Session Config. 3518 let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG 3519 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 3520 let cmd_payload_clone = cmd_payload.clone(); 3521 let resp_mt: u8 = 0x7; // Undefined MessageType 3522 let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; 3523 3524 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal_nop_logger( 3525 |mut hal| async move { 3526 let cmd = UciCommand::RawUciCmd { 3527 mt: cmd_mt.into(), 3528 gid: gid.into(), 3529 oid: oid.into(), 3530 payload: cmd_payload_clone, 3531 }; 3532 let resp = build_uci_packet(resp_mt, /* pbf = */ 0, gid, oid, resp_payload); 3533 hal.expected_send_command(cmd, vec![resp], Ok(())); 3534 }, 3535 UciLoggerMode::Disabled, 3536 ) 3537 .await; 3538 3539 let expected_result = Err(Error::Unknown); 3540 let result = 3541 uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await; 3542 assert_eq!(result, expected_result); 3543 assert!(mock_hal.wait_expected_calls_done().await); 3544 } 3545 setup_hal_for_session_active( hal: &mut MockUciHal, session_type: SessionType, session_id: u32, session_token: u32, )3546 fn setup_hal_for_session_active( 3547 hal: &mut MockUciHal, 3548 session_type: SessionType, 3549 session_id: u32, 3550 session_token: u32, 3551 ) { 3552 // Setup session init. 3553 setup_hal_for_session_initialize(hal, session_type, session_id, session_token); 3554 3555 // Setup session active. 3556 let cmd = UciCommand::SessionStart { session_token }; 3557 let mut responses = into_uci_hal_packets(uwb_uci_packets::SessionStartRspBuilder { 3558 status: uwb_uci_packets::StatusCode::UciStatusOk, 3559 }); 3560 responses.append(&mut into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder { 3561 session_token, 3562 session_state: SessionState::SessionStateActive, 3563 reason_code: 0, /* ReasonCode::StateChangeWithSessionManagementCommands */ 3564 })); 3565 hal.expected_send_command(cmd, responses, Ok(())); 3566 } 3567 setup_uci_manager_with_session_active<F, Fut>( setup_hal_fn: F, uci_logger_mode: UciLoggerMode, log_sender: mpsc::UnboundedSender<UciLogEvent>, session_id: u32, session_token: u32, ) -> (UciManagerImpl, MockUciHal) where F: FnOnce(MockUciHal) -> Fut, Fut: Future<Output = ()>,3568 async fn setup_uci_manager_with_session_active<F, Fut>( 3569 setup_hal_fn: F, 3570 uci_logger_mode: UciLoggerMode, 3571 log_sender: mpsc::UnboundedSender<UciLogEvent>, 3572 session_id: u32, 3573 session_token: u32, 3574 ) -> (UciManagerImpl, MockUciHal) 3575 where 3576 F: FnOnce(MockUciHal) -> Fut, 3577 Fut: Future<Output = ()>, 3578 { 3579 let session_type = SessionType::FiraRangingSession; 3580 3581 init_test_logging(); 3582 3583 let mut hal = MockUciHal::new(); 3584 setup_hal_for_session_active(&mut hal, session_type, session_id, session_token); 3585 3586 // Verify open_hal() is working. 3587 let uci_manager = 3588 UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode); 3589 let result = uci_manager.open_hal().await; 3590 assert!(result.is_ok()); 3591 3592 // Verify session is initialized. 3593 let result = uci_manager.session_init(session_id, session_type).await; 3594 assert!(result.is_ok()); 3595 3596 // Verify session is started. 3597 let result = uci_manager.range_start(session_id).await; 3598 assert!(result.is_ok()); 3599 assert!(hal.wait_expected_calls_done().await); 3600 3601 setup_hal_fn(hal.clone()).await; 3602 3603 (uci_manager, hal) 3604 } 3605 setup_uci_manager_with_session_active_nop_logger<F, Fut>( setup_hal_fn: F, uci_logger_mode: UciLoggerMode, session_id: u32, session_token: u32, ) -> (UciManagerImpl, MockUciHal) where F: FnOnce(MockUciHal) -> Fut, Fut: Future<Output = ()>,3606 async fn setup_uci_manager_with_session_active_nop_logger<F, Fut>( 3607 setup_hal_fn: F, 3608 uci_logger_mode: UciLoggerMode, 3609 session_id: u32, 3610 session_token: u32, 3611 ) -> (UciManagerImpl, MockUciHal) 3612 where 3613 F: FnOnce(MockUciHal) -> Fut, 3614 Fut: Future<Output = ()>, 3615 { 3616 let session_type = SessionType::FiraRangingSession; 3617 3618 init_test_logging(); 3619 3620 let mut hal = MockUciHal::new(); 3621 setup_hal_for_session_active(&mut hal, session_type, session_id, session_token); 3622 3623 // Verify open_hal() is working. 3624 let uci_manager = 3625 UciManagerImpl::new(hal.clone(), NopUciLogger::default(), uci_logger_mode); 3626 let result = uci_manager.open_hal().await; 3627 assert!(result.is_ok()); 3628 3629 // Verify session is initialized. 3630 let result = uci_manager.session_init(session_id, session_type).await; 3631 assert!(result.is_ok()); 3632 3633 // Verify session is started. 3634 let result = uci_manager.range_start(session_id).await; 3635 assert!(result.is_ok()); 3636 assert!(hal.wait_expected_calls_done().await); 3637 3638 setup_hal_fn(hal.clone()).await; 3639 3640 (uci_manager, hal) 3641 } 3642 3643 // Test Data packet receive for a single packet (on an active UWB session). 3644 #[tokio::test] test_data_packet_recv_ok()3645 async fn test_data_packet_recv_ok() { 3646 let mt_data = 0x0; 3647 let pbf = 0x0; 3648 let dpf = 0x2; 3649 let oid = 0x0; 3650 let session_id = 0x3; 3651 let session_token = 0x5; 3652 let uci_sequence_num = 0xa; 3653 let source_address = UwbAddress::Extended([0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1]); 3654 let app_data = vec![0x01, 0x02, 0x03]; 3655 let data_rcv_payload = vec![ 3656 0x05, 0x00, 0x00, 0x00, // SessionToken 3657 0x00, // StatusCode 3658 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 3659 0x0a, 0x00, // UciSequenceNumber 3660 0x03, 0x00, // AppDataLen 3661 0x01, 0x02, 0x03, // AppData 3662 ]; 3663 3664 // Setup the DataPacketRcv (Rx by HAL) and the expected DataRcvNotification. 3665 let data_packet_rcv = build_uci_packet(mt_data, pbf, dpf, oid, data_rcv_payload); 3666 let expected_data_rcv_notification = DataRcvNotification { 3667 session_token: session_id, 3668 status: StatusCode::UciStatusOk, 3669 uci_sequence_num, 3670 source_address, 3671 payload: app_data, 3672 }; 3673 3674 // Setup an active UWBS session over which the DataPacket will be received by the Host. 3675 let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 3676 |_| async move {}, 3677 UciLoggerMode::Disabled, 3678 mpsc::unbounded_channel::<UciLogEvent>().0, 3679 session_id, 3680 session_token, 3681 ) 3682 .await; 3683 3684 let (data_rcv_notification_sender, mut data_rcv_notification_receiver) = 3685 mpsc::unbounded_channel::<DataRcvNotification>(); 3686 uci_manager.set_data_rcv_notification_sender(data_rcv_notification_sender).await; 3687 3688 // Inject the UCI DataPacketRcv into HAL. 3689 let result = mock_hal.receive_packet(data_packet_rcv); 3690 assert!(result.is_ok()); 3691 3692 // UciManager should send a DataRcvNotification (for the valid Rx packet). 3693 let result = 3694 tokio::time::timeout(Duration::from_millis(100), data_rcv_notification_receiver.recv()) 3695 .await; 3696 assert!(result.is_ok()); 3697 assert_eq!(result.unwrap(), Some(expected_data_rcv_notification)); 3698 assert!(mock_hal.wait_expected_calls_done().await); 3699 } 3700 3701 // Test Data packet receive for two packet fragments (on an active UWB session). 3702 #[tokio::test] test_data_packet_recv_fragmented_packets_ok()3703 async fn test_data_packet_recv_fragmented_packets_ok() { 3704 let mt_data = 0x0; 3705 let pbf_fragment_1 = 0x1; 3706 let pbf_fragment_2 = 0x0; 3707 let dpf = 0x2; 3708 let oid = 0x0; 3709 let session_id = 0x3; 3710 let session_token = 0x5; 3711 let uci_sequence_num = 0xa; 3712 let source_address = UwbAddress::Extended([0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1]); 3713 let app_data_len = 300; 3714 let app_data_fragment_1_len = 200; 3715 let mut data_rcv_payload_fragment_1: Vec<u8> = vec![ 3716 0x05, 0x00, 0x00, 0x00, // SessionToken 3717 0x00, // StatusCode 3718 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 3719 0x0a, 0x00, // UciSequenceNumber 3720 0x2c, 0x01, // AppData Length (300) 3721 ]; 3722 3723 // Setup the application data (payload) for the 2 DataPacketRcv fragments. 3724 let mut app_data: Vec<u8> = Vec::new(); 3725 for i in 0..app_data_len { 3726 app_data.push((i & 0xff).try_into().unwrap()); 3727 } 3728 data_rcv_payload_fragment_1.extend_from_slice(&app_data[0..app_data_fragment_1_len]); 3729 let mut data_rcv_payload_fragment_2: Vec<u8> = Vec::new(); 3730 data_rcv_payload_fragment_2.extend_from_slice(&app_data[app_data_fragment_1_len..]); 3731 3732 // Setup the DataPacketRcv fragments (Rx by HAL) and the expected DataRcvNotification. 3733 let data_packet_rcv_fragment_1 = 3734 build_uci_packet(mt_data, pbf_fragment_1, dpf, oid, data_rcv_payload_fragment_1); 3735 let data_packet_rcv_fragment_2 = 3736 build_uci_packet(mt_data, pbf_fragment_2, dpf, oid, data_rcv_payload_fragment_2); 3737 let expected_data_rcv_notification = DataRcvNotification { 3738 session_token: session_id, 3739 status: StatusCode::UciStatusOk, 3740 uci_sequence_num, 3741 source_address, 3742 payload: app_data, 3743 }; 3744 3745 // Setup an active UWBS session over which the DataPacket will be received by the Host. 3746 let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_session_active_nop_logger( 3747 |_| async move {}, 3748 UciLoggerMode::Disabled, 3749 session_id, 3750 session_token, 3751 ) 3752 .await; 3753 3754 let (data_rcv_notification_sender, mut data_rcv_notification_receiver) = 3755 mpsc::unbounded_channel::<DataRcvNotification>(); 3756 uci_manager.set_data_rcv_notification_sender(data_rcv_notification_sender).await; 3757 3758 // Inject the 2 UCI DataPacketRcv into HAL. 3759 let result = mock_hal.receive_packet(data_packet_rcv_fragment_1); 3760 assert!(result.is_ok()); 3761 let result = mock_hal.receive_packet(data_packet_rcv_fragment_2); 3762 assert!(result.is_ok()); 3763 3764 // UciManager should send a DataRcvNotification (for the valid Rx packet). 3765 let result = 3766 tokio::time::timeout(Duration::from_millis(100), data_rcv_notification_receiver.recv()) 3767 .await; 3768 assert!(result.is_ok()); 3769 assert_eq!(result.unwrap(), Some(expected_data_rcv_notification)); 3770 assert!(mock_hal.wait_expected_calls_done().await); 3771 } 3772 3773 #[tokio::test] test_data_packet_recv_bad_payload_len_failure()3774 async fn test_data_packet_recv_bad_payload_len_failure() {} 3775 3776 // Test Radar Data packet receive for a single packet (on an active UWB session). 3777 #[tokio::test] test_radar_data_packet_recv_ok()3778 async fn test_radar_data_packet_recv_ok() { 3779 let mt_data = 0x0; 3780 let pbf = 0x0; 3781 let dpf = 0xf; 3782 let oid = 0x0; 3783 let session_id = 0x3; 3784 let session_token = 0x5; 3785 let radar_data_type = RadarDataType::RadarSweepSamples; 3786 let number_of_sweeps = 0x02; 3787 let samples_per_sweep = 0x02; 3788 let bits_per_sample = BitsPerSample::Value32; 3789 let sweep_offset = 0x0; 3790 let sequence_number_1 = 0xa; 3791 let sequence_number_2 = 0xb; 3792 let timestamp_1 = 0xc; 3793 let timestamp_2 = 0xd; 3794 let vendor_specific_data_1 = vec![0x0b]; 3795 let vendor_specific_data_2 = vec![0x0b, 0x0c]; 3796 let sample_data_1 = vec![0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa]; 3797 let sample_data_2 = vec![0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; 3798 let radar_data_rcv_payload = vec![ 3799 0x05, 0x00, 0x00, 0x00, // session_handle 3800 0x00, // status 3801 0x00, // radar data type 3802 0x02, // number of sweeps 3803 0x02, // samples per sweep 3804 0x00, // bits per sample 3805 0x00, 0x00, // sweep offset 3806 0x10, 0x11, // sweep data size 3807 // sweep data 1 3808 0x0a, 0x00, 0x00, 0x00, // sequence number 3809 0x0c, 0x00, 0x00, 0x00, // timestamp 3810 0x01, // vendor specific data length 3811 0x0b, // vendor specific data 3812 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, // sample data 3813 // sweep data 2 3814 0x0b, 0x00, 0x00, 0x00, // sequence number 3815 0x0d, 0x00, 0x00, 0x00, // timestamp 3816 0x02, // vendor specific data length 3817 0x0b, 0x0c, // vendor specific data 3818 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sample data 3819 ]; 3820 3821 // Setup the DataPacketRcv (Rx by HAL) and the expected DataRcvNotification. 3822 let radar_data_packet_rcv = 3823 build_uci_packet(mt_data, pbf, dpf, oid, radar_data_rcv_payload); 3824 let expected_radar_data_rcv_notification = RadarDataRcvNotification { 3825 session_token: session_id, 3826 status: DataRcvStatusCode::UciStatusSuccess, 3827 radar_data_type, 3828 number_of_sweeps, 3829 samples_per_sweep, 3830 bits_per_sample, 3831 sweep_offset, 3832 sweep_data: vec![ 3833 RadarSweepData { 3834 sequence_number: sequence_number_1, 3835 timestamp: timestamp_1, 3836 vendor_specific_data: vendor_specific_data_1, 3837 sample_data: sample_data_1, 3838 }, 3839 RadarSweepData { 3840 sequence_number: sequence_number_2, 3841 timestamp: timestamp_2, 3842 vendor_specific_data: vendor_specific_data_2, 3843 sample_data: sample_data_2, 3844 }, 3845 ], 3846 }; 3847 3848 // Setup an active UWBS session over which the DataPacket will be received by the Host. 3849 let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 3850 |_| async move {}, 3851 UciLoggerMode::Disabled, 3852 mpsc::unbounded_channel::<UciLogEvent>().0, 3853 session_id, 3854 session_token, 3855 ) 3856 .await; 3857 3858 let (radar_data_rcv_notification_sender, mut radar_data_rcv_notification_receiver) = 3859 mpsc::unbounded_channel::<RadarDataRcvNotification>(); 3860 uci_manager 3861 .set_radar_data_rcv_notification_sender(radar_data_rcv_notification_sender) 3862 .await; 3863 3864 // Inject the UCI DataPacketRcv into HAL. 3865 let result = mock_hal.receive_packet(radar_data_packet_rcv); 3866 assert!(result.is_ok()); 3867 3868 // UciManager should send a DataRcvNotification (for the valid Rx packet). 3869 let result = tokio::time::timeout( 3870 Duration::from_millis(100), 3871 radar_data_rcv_notification_receiver.recv(), 3872 ) 3873 .await; 3874 assert!(result.is_ok()); 3875 assert_eq!(result.unwrap(), Some(expected_radar_data_rcv_notification)); 3876 assert!(mock_hal.wait_expected_calls_done().await); 3877 } 3878 3879 #[tokio::test] test_data_packet_send_ok()3880 async fn test_data_packet_send_ok() { 3881 // Test Data packet send for a single packet (on a UWB session). 3882 let mt_data = 0x0; 3883 let pbf = 0x0; 3884 let dpf = 0x1; 3885 let oid = 0x0; 3886 let session_id = 0x5; 3887 let session_token = 0x5; 3888 let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1]; 3889 let uci_sequence_number: u16 = 0xa; 3890 let app_data = vec![0x01, 0x02, 0x03]; 3891 let expected_data_snd_payload = vec![ 3892 0x05, 0x00, 0x00, 0x00, // SessionID 3893 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 3894 0x0a, 0x00, // UciSequenceNumber 3895 0x03, 0x00, // AppDataLen 3896 0x01, 0x02, 0x03, // AppData 3897 ]; 3898 let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk; 3899 let tx_count = 0x00; 3900 3901 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active_nop_logger( 3902 |mut hal| async move { 3903 // Now setup the notifications that should be received after a Data packet send. 3904 let data_packet_snd = 3905 build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload); 3906 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 3907 session_token, 3908 credit_availability: CreditAvailability::CreditAvailable, 3909 }); 3910 ntfs.append(&mut into_uci_hal_packets( 3911 uwb_uci_packets::DataTransferStatusNtfBuilder { 3912 session_token, 3913 uci_sequence_number, 3914 status, 3915 tx_count, 3916 }, 3917 )); 3918 hal.expected_send_packet(data_packet_snd, ntfs, Ok(())); 3919 }, 3920 UciLoggerMode::Disabled, 3921 session_id, 3922 session_token, 3923 ) 3924 .await; 3925 3926 let result = uci_manager 3927 .send_data_packet(session_id, dest_mac_address, uci_sequence_number, app_data) 3928 .await; 3929 assert!(result.is_ok()); 3930 assert!(mock_hal.wait_expected_calls_done().await); 3931 3932 // TODO(b/276320369): Verify that session_notf_sender is called (once implemented), as a 3933 // DataTransferStatusNtf is received in this test scenario. 3934 } 3935 3936 // Test the Host sending a DATA packet to UWBS that needs to be fragmented, where the 3937 // fragment size is based on a default value (MAX_PAYLOAD_LEN). 3938 #[tokio::test] test_data_packet_send_fragmented_packet_ok_uses_default_fragment_size()3939 async fn test_data_packet_send_fragmented_packet_ok_uses_default_fragment_size() { 3940 // Don't setup UWBS returning a response to CORE_GET_DEVICE_INFO and CORE_GET_CAPS_INFO; 3941 // this simulates the scenario of the default UCI data packet fragment size being used. 3942 3943 // Test Data packet send for a set of data packet fragments (on a UWB session). 3944 let mt_data = 0x0; 3945 let pbf_fragment_1 = 0x1; 3946 let pbf_fragment_2 = 0x0; 3947 let dpf = 0x1; 3948 let oid = 0x0; 3949 let session_id = 0x5; 3950 let session_token = 0x5; 3951 let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1]; 3952 let uci_sequence_number: u16 = 0xa; 3953 let app_data_len = 300; // Larger than MAX_PAYLOAD_LEN=255, so fragmentation occurs. 3954 let mut app_data = Vec::new(); 3955 let mut expected_data_snd_payload_fragment_1 = vec![ 3956 0x05, 0x00, 0x00, 0x00, // SessionID 3957 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 3958 0x0a, 0x00, // UciSequenceNumber 3959 0x2c, 0x01, // AppDataLen = 300 3960 ]; 3961 let mut expected_data_snd_payload_fragment_2 = Vec::new(); 3962 let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk; 3963 let tx_count = 0x00; 3964 3965 // Setup the app data for both the Tx data packet and expected packet fragments. 3966 let app_data_len_fragment_1 = 255 - expected_data_snd_payload_fragment_1.len(); 3967 for i in 0..app_data_len { 3968 app_data.push((i & 0xff).try_into().unwrap()); 3969 if i < app_data_len_fragment_1 { 3970 expected_data_snd_payload_fragment_1.push((i & 0xff).try_into().unwrap()); 3971 } else { 3972 expected_data_snd_payload_fragment_2.push((i & 0xff).try_into().unwrap()); 3973 } 3974 } 3975 3976 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 3977 |mut hal| async move { 3978 // Expected data packet fragment #1 (UCI Header + Initial App data bytes). 3979 let data_packet_snd_fragment_1 = build_uci_packet( 3980 mt_data, 3981 pbf_fragment_1, 3982 dpf, 3983 oid, 3984 expected_data_snd_payload_fragment_1, 3985 ); 3986 let ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 3987 session_token, 3988 credit_availability: CreditAvailability::CreditAvailable, 3989 }); 3990 hal.expected_send_packet(data_packet_snd_fragment_1, ntfs, Ok(())); 3991 3992 // Expected data packet fragment #2 (UCI Header + Remaining App data bytes). 3993 let data_packet_snd_fragment_2 = build_uci_packet( 3994 mt_data, 3995 pbf_fragment_2, 3996 dpf, 3997 oid, 3998 expected_data_snd_payload_fragment_2, 3999 ); 4000 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 4001 session_token, 4002 credit_availability: CreditAvailability::CreditAvailable, 4003 }); 4004 ntfs.append(&mut into_uci_hal_packets( 4005 uwb_uci_packets::DataTransferStatusNtfBuilder { 4006 session_token, 4007 uci_sequence_number, 4008 status, 4009 tx_count, 4010 }, 4011 )); 4012 hal.expected_send_packet(data_packet_snd_fragment_2, ntfs, Ok(())); 4013 }, 4014 UciLoggerMode::Disabled, 4015 mpsc::unbounded_channel::<UciLogEvent>().0, 4016 session_id, 4017 session_token, 4018 ) 4019 .await; 4020 4021 let result = uci_manager 4022 .send_data_packet(session_id, dest_mac_address, uci_sequence_number, app_data) 4023 .await; 4024 assert!(result.is_ok()); 4025 assert!(mock_hal.wait_expected_calls_done().await); 4026 } 4027 run_test_data_packet_send_fragmented_packet_uwbs_max_data_payload_size( uci_version: u16, uwbs_caps_info_tlv: CapTlv, )4028 async fn run_test_data_packet_send_fragmented_packet_uwbs_max_data_payload_size( 4029 uci_version: u16, 4030 uwbs_caps_info_tlv: CapTlv, 4031 ) { 4032 let status = StatusCode::UciStatusOk; 4033 let mac_version = 0; 4034 let phy_version = 0; 4035 let uci_test_version = 0; 4036 let vendor_spec_info = vec![0x1, 0x2]; 4037 let uwbs_device_info_rsp = GetDeviceInfoResponse { 4038 status, 4039 uci_version, 4040 mac_version, 4041 phy_version, 4042 uci_test_version, 4043 vendor_spec_info: vendor_spec_info.clone(), 4044 }; 4045 4046 let uwbs_caps_info_tlv_clone = uwbs_caps_info_tlv.clone(); 4047 4048 // Test Data packet send for a set of data packet fragments (on a UWB session). 4049 let mt_data = 0x0; 4050 let pbf_fragment_1 = 0x1; 4051 let pbf_fragment_2 = 0x0; 4052 let dpf = 0x1; 4053 let oid = 0x0; 4054 let session_id = 0x5; 4055 let session_token = 0x5; 4056 let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1]; 4057 let uci_sequence_number: u16 = 0xa; 4058 let max_data_packet_payload_size = 275; 4059 let app_data_len = 300; // > max_data_packet_payload_size, so fragmentation occurs. 4060 let mut app_data = Vec::new(); 4061 let mut expected_data_snd_payload_fragment_1 = vec![ 4062 0x05, 0x00, 0x00, 0x00, // SessionID 4063 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 4064 0x0a, 0x00, // UciSequenceNumber 4065 0x2c, 0x01, // AppDataLen = 300 4066 ]; 4067 let mut expected_data_snd_payload_fragment_2 = Vec::new(); 4068 let data_status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk; 4069 let tx_count = 0x00; 4070 4071 // Setup the app data for both the Tx data packet and expected packet fragments. 4072 let app_data_len_fragment_1 = 4073 max_data_packet_payload_size - expected_data_snd_payload_fragment_1.len(); 4074 for i in 0..app_data_len { 4075 app_data.push((i & 0xff).try_into().unwrap()); 4076 if i < app_data_len_fragment_1 { 4077 expected_data_snd_payload_fragment_1.push((i & 0xff).try_into().unwrap()); 4078 } else { 4079 expected_data_snd_payload_fragment_2.push((i & 0xff).try_into().unwrap()); 4080 } 4081 } 4082 4083 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active_nop_logger( 4084 |mut hal| async move { 4085 // Expected UCI CMD CORE_GET_DEVICE_INFO 4086 let cmd = UciCommand::CoreGetDeviceInfo; 4087 let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder { 4088 status, 4089 uci_version, 4090 mac_version, 4091 phy_version, 4092 uci_test_version, 4093 vendor_spec_info, 4094 }); 4095 hal.expected_send_command(cmd, resp, Ok(())); 4096 4097 // Expected UCI CMD CORE_GET_CAPS_INFO 4098 let cmd = UciCommand::CoreGetCapsInfo; 4099 let resp = into_uci_hal_packets(uwb_uci_packets::GetCapsInfoRspBuilder { 4100 status: uwb_uci_packets::StatusCode::UciStatusOk, 4101 tlvs: vec![uwbs_caps_info_tlv_clone], 4102 }); 4103 hal.expected_send_command(cmd, resp, Ok(())); 4104 4105 // Expected data packet fragment #1 (UCI Header + Initial App data bytes). 4106 let data_packet_snd_fragment_1 = build_uci_packet( 4107 mt_data, 4108 pbf_fragment_1, 4109 dpf, 4110 oid, 4111 expected_data_snd_payload_fragment_1, 4112 ); 4113 let ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 4114 session_token, 4115 credit_availability: CreditAvailability::CreditAvailable, 4116 }); 4117 hal.expected_send_packet(data_packet_snd_fragment_1, ntfs, Ok(())); 4118 4119 // Expected data packet fragment #2 (UCI Header + Remaining App data bytes). 4120 let data_packet_snd_fragment_2 = build_uci_packet( 4121 mt_data, 4122 pbf_fragment_2, 4123 dpf, 4124 oid, 4125 expected_data_snd_payload_fragment_2, 4126 ); 4127 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 4128 session_token, 4129 credit_availability: CreditAvailability::CreditAvailable, 4130 }); 4131 ntfs.append(&mut into_uci_hal_packets( 4132 uwb_uci_packets::DataTransferStatusNtfBuilder { 4133 session_token, 4134 uci_sequence_number, 4135 status: data_status, 4136 tx_count, 4137 }, 4138 )); 4139 hal.expected_send_packet(data_packet_snd_fragment_2, ntfs, Ok(())); 4140 }, 4141 UciLoggerMode::Disabled, 4142 session_id, 4143 session_token, 4144 ) 4145 .await; 4146 4147 // First send the UCI CMD CORE_GET_DEVICE_INFO, so the UWBS returns it's UCI version. 4148 let result = uci_manager.core_get_device_info().await.unwrap(); 4149 assert_eq!(result, uwbs_device_info_rsp); 4150 4151 // Next send the UCI CMD CORE_GET_CAPS_INFO, so the UWBS returns it's capabilities. 4152 let result = uci_manager.core_get_caps_info().await.unwrap(); 4153 assert_eq!(result[0], uwbs_caps_info_tlv); 4154 4155 let result = uci_manager 4156 .send_data_packet(session_id, dest_mac_address, uci_sequence_number, app_data) 4157 .await; 4158 assert!(result.is_ok()); 4159 assert!(mock_hal.wait_expected_calls_done().await); 4160 } 4161 4162 // Test the Host sending a DATA packet to UWBS that needs to be fragmented, where the 4163 // fragment size is based on the UWBS MAX_DATA_PACKET_PAYLOAD_SIZE capability value. 4164 #[tokio::test] test_data_packet_send_fragmented_packet_ok_fira_v1_uwbs_max_data_payload_size()4165 async fn test_data_packet_send_fragmented_packet_ok_fira_v1_uwbs_max_data_payload_size() { 4166 let uci_version = 0x1001; 4167 let uwbs_caps_info_tlv = CapTlv { 4168 t: CapTlvType::SupportedV1MaxDataPacketPayloadSizeV2AoaSupport, 4169 v: vec![0x13, 0x01], 4170 }; 4171 4172 run_test_data_packet_send_fragmented_packet_uwbs_max_data_payload_size( 4173 uci_version, 4174 uwbs_caps_info_tlv, 4175 ) 4176 .await; 4177 } 4178 4179 // Test the Host sending a DATA packet to UWBS that needs to be fragmented, where the 4180 // fragment size is based on the UWBS MAX_DATA_PACKET_PAYLOAD_SIZE capability value. 4181 #[tokio::test] test_data_packet_send_fragmented_packet_ok_fira_v2_uwbs_max_data_payload_size()4182 async fn test_data_packet_send_fragmented_packet_ok_fira_v2_uwbs_max_data_payload_size() { 4183 let uci_version = 0x2002; // UCI version: Fira 2.x 4184 let uwbs_caps_info_tlv = CapTlv { 4185 t: CapTlvType::SupportedV1FiraMacVersionRangeV2MaxDataPayloadSize, 4186 v: vec![0x13, 0x01], 4187 }; 4188 4189 run_test_data_packet_send_fragmented_packet_uwbs_max_data_payload_size( 4190 uci_version, 4191 uwbs_caps_info_tlv, 4192 ) 4193 .await; 4194 } 4195 4196 #[tokio::test] test_data_packet_send_retry_ok()4197 async fn test_data_packet_send_retry_ok() { 4198 // Test Data packet send for a single packet (on a UWB session). 4199 let mt_data = 0x0; 4200 let pbf = 0x0; 4201 let dpf = 0x1; 4202 let oid = 0x0; 4203 let session_id = 0x5; 4204 let session_token = 0x5; 4205 let tx_count = 0x01; 4206 let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1]; 4207 let uci_sequence_number: u16 = 0xa; 4208 let app_data = vec![0x01, 0x02, 0x03]; 4209 let expected_data_snd_payload = vec![ 4210 0x05, 0x00, 0x00, 0x00, // SessionID 4211 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 4212 0x0a, 0x00, // UciSequenceNumber 4213 0x03, 0x00, // AppDataLen 4214 0x01, 0x02, 0x03, // AppData 4215 ]; 4216 let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk; 4217 4218 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 4219 |mut hal| async move { 4220 // Setup receiving a CORE_GENERIC_ERROR_NTF with STATUS_COMMAND_RETRY after a 4221 // failed Data packet send attempt. 4222 let data_packet_snd = 4223 build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload); 4224 let error_ntf = into_uci_hal_packets(uwb_uci_packets::GenericErrorBuilder { 4225 status: StatusCode::UciStatusCommandRetry, 4226 }); 4227 hal.expected_send_packet(data_packet_snd.clone(), error_ntf, Ok(())); 4228 4229 // Setup the notifications that should be received after the Data packet send 4230 // is successfully retried. 4231 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 4232 session_token, 4233 credit_availability: CreditAvailability::CreditAvailable, 4234 }); 4235 ntfs.append(&mut into_uci_hal_packets( 4236 uwb_uci_packets::DataTransferStatusNtfBuilder { 4237 session_token, 4238 uci_sequence_number, 4239 status, 4240 tx_count, 4241 }, 4242 )); 4243 hal.expected_send_packet(data_packet_snd, ntfs, Ok(())); 4244 }, 4245 UciLoggerMode::Disabled, 4246 mpsc::unbounded_channel::<UciLogEvent>().0, 4247 session_id, 4248 session_token, 4249 ) 4250 .await; 4251 4252 let result = uci_manager 4253 .send_data_packet(session_id, dest_mac_address, uci_sequence_number, app_data) 4254 .await; 4255 assert!(result.is_ok()); 4256 assert!(mock_hal.wait_expected_calls_done().await); 4257 4258 // TODO(b/276320369): Verify that session_notf_sender is called (once implemented), as a 4259 // DataTransferStatusNtf is received in this test scenario. 4260 } 4261 4262 // TODO(b/276320369): Listing down the Data Packet Tx scenarios below, will add unit tests 4263 // for them in subsequent CLs. 4264 4265 // Sending one data packet should succeed, when no DataCreditNtf is received. 4266 #[tokio::test] test_data_packet_send_missing_data_credit_ntf_success()4267 async fn test_data_packet_send_missing_data_credit_ntf_success() {} 4268 4269 // Sending the second data packet should fail, when no DataCreditNtf is received after 4270 // sending the first data packet. 4271 #[tokio::test] test_data_packet_send_missing_data_credit_ntf_subsequent_send_failure()4272 async fn test_data_packet_send_missing_data_credit_ntf_subsequent_send_failure() {} 4273 4274 #[tokio::test] test_data_packet_send_data_credit_ntf_bad_session_id()4275 async fn test_data_packet_send_data_credit_ntf_bad_session_id() {} 4276 4277 #[tokio::test] test_data_packet_send_data_credit_ntf_no_credit_available()4278 async fn test_data_packet_send_data_credit_ntf_no_credit_available() {} 4279 4280 #[tokio::test] test_data_packet_send_missing_data_transfer_status_ntf()4281 async fn test_data_packet_send_missing_data_transfer_status_ntf() {} 4282 4283 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_bad_session_id()4284 async fn test_data_packet_send_data_transfer_status_ntf_bad_session_id() {} 4285 4286 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_bad_uci_sequence_number()4287 async fn test_data_packet_send_data_transfer_status_ntf_bad_uci_sequence_number() {} 4288 4289 // Tests for the multiple Status values that indicate success 4290 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_status_ok()4291 async fn test_data_packet_send_data_transfer_status_ntf_status_ok() {} 4292 4293 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_status_repetition_ok()4294 async fn test_data_packet_send_data_transfer_status_ntf_status_repetition_ok() {} 4295 4296 // Tests for some of the multiple Status values that indicate error. 4297 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_status_error()4298 async fn test_data_packet_send_data_transfer_status_ntf_status_error() {} 4299 4300 #[tokio::test] test_session_get_count_retry_no_response()4301 async fn test_session_get_count_retry_no_response() { 4302 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 4303 |mut hal| async move { 4304 let cmd = UciCommand::SessionGetCount; 4305 hal.expected_send_command(cmd, vec![], Ok(())); 4306 }, 4307 UciLoggerMode::Disabled, 4308 mpsc::unbounded_channel::<UciLogEvent>().0, 4309 ) 4310 .await; 4311 4312 let result = uci_manager.session_get_count().await; 4313 assert!(matches!(result, Err(Error::Timeout))); 4314 assert!(mock_hal.wait_expected_calls_done().await); 4315 } 4316 4317 #[tokio::test] test_session_get_count_timeout()4318 async fn test_session_get_count_timeout() { 4319 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 4320 |mut hal| async move { 4321 let cmd = UciCommand::SessionGetCount; 4322 hal.expected_send_command(cmd, vec![], Err(Error::Timeout)); 4323 }, 4324 UciLoggerMode::Disabled, 4325 mpsc::unbounded_channel::<UciLogEvent>().0, 4326 ) 4327 .await; 4328 4329 let result = uci_manager.session_get_count().await; 4330 assert!(matches!(result, Err(Error::Timeout))); 4331 assert!(mock_hal.wait_expected_calls_done().await); 4332 } 4333 4334 #[tokio::test] test_session_get_count_retry_too_many_times()4335 async fn test_session_get_count_retry_too_many_times() { 4336 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 4337 |mut hal| async move { 4338 let cmd = UciCommand::SessionGetCount; 4339 let retry_resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 4340 status: uwb_uci_packets::StatusCode::UciStatusCommandRetry, 4341 session_count: 0, 4342 }); 4343 4344 for _ in 0..MAX_RETRY_COUNT { 4345 hal.expected_send_command(cmd.clone(), retry_resp.clone(), Ok(())); 4346 } 4347 }, 4348 UciLoggerMode::Disabled, 4349 mpsc::unbounded_channel::<UciLogEvent>().0, 4350 ) 4351 .await; 4352 4353 let result = uci_manager.session_get_count().await; 4354 assert!(matches!(result, Err(Error::Timeout))); 4355 assert!(mock_hal.wait_expected_calls_done().await); 4356 } 4357 4358 #[tokio::test] test_session_get_count_retry_notification()4359 async fn test_session_get_count_retry_notification() { 4360 let session_count = 5; 4361 4362 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 4363 |mut hal| async move { 4364 let cmd = UciCommand::SessionGetCount; 4365 let retry_resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 4366 status: uwb_uci_packets::StatusCode::UciStatusCommandRetry, 4367 session_count: 0, 4368 }); 4369 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 4370 status: uwb_uci_packets::StatusCode::UciStatusOk, 4371 session_count, 4372 }); 4373 4374 hal.expected_send_command(cmd.clone(), retry_resp.clone(), Ok(())); 4375 hal.expected_send_command(cmd.clone(), retry_resp, Ok(())); 4376 hal.expected_send_command(cmd, resp, Ok(())); 4377 }, 4378 UciLoggerMode::Disabled, 4379 mpsc::unbounded_channel::<UciLogEvent>().0, 4380 ) 4381 .await; 4382 4383 let result = uci_manager.session_get_count().await.unwrap(); 4384 assert_eq!(result, session_count); 4385 assert!(mock_hal.wait_expected_calls_done().await); 4386 } 4387 4388 #[tokio::test] test_log_manager_interaction()4389 async fn test_log_manager_interaction() { 4390 let (log_sender, mut log_receiver) = mpsc::unbounded_channel::<UciLogEvent>(); 4391 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 4392 |mut hal| async move { 4393 let cmd = UciCommand::SessionGetCount; 4394 let resp1 = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 4395 status: uwb_uci_packets::StatusCode::UciStatusOk, 4396 session_count: 1, 4397 }); 4398 let resp2 = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 4399 status: uwb_uci_packets::StatusCode::UciStatusOk, 4400 session_count: 2, 4401 }); 4402 hal.expected_send_command(cmd.clone(), resp1, Ok(())); 4403 hal.expected_send_command(cmd, resp2, Ok(())); 4404 }, 4405 UciLoggerMode::Disabled, 4406 log_sender, 4407 ) 4408 .await; 4409 4410 // Under Disabled mode, initialization and first command and response are not logged. 4411 uci_manager.session_get_count().await.unwrap(); 4412 assert!(log_receiver.try_recv().is_err()); 4413 4414 // Second command and response after change in logger mode are logged. 4415 uci_manager.set_logger_mode(UciLoggerMode::Filtered).await.unwrap(); 4416 uci_manager.session_get_count().await.unwrap(); 4417 let packet: Vec<u8> = log_receiver.recv().await.unwrap().try_into().unwrap(); 4418 let cmd_packet: Vec<u8> = SessionGetCountCmdBuilder {}.build().encode_to_vec().unwrap(); 4419 assert_eq!(&packet, &cmd_packet); 4420 let packet: Vec<u8> = log_receiver.recv().await.unwrap().try_into().unwrap(); 4421 let rsp_packet: Vec<u8> = 4422 SessionGetCountRspBuilder { status: StatusCode::UciStatusOk, session_count: 2 } 4423 .build() 4424 .encode_to_vec() 4425 .unwrap(); 4426 assert_eq!(&packet, &rsp_packet); 4427 4428 assert!(mock_hal.wait_expected_calls_done().await); 4429 } 4430 4431 #[tokio::test] test_session_set_rf_config_ok()4432 async fn test_session_set_rf_config_ok() { 4433 let session_id = 0x123; 4434 let session_token = 0x123; 4435 let config_tlv = 4436 RfTestConfigTlv { cfg_id: RfTestConfigTlvType::NumPackets, v: vec![0x12, 0x34, 0x56] }; 4437 let config_tlv_clone = config_tlv.clone(); 4438 4439 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 4440 |mut hal| async move { 4441 let cmd = UciCommand::SessionSetRfTestConfig { 4442 session_token, 4443 config_tlvs: vec![config_tlv_clone], 4444 }; 4445 let resp = 4446 into_uci_hal_packets(uwb_uci_packets::SessionSetRfTestConfigRspBuilder { 4447 status: uwb_uci_packets::StatusCode::UciStatusOk, 4448 cfg_status: vec![], 4449 }); 4450 4451 hal.expected_send_command(cmd, resp, Ok(())); 4452 }, 4453 UciLoggerMode::Disabled, 4454 mpsc::unbounded_channel::<UciLogEvent>().0, 4455 session_id, 4456 session_token, 4457 ) 4458 .await; 4459 4460 let expected_result = 4461 RfTestConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; 4462 let result = 4463 uci_manager.session_set_rf_test_config(session_id, vec![config_tlv]).await.unwrap(); 4464 assert_eq!(result, expected_result); 4465 assert!(mock_hal.wait_expected_calls_done().await); 4466 } 4467 } 4468