1 // Copyright 2022, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! This module offers a synchornized interface at UCI level. 16 //! 17 //! The module is designed with the replacement for Android UCI JNI adaptation in mind. The handling 18 //! of UciNotifications is different in UciManager and UciManagerSyncImpl as the sync version has 19 //! its behavior aligned with the Android JNI UCI, and routes the UciNotifications to 20 //! NotificationManager. 21 22 use log::{debug, error}; 23 use tokio::runtime::{Builder as RuntimeBuilder, Handle}; 24 use tokio::sync::mpsc; 25 use tokio::task; 26 27 use crate::error::{Error, Result}; 28 use crate::params::{ 29 AndroidRadarConfigResponse, AppConfigTlv, AppConfigTlvType, CapTlv, CoreSetConfigResponse, 30 CountryCode, DeviceConfigId, DeviceConfigTlv, GetDeviceInfoResponse, PowerStats, 31 RadarConfigTlv, RadarConfigTlvType, RawUciMessage, ResetConfig, RfTestConfigResponse, 32 RfTestConfigTlv, SessionId, SessionState, SessionType, 33 SessionUpdateControllerMulticastResponse, SessionUpdateDtTagRangingRoundsResponse, 34 SetAppConfigResponse, UpdateMulticastListAction, UpdateTime, 35 }; 36 #[cfg(any(test, feature = "mock-utils"))] 37 use crate::uci::mock_uci_manager::MockUciManager; 38 use crate::uci::notification::{ 39 CoreNotification, DataRcvNotification, RadarDataRcvNotification, RfTestNotification, 40 SessionNotification, 41 }; 42 use crate::uci::uci_hal::UciHal; 43 use crate::uci::uci_logger::{UciLogger, UciLoggerMode}; 44 use crate::uci::uci_manager::{UciManager, UciManagerImpl}; 45 use uwb_uci_packets::{ControleePhaseList, Controlees, PhaseList}; 46 47 /// The NotificationManager processes UciNotification relayed from UciManagerSync in a sync fashion. 48 /// The UciManagerSync assumes the NotificationManager takes the responsibility to properly handle 49 /// the notifications, including tracking the state of HAL. UciManagerSync and lower levels only 50 /// redirect and categorize the notifications. The notifications are processed through callbacks. 51 /// NotificationManager can be !Send and !Sync, as interfacing with other programs may require. 52 pub trait NotificationManager: 'static { 53 /// Callback for CoreNotification. on_core_notification(&mut self, core_notification: CoreNotification) -> Result<()>54 fn on_core_notification(&mut self, core_notification: CoreNotification) -> Result<()>; 55 56 /// Callback for SessionNotification. on_session_notification(&mut self, session_notification: SessionNotification) -> Result<()>57 fn on_session_notification(&mut self, session_notification: SessionNotification) -> Result<()>; 58 59 /// Callback for RawUciMessage. on_vendor_notification(&mut self, vendor_notification: RawUciMessage) -> Result<()>60 fn on_vendor_notification(&mut self, vendor_notification: RawUciMessage) -> Result<()>; 61 62 /// Callback for DataRcvNotification. on_data_rcv_notification( &mut self, data_rcv_notification: DataRcvNotification, ) -> Result<()>63 fn on_data_rcv_notification( 64 &mut self, 65 data_rcv_notification: DataRcvNotification, 66 ) -> Result<()>; 67 68 /// Callback for RadarDataRcvNotification. on_radar_data_rcv_notification( &mut self, radar_data_rcv_notification: RadarDataRcvNotification, ) -> Result<()>69 fn on_radar_data_rcv_notification( 70 &mut self, 71 radar_data_rcv_notification: RadarDataRcvNotification, 72 ) -> Result<()>; 73 74 /// Callback for RF Test notification. on_rf_test_notification(&mut self, rftest_notification: RfTestNotification) -> Result<()>75 fn on_rf_test_notification(&mut self, rftest_notification: RfTestNotification) -> Result<()>; 76 } 77 78 /// Builder for NotificationManager. Builder is sent between threads. 79 pub trait NotificationManagerBuilder: 'static + Send + Sync { 80 /// Type of NotificationManager built. 81 type NotificationManager: NotificationManager; 82 /// Builds NotificationManager. The build operation Consumes Builder. build(self) -> Option<Self::NotificationManager>83 fn build(self) -> Option<Self::NotificationManager>; 84 } 85 86 struct NotificationDriver<U: NotificationManager> { 87 core_notification_receiver: mpsc::UnboundedReceiver<CoreNotification>, 88 session_notification_receiver: mpsc::UnboundedReceiver<SessionNotification>, 89 vendor_notification_receiver: mpsc::UnboundedReceiver<RawUciMessage>, 90 data_rcv_notification_receiver: mpsc::UnboundedReceiver<DataRcvNotification>, 91 radar_data_rcv_notification_receiver: mpsc::UnboundedReceiver<RadarDataRcvNotification>, 92 rf_test_notification_receiver: mpsc::UnboundedReceiver<RfTestNotification>, 93 notification_manager: U, 94 } 95 impl<U: NotificationManager> NotificationDriver<U> { new( core_notification_receiver: mpsc::UnboundedReceiver<CoreNotification>, session_notification_receiver: mpsc::UnboundedReceiver<SessionNotification>, vendor_notification_receiver: mpsc::UnboundedReceiver<RawUciMessage>, data_rcv_notification_receiver: mpsc::UnboundedReceiver<DataRcvNotification>, radar_data_rcv_notification_receiver: mpsc::UnboundedReceiver<RadarDataRcvNotification>, rf_test_notification_receiver: mpsc::UnboundedReceiver<RfTestNotification>, notification_manager: U, ) -> Self96 fn new( 97 core_notification_receiver: mpsc::UnboundedReceiver<CoreNotification>, 98 session_notification_receiver: mpsc::UnboundedReceiver<SessionNotification>, 99 vendor_notification_receiver: mpsc::UnboundedReceiver<RawUciMessage>, 100 data_rcv_notification_receiver: mpsc::UnboundedReceiver<DataRcvNotification>, 101 radar_data_rcv_notification_receiver: mpsc::UnboundedReceiver<RadarDataRcvNotification>, 102 rf_test_notification_receiver: mpsc::UnboundedReceiver<RfTestNotification>, 103 notification_manager: U, 104 ) -> Self { 105 Self { 106 core_notification_receiver, 107 session_notification_receiver, 108 vendor_notification_receiver, 109 data_rcv_notification_receiver, 110 radar_data_rcv_notification_receiver, 111 rf_test_notification_receiver, 112 notification_manager, 113 } 114 } run(&mut self)115 async fn run(&mut self) { 116 loop { 117 tokio::select! { 118 Some(ntf) = self.core_notification_receiver.recv() =>{ 119 self.notification_manager.on_core_notification(ntf).unwrap_or_else(|e|{ 120 error!("NotificationDriver: CoreNotification callback error: {:?}",e); 121 }); 122 } 123 Some(ntf) = self.session_notification_receiver.recv() =>{ 124 self.notification_manager.on_session_notification(ntf).unwrap_or_else(|e|{ 125 error!("NotificationDriver: SessionNotification callback error: {:?}",e); 126 }); 127 } 128 Some(ntf) = self.vendor_notification_receiver.recv() =>{ 129 self.notification_manager.on_vendor_notification(ntf).unwrap_or_else(|e|{ 130 error!("NotificationDriver: RawUciMessage callback error: {:?}",e); 131 }); 132 } 133 Some(data) = self.data_rcv_notification_receiver.recv() =>{ 134 self.notification_manager.on_data_rcv_notification(data).unwrap_or_else(|e|{ 135 error!("NotificationDriver: OnDataRcv callback error: {:?}",e); 136 }); 137 } 138 Some(data) = self.radar_data_rcv_notification_receiver.recv() =>{ 139 self.notification_manager.on_radar_data_rcv_notification(data).unwrap_or_else(|e|{ 140 error!("NotificationDriver: OnRadarDataRcv callback error: {:?}",e); 141 }); 142 } 143 Some(ntf) = self.rf_test_notification_receiver.recv() =>{ 144 self.notification_manager.on_rf_test_notification(ntf).unwrap_or_else(|e|{ 145 error!("NotificationDriver: RF notification callback error: {:?}",e); 146 }); 147 } 148 else =>{ 149 debug!("NotificationDriver dropping."); 150 break; 151 } 152 } 153 } 154 } 155 } 156 157 /// The UciManagerSync provides a synchornized version of UciManager. 158 /// 159 /// Note the processing of UciNotification is different: 160 /// set_X_notification_sender methods are removed. Instead, the method 161 /// redirect_notification(NotificationManagerBuilder) is introduced to avoid the 162 /// exposure of async tokio::mpsc. 163 pub struct UciManagerSync<U: UciManager> { 164 runtime_handle: Handle, 165 uci_manager: U, 166 } 167 impl<U: UciManager> UciManagerSync<U> { 168 /// Redirects notification to a new NotificationManager using the notification_manager_builder. 169 /// The NotificationManager will live on a separate thread. redirect_notification<T: NotificationManagerBuilder>( &mut self, notification_manager_builder: T, ) -> Result<()>170 pub fn redirect_notification<T: NotificationManagerBuilder>( 171 &mut self, 172 notification_manager_builder: T, 173 ) -> Result<()> { 174 let (core_notification_sender, core_notification_receiver) = 175 mpsc::unbounded_channel::<CoreNotification>(); 176 let (session_notification_sender, session_notification_receiver) = 177 mpsc::unbounded_channel::<SessionNotification>(); 178 let (vendor_notification_sender, vendor_notification_receiver) = 179 mpsc::unbounded_channel::<RawUciMessage>(); 180 let (data_rcv_notification_sender, data_rcv_notification_receiver) = 181 mpsc::unbounded_channel::<DataRcvNotification>(); 182 let (radar_data_rcv_notification_sender, radar_data_rcv_notification_receiver) = 183 mpsc::unbounded_channel::<RadarDataRcvNotification>(); 184 let (rftest_notification_sender, rf_test_notification_receiver) = 185 mpsc::unbounded_channel::<RfTestNotification>(); 186 self.runtime_handle.to_owned().block_on(async { 187 self.uci_manager.set_core_notification_sender(core_notification_sender).await; 188 self.uci_manager.set_session_notification_sender(session_notification_sender).await; 189 self.uci_manager.set_vendor_notification_sender(vendor_notification_sender).await; 190 self.uci_manager.set_data_rcv_notification_sender(data_rcv_notification_sender).await; 191 self.uci_manager 192 .set_radar_data_rcv_notification_sender(radar_data_rcv_notification_sender) 193 .await; 194 self.uci_manager.set_rf_test_notification_sender(rftest_notification_sender).await; 195 }); 196 // The potentially !Send NotificationManager is created in a separate thread. 197 let (driver_status_sender, mut driver_status_receiver) = mpsc::unbounded_channel::<bool>(); 198 std::thread::spawn(move || { 199 let notification_runtime = 200 match RuntimeBuilder::new_current_thread().enable_all().build() { 201 Ok(nr) => nr, 202 Err(_) => { 203 // unwrap safe since receiver is in scope 204 driver_status_sender.send(false).unwrap(); 205 return; 206 } 207 }; 208 209 let local = task::LocalSet::new(); 210 let notification_manager = match notification_manager_builder.build() { 211 Some(nm) => { 212 // unwrap safe since receiver is in scope 213 driver_status_sender.send(true).unwrap(); 214 nm 215 } 216 None => { 217 // unwrap safe since receiver is in scope 218 driver_status_sender.send(false).unwrap(); 219 return; 220 } 221 }; 222 let mut notification_driver = NotificationDriver::new( 223 core_notification_receiver, 224 session_notification_receiver, 225 vendor_notification_receiver, 226 data_rcv_notification_receiver, 227 radar_data_rcv_notification_receiver, 228 rf_test_notification_receiver, 229 notification_manager, 230 ); 231 local.spawn_local(async move { 232 task::spawn_local(async move { notification_driver.run().await }).await.unwrap(); 233 }); 234 notification_runtime.block_on(local); 235 }); 236 match driver_status_receiver.blocking_recv() { 237 Some(true) => Ok(()), 238 _ => Err(Error::Unknown), 239 } 240 } 241 242 /// Set logger mode. set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>243 pub fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()> { 244 self.runtime_handle.block_on(self.uci_manager.set_logger_mode(logger_mode)) 245 } 246 /// Start UCI HAL and blocking until UCI commands can be sent. open_hal(&self) -> Result<GetDeviceInfoResponse>247 pub fn open_hal(&self) -> Result<GetDeviceInfoResponse> { 248 self.runtime_handle.block_on(self.uci_manager.open_hal()) 249 } 250 251 /// Stop the UCI HAL. close_hal(&self, force: bool) -> Result<()>252 pub fn close_hal(&self, force: bool) -> Result<()> { 253 self.runtime_handle.block_on(self.uci_manager.close_hal(force)) 254 } 255 256 // Methods for sending UCI commands. Functions are blocked until UCI response is received. 257 /// Send UCI command for device reset. device_reset(&self, reset_config: ResetConfig) -> Result<()>258 pub fn device_reset(&self, reset_config: ResetConfig) -> Result<()> { 259 self.runtime_handle.block_on(self.uci_manager.device_reset(reset_config)) 260 } 261 262 /// Send UCI command for getting device info. core_get_device_info(&self) -> Result<GetDeviceInfoResponse>263 pub fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse> { 264 self.runtime_handle.block_on(self.uci_manager.core_get_device_info()) 265 } 266 267 /// Send UCI command for getting capability info core_get_caps_info(&self) -> Result<Vec<CapTlv>>268 pub fn core_get_caps_info(&self) -> Result<Vec<CapTlv>> { 269 self.runtime_handle.block_on(self.uci_manager.core_get_caps_info()) 270 } 271 272 /// Send UCI command for setting core configuration. core_set_config( &self, config_tlvs: Vec<DeviceConfigTlv>, ) -> Result<CoreSetConfigResponse>273 pub fn core_set_config( 274 &self, 275 config_tlvs: Vec<DeviceConfigTlv>, 276 ) -> Result<CoreSetConfigResponse> { 277 self.runtime_handle.block_on(self.uci_manager.core_set_config(config_tlvs)) 278 } 279 280 /// Send UCI command for getting core configuration. core_get_config(&self, config_ids: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>>281 pub fn core_get_config(&self, config_ids: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>> { 282 self.runtime_handle.block_on(self.uci_manager.core_get_config(config_ids)) 283 } 284 285 /// Send UCI command for getting uwbs timestamp. core_query_uwb_timestamp(&self) -> Result<u64>286 pub fn core_query_uwb_timestamp(&self) -> Result<u64> { 287 self.runtime_handle.block_on(self.uci_manager.core_query_uwb_timestamp()) 288 } 289 290 /// Send UCI command for initiating session. session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>291 pub fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()> { 292 self.runtime_handle.block_on(self.uci_manager.session_init(session_id, session_type)) 293 } 294 295 /// Send UCI command for deinitiating session. session_deinit(&self, session_id: SessionId) -> Result<()>296 pub fn session_deinit(&self, session_id: SessionId) -> Result<()> { 297 self.runtime_handle.block_on(self.uci_manager.session_deinit(session_id)) 298 } 299 300 /// Send UCI command for setting app config. session_set_app_config( &self, session_id: SessionId, config_tlvs: Vec<AppConfigTlv>, ) -> Result<SetAppConfigResponse>301 pub fn session_set_app_config( 302 &self, 303 session_id: SessionId, 304 config_tlvs: Vec<AppConfigTlv>, 305 ) -> Result<SetAppConfigResponse> { 306 self.runtime_handle 307 .block_on(self.uci_manager.session_set_app_config(session_id, config_tlvs)) 308 } 309 310 /// Send UCI command for getting app config. session_get_app_config( &self, session_id: SessionId, config_ids: Vec<AppConfigTlvType>, ) -> Result<Vec<AppConfigTlv>>311 pub fn session_get_app_config( 312 &self, 313 session_id: SessionId, 314 config_ids: Vec<AppConfigTlvType>, 315 ) -> Result<Vec<AppConfigTlv>> { 316 self.runtime_handle 317 .block_on(self.uci_manager.session_get_app_config(session_id, config_ids)) 318 } 319 320 /// Send UCI command for getting count of sessions. session_get_count(&self) -> Result<u8>321 pub fn session_get_count(&self) -> Result<u8> { 322 self.runtime_handle.block_on(self.uci_manager.session_get_count()) 323 } 324 325 /// Send UCI command for getting state of session. session_get_state(&self, session_id: SessionId) -> Result<SessionState>326 pub fn session_get_state(&self, session_id: SessionId) -> Result<SessionState> { 327 self.runtime_handle.block_on(self.uci_manager.session_get_state(session_id)) 328 } 329 330 /// Send UCI command for updating multicast list for multicast session. session_update_controller_multicast_list( &self, session_id: SessionId, action: UpdateMulticastListAction, controlees: Controlees, is_multicast_list_ntf_v2_supported: bool, is_multicast_list_rsp_v2_supported: bool, ) -> Result<SessionUpdateControllerMulticastResponse>331 pub fn session_update_controller_multicast_list( 332 &self, 333 session_id: SessionId, 334 action: UpdateMulticastListAction, 335 controlees: Controlees, 336 is_multicast_list_ntf_v2_supported: bool, 337 is_multicast_list_rsp_v2_supported: bool, 338 ) -> Result<SessionUpdateControllerMulticastResponse> { 339 self.runtime_handle.block_on(self.uci_manager.session_update_controller_multicast_list( 340 session_id, 341 action, 342 controlees, 343 is_multicast_list_ntf_v2_supported, 344 is_multicast_list_rsp_v2_supported, 345 )) 346 } 347 348 /// Update ranging rounds for DT Tag session_update_dt_tag_ranging_rounds( &self, session_id: u32, ranging_round_indexes: Vec<u8>, ) -> Result<SessionUpdateDtTagRangingRoundsResponse>349 pub fn session_update_dt_tag_ranging_rounds( 350 &self, 351 session_id: u32, 352 ranging_round_indexes: Vec<u8>, 353 ) -> Result<SessionUpdateDtTagRangingRoundsResponse> { 354 self.runtime_handle.block_on( 355 self.uci_manager 356 .session_update_dt_tag_ranging_rounds(session_id, ranging_round_indexes), 357 ) 358 } 359 360 /// Send UCI command for getting max data size for session. session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>361 pub fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16> { 362 self.runtime_handle.block_on(self.uci_manager.session_query_max_data_size(session_id)) 363 } 364 365 /// Send UCI command for starting ranging of the session. range_start(&self, session_id: SessionId) -> Result<()>366 pub fn range_start(&self, session_id: SessionId) -> Result<()> { 367 self.runtime_handle.block_on(self.uci_manager.range_start(session_id)) 368 } 369 370 /// Send UCI command for stopping ranging of the session. range_stop(&self, session_id: SessionId) -> Result<()>371 pub fn range_stop(&self, session_id: SessionId) -> Result<()> { 372 self.runtime_handle.block_on(self.uci_manager.range_stop(session_id)) 373 } 374 375 /// Send UCI command for getting ranging count. range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>376 pub fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize> { 377 self.runtime_handle.block_on(self.uci_manager.range_get_ranging_count(session_id)) 378 } 379 380 /// Set the country code. Android-specific method. android_set_country_code(&self, country_code: CountryCode) -> Result<()>381 pub fn android_set_country_code(&self, country_code: CountryCode) -> Result<()> { 382 self.runtime_handle.block_on(self.uci_manager.android_set_country_code(country_code)) 383 } 384 385 /// Get the power statistics. Android-specific method. android_get_power_stats(&self) -> Result<PowerStats>386 pub fn android_get_power_stats(&self) -> Result<PowerStats> { 387 self.runtime_handle.block_on(self.uci_manager.android_get_power_stats()) 388 } 389 390 /// Set radar config. Android-specific method. android_set_radar_config( &self, session_id: SessionId, config_tlvs: Vec<RadarConfigTlv>, ) -> Result<AndroidRadarConfigResponse>391 pub fn android_set_radar_config( 392 &self, 393 session_id: SessionId, 394 config_tlvs: Vec<RadarConfigTlv>, 395 ) -> Result<AndroidRadarConfigResponse> { 396 self.runtime_handle 397 .block_on(self.uci_manager.android_set_radar_config(session_id, config_tlvs)) 398 } 399 400 /// Get radar config. Android-specific method. android_get_radar_config( &self, session_id: SessionId, config_ids: Vec<RadarConfigTlvType>, ) -> Result<Vec<RadarConfigTlv>>401 pub fn android_get_radar_config( 402 &self, 403 session_id: SessionId, 404 config_ids: Vec<RadarConfigTlvType>, 405 ) -> Result<Vec<RadarConfigTlv>> { 406 self.runtime_handle 407 .block_on(self.uci_manager.android_get_radar_config(session_id, config_ids)) 408 } 409 410 /// Send a raw UCI command. raw_uci_cmd( &self, mt: u32, gid: u32, oid: u32, payload: Vec<u8>, ) -> Result<RawUciMessage>411 pub fn raw_uci_cmd( 412 &self, 413 mt: u32, 414 gid: u32, 415 oid: u32, 416 payload: Vec<u8>, 417 ) -> Result<RawUciMessage> { 418 self.runtime_handle.block_on(self.uci_manager.raw_uci_cmd(mt, gid, oid, payload)) 419 } 420 421 /// Send a data packet send_data_packet( &self, session_id: SessionId, address: Vec<u8>, uci_sequence_num: u16, app_payload_data: Vec<u8>, ) -> Result<()>422 pub fn send_data_packet( 423 &self, 424 session_id: SessionId, 425 address: Vec<u8>, 426 uci_sequence_num: u16, 427 app_payload_data: Vec<u8>, 428 ) -> Result<()> { 429 self.runtime_handle.block_on(self.uci_manager.send_data_packet( 430 session_id, 431 address, 432 uci_sequence_num, 433 app_payload_data, 434 )) 435 } 436 437 /// Get session token for session id. get_session_token(&self, session_id: SessionId) -> Result<u32>438 pub fn get_session_token(&self, session_id: SessionId) -> Result<u32> { 439 self.runtime_handle.block_on(self.uci_manager.get_session_token_from_session_id(session_id)) 440 } 441 442 /// Send UCI command for setting hybrid controller configuration session_set_hybrid_controller_config( &self, session_id: SessionId, message_control: u8, number_of_phases: u8, update_time: UpdateTime, phase_list: PhaseList, ) -> Result<()>443 pub fn session_set_hybrid_controller_config( 444 &self, 445 session_id: SessionId, 446 message_control: u8, 447 number_of_phases: u8, 448 update_time: UpdateTime, 449 phase_list: PhaseList, 450 ) -> Result<()> { 451 self.runtime_handle.block_on(self.uci_manager.session_set_hybrid_controller_config( 452 session_id, 453 message_control, 454 number_of_phases, 455 update_time, 456 phase_list, 457 )) 458 } 459 460 /// Send UCI command for setting hybrid controlee configuration session_set_hybrid_controlee_config( &self, session_id: SessionId, controlee_phase_list: Vec<ControleePhaseList>, ) -> Result<()>461 pub fn session_set_hybrid_controlee_config( 462 &self, 463 session_id: SessionId, 464 controlee_phase_list: Vec<ControleePhaseList>, 465 ) -> Result<()> { 466 self.runtime_handle.block_on( 467 self.uci_manager.session_set_hybrid_controlee_config(session_id, controlee_phase_list), 468 ) 469 } 470 471 /// Send UCI command for session data transfer phase config session_data_transfer_phase_config( &self, session_id: SessionId, dtpcm_repetition: u8, data_transfer_control: u8, dtpml_size: u8, mac_address: Vec<u8>, slot_bitmap: Vec<u8>, ) -> Result<()>472 pub fn session_data_transfer_phase_config( 473 &self, 474 session_id: SessionId, 475 dtpcm_repetition: u8, 476 data_transfer_control: u8, 477 dtpml_size: u8, 478 mac_address: Vec<u8>, 479 slot_bitmap: Vec<u8>, 480 ) -> Result<()> { 481 self.runtime_handle.block_on(self.uci_manager.session_data_transfer_phase_config( 482 session_id, 483 dtpcm_repetition, 484 data_transfer_control, 485 dtpml_size, 486 mac_address, 487 slot_bitmap, 488 )) 489 } 490 491 /// Set rf test config. session_set_rf_test_app_config( &self, session_id: SessionId, config_tlvs: Vec<RfTestConfigTlv>, ) -> Result<RfTestConfigResponse>492 pub fn session_set_rf_test_app_config( 493 &self, 494 session_id: SessionId, 495 config_tlvs: Vec<RfTestConfigTlv>, 496 ) -> Result<RfTestConfigResponse> { 497 self.runtime_handle 498 .block_on(self.uci_manager.session_set_rf_test_config(session_id, config_tlvs)) 499 } 500 501 /// Test Periodic tx command rf_test_periodic_tx(&self, psdu_data: Vec<u8>) -> Result<()>502 pub fn rf_test_periodic_tx(&self, psdu_data: Vec<u8>) -> Result<()> { 503 self.runtime_handle.block_on(self.uci_manager.rf_test_periodic_tx(psdu_data)) 504 } 505 506 /// Test stop rf test command stop_rf_test(&self) -> Result<()>507 pub fn stop_rf_test(&self) -> Result<()> { 508 self.runtime_handle.block_on(self.uci_manager.stop_rf_test()) 509 } 510 } 511 512 impl UciManagerSync<UciManagerImpl> { 513 /// Constructor. 514 /// 515 /// UciHal and NotificationManagerBuilder required at construction as they are required before 516 /// open_hal is called. runtime_handle must be a Handle to a multithread runtime that outlives 517 /// UciManagerSyncImpl. 518 /// 519 /// Implementation note: An explicit decision is made to not use UciManagerImpl as a parameter. 520 /// UciManagerImpl::new() appears to be sync, but needs an async context to be called, but the 521 /// user is unlikely to be aware of this technicality. new<H, B, L>( hal: H, notification_manager_builder: B, logger: L, logger_mode: UciLoggerMode, runtime_handle: Handle, ) -> Result<Self> where H: UciHal, B: NotificationManagerBuilder, L: UciLogger,522 pub fn new<H, B, L>( 523 hal: H, 524 notification_manager_builder: B, 525 logger: L, 526 logger_mode: UciLoggerMode, 527 runtime_handle: Handle, 528 ) -> Result<Self> 529 where 530 H: UciHal, 531 B: NotificationManagerBuilder, 532 L: UciLogger, 533 { 534 // UciManagerImpl::new uses tokio::spawn, so it is called inside the runtime as async fn. 535 let uci_manager = 536 runtime_handle.block_on(async { UciManagerImpl::new(hal, logger, logger_mode) }); 537 let mut uci_manager_sync = UciManagerSync { runtime_handle, uci_manager }; 538 uci_manager_sync.redirect_notification(notification_manager_builder)?; 539 Ok(uci_manager_sync) 540 } 541 } 542 543 #[cfg(any(test, feature = "mock-utils"))] 544 impl UciManagerSync<MockUciManager> { 545 /// Constructor for mock version. new_mock<T: NotificationManagerBuilder>( uci_manager: MockUciManager, runtime_handle: Handle, notification_manager_builder: T, ) -> Result<Self>546 pub fn new_mock<T: NotificationManagerBuilder>( 547 uci_manager: MockUciManager, 548 runtime_handle: Handle, 549 notification_manager_builder: T, 550 ) -> Result<Self> { 551 let mut uci_manager_sync = UciManagerSync { uci_manager, runtime_handle }; 552 uci_manager_sync.redirect_notification(notification_manager_builder)?; 553 Ok(uci_manager_sync) 554 } 555 } 556 557 #[cfg(test)] 558 mod tests { 559 use super::*; 560 561 use std::cell::RefCell; 562 use std::rc::Rc; 563 564 use tokio::runtime::Builder; 565 use uwb_uci_packets::DeviceState::DeviceStateReady; 566 567 use crate::params::uci_packets::GetDeviceInfoResponse; 568 use crate::uci::mock_uci_manager::MockUciManager; 569 use crate::uci::{CoreNotification, UciNotification}; 570 use uwb_uci_packets::StatusCode::UciStatusOk; 571 572 /// Mock NotificationManager forwarding notifications received. 573 /// The nonsend_counter is deliberately !send to check UciManagerSync::redirect_notification. 574 struct MockNotificationManager { 575 notf_sender: mpsc::UnboundedSender<UciNotification>, 576 // nonsend_counter is an example of a !Send property. 577 nonsend_counter: Rc<RefCell<usize>>, 578 } 579 580 impl NotificationManager for MockNotificationManager { on_core_notification(&mut self, core_notification: CoreNotification) -> Result<()>581 fn on_core_notification(&mut self, core_notification: CoreNotification) -> Result<()> { 582 self.nonsend_counter.replace_with(|&mut prev| prev + 1); 583 self.notf_sender 584 .send(UciNotification::Core(core_notification)) 585 .map_err(|_| Error::Unknown) 586 } on_session_notification( &mut self, session_notification: SessionNotification, ) -> Result<()>587 fn on_session_notification( 588 &mut self, 589 session_notification: SessionNotification, 590 ) -> Result<()> { 591 self.nonsend_counter.replace_with(|&mut prev| prev + 1); 592 self.notf_sender 593 .send(UciNotification::Session(session_notification)) 594 .map_err(|_| Error::Unknown) 595 } on_vendor_notification(&mut self, vendor_notification: RawUciMessage) -> Result<()>596 fn on_vendor_notification(&mut self, vendor_notification: RawUciMessage) -> Result<()> { 597 self.nonsend_counter.replace_with(|&mut prev| prev + 1); 598 self.notf_sender 599 .send(UciNotification::Vendor(vendor_notification)) 600 .map_err(|_| Error::Unknown) 601 } on_data_rcv_notification(&mut self, _data_rcv_notf: DataRcvNotification) -> Result<()>602 fn on_data_rcv_notification(&mut self, _data_rcv_notf: DataRcvNotification) -> Result<()> { 603 self.nonsend_counter.replace_with(|&mut prev| prev + 1); 604 Ok(()) 605 } on_radar_data_rcv_notification( &mut self, _data_rcv_notf: RadarDataRcvNotification, ) -> Result<()>606 fn on_radar_data_rcv_notification( 607 &mut self, 608 _data_rcv_notf: RadarDataRcvNotification, 609 ) -> Result<()> { 610 self.nonsend_counter.replace_with(|&mut prev| prev + 1); 611 Ok(()) 612 } on_rf_test_notification( &mut self, rftest_notification: RfTestNotification, ) -> Result<()>613 fn on_rf_test_notification( 614 &mut self, 615 rftest_notification: RfTestNotification, 616 ) -> Result<()> { 617 self.nonsend_counter.replace_with(|&mut prev| prev + 1); 618 self.notf_sender 619 .send(UciNotification::RfTest(rftest_notification)) 620 .map_err(|_| Error::Unknown) 621 } 622 } 623 624 /// Builder for MockNotificationManager. 625 struct MockNotificationManagerBuilder { 626 notf_sender: mpsc::UnboundedSender<UciNotification>, 627 // initial_count is an example for a parameter undetermined at compile time. 628 } 629 630 impl MockNotificationManagerBuilder { 631 /// Constructor for builder. new(notf_sender: mpsc::UnboundedSender<UciNotification>) -> Self632 fn new(notf_sender: mpsc::UnboundedSender<UciNotification>) -> Self { 633 Self { notf_sender } 634 } 635 } 636 637 impl NotificationManagerBuilder for MockNotificationManagerBuilder { 638 type NotificationManager = MockNotificationManager; 639 build(self) -> Option<Self::NotificationManager>640 fn build(self) -> Option<Self::NotificationManager> { 641 Some(MockNotificationManager { 642 notf_sender: self.notf_sender, 643 nonsend_counter: Rc::new(RefCell::new(0)), 644 }) 645 } 646 } 647 648 #[test] 649 /// Tests that the Command, Response, and Notification pipeline are functional. test_sync_uci_basic_sequence()650 fn test_sync_uci_basic_sequence() { 651 let test_rt = Builder::new_multi_thread().enable_all().build().unwrap(); 652 let (notf_sender, mut notf_receiver) = mpsc::unbounded_channel::<UciNotification>(); 653 let mut uci_manager_impl = MockUciManager::new(); 654 let get_device_info_rsp = GetDeviceInfoResponse { 655 status: UciStatusOk, 656 uci_version: 0, 657 mac_version: 0, 658 phy_version: 0, 659 uci_test_version: 0, 660 vendor_spec_info: vec![], 661 }; 662 663 uci_manager_impl.expect_open_hal( 664 vec![UciNotification::Core(CoreNotification::DeviceStatus(DeviceStateReady))], 665 Ok(get_device_info_rsp.clone()), 666 ); 667 uci_manager_impl.expect_core_get_device_info(Ok(get_device_info_rsp)); 668 let uci_manager_sync = UciManagerSync::new_mock( 669 uci_manager_impl, 670 test_rt.handle().to_owned(), 671 MockNotificationManagerBuilder::new(notf_sender), 672 ) 673 .unwrap(); 674 assert!(uci_manager_sync.open_hal().is_ok()); 675 let device_state = test_rt.block_on(async { notf_receiver.recv().await }); 676 assert!(device_state.is_some()); 677 assert!(uci_manager_sync.core_get_device_info().is_ok()); 678 } 679 } 680