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