xref: /aosp_15_r20/external/uwb/src/rust/uwb_core/src/uci/uci_manager_sync.rs (revision e0df40009cb5d71e642272d38ba1bb7ffccfce41)
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