• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use std::convert::{TryFrom, TryInto};
16 
17 use log::{debug, error};
18 use uwb_uci_packets::{parse_diagnostics_ntf, Packet, UCI_PACKET_HEADER_LEN};
19 
20 use crate::error::{Error, Result};
21 use crate::params::fira_app_config_params::UwbAddress;
22 use crate::params::uci_packets::{
23     ControleeStatus, CreditAvailability, DataRcvStatusCode, DataTransferNtfStatusCode, DeviceState,
24     ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
25     ExtendedAddressTwoWayRangingMeasurement, FiraComponent, RangingMeasurementType, RawUciMessage,
26     SessionState, SessionToken, ShortAddressDlTdoaRangingMeasurement,
27     ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode,
28 };
29 
30 /// enum of all UCI notifications with structured fields.
31 #[derive(Debug, Clone, PartialEq)]
32 pub enum UciNotification {
33     /// CoreNotification equivalent.
34     Core(CoreNotification),
35     /// SessionNotification equivalent.
36     Session(SessionNotification),
37     /// UciVendor_X_Notification equivalent.
38     Vendor(RawUciMessage),
39 }
40 
41 /// UCI CoreNotification.
42 #[derive(Debug, Clone, PartialEq, Eq)]
43 pub enum CoreNotification {
44     /// DeviceStatusNtf equivalent.
45     DeviceStatus(DeviceState),
46     /// GenericErrorPacket equivalent.
47     GenericError(StatusCode),
48 }
49 
50 /// UCI SessionNotification.
51 #[derive(Debug, Clone, PartialEq)]
52 pub enum SessionNotification {
53     /// SessionStatusNtf equivalent.
54     Status {
55         /// SessionToken : u32
56         session_token: SessionToken,
57         /// uwb_uci_packets::SessionState.
58         session_state: SessionState,
59         /// uwb_uci_packets::Reasoncode.
60         reason_code: u8,
61     },
62     /// SessionUpdateControllerMulticastListNtf equivalent.
63     UpdateControllerMulticastList {
64         /// SessionToken : u32
65         session_token: SessionToken,
66         /// count of controlees: u8
67         remaining_multicast_list_size: usize,
68         /// list of controlees.
69         status_list: Vec<ControleeStatus>,
70     },
71     /// (Short/Extended)Mac()SessionInfoNtf equivalent
72     SessionInfo(SessionRangeData),
73     /// DataCreditNtf equivalent.
74     DataCredit {
75         /// SessionToken : u32
76         session_token: SessionToken,
77         /// Credit Availability (for sending Data packets on UWB Session)
78         credit_availability: CreditAvailability,
79     },
80     /// DataTransferStatusNtf equivalent.
81     DataTransferStatus {
82         /// SessionToken : u32
83         session_token: SessionToken,
84         /// Sequence Number: u8
85         uci_sequence_number: u8,
86         /// Data Transfer Status Code
87         status: DataTransferNtfStatusCode,
88     },
89 }
90 
91 /// The session range data.
92 #[derive(Debug, Clone, PartialEq)]
93 pub struct SessionRangeData {
94     /// The sequence counter that starts with 0 when the session is started.
95     pub sequence_number: u32,
96 
97     /// The identifier of the session.
98     pub session_token: SessionToken,
99 
100     /// The current ranging interval setting in the unit of ms.
101     pub current_ranging_interval_ms: u32,
102 
103     /// The ranging measurement type.
104     pub ranging_measurement_type: RangingMeasurementType,
105 
106     /// The ranging measurement data.
107     pub ranging_measurements: RangingMeasurements,
108 
109     /// Indication that a RCR was sent/received in the current ranging round.
110     pub rcr_indicator: u8,
111 
112     /// The raw data of the notification message.
113     /// (b/243555651): It's not at FiRa specification, only used by vendor's extension.
114     pub raw_ranging_data: Vec<u8>,
115 }
116 
117 /// The ranging measurements.
118 #[derive(Debug, Clone, PartialEq)]
119 pub enum RangingMeasurements {
120     /// A Two-Way measurement with short address.
121     ShortAddressTwoWay(Vec<ShortAddressTwoWayRangingMeasurement>),
122 
123     /// A Two-Way measurement with extended address.
124     ExtendedAddressTwoWay(Vec<ExtendedAddressTwoWayRangingMeasurement>),
125 
126     /// Dl-TDoA measurement with short address.
127     ShortAddressDltdoa(Vec<ShortAddressDlTdoaRangingMeasurement>),
128 
129     /// Dl-TDoA measurement with extended address.
130     ExtendedAddressDltdoa(Vec<ExtendedAddressDlTdoaRangingMeasurement>),
131 
132     /// OWR for AoA measurement with short address.
133     ShortAddressOwrAoa(ShortAddressOwrAoaRangingMeasurement),
134 
135     /// OWR for AoA measurement with extended address.
136     ExtendedAddressOwrAoa(ExtendedAddressOwrAoaRangingMeasurement),
137 }
138 
139 /// The DATA_RCV packet
140 #[derive(Debug, Clone)]
141 pub struct DataRcvNotification {
142     /// The identifier of the session on which data transfer is happening.
143     pub session_token: SessionToken,
144 
145     /// The status of the data rx.
146     pub status: DataRcvStatusCode,
147 
148     /// The sequence number of the data packet.
149     pub uci_sequence_num: u32,
150 
151     /// MacAddress of the sender of the application data.
152     pub source_address: UwbAddress,
153 
154     /// Identifier for the source FiraComponent.
155     pub source_fira_component: FiraComponent,
156 
157     /// Identifier for the destination FiraComponent.
158     pub dest_fira_component: FiraComponent,
159 
160     /// Application Payload Data
161     pub payload: Vec<u8>,
162 }
163 
164 impl TryFrom<uwb_uci_packets::UciDataPacket> for DataRcvNotification {
165     type Error = Error;
try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error>166     fn try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error> {
167         match evt.specialize() {
168             uwb_uci_packets::UciDataPacketChild::UciDataRcv(evt) => Ok(DataRcvNotification {
169                 session_token: evt.get_session_token(),
170                 status: evt.get_status(),
171                 uci_sequence_num: evt.get_uci_sequence_number(),
172                 source_address: UwbAddress::Extended(evt.get_source_mac_address().to_le_bytes()),
173                 source_fira_component: evt.get_source_fira_component(),
174                 dest_fira_component: evt.get_dest_fira_component(),
175                 payload: evt.get_data().to_vec(),
176             }),
177             _ => {
178                 error!("Unknown UciData packet: {:?}", evt);
179                 Err(Error::Unknown)
180             }
181         }
182     }
183 }
184 
185 impl UciNotification {
need_retry(&self) -> bool186     pub(crate) fn need_retry(&self) -> bool {
187         matches!(
188             self,
189             Self::Core(CoreNotification::GenericError(StatusCode::UciStatusCommandRetry))
190         )
191     }
192 }
193 
194 impl TryFrom<uwb_uci_packets::UciNotification> for UciNotification {
195     type Error = Error;
try_from(evt: uwb_uci_packets::UciNotification) -> std::result::Result<Self, Self::Error>196     fn try_from(evt: uwb_uci_packets::UciNotification) -> std::result::Result<Self, Self::Error> {
197         use uwb_uci_packets::UciNotificationChild;
198         match evt.specialize() {
199             UciNotificationChild::CoreNotification(evt) => Ok(Self::Core(evt.try_into()?)),
200             UciNotificationChild::SessionConfigNotification(evt) => {
201                 Ok(Self::Session(evt.try_into()?))
202             }
203             UciNotificationChild::SessionControlNotification(evt) => {
204                 Ok(Self::Session(evt.try_into()?))
205             }
206             UciNotificationChild::AndroidNotification(evt) => evt.try_into(),
207             UciNotificationChild::UciVendor_9_Notification(evt) => vendor_notification(evt.into()),
208             UciNotificationChild::UciVendor_A_Notification(evt) => vendor_notification(evt.into()),
209             UciNotificationChild::UciVendor_B_Notification(evt) => vendor_notification(evt.into()),
210             UciNotificationChild::UciVendor_E_Notification(evt) => vendor_notification(evt.into()),
211             UciNotificationChild::UciVendor_F_Notification(evt) => vendor_notification(evt.into()),
212             UciNotificationChild::TestNotification(evt) => vendor_notification(evt.into()),
213             _ => {
214                 error!("Unknown UciNotification: {:?}", evt);
215                 Err(Error::Unknown)
216             }
217         }
218     }
219 }
220 
221 impl TryFrom<uwb_uci_packets::CoreNotification> for CoreNotification {
222     type Error = Error;
try_from(evt: uwb_uci_packets::CoreNotification) -> std::result::Result<Self, Self::Error>223     fn try_from(evt: uwb_uci_packets::CoreNotification) -> std::result::Result<Self, Self::Error> {
224         use uwb_uci_packets::CoreNotificationChild;
225         match evt.specialize() {
226             CoreNotificationChild::DeviceStatusNtf(evt) => {
227                 Ok(Self::DeviceStatus(evt.get_device_state()))
228             }
229             CoreNotificationChild::GenericError(evt) => Ok(Self::GenericError(evt.get_status())),
230             _ => {
231                 error!("Unknown CoreNotification: {:?}", evt);
232                 Err(Error::Unknown)
233             }
234         }
235     }
236 }
237 
238 impl TryFrom<uwb_uci_packets::SessionConfigNotification> for SessionNotification {
239     type Error = Error;
try_from( evt: uwb_uci_packets::SessionConfigNotification, ) -> std::result::Result<Self, Self::Error>240     fn try_from(
241         evt: uwb_uci_packets::SessionConfigNotification,
242     ) -> std::result::Result<Self, Self::Error> {
243         use uwb_uci_packets::SessionConfigNotificationChild;
244         match evt.specialize() {
245             SessionConfigNotificationChild::SessionStatusNtf(evt) => Ok(Self::Status {
246                 session_token: evt.get_session_token(),
247                 session_state: evt.get_session_state(),
248                 reason_code: evt.get_reason_code(),
249             }),
250             SessionConfigNotificationChild::SessionUpdateControllerMulticastListNtf(evt) => {
251                 Ok(Self::UpdateControllerMulticastList {
252                     session_token: evt.get_session_token(),
253                     remaining_multicast_list_size: evt.get_remaining_multicast_list_size() as usize,
254                     status_list: evt.get_controlee_status().clone(),
255                 })
256             }
257             _ => {
258                 error!("Unknown SessionConfigNotification: {:?}", evt);
259                 Err(Error::Unknown)
260             }
261         }
262     }
263 }
264 
265 impl TryFrom<uwb_uci_packets::SessionControlNotification> for SessionNotification {
266     type Error = Error;
try_from( evt: uwb_uci_packets::SessionControlNotification, ) -> std::result::Result<Self, Self::Error>267     fn try_from(
268         evt: uwb_uci_packets::SessionControlNotification,
269     ) -> std::result::Result<Self, Self::Error> {
270         use uwb_uci_packets::SessionControlNotificationChild;
271         match evt.specialize() {
272             SessionControlNotificationChild::SessionInfoNtf(evt) => evt.try_into(),
273             SessionControlNotificationChild::DataCreditNtf(evt) => Ok(Self::DataCredit {
274                 session_token: evt.get_session_token(),
275                 credit_availability: evt.get_credit_availability(),
276             }),
277             SessionControlNotificationChild::DataTransferStatusNtf(evt) => {
278                 Ok(Self::DataTransferStatus {
279                     session_token: evt.get_session_token(),
280                     uci_sequence_number: evt.get_uci_sequence_number(),
281                     status: evt.get_status(),
282                 })
283             }
284             _ => {
285                 error!("Unknown SessionControlNotification: {:?}", evt);
286                 Err(Error::Unknown)
287             }
288         }
289     }
290 }
291 
292 impl TryFrom<uwb_uci_packets::SessionInfoNtf> for SessionNotification {
293     type Error = Error;
try_from(evt: uwb_uci_packets::SessionInfoNtf) -> std::result::Result<Self, Self::Error>294     fn try_from(evt: uwb_uci_packets::SessionInfoNtf) -> std::result::Result<Self, Self::Error> {
295         let raw_ranging_data = evt.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
296         use uwb_uci_packets::SessionInfoNtfChild;
297         let ranging_measurements = match evt.specialize() {
298             SessionInfoNtfChild::ShortMacTwoWaySessionInfoNtf(evt) => {
299                 RangingMeasurements::ShortAddressTwoWay(
300                     evt.get_two_way_ranging_measurements().clone(),
301                 )
302             }
303             SessionInfoNtfChild::ExtendedMacTwoWaySessionInfoNtf(evt) => {
304                 RangingMeasurements::ExtendedAddressTwoWay(
305                     evt.get_two_way_ranging_measurements().clone(),
306                 )
307             }
308             SessionInfoNtfChild::ShortMacOwrAoaSessionInfoNtf(evt) => {
309                 if evt.get_owr_aoa_ranging_measurements().clone().len() == 1 {
310                     RangingMeasurements::ShortAddressOwrAoa(
311                         match evt.get_owr_aoa_ranging_measurements().clone().pop() {
312                             Some(r) => r,
313                             None => {
314                                 error!(
315                                     "Unable to parse ShortAddress OwrAoA measurement: {:?}",
316                                     evt
317                                 );
318                                 return Err(Error::BadParameters);
319                             }
320                         },
321                     )
322                 } else {
323                     error!("Wrong count of OwrAoA ranging measurements {:?}", evt);
324                     return Err(Error::BadParameters);
325                 }
326             }
327             SessionInfoNtfChild::ExtendedMacOwrAoaSessionInfoNtf(evt) => {
328                 if evt.get_owr_aoa_ranging_measurements().clone().len() == 1 {
329                     RangingMeasurements::ExtendedAddressOwrAoa(
330                         match evt.get_owr_aoa_ranging_measurements().clone().pop() {
331                             Some(r) => r,
332                             None => {
333                                 error!(
334                                     "Unable to parse ExtendedAddress OwrAoA measurement: {:?}",
335                                     evt
336                                 );
337                                 return Err(Error::BadParameters);
338                             }
339                         },
340                     )
341                 } else {
342                     error!("Wrong count of OwrAoA ranging measurements {:?}", evt);
343                     return Err(Error::BadParameters);
344                 }
345             }
346             SessionInfoNtfChild::ShortMacDlTDoASessionInfoNtf(evt) => {
347                 match ShortAddressDlTdoaRangingMeasurement::parse(
348                     evt.get_dl_tdoa_measurements(),
349                     evt.get_no_of_ranging_measurements(),
350                 ) {
351                     Some(v) => {
352                         if v.len() == evt.get_no_of_ranging_measurements().into() {
353                             RangingMeasurements::ShortAddressDltdoa(v)
354                         } else {
355                             error!("Wrong count of ranging measurements {:?}", evt);
356                             return Err(Error::BadParameters);
357                         }
358                     }
359                     None => return Err(Error::BadParameters),
360                 }
361             }
362             SessionInfoNtfChild::ExtendedMacDlTDoASessionInfoNtf(evt) => {
363                 match ExtendedAddressDlTdoaRangingMeasurement::parse(
364                     evt.get_dl_tdoa_measurements(),
365                     evt.get_no_of_ranging_measurements(),
366                 ) {
367                     Some(v) => {
368                         if v.len() == evt.get_no_of_ranging_measurements().into() {
369                             RangingMeasurements::ExtendedAddressDltdoa(v)
370                         } else {
371                             error!("Wrong count of ranging measurements {:?}", evt);
372                             return Err(Error::BadParameters);
373                         }
374                     }
375                     None => return Err(Error::BadParameters),
376                 }
377             }
378             _ => {
379                 error!("Unknown SessionInfoNtf: {:?}", evt);
380                 return Err(Error::Unknown);
381             }
382         };
383         Ok(Self::SessionInfo(SessionRangeData {
384             sequence_number: evt.get_sequence_number(),
385             session_token: evt.get_session_token(),
386             current_ranging_interval_ms: evt.get_current_ranging_interval(),
387             ranging_measurement_type: evt.get_ranging_measurement_type(),
388             ranging_measurements,
389             rcr_indicator: evt.get_rcr_indicator(),
390             raw_ranging_data,
391         }))
392     }
393 }
394 
395 impl TryFrom<uwb_uci_packets::AndroidNotification> for UciNotification {
396     type Error = Error;
try_from( evt: uwb_uci_packets::AndroidNotification, ) -> std::result::Result<Self, Self::Error>397     fn try_from(
398         evt: uwb_uci_packets::AndroidNotification,
399     ) -> std::result::Result<Self, Self::Error> {
400         use uwb_uci_packets::AndroidNotificationChild;
401 
402         // (b/241336806): Currently we don't process the diagnostic packet, just log it only.
403         if let AndroidNotificationChild::AndroidRangeDiagnosticsNtf(ntf) = evt.specialize() {
404             debug!("Received diagnostic packet: {:?}", parse_diagnostics_ntf(ntf));
405         } else {
406             error!("Received unknown AndroidNotification: {:?}", evt);
407         }
408         Err(Error::Unknown)
409     }
410 }
411 
vendor_notification(evt: uwb_uci_packets::UciNotification) -> Result<UciNotification>412 fn vendor_notification(evt: uwb_uci_packets::UciNotification) -> Result<UciNotification> {
413     Ok(UciNotification::Vendor(RawUciMessage {
414         gid: evt.get_group_id().into(),
415         oid: evt.get_opcode().into(),
416         payload: get_vendor_uci_payload(evt)?,
417     }))
418 }
419 
get_vendor_uci_payload(evt: uwb_uci_packets::UciNotification) -> Result<Vec<u8>>420 fn get_vendor_uci_payload(evt: uwb_uci_packets::UciNotification) -> Result<Vec<u8>> {
421     match evt.specialize() {
422         uwb_uci_packets::UciNotificationChild::UciVendor_9_Notification(evt) => {
423             match evt.specialize() {
424                 uwb_uci_packets::UciVendor_9_NotificationChild::Payload(payload) => {
425                     Ok(payload.to_vec())
426                 }
427                 uwb_uci_packets::UciVendor_9_NotificationChild::None => Ok(Vec::new()),
428             }
429         }
430         uwb_uci_packets::UciNotificationChild::UciVendor_A_Notification(evt) => {
431             match evt.specialize() {
432                 uwb_uci_packets::UciVendor_A_NotificationChild::Payload(payload) => {
433                     Ok(payload.to_vec())
434                 }
435                 uwb_uci_packets::UciVendor_A_NotificationChild::None => Ok(Vec::new()),
436             }
437         }
438         uwb_uci_packets::UciNotificationChild::UciVendor_B_Notification(evt) => {
439             match evt.specialize() {
440                 uwb_uci_packets::UciVendor_B_NotificationChild::Payload(payload) => {
441                     Ok(payload.to_vec())
442                 }
443                 uwb_uci_packets::UciVendor_B_NotificationChild::None => Ok(Vec::new()),
444             }
445         }
446         uwb_uci_packets::UciNotificationChild::UciVendor_E_Notification(evt) => {
447             match evt.specialize() {
448                 uwb_uci_packets::UciVendor_E_NotificationChild::Payload(payload) => {
449                     Ok(payload.to_vec())
450                 }
451                 uwb_uci_packets::UciVendor_E_NotificationChild::None => Ok(Vec::new()),
452             }
453         }
454         uwb_uci_packets::UciNotificationChild::UciVendor_F_Notification(evt) => {
455             match evt.specialize() {
456                 uwb_uci_packets::UciVendor_F_NotificationChild::Payload(payload) => {
457                     Ok(payload.to_vec())
458                 }
459                 uwb_uci_packets::UciVendor_F_NotificationChild::None => Ok(Vec::new()),
460             }
461         }
462         uwb_uci_packets::UciNotificationChild::TestNotification(evt) => match evt.specialize() {
463             uwb_uci_packets::TestNotificationChild::Payload(payload) => Ok(payload.to_vec()),
464             uwb_uci_packets::TestNotificationChild::None => Ok(Vec::new()),
465         },
466         _ => {
467             error!("Unknown UciVendor packet: {:?}", evt);
468             Err(Error::Unknown)
469         }
470     }
471 }
472 
473 #[cfg(test)]
474 mod tests {
475     use super::*;
476 
477     #[test]
test_ranging_measurements_trait()478     fn test_ranging_measurements_trait() {
479         let empty_short_ranging_measurements = RangingMeasurements::ShortAddressTwoWay(vec![]);
480         assert_eq!(empty_short_ranging_measurements, empty_short_ranging_measurements);
481         let extended_ranging_measurements = RangingMeasurements::ExtendedAddressTwoWay(vec![
482             ExtendedAddressTwoWayRangingMeasurement {
483                 mac_address: 0x1234_5678_90ab,
484                 status: StatusCode::UciStatusOk,
485                 nlos: 0,
486                 distance: 4,
487                 aoa_azimuth: 5,
488                 aoa_azimuth_fom: 6,
489                 aoa_elevation: 7,
490                 aoa_elevation_fom: 8,
491                 aoa_destination_azimuth: 9,
492                 aoa_destination_azimuth_fom: 10,
493                 aoa_destination_elevation: 11,
494                 aoa_destination_elevation_fom: 12,
495                 slot_index: 0,
496                 rssi: u8::MAX,
497             },
498         ]);
499         let extended_ranging_measurements_copy = extended_ranging_measurements.clone();
500         assert_eq!(extended_ranging_measurements, extended_ranging_measurements_copy);
501         let empty_extended_ranging_measurements =
502             RangingMeasurements::ExtendedAddressTwoWay(vec![]);
503         assert_eq!(empty_short_ranging_measurements, empty_short_ranging_measurements);
504         //short and extended measurements are unequal even if both are empty:
505         assert_ne!(empty_short_ranging_measurements, empty_extended_ranging_measurements);
506     }
507     #[test]
test_core_notification_casting_from_generic_error()508     fn test_core_notification_casting_from_generic_error() {
509         let generic_error_packet = uwb_uci_packets::GenericErrorBuilder {
510             status: uwb_uci_packets::StatusCode::UciStatusRejected,
511         }
512         .build();
513         let core_notification =
514             uwb_uci_packets::CoreNotification::try_from(generic_error_packet).unwrap();
515         let core_notification = CoreNotification::try_from(core_notification).unwrap();
516         let uci_notification_from_generic_error = UciNotification::Core(core_notification);
517         assert_eq!(
518             uci_notification_from_generic_error,
519             UciNotification::Core(CoreNotification::GenericError(
520                 uwb_uci_packets::StatusCode::UciStatusRejected
521             ))
522         );
523     }
524     #[test]
test_core_notification_casting_from_device_status_ntf()525     fn test_core_notification_casting_from_device_status_ntf() {
526         let device_status_ntf_packet = uwb_uci_packets::DeviceStatusNtfBuilder {
527             device_state: uwb_uci_packets::DeviceState::DeviceStateActive,
528         }
529         .build();
530         let core_notification =
531             uwb_uci_packets::CoreNotification::try_from(device_status_ntf_packet).unwrap();
532         let uci_notification = CoreNotification::try_from(core_notification).unwrap();
533         let uci_notification_from_device_status_ntf = UciNotification::Core(uci_notification);
534         assert_eq!(
535             uci_notification_from_device_status_ntf,
536             UciNotification::Core(CoreNotification::DeviceStatus(
537                 uwb_uci_packets::DeviceState::DeviceStateActive
538             ))
539         );
540     }
541 
542     #[test]
test_session_notification_casting_from_extended_mac_two_way_session_info_ntf()543     fn test_session_notification_casting_from_extended_mac_two_way_session_info_ntf() {
544         let extended_measurement = uwb_uci_packets::ExtendedAddressTwoWayRangingMeasurement {
545             mac_address: 0x1234_5678_90ab,
546             status: StatusCode::UciStatusOk,
547             nlos: 0,
548             distance: 4,
549             aoa_azimuth: 5,
550             aoa_azimuth_fom: 6,
551             aoa_elevation: 7,
552             aoa_elevation_fom: 8,
553             aoa_destination_azimuth: 9,
554             aoa_destination_azimuth_fom: 10,
555             aoa_destination_elevation: 11,
556             aoa_destination_elevation_fom: 12,
557             slot_index: 0,
558             rssi: u8::MAX,
559         };
560         let extended_two_way_session_info_ntf =
561             uwb_uci_packets::ExtendedMacTwoWaySessionInfoNtfBuilder {
562                 sequence_number: 0x10,
563                 session_token: 0x11,
564                 rcr_indicator: 0x12,
565                 current_ranging_interval: 0x13,
566                 two_way_ranging_measurements: vec![extended_measurement.clone()],
567                 vendor_data: vec![],
568             }
569             .build();
570         let raw_ranging_data =
571             extended_two_way_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
572         let range_notification =
573             uwb_uci_packets::SessionInfoNtf::try_from(extended_two_way_session_info_ntf).unwrap();
574         let session_notification = SessionNotification::try_from(range_notification).unwrap();
575         let uci_notification_from_extended_two_way_session_info_ntf =
576             UciNotification::Session(session_notification);
577         assert_eq!(
578             uci_notification_from_extended_two_way_session_info_ntf,
579             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
580                 sequence_number: 0x10,
581                 session_token: 0x11,
582                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::TwoWay,
583                 current_ranging_interval_ms: 0x13,
584                 ranging_measurements: RangingMeasurements::ExtendedAddressTwoWay(vec![
585                     extended_measurement
586                 ]),
587                 rcr_indicator: 0x12,
588                 raw_ranging_data,
589             }))
590         );
591     }
592 
593     #[test]
test_session_notification_casting_from_short_mac_two_way_session_info_ntf()594     fn test_session_notification_casting_from_short_mac_two_way_session_info_ntf() {
595         let short_measurement = uwb_uci_packets::ShortAddressTwoWayRangingMeasurement {
596             mac_address: 0x1234,
597             status: StatusCode::UciStatusOk,
598             nlos: 0,
599             distance: 4,
600             aoa_azimuth: 5,
601             aoa_azimuth_fom: 6,
602             aoa_elevation: 7,
603             aoa_elevation_fom: 8,
604             aoa_destination_azimuth: 9,
605             aoa_destination_azimuth_fom: 10,
606             aoa_destination_elevation: 11,
607             aoa_destination_elevation_fom: 12,
608             slot_index: 0,
609             rssi: u8::MAX,
610         };
611         let short_two_way_session_info_ntf = uwb_uci_packets::ShortMacTwoWaySessionInfoNtfBuilder {
612             sequence_number: 0x10,
613             session_token: 0x11,
614             rcr_indicator: 0x12,
615             current_ranging_interval: 0x13,
616             two_way_ranging_measurements: vec![short_measurement.clone()],
617             vendor_data: vec![0x02, 0x01],
618         }
619         .build();
620         let raw_ranging_data =
621             short_two_way_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
622         let range_notification =
623             uwb_uci_packets::SessionInfoNtf::try_from(short_two_way_session_info_ntf).unwrap();
624         let session_notification = SessionNotification::try_from(range_notification).unwrap();
625         let uci_notification_from_short_two_way_session_info_ntf =
626             UciNotification::Session(session_notification);
627         assert_eq!(
628             uci_notification_from_short_two_way_session_info_ntf,
629             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
630                 sequence_number: 0x10,
631                 session_token: 0x11,
632                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::TwoWay,
633                 current_ranging_interval_ms: 0x13,
634                 ranging_measurements: RangingMeasurements::ShortAddressTwoWay(vec![
635                     short_measurement
636                 ]),
637                 rcr_indicator: 0x12,
638                 raw_ranging_data,
639             }))
640         );
641     }
642 
643     #[test]
test_session_notification_casting_from_extended_mac_owr_aoa_session_info_ntf()644     fn test_session_notification_casting_from_extended_mac_owr_aoa_session_info_ntf() {
645         let extended_measurement = uwb_uci_packets::ExtendedAddressOwrAoaRangingMeasurement {
646             mac_address: 0x1234_5678_90ab,
647             status: StatusCode::UciStatusOk,
648             nlos: 0,
649             frame_sequence_number: 1,
650             block_index: 1,
651             aoa_azimuth: 5,
652             aoa_azimuth_fom: 6,
653             aoa_elevation: 7,
654             aoa_elevation_fom: 8,
655         };
656         let extended_owr_aoa_session_info_ntf =
657             uwb_uci_packets::ExtendedMacOwrAoaSessionInfoNtfBuilder {
658                 sequence_number: 0x10,
659                 session_token: 0x11,
660                 rcr_indicator: 0x12,
661                 current_ranging_interval: 0x13,
662                 owr_aoa_ranging_measurements: vec![extended_measurement.clone()],
663                 vendor_data: vec![],
664             }
665             .build();
666         let raw_ranging_data =
667             extended_owr_aoa_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
668         let range_notification =
669             uwb_uci_packets::SessionInfoNtf::try_from(extended_owr_aoa_session_info_ntf).unwrap();
670         let session_notification = SessionNotification::try_from(range_notification).unwrap();
671         let uci_notification_from_extended_owr_aoa_session_info_ntf =
672             UciNotification::Session(session_notification);
673         assert_eq!(
674             uci_notification_from_extended_owr_aoa_session_info_ntf,
675             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
676                 sequence_number: 0x10,
677                 session_token: 0x11,
678                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::OwrAoa,
679                 current_ranging_interval_ms: 0x13,
680                 ranging_measurements: RangingMeasurements::ExtendedAddressOwrAoa(
681                     extended_measurement
682                 ),
683                 rcr_indicator: 0x12,
684                 raw_ranging_data,
685             }))
686         );
687     }
688 
689     #[test]
test_session_notification_casting_from_short_mac_owr_aoa_session_info_ntf()690     fn test_session_notification_casting_from_short_mac_owr_aoa_session_info_ntf() {
691         let short_measurement = uwb_uci_packets::ShortAddressOwrAoaRangingMeasurement {
692             mac_address: 0x1234,
693             status: StatusCode::UciStatusOk,
694             nlos: 0,
695             frame_sequence_number: 1,
696             block_index: 1,
697             aoa_azimuth: 5,
698             aoa_azimuth_fom: 6,
699             aoa_elevation: 7,
700             aoa_elevation_fom: 8,
701         };
702         let short_owr_aoa_session_info_ntf = uwb_uci_packets::ShortMacOwrAoaSessionInfoNtfBuilder {
703             sequence_number: 0x10,
704             session_token: 0x11,
705             rcr_indicator: 0x12,
706             current_ranging_interval: 0x13,
707             owr_aoa_ranging_measurements: vec![short_measurement.clone()],
708             vendor_data: vec![],
709         }
710         .build();
711         let raw_ranging_data =
712             short_owr_aoa_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
713         let range_notification =
714             uwb_uci_packets::SessionInfoNtf::try_from(short_owr_aoa_session_info_ntf).unwrap();
715         let session_notification = SessionNotification::try_from(range_notification).unwrap();
716         let uci_notification_from_short_owr_aoa_session_info_ntf =
717             UciNotification::Session(session_notification);
718         assert_eq!(
719             uci_notification_from_short_owr_aoa_session_info_ntf,
720             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
721                 sequence_number: 0x10,
722                 session_token: 0x11,
723                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::OwrAoa,
724                 current_ranging_interval_ms: 0x13,
725                 ranging_measurements: RangingMeasurements::ShortAddressOwrAoa(short_measurement),
726                 rcr_indicator: 0x12,
727                 raw_ranging_data,
728             }))
729         );
730     }
731 
732     #[test]
test_session_notification_casting_from_session_status_ntf()733     fn test_session_notification_casting_from_session_status_ntf() {
734         let session_status_ntf = uwb_uci_packets::SessionStatusNtfBuilder {
735             session_token: 0x20,
736             session_state: uwb_uci_packets::SessionState::SessionStateActive,
737             reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
738                 .into(),
739         }
740         .build();
741         let session_notification_packet =
742             uwb_uci_packets::SessionConfigNotification::try_from(session_status_ntf).unwrap();
743         let session_notification =
744             SessionNotification::try_from(session_notification_packet).unwrap();
745         let uci_notification_from_session_status_ntf =
746             UciNotification::Session(session_notification);
747         assert_eq!(
748             uci_notification_from_session_status_ntf,
749             UciNotification::Session(SessionNotification::Status {
750                 session_token: 0x20,
751                 session_state: uwb_uci_packets::SessionState::SessionStateActive,
752                 reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
753                     .into(),
754             })
755         );
756     }
757 
758     #[test]
test_session_notification_casting_from_session_update_controller_multicast_list_ntf_packet()759     fn test_session_notification_casting_from_session_update_controller_multicast_list_ntf_packet()
760     {
761         let controlee_status = uwb_uci_packets::ControleeStatus {
762             mac_address: [0x0c, 0xa8],
763             subsession_id: 0x30,
764             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
765         };
766         let another_controlee_status = uwb_uci_packets::ControleeStatus {
767             mac_address: [0x0c, 0xa9],
768             subsession_id: 0x31,
769             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusErrorKeyFetchFail,
770         };
771         let session_update_controller_multicast_list_ntf =
772             uwb_uci_packets::SessionUpdateControllerMulticastListNtfBuilder {
773                 session_token: 0x32,
774                 remaining_multicast_list_size: 0x2,
775                 controlee_status: vec![controlee_status.clone(), another_controlee_status.clone()],
776             }
777             .build();
778         let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
779             session_update_controller_multicast_list_ntf,
780         )
781         .unwrap();
782         let session_notification =
783             SessionNotification::try_from(session_notification_packet).unwrap();
784         let uci_notification_from_session_update_controller_multicast_list_ntf =
785             UciNotification::Session(session_notification);
786         assert_eq!(
787             uci_notification_from_session_update_controller_multicast_list_ntf,
788             UciNotification::Session(SessionNotification::UpdateControllerMulticastList {
789                 session_token: 0x32,
790                 remaining_multicast_list_size: 0x2,
791                 status_list: vec![controlee_status, another_controlee_status],
792             })
793         );
794     }
795 
796     #[test]
797     #[allow(non_snake_case)] //override snake case for vendor_A
test_vendor_notification_casting()798     fn test_vendor_notification_casting() {
799         let vendor_9_empty_notification: uwb_uci_packets::UciNotification =
800             uwb_uci_packets::UciVendor_9_NotificationBuilder { opcode: 0x40, payload: None }
801                 .build()
802                 .into();
803         let vendor_A_nonempty_notification: uwb_uci_packets::UciNotification =
804             uwb_uci_packets::UciVendor_A_NotificationBuilder {
805                 opcode: 0x41,
806                 payload: Some(bytes::Bytes::from_static(b"Placeholder notification.")),
807             }
808             .build()
809             .into();
810         let uci_notification_from_vendor_9 =
811             UciNotification::try_from(vendor_9_empty_notification).unwrap();
812         let uci_notification_from_vendor_A =
813             UciNotification::try_from(vendor_A_nonempty_notification).unwrap();
814         assert_eq!(
815             uci_notification_from_vendor_9,
816             UciNotification::Vendor(RawUciMessage {
817                 gid: 0x9, // per enum GroupId in uci_packets.pdl
818                 oid: 0x40,
819                 payload: vec![],
820             })
821         );
822         assert_eq!(
823             uci_notification_from_vendor_A,
824             UciNotification::Vendor(RawUciMessage {
825                 gid: 0xa,
826                 oid: 0x41,
827                 payload: b"Placeholder notification.".to_owned().into(),
828             })
829         );
830     }
831 
832     #[test]
test_test_to_vendor_notification_casting()833     fn test_test_to_vendor_notification_casting() {
834         let test_notification: uwb_uci_packets::UciNotification =
835             uwb_uci_packets::TestNotificationBuilder { opcode: 0x22, payload: None }.build().into();
836         let test_uci_notification = UciNotification::try_from(test_notification).unwrap();
837         assert_eq!(
838             test_uci_notification,
839             UciNotification::Vendor(RawUciMessage {
840                 gid: 0x0d, // per enum Test GroupId in uci_packets.pdl
841                 oid: 0x22,
842                 payload: vec![],
843             })
844         );
845     }
846 }
847