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