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