• 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::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             hus_primary_session_id: 0,
538             ranging_measurements: RangingMeasurements::ShortAddressTwoWay(vec![
539                 ShortAddressTwoWayRangingMeasurement {
540                     mac_address: 0x123,
541                     status: StatusCode::UciStatusOk,
542                     nlos: 0,
543                     distance: 4,
544                     aoa_azimuth: 5,
545                     aoa_azimuth_fom: 6,
546                     aoa_elevation: 7,
547                     aoa_elevation_fom: 8,
548                     aoa_destination_azimuth: 9,
549                     aoa_destination_azimuth_fom: 10,
550                     aoa_destination_elevation: 11,
551                     aoa_destination_elevation_fom: 12,
552                     slot_index: 0,
553                     rssi: u8::MAX,
554                 },
555             ]),
556             rcr_indicator: 0,
557             raw_ranging_data: vec![0x12, 0x34],
558         }
559     }
560 
session_status_notf( session_id: SessionId, session_state: SessionState, ) -> UciNotification561     pub(crate) fn session_status_notf(
562         session_id: SessionId,
563         session_state: SessionState,
564     ) -> UciNotification {
565         UciNotification::Session(UciSessionNotification::Status {
566             session_id: 0x0,
567             session_token: session_id,
568             session_state,
569             reason_code: ReasonCode::StateChangeWithSessionManagementCommands.into(),
570         })
571     }
572 
range_data_notf(range_data: SessionRangeData) -> UciNotification573     pub(crate) fn range_data_notf(range_data: SessionRangeData) -> UciNotification {
574         UciNotification::Session(UciSessionNotification::SessionInfo(range_data))
575     }
576 
setup_session_manager<F>( setup_uci_manager_fn: F, ) -> (SessionManager, MockUciManager, mpsc::UnboundedReceiver<SessionNotification>) where F: FnOnce(&mut MockUciManager),577     pub(super) async fn setup_session_manager<F>(
578         setup_uci_manager_fn: F,
579     ) -> (SessionManager, MockUciManager, mpsc::UnboundedReceiver<SessionNotification>)
580     where
581         F: FnOnce(&mut MockUciManager),
582     {
583         init_test_logging();
584         let (uci_notf_sender, uci_notf_receiver) = mpsc::unbounded_channel();
585         let (session_notf_sender, session_notf_receiver) = mpsc::unbounded_channel();
586         let mut uci_manager = MockUciManager::new();
587         uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP));
588         setup_uci_manager_fn(&mut uci_manager);
589         uci_manager.set_session_notification_sender(uci_notf_sender).await;
590         let _ = uci_manager.open_hal().await;
591 
592         (
593             SessionManager::new(uci_manager.clone(), uci_notf_receiver, session_notf_sender),
594             uci_manager,
595             session_notf_receiver,
596         )
597     }
598 }
599 
600 #[cfg(test)]
601 mod tests {
602     use super::test_utils::*;
603     use super::*;
604 
605     use std::collections::HashMap;
606 
607     use crate::params::ccc_started_app_config_params::CccStartedAppConfigParams;
608     use crate::params::uci_packets::{
609         AppConfigTlv, AppConfigTlvType, ControleeStatusV1, Controlees, MulticastUpdateStatusCode,
610         ReasonCode, SessionUpdateControllerMulticastResponse, SetAppConfigResponse, StatusCode,
611     };
612     use crate::params::utils::{u32_to_bytes, u64_to_bytes, u8_to_bytes};
613     use crate::params::{FiraAppConfigParamsBuilder, KeyRotation};
614     use crate::uci::notification::UciNotification;
615 
616     #[tokio::test]
test_init_deinit_session()617     async fn test_init_deinit_session() {
618         let session_id = 0x123;
619         let session_type = SessionType::FiraRangingSession;
620         let params = generate_params();
621 
622         let tlvs = params.generate_tlvs();
623         let (mut session_manager, mut mock_uci_manager, mut session_notf_receiver) =
624             setup_session_manager(move |uci_manager| {
625                 uci_manager.expect_session_init(
626                     session_id,
627                     session_type,
628                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
629                     Ok(()),
630                 );
631                 uci_manager.expect_session_set_app_config(
632                     session_id,
633                     tlvs,
634                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
635                     Ok(SetAppConfigResponse {
636                         status: StatusCode::UciStatusOk,
637                         config_status: vec![],
638                     }),
639                 );
640                 uci_manager.expect_session_deinit(
641                     session_id,
642                     vec![session_status_notf(session_id, SessionState::SessionStateDeinit)],
643                     Ok(()),
644                 );
645             })
646             .await;
647 
648         // Deinit a session before initialized should fail.
649         let result = session_manager.deinit_session(session_id).await;
650         assert_eq!(result, Err(Error::BadParameters));
651 
652         // Initialize a normal session should be successful.
653         let result = session_manager.init_session(session_id, session_type, params.clone()).await;
654         assert_eq!(result, Ok(()));
655         let session_notf = session_notf_receiver.recv().await.unwrap();
656         assert_eq!(
657             session_notf,
658             SessionNotification::SessionState {
659                 session_id,
660                 session_state: SessionState::SessionStateInit,
661                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
662             }
663         );
664         let session_notf = session_notf_receiver.recv().await.unwrap();
665         assert_eq!(
666             session_notf,
667             SessionNotification::SessionState {
668                 session_id,
669                 session_state: SessionState::SessionStateIdle,
670                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
671             }
672         );
673 
674         // Initialize a session multiple times without deinitialize should fail.
675         let result = session_manager.init_session(session_id, session_type, params).await;
676         assert_eq!(result, Err(Error::DuplicatedSessionId));
677 
678         // Deinitialize the session should be successful, and should receive the deinitialized
679         // notification.
680         let result = session_manager.deinit_session(session_id).await;
681         assert_eq!(result, Ok(()));
682         let session_notf = session_notf_receiver.recv().await.unwrap();
683         assert_eq!(
684             session_notf,
685             SessionNotification::SessionState {
686                 session_id,
687                 session_state: SessionState::SessionStateDeinit,
688                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
689             }
690         );
691 
692         // Deinit a session after deinitialized should fail.
693         let result = session_manager.deinit_session(session_id).await;
694         assert_eq!(result, Err(Error::BadParameters));
695 
696         assert!(mock_uci_manager.wait_expected_calls_done().await);
697     }
698 
699     #[tokio::test]
test_init_session_timeout()700     async fn test_init_session_timeout() {
701         let session_id = 0x123;
702         let session_type = SessionType::FiraRangingSession;
703         let params = generate_params();
704 
705         let (mut session_manager, mut mock_uci_manager, _) =
706             setup_session_manager(move |uci_manager| {
707                 let notfs = vec![]; // Not sending SessionStatus notification.
708                 uci_manager.expect_session_init(session_id, session_type, notfs, Ok(()));
709             })
710             .await;
711 
712         let result = session_manager.init_session(session_id, session_type, params).await;
713         assert_eq!(result, Err(Error::Timeout));
714 
715         assert!(mock_uci_manager.wait_expected_calls_done().await);
716     }
717 
718     #[tokio::test]
test_start_stop_ranging()719     async fn test_start_stop_ranging() {
720         let session_id = 0x123;
721         let session_type = SessionType::FiraRangingSession;
722         let params = generate_params();
723         let tlvs = params.generate_tlvs();
724 
725         let (mut session_manager, mut mock_uci_manager, _) =
726             setup_session_manager(move |uci_manager| {
727                 uci_manager.expect_session_init(
728                     session_id,
729                     session_type,
730                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
731                     Ok(()),
732                 );
733                 uci_manager.expect_session_set_app_config(
734                     session_id,
735                     tlvs,
736                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
737                     Ok(SetAppConfigResponse {
738                         status: StatusCode::UciStatusOk,
739                         config_status: vec![],
740                     }),
741                 );
742                 uci_manager.expect_range_start(
743                     session_id,
744                     vec![session_status_notf(session_id, SessionState::SessionStateActive)],
745                     Ok(()),
746                 );
747                 uci_manager.expect_range_stop(
748                     session_id,
749                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
750                     Ok(()),
751                 );
752             })
753             .await;
754 
755         let result = session_manager.init_session(session_id, session_type, params.clone()).await;
756         assert_eq!(result, Ok(()));
757         let result = session_manager.start_ranging(session_id).await;
758         assert_eq!(result, Ok(params));
759         let result = session_manager.stop_ranging(session_id).await;
760         assert_eq!(result, Ok(()));
761 
762         assert!(mock_uci_manager.wait_expected_calls_done().await);
763     }
764 
765     #[tokio::test]
test_ccc_start_ranging()766     async fn test_ccc_start_ranging() {
767         let session_id = 0x123;
768         let session_type = SessionType::Ccc;
769         // params that is passed to UciManager::session_set_app_config().
770         let params = generate_ccc_params();
771         let tlvs = params.generate_tlvs();
772         // The params that is received from UciManager::session_get_app_config().
773         let received_config_map = HashMap::from([
774             (AppConfigTlvType::StsIndex, u32_to_bytes(3)),
775             (AppConfigTlvType::CccHopModeKey, u32_to_bytes(5)),
776             (AppConfigTlvType::CccUwbTime0, u64_to_bytes(7)),
777             (AppConfigTlvType::RangingDuration, u32_to_bytes(96)),
778             (AppConfigTlvType::PreambleCodeIndex, u8_to_bytes(9)),
779         ]);
780         let received_tlvs = received_config_map
781             .iter()
782             .map(|(key, value)| AppConfigTlv::new(*key, value.clone()))
783             .collect();
784         let started_params =
785             CccStartedAppConfigParams::from_config_map(received_config_map).unwrap();
786 
787         let (mut session_manager, mut mock_uci_manager, _) =
788             setup_session_manager(move |uci_manager| {
789                 uci_manager.expect_session_init(
790                     session_id,
791                     session_type,
792                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
793                     Ok(()),
794                 );
795                 uci_manager.expect_session_set_app_config(
796                     session_id,
797                     tlvs,
798                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
799                     Ok(SetAppConfigResponse {
800                         status: StatusCode::UciStatusOk,
801                         config_status: vec![],
802                     }),
803                 );
804                 uci_manager.expect_range_start(
805                     session_id,
806                     vec![session_status_notf(session_id, SessionState::SessionStateActive)],
807                     Ok(()),
808                 );
809                 uci_manager.expect_session_get_app_config(session_id, vec![], Ok(received_tlvs));
810             })
811             .await;
812 
813         let result = session_manager.init_session(session_id, session_type, params.clone()).await;
814         assert_eq!(result, Ok(()));
815         let result = session_manager.start_ranging(session_id).await;
816         assert_eq!(result, Ok(AppConfigParams::CccStarted(started_params)));
817 
818         assert!(mock_uci_manager.wait_expected_calls_done().await);
819     }
820 
821     #[tokio::test]
test_update_controller_multicast_list()822     async fn test_update_controller_multicast_list() {
823         let session_id = 0x123;
824         let session_type = SessionType::FiraRangingSession;
825         let params = generate_params();
826         let tlvs = params.generate_tlvs();
827         let action = UpdateMulticastListAction::AddControlee;
828         let short_address: [u8; 2] = [0x12, 0x34];
829         let controlees = vec![Controlee { short_address, subsession_id: 0x24 }];
830 
831         let controlees_clone = controlees.clone();
832         let (mut session_manager, mut mock_uci_manager, _) =
833             setup_session_manager(move |uci_manager| {
834                 let multicast_list_notf = vec![UciNotification::Session(
835                     UciSessionNotification::UpdateControllerMulticastListV1 {
836                         session_token: session_id,
837                         remaining_multicast_list_size: 1,
838                         status_list: vec![ControleeStatusV1 {
839                             mac_address: [0x34, 0x12],
840                             subsession_id: 0x24,
841                             status: MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
842                         }],
843                     },
844                 )];
845                 uci_manager.expect_session_init(
846                     session_id,
847                     session_type,
848                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
849                     Ok(()),
850                 );
851                 uci_manager.expect_session_set_app_config(
852                     session_id,
853                     tlvs,
854                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
855                     Ok(SetAppConfigResponse {
856                         status: StatusCode::UciStatusOk,
857                         config_status: vec![],
858                     }),
859                 );
860                 uci_manager.expect_session_update_controller_multicast_list(
861                     session_id,
862                     action,
863                     Controlees::NoSessionKey(controlees_clone),
864                     multicast_list_notf,
865                     Ok(SessionUpdateControllerMulticastResponse {
866                         status: StatusCode::UciStatusOk,
867                         status_list: vec![],
868                     }),
869                 );
870             })
871             .await;
872 
873         let result = session_manager.init_session(session_id, session_type, params).await;
874         assert_eq!(result, Ok(()));
875         let result =
876             session_manager.update_controller_multicast_list(session_id, action, controlees).await;
877         assert_eq!(result, Ok(()));
878 
879         assert!(mock_uci_manager.wait_expected_calls_done().await);
880     }
881 
882     #[tokio::test]
test_ccc_update_controller_multicast_list()883     async fn test_ccc_update_controller_multicast_list() {
884         let session_id = 0x123;
885         let session_type = SessionType::Ccc;
886         let params = generate_ccc_params();
887         let tlvs = params.generate_tlvs();
888         let action = UpdateMulticastListAction::AddControlee;
889         let short_address: [u8; 2] = [0x12, 0x34];
890         let controlees = vec![Controlee { short_address, subsession_id: 0x24 }];
891 
892         let (mut session_manager, mut mock_uci_manager, _) =
893             setup_session_manager(move |uci_manager| {
894                 uci_manager.expect_session_init(
895                     session_id,
896                     session_type,
897                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
898                     Ok(()),
899                 );
900                 uci_manager.expect_session_set_app_config(
901                     session_id,
902                     tlvs,
903                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
904                     Ok(SetAppConfigResponse {
905                         status: StatusCode::UciStatusOk,
906                         config_status: vec![],
907                     }),
908                 );
909             })
910             .await;
911 
912         let result = session_manager.init_session(session_id, session_type, params).await;
913         assert_eq!(result, Ok(()));
914         // CCC session doesn't support update_controller_multicast_list.
915         let result =
916             session_manager.update_controller_multicast_list(session_id, action, controlees).await;
917         assert_eq!(result, Err(Error::BadParameters));
918 
919         assert!(mock_uci_manager.wait_expected_calls_done().await);
920     }
921 
922     #[tokio::test]
test_update_controller_multicast_list_without_notification()923     async fn test_update_controller_multicast_list_without_notification() {
924         let session_id = 0x123;
925         let session_type = SessionType::FiraRangingSession;
926         let params = generate_params();
927         let tlvs = params.generate_tlvs();
928         let action = UpdateMulticastListAction::AddControlee;
929         let short_address: [u8; 2] = [0x12, 0x34];
930         let controlees = vec![Controlee { short_address, subsession_id: 0x24 }];
931 
932         let controlees_clone = controlees.clone();
933         let (mut session_manager, mut mock_uci_manager, _) =
934             setup_session_manager(move |uci_manager| {
935                 uci_manager.expect_session_init(
936                     session_id,
937                     session_type,
938                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
939                     Ok(()),
940                 );
941                 uci_manager.expect_session_set_app_config(
942                     session_id,
943                     tlvs,
944                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
945                     Ok(SetAppConfigResponse {
946                         status: StatusCode::UciStatusOk,
947                         config_status: vec![],
948                     }),
949                 );
950                 uci_manager.expect_session_update_controller_multicast_list(
951                     session_id,
952                     action,
953                     uwb_uci_packets::Controlees::NoSessionKey(controlees_clone),
954                     vec![], // Not sending notification.
955                     Ok(SessionUpdateControllerMulticastResponse {
956                         status: StatusCode::UciStatusOk,
957                         status_list: vec![],
958                     }),
959                 );
960             })
961             .await;
962 
963         let result = session_manager.init_session(session_id, session_type, params).await;
964         assert_eq!(result, Ok(()));
965         // This method should timeout waiting for the notification.
966         let result =
967             session_manager.update_controller_multicast_list(session_id, action, controlees).await;
968         assert_eq!(result, Err(Error::Timeout));
969 
970         assert!(mock_uci_manager.wait_expected_calls_done().await);
971     }
972 
973     #[tokio::test]
test_receive_session_range_data()974     async fn test_receive_session_range_data() {
975         let session_id = 0x123;
976         let session_type = SessionType::FiraRangingSession;
977         let params = generate_params();
978         let tlvs = params.generate_tlvs();
979         let range_data = session_range_data(session_id);
980         let range_data_clone = range_data.clone();
981 
982         let (mut session_manager, mut mock_uci_manager, mut session_notf_receiver) =
983             setup_session_manager(move |uci_manager| {
984                 uci_manager.expect_session_init(
985                     session_id,
986                     session_type,
987                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
988                     Ok(()),
989                 );
990                 uci_manager.expect_session_set_app_config(
991                     session_id,
992                     tlvs,
993                     vec![
994                         session_status_notf(session_id, SessionState::SessionStateIdle),
995                         range_data_notf(range_data_clone),
996                     ],
997                     Ok(SetAppConfigResponse {
998                         status: StatusCode::UciStatusOk,
999                         config_status: vec![],
1000                     }),
1001                 );
1002             })
1003             .await;
1004 
1005         let result = session_manager.init_session(session_id, session_type, params).await;
1006         assert_eq!(result, Ok(()));
1007         let session_notf = session_notf_receiver.recv().await.unwrap();
1008         assert_eq!(
1009             session_notf,
1010             SessionNotification::SessionState {
1011                 session_id,
1012                 session_state: SessionState::SessionStateInit,
1013                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
1014             }
1015         );
1016         let session_notf = session_notf_receiver.recv().await.unwrap();
1017         assert_eq!(
1018             session_notf,
1019             SessionNotification::SessionState {
1020                 session_id,
1021                 session_state: SessionState::SessionStateIdle,
1022                 reason_code: ReasonCode::StateChangeWithSessionManagementCommands
1023             }
1024         );
1025 
1026         let session_notf = session_notf_receiver.recv().await.unwrap();
1027         assert_eq!(session_notf, SessionNotification::RangeData { session_id, range_data });
1028 
1029         assert!(mock_uci_manager.wait_expected_calls_done().await);
1030     }
1031 
1032     #[tokio::test]
test_reconfigure_app_config()1033     async fn test_reconfigure_app_config() {
1034         let session_id = 0x123;
1035         let session_type = SessionType::FiraRangingSession;
1036 
1037         let initial_params = generate_params();
1038         let initial_tlvs = initial_params.generate_tlvs();
1039 
1040         let non_default_key_rotation_val = KeyRotation::Enable;
1041         let idle_params = FiraAppConfigParamsBuilder::from_params(&initial_params)
1042             .unwrap()
1043             .key_rotation(non_default_key_rotation_val)
1044             .build()
1045             .unwrap();
1046         let idle_tlvs = idle_params
1047             .generate_updated_tlvs(&initial_params, SessionState::SessionStateIdle)
1048             .unwrap();
1049 
1050         let non_default_block_stride_val = 2u8;
1051         let active_params = FiraAppConfigParamsBuilder::from_params(&idle_params)
1052             .unwrap()
1053             .block_stride_length(non_default_block_stride_val)
1054             .build()
1055             .unwrap();
1056         let active_tlvs = active_params
1057             .generate_updated_tlvs(&idle_params, SessionState::SessionStateIdle)
1058             .unwrap();
1059 
1060         let (mut session_manager, mut mock_uci_manager, _) =
1061             setup_session_manager(move |uci_manager| {
1062                 uci_manager.expect_session_init(
1063                     session_id,
1064                     session_type,
1065                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
1066                     Ok(()),
1067                 );
1068                 uci_manager.expect_session_set_app_config(
1069                     session_id,
1070                     initial_tlvs,
1071                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
1072                     Ok(SetAppConfigResponse {
1073                         status: StatusCode::UciStatusOk,
1074                         config_status: vec![],
1075                     }),
1076                 );
1077                 uci_manager.expect_session_set_app_config(
1078                     session_id,
1079                     idle_tlvs,
1080                     vec![],
1081                     Ok(SetAppConfigResponse {
1082                         status: StatusCode::UciStatusOk,
1083                         config_status: vec![],
1084                     }),
1085                 );
1086                 uci_manager.expect_range_start(
1087                     session_id,
1088                     vec![session_status_notf(session_id, SessionState::SessionStateActive)],
1089                     Ok(()),
1090                 );
1091                 uci_manager.expect_session_set_app_config(
1092                     session_id,
1093                     active_tlvs,
1094                     vec![],
1095                     Ok(SetAppConfigResponse {
1096                         status: StatusCode::UciStatusOk,
1097                         config_status: vec![],
1098                     }),
1099                 );
1100             })
1101             .await;
1102 
1103         // Reconfiguring without first initing a session should fail.
1104         let result = session_manager.reconfigure(session_id, initial_params.clone()).await;
1105         assert_eq!(result, Err(Error::BadParameters));
1106 
1107         let result =
1108             session_manager.init_session(session_id, session_type, initial_params.clone()).await;
1109         assert_eq!(result, Ok(()));
1110 
1111         // Reconfiguring any parameters during idle state should succeed.
1112         let result = session_manager.reconfigure(session_id, idle_params.clone()).await;
1113         assert_eq!(result, Ok(()));
1114 
1115         let result = session_manager.start_ranging(session_id).await;
1116         assert_eq!(result, Ok(idle_params));
1117 
1118         // Reconfiguring most parameters during active state should fail.
1119         let result = session_manager.reconfigure(session_id, initial_params).await;
1120         assert_eq!(result, Err(Error::BadParameters));
1121 
1122         // Only some parameters are allowed to be reconfigured during active state.
1123         let result = session_manager.reconfigure(session_id, active_params).await;
1124         assert_eq!(result, Ok(()));
1125 
1126         assert!(mock_uci_manager.wait_expected_calls_done().await);
1127     }
1128 
1129     #[tokio::test]
test_session_params()1130     async fn test_session_params() {
1131         let session_id = 0x123;
1132         let session_type = SessionType::FiraRangingSession;
1133 
1134         let params = generate_params();
1135         let tlvs = params.generate_tlvs();
1136 
1137         let (mut session_manager, mut mock_uci_manager, _) =
1138             setup_session_manager(move |uci_manager| {
1139                 uci_manager.expect_session_init(
1140                     session_id,
1141                     session_type,
1142                     vec![session_status_notf(session_id, SessionState::SessionStateInit)],
1143                     Ok(()),
1144                 );
1145                 uci_manager.expect_session_set_app_config(
1146                     session_id,
1147                     tlvs,
1148                     vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
1149                     Ok(SetAppConfigResponse {
1150                         status: StatusCode::UciStatusOk,
1151                         config_status: vec![],
1152                     }),
1153                 );
1154             })
1155             .await;
1156 
1157         // Getting session params without initing a session should fail
1158         let result = session_manager.session_params(session_id).await;
1159         assert_eq!(result, Err(Error::BadParameters));
1160 
1161         let result = session_manager.init_session(session_id, session_type, params.clone()).await;
1162         result.unwrap();
1163 
1164         // Getting session params after they've been properly set should succeed
1165         let result = session_manager.session_params(session_id).await;
1166         assert_eq!(result, Ok(params));
1167 
1168         assert!(mock_uci_manager.wait_expected_calls_done().await);
1169     }
1170 }
1171