• 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 pdl_runtime::Packet;
19 use uwb_uci_packets::{
20     parse_diagnostics_ntf, radar_bytes_per_sample_value, RadarDataRcv, RadarSweepDataRaw,
21     UCI_PACKET_HEADER_LEN, UCI_RADAR_SEQUENCE_NUMBER_LEN, UCI_RADAR_TIMESTAMP_LEN,
22     UCI_RADAR_VENDOR_DATA_LEN_LEN,
23 };
24 
25 use crate::error::{Error, Result};
26 use crate::params::fira_app_config_params::UwbAddress;
27 use crate::params::uci_packets::{
28     BitsPerSample, ControleeStatusV1, ControleeStatusV2, CreditAvailability, DataRcvStatusCode,
29     DataTransferNtfStatusCode, DataTransferPhaseConfigUpdateStatusCode, DeviceState,
30     ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
31     ExtendedAddressTwoWayRangingMeasurement, RadarDataType, RangingMeasurementType, RawUciMessage,
32     SessionId, SessionState, SessionToken, SessionUpdateControllerMulticastListNtfV1Payload,
33     SessionUpdateControllerMulticastListNtfV2Payload, ShortAddressDlTdoaRangingMeasurement,
34     ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode,
35     UCIMajorVersion,
36 };
37 
38 /// enum of all UCI notifications with structured fields.
39 #[derive(Debug, Clone, PartialEq)]
40 pub enum UciNotification {
41     /// CoreNotification equivalent.
42     Core(CoreNotification),
43     /// SessionNotification equivalent.
44     Session(SessionNotification),
45     /// UciVendor_X_Notification equivalent.
46     Vendor(RawUciMessage),
47 }
48 
49 /// UCI CoreNotification.
50 #[derive(Debug, Clone, PartialEq, Eq)]
51 pub enum CoreNotification {
52     /// DeviceStatusNtf equivalent.
53     DeviceStatus(DeviceState),
54     /// GenericErrorPacket equivalent.
55     GenericError(StatusCode),
56 }
57 
58 /// UCI SessionNotification.
59 #[derive(Debug, Clone, PartialEq)]
60 pub enum SessionNotification {
61     /// SessionStatusNtf equivalent.
62     Status {
63         /// SessionId : u32
64         session_id: SessionId,
65         /// SessionToken : u32
66         session_token: SessionToken,
67         /// uwb_uci_packets::SessionState.
68         session_state: SessionState,
69         /// uwb_uci_packets::Reasoncode.
70         reason_code: u8,
71     },
72     /// SessionUpdateControllerMulticastListNtfV1 equivalent.
73     UpdateControllerMulticastListV1 {
74         /// SessionToken : u32
75         session_token: SessionToken,
76         /// count of controlees: u8
77         remaining_multicast_list_size: usize,
78         /// list of controlees.
79         status_list: Vec<ControleeStatusV1>,
80     },
81     /// SessionUpdateControllerMulticastListNtfV2 equivalent.
82     UpdateControllerMulticastListV2 {
83         /// SessionToken : u32
84         session_token: SessionToken,
85         /// list of controlees.
86         status_list: Vec<ControleeStatusV2>,
87     },
88     /// (Short/Extended)Mac()SessionInfoNtf equivalent
89     SessionInfo(SessionRangeData),
90     /// DataCreditNtf equivalent.
91     DataCredit {
92         /// SessionToken : u32
93         session_token: SessionToken,
94         /// Credit Availability (for sending Data packets on UWB Session)
95         credit_availability: CreditAvailability,
96     },
97     /// DataTransferStatusNtf equivalent.
98     DataTransferStatus {
99         /// SessionToken : u32
100         session_token: SessionToken,
101         /// Sequence Number: u16
102         uci_sequence_number: u16,
103         /// Data Transfer Status Code
104         status: DataTransferNtfStatusCode,
105         /// Transmission count
106         tx_count: u8,
107     },
108     /// SessionDataTransferPhaseConfigNtf equivalent.
109     DataTransferPhaseConfig {
110         /// SessionToken : u32
111         session_token: SessionToken,
112         /// status
113         status: DataTransferPhaseConfigUpdateStatusCode,
114     },
115 }
116 
117 /// The session range data.
118 #[derive(Debug, Clone, PartialEq)]
119 pub struct SessionRangeData {
120     /// The sequence counter that starts with 0 when the session is started.
121     pub sequence_number: u32,
122 
123     /// The identifier of the session.
124     pub session_token: SessionToken,
125 
126     /// The current ranging interval setting in the unit of ms.
127     pub current_ranging_interval_ms: u32,
128 
129     /// The ranging measurement type.
130     pub ranging_measurement_type: RangingMeasurementType,
131 
132     /// The ranging measurement data.
133     pub ranging_measurements: RangingMeasurements,
134 
135     /// Indication that a RCR was sent/received in the current ranging round.
136     pub rcr_indicator: u8,
137 
138     /// The raw data of the notification message.
139     /// (b/243555651): It's not at FiRa specification, only used by vendor's extension.
140     pub raw_ranging_data: Vec<u8>,
141 }
142 
143 /// The ranging measurements.
144 #[derive(Debug, Clone, PartialEq)]
145 pub enum RangingMeasurements {
146     /// A Two-Way measurement with short address.
147     ShortAddressTwoWay(Vec<ShortAddressTwoWayRangingMeasurement>),
148 
149     /// A Two-Way measurement with extended address.
150     ExtendedAddressTwoWay(Vec<ExtendedAddressTwoWayRangingMeasurement>),
151 
152     /// Dl-TDoA measurement with short address.
153     ShortAddressDltdoa(Vec<ShortAddressDlTdoaRangingMeasurement>),
154 
155     /// Dl-TDoA measurement with extended address.
156     ExtendedAddressDltdoa(Vec<ExtendedAddressDlTdoaRangingMeasurement>),
157 
158     /// OWR for AoA measurement with short address.
159     ShortAddressOwrAoa(ShortAddressOwrAoaRangingMeasurement),
160 
161     /// OWR for AoA measurement with extended address.
162     ExtendedAddressOwrAoa(ExtendedAddressOwrAoaRangingMeasurement),
163 }
164 
165 /// The DATA_RCV packet
166 #[derive(Debug, Clone, std::cmp::PartialEq)]
167 pub struct DataRcvNotification {
168     /// The identifier of the session on which data transfer is happening.
169     pub session_token: SessionToken,
170 
171     /// The status of the data rx.
172     pub status: StatusCode,
173 
174     /// The sequence number of the data packet.
175     pub uci_sequence_num: u16,
176 
177     /// MacAddress of the sender of the application data.
178     pub source_address: UwbAddress,
179 
180     /// Application Payload Data
181     pub payload: Vec<u8>,
182 }
183 
184 /// The Radar sweep data struct
185 #[derive(Debug, Clone, std::cmp::PartialEq)]
186 pub struct RadarSweepData {
187     /// Counter of a single radar sweep per receiver. Starting
188     /// with 0 when the radar session is started.
189     pub sequence_number: u32,
190 
191     /// Timestamp when this radar sweep is received. Unit is
192     /// based on the PRF.
193     pub timestamp: u32,
194 
195     /// The radar vendor specific data.
196     pub vendor_specific_data: Vec<u8>,
197 
198     /// The radar sample data.
199     pub sample_data: Vec<u8>,
200 }
201 
202 /// The RADAR_DATA_RCV packet
203 #[derive(Debug, Clone, std::cmp::PartialEq)]
204 pub struct RadarDataRcvNotification {
205     /// The identifier of the session on which radar data transfer is happening.
206     pub session_token: SessionToken,
207 
208     /// The status of the radar data rx.
209     pub status: DataRcvStatusCode,
210 
211     /// The radar data type.
212     pub radar_data_type: RadarDataType,
213 
214     /// The number of sweeps.
215     pub number_of_sweeps: u8,
216 
217     /// Number of samples captured for each radar sweep.
218     pub samples_per_sweep: u8,
219 
220     /// Bits per sample in the radar sweep.
221     pub bits_per_sample: BitsPerSample,
222 
223     /// Defines the start offset with respect to 0cm distance. Unit in samples.
224     pub sweep_offset: u16,
225 
226     /// Radar sweep data.
227     pub sweep_data: Vec<RadarSweepData>,
228 }
229 
230 impl From<&uwb_uci_packets::RadarSweepDataRaw> for RadarSweepData {
from(evt: &uwb_uci_packets::RadarSweepDataRaw) -> Self231     fn from(evt: &uwb_uci_packets::RadarSweepDataRaw) -> Self {
232         Self {
233             sequence_number: evt.sequence_number,
234             timestamp: evt.timestamp,
235             vendor_specific_data: evt.vendor_specific_data.clone(),
236             sample_data: evt.sample_data.clone(),
237         }
238     }
239 }
240 
241 impl TryFrom<uwb_uci_packets::UciDataPacket> for RadarDataRcvNotification {
242     type Error = Error;
try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error>243     fn try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error> {
244         match evt.specialize() {
245             uwb_uci_packets::UciDataPacketChild::RadarDataRcv(evt) => parse_radar_data(evt),
246             _ => Err(Error::Unknown),
247         }
248     }
249 }
250 
parse_radar_data(data: RadarDataRcv) -> Result<RadarDataRcvNotification>251 fn parse_radar_data(data: RadarDataRcv) -> Result<RadarDataRcvNotification> {
252     let session_token = data.get_session_handle();
253     let status = data.get_status();
254     let radar_data_type = data.get_radar_data_type();
255     let number_of_sweeps = data.get_number_of_sweeps();
256     let samples_per_sweep = data.get_samples_per_sweep();
257     let bits_per_sample = data.get_bits_per_sample();
258     let bytes_per_sample_value = radar_bytes_per_sample_value(bits_per_sample);
259     let sweep_offset = data.get_sweep_offset();
260 
261     Ok(RadarDataRcvNotification {
262         session_token,
263         status,
264         radar_data_type,
265         number_of_sweeps,
266         samples_per_sweep,
267         bits_per_sample,
268         sweep_offset,
269         sweep_data: parse_radar_sweep_data(
270             number_of_sweeps,
271             samples_per_sweep,
272             bytes_per_sample_value,
273             data.get_sweep_data().clone(),
274         )?,
275     })
276 }
277 
parse_radar_sweep_data( number_of_sweeps: u8, samples_per_sweep: u8, bytes_per_sample_value: u8, data: Vec<u8>, ) -> Result<Vec<RadarSweepData>>278 fn parse_radar_sweep_data(
279     number_of_sweeps: u8,
280     samples_per_sweep: u8,
281     bytes_per_sample_value: u8,
282     data: Vec<u8>,
283 ) -> Result<Vec<RadarSweepData>> {
284     let mut radar_sweep_data: Vec<RadarSweepData> = Vec::new();
285     let mut sweep_data_cursor = 0;
286     for _ in 0..number_of_sweeps {
287         let vendor_data_len_index =
288             sweep_data_cursor + UCI_RADAR_SEQUENCE_NUMBER_LEN + UCI_RADAR_TIMESTAMP_LEN;
289         if data.len() <= vendor_data_len_index {
290             error!("Invalid radar sweep data length for vendor, data: {:?}", &data);
291             return Err(Error::BadParameters);
292         }
293         let vendor_specific_data_len = data[vendor_data_len_index] as usize;
294         let sweep_data_len = UCI_RADAR_SEQUENCE_NUMBER_LEN
295             + UCI_RADAR_TIMESTAMP_LEN
296             + UCI_RADAR_VENDOR_DATA_LEN_LEN
297             + vendor_specific_data_len
298             + samples_per_sweep as usize * bytes_per_sample_value as usize;
299         if data.len() < sweep_data_cursor + sweep_data_len {
300             error!("Invalid radar sweep data length, data: {:?}", &data);
301             return Err(Error::BadParameters);
302         }
303         radar_sweep_data.push(
304             (&RadarSweepDataRaw::parse(
305                 &data[sweep_data_cursor..sweep_data_cursor + sweep_data_len],
306             )
307             .map_err(|e| {
308                 error!("Failed to parse raw Radar Sweep Data {:?}, data: {:?}", e, &data);
309                 Error::BadParameters
310             })?)
311                 .into(),
312         );
313 
314         sweep_data_cursor += sweep_data_len;
315     }
316 
317     Ok(radar_sweep_data)
318 }
319 
320 impl TryFrom<uwb_uci_packets::UciDataPacket> for DataRcvNotification {
321     type Error = Error;
try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error>322     fn try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error> {
323         match evt.specialize() {
324             uwb_uci_packets::UciDataPacketChild::UciDataRcv(evt) => Ok(DataRcvNotification {
325                 session_token: evt.get_session_token(),
326                 status: evt.get_status(),
327                 uci_sequence_num: evt.get_uci_sequence_number(),
328                 source_address: UwbAddress::Extended(evt.get_source_mac_address().to_le_bytes()),
329                 payload: evt.get_data().to_vec(),
330             }),
331             _ => Err(Error::Unknown),
332         }
333     }
334 }
335 
336 impl UciNotification {
need_retry(&self) -> bool337     pub(crate) fn need_retry(&self) -> bool {
338         matches!(
339             self,
340             Self::Core(CoreNotification::GenericError(StatusCode::UciStatusCommandRetry))
341         )
342     }
343 }
344 
345 impl TryFrom<(uwb_uci_packets::UciNotification, UCIMajorVersion, bool)> for UciNotification {
346     type Error = Error;
try_from( pair: (uwb_uci_packets::UciNotification, UCIMajorVersion, bool), ) -> std::result::Result<Self, Self::Error>347     fn try_from(
348         pair: (uwb_uci_packets::UciNotification, UCIMajorVersion, bool),
349     ) -> std::result::Result<Self, Self::Error> {
350         use uwb_uci_packets::UciNotificationChild;
351         let evt = pair.0;
352         let uci_fira_major_ver = pair.1;
353         let is_multicast_list_ntf_v2_supported = pair.2;
354 
355         match evt.specialize() {
356             UciNotificationChild::CoreNotification(evt) => Ok(Self::Core(evt.try_into()?)),
357             UciNotificationChild::SessionConfigNotification(evt) => Ok(Self::Session(
358                 (evt, uci_fira_major_ver, is_multicast_list_ntf_v2_supported).try_into()?,
359             )),
360             UciNotificationChild::SessionControlNotification(evt) => {
361                 Ok(Self::Session(evt.try_into()?))
362             }
363             UciNotificationChild::AndroidNotification(evt) => evt.try_into(),
364             UciNotificationChild::UciVendor_9_Notification(evt) => vendor_notification(evt.into()),
365             UciNotificationChild::UciVendor_A_Notification(evt) => vendor_notification(evt.into()),
366             UciNotificationChild::UciVendor_B_Notification(evt) => vendor_notification(evt.into()),
367             UciNotificationChild::UciVendor_E_Notification(evt) => vendor_notification(evt.into()),
368             UciNotificationChild::UciVendor_F_Notification(evt) => vendor_notification(evt.into()),
369             UciNotificationChild::TestNotification(evt) => vendor_notification(evt.into()),
370             _ => {
371                 error!("Unknown UciNotification: {:?}", evt);
372                 Err(Error::Unknown)
373             }
374         }
375     }
376 }
377 
378 impl TryFrom<uwb_uci_packets::CoreNotification> for CoreNotification {
379     type Error = Error;
try_from(evt: uwb_uci_packets::CoreNotification) -> std::result::Result<Self, Self::Error>380     fn try_from(evt: uwb_uci_packets::CoreNotification) -> std::result::Result<Self, Self::Error> {
381         use uwb_uci_packets::CoreNotificationChild;
382         match evt.specialize() {
383             CoreNotificationChild::DeviceStatusNtf(evt) => {
384                 Ok(Self::DeviceStatus(evt.get_device_state()))
385             }
386             CoreNotificationChild::GenericError(evt) => Ok(Self::GenericError(evt.get_status())),
387             _ => {
388                 error!("Unknown CoreNotification: {:?}", evt);
389                 Err(Error::Unknown)
390             }
391         }
392     }
393 }
394 
395 impl TryFrom<(uwb_uci_packets::SessionConfigNotification, UCIMajorVersion, bool)>
396     for SessionNotification
397 {
398     type Error = Error;
try_from( pair: (uwb_uci_packets::SessionConfigNotification, UCIMajorVersion, bool), ) -> std::result::Result<Self, Self::Error>399     fn try_from(
400         pair: (uwb_uci_packets::SessionConfigNotification, UCIMajorVersion, bool),
401     ) -> std::result::Result<Self, Self::Error> {
402         use uwb_uci_packets::SessionConfigNotificationChild;
403         let evt = pair.0;
404         let uci_fira_major_ver = pair.1;
405         let is_multicast_list_ntf_v2_supported = pair.2;
406         match evt.specialize() {
407             SessionConfigNotificationChild::SessionStatusNtf(evt) => Ok(Self::Status {
408                 //no sessionId recieved, assign from sessionIdToToken map in uci_manager
409                 session_id: 0,
410                 session_token: evt.get_session_token(),
411                 session_state: evt.get_session_state(),
412                 reason_code: evt.get_reason_code(),
413             }),
414             SessionConfigNotificationChild::SessionUpdateControllerMulticastListNtf(evt)
415                 if uci_fira_major_ver == UCIMajorVersion::V1
416                     || !is_multicast_list_ntf_v2_supported =>
417             {
418                 let payload = evt.get_payload();
419                 let multicast_update_list_payload_v1 =
420                     SessionUpdateControllerMulticastListNtfV1Payload::parse(payload).map_err(
421                         |e| {
422                             error!(
423                                 "Failed to parse Multicast list ntf v1 {:?}, payload: {:?}",
424                                 e, &payload
425                             );
426                             Error::BadParameters
427                         },
428                     )?;
429                 Ok(Self::UpdateControllerMulticastListV1 {
430                     session_token: evt.get_session_token(),
431                     remaining_multicast_list_size: multicast_update_list_payload_v1
432                         .remaining_multicast_list_size
433                         as usize,
434                     status_list: multicast_update_list_payload_v1.controlee_status,
435                 })
436             }
437             SessionConfigNotificationChild::SessionUpdateControllerMulticastListNtf(evt)
438                 if uci_fira_major_ver == UCIMajorVersion::V2 =>
439             {
440                 let payload = evt.get_payload();
441                 let multicast_update_list_payload_v2 =
442                     SessionUpdateControllerMulticastListNtfV2Payload::parse(payload).map_err(
443                         |e| {
444                             error!(
445                                 "Failed to parse Multicast list ntf v2 {:?}, payload: {:?}",
446                                 e, &payload
447                             );
448                             Error::BadParameters
449                         },
450                     )?;
451                 Ok(Self::UpdateControllerMulticastListV2 {
452                     session_token: evt.get_session_token(),
453                     status_list: multicast_update_list_payload_v2.controlee_status,
454                 })
455             }
456             SessionConfigNotificationChild::SessionDataTransferPhaseConfigNtf(evt) => {
457                 Ok(Self::DataTransferPhaseConfig {
458                     session_token: evt.get_session_token(),
459                     status: evt.get_status(),
460                 })
461             }
462             _ => {
463                 error!("Unknown SessionConfigNotification: {:?}", evt);
464                 Err(Error::Unknown)
465             }
466         }
467     }
468 }
469 
470 impl TryFrom<uwb_uci_packets::SessionControlNotification> for SessionNotification {
471     type Error = Error;
try_from( evt: uwb_uci_packets::SessionControlNotification, ) -> std::result::Result<Self, Self::Error>472     fn try_from(
473         evt: uwb_uci_packets::SessionControlNotification,
474     ) -> std::result::Result<Self, Self::Error> {
475         use uwb_uci_packets::SessionControlNotificationChild;
476         match evt.specialize() {
477             SessionControlNotificationChild::SessionInfoNtf(evt) => evt.try_into(),
478             SessionControlNotificationChild::DataCreditNtf(evt) => Ok(Self::DataCredit {
479                 session_token: evt.get_session_token(),
480                 credit_availability: evt.get_credit_availability(),
481             }),
482             SessionControlNotificationChild::DataTransferStatusNtf(evt) => {
483                 Ok(Self::DataTransferStatus {
484                     session_token: evt.get_session_token(),
485                     uci_sequence_number: evt.get_uci_sequence_number(),
486                     status: evt.get_status(),
487                     tx_count: evt.get_tx_count(),
488                 })
489             }
490             _ => {
491                 error!("Unknown SessionControlNotification: {:?}", evt);
492                 Err(Error::Unknown)
493             }
494         }
495     }
496 }
497 
498 impl TryFrom<uwb_uci_packets::SessionInfoNtf> for SessionNotification {
499     type Error = Error;
try_from(evt: uwb_uci_packets::SessionInfoNtf) -> std::result::Result<Self, Self::Error>500     fn try_from(evt: uwb_uci_packets::SessionInfoNtf) -> std::result::Result<Self, Self::Error> {
501         let raw_ranging_data = evt.encode_to_bytes().unwrap()[UCI_PACKET_HEADER_LEN..].to_vec();
502         use uwb_uci_packets::SessionInfoNtfChild;
503         let ranging_measurements = match evt.specialize() {
504             SessionInfoNtfChild::ShortMacTwoWaySessionInfoNtf(evt) => {
505                 RangingMeasurements::ShortAddressTwoWay(
506                     evt.get_two_way_ranging_measurements().clone(),
507                 )
508             }
509             SessionInfoNtfChild::ExtendedMacTwoWaySessionInfoNtf(evt) => {
510                 RangingMeasurements::ExtendedAddressTwoWay(
511                     evt.get_two_way_ranging_measurements().clone(),
512                 )
513             }
514             SessionInfoNtfChild::ShortMacOwrAoaSessionInfoNtf(evt) => {
515                 if evt.get_owr_aoa_ranging_measurements().clone().len() == 1 {
516                     RangingMeasurements::ShortAddressOwrAoa(
517                         match evt.get_owr_aoa_ranging_measurements().clone().pop() {
518                             Some(r) => r,
519                             None => {
520                                 error!(
521                                     "Unable to parse ShortAddress OwrAoA measurement: {:?}",
522                                     evt
523                                 );
524                                 return Err(Error::BadParameters);
525                             }
526                         },
527                     )
528                 } else {
529                     error!("Wrong count of OwrAoA ranging measurements {:?}", evt);
530                     return Err(Error::BadParameters);
531                 }
532             }
533             SessionInfoNtfChild::ExtendedMacOwrAoaSessionInfoNtf(evt) => {
534                 if evt.get_owr_aoa_ranging_measurements().clone().len() == 1 {
535                     RangingMeasurements::ExtendedAddressOwrAoa(
536                         match evt.get_owr_aoa_ranging_measurements().clone().pop() {
537                             Some(r) => r,
538                             None => {
539                                 error!(
540                                     "Unable to parse ExtendedAddress OwrAoA measurement: {:?}",
541                                     evt
542                                 );
543                                 return Err(Error::BadParameters);
544                             }
545                         },
546                     )
547                 } else {
548                     error!("Wrong count of OwrAoA ranging measurements {:?}", evt);
549                     return Err(Error::BadParameters);
550                 }
551             }
552             SessionInfoNtfChild::ShortMacDlTDoASessionInfoNtf(evt) => {
553                 match ShortAddressDlTdoaRangingMeasurement::parse(
554                     evt.get_dl_tdoa_measurements(),
555                     evt.get_no_of_ranging_measurements(),
556                 ) {
557                     Some(v) => {
558                         if v.len() == evt.get_no_of_ranging_measurements().into() {
559                             RangingMeasurements::ShortAddressDltdoa(v)
560                         } else {
561                             error!("Wrong count of ranging measurements {:?}", evt);
562                             return Err(Error::BadParameters);
563                         }
564                     }
565                     None => return Err(Error::BadParameters),
566                 }
567             }
568             SessionInfoNtfChild::ExtendedMacDlTDoASessionInfoNtf(evt) => {
569                 match ExtendedAddressDlTdoaRangingMeasurement::parse(
570                     evt.get_dl_tdoa_measurements(),
571                     evt.get_no_of_ranging_measurements(),
572                 ) {
573                     Some(v) => {
574                         if v.len() == evt.get_no_of_ranging_measurements().into() {
575                             RangingMeasurements::ExtendedAddressDltdoa(v)
576                         } else {
577                             error!("Wrong count of ranging measurements {:?}", evt);
578                             return Err(Error::BadParameters);
579                         }
580                     }
581                     None => return Err(Error::BadParameters),
582                 }
583             }
584             _ => {
585                 error!("Unknown SessionInfoNtf: {:?}", evt);
586                 return Err(Error::Unknown);
587             }
588         };
589         Ok(Self::SessionInfo(SessionRangeData {
590             sequence_number: evt.get_sequence_number(),
591             session_token: evt.get_session_token(),
592             current_ranging_interval_ms: evt.get_current_ranging_interval(),
593             ranging_measurement_type: evt.get_ranging_measurement_type(),
594             ranging_measurements,
595             rcr_indicator: evt.get_rcr_indicator(),
596             raw_ranging_data,
597         }))
598     }
599 }
600 
601 impl TryFrom<uwb_uci_packets::AndroidNotification> for UciNotification {
602     type Error = Error;
try_from( evt: uwb_uci_packets::AndroidNotification, ) -> std::result::Result<Self, Self::Error>603     fn try_from(
604         evt: uwb_uci_packets::AndroidNotification,
605     ) -> std::result::Result<Self, Self::Error> {
606         use uwb_uci_packets::AndroidNotificationChild;
607 
608         // (b/241336806): Currently we don't process the diagnostic packet, just log it only.
609         if let AndroidNotificationChild::AndroidRangeDiagnosticsNtf(ntf) = evt.specialize() {
610             debug!("Received diagnostic packet: {:?}", parse_diagnostics_ntf(ntf));
611         } else {
612             error!("Received unknown AndroidNotification: {:?}", evt);
613         }
614         Err(Error::Unknown)
615     }
616 }
617 
vendor_notification(evt: uwb_uci_packets::UciNotification) -> Result<UciNotification>618 fn vendor_notification(evt: uwb_uci_packets::UciNotification) -> Result<UciNotification> {
619     Ok(UciNotification::Vendor(RawUciMessage {
620         gid: evt.get_group_id().into(),
621         oid: evt.get_opcode().into(),
622         payload: get_vendor_uci_payload(evt)?,
623     }))
624 }
625 
get_vendor_uci_payload(evt: uwb_uci_packets::UciNotification) -> Result<Vec<u8>>626 fn get_vendor_uci_payload(evt: uwb_uci_packets::UciNotification) -> Result<Vec<u8>> {
627     match evt.specialize() {
628         uwb_uci_packets::UciNotificationChild::UciVendor_9_Notification(evt) => {
629             match evt.specialize() {
630                 uwb_uci_packets::UciVendor_9_NotificationChild::Payload(payload) => {
631                     Ok(payload.to_vec())
632                 }
633                 uwb_uci_packets::UciVendor_9_NotificationChild::None => Ok(Vec::new()),
634             }
635         }
636         uwb_uci_packets::UciNotificationChild::UciVendor_A_Notification(evt) => {
637             match evt.specialize() {
638                 uwb_uci_packets::UciVendor_A_NotificationChild::Payload(payload) => {
639                     Ok(payload.to_vec())
640                 }
641                 uwb_uci_packets::UciVendor_A_NotificationChild::None => Ok(Vec::new()),
642             }
643         }
644         uwb_uci_packets::UciNotificationChild::UciVendor_B_Notification(evt) => {
645             match evt.specialize() {
646                 uwb_uci_packets::UciVendor_B_NotificationChild::Payload(payload) => {
647                     Ok(payload.to_vec())
648                 }
649                 uwb_uci_packets::UciVendor_B_NotificationChild::None => Ok(Vec::new()),
650             }
651         }
652         uwb_uci_packets::UciNotificationChild::UciVendor_E_Notification(evt) => {
653             match evt.specialize() {
654                 uwb_uci_packets::UciVendor_E_NotificationChild::Payload(payload) => {
655                     Ok(payload.to_vec())
656                 }
657                 uwb_uci_packets::UciVendor_E_NotificationChild::None => Ok(Vec::new()),
658             }
659         }
660         uwb_uci_packets::UciNotificationChild::UciVendor_F_Notification(evt) => {
661             match evt.specialize() {
662                 uwb_uci_packets::UciVendor_F_NotificationChild::Payload(payload) => {
663                     Ok(payload.to_vec())
664                 }
665                 uwb_uci_packets::UciVendor_F_NotificationChild::None => Ok(Vec::new()),
666             }
667         }
668         uwb_uci_packets::UciNotificationChild::TestNotification(evt) => match evt.specialize() {
669             uwb_uci_packets::TestNotificationChild::Payload(payload) => Ok(payload.to_vec()),
670             uwb_uci_packets::TestNotificationChild::None => Ok(Vec::new()),
671         },
672         _ => {
673             error!("Unknown UciVendor packet: {:?}", evt);
674             Err(Error::Unknown)
675         }
676     }
677 }
678 #[cfg(test)]
679 mod tests {
680     use super::*;
681     use bytes::{BufMut, BytesMut};
682 
683     #[test]
test_ranging_measurements_trait()684     fn test_ranging_measurements_trait() {
685         let empty_short_ranging_measurements = RangingMeasurements::ShortAddressTwoWay(vec![]);
686         assert_eq!(empty_short_ranging_measurements, empty_short_ranging_measurements);
687         let extended_ranging_measurements = RangingMeasurements::ExtendedAddressTwoWay(vec![
688             ExtendedAddressTwoWayRangingMeasurement {
689                 mac_address: 0x1234_5678_90ab,
690                 status: StatusCode::UciStatusOk,
691                 nlos: 0,
692                 distance: 4,
693                 aoa_azimuth: 5,
694                 aoa_azimuth_fom: 6,
695                 aoa_elevation: 7,
696                 aoa_elevation_fom: 8,
697                 aoa_destination_azimuth: 9,
698                 aoa_destination_azimuth_fom: 10,
699                 aoa_destination_elevation: 11,
700                 aoa_destination_elevation_fom: 12,
701                 slot_index: 0,
702                 rssi: u8::MAX,
703             },
704         ]);
705         assert_eq!(extended_ranging_measurements, extended_ranging_measurements.clone());
706         let empty_extended_ranging_measurements =
707             RangingMeasurements::ExtendedAddressTwoWay(vec![]);
708         assert_eq!(empty_short_ranging_measurements, empty_short_ranging_measurements);
709         //short and extended measurements are unequal even if both are empty:
710         assert_ne!(empty_short_ranging_measurements, empty_extended_ranging_measurements);
711     }
712     #[test]
test_core_notification_casting_from_generic_error()713     fn test_core_notification_casting_from_generic_error() {
714         let generic_error_packet = uwb_uci_packets::GenericErrorBuilder {
715             status: uwb_uci_packets::StatusCode::UciStatusRejected,
716         }
717         .build();
718         let core_notification =
719             uwb_uci_packets::CoreNotification::try_from(generic_error_packet).unwrap();
720         let core_notification = CoreNotification::try_from(core_notification).unwrap();
721         let uci_notification_from_generic_error = UciNotification::Core(core_notification);
722         assert_eq!(
723             uci_notification_from_generic_error,
724             UciNotification::Core(CoreNotification::GenericError(
725                 uwb_uci_packets::StatusCode::UciStatusRejected
726             ))
727         );
728     }
729     #[test]
test_core_notification_casting_from_device_status_ntf()730     fn test_core_notification_casting_from_device_status_ntf() {
731         let device_status_ntf_packet = uwb_uci_packets::DeviceStatusNtfBuilder {
732             device_state: uwb_uci_packets::DeviceState::DeviceStateActive,
733         }
734         .build();
735         let core_notification =
736             uwb_uci_packets::CoreNotification::try_from(device_status_ntf_packet).unwrap();
737         let uci_notification = CoreNotification::try_from(core_notification).unwrap();
738         let uci_notification_from_device_status_ntf = UciNotification::Core(uci_notification);
739         assert_eq!(
740             uci_notification_from_device_status_ntf,
741             UciNotification::Core(CoreNotification::DeviceStatus(
742                 uwb_uci_packets::DeviceState::DeviceStateActive
743             ))
744         );
745     }
746 
747     #[test]
test_session_notification_casting_from_extended_mac_two_way_session_info_ntf()748     fn test_session_notification_casting_from_extended_mac_two_way_session_info_ntf() {
749         let extended_measurement = uwb_uci_packets::ExtendedAddressTwoWayRangingMeasurement {
750             mac_address: 0x1234_5678_90ab,
751             status: StatusCode::UciStatusOk,
752             nlos: 0,
753             distance: 4,
754             aoa_azimuth: 5,
755             aoa_azimuth_fom: 6,
756             aoa_elevation: 7,
757             aoa_elevation_fom: 8,
758             aoa_destination_azimuth: 9,
759             aoa_destination_azimuth_fom: 10,
760             aoa_destination_elevation: 11,
761             aoa_destination_elevation_fom: 12,
762             slot_index: 0,
763             rssi: u8::MAX,
764         };
765         let extended_two_way_session_info_ntf =
766             uwb_uci_packets::ExtendedMacTwoWaySessionInfoNtfBuilder {
767                 sequence_number: 0x10,
768                 session_token: 0x11,
769                 rcr_indicator: 0x12,
770                 current_ranging_interval: 0x13,
771                 two_way_ranging_measurements: vec![extended_measurement.clone()],
772                 vendor_data: vec![],
773             }
774             .build();
775         let raw_ranging_data = extended_two_way_session_info_ntf.encode_to_bytes().unwrap()
776             [UCI_PACKET_HEADER_LEN..]
777             .to_vec();
778         let range_notification =
779             uwb_uci_packets::SessionInfoNtf::try_from(extended_two_way_session_info_ntf).unwrap();
780         let session_notification = SessionNotification::try_from(range_notification).unwrap();
781         let uci_notification_from_extended_two_way_session_info_ntf =
782             UciNotification::Session(session_notification);
783         assert_eq!(
784             uci_notification_from_extended_two_way_session_info_ntf,
785             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
786                 sequence_number: 0x10,
787                 session_token: 0x11,
788                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::TwoWay,
789                 current_ranging_interval_ms: 0x13,
790                 ranging_measurements: RangingMeasurements::ExtendedAddressTwoWay(vec![
791                     extended_measurement
792                 ]),
793                 rcr_indicator: 0x12,
794                 raw_ranging_data,
795             }))
796         );
797     }
798 
799     #[test]
test_session_notification_casting_from_short_mac_two_way_session_info_ntf()800     fn test_session_notification_casting_from_short_mac_two_way_session_info_ntf() {
801         let short_measurement = uwb_uci_packets::ShortAddressTwoWayRangingMeasurement {
802             mac_address: 0x1234,
803             status: StatusCode::UciStatusOk,
804             nlos: 0,
805             distance: 4,
806             aoa_azimuth: 5,
807             aoa_azimuth_fom: 6,
808             aoa_elevation: 7,
809             aoa_elevation_fom: 8,
810             aoa_destination_azimuth: 9,
811             aoa_destination_azimuth_fom: 10,
812             aoa_destination_elevation: 11,
813             aoa_destination_elevation_fom: 12,
814             slot_index: 0,
815             rssi: u8::MAX,
816         };
817         let short_two_way_session_info_ntf = uwb_uci_packets::ShortMacTwoWaySessionInfoNtfBuilder {
818             sequence_number: 0x10,
819             session_token: 0x11,
820             rcr_indicator: 0x12,
821             current_ranging_interval: 0x13,
822             two_way_ranging_measurements: vec![short_measurement.clone()],
823             vendor_data: vec![0x02, 0x01],
824         }
825         .build();
826         let raw_ranging_data = short_two_way_session_info_ntf.encode_to_bytes().unwrap()
827             [UCI_PACKET_HEADER_LEN..]
828             .to_vec();
829         let range_notification =
830             uwb_uci_packets::SessionInfoNtf::try_from(short_two_way_session_info_ntf).unwrap();
831         let session_notification = SessionNotification::try_from(range_notification).unwrap();
832         let uci_notification_from_short_two_way_session_info_ntf =
833             UciNotification::Session(session_notification);
834         assert_eq!(
835             uci_notification_from_short_two_way_session_info_ntf,
836             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
837                 sequence_number: 0x10,
838                 session_token: 0x11,
839                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::TwoWay,
840                 current_ranging_interval_ms: 0x13,
841                 ranging_measurements: RangingMeasurements::ShortAddressTwoWay(vec![
842                     short_measurement
843                 ]),
844                 rcr_indicator: 0x12,
845                 raw_ranging_data,
846             }))
847         );
848     }
849 
850     #[test]
test_session_notification_casting_from_extended_mac_owr_aoa_session_info_ntf()851     fn test_session_notification_casting_from_extended_mac_owr_aoa_session_info_ntf() {
852         let extended_measurement = uwb_uci_packets::ExtendedAddressOwrAoaRangingMeasurement {
853             mac_address: 0x1234_5678_90ab,
854             status: StatusCode::UciStatusOk,
855             nlos: 0,
856             frame_sequence_number: 1,
857             block_index: 1,
858             aoa_azimuth: 5,
859             aoa_azimuth_fom: 6,
860             aoa_elevation: 7,
861             aoa_elevation_fom: 8,
862         };
863         let extended_owr_aoa_session_info_ntf =
864             uwb_uci_packets::ExtendedMacOwrAoaSessionInfoNtfBuilder {
865                 sequence_number: 0x10,
866                 session_token: 0x11,
867                 rcr_indicator: 0x12,
868                 current_ranging_interval: 0x13,
869                 owr_aoa_ranging_measurements: vec![extended_measurement.clone()],
870                 vendor_data: vec![],
871             }
872             .build();
873         let raw_ranging_data = extended_owr_aoa_session_info_ntf.encode_to_bytes().unwrap()
874             [UCI_PACKET_HEADER_LEN..]
875             .to_vec();
876         let range_notification =
877             uwb_uci_packets::SessionInfoNtf::try_from(extended_owr_aoa_session_info_ntf).unwrap();
878         let session_notification = SessionNotification::try_from(range_notification).unwrap();
879         let uci_notification_from_extended_owr_aoa_session_info_ntf =
880             UciNotification::Session(session_notification);
881         assert_eq!(
882             uci_notification_from_extended_owr_aoa_session_info_ntf,
883             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
884                 sequence_number: 0x10,
885                 session_token: 0x11,
886                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::OwrAoa,
887                 current_ranging_interval_ms: 0x13,
888                 ranging_measurements: RangingMeasurements::ExtendedAddressOwrAoa(
889                     extended_measurement
890                 ),
891                 rcr_indicator: 0x12,
892                 raw_ranging_data,
893             }))
894         );
895     }
896 
897     #[test]
test_session_notification_casting_from_short_mac_owr_aoa_session_info_ntf()898     fn test_session_notification_casting_from_short_mac_owr_aoa_session_info_ntf() {
899         let short_measurement = uwb_uci_packets::ShortAddressOwrAoaRangingMeasurement {
900             mac_address: 0x1234,
901             status: StatusCode::UciStatusOk,
902             nlos: 0,
903             frame_sequence_number: 1,
904             block_index: 1,
905             aoa_azimuth: 5,
906             aoa_azimuth_fom: 6,
907             aoa_elevation: 7,
908             aoa_elevation_fom: 8,
909         };
910         let short_owr_aoa_session_info_ntf = uwb_uci_packets::ShortMacOwrAoaSessionInfoNtfBuilder {
911             sequence_number: 0x10,
912             session_token: 0x11,
913             rcr_indicator: 0x12,
914             current_ranging_interval: 0x13,
915             owr_aoa_ranging_measurements: vec![short_measurement.clone()],
916             vendor_data: vec![],
917         }
918         .build();
919         let raw_ranging_data = short_owr_aoa_session_info_ntf.encode_to_bytes().unwrap()
920             [UCI_PACKET_HEADER_LEN..]
921             .to_vec();
922         let range_notification =
923             uwb_uci_packets::SessionInfoNtf::try_from(short_owr_aoa_session_info_ntf).unwrap();
924         let session_notification = SessionNotification::try_from(range_notification).unwrap();
925         let uci_notification_from_short_owr_aoa_session_info_ntf =
926             UciNotification::Session(session_notification);
927         assert_eq!(
928             uci_notification_from_short_owr_aoa_session_info_ntf,
929             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
930                 sequence_number: 0x10,
931                 session_token: 0x11,
932                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::OwrAoa,
933                 current_ranging_interval_ms: 0x13,
934                 ranging_measurements: RangingMeasurements::ShortAddressOwrAoa(short_measurement),
935                 rcr_indicator: 0x12,
936                 raw_ranging_data,
937             }))
938         );
939     }
940 
941     #[test]
test_session_notification_casting_from_session_status_ntf()942     fn test_session_notification_casting_from_session_status_ntf() {
943         let session_status_ntf = uwb_uci_packets::SessionStatusNtfBuilder {
944             session_token: 0x20,
945             session_state: uwb_uci_packets::SessionState::SessionStateActive,
946             reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
947                 .into(),
948         }
949         .build();
950         let session_notification_packet =
951             uwb_uci_packets::SessionConfigNotification::try_from(session_status_ntf).unwrap();
952         let uci_fira_major_version = UCIMajorVersion::V1;
953         let session_notification = SessionNotification::try_from((
954             session_notification_packet,
955             uci_fira_major_version,
956             false,
957         ))
958         .unwrap();
959         let uci_notification_from_session_status_ntf =
960             UciNotification::Session(session_notification);
961         assert_eq!(
962             uci_notification_from_session_status_ntf,
963             UciNotification::Session(SessionNotification::Status {
964                 session_id: 0x0,
965                 session_token: 0x20,
966                 session_state: uwb_uci_packets::SessionState::SessionStateActive,
967                 reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
968                     .into(),
969             })
970         );
971     }
972 
write_multicast_ntf_v1_payload( payload: &SessionUpdateControllerMulticastListNtfV1Payload, buffer: &mut BytesMut, )973     fn write_multicast_ntf_v1_payload(
974         payload: &SessionUpdateControllerMulticastListNtfV1Payload,
975         buffer: &mut BytesMut,
976     ) {
977         buffer.put_u8(payload.remaining_multicast_list_size);
978         buffer.put_u8(payload.controlee_status.len() as u8);
979         for elem in &payload.controlee_status {
980             write_v1_controlee_status(elem, buffer);
981         }
982     }
983 
write_v1_controlee_status(status: &ControleeStatusV1, buffer: &mut BytesMut)984     fn write_v1_controlee_status(status: &ControleeStatusV1, buffer: &mut BytesMut) {
985         for elem in &status.mac_address {
986             buffer.put_u8(*elem);
987         }
988         buffer.put_u32_le(status.subsession_id);
989         buffer.put_u8(u8::from(status.status));
990     }
991 
write_multicast_ntf_v2_payload( payload: &SessionUpdateControllerMulticastListNtfV2Payload, buffer: &mut BytesMut, )992     fn write_multicast_ntf_v2_payload(
993         payload: &SessionUpdateControllerMulticastListNtfV2Payload,
994         buffer: &mut BytesMut,
995     ) {
996         buffer.put_u8(payload.controlee_status.len() as u8);
997         for elem in &payload.controlee_status {
998             write_v2_controlee_status(elem, buffer);
999         }
1000     }
1001 
write_v2_controlee_status(status: &ControleeStatusV2, buffer: &mut BytesMut)1002     fn write_v2_controlee_status(status: &ControleeStatusV2, buffer: &mut BytesMut) {
1003         for elem in &status.mac_address {
1004             buffer.put_u8(*elem);
1005         }
1006         buffer.put_u8(u8::from(status.status));
1007     }
1008 
1009     #[test]
test_session_notification_casting_from_session_update_controller_multicast_list_ntf_v1_packet( )1010     fn test_session_notification_casting_from_session_update_controller_multicast_list_ntf_v1_packet(
1011     ) {
1012         let controlee_status_v1 = uwb_uci_packets::ControleeStatusV1 {
1013             mac_address: [0x0c, 0xa8],
1014             subsession_id: 0x30,
1015             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
1016         };
1017         let another_controlee_status_v1 = uwb_uci_packets::ControleeStatusV1 {
1018             mac_address: [0x0c, 0xa9],
1019             subsession_id: 0x31,
1020             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusErrorKeyFetchFail,
1021         };
1022         let payload = uwb_uci_packets::SessionUpdateControllerMulticastListNtfV1Payload {
1023             remaining_multicast_list_size: 0x2,
1024             controlee_status: vec![
1025                 controlee_status_v1.clone(),
1026                 another_controlee_status_v1.clone(),
1027             ],
1028         };
1029         let mut buf = BytesMut::new();
1030         write_multicast_ntf_v1_payload(&payload, &mut buf);
1031         let session_update_controller_multicast_list_ntf_v1 =
1032             uwb_uci_packets::SessionUpdateControllerMulticastListNtfBuilder {
1033                 session_token: 0x32,
1034                 payload: Some(buf.freeze()),
1035             }
1036             .build();
1037         let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
1038             session_update_controller_multicast_list_ntf_v1,
1039         )
1040         .unwrap();
1041         let uci_fira_major_version = UCIMajorVersion::V1;
1042         let session_notification = SessionNotification::try_from((
1043             session_notification_packet,
1044             uci_fira_major_version,
1045             false,
1046         ))
1047         .unwrap();
1048         let uci_notification_from_session_update_controller_multicast_list_ntf =
1049             UciNotification::Session(session_notification);
1050         assert_eq!(
1051             uci_notification_from_session_update_controller_multicast_list_ntf,
1052             UciNotification::Session(SessionNotification::UpdateControllerMulticastListV1 {
1053                 session_token: 0x32,
1054                 remaining_multicast_list_size: 0x2,
1055                 status_list: vec![controlee_status_v1, another_controlee_status_v1],
1056             })
1057         );
1058     }
1059 
1060     #[test]
test_cast_failed_from_session_update_controller_multicast_list_ntf_v1_packet_v2_payload()1061     fn test_cast_failed_from_session_update_controller_multicast_list_ntf_v1_packet_v2_payload() {
1062         let controlee_status_v2 = uwb_uci_packets::ControleeStatusV2 {
1063             mac_address: [0x0c, 0xa8],
1064             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
1065         };
1066         let another_controlee_status_v2 = uwb_uci_packets::ControleeStatusV2 {
1067             mac_address: [0x0c, 0xa9],
1068             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusErrorKeyFetchFail,
1069         };
1070         let payload = uwb_uci_packets::SessionUpdateControllerMulticastListNtfV2Payload {
1071             controlee_status: vec![controlee_status_v2, another_controlee_status_v2],
1072         };
1073         let mut buf = BytesMut::new();
1074         write_multicast_ntf_v2_payload(&payload, &mut buf);
1075         let session_update_controller_multicast_list_ntf_v1 =
1076             uwb_uci_packets::SessionUpdateControllerMulticastListNtfBuilder {
1077                 session_token: 0x32,
1078                 payload: Some(buf.freeze()),
1079             }
1080             .build();
1081         let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
1082             session_update_controller_multicast_list_ntf_v1,
1083         )
1084         .unwrap();
1085         let uci_fira_major_version = UCIMajorVersion::V1;
1086         let session_notification = SessionNotification::try_from((
1087             session_notification_packet,
1088             uci_fira_major_version,
1089             false,
1090         ));
1091         assert_eq!(session_notification, Err(Error::BadParameters));
1092     }
1093 
1094     #[test]
test_cast_failed_from_session_update_controller_multicast_list_ntf_v2_packet_v1_payload()1095     fn test_cast_failed_from_session_update_controller_multicast_list_ntf_v2_packet_v1_payload() {
1096         let controlee_status_v1 = uwb_uci_packets::ControleeStatusV1 {
1097             mac_address: [0x0c, 0xa8],
1098             subsession_id: 0x30,
1099             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
1100         };
1101         let payload = uwb_uci_packets::SessionUpdateControllerMulticastListNtfV1Payload {
1102             remaining_multicast_list_size: 0x4,
1103             controlee_status: vec![controlee_status_v1],
1104         };
1105         let mut buf = BytesMut::new();
1106         write_multicast_ntf_v1_payload(&payload, &mut buf);
1107         let session_update_controller_multicast_list_ntf_v1 =
1108             uwb_uci_packets::SessionUpdateControllerMulticastListNtfBuilder {
1109                 session_token: 0x32,
1110                 payload: Some(buf.freeze()),
1111             }
1112             .build();
1113         let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
1114             session_update_controller_multicast_list_ntf_v1,
1115         )
1116         .unwrap();
1117         let uci_fira_major_version = UCIMajorVersion::V2;
1118         let session_notification = SessionNotification::try_from((
1119             session_notification_packet,
1120             uci_fira_major_version,
1121             true,
1122         ));
1123         assert_eq!(session_notification, Err(Error::BadParameters));
1124     }
1125 
1126     #[test]
test_session_notification_casting_from_session_update_controller_multicast_list_ntf_v2_packet( )1127     fn test_session_notification_casting_from_session_update_controller_multicast_list_ntf_v2_packet(
1128     ) {
1129         let controlee_status_v2 = uwb_uci_packets::ControleeStatusV2 {
1130             mac_address: [0x0c, 0xa8],
1131             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
1132         };
1133         let another_controlee_status_v2 = uwb_uci_packets::ControleeStatusV2 {
1134             mac_address: [0x0c, 0xa9],
1135             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusErrorKeyFetchFail,
1136         };
1137         let payload = uwb_uci_packets::SessionUpdateControllerMulticastListNtfV2Payload {
1138             controlee_status: vec![
1139                 controlee_status_v2.clone(),
1140                 another_controlee_status_v2.clone(),
1141             ],
1142         };
1143         let mut buf = BytesMut::new();
1144         write_multicast_ntf_v2_payload(&payload, &mut buf);
1145         let session_update_controller_multicast_list_ntf_v2 =
1146             uwb_uci_packets::SessionUpdateControllerMulticastListNtfBuilder {
1147                 session_token: 0x32,
1148                 payload: Some(buf.freeze()),
1149             }
1150             .build();
1151         let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
1152             session_update_controller_multicast_list_ntf_v2,
1153         )
1154         .unwrap();
1155         let uci_fira_major_version = UCIMajorVersion::V2;
1156         let session_notification = SessionNotification::try_from((
1157             session_notification_packet,
1158             uci_fira_major_version,
1159             true,
1160         ))
1161         .unwrap();
1162         let uci_notification_from_session_update_controller_multicast_list_ntf =
1163             UciNotification::Session(session_notification);
1164         assert_eq!(
1165             uci_notification_from_session_update_controller_multicast_list_ntf,
1166             UciNotification::Session(SessionNotification::UpdateControllerMulticastListV2 {
1167                 session_token: 0x32,
1168                 status_list: vec![controlee_status_v2, another_controlee_status_v2],
1169             })
1170         );
1171     }
1172 
1173     #[test]
test_session_notification_casting_from_session_data_transfer_phase_config_ntf_packet()1174     fn test_session_notification_casting_from_session_data_transfer_phase_config_ntf_packet() {
1175         let session_data_transfer_phase_config_ntf =
1176             uwb_uci_packets::SessionDataTransferPhaseConfigNtfBuilder {
1177                 session_token: 0x32,
1178                 status: DataTransferPhaseConfigUpdateStatusCode::UciDtpcmConfigSuccessStatusOk,
1179             }
1180             .build();
1181         let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
1182             session_data_transfer_phase_config_ntf,
1183         )
1184         .unwrap();
1185         let uci_fira_major_version = UCIMajorVersion::V1;
1186         let session_notification = SessionNotification::try_from((
1187             session_notification_packet,
1188             uci_fira_major_version,
1189             false,
1190         ))
1191         .unwrap();
1192         let uci_notification_from_session_data_transfer_phase_config_ntf =
1193             UciNotification::Session(session_notification);
1194         assert_eq!(
1195             uci_notification_from_session_data_transfer_phase_config_ntf,
1196             UciNotification::Session(SessionNotification::DataTransferPhaseConfig {
1197                 session_token: 0x32,
1198                 status: DataTransferPhaseConfigUpdateStatusCode::UciDtpcmConfigSuccessStatusOk
1199             })
1200         );
1201     }
1202 
1203     #[test]
test_session_notification_casting_from_short_mac_dl_tdoa_session_info_ntf_packet()1204     fn test_session_notification_casting_from_short_mac_dl_tdoa_session_info_ntf_packet() {
1205         let dl_tdoa_measurements = vec![
1206             0x0a, 0x01, 0x33, 0x05, // 2(Mac address), Status, Message Type
1207             0x53, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
1208             0x07, 0x09, 0x0a, 0x01, // Round Index, NLoS, 2(AoA Azimuth)
1209             0x02, 0x05, 0x07, 0x09, // AoA Azimuth FOM, 2(AoA Elevation), AoA Elevation FOM
1210             0x0a, 0x01, 0x02, 0x05, // RSSI, 3(Tx Timestamp..)
1211             0x07, 0x09, 0x0a, 0x01, // 4(Tx Timestamp..)
1212             0x02, 0x05, 0x07, 0x09, // Tx Timestamp, 3(Rx Timestamp..)
1213             0x05, 0x07, 0x09, 0x0a, // 2(Rx Timestamp), 2(Anchor Cfo)
1214             0x01, 0x02, 0x05, 0x07, // 2(Cfo), 2(Initiator Reply Time..)
1215             0x09, 0x05, 0x07, 0x09, // 2(Initiator Reply Time), 2(Responder Reply Time..)
1216             0x0a, 0x01, 0x02, 0x05, // 2(Responder Reply Time), 2(Initiator-Responder ToF)
1217             0x07, 0x09, 0x07, 0x09, // 4(Anchor Location..)
1218             0x05, 0x07, 0x09, 0x0a, // 4(Anchor Location..)
1219             0x01, 0x02, 0x05, 0x07, // 2(Anchor Location..), 2(Active Ranging Rounds..)
1220             0x09, 0x0a, 0x01, 0x02, // 4(Active Ranging Rounds..)
1221             0x05, 0x07, 0x09, 0x05, // 4(Active Ranging Rounds)
1222         ];
1223         let short_mac_dl_tdoa_session_info_ntf =
1224             uwb_uci_packets::ShortMacDlTDoASessionInfoNtfBuilder {
1225                 current_ranging_interval: 0x13,
1226                 dl_tdoa_measurements: dl_tdoa_measurements.clone(),
1227                 no_of_ranging_measurements: 1,
1228                 rcr_indicator: 0x12,
1229                 sequence_number: 0x10,
1230                 session_token: 0x11,
1231             }
1232             .build();
1233         let raw_ranging_data = short_mac_dl_tdoa_session_info_ntf.encode_to_bytes().unwrap()
1234             [UCI_PACKET_HEADER_LEN..]
1235             .to_vec();
1236         let short_measurement =
1237             ShortAddressDlTdoaRangingMeasurement::parse(&dl_tdoa_measurements, 1).unwrap();
1238         let range_notification_packet =
1239             uwb_uci_packets::SessionInfoNtf::try_from(short_mac_dl_tdoa_session_info_ntf).unwrap();
1240         let session_notification =
1241             SessionNotification::try_from(range_notification_packet).unwrap();
1242         let uci_notification_from_short_mac_dl_tdoa_session_info_ntf =
1243             UciNotification::Session(session_notification);
1244         assert_eq!(
1245             uci_notification_from_short_mac_dl_tdoa_session_info_ntf,
1246             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
1247                 sequence_number: 0x10,
1248                 session_token: 0x11,
1249                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::DlTdoa,
1250                 current_ranging_interval_ms: 0x13,
1251                 ranging_measurements: RangingMeasurements::ShortAddressDltdoa(short_measurement),
1252                 rcr_indicator: 0x12,
1253                 raw_ranging_data,
1254             }))
1255         );
1256     }
1257 
1258     #[test]
test_session_notification_casting_from_extended_mac_dltdoa_session_info_ntf_packet()1259     fn test_session_notification_casting_from_extended_mac_dltdoa_session_info_ntf_packet() {
1260         let dl_tdoa_measurements = vec![
1261             // All Fields in Little Endian (LE)
1262             0x0a, 0x01, 0x33, 0x05, // 4(Mac address..)
1263             0x33, 0x05, 0x02, 0x05, // 4(Mac address)
1264             0x07, 0x09, 0x0a, 0x01, // Status, Message Type, 2(Message control),
1265             0x02, 0x05, 0x07, 0x09, // 2(Block Index), Round Index, NLoS,
1266             0x0a, 0x01, 0x02, 0x05, // 2(AoA Azimuth), AoA Azimuth FOM, 1(AoA Elevation..)
1267             0x07, 0x09, 0x0a, // 1(AoA Elevation), AoA Elevation FOM, RSSI,
1268             0x01, 0x02, 0x05, 0x07, // 4(Tx Timestamp..)
1269             0x09, 0x05, 0x07, 0x09, // 4(Tx Timestamp),
1270             0x0a, 0x01, 0x02, 0x05, // 4(Rx Timestamp..)
1271             0x07, 0x09, 0x05, 0x07, // 4(Rx Timestamp)
1272             0x09, 0x0a, 0x01, 0x02, // 2(Anchor Cfo), 2(Cfo),
1273             0x05, 0x07, 0x09, 0x05, // 4(Initiator Reply Time)
1274             0x07, 0x09, 0x0a, 0x01, // 4(Responder Reply Time),
1275             0x02, 0x05, 0x02, 0x05, // 2(Initiator-Responder ToF), 2(Active Ranging Rounds)
1276         ];
1277         let extended_mac_dl_tdoa_session_info_ntf =
1278             uwb_uci_packets::ExtendedMacDlTDoASessionInfoNtfBuilder {
1279                 current_ranging_interval: 0x13,
1280                 dl_tdoa_measurements: dl_tdoa_measurements.clone(),
1281                 no_of_ranging_measurements: 1,
1282                 rcr_indicator: 0x12,
1283                 sequence_number: 0x10,
1284                 session_token: 0x11,
1285             }
1286             .build();
1287         let raw_ranging_data = extended_mac_dl_tdoa_session_info_ntf.encode_to_bytes().unwrap()
1288             [UCI_PACKET_HEADER_LEN..]
1289             .to_vec();
1290         let short_measurement =
1291             ExtendedAddressDlTdoaRangingMeasurement::parse(&dl_tdoa_measurements, 1).unwrap();
1292         let range_notification_packet =
1293             uwb_uci_packets::SessionInfoNtf::try_from(extended_mac_dl_tdoa_session_info_ntf)
1294                 .unwrap();
1295         let session_notification =
1296             SessionNotification::try_from(range_notification_packet).unwrap();
1297         let uci_notification_from_extended_mac_dl_tdoa_session_info_ntf =
1298             UciNotification::Session(session_notification);
1299         assert_eq!(
1300             uci_notification_from_extended_mac_dl_tdoa_session_info_ntf,
1301             UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
1302                 sequence_number: 0x10,
1303                 session_token: 0x11,
1304                 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::DlTdoa,
1305                 current_ranging_interval_ms: 0x13,
1306                 ranging_measurements: RangingMeasurements::ExtendedAddressDltdoa(short_measurement),
1307                 rcr_indicator: 0x12,
1308                 raw_ranging_data,
1309             }))
1310         );
1311     }
1312 
1313     #[test]
1314     #[allow(non_snake_case)] //override snake case for vendor_A
test_vendor_notification_casting()1315     fn test_vendor_notification_casting() {
1316         let vendor_9_empty_notification: uwb_uci_packets::UciNotification =
1317             uwb_uci_packets::UciVendor_9_NotificationBuilder { opcode: 0x40, payload: None }
1318                 .build()
1319                 .into();
1320         let vendor_A_nonempty_notification: uwb_uci_packets::UciNotification =
1321             uwb_uci_packets::UciVendor_A_NotificationBuilder {
1322                 opcode: 0x41,
1323                 payload: Some(bytes::Bytes::from_static(b"Placeholder notification.")),
1324             }
1325             .build()
1326             .into();
1327         let vendor_B_nonempty_notification: uwb_uci_packets::UciNotification =
1328             uwb_uci_packets::UciVendor_B_NotificationBuilder {
1329                 opcode: 0x41,
1330                 payload: Some(bytes::Bytes::from_static(b"Placeholder notification.")),
1331             }
1332             .build()
1333             .into();
1334         let vendor_E_nonempty_notification: uwb_uci_packets::UciNotification =
1335             uwb_uci_packets::UciVendor_E_NotificationBuilder {
1336                 opcode: 0x41,
1337                 payload: Some(bytes::Bytes::from_static(b"Placeholder notification.")),
1338             }
1339             .build()
1340             .into();
1341         let vendor_F_nonempty_notification: uwb_uci_packets::UciNotification =
1342             uwb_uci_packets::UciVendor_F_NotificationBuilder {
1343                 opcode: 0x41,
1344                 payload: Some(bytes::Bytes::from_static(b"Placeholder notification.")),
1345             }
1346             .build()
1347             .into();
1348         let uci_fira_major_version = UCIMajorVersion::V1;
1349         let uci_notification_from_vendor_9 = UciNotification::try_from((
1350             vendor_9_empty_notification,
1351             uci_fira_major_version.clone(),
1352             false,
1353         ))
1354         .unwrap();
1355         let uci_notification_from_vendor_A = UciNotification::try_from((
1356             vendor_A_nonempty_notification,
1357             uci_fira_major_version.clone(),
1358             false,
1359         ))
1360         .unwrap();
1361         let uci_notification_from_vendor_B = UciNotification::try_from((
1362             vendor_B_nonempty_notification,
1363             uci_fira_major_version.clone(),
1364             false,
1365         ))
1366         .unwrap();
1367         let uci_notification_from_vendor_E = UciNotification::try_from((
1368             vendor_E_nonempty_notification,
1369             uci_fira_major_version.clone(),
1370             false,
1371         ))
1372         .unwrap();
1373         let uci_notification_from_vendor_F = UciNotification::try_from((
1374             vendor_F_nonempty_notification,
1375             uci_fira_major_version,
1376             false,
1377         ))
1378         .unwrap();
1379         assert_eq!(
1380             uci_notification_from_vendor_9,
1381             UciNotification::Vendor(RawUciMessage {
1382                 gid: 0x9, // per enum GroupId in uci_packets.pdl
1383                 oid: 0x40,
1384                 payload: vec![],
1385             })
1386         );
1387         assert_eq!(
1388             uci_notification_from_vendor_A,
1389             UciNotification::Vendor(RawUciMessage {
1390                 gid: 0xa,
1391                 oid: 0x41,
1392                 payload: b"Placeholder notification.".to_owned().into(),
1393             })
1394         );
1395         assert_eq!(
1396             uci_notification_from_vendor_B,
1397             UciNotification::Vendor(RawUciMessage {
1398                 gid: 0xb,
1399                 oid: 0x41,
1400                 payload: b"Placeholder notification.".to_owned().into(),
1401             })
1402         );
1403         assert_eq!(
1404             uci_notification_from_vendor_E,
1405             UciNotification::Vendor(RawUciMessage {
1406                 gid: 0xe,
1407                 oid: 0x41,
1408                 payload: b"Placeholder notification.".to_owned().into(),
1409             })
1410         );
1411         assert_eq!(
1412             uci_notification_from_vendor_F,
1413             UciNotification::Vendor(RawUciMessage {
1414                 gid: 0xf,
1415                 oid: 0x41,
1416                 payload: b"Placeholder notification.".to_owned().into(),
1417             })
1418         );
1419     }
1420 
1421     #[test]
test_test_to_vendor_notification_casting()1422     fn test_test_to_vendor_notification_casting() {
1423         let test_notification: uwb_uci_packets::UciNotification =
1424             uwb_uci_packets::TestNotificationBuilder { opcode: 0x22, payload: None }.build().into();
1425         let uci_fira_major_version = UCIMajorVersion::V1;
1426         let test_uci_notification =
1427             UciNotification::try_from((test_notification, uci_fira_major_version, false)).unwrap();
1428         assert_eq!(
1429             test_uci_notification,
1430             UciNotification::Vendor(RawUciMessage {
1431                 gid: 0x0d, // per enum Test GroupId in uci_packets.pdl
1432                 oid: 0x22,
1433                 payload: vec![],
1434             })
1435         );
1436     }
1437 }
1438