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