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