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 tokio::sync::{mpsc, oneshot, Mutex}; 22 23 use crate::uci::command::UciCommand; 24 //use crate::uci::error::{Error, Result}; 25 use crate::error::{Error, Result}; 26 use crate::params::uci_packets::{ 27 AppConfigTlv, AppConfigTlvType, CapTlv, Controlees, CoreSetConfigResponse, CountryCode, 28 CreditAvailability, DeviceConfigId, DeviceConfigTlv, DeviceState, FiraComponent, 29 GetDeviceInfoResponse, GroupId, MessageType, PowerStats, RawUciMessage, ResetConfig, SessionId, 30 SessionState, SessionToken, SessionType, SessionUpdateDtTagRangingRoundsResponse, 31 SetAppConfigResponse, UciDataPacket, UciDataPacketHal, UpdateMulticastListAction, 32 }; 33 use crate::params::utils::bytes_to_u64; 34 use crate::uci::message::UciMessage; 35 use crate::uci::notification::{ 36 CoreNotification, DataRcvNotification, SessionNotification, SessionRangeData, UciNotification, 37 }; 38 use crate::uci::response::UciResponse; 39 use crate::uci::timeout_uci_hal::TimeoutUciHal; 40 use crate::uci::uci_hal::{UciHal, UciHalPacket}; 41 use crate::uci::uci_logger::{UciLogger, UciLoggerMode, UciLoggerWrapper}; 42 use crate::utils::{clean_mpsc_receiver, PinSleep}; 43 use std::collections::{HashMap, VecDeque}; 44 use uwb_uci_packets::{Packet, RawUciControlPacket, UciDataSnd, UciDefragPacket}; 45 46 const UCI_TIMEOUT_MS: u64 = 800; 47 const MAX_RETRY_COUNT: usize = 3; 48 49 /// The UciManager organizes the state machine of the UWB HAL, and provides the interface which 50 /// abstracts the UCI commands, responses, and notifications. 51 #[async_trait] 52 pub trait UciManager: 'static + Send + Sync + Clone { set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>53 async fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>; 54 // Set the sendor of the UCI notificaions. set_core_notification_sender( &mut self, core_notf_sender: mpsc::UnboundedSender<CoreNotification>, )55 async fn set_core_notification_sender( 56 &mut self, 57 core_notf_sender: mpsc::UnboundedSender<CoreNotification>, 58 ); set_session_notification_sender( &mut self, session_notf_sender: mpsc::UnboundedSender<SessionNotification>, )59 async fn set_session_notification_sender( 60 &mut self, 61 session_notf_sender: mpsc::UnboundedSender<SessionNotification>, 62 ); set_vendor_notification_sender( &mut self, vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, )63 async fn set_vendor_notification_sender( 64 &mut self, 65 vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, 66 ); set_data_rcv_notification_sender( &mut self, data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, )67 async fn set_data_rcv_notification_sender( 68 &mut self, 69 data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, 70 ); 71 72 // Open the UCI HAL. 73 // All the UCI commands should be called after the open_hal() completes successfully. open_hal(&self) -> Result<()>74 async fn open_hal(&self) -> Result<()>; 75 76 // Close the UCI HAL. close_hal(&self, force: bool) -> Result<()>77 async fn close_hal(&self, force: bool) -> Result<()>; 78 79 // Send the standard UCI Commands. device_reset(&self, reset_config: ResetConfig) -> Result<()>80 async fn device_reset(&self, reset_config: ResetConfig) -> Result<()>; core_get_device_info(&self) -> Result<GetDeviceInfoResponse>81 async fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse>; core_get_caps_info(&self) -> Result<Vec<CapTlv>>82 async fn core_get_caps_info(&self) -> Result<Vec<CapTlv>>; core_set_config( &self, config_tlvs: Vec<DeviceConfigTlv>, ) -> Result<CoreSetConfigResponse>83 async fn core_set_config( 84 &self, 85 config_tlvs: Vec<DeviceConfigTlv>, 86 ) -> Result<CoreSetConfigResponse>; core_get_config( &self, config_ids: Vec<DeviceConfigId>, ) -> Result<Vec<DeviceConfigTlv>>87 async fn core_get_config( 88 &self, 89 config_ids: Vec<DeviceConfigId>, 90 ) -> Result<Vec<DeviceConfigTlv>>; session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>91 async fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>; session_deinit(&self, session_id: SessionId) -> Result<()>92 async fn session_deinit(&self, session_id: SessionId) -> Result<()>; session_set_app_config( &self, session_id: SessionId, config_tlvs: Vec<AppConfigTlv>, ) -> Result<SetAppConfigResponse>93 async fn session_set_app_config( 94 &self, 95 session_id: SessionId, 96 config_tlvs: Vec<AppConfigTlv>, 97 ) -> Result<SetAppConfigResponse>; session_get_app_config( &self, session_id: SessionId, config_ids: Vec<AppConfigTlvType>, ) -> Result<Vec<AppConfigTlv>>98 async fn session_get_app_config( 99 &self, 100 session_id: SessionId, 101 config_ids: Vec<AppConfigTlvType>, 102 ) -> Result<Vec<AppConfigTlv>>; session_get_count(&self) -> Result<u8>103 async fn session_get_count(&self) -> Result<u8>; session_get_state(&self, session_id: SessionId) -> Result<SessionState>104 async fn session_get_state(&self, session_id: SessionId) -> Result<SessionState>; session_update_controller_multicast_list( &self, session_id: SessionId, action: UpdateMulticastListAction, controlees: Controlees, ) -> Result<()>105 async fn session_update_controller_multicast_list( 106 &self, 107 session_id: SessionId, 108 action: UpdateMulticastListAction, 109 controlees: Controlees, 110 ) -> Result<()>; 111 112 // Update ranging rounds for DT Tag session_update_dt_tag_ranging_rounds( &self, session_id: u32, ranging_round_indexes: Vec<u8>, ) -> Result<SessionUpdateDtTagRangingRoundsResponse>113 async fn session_update_dt_tag_ranging_rounds( 114 &self, 115 session_id: u32, 116 ranging_round_indexes: Vec<u8>, 117 ) -> Result<SessionUpdateDtTagRangingRoundsResponse>; 118 session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>119 async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>; 120 range_start(&self, session_id: SessionId) -> Result<()>121 async fn range_start(&self, session_id: SessionId) -> Result<()>; range_stop(&self, session_id: SessionId) -> Result<()>122 async fn range_stop(&self, session_id: SessionId) -> Result<()>; range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>123 async fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>; 124 125 // Send the Android-specific UCI commands android_set_country_code(&self, country_code: CountryCode) -> Result<()>126 async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()>; android_get_power_stats(&self) -> Result<PowerStats>127 async fn android_get_power_stats(&self) -> Result<PowerStats>; 128 129 // Send a raw uci command. raw_uci_cmd( &self, mt: u32, gid: u32, oid: u32, payload: Vec<u8>, ) -> Result<RawUciMessage>130 async fn raw_uci_cmd( 131 &self, 132 mt: u32, 133 gid: u32, 134 oid: u32, 135 payload: Vec<u8>, 136 ) -> Result<RawUciMessage>; 137 138 // Send a Data packet. send_data_packet( &self, session_id: SessionId, address: Vec<u8>, dest_end_point: FiraComponent, uci_sequence_number: u8, app_payload_data: Vec<u8>, ) -> Result<()>139 async fn send_data_packet( 140 &self, 141 session_id: SessionId, 142 address: Vec<u8>, 143 dest_end_point: FiraComponent, 144 uci_sequence_number: u8, 145 app_payload_data: Vec<u8>, 146 ) -> Result<()>; 147 148 // Get Session token from session id get_session_token_from_session_id( &self, session_id: SessionId, ) -> Result<SessionToken>149 async fn get_session_token_from_session_id( 150 &self, 151 session_id: SessionId, 152 ) -> Result<SessionToken>; 153 } 154 155 /// UciManagerImpl is the main implementation of UciManager. Using the actor model, UciManagerImpl 156 /// delegates the requests to UciManagerActor. 157 #[derive(Clone)] 158 pub struct UciManagerImpl { 159 cmd_sender: mpsc::UnboundedSender<(UciManagerCmd, oneshot::Sender<Result<UciResponse>>)>, 160 161 // FIRA version 2 introduces a UWBS generated session handle to use as identifier for all 162 // session related commands. This map stores the app provided session id to UWBS generated 163 // session handle mapping if provided, else reuses session id. 164 session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>, 165 } 166 167 impl UciManagerImpl { 168 /// Constructor. Need to be called in an async context. new<T: UciHal, U: UciLogger>( hal: T, logger: U, logger_mode: UciLoggerMode, ) -> Self169 pub(crate) fn new<T: UciHal, U: UciLogger>( 170 hal: T, 171 logger: U, 172 logger_mode: UciLoggerMode, 173 ) -> Self { 174 let (cmd_sender, cmd_receiver) = mpsc::unbounded_channel(); 175 let session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>> = 176 Arc::new(Mutex::new(HashMap::new())); 177 let mut actor = UciManagerActor::new( 178 hal, 179 logger, 180 logger_mode, 181 cmd_receiver, 182 session_id_to_token_map.clone(), 183 ); 184 tokio::spawn(async move { actor.run().await }); 185 186 Self { cmd_sender, session_id_to_token_map } 187 } 188 189 // Send the |cmd| to the UciManagerActor. send_cmd(&self, cmd: UciManagerCmd) -> Result<UciResponse>190 async fn send_cmd(&self, cmd: UciManagerCmd) -> Result<UciResponse> { 191 let (result_sender, result_receiver) = oneshot::channel(); 192 match self.cmd_sender.send((cmd, result_sender)) { 193 Ok(()) => result_receiver.await.unwrap_or(Err(Error::Unknown)), 194 Err(cmd) => { 195 error!("Failed to send cmd: {:?}", cmd.0); 196 Err(Error::Unknown) 197 } 198 } 199 } 200 get_session_token(&self, session_id: &SessionId) -> Result<SessionToken>201 async fn get_session_token(&self, session_id: &SessionId) -> Result<SessionToken> { 202 self.session_id_to_token_map 203 .lock() 204 .await 205 .get(session_id) 206 .ok_or(Error::BadParameters) 207 .copied() 208 } 209 } 210 211 #[async_trait] 212 impl UciManager for UciManagerImpl { set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>213 async fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()> { 214 match self.send_cmd(UciManagerCmd::SetLoggerMode { logger_mode }).await { 215 Ok(UciResponse::SetLoggerMode) => Ok(()), 216 Ok(_) => Err(Error::Unknown), 217 Err(e) => Err(e), 218 } 219 } set_core_notification_sender( &mut self, core_notf_sender: mpsc::UnboundedSender<CoreNotification>, )220 async fn set_core_notification_sender( 221 &mut self, 222 core_notf_sender: mpsc::UnboundedSender<CoreNotification>, 223 ) { 224 let _ = self.send_cmd(UciManagerCmd::SetCoreNotificationSender { core_notf_sender }).await; 225 } set_session_notification_sender( &mut self, session_notf_sender: mpsc::UnboundedSender<SessionNotification>, )226 async fn set_session_notification_sender( 227 &mut self, 228 session_notf_sender: mpsc::UnboundedSender<SessionNotification>, 229 ) { 230 let _ = self 231 .send_cmd(UciManagerCmd::SetSessionNotificationSender { session_notf_sender }) 232 .await; 233 } set_vendor_notification_sender( &mut self, vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, )234 async fn set_vendor_notification_sender( 235 &mut self, 236 vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, 237 ) { 238 let _ = 239 self.send_cmd(UciManagerCmd::SetVendorNotificationSender { vendor_notf_sender }).await; 240 } set_data_rcv_notification_sender( &mut self, data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, )241 async fn set_data_rcv_notification_sender( 242 &mut self, 243 data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, 244 ) { 245 let _ = self 246 .send_cmd(UciManagerCmd::SetDataRcvNotificationSender { data_rcv_notf_sender }) 247 .await; 248 } 249 open_hal(&self) -> Result<()>250 async fn open_hal(&self) -> Result<()> { 251 match self.send_cmd(UciManagerCmd::OpenHal).await { 252 Ok(UciResponse::OpenHal) => { 253 // According to the UCI spec: "The Host shall send CORE_GET_DEVICE_INFO_CMD to 254 // retrieve the device information.", we call get_device_info() after successfully 255 // opening the HAL. 256 let device_info = self.core_get_device_info().await; 257 debug!("UCI device info: {:?}", device_info); 258 259 Ok(()) 260 } 261 Ok(_) => Err(Error::Unknown), 262 Err(e) => Err(e), 263 } 264 } 265 close_hal(&self, force: bool) -> Result<()>266 async fn close_hal(&self, force: bool) -> Result<()> { 267 match self.send_cmd(UciManagerCmd::CloseHal { force }).await { 268 Ok(UciResponse::CloseHal) => Ok(()), 269 Ok(_) => Err(Error::Unknown), 270 Err(e) => Err(e), 271 } 272 } 273 device_reset(&self, reset_config: ResetConfig) -> Result<()>274 async fn device_reset(&self, reset_config: ResetConfig) -> Result<()> { 275 let cmd = UciCommand::DeviceReset { reset_config }; 276 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 277 Ok(UciResponse::DeviceReset(resp)) => resp, 278 Ok(_) => Err(Error::Unknown), 279 Err(e) => Err(e), 280 } 281 } 282 core_get_device_info(&self) -> Result<GetDeviceInfoResponse>283 async fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse> { 284 let cmd = UciCommand::CoreGetDeviceInfo; 285 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 286 Ok(UciResponse::CoreGetDeviceInfo(resp)) => resp, 287 Ok(_) => Err(Error::Unknown), 288 Err(e) => Err(e), 289 } 290 } 291 core_get_caps_info(&self) -> Result<Vec<CapTlv>>292 async fn core_get_caps_info(&self) -> Result<Vec<CapTlv>> { 293 let cmd = UciCommand::CoreGetCapsInfo; 294 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 295 Ok(UciResponse::CoreGetCapsInfo(resp)) => resp, 296 Ok(_) => Err(Error::Unknown), 297 Err(e) => Err(e), 298 } 299 } 300 core_set_config( &self, config_tlvs: Vec<DeviceConfigTlv>, ) -> Result<CoreSetConfigResponse>301 async fn core_set_config( 302 &self, 303 config_tlvs: Vec<DeviceConfigTlv>, 304 ) -> Result<CoreSetConfigResponse> { 305 let cmd = UciCommand::CoreSetConfig { config_tlvs }; 306 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 307 Ok(UciResponse::CoreSetConfig(resp)) => Ok(resp), 308 Ok(_) => Err(Error::Unknown), 309 Err(e) => Err(e), 310 } 311 } 312 core_get_config(&self, cfg_id: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>>313 async fn core_get_config(&self, cfg_id: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>> { 314 let cmd = UciCommand::CoreGetConfig { cfg_id }; 315 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 316 Ok(UciResponse::CoreGetConfig(resp)) => resp, 317 Ok(_) => Err(Error::Unknown), 318 Err(e) => Err(e), 319 } 320 } 321 session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>322 async fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()> { 323 let cmd = UciCommand::SessionInit { session_id, session_type }; 324 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 325 Ok(UciResponse::SessionInit(resp)) => resp.map(|_| {}), 326 Ok(_) => Err(Error::Unknown), 327 Err(e) => Err(e), 328 } 329 } 330 session_deinit(&self, session_id: SessionId) -> Result<()>331 async fn session_deinit(&self, session_id: SessionId) -> Result<()> { 332 let cmd = 333 UciCommand::SessionDeinit { session_token: self.get_session_token(&session_id).await? }; 334 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 335 Ok(UciResponse::SessionDeinit(resp)) => resp, 336 Ok(_) => Err(Error::Unknown), 337 Err(e) => Err(e), 338 } 339 } 340 session_set_app_config( &self, session_id: SessionId, config_tlvs: Vec<AppConfigTlv>, ) -> Result<SetAppConfigResponse>341 async fn session_set_app_config( 342 &self, 343 session_id: SessionId, 344 config_tlvs: Vec<AppConfigTlv>, 345 ) -> Result<SetAppConfigResponse> { 346 let cmd = UciCommand::SessionSetAppConfig { 347 session_token: self.get_session_token(&session_id).await?, 348 config_tlvs, 349 }; 350 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 351 Ok(UciResponse::SessionSetAppConfig(resp)) => Ok(resp), 352 Ok(_) => Err(Error::Unknown), 353 Err(e) => Err(e), 354 } 355 } 356 session_get_app_config( &self, session_id: SessionId, app_cfg: Vec<AppConfigTlvType>, ) -> Result<Vec<AppConfigTlv>>357 async fn session_get_app_config( 358 &self, 359 session_id: SessionId, 360 app_cfg: Vec<AppConfigTlvType>, 361 ) -> Result<Vec<AppConfigTlv>> { 362 let cmd = UciCommand::SessionGetAppConfig { 363 session_token: self.get_session_token(&session_id).await?, 364 app_cfg, 365 }; 366 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 367 Ok(UciResponse::SessionGetAppConfig(resp)) => resp, 368 Ok(_) => Err(Error::Unknown), 369 Err(e) => Err(e), 370 } 371 } 372 session_get_count(&self) -> Result<u8>373 async fn session_get_count(&self) -> Result<u8> { 374 let cmd = UciCommand::SessionGetCount; 375 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 376 Ok(UciResponse::SessionGetCount(resp)) => resp, 377 Ok(_) => Err(Error::Unknown), 378 Err(e) => Err(e), 379 } 380 } 381 session_get_state(&self, session_id: SessionId) -> Result<SessionState>382 async fn session_get_state(&self, session_id: SessionId) -> Result<SessionState> { 383 let cmd = UciCommand::SessionGetState { 384 session_token: self.get_session_token(&session_id).await?, 385 }; 386 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 387 Ok(UciResponse::SessionGetState(resp)) => resp, 388 Ok(_) => Err(Error::Unknown), 389 Err(e) => Err(e), 390 } 391 } 392 session_update_controller_multicast_list( &self, session_id: SessionId, action: UpdateMulticastListAction, controlees: Controlees, ) -> Result<()>393 async fn session_update_controller_multicast_list( 394 &self, 395 session_id: SessionId, 396 action: UpdateMulticastListAction, 397 controlees: Controlees, 398 ) -> Result<()> { 399 let controlees_len = match controlees { 400 Controlees::NoSessionKey(ref controlee_vec) => controlee_vec.len(), 401 Controlees::ShortSessionKey(ref controlee_vec) => controlee_vec.len(), 402 Controlees::LongSessionKey(ref controlee_vec) => controlee_vec.len(), 403 }; 404 if !(1..=8).contains(&controlees_len) { 405 warn!("Number of controlees should be between 1 to 8"); 406 return Err(Error::BadParameters); 407 } 408 let cmd = UciCommand::SessionUpdateControllerMulticastList { 409 session_token: self.get_session_token(&session_id).await?, 410 action, 411 controlees, 412 }; 413 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 414 Ok(UciResponse::SessionUpdateControllerMulticastList(resp)) => resp, 415 Ok(_) => Err(Error::Unknown), 416 Err(e) => Err(e), 417 } 418 } 419 session_update_dt_tag_ranging_rounds( &self, session_id: u32, ranging_round_indexes: Vec<u8>, ) -> Result<SessionUpdateDtTagRangingRoundsResponse>420 async fn session_update_dt_tag_ranging_rounds( 421 &self, 422 session_id: u32, 423 ranging_round_indexes: Vec<u8>, 424 ) -> Result<SessionUpdateDtTagRangingRoundsResponse> { 425 let cmd = UciCommand::SessionUpdateDtTagRangingRounds { 426 session_token: self.get_session_token(&session_id).await?, 427 ranging_round_indexes, 428 }; 429 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 430 Ok(UciResponse::SessionUpdateDtTagRangingRounds(resp)) => resp, 431 Ok(_) => Err(Error::Unknown), 432 Err(e) => Err(e), 433 } 434 } 435 session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>436 async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16> { 437 let cmd = UciCommand::SessionQueryMaxDataSize { 438 session_token: self.get_session_token(&session_id).await?, 439 }; 440 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 441 Ok(UciResponse::SessionQueryMaxDataSize(resp)) => resp, 442 Ok(_) => Err(Error::Unknown), 443 Err(e) => Err(e), 444 } 445 } 446 range_start(&self, session_id: SessionId) -> Result<()>447 async fn range_start(&self, session_id: SessionId) -> Result<()> { 448 let cmd = 449 UciCommand::SessionStart { session_token: self.get_session_token(&session_id).await? }; 450 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 451 Ok(UciResponse::SessionStart(resp)) => resp, 452 Ok(_) => Err(Error::Unknown), 453 Err(e) => Err(e), 454 } 455 } 456 range_stop(&self, session_id: SessionId) -> Result<()>457 async fn range_stop(&self, session_id: SessionId) -> Result<()> { 458 let cmd = 459 UciCommand::SessionStop { session_token: self.get_session_token(&session_id).await? }; 460 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 461 Ok(UciResponse::SessionStop(resp)) => resp, 462 Ok(_) => Err(Error::Unknown), 463 Err(e) => Err(e), 464 } 465 } 466 range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>467 async fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize> { 468 let cmd = UciCommand::SessionGetRangingCount { 469 session_token: self.get_session_token(&session_id).await?, 470 }; 471 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 472 Ok(UciResponse::SessionGetRangingCount(resp)) => resp, 473 Ok(_) => Err(Error::Unknown), 474 Err(e) => Err(e), 475 } 476 } 477 android_set_country_code(&self, country_code: CountryCode) -> Result<()>478 async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()> { 479 let cmd = UciCommand::AndroidSetCountryCode { country_code }; 480 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 481 Ok(UciResponse::AndroidSetCountryCode(resp)) => resp, 482 Ok(_) => Err(Error::Unknown), 483 Err(e) => Err(e), 484 } 485 } 486 android_get_power_stats(&self) -> Result<PowerStats>487 async fn android_get_power_stats(&self) -> Result<PowerStats> { 488 let cmd = UciCommand::AndroidGetPowerStats; 489 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 490 Ok(UciResponse::AndroidGetPowerStats(resp)) => resp, 491 Ok(_) => Err(Error::Unknown), 492 Err(e) => Err(e), 493 } 494 } 495 raw_uci_cmd( &self, mt: u32, gid: u32, oid: u32, payload: Vec<u8>, ) -> Result<RawUciMessage>496 async fn raw_uci_cmd( 497 &self, 498 mt: u32, 499 gid: u32, 500 oid: u32, 501 payload: Vec<u8>, 502 ) -> Result<RawUciMessage> { 503 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload }; 504 match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { 505 Ok(UciResponse::RawUciCmd(resp)) => resp, 506 Ok(_) => Err(Error::Unknown), 507 Err(e) => Err(e), 508 } 509 } 510 511 // Send a data packet to the UWBS (use the UciManagerActor). send_data_packet( &self, session_id: SessionId, dest_mac_address_bytes: Vec<u8>, dest_fira_component: FiraComponent, uci_sequence_number: u8, data: Vec<u8>, ) -> Result<()>512 async fn send_data_packet( 513 &self, 514 session_id: SessionId, 515 dest_mac_address_bytes: Vec<u8>, 516 dest_fira_component: FiraComponent, 517 uci_sequence_number: u8, 518 data: Vec<u8>, 519 ) -> Result<()> { 520 debug!( 521 "send_data_packet(): will Tx a data packet, session_id {}, sequence_number {}", 522 session_id, uci_sequence_number 523 ); 524 let dest_mac_address = bytes_to_u64(dest_mac_address_bytes).ok_or(Error::BadParameters)?; 525 let data_snd_packet = uwb_uci_packets::UciDataSndBuilder { 526 session_token: self.get_session_token(&session_id).await?, 527 dest_mac_address, 528 dest_fira_component, 529 uci_sequence_number, 530 data, 531 } 532 .build(); 533 534 match self.send_cmd(UciManagerCmd::SendUciData { data_snd_packet }).await { 535 Ok(UciResponse::SendUciData(resp)) => resp, 536 Ok(_) => Err(Error::Unknown), 537 Err(e) => Err(e), 538 } 539 } 540 541 // Get session token from session id (no uci call). get_session_token_from_session_id( &self, session_id: SessionId, ) -> Result<SessionToken>542 async fn get_session_token_from_session_id( 543 &self, 544 session_id: SessionId, 545 ) -> Result<SessionToken> { 546 Ok(self.get_session_token(&session_id).await?) 547 } 548 } 549 550 struct UciManagerActor<T: UciHal, U: UciLogger> { 551 // The UCI HAL. 552 hal: TimeoutUciHal<T>, 553 // UCI Log. 554 logger: UciLoggerWrapper<U>, 555 // Receive the commands and the corresponding response senders from UciManager. 556 cmd_receiver: mpsc::UnboundedReceiver<(UciManagerCmd, oneshot::Sender<Result<UciResponse>>)>, 557 558 // Set to true when |hal| is opened successfully. 559 is_hal_opened: bool, 560 // Receive response, notification and data packets from |mut hal|. Only used when |hal| is opened 561 // successfully. 562 packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>, 563 // Defrag the UCI packets. 564 defrager: uwb_uci_packets::PacketDefrager, 565 566 // The response sender of UciManager's open_hal() method. Used to wait for the device ready 567 // notification. 568 open_hal_result_sender: Option<oneshot::Sender<Result<UciResponse>>>, 569 570 // Store per-session CreditAvailability. This should be initialized when a UWB session becomes 571 // ACTIVE, and updated every time a Data packet fragment is sent or a DataCreditNtf is received. 572 data_credit_map: HashMap<SessionToken, CreditAvailability>, 573 574 // Store the Uci Data packet fragments to be sent to the UWBS, keyed by the SessionId. This 575 // helps to retrieve the next packet fragment to be sent, when the UWBS is ready to accept it. 576 data_packet_fragments_map: HashMap<SessionToken, VecDeque<UciDataPacketHal>>, 577 578 // The timeout of waiting for the notification of device ready notification. 579 wait_device_status_timeout: PinSleep, 580 581 // Used for the logic of retrying the command. Only valid when waiting for the response of a 582 // UCI command. 583 uci_cmd_retryer: Option<UciCmdRetryer>, 584 // The timeout of waiting for the response. Only used when waiting for the response of a UCI 585 // command. 586 wait_resp_timeout: PinSleep, 587 588 // Used for the logic of retrying the DataSnd packet. Only valid when waiting for the 589 // DATA_TRANSFER_STATUS_NTF. 590 uci_data_snd_retryer: Option<UciDataSndRetryer>, 591 592 // Used to identify if response corresponds to the last vendor command, if so return 593 // a raw packet as a response to the sender. 594 last_raw_cmd: Option<RawUciControlPacket>, 595 596 // Send the notifications to the caller of UciManager. 597 core_notf_sender: mpsc::UnboundedSender<CoreNotification>, 598 session_notf_sender: mpsc::UnboundedSender<SessionNotification>, 599 vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, 600 data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, 601 602 // Used to store the last init session id to help map the session handle sent 603 // in session int response can be correctly mapped. 604 last_init_session_id: Option<SessionId>, 605 // FIRA version 2 introduces a UWBS generated session handle to use as identifier for all 606 // session related commands. This map stores the app provided session id to UWBS generated 607 // session handle mapping if provided, else reuses session id. 608 session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>, 609 } 610 611 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>>>, ) -> Self612 fn new( 613 hal: T, 614 logger: U, 615 logger_mode: UciLoggerMode, 616 cmd_receiver: mpsc::UnboundedReceiver<( 617 UciManagerCmd, 618 oneshot::Sender<Result<UciResponse>>, 619 )>, 620 session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>, 621 ) -> Self { 622 Self { 623 hal: TimeoutUciHal::new(hal), 624 logger: UciLoggerWrapper::new(logger, logger_mode), 625 cmd_receiver, 626 is_hal_opened: false, 627 packet_receiver: mpsc::unbounded_channel().1, 628 defrager: Default::default(), 629 open_hal_result_sender: None, 630 data_credit_map: HashMap::new(), 631 data_packet_fragments_map: HashMap::new(), 632 wait_device_status_timeout: PinSleep::new(Duration::MAX), 633 uci_cmd_retryer: None, 634 uci_data_snd_retryer: None, 635 wait_resp_timeout: PinSleep::new(Duration::MAX), 636 last_raw_cmd: None, 637 core_notf_sender: mpsc::unbounded_channel().0, 638 session_notf_sender: mpsc::unbounded_channel().0, 639 vendor_notf_sender: mpsc::unbounded_channel().0, 640 data_rcv_notf_sender: mpsc::unbounded_channel().0, 641 last_init_session_id: None, 642 session_id_to_token_map, 643 } 644 } 645 run(&mut self)646 async fn run(&mut self) { 647 loop { 648 tokio::select! { 649 // Handle the next command. Only when the previous command already received the 650 // response. 651 cmd = self.cmd_receiver.recv(), if !self.is_waiting_resp() => { 652 match cmd { 653 None => { 654 debug!("UciManager is about to drop."); 655 break; 656 }, 657 Some((cmd, result_sender)) => { 658 self.handle_cmd(cmd, result_sender).await; 659 } 660 } 661 } 662 663 // Handle the UCI response, notification or data packet from HAL. Only when HAL 664 // is opened. 665 packet = self.packet_receiver.recv(), if self.is_hal_opened => { 666 self.handle_hal_packet(packet).await; 667 } 668 669 // Timeout waiting for the response of the UCI command. 670 _ = &mut self.wait_resp_timeout, if self.is_waiting_resp() => { 671 if let Some(uci_cmd_retryer) = self.uci_cmd_retryer.take() { 672 uci_cmd_retryer.send_result(Err(Error::Timeout)); 673 } 674 } 675 676 // Timeout waiting for the notification of the device status. 677 _ = &mut self.wait_device_status_timeout, if self.is_waiting_device_status() => { 678 if let Some(result_sender) = self.open_hal_result_sender.take() { 679 let _ = result_sender.send(Err(Error::Timeout)); 680 } 681 } 682 } 683 } 684 685 if self.is_hal_opened { 686 debug!("The HAL is still opened when exit, close the HAL"); 687 let _ = self.hal.close().await; 688 self.on_hal_closed(); 689 } 690 } 691 insert_session_token(&self, session_id: SessionId, session_token: SessionToken)692 async fn insert_session_token(&self, session_id: SessionId, session_token: SessionToken) { 693 self.session_id_to_token_map.lock().await.insert(session_id, session_token); 694 } 695 remove_session_token(&self, session_token: &SessionToken)696 async fn remove_session_token(&self, session_token: &SessionToken) { 697 self.session_id_to_token_map.lock().await.retain(|_, val| *val != *session_token); 698 } 699 get_session_id(&self, session_token: &SessionToken) -> Result<SessionId>700 async fn get_session_id(&self, session_token: &SessionToken) -> Result<SessionId> { 701 self.session_id_to_token_map 702 .lock() 703 .await 704 .iter() 705 .find_map(|(key, &val)| if val == *session_token { Some(key) } else { None }) 706 .ok_or(Error::BadParameters) 707 .copied() 708 } 709 save_session_id_if_init_cmd(&mut self, cmd: &UciCommand)710 fn save_session_id_if_init_cmd(&mut self, cmd: &UciCommand) { 711 // Store the last init session id to help map the session handle sent 712 // in session init response. 713 if let UciCommand::SessionInit { session_id, .. } = cmd { 714 self.last_init_session_id = Some(*session_id); 715 } 716 } 717 store_session_token_if_init_resp(&mut self, resp: &UciResponse) -> Result<()>718 async fn store_session_token_if_init_resp(&mut self, resp: &UciResponse) -> Result<()> { 719 // Store the session_id to session_token mapping for this new session. 720 if let UciResponse::SessionInit(session_init_resp) = resp { 721 let session_id = match self.last_init_session_id.take() { 722 Some(session_id) => session_id, 723 None => { 724 return Err(Error::Unknown); 725 } 726 }; 727 if let Ok(opt_session_handle) = session_init_resp { 728 let session_handle = match opt_session_handle { 729 // Session Handle provided by UWBS, use as token for further commands. 730 Some(session_handle) => { 731 info!( 732 "session handle: {:?} provided for session id: {:?}", 733 session_handle, session_id 734 ); 735 *session_handle 736 } 737 // Session Handle not provided by UWBS, reuse session id as token for further commands. 738 None => session_id, 739 }; 740 self.insert_session_token(session_id, session_handle).await; 741 } 742 } 743 Ok(()) 744 } 745 handle_cmd( &mut self, cmd: UciManagerCmd, result_sender: oneshot::Sender<Result<UciResponse>>, )746 async fn handle_cmd( 747 &mut self, 748 cmd: UciManagerCmd, 749 result_sender: oneshot::Sender<Result<UciResponse>>, 750 ) { 751 debug!("Received cmd: {:?}", cmd); 752 753 match cmd { 754 UciManagerCmd::SetLoggerMode { logger_mode } => { 755 self.logger.set_logger_mode(logger_mode); 756 let _ = result_sender.send(Ok(UciResponse::SetLoggerMode)); 757 } 758 UciManagerCmd::SetCoreNotificationSender { core_notf_sender } => { 759 self.core_notf_sender = core_notf_sender; 760 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 761 } 762 UciManagerCmd::SetSessionNotificationSender { session_notf_sender } => { 763 self.session_notf_sender = session_notf_sender; 764 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 765 } 766 UciManagerCmd::SetVendorNotificationSender { vendor_notf_sender } => { 767 self.vendor_notf_sender = vendor_notf_sender; 768 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 769 } 770 UciManagerCmd::SetDataRcvNotificationSender { data_rcv_notf_sender } => { 771 self.data_rcv_notf_sender = data_rcv_notf_sender; 772 let _ = result_sender.send(Ok(UciResponse::SetNotification)); 773 } 774 UciManagerCmd::OpenHal => { 775 if self.is_hal_opened { 776 warn!("The UCI HAL is already opened, skip."); 777 let _ = result_sender.send(Err(Error::BadParameters)); 778 return; 779 } 780 781 let (packet_sender, packet_receiver) = mpsc::unbounded_channel(); 782 let result = self.hal.open(packet_sender).await; 783 self.logger.log_hal_open(&result); 784 match result { 785 Ok(()) => { 786 self.on_hal_open(packet_receiver); 787 self.wait_device_status_timeout = 788 PinSleep::new(Duration::from_millis(UCI_TIMEOUT_MS)); 789 self.open_hal_result_sender.replace(result_sender); 790 } 791 Err(e) => { 792 error!("Failed to open hal: {:?}", e); 793 let _ = result_sender.send(Err(e)); 794 } 795 } 796 } 797 798 UciManagerCmd::CloseHal { force } => { 799 if force { 800 debug!("Force closing the UCI HAL"); 801 let close_result = self.hal.close().await; 802 self.logger.log_hal_close(&close_result); 803 self.on_hal_closed(); 804 let _ = result_sender.send(Ok(UciResponse::CloseHal)); 805 } else { 806 if !self.is_hal_opened { 807 warn!("The UCI HAL is already closed, skip."); 808 let _ = result_sender.send(Err(Error::BadParameters)); 809 return; 810 } 811 812 let result = self.hal.close().await; 813 self.logger.log_hal_close(&result); 814 if result.is_ok() { 815 self.on_hal_closed(); 816 } 817 let _ = result_sender.send(result.map(|_| UciResponse::CloseHal)); 818 } 819 } 820 821 UciManagerCmd::SendUciCommand { cmd } => { 822 debug_assert!(self.uci_cmd_retryer.is_none()); 823 824 self.save_session_id_if_init_cmd(&cmd); 825 826 // Remember that this command is a raw UCI command, we'll use this later 827 // to send a raw UCI response. 828 if let UciCommand::RawUciCmd { mt: _, gid, oid, payload: _ } = cmd.clone() { 829 let gid_u8 = u8::try_from(gid); 830 if gid_u8.is_err() || GroupId::try_from(gid_u8.unwrap()).is_err() { 831 error!("Received an invalid GID={} for RawUciCmd", gid); 832 let _ = result_sender.send(Err(Error::BadParameters)); 833 return; 834 } 835 836 let oid_u8 = u8::try_from(oid); 837 if oid_u8.is_err() { 838 error!("Received an invalid OID={} for RawUciCmd", oid); 839 let _ = result_sender.send(Err(Error::BadParameters)); 840 return; 841 } 842 self.last_raw_cmd = Some(RawUciControlPacket { 843 mt: u8::from(MessageType::Command), 844 gid: gid_u8.unwrap(), // Safe as we check gid_u8.is_err() above. 845 oid: oid_u8.unwrap(), // Safe as we check uid_i8.is_err() above. 846 payload: Vec::new(), // There's no need to store the Raw UCI CMD's payload. 847 }); 848 } 849 850 self.uci_cmd_retryer = 851 Some(UciCmdRetryer { cmd, result_sender, retry_count: MAX_RETRY_COUNT }); 852 853 // Reset DataSndRetryer so if a CORE_GENERIC_ERROR_NTF with STATUS_UCI_PACKET_RETRY 854 // is received, only this UCI CMD packet will be retried. 855 let _ = self.uci_data_snd_retryer.take(); 856 857 self.retry_uci_cmd().await; 858 } 859 860 UciManagerCmd::SendUciData { data_snd_packet } => { 861 let result = self.handle_data_snd_packet(data_snd_packet).await; 862 let _ = result_sender.send(result); 863 } 864 } 865 } 866 retry_uci_cmd(&mut self)867 async fn retry_uci_cmd(&mut self) { 868 if let Some(mut uci_cmd_retryer) = self.uci_cmd_retryer.take() { 869 if !uci_cmd_retryer.could_retry() { 870 error!("Out of retries for Uci Cmd packet"); 871 uci_cmd_retryer.send_result(Err(Error::Timeout)); 872 return; 873 } 874 875 match self.send_uci_command(uci_cmd_retryer.cmd.clone()).await { 876 Ok(_) => { 877 self.wait_resp_timeout = PinSleep::new(Duration::from_millis(UCI_TIMEOUT_MS)); 878 self.uci_cmd_retryer = Some(uci_cmd_retryer); 879 } 880 Err(e) => { 881 error!("Uci Cmd send resulted in error:{}", e); 882 uci_cmd_retryer.send_result(Err(e)); 883 } 884 } 885 } 886 } 887 retry_uci_data_snd(&mut self)888 async fn retry_uci_data_snd(&mut self) { 889 if let Some(mut uci_data_snd_retryer) = self.uci_data_snd_retryer.take() { 890 let data_packet_session_token = uci_data_snd_retryer.data_packet_session_token; 891 if !uci_data_snd_retryer.could_retry() { 892 error!( 893 "Out of retries for Uci DataSnd packet, last DataSnd packet session_id:{}", 894 data_packet_session_token 895 ); 896 return; 897 } 898 899 match self.hal.send_packet(uci_data_snd_retryer.data_packet.clone().to_vec()).await { 900 Ok(_) => { 901 self.uci_data_snd_retryer = Some(uci_data_snd_retryer); 902 } 903 Err(e) => { 904 error!( 905 "DataSnd packet fragment session_id:{} retry failed with error:{}", 906 data_packet_session_token, e 907 ); 908 } 909 } 910 } 911 } 912 send_uci_command(&mut self, cmd: UciCommand) -> Result<()>913 async fn send_uci_command(&mut self, cmd: UciCommand) -> Result<()> { 914 if !self.is_hal_opened { 915 warn!("The UCI HAL is already closed, skip."); 916 return Err(Error::BadParameters); 917 } 918 let result = self.hal.send_command(cmd.clone()).await; 919 if result.is_ok() { 920 self.logger.log_uci_command(&cmd); 921 } 922 result 923 } 924 handle_data_snd_packet(&mut self, data_snd_packet: UciDataSnd) -> Result<UciResponse>925 async fn handle_data_snd_packet(&mut self, data_snd_packet: UciDataSnd) -> Result<UciResponse> { 926 // Verify that there's an entry for the Session in the CreditAvailability map. 927 let data_packet_session_token = data_snd_packet.get_session_token(); 928 let data_packet_sequence_number = data_snd_packet.get_uci_sequence_number(); 929 930 if !self.data_credit_map.contains_key(&data_packet_session_token) { 931 error!( 932 "DataSnd packet session_token:{}, sequence_number:{} cannot be sent as unknown \ 933 credit availability for the session", 934 data_packet_session_token, data_packet_sequence_number 935 ); 936 return Err(Error::PacketTxError); 937 } 938 939 // Enqueue the data packet fragments, from the data packet to be sent to UWBS. 940 let mut packet_fragments: Vec<UciDataPacketHal> = data_snd_packet.into(); 941 if packet_fragments.is_empty() { 942 error!( 943 "DataSnd packet session_token:{}, sequence number:{} could not be split into fragments", 944 data_packet_session_token, data_packet_sequence_number 945 ); 946 return Err(Error::PacketTxError); 947 } 948 949 match self.data_packet_fragments_map.get_mut(&data_packet_session_token) { 950 Some(q) => { 951 for p in packet_fragments.drain(..) { 952 q.push_back(p); 953 } 954 } 955 None => { 956 error!( 957 "DataSnd packet fragments map not found for session_token:{}", 958 data_packet_session_token 959 ); 960 return Err(Error::PacketTxError); 961 } 962 } 963 964 self.send_data_packet_fragment(data_packet_session_token).await 965 } 966 send_data_packet_fragment( &mut self, data_packet_session_token: SessionToken, ) -> Result<UciResponse>967 async fn send_data_packet_fragment( 968 &mut self, 969 data_packet_session_token: SessionToken, 970 ) -> Result<UciResponse> { 971 // Check if a credit is available before sending this data packet fragment. If not, return 972 // for now, and send this packet later when the credit becomes available (indicated by 973 // receiving a DataCreditNtf). 974 let credit = self.data_credit_map.get(&data_packet_session_token); 975 if credit.is_none() { 976 error!( 977 "DataSnd packet fragment cannot be sent for session_token:{} as unknown \ 978 credit availability for the session", 979 data_packet_session_token 980 ); 981 return Err(Error::PacketTxError); 982 } 983 if credit == Some(&CreditAvailability::CreditNotAvailable) { 984 return Ok(UciResponse::SendUciData(Ok(()))); 985 } 986 987 // We have credit available, let's send the packet to UWBS. 988 let hal_data_packet_fragment = 989 match self.data_packet_fragments_map.get_mut(&data_packet_session_token) { 990 Some(q) => { 991 match q.pop_front() { 992 Some(p) => p, 993 None => { 994 // No more packets left to send. 995 return Ok(UciResponse::SendUciData(Ok(()))); 996 } 997 } 998 } 999 None => { 1000 return Err(Error::PacketTxError); 1001 } 1002 }; 1003 1004 // Create and save a retryer for sending this data packet fragment. 1005 self.uci_data_snd_retryer = Some(UciDataSndRetryer { 1006 data_packet: hal_data_packet_fragment.clone(), 1007 data_packet_session_token, 1008 retry_count: MAX_RETRY_COUNT, 1009 }); 1010 1011 let result = self.hal.send_packet(hal_data_packet_fragment.to_vec()).await; 1012 if result.is_err() { 1013 error!( 1014 "Result {:?} of sending data packet fragment SessionToken: {} to HAL", 1015 result, data_packet_session_token 1016 ); 1017 return Err(Error::PacketTxError); 1018 } 1019 1020 // Update the map after the successful write. 1021 self.data_credit_map 1022 .insert(data_packet_session_token, CreditAvailability::CreditNotAvailable); 1023 Ok(UciResponse::SendUciData(Ok(()))) 1024 } 1025 handle_hal_packet(&mut self, packet: Option<UciHalPacket>)1026 async fn handle_hal_packet(&mut self, packet: Option<UciHalPacket>) { 1027 let defrag_packet = match packet { 1028 Some(rx_packet) => { 1029 self.defrager.defragment_packet(&rx_packet, self.last_raw_cmd.clone()) 1030 } 1031 None => { 1032 warn!("UciHal dropped the packet_sender unexpectedly."); 1033 self.on_hal_closed(); 1034 return; 1035 } 1036 }; 1037 let defrag_packet = match defrag_packet { 1038 Some(p) => p, 1039 None => return, 1040 }; 1041 1042 match defrag_packet { 1043 UciDefragPacket::Control(packet) => { 1044 self.logger.log_uci_response_or_notification(&packet); 1045 1046 match packet.try_into() { 1047 Ok(UciMessage::Response(resp)) => { 1048 self.handle_response(resp).await; 1049 } 1050 Ok(UciMessage::Notification(notf)) => { 1051 self.handle_notification(notf).await; 1052 } 1053 Err(e) => { 1054 error!("Failed to parse received message: {:?}", e); 1055 } 1056 } 1057 } 1058 UciDefragPacket::Data(packet) => { 1059 self.logger.log_uci_data(&packet); 1060 self.handle_data_rcv(packet); 1061 } 1062 UciDefragPacket::Raw(result, raw_uci_control_packet) => { 1063 // Handle response to raw UCI cmd. We want to send it back as 1064 // raw UCI message instead of standard response message. 1065 let resp = match result { 1066 Ok(()) => { 1067 // We should receive only a valid UCI response packet here. 1068 UciResponse::RawUciCmd(Ok(RawUciMessage { 1069 gid: raw_uci_control_packet.gid.into(), 1070 oid: raw_uci_control_packet.oid.into(), 1071 payload: raw_uci_control_packet.payload, 1072 })) 1073 } 1074 // TODO: Implement conversion between Error::InvalidPacketError (returned by 1075 // lib.rs and defined in the PDL uci_packets.rs) and the uwb_core::Error enums. 1076 Err(_) => UciResponse::RawUciCmd(Err(Error::Unknown)), 1077 }; 1078 self.handle_response(resp).await; 1079 self.last_raw_cmd = None; 1080 } 1081 } 1082 } 1083 handle_response(&mut self, resp: UciResponse)1084 async fn handle_response(&mut self, resp: UciResponse) { 1085 if resp.need_retry() { 1086 self.retry_uci_cmd().await; 1087 return; 1088 } 1089 if let Err(_e) = self.store_session_token_if_init_resp(&resp).await { 1090 error!("Session init response received without a sesson id stored! Something has gone badly wrong: {:?}", resp); 1091 return; 1092 } 1093 1094 if let Some(uci_cmd_retryer) = self.uci_cmd_retryer.take() { 1095 uci_cmd_retryer.send_result(Ok(resp)); 1096 } else { 1097 warn!("Received an UCI response unexpectedly: {:?}", resp); 1098 } 1099 } 1100 handle_notification(&mut self, notf: UciNotification)1101 async fn handle_notification(&mut self, notf: UciNotification) { 1102 if notf.need_retry() { 1103 // Retry sending both last sent UCI CMD and UCI DataSnd packet since the notification 1104 // could be for either of them. 1105 self.retry_uci_cmd().await; 1106 self.retry_uci_data_snd().await; 1107 return; 1108 } 1109 1110 match notf { 1111 UciNotification::Core(core_notf) => { 1112 if let CoreNotification::DeviceStatus(status) = core_notf { 1113 if let Some(result_sender) = self.open_hal_result_sender.take() { 1114 let result = match status { 1115 DeviceState::DeviceStateReady | DeviceState::DeviceStateActive => { 1116 Ok(UciResponse::OpenHal) 1117 } 1118 _ => Err(Error::Unknown), 1119 }; 1120 let _ = result_sender.send(result); 1121 } 1122 } 1123 let _ = self.core_notf_sender.send(core_notf); 1124 } 1125 UciNotification::Session(orig_session_notf) => { 1126 let mod_session_notf = { 1127 match self 1128 .replace_session_token_with_session_id(orig_session_notf.clone()) 1129 .await 1130 { 1131 Ok(session_notf) => session_notf, 1132 Err(e) => { 1133 error!("Failed to find corresponding session id, discarding session notification {:?}: {:?}", orig_session_notf, e); 1134 return; 1135 } 1136 } 1137 }; 1138 match orig_session_notf { 1139 SessionNotification::Status { 1140 session_token, 1141 session_state, 1142 reason_code: _, 1143 } => self.handle_session_state_notification(session_token, session_state).await, 1144 SessionNotification::DataCredit { session_token, credit_availability } => { 1145 if !self.data_credit_map.contains_key(&session_token) { 1146 // Currently just log, as this is unexpected (the entry should exist once 1147 // the ranging session is Active and be removed once it is Idle). 1148 debug!( 1149 "Received a DataCreditNtf for non-existent session_token: {}", 1150 session_token 1151 ); 1152 } 1153 self.data_credit_map.insert(session_token, credit_availability); 1154 if credit_availability == CreditAvailability::CreditAvailable { 1155 if let Err(e) = self.send_data_packet_fragment(session_token).await { 1156 error!( 1157 "Sending data packet fragment failed with Err:{}, after a\ 1158 DataCreditNtf is received, for session_token:{}", 1159 e, session_token 1160 ); 1161 } 1162 } else { 1163 // Log as this should usually not happen (it's not an error). 1164 debug!( 1165 "Received a DataCreditNtf with no credit available for session_token:{}", 1166 session_token 1167 ); 1168 } 1169 return; // We consume these here and don't need to send to upper layer. 1170 } 1171 SessionNotification::DataTransferStatus { 1172 session_token: _, 1173 uci_sequence_number: _, 1174 status: _, 1175 } => { 1176 // Reset the UciDataSnd Retryer since we received a DataTransferStatusNtf. 1177 let _ = self.uci_data_snd_retryer.take(); 1178 } 1179 _ => {} 1180 } 1181 let _ = self.session_notf_sender.send(mod_session_notf); 1182 } 1183 UciNotification::Vendor(vendor_notf) => { 1184 let _ = self.vendor_notf_sender.send(vendor_notf); 1185 } 1186 } 1187 } 1188 1189 // Modify session_token field in all session related notifications with session id. 1190 // TODO: Sharing of structs across UCI (PDL) & JNI layer like this makes this ugly. Ideally 1191 // the struct sent to JNI layer should only contain |session_id| and at uci layer 1192 // it could be |session_id| or |session_handle|. replace_session_token_with_session_id( &self, session_notification: SessionNotification, ) -> Result<SessionNotification>1193 async fn replace_session_token_with_session_id( 1194 &self, 1195 session_notification: SessionNotification, 1196 ) -> Result<SessionNotification> { 1197 match session_notification { 1198 SessionNotification::Status { session_token, session_state, reason_code } => { 1199 Ok(SessionNotification::Status { 1200 session_token: self.get_session_id(&session_token).await?, 1201 session_state, 1202 reason_code, 1203 }) 1204 } 1205 SessionNotification::UpdateControllerMulticastList { 1206 session_token, 1207 remaining_multicast_list_size, 1208 status_list, 1209 } => Ok(SessionNotification::UpdateControllerMulticastList { 1210 session_token: self.get_session_id(&session_token).await?, 1211 remaining_multicast_list_size, 1212 status_list, 1213 }), 1214 SessionNotification::SessionInfo(session_range_data) => { 1215 Ok(SessionNotification::SessionInfo(SessionRangeData { 1216 sequence_number: session_range_data.sequence_number, 1217 session_token: self.get_session_id(&session_range_data.session_token).await?, 1218 current_ranging_interval_ms: session_range_data.current_ranging_interval_ms, 1219 ranging_measurement_type: session_range_data.ranging_measurement_type, 1220 ranging_measurements: session_range_data.ranging_measurements, 1221 rcr_indicator: session_range_data.rcr_indicator, 1222 raw_ranging_data: session_range_data.raw_ranging_data, 1223 })) 1224 } 1225 SessionNotification::DataTransferStatus { 1226 session_token, 1227 uci_sequence_number, 1228 status, 1229 } => Ok(SessionNotification::DataTransferStatus { 1230 session_token: self.get_session_id(&session_token).await?, 1231 uci_sequence_number, 1232 status, 1233 }), 1234 SessionNotification::DataCredit { session_token, credit_availability } => { 1235 Ok(SessionNotification::DataCredit { 1236 session_token: self.get_session_id(&session_token).await?, 1237 credit_availability, 1238 }) 1239 } 1240 } 1241 } 1242 handle_session_state_notification( &mut self, session_token: SessionToken, session_state: SessionState, )1243 async fn handle_session_state_notification( 1244 &mut self, 1245 session_token: SessionToken, 1246 session_state: SessionState, 1247 ) { 1248 match session_state { 1249 SessionState::SessionStateInit => { 1250 if let Err(e) = self.hal.notify_session_initialized(session_token).await { 1251 warn!("notify_session_initialized() failed: {:?}", e); 1252 } 1253 } 1254 SessionState::SessionStateActive => { 1255 self.data_credit_map.insert(session_token, CreditAvailability::CreditAvailable); 1256 self.data_packet_fragments_map.insert(session_token, VecDeque::new()); 1257 } 1258 SessionState::SessionStateIdle => { 1259 self.data_credit_map.remove(&session_token); 1260 self.data_packet_fragments_map.remove(&session_token); 1261 } 1262 SessionState::SessionStateDeinit => { 1263 self.remove_session_token(&session_token).await; 1264 } 1265 } 1266 } 1267 handle_data_rcv(&mut self, packet: UciDataPacket)1268 fn handle_data_rcv(&mut self, packet: UciDataPacket) { 1269 match packet.try_into() { 1270 Ok(data_rcv) => { 1271 let _ = self.data_rcv_notf_sender.send(data_rcv); 1272 } 1273 Err(e) => { 1274 error!("Unable to parse incoming Data packet, error {:?}", e); 1275 } 1276 } 1277 } 1278 on_hal_open(&mut self, packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>)1279 fn on_hal_open(&mut self, packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>) { 1280 self.is_hal_opened = true; 1281 self.packet_receiver = packet_receiver; 1282 } 1283 on_hal_closed(&mut self)1284 fn on_hal_closed(&mut self) { 1285 self.is_hal_opened = false; 1286 self.packet_receiver = mpsc::unbounded_channel().1; 1287 self.last_raw_cmd = None; 1288 } 1289 is_waiting_resp(&self) -> bool1290 fn is_waiting_resp(&self) -> bool { 1291 self.uci_cmd_retryer.is_some() 1292 } is_waiting_device_status(&self) -> bool1293 fn is_waiting_device_status(&self) -> bool { 1294 self.open_hal_result_sender.is_some() 1295 } 1296 } 1297 1298 impl<T: UciHal, U: UciLogger> Drop for UciManagerActor<T, U> { drop(&mut self)1299 fn drop(&mut self) { 1300 // mpsc receiver is about to be dropped. Clean shutdown the mpsc message. 1301 clean_mpsc_receiver(&mut self.packet_receiver); 1302 } 1303 } 1304 1305 struct UciCmdRetryer { 1306 cmd: UciCommand, 1307 result_sender: oneshot::Sender<Result<UciResponse>>, 1308 retry_count: usize, 1309 } 1310 1311 impl UciCmdRetryer { could_retry(&mut self) -> bool1312 fn could_retry(&mut self) -> bool { 1313 if self.retry_count == 0 { 1314 return false; 1315 } 1316 self.retry_count -= 1; 1317 true 1318 } 1319 send_result(self, result: Result<UciResponse>)1320 fn send_result(self, result: Result<UciResponse>) { 1321 let _ = self.result_sender.send(result); 1322 } 1323 } 1324 1325 struct UciDataSndRetryer { 1326 // Store the last-sent DataSnd packet fragment across all the active UWB session, as the UCI 1327 // spec states that the "last UCI packet should be re-transmitted from Host". 1328 // 1329 // TODO(b/273376343): The spec is open to a race condition in the scenario of multiple active 1330 // sessions, as there can be outstanding DataSnd packet fragments across them. We could do an 1331 // alternative implementation of sending all of them. 1332 data_packet: UciDataPacketHal, 1333 data_packet_session_token: SessionToken, 1334 retry_count: usize, 1335 } 1336 1337 impl UciDataSndRetryer { could_retry(&mut self) -> bool1338 fn could_retry(&mut self) -> bool { 1339 if self.retry_count == 0 { 1340 return false; 1341 } 1342 self.retry_count -= 1; 1343 true 1344 } 1345 } 1346 1347 #[derive(Debug)] 1348 enum UciManagerCmd { 1349 SetLoggerMode { 1350 logger_mode: UciLoggerMode, 1351 }, 1352 SetCoreNotificationSender { 1353 core_notf_sender: mpsc::UnboundedSender<CoreNotification>, 1354 }, 1355 SetSessionNotificationSender { 1356 session_notf_sender: mpsc::UnboundedSender<SessionNotification>, 1357 }, 1358 SetVendorNotificationSender { 1359 vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, 1360 }, 1361 SetDataRcvNotificationSender { 1362 data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, 1363 }, 1364 OpenHal, 1365 CloseHal { 1366 force: bool, 1367 }, 1368 SendUciCommand { 1369 cmd: UciCommand, 1370 }, 1371 SendUciData { 1372 data_snd_packet: UciDataSnd, 1373 }, 1374 } 1375 1376 #[cfg(any(test))] 1377 mod tests { 1378 use super::*; 1379 1380 use bytes::Bytes; 1381 use tokio::macros::support::Future; 1382 use uwb_uci_packets::{SessionGetCountCmdBuilder, SessionGetCountRspBuilder}; 1383 1384 use crate::params::uci_packets::{ 1385 AppConfigStatus, AppConfigTlvType, CapTlvType, Controlee, DataTransferNtfStatusCode, 1386 StatusCode, 1387 }; 1388 use crate::uci::mock_uci_hal::MockUciHal; 1389 use crate::uci::mock_uci_logger::{MockUciLogger, UciLogEvent}; 1390 use crate::uci::uci_logger::NopUciLogger; 1391 use crate::utils::init_test_logging; 1392 into_uci_hal_packets<T: Into<uwb_uci_packets::UciControlPacket>>( builder: T, ) -> Vec<UciHalPacket>1393 fn into_uci_hal_packets<T: Into<uwb_uci_packets::UciControlPacket>>( 1394 builder: T, 1395 ) -> Vec<UciHalPacket> { 1396 let packets: Vec<uwb_uci_packets::UciControlPacketHal> = builder.into().into(); 1397 packets.into_iter().map(|packet| packet.into()).collect() 1398 } 1399 1400 // 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>1401 fn build_uci_packet(mt: u8, pbf: u8, gid: u8, oid: u8, mut payload: Vec<u8>) -> Vec<u8> { 1402 let len: u16 = payload.len() as u16; 1403 let mut bytes: Vec<u8> = vec![(mt & 0x7) << 5 | (pbf & 0x1) << 4 | (gid & 0xF), oid & 0x3F]; 1404 if mt == 0 { 1405 // UCI Data packet 1406 // Store 16-bit payload length in LSB format. 1407 bytes.push((len & 0xFF).try_into().unwrap()); 1408 bytes.push((len >> 8).try_into().unwrap()); 1409 } else { 1410 // One byte RFU, followed by one-byte payload length. 1411 bytes.push(0); 1412 bytes.push((len & 0xFF).try_into().unwrap()); 1413 } 1414 bytes.append(&mut payload); 1415 bytes 1416 } 1417 setup_hal_for_open(hal: &mut MockUciHal)1418 fn setup_hal_for_open(hal: &mut MockUciHal) { 1419 // Setup Open the hal. 1420 let notf = into_uci_hal_packets(uwb_uci_packets::DeviceStatusNtfBuilder { 1421 device_state: uwb_uci_packets::DeviceState::DeviceStateReady, 1422 }); 1423 hal.expected_open(Some(notf), Ok(())); 1424 1425 // Setup Get the device info. 1426 let cmd = UciCommand::CoreGetDeviceInfo; 1427 let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder { 1428 status: uwb_uci_packets::StatusCode::UciStatusOk, 1429 uci_version: 0x1234, 1430 mac_version: 0x5678, 1431 phy_version: 0x90ab, 1432 uci_test_version: 0x1357, 1433 vendor_spec_info: vec![0x1, 0x2], 1434 }); 1435 hal.expected_send_command(cmd, resp, Ok(())); 1436 } 1437 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 = ()>,1438 async fn setup_uci_manager_with_open_hal<F, Fut>( 1439 setup_hal_fn: F, 1440 uci_logger_mode: UciLoggerMode, 1441 log_sender: mpsc::UnboundedSender<UciLogEvent>, 1442 ) -> (UciManagerImpl, MockUciHal) 1443 where 1444 F: FnOnce(MockUciHal) -> Fut, 1445 Fut: Future<Output = ()>, 1446 { 1447 init_test_logging(); 1448 1449 let mut hal = MockUciHal::new(); 1450 // Open the hal. 1451 setup_hal_for_open(&mut hal); 1452 1453 // Verify open_hal() is working. 1454 let uci_manager = 1455 UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode); 1456 let result = uci_manager.open_hal().await; 1457 assert!(result.is_ok()); 1458 assert!(hal.wait_expected_calls_done().await); 1459 1460 setup_hal_fn(hal.clone()).await; 1461 1462 (uci_manager, hal) 1463 } 1464 1465 #[tokio::test] test_open_hal_without_notification()1466 async fn test_open_hal_without_notification() { 1467 init_test_logging(); 1468 1469 let mut hal = MockUciHal::new(); 1470 hal.expected_open(None, Ok(())); 1471 let uci_manager = 1472 UciManagerImpl::new(hal.clone(), NopUciLogger::default(), UciLoggerMode::Disabled); 1473 1474 let result = uci_manager.open_hal().await; 1475 assert!(matches!(result, Err(Error::Timeout))); 1476 assert!(hal.wait_expected_calls_done().await); 1477 } 1478 1479 #[tokio::test] test_close_hal_explicitly()1480 async fn test_close_hal_explicitly() { 1481 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1482 |mut hal| async move { 1483 hal.expected_close(Ok(())); 1484 }, 1485 UciLoggerMode::Disabled, 1486 mpsc::unbounded_channel::<UciLogEvent>().0, 1487 ) 1488 .await; 1489 1490 let result = uci_manager.close_hal(false).await; 1491 assert!(result.is_ok()); 1492 assert!(mock_hal.wait_expected_calls_done().await); 1493 } 1494 1495 #[tokio::test] test_close_hal_when_exit()1496 async fn test_close_hal_when_exit() { 1497 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1498 |mut hal| async move { 1499 // UciManager should close the hal if the hal is still opened when exit. 1500 hal.expected_close(Ok(())); 1501 }, 1502 UciLoggerMode::Disabled, 1503 mpsc::unbounded_channel::<UciLogEvent>().0, 1504 ) 1505 .await; 1506 1507 drop(uci_manager); 1508 assert!(mock_hal.wait_expected_calls_done().await); 1509 } 1510 1511 #[tokio::test] test_close_hal_without_open_hal()1512 async fn test_close_hal_without_open_hal() { 1513 init_test_logging(); 1514 1515 let mut hal = MockUciHal::new(); 1516 let uci_manager = 1517 UciManagerImpl::new(hal.clone(), NopUciLogger::default(), UciLoggerMode::Disabled); 1518 1519 let result = uci_manager.close_hal(false).await; 1520 assert!(matches!(result, Err(Error::BadParameters))); 1521 assert!(hal.wait_expected_calls_done().await); 1522 } 1523 1524 #[tokio::test] test_device_reset_ok()1525 async fn test_device_reset_ok() { 1526 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1527 |mut hal| async move { 1528 let cmd = UciCommand::DeviceReset { reset_config: ResetConfig::UwbsReset }; 1529 let resp = into_uci_hal_packets(uwb_uci_packets::DeviceResetRspBuilder { 1530 status: uwb_uci_packets::StatusCode::UciStatusOk, 1531 }); 1532 hal.expected_send_command(cmd, resp, Ok(())); 1533 }, 1534 UciLoggerMode::Disabled, 1535 mpsc::unbounded_channel::<UciLogEvent>().0, 1536 ) 1537 .await; 1538 1539 let result = uci_manager.device_reset(ResetConfig::UwbsReset).await; 1540 assert!(result.is_ok()); 1541 assert!(mock_hal.wait_expected_calls_done().await); 1542 } 1543 1544 #[tokio::test] test_core_get_device_info_ok()1545 async fn test_core_get_device_info_ok() { 1546 let status = StatusCode::UciStatusOk; 1547 let uci_version = 0x1234; 1548 let mac_version = 0x5678; 1549 let phy_version = 0x90ab; 1550 let uci_test_version = 0x1357; 1551 let vendor_spec_info = vec![0x1, 0x2]; 1552 let vendor_spec_info_clone = vendor_spec_info.clone(); 1553 1554 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1555 |mut hal| async move { 1556 let cmd = UciCommand::CoreGetDeviceInfo; 1557 let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder { 1558 status, 1559 uci_version, 1560 mac_version, 1561 phy_version, 1562 uci_test_version, 1563 vendor_spec_info: vendor_spec_info_clone, 1564 }); 1565 1566 hal.expected_send_command(cmd, resp, Ok(())); 1567 }, 1568 UciLoggerMode::Disabled, 1569 mpsc::unbounded_channel::<UciLogEvent>().0, 1570 ) 1571 .await; 1572 1573 let expected_result = GetDeviceInfoResponse { 1574 uci_version, 1575 mac_version, 1576 phy_version, 1577 uci_test_version, 1578 vendor_spec_info, 1579 }; 1580 let result = uci_manager.core_get_device_info().await.unwrap(); 1581 assert_eq!(result, expected_result); 1582 assert!(mock_hal.wait_expected_calls_done().await); 1583 } 1584 1585 #[tokio::test] test_core_get_caps_info_ok()1586 async fn test_core_get_caps_info_ok() { 1587 let tlv = CapTlv { t: CapTlvType::SupportedFiraPhyVersionRange, v: vec![0x12, 0x34, 0x56] }; 1588 let tlv_clone = tlv.clone(); 1589 1590 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1591 |mut hal| async move { 1592 let cmd = UciCommand::CoreGetCapsInfo; 1593 let resp = into_uci_hal_packets(uwb_uci_packets::GetCapsInfoRspBuilder { 1594 status: uwb_uci_packets::StatusCode::UciStatusOk, 1595 tlvs: vec![tlv_clone], 1596 }); 1597 1598 hal.expected_send_command(cmd, resp, Ok(())); 1599 }, 1600 UciLoggerMode::Disabled, 1601 mpsc::unbounded_channel::<UciLogEvent>().0, 1602 ) 1603 .await; 1604 1605 let result = uci_manager.core_get_caps_info().await.unwrap(); 1606 assert_eq!(result[0], tlv); 1607 assert!(mock_hal.wait_expected_calls_done().await); 1608 } 1609 1610 #[tokio::test] test_core_set_config_ok()1611 async fn test_core_set_config_ok() { 1612 let tlv = DeviceConfigTlv { 1613 cfg_id: uwb_uci_packets::DeviceConfigId::DeviceState, 1614 v: vec![0x12, 0x34, 0x56], 1615 }; 1616 let tlv_clone = tlv.clone(); 1617 let status = StatusCode::UciStatusOk; 1618 let config_status = vec![]; 1619 let config_status_clone = config_status.clone(); 1620 1621 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1622 |mut hal| async move { 1623 let cmd = UciCommand::CoreSetConfig { config_tlvs: vec![tlv_clone] }; 1624 let resp = into_uci_hal_packets(uwb_uci_packets::SetConfigRspBuilder { 1625 status, 1626 cfg_status: config_status_clone, 1627 }); 1628 1629 hal.expected_send_command(cmd, resp, Ok(())); 1630 }, 1631 UciLoggerMode::Disabled, 1632 mpsc::unbounded_channel::<UciLogEvent>().0, 1633 ) 1634 .await; 1635 1636 let expected_result = CoreSetConfigResponse { status, config_status }; 1637 let result = uci_manager.core_set_config(vec![tlv]).await.unwrap(); 1638 assert_eq!(result, expected_result); 1639 assert!(mock_hal.wait_expected_calls_done().await); 1640 } 1641 1642 #[tokio::test] test_core_get_config_ok()1643 async fn test_core_get_config_ok() { 1644 let cfg_id = DeviceConfigId::DeviceState; 1645 let tlv = DeviceConfigTlv { cfg_id, v: vec![0x12, 0x34, 0x56] }; 1646 let tlv_clone = tlv.clone(); 1647 1648 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1649 |mut hal| async move { 1650 let cmd = UciCommand::CoreGetConfig { cfg_id: vec![cfg_id] }; 1651 let resp = into_uci_hal_packets(uwb_uci_packets::GetConfigRspBuilder { 1652 status: uwb_uci_packets::StatusCode::UciStatusOk, 1653 tlvs: vec![tlv_clone], 1654 }); 1655 1656 hal.expected_send_command(cmd, resp, Ok(())); 1657 }, 1658 UciLoggerMode::Disabled, 1659 mpsc::unbounded_channel::<UciLogEvent>().0, 1660 ) 1661 .await; 1662 1663 let expected_result = vec![tlv]; 1664 let result = uci_manager.core_get_config(vec![cfg_id]).await.unwrap(); 1665 assert_eq!(result, expected_result); 1666 assert!(mock_hal.wait_expected_calls_done().await); 1667 } 1668 setup_hal_for_session_initialize( hal: &mut MockUciHal, session_type: SessionType, session_id: u32, session_token: u32, )1669 fn setup_hal_for_session_initialize( 1670 hal: &mut MockUciHal, 1671 session_type: SessionType, 1672 session_id: u32, 1673 session_token: u32, 1674 ) { 1675 // Setup for hal open. 1676 setup_hal_for_open(hal); 1677 1678 // Setup session init. 1679 let cmd = UciCommand::SessionInit { session_id, session_type }; 1680 let mut resp = if session_id == session_token { 1681 into_uci_hal_packets(uwb_uci_packets::SessionInitRspBuilder { 1682 status: uwb_uci_packets::StatusCode::UciStatusOk, 1683 }) 1684 } else { 1685 // This is testing FIRA v2 flow where a session handle is provided by UWBS. 1686 into_uci_hal_packets(uwb_uci_packets::SessionInitRsp_V2Builder { 1687 status: uwb_uci_packets::StatusCode::UciStatusOk, 1688 session_handle: session_token, 1689 }) 1690 }; 1691 let mut notf = into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder { 1692 session_token, 1693 session_state: uwb_uci_packets::SessionState::SessionStateInit, 1694 reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands 1695 .into(), 1696 }); 1697 resp.append(&mut notf); 1698 hal.expected_send_command(cmd, resp, Ok(())); 1699 hal.expected_notify_session_initialized(session_token, Ok(())); 1700 } 1701 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 = ()>,1702 async fn setup_uci_manager_with_session_initialized<F, Fut>( 1703 setup_hal_fn: F, 1704 uci_logger_mode: UciLoggerMode, 1705 log_sender: mpsc::UnboundedSender<UciLogEvent>, 1706 session_id: u32, 1707 session_token: u32, 1708 ) -> (UciManagerImpl, MockUciHal) 1709 where 1710 F: FnOnce(MockUciHal) -> Fut, 1711 Fut: Future<Output = ()>, 1712 { 1713 let session_type = SessionType::FiraRangingSession; 1714 1715 init_test_logging(); 1716 1717 let mut hal = MockUciHal::new(); 1718 setup_hal_for_session_initialize(&mut hal, session_type, session_id, session_token); 1719 1720 // Verify open_hal() is working. 1721 let uci_manager = 1722 UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode); 1723 let result = uci_manager.open_hal().await; 1724 assert!(result.is_ok()); 1725 1726 // Verify session is initialized. 1727 let result = uci_manager.session_init(session_id, session_type).await; 1728 assert!(result.is_ok()); 1729 assert!(hal.wait_expected_calls_done().await); 1730 1731 setup_hal_fn(hal.clone()).await; 1732 1733 (uci_manager, hal) 1734 } 1735 1736 #[tokio::test] test_session_init_ok()1737 async fn test_session_init_ok() { 1738 let session_id = 0x123; 1739 let session_token = 0x123; 1740 let (_, mut mock_hal) = setup_uci_manager_with_session_initialized( 1741 |_hal| async move {}, 1742 UciLoggerMode::Disabled, 1743 mpsc::unbounded_channel::<UciLogEvent>().0, 1744 session_id, 1745 session_token, 1746 ) 1747 .await; 1748 assert!(mock_hal.wait_expected_calls_done().await); 1749 } 1750 1751 #[tokio::test] test_session_init_v2_ok()1752 async fn test_session_init_v2_ok() { 1753 let session_id = 0x123; 1754 let session_token = 0x321; // different session handle 1755 let (_, mut mock_hal) = setup_uci_manager_with_session_initialized( 1756 |_hal| async move {}, 1757 UciLoggerMode::Disabled, 1758 mpsc::unbounded_channel::<UciLogEvent>().0, 1759 session_id, 1760 session_token, 1761 ) 1762 .await; 1763 assert!(mock_hal.wait_expected_calls_done().await); 1764 } 1765 1766 #[tokio::test] test_session_deinit_ok()1767 async fn test_session_deinit_ok() { 1768 let session_id = 0x123; 1769 let session_token = 0x123; 1770 1771 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 1772 |mut hal| async move { 1773 let cmd = UciCommand::SessionDeinit { session_token }; 1774 let resp = into_uci_hal_packets(uwb_uci_packets::SessionDeinitRspBuilder { 1775 status: uwb_uci_packets::StatusCode::UciStatusOk, 1776 }); 1777 1778 hal.expected_send_command(cmd, resp, Ok(())); 1779 }, 1780 UciLoggerMode::Disabled, 1781 mpsc::unbounded_channel::<UciLogEvent>().0, 1782 session_id, 1783 session_token, 1784 ) 1785 .await; 1786 1787 let result = uci_manager.session_deinit(session_id).await; 1788 assert!(result.is_ok()); 1789 assert!(mock_hal.wait_expected_calls_done().await); 1790 } 1791 1792 #[tokio::test] test_session_deinit_v2_ok()1793 async fn test_session_deinit_v2_ok() { 1794 let session_id = 0x123; 1795 let session_token = 0x321; // different session handle 1796 1797 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 1798 |mut hal| async move { 1799 let cmd = UciCommand::SessionDeinit { session_token }; 1800 let resp = into_uci_hal_packets(uwb_uci_packets::SessionDeinitRspBuilder { 1801 status: uwb_uci_packets::StatusCode::UciStatusOk, 1802 }); 1803 1804 hal.expected_send_command(cmd, resp, Ok(())); 1805 }, 1806 UciLoggerMode::Disabled, 1807 mpsc::unbounded_channel::<UciLogEvent>().0, 1808 session_id, 1809 session_token, 1810 ) 1811 .await; 1812 1813 let result = uci_manager.session_deinit(session_id).await; 1814 assert!(result.is_ok()); 1815 assert!(mock_hal.wait_expected_calls_done().await); 1816 } 1817 1818 #[tokio::test] test_session_set_app_config_ok()1819 async fn test_session_set_app_config_ok() { 1820 let session_id = 0x123; 1821 let session_token = 0x123; 1822 let config_tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]); 1823 let config_tlv_clone = config_tlv.clone(); 1824 1825 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 1826 |mut hal| async move { 1827 let cmd = UciCommand::SessionSetAppConfig { 1828 session_token, 1829 config_tlvs: vec![config_tlv_clone], 1830 }; 1831 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 1832 status: uwb_uci_packets::StatusCode::UciStatusOk, 1833 cfg_status: vec![], 1834 }); 1835 1836 hal.expected_send_command(cmd, resp, Ok(())); 1837 }, 1838 UciLoggerMode::Disabled, 1839 mpsc::unbounded_channel::<UciLogEvent>().0, 1840 session_id, 1841 session_token, 1842 ) 1843 .await; 1844 1845 let expected_result = 1846 SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; 1847 let result = 1848 uci_manager.session_set_app_config(session_id, vec![config_tlv]).await.unwrap(); 1849 assert_eq!(result, expected_result); 1850 assert!(mock_hal.wait_expected_calls_done().await); 1851 } 1852 1853 #[tokio::test] test_session_set_app_config_v2_ok()1854 async fn test_session_set_app_config_v2_ok() { 1855 let session_id = 0x123; 1856 let session_token = 0x321; 1857 let config_tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]); 1858 let config_tlv_clone = config_tlv.clone(); 1859 1860 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 1861 |mut hal| async move { 1862 let cmd = UciCommand::SessionSetAppConfig { 1863 session_token, 1864 config_tlvs: vec![config_tlv_clone], 1865 }; 1866 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 1867 status: uwb_uci_packets::StatusCode::UciStatusOk, 1868 cfg_status: vec![], 1869 }); 1870 1871 hal.expected_send_command(cmd, resp, Ok(())); 1872 }, 1873 UciLoggerMode::Disabled, 1874 mpsc::unbounded_channel::<UciLogEvent>().0, 1875 session_id, 1876 session_token, 1877 ) 1878 .await; 1879 1880 let expected_result = 1881 SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; 1882 let result = 1883 uci_manager.session_set_app_config(session_id, vec![config_tlv]).await.unwrap(); 1884 assert_eq!(result, expected_result); 1885 assert!(mock_hal.wait_expected_calls_done().await); 1886 } 1887 1888 #[tokio::test] test_session_get_app_config_ok()1889 async fn test_session_get_app_config_ok() { 1890 let session_id = 0x123; 1891 let session_token = 0x123; 1892 let config_id = AppConfigTlvType::DeviceType; 1893 let tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]); 1894 let tlv_clone = tlv.clone(); 1895 1896 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 1897 |mut hal| async move { 1898 let cmd = 1899 UciCommand::SessionGetAppConfig { session_token, app_cfg: vec![config_id] }; 1900 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetAppConfigRspBuilder { 1901 status: uwb_uci_packets::StatusCode::UciStatusOk, 1902 tlvs: vec![tlv_clone.into_inner()], 1903 }); 1904 1905 hal.expected_send_command(cmd, resp, Ok(())); 1906 }, 1907 UciLoggerMode::Disabled, 1908 mpsc::unbounded_channel::<UciLogEvent>().0, 1909 session_id, 1910 session_token, 1911 ) 1912 .await; 1913 1914 let expected_result = vec![tlv]; 1915 let result = uci_manager.session_get_app_config(session_id, vec![config_id]).await.unwrap(); 1916 assert_eq!(result, expected_result); 1917 assert!(mock_hal.wait_expected_calls_done().await); 1918 } 1919 1920 #[tokio::test] test_session_get_count_ok()1921 async fn test_session_get_count_ok() { 1922 let session_count = 5; 1923 1924 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 1925 |mut hal| async move { 1926 let cmd = UciCommand::SessionGetCount; 1927 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 1928 status: uwb_uci_packets::StatusCode::UciStatusOk, 1929 session_count, 1930 }); 1931 1932 hal.expected_send_command(cmd, resp, Ok(())); 1933 }, 1934 UciLoggerMode::Disabled, 1935 mpsc::unbounded_channel::<UciLogEvent>().0, 1936 ) 1937 .await; 1938 1939 let result = uci_manager.session_get_count().await.unwrap(); 1940 assert_eq!(result, session_count); 1941 assert!(mock_hal.wait_expected_calls_done().await); 1942 } 1943 1944 #[tokio::test] test_session_get_state_ok()1945 async fn test_session_get_state_ok() { 1946 let session_id = 0x123; 1947 let session_token = 0x123; 1948 let session_state = SessionState::SessionStateActive; 1949 1950 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 1951 |mut hal| async move { 1952 let cmd = UciCommand::SessionGetState { session_token }; 1953 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetStateRspBuilder { 1954 status: uwb_uci_packets::StatusCode::UciStatusOk, 1955 session_state, 1956 }); 1957 1958 hal.expected_send_command(cmd, resp, Ok(())); 1959 }, 1960 UciLoggerMode::Disabled, 1961 mpsc::unbounded_channel::<UciLogEvent>().0, 1962 session_id, 1963 session_token, 1964 ) 1965 .await; 1966 1967 let result = uci_manager.session_get_state(session_id).await.unwrap(); 1968 assert_eq!(result, session_state); 1969 assert!(mock_hal.wait_expected_calls_done().await); 1970 } 1971 1972 #[tokio::test] test_session_update_controller_multicast_list_ok()1973 async fn test_session_update_controller_multicast_list_ok() { 1974 let session_id = 0x123; 1975 let session_token = 0x123; 1976 let action = UpdateMulticastListAction::AddControlee; 1977 let short_address: [u8; 2] = [0x45, 0x67]; 1978 let controlee = Controlee { short_address, subsession_id: 0x90ab }; 1979 let controlee_clone = controlee.clone(); 1980 1981 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 1982 |mut hal| async move { 1983 let cmd = UciCommand::SessionUpdateControllerMulticastList { 1984 session_token, 1985 action, 1986 controlees: Controlees::NoSessionKey(vec![controlee_clone]), 1987 }; 1988 let resp = into_uci_hal_packets( 1989 uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder { 1990 status: uwb_uci_packets::StatusCode::UciStatusOk, 1991 }, 1992 ); 1993 1994 hal.expected_send_command(cmd, resp, Ok(())); 1995 }, 1996 UciLoggerMode::Disabled, 1997 mpsc::unbounded_channel::<UciLogEvent>().0, 1998 session_id, 1999 session_token, 2000 ) 2001 .await; 2002 2003 let result = uci_manager 2004 .session_update_controller_multicast_list( 2005 session_id, 2006 action, 2007 uwb_uci_packets::Controlees::NoSessionKey(vec![controlee]), 2008 ) 2009 .await; 2010 assert!(result.is_ok()); 2011 assert!(mock_hal.wait_expected_calls_done().await); 2012 } 2013 2014 #[tokio::test] test_set_active_dt_tag_ranging_rounds()2015 async fn test_set_active_dt_tag_ranging_rounds() { 2016 let session_id = 0x123; 2017 let session_token = 0x123; 2018 2019 let ranging_rounds = SessionUpdateDtTagRangingRoundsResponse { 2020 status: StatusCode::UciStatusErrorRoundIndexNotActivated, 2021 ranging_round_indexes: vec![3], 2022 }; 2023 2024 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2025 |mut hal| async move { 2026 let cmd = UciCommand::SessionUpdateDtTagRangingRounds { 2027 session_token, 2028 ranging_round_indexes: vec![3, 5], 2029 }; 2030 let resp = into_uci_hal_packets( 2031 uwb_uci_packets::SessionUpdateDtTagRangingRoundsRspBuilder { 2032 status: StatusCode::UciStatusErrorRoundIndexNotActivated, 2033 ranging_round_indexes: vec![3], 2034 }, 2035 ); 2036 2037 hal.expected_send_command(cmd, resp, Ok(())); 2038 }, 2039 UciLoggerMode::Disabled, 2040 mpsc::unbounded_channel::<UciLogEvent>().0, 2041 session_id, 2042 session_token, 2043 ) 2044 .await; 2045 2046 let result = 2047 uci_manager.session_update_dt_tag_ranging_rounds(session_id, vec![3, 5]).await.unwrap(); 2048 2049 assert_eq!(result, ranging_rounds); 2050 assert!(mock_hal.wait_expected_calls_done().await); 2051 } 2052 2053 #[tokio::test] test_range_start_ok()2054 async fn test_range_start_ok() { 2055 let session_id = 0x123; 2056 let session_token = 0x123; 2057 2058 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2059 |mut hal| async move { 2060 let cmd = UciCommand::SessionStart { session_token }; 2061 let resp = into_uci_hal_packets(uwb_uci_packets::SessionStartRspBuilder { 2062 status: uwb_uci_packets::StatusCode::UciStatusOk, 2063 }); 2064 2065 hal.expected_send_command(cmd, resp, Ok(())); 2066 }, 2067 UciLoggerMode::Disabled, 2068 mpsc::unbounded_channel::<UciLogEvent>().0, 2069 session_id, 2070 session_token, 2071 ) 2072 .await; 2073 2074 let result = uci_manager.range_start(session_id).await; 2075 assert!(result.is_ok()); 2076 assert!(mock_hal.wait_expected_calls_done().await); 2077 } 2078 2079 #[tokio::test] test_range_stop_ok()2080 async fn test_range_stop_ok() { 2081 let session_id = 0x123; 2082 let session_token = 0x123; 2083 2084 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2085 |mut hal| async move { 2086 let cmd = UciCommand::SessionStop { session_token }; 2087 let resp = into_uci_hal_packets(uwb_uci_packets::SessionStopRspBuilder { 2088 status: uwb_uci_packets::StatusCode::UciStatusOk, 2089 }); 2090 2091 hal.expected_send_command(cmd, resp, Ok(())); 2092 }, 2093 UciLoggerMode::Disabled, 2094 mpsc::unbounded_channel::<UciLogEvent>().0, 2095 session_id, 2096 session_token, 2097 ) 2098 .await; 2099 2100 let result = uci_manager.range_stop(session_id).await; 2101 assert!(result.is_ok()); 2102 assert!(mock_hal.wait_expected_calls_done().await); 2103 } 2104 2105 #[tokio::test] test_range_get_ranging_count_ok()2106 async fn test_range_get_ranging_count_ok() { 2107 let session_id = 0x123; 2108 let session_token = 0x123; 2109 let count = 3; 2110 2111 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( 2112 |mut hal| async move { 2113 let cmd = UciCommand::SessionGetRangingCount { session_token }; 2114 let resp = 2115 into_uci_hal_packets(uwb_uci_packets::SessionGetRangingCountRspBuilder { 2116 status: uwb_uci_packets::StatusCode::UciStatusOk, 2117 count, 2118 }); 2119 2120 hal.expected_send_command(cmd, resp, Ok(())); 2121 }, 2122 UciLoggerMode::Disabled, 2123 mpsc::unbounded_channel::<UciLogEvent>().0, 2124 session_id, 2125 session_token, 2126 ) 2127 .await; 2128 2129 let result = uci_manager.range_get_ranging_count(session_id).await.unwrap(); 2130 assert_eq!(result, count as usize); 2131 assert!(mock_hal.wait_expected_calls_done().await); 2132 } 2133 2134 #[tokio::test] test_android_set_country_code_ok()2135 async fn test_android_set_country_code_ok() { 2136 let country_code = CountryCode::new(b"US").unwrap(); 2137 let country_code_clone = country_code.clone(); 2138 2139 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2140 |mut hal| async move { 2141 let cmd = UciCommand::AndroidSetCountryCode { country_code: country_code_clone }; 2142 let resp = into_uci_hal_packets(uwb_uci_packets::AndroidSetCountryCodeRspBuilder { 2143 status: uwb_uci_packets::StatusCode::UciStatusOk, 2144 }); 2145 2146 hal.expected_send_command(cmd, resp, Ok(())); 2147 }, 2148 UciLoggerMode::Disabled, 2149 mpsc::unbounded_channel::<UciLogEvent>().0, 2150 ) 2151 .await; 2152 2153 let result = uci_manager.android_set_country_code(country_code).await; 2154 assert!(result.is_ok()); 2155 assert!(mock_hal.wait_expected_calls_done().await); 2156 } 2157 2158 #[tokio::test] test_android_get_power_stats_ok()2159 async fn test_android_get_power_stats_ok() { 2160 let power_stats = PowerStats { 2161 status: StatusCode::UciStatusOk, 2162 idle_time_ms: 123, 2163 tx_time_ms: 456, 2164 rx_time_ms: 789, 2165 total_wake_count: 5, 2166 }; 2167 let power_stats_clone = power_stats.clone(); 2168 2169 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2170 |mut hal| async move { 2171 let cmd = UciCommand::AndroidGetPowerStats; 2172 let resp = into_uci_hal_packets(uwb_uci_packets::AndroidGetPowerStatsRspBuilder { 2173 stats: power_stats_clone, 2174 }); 2175 2176 hal.expected_send_command(cmd, resp, Ok(())); 2177 }, 2178 UciLoggerMode::Disabled, 2179 mpsc::unbounded_channel::<UciLogEvent>().0, 2180 ) 2181 .await; 2182 2183 let result = uci_manager.android_get_power_stats().await.unwrap(); 2184 assert_eq!(result, power_stats); 2185 assert!(mock_hal.wait_expected_calls_done().await); 2186 } 2187 2188 #[tokio::test] test_raw_uci_cmd_vendor_gid_ok()2189 async fn test_raw_uci_cmd_vendor_gid_ok() { 2190 let mt = 0x1; 2191 let gid = 0xF; // Vendor reserved GID. 2192 let oid = 0x3; 2193 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2194 let cmd_payload_clone = cmd_payload.clone(); 2195 let resp_payload = vec![0x55, 0x66, 0x77, 0x88]; 2196 let resp_payload_clone = resp_payload.clone(); 2197 2198 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2199 |mut hal| async move { 2200 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone }; 2201 let resp = into_uci_hal_packets(uwb_uci_packets::UciVendor_F_ResponseBuilder { 2202 opcode: oid as u8, 2203 payload: Some(Bytes::from(resp_payload_clone)), 2204 }); 2205 2206 hal.expected_send_command(cmd, resp, Ok(())); 2207 }, 2208 UciLoggerMode::Disabled, 2209 mpsc::unbounded_channel::<UciLogEvent>().0, 2210 ) 2211 .await; 2212 2213 let expected_result = RawUciMessage { gid, oid, payload: resp_payload }; 2214 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap(); 2215 assert_eq!(result, expected_result); 2216 assert!(mock_hal.wait_expected_calls_done().await); 2217 } 2218 2219 #[tokio::test] test_raw_uci_cmd_fira_gid_ok()2220 async fn test_raw_uci_cmd_fira_gid_ok() { 2221 let mt = 0x1; 2222 let gid = 0x1; // SESSION_CONFIG GID. 2223 let oid = 0x3; 2224 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2225 let cmd_payload_clone = cmd_payload.clone(); 2226 let resp_payload = vec![0x00, 0x01, 0x07, 0x00]; 2227 let status = StatusCode::UciStatusOk; 2228 let cfg_id = AppConfigTlvType::DstMacAddress; 2229 let app_config = AppConfigStatus { cfg_id, status }; 2230 let cfg_status = vec![app_config]; 2231 2232 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2233 |mut hal| async move { 2234 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone }; 2235 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 2236 status, 2237 cfg_status, 2238 }); 2239 2240 hal.expected_send_command(cmd, resp, Ok(())); 2241 }, 2242 UciLoggerMode::Disabled, 2243 mpsc::unbounded_channel::<UciLogEvent>().0, 2244 ) 2245 .await; 2246 2247 let expected_result = RawUciMessage { gid, oid, payload: resp_payload }; 2248 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap(); 2249 assert_eq!(result, expected_result); 2250 assert!(mock_hal.wait_expected_calls_done().await); 2251 } 2252 2253 #[tokio::test] test_raw_uci_cmd_undefined_mt_ok()2254 async fn test_raw_uci_cmd_undefined_mt_ok() { 2255 let mt = 0x4; 2256 let gid = 0x1; // SESSION_CONFIG GID. 2257 let oid = 0x3; 2258 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2259 let cmd_payload_clone = cmd_payload.clone(); 2260 let resp_payload = vec![0x00, 0x01, 0x07, 0x00]; 2261 let status = StatusCode::UciStatusOk; 2262 let cfg_id = AppConfigTlvType::DstMacAddress; 2263 let app_config = AppConfigStatus { cfg_id, status }; 2264 let cfg_status = vec![app_config]; 2265 2266 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2267 |mut hal| async move { 2268 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone }; 2269 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 2270 status, 2271 cfg_status, 2272 }); 2273 2274 hal.expected_send_command(cmd, resp, Ok(())); 2275 }, 2276 UciLoggerMode::Disabled, 2277 mpsc::unbounded_channel::<UciLogEvent>().0, 2278 ) 2279 .await; 2280 2281 let expected_result = RawUciMessage { gid, oid, payload: resp_payload }; 2282 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap(); 2283 assert_eq!(result, expected_result); 2284 assert!(mock_hal.wait_expected_calls_done().await); 2285 } 2286 2287 #[tokio::test] test_raw_uci_cmd_custom_payload_format()2288 async fn test_raw_uci_cmd_custom_payload_format() { 2289 // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the 2290 // UCI HAL returns a UCI response with a custom payload format. The UCI response packet 2291 // should still be successfully parsed and returned, since it's a Raw UCI RSP. 2292 let cmd_mt: u8 = 0x1; 2293 let gid: u8 = 0x1; // Session Config. 2294 let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG 2295 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2296 let cmd_payload_clone = cmd_payload.clone(); 2297 let resp_mt: u8 = 0x2; 2298 let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; 2299 let resp_payload_clone = resp_payload.clone(); 2300 2301 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2302 |mut hal| async move { 2303 let cmd = UciCommand::RawUciCmd { 2304 mt: cmd_mt.into(), 2305 gid: gid.into(), 2306 oid: oid.into(), 2307 payload: cmd_payload_clone, 2308 }; 2309 let resp = build_uci_packet(resp_mt, 0, gid, oid, resp_payload_clone); 2310 hal.expected_send_command(cmd, vec![resp], Ok(())); 2311 }, 2312 UciLoggerMode::Disabled, 2313 mpsc::unbounded_channel::<UciLogEvent>().0, 2314 ) 2315 .await; 2316 2317 let expected_result = 2318 Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload }); 2319 let result = 2320 uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await; 2321 assert_eq!(result, expected_result); 2322 assert!(mock_hal.wait_expected_calls_done().await); 2323 } 2324 2325 #[tokio::test] test_raw_uci_cmd_fragmented_responses()2326 async fn test_raw_uci_cmd_fragmented_responses() { 2327 // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the 2328 // UCI HAL returns a UCI response with a custom payload format, in 2 UCI packet fragments. 2329 let cmd_mt: u8 = 0x1; 2330 let gid: u8 = 0x1; // Session Config. 2331 let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG 2332 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2333 let cmd_payload_clone = cmd_payload.clone(); 2334 let resp_mt: u8 = 0x2; 2335 let resp_payload_fragment_1 = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; 2336 let resp_payload_fragment_2 = vec![0x09, 0x0a, 0x0b]; 2337 let mut resp_payload_expected = resp_payload_fragment_1.clone(); 2338 resp_payload_expected.extend(resp_payload_fragment_2.clone().into_iter()); 2339 2340 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2341 |mut hal| async move { 2342 let cmd = UciCommand::RawUciCmd { 2343 mt: cmd_mt.into(), 2344 gid: gid.into(), 2345 oid: oid.into(), 2346 payload: cmd_payload_clone, 2347 }; 2348 let resp_fragment_1 = build_uci_packet( 2349 resp_mt, 2350 /* pbf = */ 1, 2351 gid, 2352 oid, 2353 resp_payload_fragment_1, 2354 ); 2355 let resp_fragment_2 = build_uci_packet( 2356 resp_mt, 2357 /* pbf = */ 0, 2358 gid, 2359 oid, 2360 resp_payload_fragment_2, 2361 ); 2362 hal.expected_send_command(cmd, vec![resp_fragment_1, resp_fragment_2], Ok(())); 2363 }, 2364 UciLoggerMode::Disabled, 2365 mpsc::unbounded_channel::<UciLogEvent>().0, 2366 ) 2367 .await; 2368 2369 let expected_result = 2370 Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload_expected }); 2371 let result = 2372 uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await; 2373 assert_eq!(result, expected_result); 2374 assert!(mock_hal.wait_expected_calls_done().await); 2375 } 2376 2377 #[tokio::test] test_raw_uci_cmd_wrong_gid()2378 async fn test_raw_uci_cmd_wrong_gid() { 2379 // Send a raw UCI command with CORE GID, but UCI HAL returns a UCI response with 2380 // SESSION_CONFIG GID. In this case, UciManager should return Error::Unknown, as the 2381 // RawUciSignature fields (GID, OID) of the CMD and RSP packets don't match. 2382 2383 let mt = 0x1; 2384 let gid = 0x0; // CORE GID. 2385 let oid = 0x1; 2386 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2387 let cmd_payload_clone = cmd_payload.clone(); 2388 let status = StatusCode::UciStatusOk; 2389 let cfg_id = AppConfigTlvType::DstMacAddress; 2390 let app_config = AppConfigStatus { cfg_id, status }; 2391 let cfg_status = vec![app_config]; 2392 2393 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2394 |mut hal| async move { 2395 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone }; 2396 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { 2397 status, 2398 cfg_status, 2399 }); 2400 2401 hal.expected_send_command(cmd, resp, Ok(())); 2402 }, 2403 UciLoggerMode::Disabled, 2404 mpsc::unbounded_channel::<UciLogEvent>().0, 2405 ) 2406 .await; 2407 2408 let expected_result = Err(Error::Unknown); 2409 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await; 2410 assert_eq!(result, expected_result); 2411 assert!(mock_hal.wait_expected_calls_done().await); 2412 } 2413 2414 #[tokio::test] test_raw_uci_cmd_out_of_range_gid()2415 async fn test_raw_uci_cmd_out_of_range_gid() { 2416 // Send a raw UCI command with a GID value outside it's 8-bit size. This should result in 2417 // an error since the input GID value cannot be encoded into the UCI packet. 2418 let mt = 0x1; 2419 let gid = 0x1FF; 2420 let oid = 0x1; 2421 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2422 2423 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2424 move |_hal| async {}, 2425 UciLoggerMode::Disabled, 2426 mpsc::unbounded_channel::<UciLogEvent>().0, 2427 ) 2428 .await; 2429 2430 let expected_result = Err(Error::BadParameters); 2431 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await; 2432 assert_eq!(result, expected_result); 2433 assert!(mock_hal.wait_expected_calls_done().await); 2434 } 2435 2436 #[tokio::test] test_raw_uci_cmd_out_of_range_oid()2437 async fn test_raw_uci_cmd_out_of_range_oid() { 2438 // Send a raw UCI command with a valid GID (CORE), but an OID value outside it's 8-bit 2439 // size. This should result in an error since the input OID value cannot be encoded into 2440 // the UCI packet. 2441 let mt = 0x1; 2442 let gid = 0x0; // CORE GID. 2443 let oid = 0x1FF; 2444 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2445 2446 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2447 |_hal| async move {}, 2448 UciLoggerMode::Disabled, 2449 mpsc::unbounded_channel::<UciLogEvent>().0, 2450 ) 2451 .await; 2452 2453 let expected_result = Err(Error::BadParameters); 2454 let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await; 2455 assert_eq!(result, expected_result); 2456 assert!(mock_hal.wait_expected_calls_done().await); 2457 } 2458 2459 #[tokio::test] test_raw_uci_cmd_uwbs_response_notification()2460 async fn test_raw_uci_cmd_uwbs_response_notification() { 2461 // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the 2462 // UCI HAL returns a valid UCI Notification packet before the raw UCI response. 2463 let cmd_mt: u8 = 0x1; 2464 let gid: u8 = 0x1; // Session Config. 2465 let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG 2466 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2467 let cmd_payload_clone = cmd_payload.clone(); 2468 let session_token = 0x123; 2469 let resp_mt: u8 = 0x2; 2470 let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; 2471 let resp_payload_clone = resp_payload.clone(); 2472 2473 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2474 |mut hal| async move { 2475 let cmd = UciCommand::RawUciCmd { 2476 mt: cmd_mt.into(), 2477 gid: gid.into(), 2478 oid: oid.into(), 2479 payload: cmd_payload_clone, 2480 }; 2481 let raw_resp = build_uci_packet(resp_mt, 0, gid, oid, resp_payload_clone); 2482 let mut responses = 2483 into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder { 2484 session_token, 2485 session_state: uwb_uci_packets::SessionState::SessionStateInit, 2486 reason_code: 2487 uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands 2488 .into(), 2489 }); 2490 responses.push(raw_resp); 2491 hal.expected_send_command(cmd, responses, Ok(())); 2492 }, 2493 UciLoggerMode::Disabled, 2494 mpsc::unbounded_channel::<UciLogEvent>().0, 2495 ) 2496 .await; 2497 2498 let expected_result = 2499 Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload }); 2500 let result = 2501 uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await; 2502 assert_eq!(result, expected_result); 2503 assert!(mock_hal.wait_expected_calls_done().await); 2504 } 2505 2506 #[tokio::test] test_raw_uci_cmd_uwbs_response_undefined_mt()2507 async fn test_raw_uci_cmd_uwbs_response_undefined_mt() { 2508 // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the 2509 // UCI HAL returns a UCI packet with an undefined MessageType in response. 2510 let cmd_mt: u8 = 0x1; 2511 let gid: u8 = 0x1; // Session Config. 2512 let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG 2513 let cmd_payload = vec![0x11, 0x22, 0x33, 0x44]; 2514 let cmd_payload_clone = cmd_payload.clone(); 2515 let resp_mt: u8 = 0x7; // Undefined MessageType 2516 let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; 2517 2518 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2519 |mut hal| async move { 2520 let cmd = UciCommand::RawUciCmd { 2521 mt: cmd_mt.into(), 2522 gid: gid.into(), 2523 oid: oid.into(), 2524 payload: cmd_payload_clone, 2525 }; 2526 let resp = build_uci_packet(resp_mt, /* pbf = */ 0, gid, oid, resp_payload); 2527 hal.expected_send_command(cmd, vec![resp], Ok(())); 2528 }, 2529 UciLoggerMode::Disabled, 2530 mpsc::unbounded_channel::<UciLogEvent>().0, 2531 ) 2532 .await; 2533 2534 let expected_result = Err(Error::Unknown); 2535 let result = 2536 uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await; 2537 assert_eq!(result, expected_result); 2538 assert!(mock_hal.wait_expected_calls_done().await); 2539 } 2540 2541 // TODO(b/276320369): Listing down the Data Packet Rx scenarios below, will add unit tests 2542 // for them in subsequent CLs. 2543 #[tokio::test] test_data_packet_recv_ok()2544 async fn test_data_packet_recv_ok() {} 2545 2546 #[tokio::test] test_data_packet_recv_fragmented_packet_ok()2547 async fn test_data_packet_recv_fragmented_packet_ok() {} 2548 setup_hal_for_session_active( hal: &mut MockUciHal, session_type: SessionType, session_id: u32, session_token: u32, )2549 fn setup_hal_for_session_active( 2550 hal: &mut MockUciHal, 2551 session_type: SessionType, 2552 session_id: u32, 2553 session_token: u32, 2554 ) { 2555 // Setup session init. 2556 setup_hal_for_session_initialize(hal, session_type, session_id, session_token); 2557 2558 // Setup session active. 2559 let cmd = UciCommand::SessionStart { session_token }; 2560 let mut responses = into_uci_hal_packets(uwb_uci_packets::SessionStartRspBuilder { 2561 status: uwb_uci_packets::StatusCode::UciStatusOk, 2562 }); 2563 responses.append(&mut into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder { 2564 session_token, 2565 session_state: SessionState::SessionStateActive, 2566 reason_code: 0, /* ReasonCode::StateChangeWithSessionManagementCommands */ 2567 })); 2568 hal.expected_send_command(cmd, responses, Ok(())); 2569 } 2570 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 = ()>,2571 async fn setup_uci_manager_with_session_active<F, Fut>( 2572 setup_hal_fn: F, 2573 uci_logger_mode: UciLoggerMode, 2574 log_sender: mpsc::UnboundedSender<UciLogEvent>, 2575 session_id: u32, 2576 session_token: u32, 2577 ) -> (UciManagerImpl, MockUciHal) 2578 where 2579 F: FnOnce(MockUciHal) -> Fut, 2580 Fut: Future<Output = ()>, 2581 { 2582 let session_type = SessionType::FiraRangingSession; 2583 2584 init_test_logging(); 2585 2586 let mut hal = MockUciHal::new(); 2587 setup_hal_for_session_active(&mut hal, session_type, session_id, session_token); 2588 2589 // Verify open_hal() is working. 2590 let uci_manager = 2591 UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode); 2592 let result = uci_manager.open_hal().await; 2593 assert!(result.is_ok()); 2594 2595 // Verify session is initialized. 2596 let result = uci_manager.session_init(session_id, session_type).await; 2597 assert!(result.is_ok()); 2598 2599 // Verify session is started. 2600 let result = uci_manager.range_start(session_id).await; 2601 assert!(result.is_ok()); 2602 assert!(hal.wait_expected_calls_done().await); 2603 2604 setup_hal_fn(hal.clone()).await; 2605 2606 (uci_manager, hal) 2607 } 2608 2609 #[tokio::test] test_data_packet_send_ok()2610 async fn test_data_packet_send_ok() { 2611 // Test Data packet send for a single packet (on a UWB session). 2612 let mt_data = 0x0; 2613 let pbf = 0x0; 2614 let dpf = 0x1; 2615 let oid = 0x0; 2616 let session_id = 0x5; 2617 let session_token = 0x5; 2618 let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1]; 2619 let dest_fira_component = FiraComponent::Host; 2620 let uci_sequence_number = 0xa; 2621 let app_data = vec![0x01, 0x02, 0x03]; 2622 let expected_data_snd_payload = vec![ 2623 0x05, 0x00, 0x00, 0x00, // SessionID 2624 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 2625 0x01, // FiraComponent 2626 0x0a, // UciSequenceNumber 2627 0x03, 0x00, // AppDataLen 2628 0x01, 0x02, 0x03, // AppData 2629 ]; 2630 let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk; 2631 2632 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 2633 |mut hal| async move { 2634 // Now setup the notifications that should be received after a Data packet send. 2635 let data_packet_snd = 2636 build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload); 2637 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 2638 session_token, 2639 credit_availability: CreditAvailability::CreditAvailable, 2640 }); 2641 ntfs.append(&mut into_uci_hal_packets( 2642 uwb_uci_packets::DataTransferStatusNtfBuilder { 2643 session_token, 2644 uci_sequence_number, 2645 status, 2646 }, 2647 )); 2648 hal.expected_send_packet(data_packet_snd, ntfs, Ok(())); 2649 }, 2650 UciLoggerMode::Disabled, 2651 mpsc::unbounded_channel::<UciLogEvent>().0, 2652 session_id, 2653 session_token, 2654 ) 2655 .await; 2656 2657 let result = uci_manager 2658 .send_data_packet( 2659 session_id, 2660 dest_mac_address, 2661 dest_fira_component, 2662 uci_sequence_number, 2663 app_data, 2664 ) 2665 .await; 2666 assert!(result.is_ok()); 2667 assert!(mock_hal.wait_expected_calls_done().await); 2668 2669 // TODO(b/276320369): Verify that session_notf_sender is called (once implemented), as a 2670 // DataTransferStatusNtf is received in this test scenario. 2671 } 2672 2673 #[tokio::test] test_data_packet_send_fragmented_packet_ok()2674 async fn test_data_packet_send_fragmented_packet_ok() { 2675 // Test Data packet send for a set of data packet fragments (on a UWB session). 2676 let mt_data = 0x0; 2677 let pbf_fragment_1 = 0x1; 2678 let pbf_fragment_2 = 0x0; 2679 let dpf = 0x1; 2680 let oid = 0x0; 2681 let session_id = 0x5; 2682 let session_token = 0x5; 2683 let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1]; 2684 let dest_fira_component = FiraComponent::Host; 2685 let uci_sequence_number = 0xa; 2686 let app_data_len = 300; // Larger than MAX_PAYLOAD_LEN=255, so fragmentation occurs. 2687 let mut app_data = Vec::new(); 2688 let mut expected_data_snd_payload_fragment_1 = vec![ 2689 0x05, 0x00, 0x00, 0x00, // SessionID 2690 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 2691 0x01, // FiraComponent 2692 0x0a, // UciSequenceNumber 2693 0x2c, 0x01, // AppDataLen = 300 2694 ]; 2695 let mut expected_data_snd_payload_fragment_2 = Vec::new(); 2696 let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk; 2697 2698 // Setup the app data for both the Tx data packet and expected packet fragments. 2699 let app_data_len_fragment_1 = 255 - expected_data_snd_payload_fragment_1.len(); 2700 for i in 0..app_data_len { 2701 app_data.push((i & 0xff).try_into().unwrap()); 2702 if i < app_data_len_fragment_1 { 2703 expected_data_snd_payload_fragment_1.push((i & 0xff).try_into().unwrap()); 2704 } else { 2705 expected_data_snd_payload_fragment_2.push((i & 0xff).try_into().unwrap()); 2706 } 2707 } 2708 2709 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 2710 |mut hal| async move { 2711 // Expected data packet fragment #1 (UCI Header + Initial App data bytes). 2712 let data_packet_snd_fragment_1 = build_uci_packet( 2713 mt_data, 2714 pbf_fragment_1, 2715 dpf, 2716 oid, 2717 expected_data_snd_payload_fragment_1, 2718 ); 2719 let ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 2720 session_token, 2721 credit_availability: CreditAvailability::CreditAvailable, 2722 }); 2723 hal.expected_send_packet(data_packet_snd_fragment_1, ntfs, Ok(())); 2724 2725 // Expected data packet fragment #2 (UCI Header + Remaining App data bytes). 2726 let data_packet_snd_fragment_2 = build_uci_packet( 2727 mt_data, 2728 pbf_fragment_2, 2729 dpf, 2730 oid, 2731 expected_data_snd_payload_fragment_2, 2732 ); 2733 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 2734 session_token, 2735 credit_availability: CreditAvailability::CreditAvailable, 2736 }); 2737 ntfs.append(&mut into_uci_hal_packets( 2738 uwb_uci_packets::DataTransferStatusNtfBuilder { 2739 session_token, 2740 uci_sequence_number, 2741 status, 2742 }, 2743 )); 2744 hal.expected_send_packet(data_packet_snd_fragment_2, ntfs, Ok(())); 2745 }, 2746 UciLoggerMode::Disabled, 2747 mpsc::unbounded_channel::<UciLogEvent>().0, 2748 session_id, 2749 session_token, 2750 ) 2751 .await; 2752 2753 let result = uci_manager 2754 .send_data_packet( 2755 session_id, 2756 dest_mac_address, 2757 dest_fira_component, 2758 uci_sequence_number, 2759 app_data, 2760 ) 2761 .await; 2762 assert!(result.is_ok()); 2763 assert!(mock_hal.wait_expected_calls_done().await); 2764 } 2765 2766 #[tokio::test] test_data_packet_send_retry_ok()2767 async fn test_data_packet_send_retry_ok() { 2768 // Test Data packet send for a single packet (on a UWB session). 2769 let mt_data = 0x0; 2770 let pbf = 0x0; 2771 let dpf = 0x1; 2772 let oid = 0x0; 2773 let session_id = 0x5; 2774 let session_token = 0x5; 2775 let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1]; 2776 let dest_fira_component = FiraComponent::Host; 2777 let uci_sequence_number = 0xa; 2778 let app_data = vec![0x01, 0x02, 0x03]; 2779 let expected_data_snd_payload = vec![ 2780 0x05, 0x00, 0x00, 0x00, // SessionID 2781 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 2782 0x01, // FiraComponent 2783 0x0a, // UciSequenceNumber 2784 0x03, 0x00, // AppDataLen 2785 0x01, 0x02, 0x03, // AppData 2786 ]; 2787 let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk; 2788 2789 let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( 2790 |mut hal| async move { 2791 // Setup receiving a CORE_GENERIC_ERROR_NTF with STATUS_COMMAND_RETRY after a 2792 // failed Data packet send attempt. 2793 let data_packet_snd = 2794 build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload); 2795 let error_ntf = into_uci_hal_packets(uwb_uci_packets::GenericErrorBuilder { 2796 status: StatusCode::UciStatusCommandRetry, 2797 }); 2798 hal.expected_send_packet(data_packet_snd.clone(), error_ntf, Ok(())); 2799 2800 // Setup the notifications that should be received after the Data packet send 2801 // is successfully retried. 2802 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder { 2803 session_token, 2804 credit_availability: CreditAvailability::CreditAvailable, 2805 }); 2806 ntfs.append(&mut into_uci_hal_packets( 2807 uwb_uci_packets::DataTransferStatusNtfBuilder { 2808 session_token, 2809 uci_sequence_number, 2810 status, 2811 }, 2812 )); 2813 hal.expected_send_packet(data_packet_snd, ntfs, Ok(())); 2814 }, 2815 UciLoggerMode::Disabled, 2816 mpsc::unbounded_channel::<UciLogEvent>().0, 2817 session_id, 2818 session_token, 2819 ) 2820 .await; 2821 2822 let result = uci_manager 2823 .send_data_packet( 2824 session_id, 2825 dest_mac_address, 2826 dest_fira_component, 2827 uci_sequence_number, 2828 app_data, 2829 ) 2830 .await; 2831 assert!(result.is_ok()); 2832 assert!(mock_hal.wait_expected_calls_done().await); 2833 2834 // TODO(b/276320369): Verify that session_notf_sender is called (once implemented), as a 2835 // DataTransferStatusNtf is received in this test scenario. 2836 } 2837 2838 // TODO(b/276320369): Listing down the Data Packet Tx scenarios below, will add unit tests 2839 // for them in subsequent CLs. 2840 2841 // Sending one data packet should succeed, when no DataCreditNtf is received. 2842 #[tokio::test] test_data_packet_send_missing_data_credit_ntf_success()2843 async fn test_data_packet_send_missing_data_credit_ntf_success() {} 2844 2845 // Sending the second data packet should fail, when no DataCreditNtf is received after 2846 // sending the first data packet. 2847 #[tokio::test] test_data_packet_send_missing_data_credit_ntf_subsequent_send_failure()2848 async fn test_data_packet_send_missing_data_credit_ntf_subsequent_send_failure() {} 2849 2850 #[tokio::test] test_data_packet_send_data_credit_ntf_bad_session_id()2851 async fn test_data_packet_send_data_credit_ntf_bad_session_id() {} 2852 2853 #[tokio::test] test_data_packet_send_data_credit_ntf_no_credit_available()2854 async fn test_data_packet_send_data_credit_ntf_no_credit_available() {} 2855 2856 #[tokio::test] test_data_packet_send_missing_data_transfer_status_ntf()2857 async fn test_data_packet_send_missing_data_transfer_status_ntf() {} 2858 2859 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_bad_session_id()2860 async fn test_data_packet_send_data_transfer_status_ntf_bad_session_id() {} 2861 2862 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_bad_uci_sequence_number()2863 async fn test_data_packet_send_data_transfer_status_ntf_bad_uci_sequence_number() {} 2864 2865 // Tests for the multiple Status values that indicate success 2866 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_status_ok()2867 async fn test_data_packet_send_data_transfer_status_ntf_status_ok() {} 2868 2869 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_status_repetition_ok()2870 async fn test_data_packet_send_data_transfer_status_ntf_status_repetition_ok() {} 2871 2872 // Tests for some of the multiple Status values that indicate error. 2873 #[tokio::test] test_data_packet_send_data_transfer_status_ntf_status_error()2874 async fn test_data_packet_send_data_transfer_status_ntf_status_error() {} 2875 2876 #[tokio::test] test_session_get_count_retry_no_response()2877 async fn test_session_get_count_retry_no_response() { 2878 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2879 |mut hal| async move { 2880 let cmd = UciCommand::SessionGetCount; 2881 hal.expected_send_command(cmd, vec![], Ok(())); 2882 }, 2883 UciLoggerMode::Disabled, 2884 mpsc::unbounded_channel::<UciLogEvent>().0, 2885 ) 2886 .await; 2887 2888 let result = uci_manager.session_get_count().await; 2889 assert!(matches!(result, Err(Error::Timeout))); 2890 assert!(mock_hal.wait_expected_calls_done().await); 2891 } 2892 2893 #[tokio::test] test_session_get_count_timeout()2894 async fn test_session_get_count_timeout() { 2895 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2896 |mut hal| async move { 2897 let cmd = UciCommand::SessionGetCount; 2898 hal.expected_send_command(cmd, vec![], Err(Error::Timeout)); 2899 }, 2900 UciLoggerMode::Disabled, 2901 mpsc::unbounded_channel::<UciLogEvent>().0, 2902 ) 2903 .await; 2904 2905 let result = uci_manager.session_get_count().await; 2906 assert!(matches!(result, Err(Error::Timeout))); 2907 assert!(mock_hal.wait_expected_calls_done().await); 2908 } 2909 2910 #[tokio::test] test_session_get_count_retry_too_many_times()2911 async fn test_session_get_count_retry_too_many_times() { 2912 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2913 |mut hal| async move { 2914 let cmd = UciCommand::SessionGetCount; 2915 let retry_resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 2916 status: uwb_uci_packets::StatusCode::UciStatusCommandRetry, 2917 session_count: 0, 2918 }); 2919 2920 for _ in 0..MAX_RETRY_COUNT { 2921 hal.expected_send_command(cmd.clone(), retry_resp.clone(), Ok(())); 2922 } 2923 }, 2924 UciLoggerMode::Disabled, 2925 mpsc::unbounded_channel::<UciLogEvent>().0, 2926 ) 2927 .await; 2928 2929 let result = uci_manager.session_get_count().await; 2930 assert!(matches!(result, Err(Error::Timeout))); 2931 assert!(mock_hal.wait_expected_calls_done().await); 2932 } 2933 2934 #[tokio::test] test_session_get_count_retry_notification()2935 async fn test_session_get_count_retry_notification() { 2936 let session_count = 5; 2937 2938 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2939 |mut hal| async move { 2940 let cmd = UciCommand::SessionGetCount; 2941 let retry_resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 2942 status: uwb_uci_packets::StatusCode::UciStatusCommandRetry, 2943 session_count: 0, 2944 }); 2945 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 2946 status: uwb_uci_packets::StatusCode::UciStatusOk, 2947 session_count, 2948 }); 2949 2950 hal.expected_send_command(cmd.clone(), retry_resp.clone(), Ok(())); 2951 hal.expected_send_command(cmd.clone(), retry_resp, Ok(())); 2952 hal.expected_send_command(cmd, resp, Ok(())); 2953 }, 2954 UciLoggerMode::Disabled, 2955 mpsc::unbounded_channel::<UciLogEvent>().0, 2956 ) 2957 .await; 2958 2959 let result = uci_manager.session_get_count().await.unwrap(); 2960 assert_eq!(result, session_count); 2961 assert!(mock_hal.wait_expected_calls_done().await); 2962 } 2963 2964 #[tokio::test] test_log_manager_interaction()2965 async fn test_log_manager_interaction() { 2966 let (log_sender, mut log_receiver) = mpsc::unbounded_channel::<UciLogEvent>(); 2967 let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( 2968 |mut hal| async move { 2969 let cmd = UciCommand::SessionGetCount; 2970 let resp1 = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 2971 status: uwb_uci_packets::StatusCode::UciStatusOk, 2972 session_count: 1, 2973 }); 2974 let resp2 = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { 2975 status: uwb_uci_packets::StatusCode::UciStatusOk, 2976 session_count: 2, 2977 }); 2978 hal.expected_send_command(cmd.clone(), resp1, Ok(())); 2979 hal.expected_send_command(cmd, resp2, Ok(())); 2980 }, 2981 UciLoggerMode::Disabled, 2982 log_sender, 2983 ) 2984 .await; 2985 2986 // Under Disabled mode, initialization and first command and response are not logged. 2987 uci_manager.session_get_count().await.unwrap(); 2988 assert!(log_receiver.try_recv().is_err()); 2989 2990 // Second command and response after change in logger mode are logged. 2991 uci_manager.set_logger_mode(UciLoggerMode::Filtered).await.unwrap(); 2992 uci_manager.session_get_count().await.unwrap(); 2993 let packet: Vec<u8> = log_receiver.recv().await.unwrap().try_into().unwrap(); 2994 let cmd_packet: Vec<u8> = SessionGetCountCmdBuilder {}.build().into(); 2995 assert_eq!(&packet, &cmd_packet); 2996 let packet: Vec<u8> = log_receiver.recv().await.unwrap().try_into().unwrap(); 2997 let rsp_packet: Vec<u8> = 2998 SessionGetCountRspBuilder { status: StatusCode::UciStatusOk, session_count: 2 } 2999 .build() 3000 .into(); 3001 assert_eq!(&packet, &rsp_packet); 3002 3003 assert!(mock_hal.wait_expected_calls_done().await); 3004 } 3005 } 3006