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