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