xref: /aosp_15_r20/external/uwb/src/rust/uwb_core/src/session/session_manager.rs (revision e0df40009cb5d71e642272d38ba1bb7ffccfce41)
1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use std::collections::BTreeMap;
16 
17 use log::{debug, error, warn};
18 use tokio::sync::{mpsc, oneshot};
19 
20 use crate::error::{Error, Result};
21 use crate::params::app_config_params::AppConfigParams;
22 use crate::params::uci_packets::{
23     Controlee, ControleeStatusList, ReasonCode, SessionId, SessionState, SessionType,
24     UpdateMulticastListAction,
25 };
26 use crate::session::uwb_session::{Response as SessionResponse, ResponseSender, UwbSession};
27 use crate::uci::notification::{SessionNotification as UciSessionNotification, SessionRangeData};
28 use crate::uci::uci_manager::UciManager;
29 use crate::utils::clean_mpsc_receiver;
30 
31 const MAX_SESSION_COUNT: usize = 5;
32 
33 /// The notifications that are sent from SessionManager to its caller.
34 #[derive(Debug, PartialEq)]
35 pub(crate) enum SessionNotification {
36     SessionState { session_id: SessionId, session_state: SessionState, reason_code: ReasonCode },
37     RangeData { session_id: SessionId, range_data: SessionRangeData },
38 }
39 
40 /// The SessionManager organizes the state machine of the existing UWB ranging sessions, sends
41 /// the session-related requests to the UciManager, and handles the session notifications from the
42 /// UciManager.
43 /// Using the actor model, SessionManager delegates the requests to SessionManagerActor.
44 pub(crate) struct SessionManager {
45     cmd_sender: mpsc::UnboundedSender<(SessionCommand, ResponseSender)>,
46 }
47 
48 impl SessionManager {
new<T: UciManager>( uci_manager: T, uci_notf_receiver: mpsc::UnboundedReceiver<UciSessionNotification>, session_notf_sender: mpsc::UnboundedSender<SessionNotification>, ) -> Self49     pub fn new<T: UciManager>(
50         uci_manager: T,
51         uci_notf_receiver: mpsc::UnboundedReceiver<UciSessionNotification>,
52         session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
53     ) -> Self {
54         let (cmd_sender, cmd_receiver) = mpsc::unbounded_channel();
55         let mut actor = SessionManagerActor::new(
56             cmd_receiver,
57             uci_manager,
58             uci_notf_receiver,
59             session_notf_sender,
60         );
61         tokio::spawn(async move { actor.run().await });
62 
63         Self { cmd_sender }
64     }
65 
init_session( &mut self, session_id: SessionId, session_type: SessionType, params: AppConfigParams, ) -> Result<()>66     pub async fn init_session(
67         &mut self,
68         session_id: SessionId,
69         session_type: SessionType,
70         params: AppConfigParams,
71     ) -> Result<()> {
72         let result = self
73             .send_cmd(SessionCommand::InitSession { session_id, session_type, params })
74             .await
75             .map(|_| ());
76         if result.is_err() && result != Err(Error::DuplicatedSessionId) {
77             let _ = self.deinit_session(session_id).await;
78         }
79         result
80     }
81 
deinit_session(&mut self, session_id: SessionId) -> Result<()>82     pub async fn deinit_session(&mut self, session_id: SessionId) -> Result<()> {
83         self.send_cmd(SessionCommand::DeinitSession { session_id }).await?;
84         Ok(())
85     }
86 
start_ranging(&mut self, session_id: SessionId) -> Result<AppConfigParams>87     pub async fn start_ranging(&mut self, session_id: SessionId) -> Result<AppConfigParams> {
88         match self.send_cmd(SessionCommand::StartRanging { session_id }).await? {
89             SessionResponse::AppConfigParams(params) => Ok(params),
90             _ => panic!("start_ranging() should reply AppConfigParams result"),
91         }
92     }
93 
stop_ranging(&mut self, session_id: SessionId) -> Result<()>94     pub async fn stop_ranging(&mut self, session_id: SessionId) -> Result<()> {
95         self.send_cmd(SessionCommand::StopRanging { session_id }).await?;
96         Ok(())
97     }
98 
reconfigure( &mut self, session_id: SessionId, params: AppConfigParams, ) -> Result<()>99     pub async fn reconfigure(
100         &mut self,
101         session_id: SessionId,
102         params: AppConfigParams,
103     ) -> Result<()> {
104         self.send_cmd(SessionCommand::Reconfigure { session_id, params }).await?;
105         Ok(())
106     }
107 
update_controller_multicast_list( &mut self, session_id: SessionId, action: UpdateMulticastListAction, controlees: Vec<Controlee>, ) -> Result<()>108     pub async fn update_controller_multicast_list(
109         &mut self,
110         session_id: SessionId,
111         action: UpdateMulticastListAction,
112         controlees: Vec<Controlee>,
113     ) -> Result<()> {
114         self.send_cmd(SessionCommand::UpdateControllerMulticastList {
115             session_id,
116             action,
117             controlees,
118         })
119         .await?;
120         Ok(())
121     }
122 
session_params(&mut self, session_id: SessionId) -> Result<AppConfigParams>123     pub async fn session_params(&mut self, session_id: SessionId) -> Result<AppConfigParams> {
124         match self.send_cmd(SessionCommand::GetParams { session_id }).await? {
125             SessionResponse::AppConfigParams(params) => Ok(params),
126             _ => panic!("session_params() should reply AppConfigParams result"),
127         }
128     }
129 
130     // Send the |cmd| to the SessionManagerActor.
send_cmd(&self, cmd: SessionCommand) -> Result<SessionResponse>131     async fn send_cmd(&self, cmd: SessionCommand) -> Result<SessionResponse> {
132         let (result_sender, result_receiver) = oneshot::channel();
133         self.cmd_sender.send((cmd, result_sender)).map_err(|cmd| {
134             error!("Failed to send cmd: {:?}", cmd.0);
135             Error::Unknown
136         })?;
137         result_receiver.await.unwrap_or_else(|e| {
138             error!("Failed to receive the result for cmd: {:?}", e);
139             Err(Error::Unknown)
140         })
141     }
142 }
143 
144 struct SessionManagerActor<T: UciManager> {
145     // Receive the commands and the corresponding response senders from SessionManager.
146     cmd_receiver: mpsc::UnboundedReceiver<(SessionCommand, ResponseSender)>,
147     // Send the notification to SessionManager's caller.
148     session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
149 
150     // The UciManager for delegating UCI requests.
151     uci_manager: T,
152     // Receive the notification from |uci_manager|.
153     uci_notf_receiver: mpsc::UnboundedReceiver<UciSessionNotification>,
154 
155     active_sessions: BTreeMap<SessionId, UwbSession>,
156 }
157 
158 impl<T: UciManager> SessionManagerActor<T> {
new( cmd_receiver: mpsc::UnboundedReceiver<(SessionCommand, ResponseSender)>, uci_manager: T, uci_notf_receiver: mpsc::UnboundedReceiver<UciSessionNotification>, session_notf_sender: mpsc::UnboundedSender<SessionNotification>, ) -> Self159     fn new(
160         cmd_receiver: mpsc::UnboundedReceiver<(SessionCommand, ResponseSender)>,
161         uci_manager: T,
162         uci_notf_receiver: mpsc::UnboundedReceiver<UciSessionNotification>,
163         session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
164     ) -> Self {
165         Self {
166             cmd_receiver,
167             session_notf_sender,
168             uci_manager,
169             uci_notf_receiver,
170             active_sessions: BTreeMap::new(),
171         }
172     }
173 
run(&mut self)174     async fn run(&mut self) {
175         loop {
176             tokio::select! {
177                 cmd = self.cmd_receiver.recv() => {
178                     match cmd {
179                         None => {
180                             debug!("SessionManager is about to drop.");
181                             break;
182                         },
183                         Some((cmd, result_sender)) => {
184                             self.handle_cmd(cmd, result_sender);
185                         }
186                     }
187                 }
188 
189                 Some(notf) = self.uci_notf_receiver.recv() => {
190                     self.handle_uci_notification(notf);
191                 }
192             }
193         }
194     }
195 
handle_cmd(&mut self, cmd: SessionCommand, result_sender: ResponseSender)196     fn handle_cmd(&mut self, cmd: SessionCommand, result_sender: ResponseSender) {
197         match cmd {
198             SessionCommand::InitSession { session_id, session_type, params } => {
199                 if self.active_sessions.contains_key(&session_id) {
200                     warn!("Session {} already exists", session_id);
201                     let _ = result_sender.send(Err(Error::DuplicatedSessionId));
202                     return;
203                 }
204                 if self.active_sessions.len() == MAX_SESSION_COUNT {
205                     warn!("The amount of active sessions already reached {}", MAX_SESSION_COUNT);
206                     let _ = result_sender.send(Err(Error::MaxSessionsExceeded));
207                     return;
208                 }
209 
210                 if !params.is_type_matched(session_type) {
211                     warn!(
212                         "session_type {:?} doesn't match with the params {:?}",
213                         session_type, params
214                     );
215                     let _ = result_sender.send(Err(Error::BadParameters));
216                     return;
217                 }
218 
219                 let mut session =
220                     UwbSession::new(self.uci_manager.clone(), session_id, session_type);
221                 session.initialize(params, result_sender);
222 
223                 // We store the session first. If the initialize() fails, then SessionManager will
224                 // call deinit_session() to remove it.
225                 self.active_sessions.insert(session_id, session);
226             }
227             SessionCommand::DeinitSession { session_id } => {
228                 match self.active_sessions.remove(&session_id) {
229                     None => {
230                         warn!("Session {} doesn't exist", session_id);
231                         let _ = result_sender.send(Err(Error::BadParameters));
232                     }
233                     Some(mut session) => {
234                         session.deinitialize(result_sender);
235                     }
236                 }
237             }
238             SessionCommand::StartRanging { session_id } => {
239                 match self.active_sessions.get_mut(&session_id) {
240                     None => {
241                         warn!("Session {} doesn't exist", session_id);
242                         let _ = result_sender.send(Err(Error::BadParameters));
243                     }
244                     Some(session) => {
245                         session.start_ranging(result_sender);
246                     }
247                 }
248             }
249             SessionCommand::StopRanging { session_id } => {
250                 match self.active_sessions.get_mut(&session_id) {
251                     None => {
252                         warn!("Session {} doesn't exist", session_id);
253                         let _ = result_sender.send(Err(Error::BadParameters));
254                     }
255                     Some(session) => {
256                         session.stop_ranging(result_sender);
257                     }
258                 }
259             }
260             SessionCommand::Reconfigure { session_id, params } => {
261                 match self.active_sessions.get_mut(&session_id) {
262                     None => {
263                         warn!("Session {} doesn't exist", session_id);
264                         let _ = result_sender.send(Err(Error::BadParameters));
265                     }
266                     Some(session) => {
267                         session.reconfigure(params, result_sender);
268                     }
269                 }
270             }
271             SessionCommand::UpdateControllerMulticastList { session_id, action, controlees } => {
272                 match self.active_sessions.get_mut(&session_id) {
273                     None => {
274                         warn!("Session {} doesn't exist", session_id);
275                         let _ = result_sender.send(Err(Error::BadParameters));
276                     }
277                     Some(session) => {
278                         session.update_controller_multicast_list(action, controlees, result_sender);
279                     }
280                 }
281             }
282             SessionCommand::GetParams { session_id } => {
283                 match self.active_sessions.get_mut(&session_id) {
284                     None => {
285                         warn!("Session {} doesn't exist", session_id);
286                         let _ = result_sender.send(Err(Error::BadParameters));
287                     }
288                     Some(session) => {
289                         session.params(result_sender);
290                     }
291                 }
292             }
293         }
294     }
295 
handle_uci_notification(&mut self, notf: UciSessionNotification)296     fn handle_uci_notification(&mut self, notf: UciSessionNotification) {
297         match notf {
298             UciSessionNotification::Status {
299                 session_id: _,
300                 session_token,
301                 session_state,
302                 reason_code,
303             } => {
304                 let reason_code = match ReasonCode::try_from(reason_code) {
305                     Ok(r) => r,
306                     Err(_) => {
307                         error!(
308                             "Received unknown reason_code {:?} in UciSessionNotification",
309                             reason_code
310                         );
311                         return;
312                     }
313                 };
314                 if session_state == SessionState::SessionStateDeinit {
315                     debug!("Session {} is deinitialized", session_token);
316                     let _ = self.active_sessions.remove(&session_token);
317                     let _ = self.session_notf_sender.send(SessionNotification::SessionState {
318                         session_id: session_token,
319                         session_state,
320                         reason_code,
321                     });
322                     return;
323                 }
324 
325                 match self.active_sessions.get_mut(&session_token) {
326                     Some(session) => {
327                         session.on_session_status_changed(session_state);
328                         let _ = self.session_notf_sender.send(SessionNotification::SessionState {
329                             session_id: session_token,
330                             session_state,
331                             reason_code,
332                         });
333                     }
334                     None => {
335                         warn!(
336                             "Received notification of the unknown Session {}: {:?}, {:?}",
337                             session_token, session_state, reason_code
338                         );
339                     }
340                 }
341             }
342             UciSessionNotification::UpdateControllerMulticastListV1 {
343                 session_token,
344                 remaining_multicast_list_size: _,
345                 status_list,
346             } => match self.active_sessions.get_mut(&session_token) {
347                 Some(session) => session
348                     .on_controller_multicast_list_updated(ControleeStatusList::V1(status_list)),
349                 None => {
350                     warn!(
351                         "Received the notification of the unknown Session {}: {:?}",
352                         session_token, status_list
353                     );
354                 }
355             },
356             UciSessionNotification::UpdateControllerMulticastListV2 {
357                 session_token,
358                 status_list,
359             } => match self.active_sessions.get_mut(&session_token) {
360                 Some(session) => session
361                     .on_controller_multicast_list_updated(ControleeStatusList::V2(status_list)),
362                 None => {
363                     warn!(
364                         "Received the notification of the unknown Session {}: {:?}",
365                         session_token, status_list
366                     );
367                 }
368             },
369             UciSessionNotification::SessionInfo(range_data) => {
370                 if self.active_sessions.contains_key(&range_data.session_token) {
371                     let _ = self.session_notf_sender.send(SessionNotification::RangeData {
372                         session_id: range_data.session_token,
373                         range_data,
374                     });
375                 } else {
376                     warn!("Received range data of the unknown Session: {:?}", range_data);
377                 }
378             }
379             UciSessionNotification::DataCredit { session_token, credit_availability: _ } => {
380                 match self.active_sessions.get(&session_token) {
381                     Some(_) => {
382                         /*
383                          * TODO(b/270443790): Handle the DataCredit notification in the new
384                          * code flow.
385                          */
386                     }
387                     None => {
388                         warn!(
389                             "Received the Data Credit notification for an unknown Session {}",
390                             session_token
391                         );
392                     }
393                 }
394             }
395             UciSessionNotification::DataTransferStatus {
396                 session_token,
397                 uci_sequence_number: _,
398                 status: _,
399                 tx_count: _,
400             } => {
401                 match self.active_sessions.get(&session_token) {
402                     Some(_) => {
403                         /*
404                          * TODO(b/270443790): Handle the DataTransferStatus notification in the
405                          * new code flow.
406                          */
407                     }
408                     None => {
409                         warn!(
410                             "Received a Data Transfer Status notification for unknown Session {}",
411                             session_token
412                         );
413                     }
414                 }
415             }
416             UciSessionNotification::DataTransferPhaseConfig { session_token, status } => {
417                 match self.active_sessions.get_mut(&session_token) {
418                     Some(_) => {
419                         /*
420                          *TODO
421                          */
422                     }
423                     None => {
424                         warn!(
425                             "Received data transfer phase configuration notification of the unknown
426                             Session {:?}",
427                             status
428                         );
429                     }
430                 }
431             }
432         }
433     }
434 }
435 
436 impl<T: UciManager> Drop for SessionManagerActor<T> {
drop(&mut self)437     fn drop(&mut self) {
438         // mpsc receiver is about to be dropped. Clean shutdown the mpsc message.
439         clean_mpsc_receiver(&mut self.uci_notf_receiver);
440     }
441 }
442 
443 #[derive(Debug)]
444 enum SessionCommand {
445     InitSession {
446         session_id: SessionId,
447         session_type: SessionType,
448         params: AppConfigParams,
449     },
450     DeinitSession {
451         session_id: SessionId,
452     },
453     StartRanging {
454         session_id: SessionId,
455     },
456     StopRanging {
457         session_id: SessionId,
458     },
459     Reconfigure {
460         session_id: SessionId,
461         params: AppConfigParams,
462     },
463     UpdateControllerMulticastList {
464         session_id: SessionId,
465         action: UpdateMulticastListAction,
466         controlees: Vec<Controlee>,
467     },
468     GetParams {
469         session_id: SessionId,
470     },
471 }
472 
473 #[cfg(test)]
474 pub(crate) mod test_utils {
475     use super::*;
476 
477     use crate::params::ccc_app_config_params::*;
478     use crate::params::fira_app_config_params::*;
479     use crate::params::uci_packets::{
480         RangingMeasurementType, ReasonCode, ShortAddressTwoWayRangingMeasurement, StatusCode,
481     };
482     use crate::params::GetDeviceInfoResponse;
483     use crate::uci::mock_uci_manager::MockUciManager;
484     use crate::uci::notification::{RangingMeasurements, UciNotification};
485     use crate::utils::init_test_logging;
486     use uwb_uci_packets::StatusCode::UciStatusOk;
487 
488     const GET_DEVICE_INFO_RSP: GetDeviceInfoResponse = GetDeviceInfoResponse {
489         status: UciStatusOk,
490         uci_version: 0,
491         mac_version: 0,
492         phy_version: 0,
493         uci_test_version: 0,
494         vendor_spec_info: vec![],
495     };
496 
generate_params() -> AppConfigParams497     pub(crate) fn generate_params() -> AppConfigParams {
498         FiraAppConfigParamsBuilder::new()
499             .device_type(DeviceType::Controller)
500             .multi_node_mode(MultiNodeMode::Unicast)
501             .device_mac_address(UwbAddress::Short([1, 2]))
502             .dst_mac_address(vec![UwbAddress::Short([3, 4])])
503             .device_role(DeviceRole::Initiator)
504             .vendor_id([0xFE, 0xDC])
505             .static_sts_iv([0xDF, 0xCE, 0xAB, 0x12, 0x34, 0x56])
506             .build()
507             .unwrap()
508     }
509 
generate_ccc_params() -> AppConfigParams510     pub(crate) fn generate_ccc_params() -> AppConfigParams {
511         CccAppConfigParamsBuilder::new()
512             .protocol_version(CccProtocolVersion { major: 2, minor: 1 })
513             .uwb_config(CccUwbConfig::Config0)
514             .pulse_shape_combo(CccPulseShapeCombo {
515                 initiator_tx: PulseShape::PrecursorFree,
516                 responder_tx: PulseShape::PrecursorFreeSpecial,
517             })
518             .ran_multiplier(3)
519             .channel_number(CccUwbChannel::Channel9)
520             .chaps_per_slot(ChapsPerSlot::Value9)
521             .num_responder_nodes(1)
522             .slots_per_rr(3)
523             .sync_code_index(12)
524             .hopping_mode(CccHoppingMode::ContinuousAes)
525             .build()
526             .unwrap()
527     }
528 
529     // TODO(b/321757248): Add a unit test generate_aliro_params().
530 
session_range_data(session_id: SessionId) -> SessionRangeData531     pub(crate) fn session_range_data(session_id: SessionId) -> SessionRangeData {
532         SessionRangeData {
533             sequence_number: 1,
534             session_token: session_id,
535             current_ranging_interval_ms: 3,
536             ranging_measurement_type: RangingMeasurementType::TwoWay,
537             ranging_measurements: RangingMeasurements::ShortAddressTwoWay(vec![
538                 ShortAddressTwoWayRangingMeasurement {
539                     mac_address: 0x123,
540                     status: StatusCode::UciStatusOk,
541                     nlos: 0,
542                     distance: 4,
543                     aoa_azimuth: 5,
544                     aoa_azimuth_fom: 6,
545                     aoa_elevation: 7,
546                     aoa_elevation_fom: 8,
547                     aoa_destination_azimuth: 9,
548                     aoa_destination_azimuth_fom: 10,
549                     aoa_destination_elevation: 11,
550                     aoa_destination_elevation_fom: 12,
551                     slot_index: 0,
552                     rssi: u8::MAX,
553                 },
554             ]),
555             rcr_indicator: 0,
556             raw_ranging_data: vec![0x12, 0x34],
557         }
558     }
559 
session_status_notf( session_id: SessionId, session_state: SessionState, ) -> UciNotification560     pub(crate) fn session_status_notf(
561         session_id: SessionId,
562         session_state: SessionState,
563     ) -> UciNotification {
564         UciNotification::Session(UciSessionNotification::Status {
565             session_id: 0x0,
566             session_token: session_id,
567             session_state,
568             reason_code: ReasonCode::StateChangeWithSessionManagementCommands.into(),
569         })
570     }
571 
range_data_notf(range_data: SessionRangeData) -> UciNotification572     pub(crate) fn range_data_notf(range_data: SessionRangeData) -> UciNotification {
573         UciNotification::Session(UciSessionNotification::SessionInfo(range_data))
574     }
575 
setup_session_manager<F>( setup_uci_manager_fn: F, ) -> (SessionManager, MockUciManager, mpsc::UnboundedReceiver<SessionNotification>) where F: FnOnce(&mut MockUciManager),576     pub(super) async fn setup_session_manager<F>(
577         setup_uci_manager_fn: F,
578     ) -> (SessionManager, MockUciManager, mpsc::UnboundedReceiver<SessionNotification>)
579     where
580         F: FnOnce(&mut MockUciManager),
581     {
582         init_test_logging();
583         let (uci_notf_sender, uci_notf_receiver) = mpsc::unbounded_channel();
584         let (session_notf_sender, session_notf_receiver) = mpsc::unbounded_channel();
585         let mut uci_manager = MockUciManager::new();
586         uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP));
587         setup_uci_manager_fn(&mut uci_manager);
588         uci_manager.set_session_notification_sender(uci_notf_sender).await;
589         let _ = uci_manager.open_hal().await;
590 
591         (
592             SessionManager::new(uci_manager.clone(), uci_notf_receiver, session_notf_sender),
593             uci_manager,
594             session_notf_receiver,
595         )
596     }
597 }
598 
599 #[cfg(test)]
600 mod tests {
601     use super::test_utils::*;
602     use super::*;
603 
604     use std::collections::HashMap;
605 
606     use crate::params::ccc_started_app_config_params::CccStartedAppConfigParams;
607     use crate::params::uci_packets::{
608         AppConfigTlv, AppConfigTlvType, ControleeStatusV1, Controlees, MulticastUpdateStatusCode,
609         ReasonCode, SessionUpdateControllerMulticastResponse, SetAppConfigResponse, StatusCode,
610     };
611     use crate::params::utils::{u32_to_bytes, u64_to_bytes, u8_to_bytes};
612     use crate::params::{FiraAppConfigParamsBuilder, KeyRotation};
613     use crate::uci::notification::UciNotification;
614 
615     #[tokio::test]
test_init_deinit_session()616     async fn test_init_deinit_session() {
617         let session_id = 0x123;
618         let session_type = SessionType::FiraRangingSession;
619         let params = generate_params();
620 
621         let tlvs = params.generate_tlvs();
622         let (mut session_manager, mut mock_uci_manager, mut session_notf_receiver) =
623             setup_session_manager(move |uci_manager| {
624                 uci_manager.expect_session_init(
625                     session_id,
626                     session_type,
627                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
628                     Ok(()),
629                 );
630                 uci_manager.expect_session_set_app_config(
631                     session_id,
632                     tlvs,
633                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
634                     Ok(SetAppConfigResponse {
635                         status: StatusCode::UciStatusOk,
636                         config_status: vec![],
637                     }),
638                 );
639                 uci_manager.expect_session_deinit(
640                     session_id,
641                     vec![session_status_notf(session_id, SessionState::SessionStateDeinit)],
642                     Ok(()),
643                 );
644             })
645             .await;
646 
647         // Deinit a session before initialized should fail.
648         let result = session_manager.deinit_session(session_id).await;
649         assert_eq!(result, Err(Error::BadParameters));
650 
651         // Initialize a normal session should be successful.
652         let result = session_manager.init_session(session_id, session_type, params.clone()).await;
653         assert_eq!(result, Ok(()));
654         let session_notf = session_notf_receiver.recv().await.unwrap();
655         assert_eq!(
656             session_notf,
657             SessionNotification::SessionState {
658                 session_id,
659                 session_state: SessionState::SessionStateInit,
660                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
661             }
662         );
663         let session_notf = session_notf_receiver.recv().await.unwrap();
664         assert_eq!(
665             session_notf,
666             SessionNotification::SessionState {
667                 session_id,
668                 session_state: SessionState::SessionStateIdle,
669                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
670             }
671         );
672 
673         // Initialize a session multiple times without deinitialize should fail.
674         let result = session_manager.init_session(session_id, session_type, params).await;
675         assert_eq!(result, Err(Error::DuplicatedSessionId));
676 
677         // Deinitialize the session should be successful, and should receive the deinitialized
678         // notification.
679         let result = session_manager.deinit_session(session_id).await;
680         assert_eq!(result, Ok(()));
681         let session_notf = session_notf_receiver.recv().await.unwrap();
682         assert_eq!(
683             session_notf,
684             SessionNotification::SessionState {
685                 session_id,
686                 session_state: SessionState::SessionStateDeinit,
687                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
688             }
689         );
690 
691         // Deinit a session after deinitialized should fail.
692         let result = session_manager.deinit_session(session_id).await;
693         assert_eq!(result, Err(Error::BadParameters));
694 
695         assert!(mock_uci_manager.wait_expected_calls_done().await);
696     }
697 
698     #[tokio::test]
test_init_session_timeout()699     async fn test_init_session_timeout() {
700         let session_id = 0x123;
701         let session_type = SessionType::FiraRangingSession;
702         let params = generate_params();
703 
704         let (mut session_manager, mut mock_uci_manager, _) =
705             setup_session_manager(move |uci_manager| {
706                 let notfs = vec![]; // Not sending SessionStatus notification.
707                 uci_manager.expect_session_init(session_id, session_type, notfs, Ok(()));
708             })
709             .await;
710 
711         let result = session_manager.init_session(session_id, session_type, params).await;
712         assert_eq!(result, Err(Error::Timeout));
713 
714         assert!(mock_uci_manager.wait_expected_calls_done().await);
715     }
716 
717     #[tokio::test]
test_start_stop_ranging()718     async fn test_start_stop_ranging() {
719         let session_id = 0x123;
720         let session_type = SessionType::FiraRangingSession;
721         let params = generate_params();
722         let tlvs = params.generate_tlvs();
723 
724         let (mut session_manager, mut mock_uci_manager, _) =
725             setup_session_manager(move |uci_manager| {
726                 uci_manager.expect_session_init(
727                     session_id,
728                     session_type,
729                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
730                     Ok(()),
731                 );
732                 uci_manager.expect_session_set_app_config(
733                     session_id,
734                     tlvs,
735                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
736                     Ok(SetAppConfigResponse {
737                         status: StatusCode::UciStatusOk,
738                         config_status: vec![],
739                     }),
740                 );
741                 uci_manager.expect_range_start(
742                     session_id,
743                     vec![session_status_notf(session_id, SessionState::SessionStateActive)],
744                     Ok(()),
745                 );
746                 uci_manager.expect_range_stop(
747                     session_id,
748                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
749                     Ok(()),
750                 );
751             })
752             .await;
753 
754         let result = session_manager.init_session(session_id, session_type, params.clone()).await;
755         assert_eq!(result, Ok(()));
756         let result = session_manager.start_ranging(session_id).await;
757         assert_eq!(result, Ok(params));
758         let result = session_manager.stop_ranging(session_id).await;
759         assert_eq!(result, Ok(()));
760 
761         assert!(mock_uci_manager.wait_expected_calls_done().await);
762     }
763 
764     #[tokio::test]
test_ccc_start_ranging()765     async fn test_ccc_start_ranging() {
766         let session_id = 0x123;
767         let session_type = SessionType::Ccc;
768         // params that is passed to UciManager::session_set_app_config().
769         let params = generate_ccc_params();
770         let tlvs = params.generate_tlvs();
771         // The params that is received from UciManager::session_get_app_config().
772         let received_config_map = HashMap::from([
773             (AppConfigTlvType::StsIndex, u32_to_bytes(3)),
774             (AppConfigTlvType::CccHopModeKey, u32_to_bytes(5)),
775             (AppConfigTlvType::CccUwbTime0, u64_to_bytes(7)),
776             (AppConfigTlvType::RangingDuration, u32_to_bytes(96)),
777             (AppConfigTlvType::PreambleCodeIndex, u8_to_bytes(9)),
778         ]);
779         let received_tlvs = received_config_map
780             .iter()
781             .map(|(key, value)| AppConfigTlv::new(*key, value.clone()))
782             .collect();
783         let started_params =
784             CccStartedAppConfigParams::from_config_map(received_config_map).unwrap();
785 
786         let (mut session_manager, mut mock_uci_manager, _) =
787             setup_session_manager(move |uci_manager| {
788                 uci_manager.expect_session_init(
789                     session_id,
790                     session_type,
791                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
792                     Ok(()),
793                 );
794                 uci_manager.expect_session_set_app_config(
795                     session_id,
796                     tlvs,
797                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
798                     Ok(SetAppConfigResponse {
799                         status: StatusCode::UciStatusOk,
800                         config_status: vec![],
801                     }),
802                 );
803                 uci_manager.expect_range_start(
804                     session_id,
805                     vec![session_status_notf(session_id, SessionState::SessionStateActive)],
806                     Ok(()),
807                 );
808                 uci_manager.expect_session_get_app_config(session_id, vec![], Ok(received_tlvs));
809             })
810             .await;
811 
812         let result = session_manager.init_session(session_id, session_type, params.clone()).await;
813         assert_eq!(result, Ok(()));
814         let result = session_manager.start_ranging(session_id).await;
815         assert_eq!(result, Ok(AppConfigParams::CccStarted(started_params)));
816 
817         assert!(mock_uci_manager.wait_expected_calls_done().await);
818     }
819 
820     #[tokio::test]
test_update_controller_multicast_list()821     async fn test_update_controller_multicast_list() {
822         let session_id = 0x123;
823         let session_type = SessionType::FiraRangingSession;
824         let params = generate_params();
825         let tlvs = params.generate_tlvs();
826         let action = UpdateMulticastListAction::AddControlee;
827         let short_address: [u8; 2] = [0x12, 0x34];
828         let controlees = vec![Controlee { short_address, subsession_id: 0x24 }];
829 
830         let controlees_clone = controlees.clone();
831         let (mut session_manager, mut mock_uci_manager, _) =
832             setup_session_manager(move |uci_manager| {
833                 let multicast_list_notf = vec![UciNotification::Session(
834                     UciSessionNotification::UpdateControllerMulticastListV1 {
835                         session_token: session_id,
836                         remaining_multicast_list_size: 1,
837                         status_list: vec![ControleeStatusV1 {
838                             mac_address: [0x34, 0x12],
839                             subsession_id: 0x24,
840                             status: MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
841                         }],
842                     },
843                 )];
844                 uci_manager.expect_session_init(
845                     session_id,
846                     session_type,
847                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
848                     Ok(()),
849                 );
850                 uci_manager.expect_session_set_app_config(
851                     session_id,
852                     tlvs,
853                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
854                     Ok(SetAppConfigResponse {
855                         status: StatusCode::UciStatusOk,
856                         config_status: vec![],
857                     }),
858                 );
859                 uci_manager.expect_session_update_controller_multicast_list(
860                     session_id,
861                     action,
862                     Controlees::NoSessionKey(controlees_clone),
863                     multicast_list_notf,
864                     Ok(SessionUpdateControllerMulticastResponse {
865                         status: StatusCode::UciStatusOk,
866                         status_list: vec![],
867                     }),
868                 );
869             })
870             .await;
871 
872         let result = session_manager.init_session(session_id, session_type, params).await;
873         assert_eq!(result, Ok(()));
874         let result =
875             session_manager.update_controller_multicast_list(session_id, action, controlees).await;
876         assert_eq!(result, Ok(()));
877 
878         assert!(mock_uci_manager.wait_expected_calls_done().await);
879     }
880 
881     #[tokio::test]
test_ccc_update_controller_multicast_list()882     async fn test_ccc_update_controller_multicast_list() {
883         let session_id = 0x123;
884         let session_type = SessionType::Ccc;
885         let params = generate_ccc_params();
886         let tlvs = params.generate_tlvs();
887         let action = UpdateMulticastListAction::AddControlee;
888         let short_address: [u8; 2] = [0x12, 0x34];
889         let controlees = vec![Controlee { short_address, subsession_id: 0x24 }];
890 
891         let (mut session_manager, mut mock_uci_manager, _) =
892             setup_session_manager(move |uci_manager| {
893                 uci_manager.expect_session_init(
894                     session_id,
895                     session_type,
896                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
897                     Ok(()),
898                 );
899                 uci_manager.expect_session_set_app_config(
900                     session_id,
901                     tlvs,
902                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
903                     Ok(SetAppConfigResponse {
904                         status: StatusCode::UciStatusOk,
905                         config_status: vec![],
906                     }),
907                 );
908             })
909             .await;
910 
911         let result = session_manager.init_session(session_id, session_type, params).await;
912         assert_eq!(result, Ok(()));
913         // CCC session doesn't support update_controller_multicast_list.
914         let result =
915             session_manager.update_controller_multicast_list(session_id, action, controlees).await;
916         assert_eq!(result, Err(Error::BadParameters));
917 
918         assert!(mock_uci_manager.wait_expected_calls_done().await);
919     }
920 
921     #[tokio::test]
test_update_controller_multicast_list_without_notification()922     async fn test_update_controller_multicast_list_without_notification() {
923         let session_id = 0x123;
924         let session_type = SessionType::FiraRangingSession;
925         let params = generate_params();
926         let tlvs = params.generate_tlvs();
927         let action = UpdateMulticastListAction::AddControlee;
928         let short_address: [u8; 2] = [0x12, 0x34];
929         let controlees = vec![Controlee { short_address, subsession_id: 0x24 }];
930 
931         let controlees_clone = controlees.clone();
932         let (mut session_manager, mut mock_uci_manager, _) =
933             setup_session_manager(move |uci_manager| {
934                 uci_manager.expect_session_init(
935                     session_id,
936                     session_type,
937                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
938                     Ok(()),
939                 );
940                 uci_manager.expect_session_set_app_config(
941                     session_id,
942                     tlvs,
943                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
944                     Ok(SetAppConfigResponse {
945                         status: StatusCode::UciStatusOk,
946                         config_status: vec![],
947                     }),
948                 );
949                 uci_manager.expect_session_update_controller_multicast_list(
950                     session_id,
951                     action,
952                     uwb_uci_packets::Controlees::NoSessionKey(controlees_clone),
953                     vec![], // Not sending notification.
954                     Ok(SessionUpdateControllerMulticastResponse {
955                         status: StatusCode::UciStatusOk,
956                         status_list: vec![],
957                     }),
958                 );
959             })
960             .await;
961 
962         let result = session_manager.init_session(session_id, session_type, params).await;
963         assert_eq!(result, Ok(()));
964         // This method should timeout waiting for the notification.
965         let result =
966             session_manager.update_controller_multicast_list(session_id, action, controlees).await;
967         assert_eq!(result, Err(Error::Timeout));
968 
969         assert!(mock_uci_manager.wait_expected_calls_done().await);
970     }
971 
972     #[tokio::test]
test_receive_session_range_data()973     async fn test_receive_session_range_data() {
974         let session_id = 0x123;
975         let session_type = SessionType::FiraRangingSession;
976         let params = generate_params();
977         let tlvs = params.generate_tlvs();
978         let range_data = session_range_data(session_id);
979         let range_data_clone = range_data.clone();
980 
981         let (mut session_manager, mut mock_uci_manager, mut session_notf_receiver) =
982             setup_session_manager(move |uci_manager| {
983                 uci_manager.expect_session_init(
984                     session_id,
985                     session_type,
986                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
987                     Ok(()),
988                 );
989                 uci_manager.expect_session_set_app_config(
990                     session_id,
991                     tlvs,
992                     vec![
993                         session_status_notf(session_id, SessionState::SessionStateIdle),
994                         range_data_notf(range_data_clone),
995                     ],
996                     Ok(SetAppConfigResponse {
997                         status: StatusCode::UciStatusOk,
998                         config_status: vec![],
999                     }),
1000                 );
1001             })
1002             .await;
1003 
1004         let result = session_manager.init_session(session_id, session_type, params).await;
1005         assert_eq!(result, Ok(()));
1006         let session_notf = session_notf_receiver.recv().await.unwrap();
1007         assert_eq!(
1008             session_notf,
1009             SessionNotification::SessionState {
1010                 session_id,
1011                 session_state: SessionState::SessionStateInit,
1012                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
1013             }
1014         );
1015         let session_notf = session_notf_receiver.recv().await.unwrap();
1016         assert_eq!(
1017             session_notf,
1018             SessionNotification::SessionState {
1019                 session_id,
1020                 session_state: SessionState::SessionStateIdle,
1021                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
1022             }
1023         );
1024 
1025         let session_notf = session_notf_receiver.recv().await.unwrap();
1026         assert_eq!(session_notf, SessionNotification::RangeData { session_id, range_data });
1027 
1028         assert!(mock_uci_manager.wait_expected_calls_done().await);
1029     }
1030 
1031     #[tokio::test]
test_reconfigure_app_config()1032     async fn test_reconfigure_app_config() {
1033         let session_id = 0x123;
1034         let session_type = SessionType::FiraRangingSession;
1035 
1036         let initial_params = generate_params();
1037         let initial_tlvs = initial_params.generate_tlvs();
1038 
1039         let non_default_key_rotation_val = KeyRotation::Enable;
1040         let idle_params = FiraAppConfigParamsBuilder::from_params(&initial_params)
1041             .unwrap()
1042             .key_rotation(non_default_key_rotation_val)
1043             .build()
1044             .unwrap();
1045         let idle_tlvs = idle_params
1046             .generate_updated_tlvs(&initial_params, SessionState::SessionStateIdle)
1047             .unwrap();
1048 
1049         let non_default_block_stride_val = 2u8;
1050         let active_params = FiraAppConfigParamsBuilder::from_params(&idle_params)
1051             .unwrap()
1052             .block_stride_length(non_default_block_stride_val)
1053             .build()
1054             .unwrap();
1055         let active_tlvs = active_params
1056             .generate_updated_tlvs(&idle_params, SessionState::SessionStateIdle)
1057             .unwrap();
1058 
1059         let (mut session_manager, mut mock_uci_manager, _) =
1060             setup_session_manager(move |uci_manager| {
1061                 uci_manager.expect_session_init(
1062                     session_id,
1063                     session_type,
1064                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
1065                     Ok(()),
1066                 );
1067                 uci_manager.expect_session_set_app_config(
1068                     session_id,
1069                     initial_tlvs,
1070                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
1071                     Ok(SetAppConfigResponse {
1072                         status: StatusCode::UciStatusOk,
1073                         config_status: vec![],
1074                     }),
1075                 );
1076                 uci_manager.expect_session_set_app_config(
1077                     session_id,
1078                     idle_tlvs,
1079                     vec![],
1080                     Ok(SetAppConfigResponse {
1081                         status: StatusCode::UciStatusOk,
1082                         config_status: vec![],
1083                     }),
1084                 );
1085                 uci_manager.expect_range_start(
1086                     session_id,
1087                     vec![session_status_notf(session_id, SessionState::SessionStateActive)],
1088                     Ok(()),
1089                 );
1090                 uci_manager.expect_session_set_app_config(
1091                     session_id,
1092                     active_tlvs,
1093                     vec![],
1094                     Ok(SetAppConfigResponse {
1095                         status: StatusCode::UciStatusOk,
1096                         config_status: vec![],
1097                     }),
1098                 );
1099             })
1100             .await;
1101 
1102         // Reconfiguring without first initing a session should fail.
1103         let result = session_manager.reconfigure(session_id, initial_params.clone()).await;
1104         assert_eq!(result, Err(Error::BadParameters));
1105 
1106         let result =
1107             session_manager.init_session(session_id, session_type, initial_params.clone()).await;
1108         assert_eq!(result, Ok(()));
1109 
1110         // Reconfiguring any parameters during idle state should succeed.
1111         let result = session_manager.reconfigure(session_id, idle_params.clone()).await;
1112         assert_eq!(result, Ok(()));
1113 
1114         let result = session_manager.start_ranging(session_id).await;
1115         assert_eq!(result, Ok(idle_params));
1116 
1117         // Reconfiguring most parameters during active state should fail.
1118         let result = session_manager.reconfigure(session_id, initial_params).await;
1119         assert_eq!(result, Err(Error::BadParameters));
1120 
1121         // Only some parameters are allowed to be reconfigured during active state.
1122         let result = session_manager.reconfigure(session_id, active_params).await;
1123         assert_eq!(result, Ok(()));
1124 
1125         assert!(mock_uci_manager.wait_expected_calls_done().await);
1126     }
1127 
1128     #[tokio::test]
test_session_params()1129     async fn test_session_params() {
1130         let session_id = 0x123;
1131         let session_type = SessionType::FiraRangingSession;
1132 
1133         let params = generate_params();
1134         let tlvs = params.generate_tlvs();
1135 
1136         let (mut session_manager, mut mock_uci_manager, _) =
1137             setup_session_manager(move |uci_manager| {
1138                 uci_manager.expect_session_init(
1139                     session_id,
1140                     session_type,
1141                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
1142                     Ok(()),
1143                 );
1144                 uci_manager.expect_session_set_app_config(
1145                     session_id,
1146                     tlvs,
1147                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
1148                     Ok(SetAppConfigResponse {
1149                         status: StatusCode::UciStatusOk,
1150                         config_status: vec![],
1151                     }),
1152                 );
1153             })
1154             .await;
1155 
1156         // Getting session params without initing a session should fail
1157         let result = session_manager.session_params(session_id).await;
1158         assert_eq!(result, Err(Error::BadParameters));
1159 
1160         let result = session_manager.init_session(session_id, session_type, params.clone()).await;
1161         result.unwrap();
1162 
1163         // Getting session params after they've been properly set should succeed
1164         let result = session_manager.session_params(session_id).await;
1165         assert_eq!(result, Ok(params));
1166 
1167         assert!(mock_uci_manager.wait_expected_calls_done().await);
1168     }
1169 }
1170