• 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 tokio::sync::{mpsc, oneshot, Mutex};
22 
23 use crate::uci::command::UciCommand;
24 //use crate::uci::error::{Error, Result};
25 use crate::error::{Error, Result};
26 use crate::params::uci_packets::{
27     AppConfigTlv, AppConfigTlvType, CapTlv, Controlees, CoreSetConfigResponse, CountryCode,
28     CreditAvailability, DeviceConfigId, DeviceConfigTlv, DeviceState, FiraComponent,
29     GetDeviceInfoResponse, GroupId, MessageType, PowerStats, RawUciMessage, ResetConfig, SessionId,
30     SessionState, SessionToken, SessionType, SessionUpdateDtTagRangingRoundsResponse,
31     SetAppConfigResponse, UciDataPacket, UciDataPacketHal, UpdateMulticastListAction,
32 };
33 use crate::params::utils::bytes_to_u64;
34 use crate::uci::message::UciMessage;
35 use crate::uci::notification::{
36     CoreNotification, DataRcvNotification, SessionNotification, SessionRangeData, UciNotification,
37 };
38 use crate::uci::response::UciResponse;
39 use crate::uci::timeout_uci_hal::TimeoutUciHal;
40 use crate::uci::uci_hal::{UciHal, UciHalPacket};
41 use crate::uci::uci_logger::{UciLogger, UciLoggerMode, UciLoggerWrapper};
42 use crate::utils::{clean_mpsc_receiver, PinSleep};
43 use std::collections::{HashMap, VecDeque};
44 use uwb_uci_packets::{Packet, RawUciControlPacket, UciDataSnd, UciDefragPacket};
45 
46 const UCI_TIMEOUT_MS: u64 = 800;
47 const MAX_RETRY_COUNT: usize = 3;
48 
49 /// The UciManager organizes the state machine of the UWB HAL, and provides the interface which
50 /// abstracts the UCI commands, responses, and notifications.
51 #[async_trait]
52 pub trait UciManager: 'static + Send + Sync + Clone {
set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>53     async fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>;
54     // Set the sendor of the UCI notificaions.
set_core_notification_sender( &mut self, core_notf_sender: mpsc::UnboundedSender<CoreNotification>, )55     async fn set_core_notification_sender(
56         &mut self,
57         core_notf_sender: mpsc::UnboundedSender<CoreNotification>,
58     );
set_session_notification_sender( &mut self, session_notf_sender: mpsc::UnboundedSender<SessionNotification>, )59     async fn set_session_notification_sender(
60         &mut self,
61         session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
62     );
set_vendor_notification_sender( &mut self, vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, )63     async fn set_vendor_notification_sender(
64         &mut self,
65         vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
66     );
set_data_rcv_notification_sender( &mut self, data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, )67     async fn set_data_rcv_notification_sender(
68         &mut self,
69         data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
70     );
71 
72     // Open the UCI HAL.
73     // All the UCI commands should be called after the open_hal() completes successfully.
open_hal(&self) -> Result<()>74     async fn open_hal(&self) -> Result<()>;
75 
76     // Close the UCI HAL.
close_hal(&self, force: bool) -> Result<()>77     async fn close_hal(&self, force: bool) -> Result<()>;
78 
79     // Send the standard UCI Commands.
device_reset(&self, reset_config: ResetConfig) -> Result<()>80     async fn device_reset(&self, reset_config: ResetConfig) -> Result<()>;
core_get_device_info(&self) -> Result<GetDeviceInfoResponse>81     async fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse>;
core_get_caps_info(&self) -> Result<Vec<CapTlv>>82     async fn core_get_caps_info(&self) -> Result<Vec<CapTlv>>;
core_set_config( &self, config_tlvs: Vec<DeviceConfigTlv>, ) -> Result<CoreSetConfigResponse>83     async fn core_set_config(
84         &self,
85         config_tlvs: Vec<DeviceConfigTlv>,
86     ) -> Result<CoreSetConfigResponse>;
core_get_config( &self, config_ids: Vec<DeviceConfigId>, ) -> Result<Vec<DeviceConfigTlv>>87     async fn core_get_config(
88         &self,
89         config_ids: Vec<DeviceConfigId>,
90     ) -> Result<Vec<DeviceConfigTlv>>;
session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>91     async fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>;
session_deinit(&self, session_id: SessionId) -> Result<()>92     async fn session_deinit(&self, session_id: SessionId) -> Result<()>;
session_set_app_config( &self, session_id: SessionId, config_tlvs: Vec<AppConfigTlv>, ) -> Result<SetAppConfigResponse>93     async fn session_set_app_config(
94         &self,
95         session_id: SessionId,
96         config_tlvs: Vec<AppConfigTlv>,
97     ) -> Result<SetAppConfigResponse>;
session_get_app_config( &self, session_id: SessionId, config_ids: Vec<AppConfigTlvType>, ) -> Result<Vec<AppConfigTlv>>98     async fn session_get_app_config(
99         &self,
100         session_id: SessionId,
101         config_ids: Vec<AppConfigTlvType>,
102     ) -> Result<Vec<AppConfigTlv>>;
session_get_count(&self) -> Result<u8>103     async fn session_get_count(&self) -> Result<u8>;
session_get_state(&self, session_id: SessionId) -> Result<SessionState>104     async fn session_get_state(&self, session_id: SessionId) -> Result<SessionState>;
session_update_controller_multicast_list( &self, session_id: SessionId, action: UpdateMulticastListAction, controlees: Controlees, ) -> Result<()>105     async fn session_update_controller_multicast_list(
106         &self,
107         session_id: SessionId,
108         action: UpdateMulticastListAction,
109         controlees: Controlees,
110     ) -> Result<()>;
111 
112     // Update ranging rounds for DT Tag
session_update_dt_tag_ranging_rounds( &self, session_id: u32, ranging_round_indexes: Vec<u8>, ) -> Result<SessionUpdateDtTagRangingRoundsResponse>113     async fn session_update_dt_tag_ranging_rounds(
114         &self,
115         session_id: u32,
116         ranging_round_indexes: Vec<u8>,
117     ) -> Result<SessionUpdateDtTagRangingRoundsResponse>;
118 
session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>119     async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>;
120 
range_start(&self, session_id: SessionId) -> Result<()>121     async fn range_start(&self, session_id: SessionId) -> Result<()>;
range_stop(&self, session_id: SessionId) -> Result<()>122     async fn range_stop(&self, session_id: SessionId) -> Result<()>;
range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>123     async fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>;
124 
125     // Send the Android-specific UCI commands
android_set_country_code(&self, country_code: CountryCode) -> Result<()>126     async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()>;
android_get_power_stats(&self) -> Result<PowerStats>127     async fn android_get_power_stats(&self) -> Result<PowerStats>;
128 
129     // Send a raw uci command.
raw_uci_cmd( &self, mt: u32, gid: u32, oid: u32, payload: Vec<u8>, ) -> Result<RawUciMessage>130     async fn raw_uci_cmd(
131         &self,
132         mt: u32,
133         gid: u32,
134         oid: u32,
135         payload: Vec<u8>,
136     ) -> Result<RawUciMessage>;
137 
138     // Send a Data packet.
send_data_packet( &self, session_id: SessionId, address: Vec<u8>, dest_end_point: FiraComponent, uci_sequence_number: u8, app_payload_data: Vec<u8>, ) -> Result<()>139     async fn send_data_packet(
140         &self,
141         session_id: SessionId,
142         address: Vec<u8>,
143         dest_end_point: FiraComponent,
144         uci_sequence_number: u8,
145         app_payload_data: Vec<u8>,
146     ) -> Result<()>;
147 
148     // Get Session token from session id
get_session_token_from_session_id( &self, session_id: SessionId, ) -> Result<SessionToken>149     async fn get_session_token_from_session_id(
150         &self,
151         session_id: SessionId,
152     ) -> Result<SessionToken>;
153 }
154 
155 /// UciManagerImpl is the main implementation of UciManager. Using the actor model, UciManagerImpl
156 /// delegates the requests to UciManagerActor.
157 #[derive(Clone)]
158 pub struct UciManagerImpl {
159     cmd_sender: mpsc::UnboundedSender<(UciManagerCmd, oneshot::Sender<Result<UciResponse>>)>,
160 
161     // FIRA version 2 introduces a UWBS generated session handle to use as identifier for all
162     // session related commands. This map stores the app provided session id to UWBS generated
163     // session handle mapping if provided, else reuses session id.
164     session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>,
165 }
166 
167 impl UciManagerImpl {
168     /// Constructor. Need to be called in an async context.
new<T: UciHal, U: UciLogger>( hal: T, logger: U, logger_mode: UciLoggerMode, ) -> Self169     pub(crate) fn new<T: UciHal, U: UciLogger>(
170         hal: T,
171         logger: U,
172         logger_mode: UciLoggerMode,
173     ) -> Self {
174         let (cmd_sender, cmd_receiver) = mpsc::unbounded_channel();
175         let session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>> =
176             Arc::new(Mutex::new(HashMap::new()));
177         let mut actor = UciManagerActor::new(
178             hal,
179             logger,
180             logger_mode,
181             cmd_receiver,
182             session_id_to_token_map.clone(),
183         );
184         tokio::spawn(async move { actor.run().await });
185 
186         Self { cmd_sender, session_id_to_token_map }
187     }
188 
189     // Send the |cmd| to the UciManagerActor.
send_cmd(&self, cmd: UciManagerCmd) -> Result<UciResponse>190     async fn send_cmd(&self, cmd: UciManagerCmd) -> Result<UciResponse> {
191         let (result_sender, result_receiver) = oneshot::channel();
192         match self.cmd_sender.send((cmd, result_sender)) {
193             Ok(()) => result_receiver.await.unwrap_or(Err(Error::Unknown)),
194             Err(cmd) => {
195                 error!("Failed to send cmd: {:?}", cmd.0);
196                 Err(Error::Unknown)
197             }
198         }
199     }
200 
get_session_token(&self, session_id: &SessionId) -> Result<SessionToken>201     async fn get_session_token(&self, session_id: &SessionId) -> Result<SessionToken> {
202         self.session_id_to_token_map
203             .lock()
204             .await
205             .get(session_id)
206             .ok_or(Error::BadParameters)
207             .copied()
208     }
209 }
210 
211 #[async_trait]
212 impl UciManager for UciManagerImpl {
set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>213     async fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()> {
214         match self.send_cmd(UciManagerCmd::SetLoggerMode { logger_mode }).await {
215             Ok(UciResponse::SetLoggerMode) => Ok(()),
216             Ok(_) => Err(Error::Unknown),
217             Err(e) => Err(e),
218         }
219     }
set_core_notification_sender( &mut self, core_notf_sender: mpsc::UnboundedSender<CoreNotification>, )220     async fn set_core_notification_sender(
221         &mut self,
222         core_notf_sender: mpsc::UnboundedSender<CoreNotification>,
223     ) {
224         let _ = self.send_cmd(UciManagerCmd::SetCoreNotificationSender { core_notf_sender }).await;
225     }
set_session_notification_sender( &mut self, session_notf_sender: mpsc::UnboundedSender<SessionNotification>, )226     async fn set_session_notification_sender(
227         &mut self,
228         session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
229     ) {
230         let _ = self
231             .send_cmd(UciManagerCmd::SetSessionNotificationSender { session_notf_sender })
232             .await;
233     }
set_vendor_notification_sender( &mut self, vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, )234     async fn set_vendor_notification_sender(
235         &mut self,
236         vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
237     ) {
238         let _ =
239             self.send_cmd(UciManagerCmd::SetVendorNotificationSender { vendor_notf_sender }).await;
240     }
set_data_rcv_notification_sender( &mut self, data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, )241     async fn set_data_rcv_notification_sender(
242         &mut self,
243         data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
244     ) {
245         let _ = self
246             .send_cmd(UciManagerCmd::SetDataRcvNotificationSender { data_rcv_notf_sender })
247             .await;
248     }
249 
open_hal(&self) -> Result<()>250     async fn open_hal(&self) -> Result<()> {
251         match self.send_cmd(UciManagerCmd::OpenHal).await {
252             Ok(UciResponse::OpenHal) => {
253                 // According to the UCI spec: "The Host shall send CORE_GET_DEVICE_INFO_CMD to
254                 // retrieve the device information.", we call get_device_info() after successfully
255                 // opening the HAL.
256                 let device_info = self.core_get_device_info().await;
257                 debug!("UCI device info: {:?}", device_info);
258 
259                 Ok(())
260             }
261             Ok(_) => Err(Error::Unknown),
262             Err(e) => Err(e),
263         }
264     }
265 
close_hal(&self, force: bool) -> Result<()>266     async fn close_hal(&self, force: bool) -> Result<()> {
267         match self.send_cmd(UciManagerCmd::CloseHal { force }).await {
268             Ok(UciResponse::CloseHal) => Ok(()),
269             Ok(_) => Err(Error::Unknown),
270             Err(e) => Err(e),
271         }
272     }
273 
device_reset(&self, reset_config: ResetConfig) -> Result<()>274     async fn device_reset(&self, reset_config: ResetConfig) -> Result<()> {
275         let cmd = UciCommand::DeviceReset { reset_config };
276         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
277             Ok(UciResponse::DeviceReset(resp)) => resp,
278             Ok(_) => Err(Error::Unknown),
279             Err(e) => Err(e),
280         }
281     }
282 
core_get_device_info(&self) -> Result<GetDeviceInfoResponse>283     async fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse> {
284         let cmd = UciCommand::CoreGetDeviceInfo;
285         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
286             Ok(UciResponse::CoreGetDeviceInfo(resp)) => resp,
287             Ok(_) => Err(Error::Unknown),
288             Err(e) => Err(e),
289         }
290     }
291 
core_get_caps_info(&self) -> Result<Vec<CapTlv>>292     async fn core_get_caps_info(&self) -> Result<Vec<CapTlv>> {
293         let cmd = UciCommand::CoreGetCapsInfo;
294         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
295             Ok(UciResponse::CoreGetCapsInfo(resp)) => resp,
296             Ok(_) => Err(Error::Unknown),
297             Err(e) => Err(e),
298         }
299     }
300 
core_set_config( &self, config_tlvs: Vec<DeviceConfigTlv>, ) -> Result<CoreSetConfigResponse>301     async fn core_set_config(
302         &self,
303         config_tlvs: Vec<DeviceConfigTlv>,
304     ) -> Result<CoreSetConfigResponse> {
305         let cmd = UciCommand::CoreSetConfig { config_tlvs };
306         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
307             Ok(UciResponse::CoreSetConfig(resp)) => Ok(resp),
308             Ok(_) => Err(Error::Unknown),
309             Err(e) => Err(e),
310         }
311     }
312 
core_get_config(&self, cfg_id: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>>313     async fn core_get_config(&self, cfg_id: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>> {
314         let cmd = UciCommand::CoreGetConfig { cfg_id };
315         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
316             Ok(UciResponse::CoreGetConfig(resp)) => resp,
317             Ok(_) => Err(Error::Unknown),
318             Err(e) => Err(e),
319         }
320     }
321 
session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>322     async fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()> {
323         let cmd = UciCommand::SessionInit { session_id, session_type };
324         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
325             Ok(UciResponse::SessionInit(resp)) => resp.map(|_| {}),
326             Ok(_) => Err(Error::Unknown),
327             Err(e) => Err(e),
328         }
329     }
330 
session_deinit(&self, session_id: SessionId) -> Result<()>331     async fn session_deinit(&self, session_id: SessionId) -> Result<()> {
332         let cmd =
333             UciCommand::SessionDeinit { session_token: self.get_session_token(&session_id).await? };
334         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
335             Ok(UciResponse::SessionDeinit(resp)) => resp,
336             Ok(_) => Err(Error::Unknown),
337             Err(e) => Err(e),
338         }
339     }
340 
session_set_app_config( &self, session_id: SessionId, config_tlvs: Vec<AppConfigTlv>, ) -> Result<SetAppConfigResponse>341     async fn session_set_app_config(
342         &self,
343         session_id: SessionId,
344         config_tlvs: Vec<AppConfigTlv>,
345     ) -> Result<SetAppConfigResponse> {
346         let cmd = UciCommand::SessionSetAppConfig {
347             session_token: self.get_session_token(&session_id).await?,
348             config_tlvs,
349         };
350         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
351             Ok(UciResponse::SessionSetAppConfig(resp)) => Ok(resp),
352             Ok(_) => Err(Error::Unknown),
353             Err(e) => Err(e),
354         }
355     }
356 
session_get_app_config( &self, session_id: SessionId, app_cfg: Vec<AppConfigTlvType>, ) -> Result<Vec<AppConfigTlv>>357     async fn session_get_app_config(
358         &self,
359         session_id: SessionId,
360         app_cfg: Vec<AppConfigTlvType>,
361     ) -> Result<Vec<AppConfigTlv>> {
362         let cmd = UciCommand::SessionGetAppConfig {
363             session_token: self.get_session_token(&session_id).await?,
364             app_cfg,
365         };
366         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
367             Ok(UciResponse::SessionGetAppConfig(resp)) => resp,
368             Ok(_) => Err(Error::Unknown),
369             Err(e) => Err(e),
370         }
371     }
372 
session_get_count(&self) -> Result<u8>373     async fn session_get_count(&self) -> Result<u8> {
374         let cmd = UciCommand::SessionGetCount;
375         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
376             Ok(UciResponse::SessionGetCount(resp)) => resp,
377             Ok(_) => Err(Error::Unknown),
378             Err(e) => Err(e),
379         }
380     }
381 
session_get_state(&self, session_id: SessionId) -> Result<SessionState>382     async fn session_get_state(&self, session_id: SessionId) -> Result<SessionState> {
383         let cmd = UciCommand::SessionGetState {
384             session_token: self.get_session_token(&session_id).await?,
385         };
386         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
387             Ok(UciResponse::SessionGetState(resp)) => resp,
388             Ok(_) => Err(Error::Unknown),
389             Err(e) => Err(e),
390         }
391     }
392 
session_update_controller_multicast_list( &self, session_id: SessionId, action: UpdateMulticastListAction, controlees: Controlees, ) -> Result<()>393     async fn session_update_controller_multicast_list(
394         &self,
395         session_id: SessionId,
396         action: UpdateMulticastListAction,
397         controlees: Controlees,
398     ) -> Result<()> {
399         let controlees_len = match controlees {
400             Controlees::NoSessionKey(ref controlee_vec) => controlee_vec.len(),
401             Controlees::ShortSessionKey(ref controlee_vec) => controlee_vec.len(),
402             Controlees::LongSessionKey(ref controlee_vec) => controlee_vec.len(),
403         };
404         if !(1..=8).contains(&controlees_len) {
405             warn!("Number of controlees should be between 1 to 8");
406             return Err(Error::BadParameters);
407         }
408         let cmd = UciCommand::SessionUpdateControllerMulticastList {
409             session_token: self.get_session_token(&session_id).await?,
410             action,
411             controlees,
412         };
413         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
414             Ok(UciResponse::SessionUpdateControllerMulticastList(resp)) => resp,
415             Ok(_) => Err(Error::Unknown),
416             Err(e) => Err(e),
417         }
418     }
419 
session_update_dt_tag_ranging_rounds( &self, session_id: u32, ranging_round_indexes: Vec<u8>, ) -> Result<SessionUpdateDtTagRangingRoundsResponse>420     async fn session_update_dt_tag_ranging_rounds(
421         &self,
422         session_id: u32,
423         ranging_round_indexes: Vec<u8>,
424     ) -> Result<SessionUpdateDtTagRangingRoundsResponse> {
425         let cmd = UciCommand::SessionUpdateDtTagRangingRounds {
426             session_token: self.get_session_token(&session_id).await?,
427             ranging_round_indexes,
428         };
429         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
430             Ok(UciResponse::SessionUpdateDtTagRangingRounds(resp)) => resp,
431             Ok(_) => Err(Error::Unknown),
432             Err(e) => Err(e),
433         }
434     }
435 
session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>436     async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16> {
437         let cmd = UciCommand::SessionQueryMaxDataSize {
438             session_token: self.get_session_token(&session_id).await?,
439         };
440         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
441             Ok(UciResponse::SessionQueryMaxDataSize(resp)) => resp,
442             Ok(_) => Err(Error::Unknown),
443             Err(e) => Err(e),
444         }
445     }
446 
range_start(&self, session_id: SessionId) -> Result<()>447     async fn range_start(&self, session_id: SessionId) -> Result<()> {
448         let cmd =
449             UciCommand::SessionStart { session_token: self.get_session_token(&session_id).await? };
450         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
451             Ok(UciResponse::SessionStart(resp)) => resp,
452             Ok(_) => Err(Error::Unknown),
453             Err(e) => Err(e),
454         }
455     }
456 
range_stop(&self, session_id: SessionId) -> Result<()>457     async fn range_stop(&self, session_id: SessionId) -> Result<()> {
458         let cmd =
459             UciCommand::SessionStop { session_token: self.get_session_token(&session_id).await? };
460         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
461             Ok(UciResponse::SessionStop(resp)) => resp,
462             Ok(_) => Err(Error::Unknown),
463             Err(e) => Err(e),
464         }
465     }
466 
range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>467     async fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize> {
468         let cmd = UciCommand::SessionGetRangingCount {
469             session_token: self.get_session_token(&session_id).await?,
470         };
471         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
472             Ok(UciResponse::SessionGetRangingCount(resp)) => resp,
473             Ok(_) => Err(Error::Unknown),
474             Err(e) => Err(e),
475         }
476     }
477 
android_set_country_code(&self, country_code: CountryCode) -> Result<()>478     async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()> {
479         let cmd = UciCommand::AndroidSetCountryCode { country_code };
480         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
481             Ok(UciResponse::AndroidSetCountryCode(resp)) => resp,
482             Ok(_) => Err(Error::Unknown),
483             Err(e) => Err(e),
484         }
485     }
486 
android_get_power_stats(&self) -> Result<PowerStats>487     async fn android_get_power_stats(&self) -> Result<PowerStats> {
488         let cmd = UciCommand::AndroidGetPowerStats;
489         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
490             Ok(UciResponse::AndroidGetPowerStats(resp)) => resp,
491             Ok(_) => Err(Error::Unknown),
492             Err(e) => Err(e),
493         }
494     }
495 
raw_uci_cmd( &self, mt: u32, gid: u32, oid: u32, payload: Vec<u8>, ) -> Result<RawUciMessage>496     async fn raw_uci_cmd(
497         &self,
498         mt: u32,
499         gid: u32,
500         oid: u32,
501         payload: Vec<u8>,
502     ) -> Result<RawUciMessage> {
503         let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload };
504         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
505             Ok(UciResponse::RawUciCmd(resp)) => resp,
506             Ok(_) => Err(Error::Unknown),
507             Err(e) => Err(e),
508         }
509     }
510 
511     // Send a data packet to the UWBS (use the UciManagerActor).
send_data_packet( &self, session_id: SessionId, dest_mac_address_bytes: Vec<u8>, dest_fira_component: FiraComponent, uci_sequence_number: u8, data: Vec<u8>, ) -> Result<()>512     async fn send_data_packet(
513         &self,
514         session_id: SessionId,
515         dest_mac_address_bytes: Vec<u8>,
516         dest_fira_component: FiraComponent,
517         uci_sequence_number: u8,
518         data: Vec<u8>,
519     ) -> Result<()> {
520         debug!(
521             "send_data_packet(): will Tx a data packet, session_id {}, sequence_number {}",
522             session_id, uci_sequence_number
523         );
524         let dest_mac_address = bytes_to_u64(dest_mac_address_bytes).ok_or(Error::BadParameters)?;
525         let data_snd_packet = uwb_uci_packets::UciDataSndBuilder {
526             session_token: self.get_session_token(&session_id).await?,
527             dest_mac_address,
528             dest_fira_component,
529             uci_sequence_number,
530             data,
531         }
532         .build();
533 
534         match self.send_cmd(UciManagerCmd::SendUciData { data_snd_packet }).await {
535             Ok(UciResponse::SendUciData(resp)) => resp,
536             Ok(_) => Err(Error::Unknown),
537             Err(e) => Err(e),
538         }
539     }
540 
541     // Get session token from session id (no uci call).
get_session_token_from_session_id( &self, session_id: SessionId, ) -> Result<SessionToken>542     async fn get_session_token_from_session_id(
543         &self,
544         session_id: SessionId,
545     ) -> Result<SessionToken> {
546         Ok(self.get_session_token(&session_id).await?)
547     }
548 }
549 
550 struct UciManagerActor<T: UciHal, U: UciLogger> {
551     // The UCI HAL.
552     hal: TimeoutUciHal<T>,
553     // UCI Log.
554     logger: UciLoggerWrapper<U>,
555     // Receive the commands and the corresponding response senders from UciManager.
556     cmd_receiver: mpsc::UnboundedReceiver<(UciManagerCmd, oneshot::Sender<Result<UciResponse>>)>,
557 
558     // Set to true when |hal| is opened successfully.
559     is_hal_opened: bool,
560     // Receive response, notification and data packets from |mut hal|. Only used when |hal| is opened
561     // successfully.
562     packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>,
563     // Defrag the UCI packets.
564     defrager: uwb_uci_packets::PacketDefrager,
565 
566     // The response sender of UciManager's open_hal() method. Used to wait for the device ready
567     // notification.
568     open_hal_result_sender: Option<oneshot::Sender<Result<UciResponse>>>,
569 
570     // Store per-session CreditAvailability. This should be initialized when a UWB session becomes
571     // ACTIVE, and updated every time a Data packet fragment is sent or a DataCreditNtf is received.
572     data_credit_map: HashMap<SessionToken, CreditAvailability>,
573 
574     // Store the Uci Data packet fragments to be sent to the UWBS, keyed by the SessionId. This
575     // helps to retrieve the next packet fragment to be sent, when the UWBS is ready to accept it.
576     data_packet_fragments_map: HashMap<SessionToken, VecDeque<UciDataPacketHal>>,
577 
578     // The timeout of waiting for the notification of device ready notification.
579     wait_device_status_timeout: PinSleep,
580 
581     // Used for the logic of retrying the command. Only valid when waiting for the response of a
582     // UCI command.
583     uci_cmd_retryer: Option<UciCmdRetryer>,
584     // The timeout of waiting for the response. Only used when waiting for the response of a UCI
585     // command.
586     wait_resp_timeout: PinSleep,
587 
588     // Used for the logic of retrying the DataSnd packet. Only valid when waiting for the
589     // DATA_TRANSFER_STATUS_NTF.
590     uci_data_snd_retryer: Option<UciDataSndRetryer>,
591 
592     // Used to identify if response corresponds to the last vendor command, if so return
593     // a raw packet as a response to the sender.
594     last_raw_cmd: Option<RawUciControlPacket>,
595 
596     // Send the notifications to the caller of UciManager.
597     core_notf_sender: mpsc::UnboundedSender<CoreNotification>,
598     session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
599     vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
600     data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
601 
602     // Used to store the last init session id to help map the session handle sent
603     // in session int response can be correctly mapped.
604     last_init_session_id: Option<SessionId>,
605     // FIRA version 2 introduces a UWBS generated session handle to use as identifier for all
606     // session related commands. This map stores the app provided session id to UWBS generated
607     // session handle mapping if provided, else reuses session id.
608     session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>,
609 }
610 
611 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>>>, ) -> Self612     fn new(
613         hal: T,
614         logger: U,
615         logger_mode: UciLoggerMode,
616         cmd_receiver: mpsc::UnboundedReceiver<(
617             UciManagerCmd,
618             oneshot::Sender<Result<UciResponse>>,
619         )>,
620         session_id_to_token_map: Arc<Mutex<HashMap<SessionId, SessionToken>>>,
621     ) -> Self {
622         Self {
623             hal: TimeoutUciHal::new(hal),
624             logger: UciLoggerWrapper::new(logger, logger_mode),
625             cmd_receiver,
626             is_hal_opened: false,
627             packet_receiver: mpsc::unbounded_channel().1,
628             defrager: Default::default(),
629             open_hal_result_sender: None,
630             data_credit_map: HashMap::new(),
631             data_packet_fragments_map: HashMap::new(),
632             wait_device_status_timeout: PinSleep::new(Duration::MAX),
633             uci_cmd_retryer: None,
634             uci_data_snd_retryer: None,
635             wait_resp_timeout: PinSleep::new(Duration::MAX),
636             last_raw_cmd: None,
637             core_notf_sender: mpsc::unbounded_channel().0,
638             session_notf_sender: mpsc::unbounded_channel().0,
639             vendor_notf_sender: mpsc::unbounded_channel().0,
640             data_rcv_notf_sender: mpsc::unbounded_channel().0,
641             last_init_session_id: None,
642             session_id_to_token_map,
643         }
644     }
645 
run(&mut self)646     async fn run(&mut self) {
647         loop {
648             tokio::select! {
649                 // Handle the next command. Only when the previous command already received the
650                 // response.
651                 cmd = self.cmd_receiver.recv(), if !self.is_waiting_resp() => {
652                     match cmd {
653                         None => {
654                             debug!("UciManager is about to drop.");
655                             break;
656                         },
657                         Some((cmd, result_sender)) => {
658                             self.handle_cmd(cmd, result_sender).await;
659                         }
660                     }
661                 }
662 
663                 // Handle the UCI response, notification or data packet from HAL. Only when HAL
664                 // is opened.
665                 packet = self.packet_receiver.recv(), if self.is_hal_opened => {
666                     self.handle_hal_packet(packet).await;
667                 }
668 
669                 // Timeout waiting for the response of the UCI command.
670                 _ = &mut self.wait_resp_timeout, if self.is_waiting_resp() => {
671                     if let Some(uci_cmd_retryer) = self.uci_cmd_retryer.take() {
672                         uci_cmd_retryer.send_result(Err(Error::Timeout));
673                     }
674                 }
675 
676                 // Timeout waiting for the notification of the device status.
677                 _ = &mut self.wait_device_status_timeout, if self.is_waiting_device_status() => {
678                     if let Some(result_sender) = self.open_hal_result_sender.take() {
679                         let _ = result_sender.send(Err(Error::Timeout));
680                     }
681                 }
682             }
683         }
684 
685         if self.is_hal_opened {
686             debug!("The HAL is still opened when exit, close the HAL");
687             let _ = self.hal.close().await;
688             self.on_hal_closed();
689         }
690     }
691 
insert_session_token(&self, session_id: SessionId, session_token: SessionToken)692     async fn insert_session_token(&self, session_id: SessionId, session_token: SessionToken) {
693         self.session_id_to_token_map.lock().await.insert(session_id, session_token);
694     }
695 
remove_session_token(&self, session_token: &SessionToken)696     async fn remove_session_token(&self, session_token: &SessionToken) {
697         self.session_id_to_token_map.lock().await.retain(|_, val| *val != *session_token);
698     }
699 
get_session_id(&self, session_token: &SessionToken) -> Result<SessionId>700     async fn get_session_id(&self, session_token: &SessionToken) -> Result<SessionId> {
701         self.session_id_to_token_map
702             .lock()
703             .await
704             .iter()
705             .find_map(|(key, &val)| if val == *session_token { Some(key) } else { None })
706             .ok_or(Error::BadParameters)
707             .copied()
708     }
709 
save_session_id_if_init_cmd(&mut self, cmd: &UciCommand)710     fn save_session_id_if_init_cmd(&mut self, cmd: &UciCommand) {
711         // Store the last init session id to help map the session handle sent
712         // in session init response.
713         if let UciCommand::SessionInit { session_id, .. } = cmd {
714             self.last_init_session_id = Some(*session_id);
715         }
716     }
717 
store_session_token_if_init_resp(&mut self, resp: &UciResponse) -> Result<()>718     async fn store_session_token_if_init_resp(&mut self, resp: &UciResponse) -> Result<()> {
719         // Store the session_id to session_token mapping for this new session.
720         if let UciResponse::SessionInit(session_init_resp) = resp {
721             let session_id = match self.last_init_session_id.take() {
722                 Some(session_id) => session_id,
723                 None => {
724                     return Err(Error::Unknown);
725                 }
726             };
727             if let Ok(opt_session_handle) = session_init_resp {
728                 let session_handle = match opt_session_handle {
729                     // Session Handle provided by UWBS, use as token for further commands.
730                     Some(session_handle) => {
731                         info!(
732                             "session handle: {:?} provided for session id: {:?}",
733                             session_handle, session_id
734                         );
735                         *session_handle
736                     }
737                     // Session Handle not provided by UWBS, reuse session id as token for further commands.
738                     None => session_id,
739                 };
740                 self.insert_session_token(session_id, session_handle).await;
741             }
742         }
743         Ok(())
744     }
745 
handle_cmd( &mut self, cmd: UciManagerCmd, result_sender: oneshot::Sender<Result<UciResponse>>, )746     async fn handle_cmd(
747         &mut self,
748         cmd: UciManagerCmd,
749         result_sender: oneshot::Sender<Result<UciResponse>>,
750     ) {
751         debug!("Received cmd: {:?}", cmd);
752 
753         match cmd {
754             UciManagerCmd::SetLoggerMode { logger_mode } => {
755                 self.logger.set_logger_mode(logger_mode);
756                 let _ = result_sender.send(Ok(UciResponse::SetLoggerMode));
757             }
758             UciManagerCmd::SetCoreNotificationSender { core_notf_sender } => {
759                 self.core_notf_sender = core_notf_sender;
760                 let _ = result_sender.send(Ok(UciResponse::SetNotification));
761             }
762             UciManagerCmd::SetSessionNotificationSender { session_notf_sender } => {
763                 self.session_notf_sender = session_notf_sender;
764                 let _ = result_sender.send(Ok(UciResponse::SetNotification));
765             }
766             UciManagerCmd::SetVendorNotificationSender { vendor_notf_sender } => {
767                 self.vendor_notf_sender = vendor_notf_sender;
768                 let _ = result_sender.send(Ok(UciResponse::SetNotification));
769             }
770             UciManagerCmd::SetDataRcvNotificationSender { data_rcv_notf_sender } => {
771                 self.data_rcv_notf_sender = data_rcv_notf_sender;
772                 let _ = result_sender.send(Ok(UciResponse::SetNotification));
773             }
774             UciManagerCmd::OpenHal => {
775                 if self.is_hal_opened {
776                     warn!("The UCI HAL is already opened, skip.");
777                     let _ = result_sender.send(Err(Error::BadParameters));
778                     return;
779                 }
780 
781                 let (packet_sender, packet_receiver) = mpsc::unbounded_channel();
782                 let result = self.hal.open(packet_sender).await;
783                 self.logger.log_hal_open(&result);
784                 match result {
785                     Ok(()) => {
786                         self.on_hal_open(packet_receiver);
787                         self.wait_device_status_timeout =
788                             PinSleep::new(Duration::from_millis(UCI_TIMEOUT_MS));
789                         self.open_hal_result_sender.replace(result_sender);
790                     }
791                     Err(e) => {
792                         error!("Failed to open hal: {:?}", e);
793                         let _ = result_sender.send(Err(e));
794                     }
795                 }
796             }
797 
798             UciManagerCmd::CloseHal { force } => {
799                 if force {
800                     debug!("Force closing the UCI HAL");
801                     let close_result = self.hal.close().await;
802                     self.logger.log_hal_close(&close_result);
803                     self.on_hal_closed();
804                     let _ = result_sender.send(Ok(UciResponse::CloseHal));
805                 } else {
806                     if !self.is_hal_opened {
807                         warn!("The UCI HAL is already closed, skip.");
808                         let _ = result_sender.send(Err(Error::BadParameters));
809                         return;
810                     }
811 
812                     let result = self.hal.close().await;
813                     self.logger.log_hal_close(&result);
814                     if result.is_ok() {
815                         self.on_hal_closed();
816                     }
817                     let _ = result_sender.send(result.map(|_| UciResponse::CloseHal));
818                 }
819             }
820 
821             UciManagerCmd::SendUciCommand { cmd } => {
822                 debug_assert!(self.uci_cmd_retryer.is_none());
823 
824                 self.save_session_id_if_init_cmd(&cmd);
825 
826                 // Remember that this command is a raw UCI command, we'll use this later
827                 // to send a raw UCI response.
828                 if let UciCommand::RawUciCmd { mt: _, gid, oid, payload: _ } = cmd.clone() {
829                     let gid_u8 = u8::try_from(gid);
830                     if gid_u8.is_err() || GroupId::try_from(gid_u8.unwrap()).is_err() {
831                         error!("Received an invalid GID={} for RawUciCmd", gid);
832                         let _ = result_sender.send(Err(Error::BadParameters));
833                         return;
834                     }
835 
836                     let oid_u8 = u8::try_from(oid);
837                     if oid_u8.is_err() {
838                         error!("Received an invalid OID={} for RawUciCmd", oid);
839                         let _ = result_sender.send(Err(Error::BadParameters));
840                         return;
841                     }
842                     self.last_raw_cmd = Some(RawUciControlPacket {
843                         mt: u8::from(MessageType::Command),
844                         gid: gid_u8.unwrap(), // Safe as we check gid_u8.is_err() above.
845                         oid: oid_u8.unwrap(), // Safe as we check uid_i8.is_err() above.
846                         payload: Vec::new(),  // There's no need to store the Raw UCI CMD's payload.
847                     });
848                 }
849 
850                 self.uci_cmd_retryer =
851                     Some(UciCmdRetryer { cmd, result_sender, retry_count: MAX_RETRY_COUNT });
852 
853                 // Reset DataSndRetryer so if a CORE_GENERIC_ERROR_NTF with STATUS_UCI_PACKET_RETRY
854                 // is received, only this UCI CMD packet will be retried.
855                 let _ = self.uci_data_snd_retryer.take();
856 
857                 self.retry_uci_cmd().await;
858             }
859 
860             UciManagerCmd::SendUciData { data_snd_packet } => {
861                 let result = self.handle_data_snd_packet(data_snd_packet).await;
862                 let _ = result_sender.send(result);
863             }
864         }
865     }
866 
retry_uci_cmd(&mut self)867     async fn retry_uci_cmd(&mut self) {
868         if let Some(mut uci_cmd_retryer) = self.uci_cmd_retryer.take() {
869             if !uci_cmd_retryer.could_retry() {
870                 error!("Out of retries for Uci Cmd packet");
871                 uci_cmd_retryer.send_result(Err(Error::Timeout));
872                 return;
873             }
874 
875             match self.send_uci_command(uci_cmd_retryer.cmd.clone()).await {
876                 Ok(_) => {
877                     self.wait_resp_timeout = PinSleep::new(Duration::from_millis(UCI_TIMEOUT_MS));
878                     self.uci_cmd_retryer = Some(uci_cmd_retryer);
879                 }
880                 Err(e) => {
881                     error!("Uci Cmd send resulted in error:{}", e);
882                     uci_cmd_retryer.send_result(Err(e));
883                 }
884             }
885         }
886     }
887 
retry_uci_data_snd(&mut self)888     async fn retry_uci_data_snd(&mut self) {
889         if let Some(mut uci_data_snd_retryer) = self.uci_data_snd_retryer.take() {
890             let data_packet_session_token = uci_data_snd_retryer.data_packet_session_token;
891             if !uci_data_snd_retryer.could_retry() {
892                 error!(
893                     "Out of retries for Uci DataSnd packet, last DataSnd packet session_id:{}",
894                     data_packet_session_token
895                 );
896                 return;
897             }
898 
899             match self.hal.send_packet(uci_data_snd_retryer.data_packet.clone().to_vec()).await {
900                 Ok(_) => {
901                     self.uci_data_snd_retryer = Some(uci_data_snd_retryer);
902                 }
903                 Err(e) => {
904                     error!(
905                         "DataSnd packet fragment session_id:{} retry failed with error:{}",
906                         data_packet_session_token, e
907                     );
908                 }
909             }
910         }
911     }
912 
send_uci_command(&mut self, cmd: UciCommand) -> Result<()>913     async fn send_uci_command(&mut self, cmd: UciCommand) -> Result<()> {
914         if !self.is_hal_opened {
915             warn!("The UCI HAL is already closed, skip.");
916             return Err(Error::BadParameters);
917         }
918         let result = self.hal.send_command(cmd.clone()).await;
919         if result.is_ok() {
920             self.logger.log_uci_command(&cmd);
921         }
922         result
923     }
924 
handle_data_snd_packet(&mut self, data_snd_packet: UciDataSnd) -> Result<UciResponse>925     async fn handle_data_snd_packet(&mut self, data_snd_packet: UciDataSnd) -> Result<UciResponse> {
926         // Verify that there's an entry for the Session in the CreditAvailability map.
927         let data_packet_session_token = data_snd_packet.get_session_token();
928         let data_packet_sequence_number = data_snd_packet.get_uci_sequence_number();
929 
930         if !self.data_credit_map.contains_key(&data_packet_session_token) {
931             error!(
932                 "DataSnd packet session_token:{}, sequence_number:{} cannot be sent as unknown \
933                 credit availability for the session",
934                 data_packet_session_token, data_packet_sequence_number
935             );
936             return Err(Error::PacketTxError);
937         }
938 
939         // Enqueue the data packet fragments, from the data packet to be sent to UWBS.
940         let mut packet_fragments: Vec<UciDataPacketHal> = data_snd_packet.into();
941         if packet_fragments.is_empty() {
942             error!(
943                 "DataSnd packet session_token:{}, sequence number:{} could not be split into fragments",
944                 data_packet_session_token, data_packet_sequence_number
945             );
946             return Err(Error::PacketTxError);
947         }
948 
949         match self.data_packet_fragments_map.get_mut(&data_packet_session_token) {
950             Some(q) => {
951                 for p in packet_fragments.drain(..) {
952                     q.push_back(p);
953                 }
954             }
955             None => {
956                 error!(
957                     "DataSnd packet fragments map not found for session_token:{}",
958                     data_packet_session_token
959                 );
960                 return Err(Error::PacketTxError);
961             }
962         }
963 
964         self.send_data_packet_fragment(data_packet_session_token).await
965     }
966 
send_data_packet_fragment( &mut self, data_packet_session_token: SessionToken, ) -> Result<UciResponse>967     async fn send_data_packet_fragment(
968         &mut self,
969         data_packet_session_token: SessionToken,
970     ) -> Result<UciResponse> {
971         // Check if a credit is available before sending this data packet fragment. If not, return
972         // for now, and send this packet later when the credit becomes available (indicated by
973         // receiving a DataCreditNtf).
974         let credit = self.data_credit_map.get(&data_packet_session_token);
975         if credit.is_none() {
976             error!(
977                 "DataSnd packet fragment cannot be sent for session_token:{} as unknown \
978                 credit availability for the session",
979                 data_packet_session_token
980             );
981             return Err(Error::PacketTxError);
982         }
983         if credit == Some(&CreditAvailability::CreditNotAvailable) {
984             return Ok(UciResponse::SendUciData(Ok(())));
985         }
986 
987         // We have credit available, let's send the packet to UWBS.
988         let hal_data_packet_fragment =
989             match self.data_packet_fragments_map.get_mut(&data_packet_session_token) {
990                 Some(q) => {
991                     match q.pop_front() {
992                         Some(p) => p,
993                         None => {
994                             // No more packets left to send.
995                             return Ok(UciResponse::SendUciData(Ok(())));
996                         }
997                     }
998                 }
999                 None => {
1000                     return Err(Error::PacketTxError);
1001                 }
1002             };
1003 
1004         // Create and save a retryer for sending this data packet fragment.
1005         self.uci_data_snd_retryer = Some(UciDataSndRetryer {
1006             data_packet: hal_data_packet_fragment.clone(),
1007             data_packet_session_token,
1008             retry_count: MAX_RETRY_COUNT,
1009         });
1010 
1011         let result = self.hal.send_packet(hal_data_packet_fragment.to_vec()).await;
1012         if result.is_err() {
1013             error!(
1014                 "Result {:?} of sending data packet fragment SessionToken: {} to HAL",
1015                 result, data_packet_session_token
1016             );
1017             return Err(Error::PacketTxError);
1018         }
1019 
1020         // Update the map after the successful write.
1021         self.data_credit_map
1022             .insert(data_packet_session_token, CreditAvailability::CreditNotAvailable);
1023         Ok(UciResponse::SendUciData(Ok(())))
1024     }
1025 
handle_hal_packet(&mut self, packet: Option<UciHalPacket>)1026     async fn handle_hal_packet(&mut self, packet: Option<UciHalPacket>) {
1027         let defrag_packet = match packet {
1028             Some(rx_packet) => {
1029                 self.defrager.defragment_packet(&rx_packet, self.last_raw_cmd.clone())
1030             }
1031             None => {
1032                 warn!("UciHal dropped the packet_sender unexpectedly.");
1033                 self.on_hal_closed();
1034                 return;
1035             }
1036         };
1037         let defrag_packet = match defrag_packet {
1038             Some(p) => p,
1039             None => return,
1040         };
1041 
1042         match defrag_packet {
1043             UciDefragPacket::Control(packet) => {
1044                 self.logger.log_uci_response_or_notification(&packet);
1045 
1046                 match packet.try_into() {
1047                     Ok(UciMessage::Response(resp)) => {
1048                         self.handle_response(resp).await;
1049                     }
1050                     Ok(UciMessage::Notification(notf)) => {
1051                         self.handle_notification(notf).await;
1052                     }
1053                     Err(e) => {
1054                         error!("Failed to parse received message: {:?}", e);
1055                     }
1056                 }
1057             }
1058             UciDefragPacket::Data(packet) => {
1059                 self.logger.log_uci_data(&packet);
1060                 self.handle_data_rcv(packet);
1061             }
1062             UciDefragPacket::Raw(result, raw_uci_control_packet) => {
1063                 // Handle response to raw UCI cmd. We want to send it back as
1064                 // raw UCI message instead of standard response message.
1065                 let resp = match result {
1066                     Ok(()) => {
1067                         // We should receive only a valid UCI response packet here.
1068                         UciResponse::RawUciCmd(Ok(RawUciMessage {
1069                             gid: raw_uci_control_packet.gid.into(),
1070                             oid: raw_uci_control_packet.oid.into(),
1071                             payload: raw_uci_control_packet.payload,
1072                         }))
1073                     }
1074                     // TODO: Implement conversion between Error::InvalidPacketError (returned by
1075                     // lib.rs and defined in the PDL uci_packets.rs) and the uwb_core::Error enums.
1076                     Err(_) => UciResponse::RawUciCmd(Err(Error::Unknown)),
1077                 };
1078                 self.handle_response(resp).await;
1079                 self.last_raw_cmd = None;
1080             }
1081         }
1082     }
1083 
handle_response(&mut self, resp: UciResponse)1084     async fn handle_response(&mut self, resp: UciResponse) {
1085         if resp.need_retry() {
1086             self.retry_uci_cmd().await;
1087             return;
1088         }
1089         if let Err(_e) = self.store_session_token_if_init_resp(&resp).await {
1090             error!("Session init response received without a sesson id stored! Something has gone badly wrong: {:?}", resp);
1091             return;
1092         }
1093 
1094         if let Some(uci_cmd_retryer) = self.uci_cmd_retryer.take() {
1095             uci_cmd_retryer.send_result(Ok(resp));
1096         } else {
1097             warn!("Received an UCI response unexpectedly: {:?}", resp);
1098         }
1099     }
1100 
handle_notification(&mut self, notf: UciNotification)1101     async fn handle_notification(&mut self, notf: UciNotification) {
1102         if notf.need_retry() {
1103             // Retry sending both last sent UCI CMD and UCI DataSnd packet since the notification
1104             // could be for either of them.
1105             self.retry_uci_cmd().await;
1106             self.retry_uci_data_snd().await;
1107             return;
1108         }
1109 
1110         match notf {
1111             UciNotification::Core(core_notf) => {
1112                 if let CoreNotification::DeviceStatus(status) = core_notf {
1113                     if let Some(result_sender) = self.open_hal_result_sender.take() {
1114                         let result = match status {
1115                             DeviceState::DeviceStateReady | DeviceState::DeviceStateActive => {
1116                                 Ok(UciResponse::OpenHal)
1117                             }
1118                             _ => Err(Error::Unknown),
1119                         };
1120                         let _ = result_sender.send(result);
1121                     }
1122                 }
1123                 let _ = self.core_notf_sender.send(core_notf);
1124             }
1125             UciNotification::Session(orig_session_notf) => {
1126                 let mod_session_notf = {
1127                     match self
1128                         .replace_session_token_with_session_id(orig_session_notf.clone())
1129                         .await
1130                     {
1131                         Ok(session_notf) => session_notf,
1132                         Err(e) => {
1133                             error!("Failed to find corresponding session id, discarding session notification {:?}: {:?}", orig_session_notf, e);
1134                             return;
1135                         }
1136                     }
1137                 };
1138                 match orig_session_notf {
1139                     SessionNotification::Status {
1140                         session_token,
1141                         session_state,
1142                         reason_code: _,
1143                     } => self.handle_session_state_notification(session_token, session_state).await,
1144                     SessionNotification::DataCredit { session_token, credit_availability } => {
1145                         if !self.data_credit_map.contains_key(&session_token) {
1146                             // Currently just log, as this is unexpected (the entry should exist once
1147                             // the ranging session is Active and be removed once it is Idle).
1148                             debug!(
1149                                 "Received a DataCreditNtf for non-existent session_token: {}",
1150                                 session_token
1151                             );
1152                         }
1153                         self.data_credit_map.insert(session_token, credit_availability);
1154                         if credit_availability == CreditAvailability::CreditAvailable {
1155                             if let Err(e) = self.send_data_packet_fragment(session_token).await {
1156                                 error!(
1157                                     "Sending data packet fragment failed with Err:{}, after a\
1158                                    DataCreditNtf is received, for session_token:{}",
1159                                     e, session_token
1160                                 );
1161                             }
1162                         } else {
1163                             // Log as this should usually not happen (it's not an error).
1164                             debug!(
1165                             "Received a DataCreditNtf with no credit available for session_token:{}",
1166                             session_token
1167                         );
1168                         }
1169                         return; // We consume these here and don't need to send to upper layer.
1170                     }
1171                     SessionNotification::DataTransferStatus {
1172                         session_token: _,
1173                         uci_sequence_number: _,
1174                         status: _,
1175                     } => {
1176                         // Reset the UciDataSnd Retryer since we received a DataTransferStatusNtf.
1177                         let _ = self.uci_data_snd_retryer.take();
1178                     }
1179                     _ => {}
1180                 }
1181                 let _ = self.session_notf_sender.send(mod_session_notf);
1182             }
1183             UciNotification::Vendor(vendor_notf) => {
1184                 let _ = self.vendor_notf_sender.send(vendor_notf);
1185             }
1186         }
1187     }
1188 
1189     // Modify session_token field in all session related notifications with session id.
1190     // TODO: Sharing of structs across UCI (PDL) & JNI layer like this makes this ugly. Ideally
1191     // the struct sent to JNI layer should only contain |session_id| and at uci layer
1192     // it could be |session_id| or |session_handle|.
replace_session_token_with_session_id( &self, session_notification: SessionNotification, ) -> Result<SessionNotification>1193     async fn replace_session_token_with_session_id(
1194         &self,
1195         session_notification: SessionNotification,
1196     ) -> Result<SessionNotification> {
1197         match session_notification {
1198             SessionNotification::Status { session_token, session_state, reason_code } => {
1199                 Ok(SessionNotification::Status {
1200                     session_token: self.get_session_id(&session_token).await?,
1201                     session_state,
1202                     reason_code,
1203                 })
1204             }
1205             SessionNotification::UpdateControllerMulticastList {
1206                 session_token,
1207                 remaining_multicast_list_size,
1208                 status_list,
1209             } => Ok(SessionNotification::UpdateControllerMulticastList {
1210                 session_token: self.get_session_id(&session_token).await?,
1211                 remaining_multicast_list_size,
1212                 status_list,
1213             }),
1214             SessionNotification::SessionInfo(session_range_data) => {
1215                 Ok(SessionNotification::SessionInfo(SessionRangeData {
1216                     sequence_number: session_range_data.sequence_number,
1217                     session_token: self.get_session_id(&session_range_data.session_token).await?,
1218                     current_ranging_interval_ms: session_range_data.current_ranging_interval_ms,
1219                     ranging_measurement_type: session_range_data.ranging_measurement_type,
1220                     ranging_measurements: session_range_data.ranging_measurements,
1221                     rcr_indicator: session_range_data.rcr_indicator,
1222                     raw_ranging_data: session_range_data.raw_ranging_data,
1223                 }))
1224             }
1225             SessionNotification::DataTransferStatus {
1226                 session_token,
1227                 uci_sequence_number,
1228                 status,
1229             } => Ok(SessionNotification::DataTransferStatus {
1230                 session_token: self.get_session_id(&session_token).await?,
1231                 uci_sequence_number,
1232                 status,
1233             }),
1234             SessionNotification::DataCredit { session_token, credit_availability } => {
1235                 Ok(SessionNotification::DataCredit {
1236                     session_token: self.get_session_id(&session_token).await?,
1237                     credit_availability,
1238                 })
1239             }
1240         }
1241     }
1242 
handle_session_state_notification( &mut self, session_token: SessionToken, session_state: SessionState, )1243     async fn handle_session_state_notification(
1244         &mut self,
1245         session_token: SessionToken,
1246         session_state: SessionState,
1247     ) {
1248         match session_state {
1249             SessionState::SessionStateInit => {
1250                 if let Err(e) = self.hal.notify_session_initialized(session_token).await {
1251                     warn!("notify_session_initialized() failed: {:?}", e);
1252                 }
1253             }
1254             SessionState::SessionStateActive => {
1255                 self.data_credit_map.insert(session_token, CreditAvailability::CreditAvailable);
1256                 self.data_packet_fragments_map.insert(session_token, VecDeque::new());
1257             }
1258             SessionState::SessionStateIdle => {
1259                 self.data_credit_map.remove(&session_token);
1260                 self.data_packet_fragments_map.remove(&session_token);
1261             }
1262             SessionState::SessionStateDeinit => {
1263                 self.remove_session_token(&session_token).await;
1264             }
1265         }
1266     }
1267 
handle_data_rcv(&mut self, packet: UciDataPacket)1268     fn handle_data_rcv(&mut self, packet: UciDataPacket) {
1269         match packet.try_into() {
1270             Ok(data_rcv) => {
1271                 let _ = self.data_rcv_notf_sender.send(data_rcv);
1272             }
1273             Err(e) => {
1274                 error!("Unable to parse incoming Data packet, error {:?}", e);
1275             }
1276         }
1277     }
1278 
on_hal_open(&mut self, packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>)1279     fn on_hal_open(&mut self, packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>) {
1280         self.is_hal_opened = true;
1281         self.packet_receiver = packet_receiver;
1282     }
1283 
on_hal_closed(&mut self)1284     fn on_hal_closed(&mut self) {
1285         self.is_hal_opened = false;
1286         self.packet_receiver = mpsc::unbounded_channel().1;
1287         self.last_raw_cmd = None;
1288     }
1289 
is_waiting_resp(&self) -> bool1290     fn is_waiting_resp(&self) -> bool {
1291         self.uci_cmd_retryer.is_some()
1292     }
is_waiting_device_status(&self) -> bool1293     fn is_waiting_device_status(&self) -> bool {
1294         self.open_hal_result_sender.is_some()
1295     }
1296 }
1297 
1298 impl<T: UciHal, U: UciLogger> Drop for UciManagerActor<T, U> {
drop(&mut self)1299     fn drop(&mut self) {
1300         // mpsc receiver is about to be dropped. Clean shutdown the mpsc message.
1301         clean_mpsc_receiver(&mut self.packet_receiver);
1302     }
1303 }
1304 
1305 struct UciCmdRetryer {
1306     cmd: UciCommand,
1307     result_sender: oneshot::Sender<Result<UciResponse>>,
1308     retry_count: usize,
1309 }
1310 
1311 impl UciCmdRetryer {
could_retry(&mut self) -> bool1312     fn could_retry(&mut self) -> bool {
1313         if self.retry_count == 0 {
1314             return false;
1315         }
1316         self.retry_count -= 1;
1317         true
1318     }
1319 
send_result(self, result: Result<UciResponse>)1320     fn send_result(self, result: Result<UciResponse>) {
1321         let _ = self.result_sender.send(result);
1322     }
1323 }
1324 
1325 struct UciDataSndRetryer {
1326     // Store the last-sent DataSnd packet fragment across all the active UWB session, as the UCI
1327     // spec states that the "last UCI packet should be re-transmitted from Host".
1328     //
1329     // TODO(b/273376343): The spec is open to a race condition in the scenario of multiple active
1330     // sessions, as there can be outstanding DataSnd packet fragments across them. We could do an
1331     // alternative implementation of sending all of them.
1332     data_packet: UciDataPacketHal,
1333     data_packet_session_token: SessionToken,
1334     retry_count: usize,
1335 }
1336 
1337 impl UciDataSndRetryer {
could_retry(&mut self) -> bool1338     fn could_retry(&mut self) -> bool {
1339         if self.retry_count == 0 {
1340             return false;
1341         }
1342         self.retry_count -= 1;
1343         true
1344     }
1345 }
1346 
1347 #[derive(Debug)]
1348 enum UciManagerCmd {
1349     SetLoggerMode {
1350         logger_mode: UciLoggerMode,
1351     },
1352     SetCoreNotificationSender {
1353         core_notf_sender: mpsc::UnboundedSender<CoreNotification>,
1354     },
1355     SetSessionNotificationSender {
1356         session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
1357     },
1358     SetVendorNotificationSender {
1359         vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
1360     },
1361     SetDataRcvNotificationSender {
1362         data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
1363     },
1364     OpenHal,
1365     CloseHal {
1366         force: bool,
1367     },
1368     SendUciCommand {
1369         cmd: UciCommand,
1370     },
1371     SendUciData {
1372         data_snd_packet: UciDataSnd,
1373     },
1374 }
1375 
1376 #[cfg(any(test))]
1377 mod tests {
1378     use super::*;
1379 
1380     use bytes::Bytes;
1381     use tokio::macros::support::Future;
1382     use uwb_uci_packets::{SessionGetCountCmdBuilder, SessionGetCountRspBuilder};
1383 
1384     use crate::params::uci_packets::{
1385         AppConfigStatus, AppConfigTlvType, CapTlvType, Controlee, DataTransferNtfStatusCode,
1386         StatusCode,
1387     };
1388     use crate::uci::mock_uci_hal::MockUciHal;
1389     use crate::uci::mock_uci_logger::{MockUciLogger, UciLogEvent};
1390     use crate::uci::uci_logger::NopUciLogger;
1391     use crate::utils::init_test_logging;
1392 
into_uci_hal_packets<T: Into<uwb_uci_packets::UciControlPacket>>( builder: T, ) -> Vec<UciHalPacket>1393     fn into_uci_hal_packets<T: Into<uwb_uci_packets::UciControlPacket>>(
1394         builder: T,
1395     ) -> Vec<UciHalPacket> {
1396         let packets: Vec<uwb_uci_packets::UciControlPacketHal> = builder.into().into();
1397         packets.into_iter().map(|packet| packet.into()).collect()
1398     }
1399 
1400     // 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>1401     fn build_uci_packet(mt: u8, pbf: u8, gid: u8, oid: u8, mut payload: Vec<u8>) -> Vec<u8> {
1402         let len: u16 = payload.len() as u16;
1403         let mut bytes: Vec<u8> = vec![(mt & 0x7) << 5 | (pbf & 0x1) << 4 | (gid & 0xF), oid & 0x3F];
1404         if mt == 0 {
1405             // UCI Data packet
1406             // Store 16-bit payload length in LSB format.
1407             bytes.push((len & 0xFF).try_into().unwrap());
1408             bytes.push((len >> 8).try_into().unwrap());
1409         } else {
1410             // One byte RFU, followed by one-byte payload length.
1411             bytes.push(0);
1412             bytes.push((len & 0xFF).try_into().unwrap());
1413         }
1414         bytes.append(&mut payload);
1415         bytes
1416     }
1417 
setup_hal_for_open(hal: &mut MockUciHal)1418     fn setup_hal_for_open(hal: &mut MockUciHal) {
1419         // Setup Open the hal.
1420         let notf = into_uci_hal_packets(uwb_uci_packets::DeviceStatusNtfBuilder {
1421             device_state: uwb_uci_packets::DeviceState::DeviceStateReady,
1422         });
1423         hal.expected_open(Some(notf), Ok(()));
1424 
1425         // Setup Get the device info.
1426         let cmd = UciCommand::CoreGetDeviceInfo;
1427         let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder {
1428             status: uwb_uci_packets::StatusCode::UciStatusOk,
1429             uci_version: 0x1234,
1430             mac_version: 0x5678,
1431             phy_version: 0x90ab,
1432             uci_test_version: 0x1357,
1433             vendor_spec_info: vec![0x1, 0x2],
1434         });
1435         hal.expected_send_command(cmd, resp, Ok(()));
1436     }
1437 
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 = ()>,1438     async fn setup_uci_manager_with_open_hal<F, Fut>(
1439         setup_hal_fn: F,
1440         uci_logger_mode: UciLoggerMode,
1441         log_sender: mpsc::UnboundedSender<UciLogEvent>,
1442     ) -> (UciManagerImpl, MockUciHal)
1443     where
1444         F: FnOnce(MockUciHal) -> Fut,
1445         Fut: Future<Output = ()>,
1446     {
1447         init_test_logging();
1448 
1449         let mut hal = MockUciHal::new();
1450         // Open the hal.
1451         setup_hal_for_open(&mut hal);
1452 
1453         // Verify open_hal() is working.
1454         let uci_manager =
1455             UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode);
1456         let result = uci_manager.open_hal().await;
1457         assert!(result.is_ok());
1458         assert!(hal.wait_expected_calls_done().await);
1459 
1460         setup_hal_fn(hal.clone()).await;
1461 
1462         (uci_manager, hal)
1463     }
1464 
1465     #[tokio::test]
test_open_hal_without_notification()1466     async fn test_open_hal_without_notification() {
1467         init_test_logging();
1468 
1469         let mut hal = MockUciHal::new();
1470         hal.expected_open(None, Ok(()));
1471         let uci_manager =
1472             UciManagerImpl::new(hal.clone(), NopUciLogger::default(), UciLoggerMode::Disabled);
1473 
1474         let result = uci_manager.open_hal().await;
1475         assert!(matches!(result, Err(Error::Timeout)));
1476         assert!(hal.wait_expected_calls_done().await);
1477     }
1478 
1479     #[tokio::test]
test_close_hal_explicitly()1480     async fn test_close_hal_explicitly() {
1481         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
1482             |mut hal| async move {
1483                 hal.expected_close(Ok(()));
1484             },
1485             UciLoggerMode::Disabled,
1486             mpsc::unbounded_channel::<UciLogEvent>().0,
1487         )
1488         .await;
1489 
1490         let result = uci_manager.close_hal(false).await;
1491         assert!(result.is_ok());
1492         assert!(mock_hal.wait_expected_calls_done().await);
1493     }
1494 
1495     #[tokio::test]
test_close_hal_when_exit()1496     async fn test_close_hal_when_exit() {
1497         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
1498             |mut hal| async move {
1499                 // UciManager should close the hal if the hal is still opened when exit.
1500                 hal.expected_close(Ok(()));
1501             },
1502             UciLoggerMode::Disabled,
1503             mpsc::unbounded_channel::<UciLogEvent>().0,
1504         )
1505         .await;
1506 
1507         drop(uci_manager);
1508         assert!(mock_hal.wait_expected_calls_done().await);
1509     }
1510 
1511     #[tokio::test]
test_close_hal_without_open_hal()1512     async fn test_close_hal_without_open_hal() {
1513         init_test_logging();
1514 
1515         let mut hal = MockUciHal::new();
1516         let uci_manager =
1517             UciManagerImpl::new(hal.clone(), NopUciLogger::default(), UciLoggerMode::Disabled);
1518 
1519         let result = uci_manager.close_hal(false).await;
1520         assert!(matches!(result, Err(Error::BadParameters)));
1521         assert!(hal.wait_expected_calls_done().await);
1522     }
1523 
1524     #[tokio::test]
test_device_reset_ok()1525     async fn test_device_reset_ok() {
1526         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
1527             |mut hal| async move {
1528                 let cmd = UciCommand::DeviceReset { reset_config: ResetConfig::UwbsReset };
1529                 let resp = into_uci_hal_packets(uwb_uci_packets::DeviceResetRspBuilder {
1530                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1531                 });
1532                 hal.expected_send_command(cmd, resp, Ok(()));
1533             },
1534             UciLoggerMode::Disabled,
1535             mpsc::unbounded_channel::<UciLogEvent>().0,
1536         )
1537         .await;
1538 
1539         let result = uci_manager.device_reset(ResetConfig::UwbsReset).await;
1540         assert!(result.is_ok());
1541         assert!(mock_hal.wait_expected_calls_done().await);
1542     }
1543 
1544     #[tokio::test]
test_core_get_device_info_ok()1545     async fn test_core_get_device_info_ok() {
1546         let status = StatusCode::UciStatusOk;
1547         let uci_version = 0x1234;
1548         let mac_version = 0x5678;
1549         let phy_version = 0x90ab;
1550         let uci_test_version = 0x1357;
1551         let vendor_spec_info = vec![0x1, 0x2];
1552         let vendor_spec_info_clone = vendor_spec_info.clone();
1553 
1554         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
1555             |mut hal| async move {
1556                 let cmd = UciCommand::CoreGetDeviceInfo;
1557                 let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder {
1558                     status,
1559                     uci_version,
1560                     mac_version,
1561                     phy_version,
1562                     uci_test_version,
1563                     vendor_spec_info: vendor_spec_info_clone,
1564                 });
1565 
1566                 hal.expected_send_command(cmd, resp, Ok(()));
1567             },
1568             UciLoggerMode::Disabled,
1569             mpsc::unbounded_channel::<UciLogEvent>().0,
1570         )
1571         .await;
1572 
1573         let expected_result = GetDeviceInfoResponse {
1574             uci_version,
1575             mac_version,
1576             phy_version,
1577             uci_test_version,
1578             vendor_spec_info,
1579         };
1580         let result = uci_manager.core_get_device_info().await.unwrap();
1581         assert_eq!(result, expected_result);
1582         assert!(mock_hal.wait_expected_calls_done().await);
1583     }
1584 
1585     #[tokio::test]
test_core_get_caps_info_ok()1586     async fn test_core_get_caps_info_ok() {
1587         let tlv = CapTlv { t: CapTlvType::SupportedFiraPhyVersionRange, v: vec![0x12, 0x34, 0x56] };
1588         let tlv_clone = tlv.clone();
1589 
1590         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
1591             |mut hal| async move {
1592                 let cmd = UciCommand::CoreGetCapsInfo;
1593                 let resp = into_uci_hal_packets(uwb_uci_packets::GetCapsInfoRspBuilder {
1594                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1595                     tlvs: vec![tlv_clone],
1596                 });
1597 
1598                 hal.expected_send_command(cmd, resp, Ok(()));
1599             },
1600             UciLoggerMode::Disabled,
1601             mpsc::unbounded_channel::<UciLogEvent>().0,
1602         )
1603         .await;
1604 
1605         let result = uci_manager.core_get_caps_info().await.unwrap();
1606         assert_eq!(result[0], tlv);
1607         assert!(mock_hal.wait_expected_calls_done().await);
1608     }
1609 
1610     #[tokio::test]
test_core_set_config_ok()1611     async fn test_core_set_config_ok() {
1612         let tlv = DeviceConfigTlv {
1613             cfg_id: uwb_uci_packets::DeviceConfigId::DeviceState,
1614             v: vec![0x12, 0x34, 0x56],
1615         };
1616         let tlv_clone = tlv.clone();
1617         let status = StatusCode::UciStatusOk;
1618         let config_status = vec![];
1619         let config_status_clone = config_status.clone();
1620 
1621         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
1622             |mut hal| async move {
1623                 let cmd = UciCommand::CoreSetConfig { config_tlvs: vec![tlv_clone] };
1624                 let resp = into_uci_hal_packets(uwb_uci_packets::SetConfigRspBuilder {
1625                     status,
1626                     cfg_status: config_status_clone,
1627                 });
1628 
1629                 hal.expected_send_command(cmd, resp, Ok(()));
1630             },
1631             UciLoggerMode::Disabled,
1632             mpsc::unbounded_channel::<UciLogEvent>().0,
1633         )
1634         .await;
1635 
1636         let expected_result = CoreSetConfigResponse { status, config_status };
1637         let result = uci_manager.core_set_config(vec![tlv]).await.unwrap();
1638         assert_eq!(result, expected_result);
1639         assert!(mock_hal.wait_expected_calls_done().await);
1640     }
1641 
1642     #[tokio::test]
test_core_get_config_ok()1643     async fn test_core_get_config_ok() {
1644         let cfg_id = DeviceConfigId::DeviceState;
1645         let tlv = DeviceConfigTlv { cfg_id, v: vec![0x12, 0x34, 0x56] };
1646         let tlv_clone = tlv.clone();
1647 
1648         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
1649             |mut hal| async move {
1650                 let cmd = UciCommand::CoreGetConfig { cfg_id: vec![cfg_id] };
1651                 let resp = into_uci_hal_packets(uwb_uci_packets::GetConfigRspBuilder {
1652                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1653                     tlvs: vec![tlv_clone],
1654                 });
1655 
1656                 hal.expected_send_command(cmd, resp, Ok(()));
1657             },
1658             UciLoggerMode::Disabled,
1659             mpsc::unbounded_channel::<UciLogEvent>().0,
1660         )
1661         .await;
1662 
1663         let expected_result = vec![tlv];
1664         let result = uci_manager.core_get_config(vec![cfg_id]).await.unwrap();
1665         assert_eq!(result, expected_result);
1666         assert!(mock_hal.wait_expected_calls_done().await);
1667     }
1668 
setup_hal_for_session_initialize( hal: &mut MockUciHal, session_type: SessionType, session_id: u32, session_token: u32, )1669     fn setup_hal_for_session_initialize(
1670         hal: &mut MockUciHal,
1671         session_type: SessionType,
1672         session_id: u32,
1673         session_token: u32,
1674     ) {
1675         // Setup for hal open.
1676         setup_hal_for_open(hal);
1677 
1678         // Setup session init.
1679         let cmd = UciCommand::SessionInit { session_id, session_type };
1680         let mut resp = if session_id == session_token {
1681             into_uci_hal_packets(uwb_uci_packets::SessionInitRspBuilder {
1682                 status: uwb_uci_packets::StatusCode::UciStatusOk,
1683             })
1684         } else {
1685             // This is testing FIRA v2 flow where a session handle is provided by UWBS.
1686             into_uci_hal_packets(uwb_uci_packets::SessionInitRsp_V2Builder {
1687                 status: uwb_uci_packets::StatusCode::UciStatusOk,
1688                 session_handle: session_token,
1689             })
1690         };
1691         let mut notf = into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder {
1692             session_token,
1693             session_state: uwb_uci_packets::SessionState::SessionStateInit,
1694             reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
1695                 .into(),
1696         });
1697         resp.append(&mut notf);
1698         hal.expected_send_command(cmd, resp, Ok(()));
1699         hal.expected_notify_session_initialized(session_token, Ok(()));
1700     }
1701 
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 = ()>,1702     async fn setup_uci_manager_with_session_initialized<F, Fut>(
1703         setup_hal_fn: F,
1704         uci_logger_mode: UciLoggerMode,
1705         log_sender: mpsc::UnboundedSender<UciLogEvent>,
1706         session_id: u32,
1707         session_token: u32,
1708     ) -> (UciManagerImpl, MockUciHal)
1709     where
1710         F: FnOnce(MockUciHal) -> Fut,
1711         Fut: Future<Output = ()>,
1712     {
1713         let session_type = SessionType::FiraRangingSession;
1714 
1715         init_test_logging();
1716 
1717         let mut hal = MockUciHal::new();
1718         setup_hal_for_session_initialize(&mut hal, session_type, session_id, session_token);
1719 
1720         // Verify open_hal() is working.
1721         let uci_manager =
1722             UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode);
1723         let result = uci_manager.open_hal().await;
1724         assert!(result.is_ok());
1725 
1726         // Verify session is initialized.
1727         let result = uci_manager.session_init(session_id, session_type).await;
1728         assert!(result.is_ok());
1729         assert!(hal.wait_expected_calls_done().await);
1730 
1731         setup_hal_fn(hal.clone()).await;
1732 
1733         (uci_manager, hal)
1734     }
1735 
1736     #[tokio::test]
test_session_init_ok()1737     async fn test_session_init_ok() {
1738         let session_id = 0x123;
1739         let session_token = 0x123;
1740         let (_, mut mock_hal) = setup_uci_manager_with_session_initialized(
1741             |_hal| async move {},
1742             UciLoggerMode::Disabled,
1743             mpsc::unbounded_channel::<UciLogEvent>().0,
1744             session_id,
1745             session_token,
1746         )
1747         .await;
1748         assert!(mock_hal.wait_expected_calls_done().await);
1749     }
1750 
1751     #[tokio::test]
test_session_init_v2_ok()1752     async fn test_session_init_v2_ok() {
1753         let session_id = 0x123;
1754         let session_token = 0x321; // different session handle
1755         let (_, mut mock_hal) = setup_uci_manager_with_session_initialized(
1756             |_hal| async move {},
1757             UciLoggerMode::Disabled,
1758             mpsc::unbounded_channel::<UciLogEvent>().0,
1759             session_id,
1760             session_token,
1761         )
1762         .await;
1763         assert!(mock_hal.wait_expected_calls_done().await);
1764     }
1765 
1766     #[tokio::test]
test_session_deinit_ok()1767     async fn test_session_deinit_ok() {
1768         let session_id = 0x123;
1769         let session_token = 0x123;
1770 
1771         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
1772             |mut hal| async move {
1773                 let cmd = UciCommand::SessionDeinit { session_token };
1774                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionDeinitRspBuilder {
1775                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1776                 });
1777 
1778                 hal.expected_send_command(cmd, resp, Ok(()));
1779             },
1780             UciLoggerMode::Disabled,
1781             mpsc::unbounded_channel::<UciLogEvent>().0,
1782             session_id,
1783             session_token,
1784         )
1785         .await;
1786 
1787         let result = uci_manager.session_deinit(session_id).await;
1788         assert!(result.is_ok());
1789         assert!(mock_hal.wait_expected_calls_done().await);
1790     }
1791 
1792     #[tokio::test]
test_session_deinit_v2_ok()1793     async fn test_session_deinit_v2_ok() {
1794         let session_id = 0x123;
1795         let session_token = 0x321; // different session handle
1796 
1797         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
1798             |mut hal| async move {
1799                 let cmd = UciCommand::SessionDeinit { session_token };
1800                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionDeinitRspBuilder {
1801                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1802                 });
1803 
1804                 hal.expected_send_command(cmd, resp, Ok(()));
1805             },
1806             UciLoggerMode::Disabled,
1807             mpsc::unbounded_channel::<UciLogEvent>().0,
1808             session_id,
1809             session_token,
1810         )
1811         .await;
1812 
1813         let result = uci_manager.session_deinit(session_id).await;
1814         assert!(result.is_ok());
1815         assert!(mock_hal.wait_expected_calls_done().await);
1816     }
1817 
1818     #[tokio::test]
test_session_set_app_config_ok()1819     async fn test_session_set_app_config_ok() {
1820         let session_id = 0x123;
1821         let session_token = 0x123;
1822         let config_tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]);
1823         let config_tlv_clone = config_tlv.clone();
1824 
1825         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
1826             |mut hal| async move {
1827                 let cmd = UciCommand::SessionSetAppConfig {
1828                     session_token,
1829                     config_tlvs: vec![config_tlv_clone],
1830                 };
1831                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
1832                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1833                     cfg_status: vec![],
1834                 });
1835 
1836                 hal.expected_send_command(cmd, resp, Ok(()));
1837             },
1838             UciLoggerMode::Disabled,
1839             mpsc::unbounded_channel::<UciLogEvent>().0,
1840             session_id,
1841             session_token,
1842         )
1843         .await;
1844 
1845         let expected_result =
1846             SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] };
1847         let result =
1848             uci_manager.session_set_app_config(session_id, vec![config_tlv]).await.unwrap();
1849         assert_eq!(result, expected_result);
1850         assert!(mock_hal.wait_expected_calls_done().await);
1851     }
1852 
1853     #[tokio::test]
test_session_set_app_config_v2_ok()1854     async fn test_session_set_app_config_v2_ok() {
1855         let session_id = 0x123;
1856         let session_token = 0x321;
1857         let config_tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]);
1858         let config_tlv_clone = config_tlv.clone();
1859 
1860         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
1861             |mut hal| async move {
1862                 let cmd = UciCommand::SessionSetAppConfig {
1863                     session_token,
1864                     config_tlvs: vec![config_tlv_clone],
1865                 };
1866                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
1867                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1868                     cfg_status: vec![],
1869                 });
1870 
1871                 hal.expected_send_command(cmd, resp, Ok(()));
1872             },
1873             UciLoggerMode::Disabled,
1874             mpsc::unbounded_channel::<UciLogEvent>().0,
1875             session_id,
1876             session_token,
1877         )
1878         .await;
1879 
1880         let expected_result =
1881             SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] };
1882         let result =
1883             uci_manager.session_set_app_config(session_id, vec![config_tlv]).await.unwrap();
1884         assert_eq!(result, expected_result);
1885         assert!(mock_hal.wait_expected_calls_done().await);
1886     }
1887 
1888     #[tokio::test]
test_session_get_app_config_ok()1889     async fn test_session_get_app_config_ok() {
1890         let session_id = 0x123;
1891         let session_token = 0x123;
1892         let config_id = AppConfigTlvType::DeviceType;
1893         let tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]);
1894         let tlv_clone = tlv.clone();
1895 
1896         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
1897             |mut hal| async move {
1898                 let cmd =
1899                     UciCommand::SessionGetAppConfig { session_token, app_cfg: vec![config_id] };
1900                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetAppConfigRspBuilder {
1901                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1902                     tlvs: vec![tlv_clone.into_inner()],
1903                 });
1904 
1905                 hal.expected_send_command(cmd, resp, Ok(()));
1906             },
1907             UciLoggerMode::Disabled,
1908             mpsc::unbounded_channel::<UciLogEvent>().0,
1909             session_id,
1910             session_token,
1911         )
1912         .await;
1913 
1914         let expected_result = vec![tlv];
1915         let result = uci_manager.session_get_app_config(session_id, vec![config_id]).await.unwrap();
1916         assert_eq!(result, expected_result);
1917         assert!(mock_hal.wait_expected_calls_done().await);
1918     }
1919 
1920     #[tokio::test]
test_session_get_count_ok()1921     async fn test_session_get_count_ok() {
1922         let session_count = 5;
1923 
1924         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
1925             |mut hal| async move {
1926                 let cmd = UciCommand::SessionGetCount;
1927                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
1928                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1929                     session_count,
1930                 });
1931 
1932                 hal.expected_send_command(cmd, resp, Ok(()));
1933             },
1934             UciLoggerMode::Disabled,
1935             mpsc::unbounded_channel::<UciLogEvent>().0,
1936         )
1937         .await;
1938 
1939         let result = uci_manager.session_get_count().await.unwrap();
1940         assert_eq!(result, session_count);
1941         assert!(mock_hal.wait_expected_calls_done().await);
1942     }
1943 
1944     #[tokio::test]
test_session_get_state_ok()1945     async fn test_session_get_state_ok() {
1946         let session_id = 0x123;
1947         let session_token = 0x123;
1948         let session_state = SessionState::SessionStateActive;
1949 
1950         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
1951             |mut hal| async move {
1952                 let cmd = UciCommand::SessionGetState { session_token };
1953                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetStateRspBuilder {
1954                     status: uwb_uci_packets::StatusCode::UciStatusOk,
1955                     session_state,
1956                 });
1957 
1958                 hal.expected_send_command(cmd, resp, Ok(()));
1959             },
1960             UciLoggerMode::Disabled,
1961             mpsc::unbounded_channel::<UciLogEvent>().0,
1962             session_id,
1963             session_token,
1964         )
1965         .await;
1966 
1967         let result = uci_manager.session_get_state(session_id).await.unwrap();
1968         assert_eq!(result, session_state);
1969         assert!(mock_hal.wait_expected_calls_done().await);
1970     }
1971 
1972     #[tokio::test]
test_session_update_controller_multicast_list_ok()1973     async fn test_session_update_controller_multicast_list_ok() {
1974         let session_id = 0x123;
1975         let session_token = 0x123;
1976         let action = UpdateMulticastListAction::AddControlee;
1977         let short_address: [u8; 2] = [0x45, 0x67];
1978         let controlee = Controlee { short_address, subsession_id: 0x90ab };
1979         let controlee_clone = controlee.clone();
1980 
1981         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
1982             |mut hal| async move {
1983                 let cmd = UciCommand::SessionUpdateControllerMulticastList {
1984                     session_token,
1985                     action,
1986                     controlees: Controlees::NoSessionKey(vec![controlee_clone]),
1987                 };
1988                 let resp = into_uci_hal_packets(
1989                     uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder {
1990                         status: uwb_uci_packets::StatusCode::UciStatusOk,
1991                     },
1992                 );
1993 
1994                 hal.expected_send_command(cmd, resp, Ok(()));
1995             },
1996             UciLoggerMode::Disabled,
1997             mpsc::unbounded_channel::<UciLogEvent>().0,
1998             session_id,
1999             session_token,
2000         )
2001         .await;
2002 
2003         let result = uci_manager
2004             .session_update_controller_multicast_list(
2005                 session_id,
2006                 action,
2007                 uwb_uci_packets::Controlees::NoSessionKey(vec![controlee]),
2008             )
2009             .await;
2010         assert!(result.is_ok());
2011         assert!(mock_hal.wait_expected_calls_done().await);
2012     }
2013 
2014     #[tokio::test]
test_set_active_dt_tag_ranging_rounds()2015     async fn test_set_active_dt_tag_ranging_rounds() {
2016         let session_id = 0x123;
2017         let session_token = 0x123;
2018 
2019         let ranging_rounds = SessionUpdateDtTagRangingRoundsResponse {
2020             status: StatusCode::UciStatusErrorRoundIndexNotActivated,
2021             ranging_round_indexes: vec![3],
2022         };
2023 
2024         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
2025             |mut hal| async move {
2026                 let cmd = UciCommand::SessionUpdateDtTagRangingRounds {
2027                     session_token,
2028                     ranging_round_indexes: vec![3, 5],
2029                 };
2030                 let resp = into_uci_hal_packets(
2031                     uwb_uci_packets::SessionUpdateDtTagRangingRoundsRspBuilder {
2032                         status: StatusCode::UciStatusErrorRoundIndexNotActivated,
2033                         ranging_round_indexes: vec![3],
2034                     },
2035                 );
2036 
2037                 hal.expected_send_command(cmd, resp, Ok(()));
2038             },
2039             UciLoggerMode::Disabled,
2040             mpsc::unbounded_channel::<UciLogEvent>().0,
2041             session_id,
2042             session_token,
2043         )
2044         .await;
2045 
2046         let result =
2047             uci_manager.session_update_dt_tag_ranging_rounds(session_id, vec![3, 5]).await.unwrap();
2048 
2049         assert_eq!(result, ranging_rounds);
2050         assert!(mock_hal.wait_expected_calls_done().await);
2051     }
2052 
2053     #[tokio::test]
test_range_start_ok()2054     async fn test_range_start_ok() {
2055         let session_id = 0x123;
2056         let session_token = 0x123;
2057 
2058         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
2059             |mut hal| async move {
2060                 let cmd = UciCommand::SessionStart { session_token };
2061                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionStartRspBuilder {
2062                     status: uwb_uci_packets::StatusCode::UciStatusOk,
2063                 });
2064 
2065                 hal.expected_send_command(cmd, resp, Ok(()));
2066             },
2067             UciLoggerMode::Disabled,
2068             mpsc::unbounded_channel::<UciLogEvent>().0,
2069             session_id,
2070             session_token,
2071         )
2072         .await;
2073 
2074         let result = uci_manager.range_start(session_id).await;
2075         assert!(result.is_ok());
2076         assert!(mock_hal.wait_expected_calls_done().await);
2077     }
2078 
2079     #[tokio::test]
test_range_stop_ok()2080     async fn test_range_stop_ok() {
2081         let session_id = 0x123;
2082         let session_token = 0x123;
2083 
2084         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
2085             |mut hal| async move {
2086                 let cmd = UciCommand::SessionStop { session_token };
2087                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionStopRspBuilder {
2088                     status: uwb_uci_packets::StatusCode::UciStatusOk,
2089                 });
2090 
2091                 hal.expected_send_command(cmd, resp, Ok(()));
2092             },
2093             UciLoggerMode::Disabled,
2094             mpsc::unbounded_channel::<UciLogEvent>().0,
2095             session_id,
2096             session_token,
2097         )
2098         .await;
2099 
2100         let result = uci_manager.range_stop(session_id).await;
2101         assert!(result.is_ok());
2102         assert!(mock_hal.wait_expected_calls_done().await);
2103     }
2104 
2105     #[tokio::test]
test_range_get_ranging_count_ok()2106     async fn test_range_get_ranging_count_ok() {
2107         let session_id = 0x123;
2108         let session_token = 0x123;
2109         let count = 3;
2110 
2111         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized(
2112             |mut hal| async move {
2113                 let cmd = UciCommand::SessionGetRangingCount { session_token };
2114                 let resp =
2115                     into_uci_hal_packets(uwb_uci_packets::SessionGetRangingCountRspBuilder {
2116                         status: uwb_uci_packets::StatusCode::UciStatusOk,
2117                         count,
2118                     });
2119 
2120                 hal.expected_send_command(cmd, resp, Ok(()));
2121             },
2122             UciLoggerMode::Disabled,
2123             mpsc::unbounded_channel::<UciLogEvent>().0,
2124             session_id,
2125             session_token,
2126         )
2127         .await;
2128 
2129         let result = uci_manager.range_get_ranging_count(session_id).await.unwrap();
2130         assert_eq!(result, count as usize);
2131         assert!(mock_hal.wait_expected_calls_done().await);
2132     }
2133 
2134     #[tokio::test]
test_android_set_country_code_ok()2135     async fn test_android_set_country_code_ok() {
2136         let country_code = CountryCode::new(b"US").unwrap();
2137         let country_code_clone = country_code.clone();
2138 
2139         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2140             |mut hal| async move {
2141                 let cmd = UciCommand::AndroidSetCountryCode { country_code: country_code_clone };
2142                 let resp = into_uci_hal_packets(uwb_uci_packets::AndroidSetCountryCodeRspBuilder {
2143                     status: uwb_uci_packets::StatusCode::UciStatusOk,
2144                 });
2145 
2146                 hal.expected_send_command(cmd, resp, Ok(()));
2147             },
2148             UciLoggerMode::Disabled,
2149             mpsc::unbounded_channel::<UciLogEvent>().0,
2150         )
2151         .await;
2152 
2153         let result = uci_manager.android_set_country_code(country_code).await;
2154         assert!(result.is_ok());
2155         assert!(mock_hal.wait_expected_calls_done().await);
2156     }
2157 
2158     #[tokio::test]
test_android_get_power_stats_ok()2159     async fn test_android_get_power_stats_ok() {
2160         let power_stats = PowerStats {
2161             status: StatusCode::UciStatusOk,
2162             idle_time_ms: 123,
2163             tx_time_ms: 456,
2164             rx_time_ms: 789,
2165             total_wake_count: 5,
2166         };
2167         let power_stats_clone = power_stats.clone();
2168 
2169         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2170             |mut hal| async move {
2171                 let cmd = UciCommand::AndroidGetPowerStats;
2172                 let resp = into_uci_hal_packets(uwb_uci_packets::AndroidGetPowerStatsRspBuilder {
2173                     stats: power_stats_clone,
2174                 });
2175 
2176                 hal.expected_send_command(cmd, resp, Ok(()));
2177             },
2178             UciLoggerMode::Disabled,
2179             mpsc::unbounded_channel::<UciLogEvent>().0,
2180         )
2181         .await;
2182 
2183         let result = uci_manager.android_get_power_stats().await.unwrap();
2184         assert_eq!(result, power_stats);
2185         assert!(mock_hal.wait_expected_calls_done().await);
2186     }
2187 
2188     #[tokio::test]
test_raw_uci_cmd_vendor_gid_ok()2189     async fn test_raw_uci_cmd_vendor_gid_ok() {
2190         let mt = 0x1;
2191         let gid = 0xF; // Vendor reserved GID.
2192         let oid = 0x3;
2193         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2194         let cmd_payload_clone = cmd_payload.clone();
2195         let resp_payload = vec![0x55, 0x66, 0x77, 0x88];
2196         let resp_payload_clone = resp_payload.clone();
2197 
2198         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2199             |mut hal| async move {
2200                 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
2201                 let resp = into_uci_hal_packets(uwb_uci_packets::UciVendor_F_ResponseBuilder {
2202                     opcode: oid as u8,
2203                     payload: Some(Bytes::from(resp_payload_clone)),
2204                 });
2205 
2206                 hal.expected_send_command(cmd, resp, Ok(()));
2207             },
2208             UciLoggerMode::Disabled,
2209             mpsc::unbounded_channel::<UciLogEvent>().0,
2210         )
2211         .await;
2212 
2213         let expected_result = RawUciMessage { gid, oid, payload: resp_payload };
2214         let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap();
2215         assert_eq!(result, expected_result);
2216         assert!(mock_hal.wait_expected_calls_done().await);
2217     }
2218 
2219     #[tokio::test]
test_raw_uci_cmd_fira_gid_ok()2220     async fn test_raw_uci_cmd_fira_gid_ok() {
2221         let mt = 0x1;
2222         let gid = 0x1; // SESSION_CONFIG GID.
2223         let oid = 0x3;
2224         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2225         let cmd_payload_clone = cmd_payload.clone();
2226         let resp_payload = vec![0x00, 0x01, 0x07, 0x00];
2227         let status = StatusCode::UciStatusOk;
2228         let cfg_id = AppConfigTlvType::DstMacAddress;
2229         let app_config = AppConfigStatus { cfg_id, status };
2230         let cfg_status = vec![app_config];
2231 
2232         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2233             |mut hal| async move {
2234                 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
2235                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
2236                     status,
2237                     cfg_status,
2238                 });
2239 
2240                 hal.expected_send_command(cmd, resp, Ok(()));
2241             },
2242             UciLoggerMode::Disabled,
2243             mpsc::unbounded_channel::<UciLogEvent>().0,
2244         )
2245         .await;
2246 
2247         let expected_result = RawUciMessage { gid, oid, payload: resp_payload };
2248         let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap();
2249         assert_eq!(result, expected_result);
2250         assert!(mock_hal.wait_expected_calls_done().await);
2251     }
2252 
2253     #[tokio::test]
test_raw_uci_cmd_undefined_mt_ok()2254     async fn test_raw_uci_cmd_undefined_mt_ok() {
2255         let mt = 0x4;
2256         let gid = 0x1; // SESSION_CONFIG GID.
2257         let oid = 0x3;
2258         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2259         let cmd_payload_clone = cmd_payload.clone();
2260         let resp_payload = vec![0x00, 0x01, 0x07, 0x00];
2261         let status = StatusCode::UciStatusOk;
2262         let cfg_id = AppConfigTlvType::DstMacAddress;
2263         let app_config = AppConfigStatus { cfg_id, status };
2264         let cfg_status = vec![app_config];
2265 
2266         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2267             |mut hal| async move {
2268                 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
2269                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
2270                     status,
2271                     cfg_status,
2272                 });
2273 
2274                 hal.expected_send_command(cmd, resp, Ok(()));
2275             },
2276             UciLoggerMode::Disabled,
2277             mpsc::unbounded_channel::<UciLogEvent>().0,
2278         )
2279         .await;
2280 
2281         let expected_result = RawUciMessage { gid, oid, payload: resp_payload };
2282         let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap();
2283         assert_eq!(result, expected_result);
2284         assert!(mock_hal.wait_expected_calls_done().await);
2285     }
2286 
2287     #[tokio::test]
test_raw_uci_cmd_custom_payload_format()2288     async fn test_raw_uci_cmd_custom_payload_format() {
2289         // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the
2290         // UCI HAL returns a UCI response with a custom payload format. The UCI response packet
2291         // should still be successfully parsed and returned, since it's a Raw UCI RSP.
2292         let cmd_mt: u8 = 0x1;
2293         let gid: u8 = 0x1; // Session Config.
2294         let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG
2295         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2296         let cmd_payload_clone = cmd_payload.clone();
2297         let resp_mt: u8 = 0x2;
2298         let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
2299         let resp_payload_clone = resp_payload.clone();
2300 
2301         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2302             |mut hal| async move {
2303                 let cmd = UciCommand::RawUciCmd {
2304                     mt: cmd_mt.into(),
2305                     gid: gid.into(),
2306                     oid: oid.into(),
2307                     payload: cmd_payload_clone,
2308                 };
2309                 let resp = build_uci_packet(resp_mt, 0, gid, oid, resp_payload_clone);
2310                 hal.expected_send_command(cmd, vec![resp], Ok(()));
2311             },
2312             UciLoggerMode::Disabled,
2313             mpsc::unbounded_channel::<UciLogEvent>().0,
2314         )
2315         .await;
2316 
2317         let expected_result =
2318             Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload });
2319         let result =
2320             uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await;
2321         assert_eq!(result, expected_result);
2322         assert!(mock_hal.wait_expected_calls_done().await);
2323     }
2324 
2325     #[tokio::test]
test_raw_uci_cmd_fragmented_responses()2326     async fn test_raw_uci_cmd_fragmented_responses() {
2327         // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the
2328         // UCI HAL returns a UCI response with a custom payload format, in 2 UCI packet fragments.
2329         let cmd_mt: u8 = 0x1;
2330         let gid: u8 = 0x1; // Session Config.
2331         let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG
2332         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2333         let cmd_payload_clone = cmd_payload.clone();
2334         let resp_mt: u8 = 0x2;
2335         let resp_payload_fragment_1 = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
2336         let resp_payload_fragment_2 = vec![0x09, 0x0a, 0x0b];
2337         let mut resp_payload_expected = resp_payload_fragment_1.clone();
2338         resp_payload_expected.extend(resp_payload_fragment_2.clone().into_iter());
2339 
2340         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2341             |mut hal| async move {
2342                 let cmd = UciCommand::RawUciCmd {
2343                     mt: cmd_mt.into(),
2344                     gid: gid.into(),
2345                     oid: oid.into(),
2346                     payload: cmd_payload_clone,
2347                 };
2348                 let resp_fragment_1 = build_uci_packet(
2349                     resp_mt,
2350                     /* pbf = */ 1,
2351                     gid,
2352                     oid,
2353                     resp_payload_fragment_1,
2354                 );
2355                 let resp_fragment_2 = build_uci_packet(
2356                     resp_mt,
2357                     /* pbf = */ 0,
2358                     gid,
2359                     oid,
2360                     resp_payload_fragment_2,
2361                 );
2362                 hal.expected_send_command(cmd, vec![resp_fragment_1, resp_fragment_2], Ok(()));
2363             },
2364             UciLoggerMode::Disabled,
2365             mpsc::unbounded_channel::<UciLogEvent>().0,
2366         )
2367         .await;
2368 
2369         let expected_result =
2370             Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload_expected });
2371         let result =
2372             uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await;
2373         assert_eq!(result, expected_result);
2374         assert!(mock_hal.wait_expected_calls_done().await);
2375     }
2376 
2377     #[tokio::test]
test_raw_uci_cmd_wrong_gid()2378     async fn test_raw_uci_cmd_wrong_gid() {
2379         // Send a raw UCI command with CORE GID, but UCI HAL returns a UCI response with
2380         // SESSION_CONFIG GID. In this case, UciManager should return Error::Unknown, as the
2381         // RawUciSignature fields (GID, OID) of the CMD and RSP packets don't match.
2382 
2383         let mt = 0x1;
2384         let gid = 0x0; // CORE GID.
2385         let oid = 0x1;
2386         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2387         let cmd_payload_clone = cmd_payload.clone();
2388         let status = StatusCode::UciStatusOk;
2389         let cfg_id = AppConfigTlvType::DstMacAddress;
2390         let app_config = AppConfigStatus { cfg_id, status };
2391         let cfg_status = vec![app_config];
2392 
2393         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2394             |mut hal| async move {
2395                 let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
2396                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
2397                     status,
2398                     cfg_status,
2399                 });
2400 
2401                 hal.expected_send_command(cmd, resp, Ok(()));
2402             },
2403             UciLoggerMode::Disabled,
2404             mpsc::unbounded_channel::<UciLogEvent>().0,
2405         )
2406         .await;
2407 
2408         let expected_result = Err(Error::Unknown);
2409         let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await;
2410         assert_eq!(result, expected_result);
2411         assert!(mock_hal.wait_expected_calls_done().await);
2412     }
2413 
2414     #[tokio::test]
test_raw_uci_cmd_out_of_range_gid()2415     async fn test_raw_uci_cmd_out_of_range_gid() {
2416         // Send a raw UCI command with a GID value outside it's 8-bit size. This should result in
2417         // an error since the input GID value cannot be encoded into the UCI packet.
2418         let mt = 0x1;
2419         let gid = 0x1FF;
2420         let oid = 0x1;
2421         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2422 
2423         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2424             move |_hal| async {},
2425             UciLoggerMode::Disabled,
2426             mpsc::unbounded_channel::<UciLogEvent>().0,
2427         )
2428         .await;
2429 
2430         let expected_result = Err(Error::BadParameters);
2431         let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await;
2432         assert_eq!(result, expected_result);
2433         assert!(mock_hal.wait_expected_calls_done().await);
2434     }
2435 
2436     #[tokio::test]
test_raw_uci_cmd_out_of_range_oid()2437     async fn test_raw_uci_cmd_out_of_range_oid() {
2438         // Send a raw UCI command with a valid GID (CORE), but an OID value outside it's 8-bit
2439         // size. This should result in an error since the input OID value cannot be encoded into
2440         // the UCI packet.
2441         let mt = 0x1;
2442         let gid = 0x0; // CORE GID.
2443         let oid = 0x1FF;
2444         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2445 
2446         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2447             |_hal| async move {},
2448             UciLoggerMode::Disabled,
2449             mpsc::unbounded_channel::<UciLogEvent>().0,
2450         )
2451         .await;
2452 
2453         let expected_result = Err(Error::BadParameters);
2454         let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await;
2455         assert_eq!(result, expected_result);
2456         assert!(mock_hal.wait_expected_calls_done().await);
2457     }
2458 
2459     #[tokio::test]
test_raw_uci_cmd_uwbs_response_notification()2460     async fn test_raw_uci_cmd_uwbs_response_notification() {
2461         // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the
2462         // UCI HAL returns a valid UCI Notification packet before the raw UCI response.
2463         let cmd_mt: u8 = 0x1;
2464         let gid: u8 = 0x1; // Session Config.
2465         let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG
2466         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2467         let cmd_payload_clone = cmd_payload.clone();
2468         let session_token = 0x123;
2469         let resp_mt: u8 = 0x2;
2470         let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
2471         let resp_payload_clone = resp_payload.clone();
2472 
2473         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2474             |mut hal| async move {
2475                 let cmd = UciCommand::RawUciCmd {
2476                     mt: cmd_mt.into(),
2477                     gid: gid.into(),
2478                     oid: oid.into(),
2479                     payload: cmd_payload_clone,
2480                 };
2481                 let raw_resp = build_uci_packet(resp_mt, 0, gid, oid, resp_payload_clone);
2482                 let mut responses =
2483                     into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder {
2484                         session_token,
2485                         session_state: uwb_uci_packets::SessionState::SessionStateInit,
2486                         reason_code:
2487                             uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
2488                                 .into(),
2489                     });
2490                 responses.push(raw_resp);
2491                 hal.expected_send_command(cmd, responses, Ok(()));
2492             },
2493             UciLoggerMode::Disabled,
2494             mpsc::unbounded_channel::<UciLogEvent>().0,
2495         )
2496         .await;
2497 
2498         let expected_result =
2499             Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload });
2500         let result =
2501             uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await;
2502         assert_eq!(result, expected_result);
2503         assert!(mock_hal.wait_expected_calls_done().await);
2504     }
2505 
2506     #[tokio::test]
test_raw_uci_cmd_uwbs_response_undefined_mt()2507     async fn test_raw_uci_cmd_uwbs_response_undefined_mt() {
2508         // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the
2509         // UCI HAL returns a UCI packet with an undefined MessageType in response.
2510         let cmd_mt: u8 = 0x1;
2511         let gid: u8 = 0x1; // Session Config.
2512         let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG
2513         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
2514         let cmd_payload_clone = cmd_payload.clone();
2515         let resp_mt: u8 = 0x7; // Undefined MessageType
2516         let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
2517 
2518         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2519             |mut hal| async move {
2520                 let cmd = UciCommand::RawUciCmd {
2521                     mt: cmd_mt.into(),
2522                     gid: gid.into(),
2523                     oid: oid.into(),
2524                     payload: cmd_payload_clone,
2525                 };
2526                 let resp = build_uci_packet(resp_mt, /* pbf = */ 0, gid, oid, resp_payload);
2527                 hal.expected_send_command(cmd, vec![resp], Ok(()));
2528             },
2529             UciLoggerMode::Disabled,
2530             mpsc::unbounded_channel::<UciLogEvent>().0,
2531         )
2532         .await;
2533 
2534         let expected_result = Err(Error::Unknown);
2535         let result =
2536             uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await;
2537         assert_eq!(result, expected_result);
2538         assert!(mock_hal.wait_expected_calls_done().await);
2539     }
2540 
2541     // TODO(b/276320369): Listing down the Data Packet Rx scenarios below, will add unit tests
2542     // for them in subsequent CLs.
2543     #[tokio::test]
test_data_packet_recv_ok()2544     async fn test_data_packet_recv_ok() {}
2545 
2546     #[tokio::test]
test_data_packet_recv_fragmented_packet_ok()2547     async fn test_data_packet_recv_fragmented_packet_ok() {}
2548 
setup_hal_for_session_active( hal: &mut MockUciHal, session_type: SessionType, session_id: u32, session_token: u32, )2549     fn setup_hal_for_session_active(
2550         hal: &mut MockUciHal,
2551         session_type: SessionType,
2552         session_id: u32,
2553         session_token: u32,
2554     ) {
2555         // Setup session init.
2556         setup_hal_for_session_initialize(hal, session_type, session_id, session_token);
2557 
2558         // Setup session active.
2559         let cmd = UciCommand::SessionStart { session_token };
2560         let mut responses = into_uci_hal_packets(uwb_uci_packets::SessionStartRspBuilder {
2561             status: uwb_uci_packets::StatusCode::UciStatusOk,
2562         });
2563         responses.append(&mut into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder {
2564             session_token,
2565             session_state: SessionState::SessionStateActive,
2566             reason_code: 0, /* ReasonCode::StateChangeWithSessionManagementCommands */
2567         }));
2568         hal.expected_send_command(cmd, responses, Ok(()));
2569     }
2570 
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 = ()>,2571     async fn setup_uci_manager_with_session_active<F, Fut>(
2572         setup_hal_fn: F,
2573         uci_logger_mode: UciLoggerMode,
2574         log_sender: mpsc::UnboundedSender<UciLogEvent>,
2575         session_id: u32,
2576         session_token: u32,
2577     ) -> (UciManagerImpl, MockUciHal)
2578     where
2579         F: FnOnce(MockUciHal) -> Fut,
2580         Fut: Future<Output = ()>,
2581     {
2582         let session_type = SessionType::FiraRangingSession;
2583 
2584         init_test_logging();
2585 
2586         let mut hal = MockUciHal::new();
2587         setup_hal_for_session_active(&mut hal, session_type, session_id, session_token);
2588 
2589         // Verify open_hal() is working.
2590         let uci_manager =
2591             UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode);
2592         let result = uci_manager.open_hal().await;
2593         assert!(result.is_ok());
2594 
2595         // Verify session is initialized.
2596         let result = uci_manager.session_init(session_id, session_type).await;
2597         assert!(result.is_ok());
2598 
2599         // Verify session is started.
2600         let result = uci_manager.range_start(session_id).await;
2601         assert!(result.is_ok());
2602         assert!(hal.wait_expected_calls_done().await);
2603 
2604         setup_hal_fn(hal.clone()).await;
2605 
2606         (uci_manager, hal)
2607     }
2608 
2609     #[tokio::test]
test_data_packet_send_ok()2610     async fn test_data_packet_send_ok() {
2611         // Test Data packet send for a single packet (on a UWB session).
2612         let mt_data = 0x0;
2613         let pbf = 0x0;
2614         let dpf = 0x1;
2615         let oid = 0x0;
2616         let session_id = 0x5;
2617         let session_token = 0x5;
2618         let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1];
2619         let dest_fira_component = FiraComponent::Host;
2620         let uci_sequence_number = 0xa;
2621         let app_data = vec![0x01, 0x02, 0x03];
2622         let expected_data_snd_payload = vec![
2623             0x05, 0x00, 0x00, 0x00, // SessionID
2624             0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress
2625             0x01, // FiraComponent
2626             0x0a, // UciSequenceNumber
2627             0x03, 0x00, // AppDataLen
2628             0x01, 0x02, 0x03, // AppData
2629         ];
2630         let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk;
2631 
2632         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active(
2633             |mut hal| async move {
2634                 // Now setup the notifications that should be received after a Data packet send.
2635                 let data_packet_snd =
2636                     build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload);
2637                 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
2638                     session_token,
2639                     credit_availability: CreditAvailability::CreditAvailable,
2640                 });
2641                 ntfs.append(&mut into_uci_hal_packets(
2642                     uwb_uci_packets::DataTransferStatusNtfBuilder {
2643                         session_token,
2644                         uci_sequence_number,
2645                         status,
2646                     },
2647                 ));
2648                 hal.expected_send_packet(data_packet_snd, ntfs, Ok(()));
2649             },
2650             UciLoggerMode::Disabled,
2651             mpsc::unbounded_channel::<UciLogEvent>().0,
2652             session_id,
2653             session_token,
2654         )
2655         .await;
2656 
2657         let result = uci_manager
2658             .send_data_packet(
2659                 session_id,
2660                 dest_mac_address,
2661                 dest_fira_component,
2662                 uci_sequence_number,
2663                 app_data,
2664             )
2665             .await;
2666         assert!(result.is_ok());
2667         assert!(mock_hal.wait_expected_calls_done().await);
2668 
2669         // TODO(b/276320369): Verify that session_notf_sender is called (once implemented), as a
2670         // DataTransferStatusNtf is received in this test scenario.
2671     }
2672 
2673     #[tokio::test]
test_data_packet_send_fragmented_packet_ok()2674     async fn test_data_packet_send_fragmented_packet_ok() {
2675         // Test Data packet send for a set of data packet fragments (on a UWB session).
2676         let mt_data = 0x0;
2677         let pbf_fragment_1 = 0x1;
2678         let pbf_fragment_2 = 0x0;
2679         let dpf = 0x1;
2680         let oid = 0x0;
2681         let session_id = 0x5;
2682         let session_token = 0x5;
2683         let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1];
2684         let dest_fira_component = FiraComponent::Host;
2685         let uci_sequence_number = 0xa;
2686         let app_data_len = 300; // Larger than MAX_PAYLOAD_LEN=255, so fragmentation occurs.
2687         let mut app_data = Vec::new();
2688         let mut expected_data_snd_payload_fragment_1 = vec![
2689             0x05, 0x00, 0x00, 0x00, // SessionID
2690             0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress
2691             0x01, // FiraComponent
2692             0x0a, // UciSequenceNumber
2693             0x2c, 0x01, // AppDataLen = 300
2694         ];
2695         let mut expected_data_snd_payload_fragment_2 = Vec::new();
2696         let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk;
2697 
2698         // Setup the app data for both the Tx data packet and expected packet fragments.
2699         let app_data_len_fragment_1 = 255 - expected_data_snd_payload_fragment_1.len();
2700         for i in 0..app_data_len {
2701             app_data.push((i & 0xff).try_into().unwrap());
2702             if i < app_data_len_fragment_1 {
2703                 expected_data_snd_payload_fragment_1.push((i & 0xff).try_into().unwrap());
2704             } else {
2705                 expected_data_snd_payload_fragment_2.push((i & 0xff).try_into().unwrap());
2706             }
2707         }
2708 
2709         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active(
2710             |mut hal| async move {
2711                 // Expected data packet fragment #1 (UCI Header + Initial App data bytes).
2712                 let data_packet_snd_fragment_1 = build_uci_packet(
2713                     mt_data,
2714                     pbf_fragment_1,
2715                     dpf,
2716                     oid,
2717                     expected_data_snd_payload_fragment_1,
2718                 );
2719                 let ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
2720                     session_token,
2721                     credit_availability: CreditAvailability::CreditAvailable,
2722                 });
2723                 hal.expected_send_packet(data_packet_snd_fragment_1, ntfs, Ok(()));
2724 
2725                 // Expected data packet fragment #2 (UCI Header + Remaining App data bytes).
2726                 let data_packet_snd_fragment_2 = build_uci_packet(
2727                     mt_data,
2728                     pbf_fragment_2,
2729                     dpf,
2730                     oid,
2731                     expected_data_snd_payload_fragment_2,
2732                 );
2733                 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
2734                     session_token,
2735                     credit_availability: CreditAvailability::CreditAvailable,
2736                 });
2737                 ntfs.append(&mut into_uci_hal_packets(
2738                     uwb_uci_packets::DataTransferStatusNtfBuilder {
2739                         session_token,
2740                         uci_sequence_number,
2741                         status,
2742                     },
2743                 ));
2744                 hal.expected_send_packet(data_packet_snd_fragment_2, ntfs, Ok(()));
2745             },
2746             UciLoggerMode::Disabled,
2747             mpsc::unbounded_channel::<UciLogEvent>().0,
2748             session_id,
2749             session_token,
2750         )
2751         .await;
2752 
2753         let result = uci_manager
2754             .send_data_packet(
2755                 session_id,
2756                 dest_mac_address,
2757                 dest_fira_component,
2758                 uci_sequence_number,
2759                 app_data,
2760             )
2761             .await;
2762         assert!(result.is_ok());
2763         assert!(mock_hal.wait_expected_calls_done().await);
2764     }
2765 
2766     #[tokio::test]
test_data_packet_send_retry_ok()2767     async fn test_data_packet_send_retry_ok() {
2768         // Test Data packet send for a single packet (on a UWB session).
2769         let mt_data = 0x0;
2770         let pbf = 0x0;
2771         let dpf = 0x1;
2772         let oid = 0x0;
2773         let session_id = 0x5;
2774         let session_token = 0x5;
2775         let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1];
2776         let dest_fira_component = FiraComponent::Host;
2777         let uci_sequence_number = 0xa;
2778         let app_data = vec![0x01, 0x02, 0x03];
2779         let expected_data_snd_payload = vec![
2780             0x05, 0x00, 0x00, 0x00, // SessionID
2781             0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress
2782             0x01, // FiraComponent
2783             0x0a, // UciSequenceNumber
2784             0x03, 0x00, // AppDataLen
2785             0x01, 0x02, 0x03, // AppData
2786         ];
2787         let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk;
2788 
2789         let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active(
2790             |mut hal| async move {
2791                 // Setup receiving a CORE_GENERIC_ERROR_NTF with STATUS_COMMAND_RETRY after a
2792                 // failed Data packet send attempt.
2793                 let data_packet_snd =
2794                     build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload);
2795                 let error_ntf = into_uci_hal_packets(uwb_uci_packets::GenericErrorBuilder {
2796                     status: StatusCode::UciStatusCommandRetry,
2797                 });
2798                 hal.expected_send_packet(data_packet_snd.clone(), error_ntf, Ok(()));
2799 
2800                 // Setup the notifications that should be received after the Data packet send
2801                 // is successfully retried.
2802                 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
2803                     session_token,
2804                     credit_availability: CreditAvailability::CreditAvailable,
2805                 });
2806                 ntfs.append(&mut into_uci_hal_packets(
2807                     uwb_uci_packets::DataTransferStatusNtfBuilder {
2808                         session_token,
2809                         uci_sequence_number,
2810                         status,
2811                     },
2812                 ));
2813                 hal.expected_send_packet(data_packet_snd, ntfs, Ok(()));
2814             },
2815             UciLoggerMode::Disabled,
2816             mpsc::unbounded_channel::<UciLogEvent>().0,
2817             session_id,
2818             session_token,
2819         )
2820         .await;
2821 
2822         let result = uci_manager
2823             .send_data_packet(
2824                 session_id,
2825                 dest_mac_address,
2826                 dest_fira_component,
2827                 uci_sequence_number,
2828                 app_data,
2829             )
2830             .await;
2831         assert!(result.is_ok());
2832         assert!(mock_hal.wait_expected_calls_done().await);
2833 
2834         // TODO(b/276320369): Verify that session_notf_sender is called (once implemented), as a
2835         // DataTransferStatusNtf is received in this test scenario.
2836     }
2837 
2838     // TODO(b/276320369): Listing down the Data Packet Tx scenarios below, will add unit tests
2839     // for them in subsequent CLs.
2840 
2841     // Sending one data packet should succeed, when no DataCreditNtf is received.
2842     #[tokio::test]
test_data_packet_send_missing_data_credit_ntf_success()2843     async fn test_data_packet_send_missing_data_credit_ntf_success() {}
2844 
2845     // Sending the second data packet should fail, when no DataCreditNtf is received after
2846     // sending the first data packet.
2847     #[tokio::test]
test_data_packet_send_missing_data_credit_ntf_subsequent_send_failure()2848     async fn test_data_packet_send_missing_data_credit_ntf_subsequent_send_failure() {}
2849 
2850     #[tokio::test]
test_data_packet_send_data_credit_ntf_bad_session_id()2851     async fn test_data_packet_send_data_credit_ntf_bad_session_id() {}
2852 
2853     #[tokio::test]
test_data_packet_send_data_credit_ntf_no_credit_available()2854     async fn test_data_packet_send_data_credit_ntf_no_credit_available() {}
2855 
2856     #[tokio::test]
test_data_packet_send_missing_data_transfer_status_ntf()2857     async fn test_data_packet_send_missing_data_transfer_status_ntf() {}
2858 
2859     #[tokio::test]
test_data_packet_send_data_transfer_status_ntf_bad_session_id()2860     async fn test_data_packet_send_data_transfer_status_ntf_bad_session_id() {}
2861 
2862     #[tokio::test]
test_data_packet_send_data_transfer_status_ntf_bad_uci_sequence_number()2863     async fn test_data_packet_send_data_transfer_status_ntf_bad_uci_sequence_number() {}
2864 
2865     // Tests for the multiple Status values that indicate success
2866     #[tokio::test]
test_data_packet_send_data_transfer_status_ntf_status_ok()2867     async fn test_data_packet_send_data_transfer_status_ntf_status_ok() {}
2868 
2869     #[tokio::test]
test_data_packet_send_data_transfer_status_ntf_status_repetition_ok()2870     async fn test_data_packet_send_data_transfer_status_ntf_status_repetition_ok() {}
2871 
2872     // Tests for some of the multiple Status values that indicate error.
2873     #[tokio::test]
test_data_packet_send_data_transfer_status_ntf_status_error()2874     async fn test_data_packet_send_data_transfer_status_ntf_status_error() {}
2875 
2876     #[tokio::test]
test_session_get_count_retry_no_response()2877     async fn test_session_get_count_retry_no_response() {
2878         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2879             |mut hal| async move {
2880                 let cmd = UciCommand::SessionGetCount;
2881                 hal.expected_send_command(cmd, vec![], Ok(()));
2882             },
2883             UciLoggerMode::Disabled,
2884             mpsc::unbounded_channel::<UciLogEvent>().0,
2885         )
2886         .await;
2887 
2888         let result = uci_manager.session_get_count().await;
2889         assert!(matches!(result, Err(Error::Timeout)));
2890         assert!(mock_hal.wait_expected_calls_done().await);
2891     }
2892 
2893     #[tokio::test]
test_session_get_count_timeout()2894     async fn test_session_get_count_timeout() {
2895         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2896             |mut hal| async move {
2897                 let cmd = UciCommand::SessionGetCount;
2898                 hal.expected_send_command(cmd, vec![], Err(Error::Timeout));
2899             },
2900             UciLoggerMode::Disabled,
2901             mpsc::unbounded_channel::<UciLogEvent>().0,
2902         )
2903         .await;
2904 
2905         let result = uci_manager.session_get_count().await;
2906         assert!(matches!(result, Err(Error::Timeout)));
2907         assert!(mock_hal.wait_expected_calls_done().await);
2908     }
2909 
2910     #[tokio::test]
test_session_get_count_retry_too_many_times()2911     async fn test_session_get_count_retry_too_many_times() {
2912         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2913             |mut hal| async move {
2914                 let cmd = UciCommand::SessionGetCount;
2915                 let retry_resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
2916                     status: uwb_uci_packets::StatusCode::UciStatusCommandRetry,
2917                     session_count: 0,
2918                 });
2919 
2920                 for _ in 0..MAX_RETRY_COUNT {
2921                     hal.expected_send_command(cmd.clone(), retry_resp.clone(), Ok(()));
2922                 }
2923             },
2924             UciLoggerMode::Disabled,
2925             mpsc::unbounded_channel::<UciLogEvent>().0,
2926         )
2927         .await;
2928 
2929         let result = uci_manager.session_get_count().await;
2930         assert!(matches!(result, Err(Error::Timeout)));
2931         assert!(mock_hal.wait_expected_calls_done().await);
2932     }
2933 
2934     #[tokio::test]
test_session_get_count_retry_notification()2935     async fn test_session_get_count_retry_notification() {
2936         let session_count = 5;
2937 
2938         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2939             |mut hal| async move {
2940                 let cmd = UciCommand::SessionGetCount;
2941                 let retry_resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
2942                     status: uwb_uci_packets::StatusCode::UciStatusCommandRetry,
2943                     session_count: 0,
2944                 });
2945                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
2946                     status: uwb_uci_packets::StatusCode::UciStatusOk,
2947                     session_count,
2948                 });
2949 
2950                 hal.expected_send_command(cmd.clone(), retry_resp.clone(), Ok(()));
2951                 hal.expected_send_command(cmd.clone(), retry_resp, Ok(()));
2952                 hal.expected_send_command(cmd, resp, Ok(()));
2953             },
2954             UciLoggerMode::Disabled,
2955             mpsc::unbounded_channel::<UciLogEvent>().0,
2956         )
2957         .await;
2958 
2959         let result = uci_manager.session_get_count().await.unwrap();
2960         assert_eq!(result, session_count);
2961         assert!(mock_hal.wait_expected_calls_done().await);
2962     }
2963 
2964     #[tokio::test]
test_log_manager_interaction()2965     async fn test_log_manager_interaction() {
2966         let (log_sender, mut log_receiver) = mpsc::unbounded_channel::<UciLogEvent>();
2967         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
2968             |mut hal| async move {
2969                 let cmd = UciCommand::SessionGetCount;
2970                 let resp1 = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
2971                     status: uwb_uci_packets::StatusCode::UciStatusOk,
2972                     session_count: 1,
2973                 });
2974                 let resp2 = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
2975                     status: uwb_uci_packets::StatusCode::UciStatusOk,
2976                     session_count: 2,
2977                 });
2978                 hal.expected_send_command(cmd.clone(), resp1, Ok(()));
2979                 hal.expected_send_command(cmd, resp2, Ok(()));
2980             },
2981             UciLoggerMode::Disabled,
2982             log_sender,
2983         )
2984         .await;
2985 
2986         // Under Disabled mode, initialization and first command and response are not logged.
2987         uci_manager.session_get_count().await.unwrap();
2988         assert!(log_receiver.try_recv().is_err());
2989 
2990         // Second command and response after change in logger mode are logged.
2991         uci_manager.set_logger_mode(UciLoggerMode::Filtered).await.unwrap();
2992         uci_manager.session_get_count().await.unwrap();
2993         let packet: Vec<u8> = log_receiver.recv().await.unwrap().try_into().unwrap();
2994         let cmd_packet: Vec<u8> = SessionGetCountCmdBuilder {}.build().into();
2995         assert_eq!(&packet, &cmd_packet);
2996         let packet: Vec<u8> = log_receiver.recv().await.unwrap().try_into().unwrap();
2997         let rsp_packet: Vec<u8> =
2998             SessionGetCountRspBuilder { status: StatusCode::UciStatusOk, session_count: 2 }
2999                 .build()
3000                 .into();
3001         assert_eq!(&packet, &rsp_packet);
3002 
3003         assert!(mock_hal.wait_expected_calls_done().await);
3004     }
3005 }
3006