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