• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,
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, ControllerPhaseList};
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, number_of_phases: u8, phase_list: Vec<ControllerPhaseList>, ) -> Result<()>443     pub fn session_set_hybrid_controller_config(
444         &self,
445         session_id: SessionId,
446         number_of_phases: u8,
447         phase_list: Vec<ControllerPhaseList>,
448     ) -> Result<()> {
449         self.runtime_handle.block_on(self.uci_manager.session_set_hybrid_controller_config(
450             session_id,
451             number_of_phases,
452             phase_list,
453         ))
454     }
455 
456     /// Send UCI command for setting hybrid controlee configuration
session_set_hybrid_controlee_config( &self, session_id: SessionId, controlee_phase_list: Vec<ControleePhaseList>, ) -> Result<()>457     pub fn session_set_hybrid_controlee_config(
458         &self,
459         session_id: SessionId,
460         controlee_phase_list: Vec<ControleePhaseList>,
461     ) -> Result<()> {
462         self.runtime_handle.block_on(
463             self.uci_manager.session_set_hybrid_controlee_config(session_id, controlee_phase_list),
464         )
465     }
466 
467     /// Send UCI command for session data transfer phase config
468     #[allow(clippy::too_many_arguments)]
session_data_transfer_phase_config( &self, session_id: SessionId, dtpcm_repetition: u8, data_transfer_control: u8, dtpml_size: u8, mac_address: Vec<u8>, slot_bitmap: Vec<u8>, stop_data_transfer: Vec<u8>, ) -> Result<()>469     pub fn session_data_transfer_phase_config(
470         &self,
471         session_id: SessionId,
472         dtpcm_repetition: u8,
473         data_transfer_control: u8,
474         dtpml_size: u8,
475         mac_address: Vec<u8>,
476         slot_bitmap: Vec<u8>,
477         stop_data_transfer: Vec<u8>,
478     ) -> Result<()> {
479         self.runtime_handle.block_on(self.uci_manager.session_data_transfer_phase_config(
480             session_id,
481             dtpcm_repetition,
482             data_transfer_control,
483             dtpml_size,
484             mac_address,
485             slot_bitmap,
486             stop_data_transfer,
487         ))
488     }
489 
490     /// Set rf test config.
session_set_rf_test_app_config( &self, session_id: SessionId, config_tlvs: Vec<RfTestConfigTlv>, ) -> Result<RfTestConfigResponse>491     pub fn session_set_rf_test_app_config(
492         &self,
493         session_id: SessionId,
494         config_tlvs: Vec<RfTestConfigTlv>,
495     ) -> Result<RfTestConfigResponse> {
496         self.runtime_handle
497             .block_on(self.uci_manager.session_set_rf_test_config(session_id, config_tlvs))
498     }
499 
500     /// Test Periodic tx command
rf_test_periodic_tx(&self, psdu_data: Vec<u8>) -> Result<()>501     pub fn rf_test_periodic_tx(&self, psdu_data: Vec<u8>) -> Result<()> {
502         self.runtime_handle.block_on(self.uci_manager.rf_test_periodic_tx(psdu_data))
503     }
504 
505     /// Test Per rx command
rf_test_per_rx(&self, psdu_data: Vec<u8>) -> Result<()>506     pub fn rf_test_per_rx(&self, psdu_data: Vec<u8>) -> Result<()> {
507         self.runtime_handle.block_on(self.uci_manager.rf_test_per_rx(psdu_data))
508     }
509 
510     /// Test stop rf test command
stop_rf_test(&self) -> Result<()>511     pub fn stop_rf_test(&self) -> Result<()> {
512         self.runtime_handle.block_on(self.uci_manager.stop_rf_test())
513     }
514 }
515 
516 impl UciManagerSync<UciManagerImpl> {
517     /// Constructor.
518     ///
519     /// UciHal and NotificationManagerBuilder required at construction as they are required before
520     /// open_hal is called. runtime_handle must be a Handle to a multithread runtime that outlives
521     /// UciManagerSyncImpl.
522     ///
523     /// Implementation note: An explicit decision is made to not use UciManagerImpl as a parameter.
524     /// UciManagerImpl::new() appears to be sync, but needs an async context to be called, but the
525     /// 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,526     pub fn new<H, B, L>(
527         hal: H,
528         notification_manager_builder: B,
529         logger: L,
530         logger_mode: UciLoggerMode,
531         runtime_handle: Handle,
532     ) -> Result<Self>
533     where
534         H: UciHal,
535         B: NotificationManagerBuilder,
536         L: UciLogger,
537     {
538         // UciManagerImpl::new uses tokio::spawn, so it is called inside the runtime as async fn.
539         let uci_manager =
540             runtime_handle.block_on(async { UciManagerImpl::new(hal, logger, logger_mode) });
541         let mut uci_manager_sync = UciManagerSync { runtime_handle, uci_manager };
542         uci_manager_sync.redirect_notification(notification_manager_builder)?;
543         Ok(uci_manager_sync)
544     }
545 }
546 
547 #[cfg(any(test, feature = "mock-utils"))]
548 impl UciManagerSync<MockUciManager> {
549     /// Constructor for mock version.
new_mock<T: NotificationManagerBuilder>( uci_manager: MockUciManager, runtime_handle: Handle, notification_manager_builder: T, ) -> Result<Self>550     pub fn new_mock<T: NotificationManagerBuilder>(
551         uci_manager: MockUciManager,
552         runtime_handle: Handle,
553         notification_manager_builder: T,
554     ) -> Result<Self> {
555         let mut uci_manager_sync = UciManagerSync { uci_manager, runtime_handle };
556         uci_manager_sync.redirect_notification(notification_manager_builder)?;
557         Ok(uci_manager_sync)
558     }
559 }
560 
561 #[cfg(test)]
562 mod tests {
563     use super::*;
564 
565     use std::cell::RefCell;
566     use std::rc::Rc;
567 
568     use tokio::runtime::Builder;
569     use uwb_uci_packets::DeviceState::DeviceStateReady;
570 
571     use crate::params::uci_packets::GetDeviceInfoResponse;
572     use crate::uci::mock_uci_manager::MockUciManager;
573     use crate::uci::{CoreNotification, UciNotification};
574     use uwb_uci_packets::StatusCode::UciStatusOk;
575 
576     /// Mock NotificationManager forwarding notifications received.
577     /// The nonsend_counter is deliberately !send to check UciManagerSync::redirect_notification.
578     struct MockNotificationManager {
579         notf_sender: mpsc::UnboundedSender<UciNotification>,
580         // nonsend_counter is an example of a !Send property.
581         nonsend_counter: Rc<RefCell<usize>>,
582     }
583 
584     impl NotificationManager for MockNotificationManager {
on_core_notification(&mut self, core_notification: CoreNotification) -> Result<()>585         fn on_core_notification(&mut self, core_notification: CoreNotification) -> Result<()> {
586             self.nonsend_counter.replace_with(|&mut prev| prev + 1);
587             self.notf_sender
588                 .send(UciNotification::Core(core_notification))
589                 .map_err(|_| Error::Unknown)
590         }
on_session_notification( &mut self, session_notification: SessionNotification, ) -> Result<()>591         fn on_session_notification(
592             &mut self,
593             session_notification: SessionNotification,
594         ) -> Result<()> {
595             self.nonsend_counter.replace_with(|&mut prev| prev + 1);
596             self.notf_sender
597                 .send(UciNotification::Session(session_notification))
598                 .map_err(|_| Error::Unknown)
599         }
on_vendor_notification(&mut self, vendor_notification: RawUciMessage) -> Result<()>600         fn on_vendor_notification(&mut self, vendor_notification: RawUciMessage) -> Result<()> {
601             self.nonsend_counter.replace_with(|&mut prev| prev + 1);
602             self.notf_sender
603                 .send(UciNotification::Vendor(vendor_notification))
604                 .map_err(|_| Error::Unknown)
605         }
on_data_rcv_notification(&mut self, _data_rcv_notf: DataRcvNotification) -> Result<()>606         fn on_data_rcv_notification(&mut self, _data_rcv_notf: DataRcvNotification) -> Result<()> {
607             self.nonsend_counter.replace_with(|&mut prev| prev + 1);
608             Ok(())
609         }
on_radar_data_rcv_notification( &mut self, _data_rcv_notf: RadarDataRcvNotification, ) -> Result<()>610         fn on_radar_data_rcv_notification(
611             &mut self,
612             _data_rcv_notf: RadarDataRcvNotification,
613         ) -> Result<()> {
614             self.nonsend_counter.replace_with(|&mut prev| prev + 1);
615             Ok(())
616         }
on_rf_test_notification( &mut self, rftest_notification: RfTestNotification, ) -> Result<()>617         fn on_rf_test_notification(
618             &mut self,
619             rftest_notification: RfTestNotification,
620         ) -> Result<()> {
621             self.nonsend_counter.replace_with(|&mut prev| prev + 1);
622             self.notf_sender
623                 .send(UciNotification::RfTest(rftest_notification))
624                 .map_err(|_| Error::Unknown)
625         }
626     }
627 
628     /// Builder for MockNotificationManager.
629     struct MockNotificationManagerBuilder {
630         notf_sender: mpsc::UnboundedSender<UciNotification>,
631         // initial_count is an example for a parameter undetermined at compile time.
632     }
633 
634     impl MockNotificationManagerBuilder {
635         /// Constructor for builder.
new(notf_sender: mpsc::UnboundedSender<UciNotification>) -> Self636         fn new(notf_sender: mpsc::UnboundedSender<UciNotification>) -> Self {
637             Self { notf_sender }
638         }
639     }
640 
641     impl NotificationManagerBuilder for MockNotificationManagerBuilder {
642         type NotificationManager = MockNotificationManager;
643 
build(self) -> Option<Self::NotificationManager>644         fn build(self) -> Option<Self::NotificationManager> {
645             Some(MockNotificationManager {
646                 notf_sender: self.notf_sender,
647                 nonsend_counter: Rc::new(RefCell::new(0)),
648             })
649         }
650     }
651 
652     #[test]
653     /// Tests that the Command, Response, and Notification pipeline are functional.
test_sync_uci_basic_sequence()654     fn test_sync_uci_basic_sequence() {
655         let test_rt = Builder::new_multi_thread().enable_all().build().unwrap();
656         let (notf_sender, mut notf_receiver) = mpsc::unbounded_channel::<UciNotification>();
657         let mut uci_manager_impl = MockUciManager::new();
658         let get_device_info_rsp = GetDeviceInfoResponse {
659             status: UciStatusOk,
660             uci_version: 0,
661             mac_version: 0,
662             phy_version: 0,
663             uci_test_version: 0,
664             vendor_spec_info: vec![],
665         };
666 
667         uci_manager_impl.expect_open_hal(
668             vec![UciNotification::Core(CoreNotification::DeviceStatus(DeviceStateReady))],
669             Ok(get_device_info_rsp.clone()),
670         );
671         uci_manager_impl.expect_core_get_device_info(Ok(get_device_info_rsp));
672         let uci_manager_sync = UciManagerSync::new_mock(
673             uci_manager_impl,
674             test_rt.handle().to_owned(),
675             MockNotificationManagerBuilder::new(notf_sender),
676         )
677         .unwrap();
678         assert!(uci_manager_sync.open_hal().is_ok());
679         let device_state = test_rt.block_on(async { notf_receiver.recv().await });
680         assert!(device_state.is_some());
681         assert!(uci_manager_sync.core_get_device_info().is_ok());
682     }
683 }
684