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