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