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 uwb_uci_packets::{parse_diagnostics_ntf, Packet, UCI_PACKET_HEADER_LEN};
19
20 use crate::error::{Error, Result};
21 use crate::params::fira_app_config_params::UwbAddress;
22 use crate::params::uci_packets::{
23 ControleeStatus, CreditAvailability, DataRcvStatusCode, DataTransferNtfStatusCode, DeviceState,
24 ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
25 ExtendedAddressTwoWayRangingMeasurement, FiraComponent, RangingMeasurementType, RawUciMessage,
26 SessionState, SessionToken, ShortAddressDlTdoaRangingMeasurement,
27 ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode,
28 };
29
30 /// enum of all UCI notifications with structured fields.
31 #[derive(Debug, Clone, PartialEq)]
32 pub enum UciNotification {
33 /// CoreNotification equivalent.
34 Core(CoreNotification),
35 /// SessionNotification equivalent.
36 Session(SessionNotification),
37 /// UciVendor_X_Notification equivalent.
38 Vendor(RawUciMessage),
39 }
40
41 /// UCI CoreNotification.
42 #[derive(Debug, Clone, PartialEq, Eq)]
43 pub enum CoreNotification {
44 /// DeviceStatusNtf equivalent.
45 DeviceStatus(DeviceState),
46 /// GenericErrorPacket equivalent.
47 GenericError(StatusCode),
48 }
49
50 /// UCI SessionNotification.
51 #[derive(Debug, Clone, PartialEq)]
52 pub enum SessionNotification {
53 /// SessionStatusNtf equivalent.
54 Status {
55 /// SessionToken : u32
56 session_token: SessionToken,
57 /// uwb_uci_packets::SessionState.
58 session_state: SessionState,
59 /// uwb_uci_packets::Reasoncode.
60 reason_code: u8,
61 },
62 /// SessionUpdateControllerMulticastListNtf equivalent.
63 UpdateControllerMulticastList {
64 /// SessionToken : u32
65 session_token: SessionToken,
66 /// count of controlees: u8
67 remaining_multicast_list_size: usize,
68 /// list of controlees.
69 status_list: Vec<ControleeStatus>,
70 },
71 /// (Short/Extended)Mac()SessionInfoNtf equivalent
72 SessionInfo(SessionRangeData),
73 /// DataCreditNtf equivalent.
74 DataCredit {
75 /// SessionToken : u32
76 session_token: SessionToken,
77 /// Credit Availability (for sending Data packets on UWB Session)
78 credit_availability: CreditAvailability,
79 },
80 /// DataTransferStatusNtf equivalent.
81 DataTransferStatus {
82 /// SessionToken : u32
83 session_token: SessionToken,
84 /// Sequence Number: u8
85 uci_sequence_number: u8,
86 /// Data Transfer Status Code
87 status: DataTransferNtfStatusCode,
88 },
89 }
90
91 /// The session range data.
92 #[derive(Debug, Clone, PartialEq)]
93 pub struct SessionRangeData {
94 /// The sequence counter that starts with 0 when the session is started.
95 pub sequence_number: u32,
96
97 /// The identifier of the session.
98 pub session_token: SessionToken,
99
100 /// The current ranging interval setting in the unit of ms.
101 pub current_ranging_interval_ms: u32,
102
103 /// The ranging measurement type.
104 pub ranging_measurement_type: RangingMeasurementType,
105
106 /// The ranging measurement data.
107 pub ranging_measurements: RangingMeasurements,
108
109 /// Indication that a RCR was sent/received in the current ranging round.
110 pub rcr_indicator: u8,
111
112 /// The raw data of the notification message.
113 /// (b/243555651): It's not at FiRa specification, only used by vendor's extension.
114 pub raw_ranging_data: Vec<u8>,
115 }
116
117 /// The ranging measurements.
118 #[derive(Debug, Clone, PartialEq)]
119 pub enum RangingMeasurements {
120 /// A Two-Way measurement with short address.
121 ShortAddressTwoWay(Vec<ShortAddressTwoWayRangingMeasurement>),
122
123 /// A Two-Way measurement with extended address.
124 ExtendedAddressTwoWay(Vec<ExtendedAddressTwoWayRangingMeasurement>),
125
126 /// Dl-TDoA measurement with short address.
127 ShortAddressDltdoa(Vec<ShortAddressDlTdoaRangingMeasurement>),
128
129 /// Dl-TDoA measurement with extended address.
130 ExtendedAddressDltdoa(Vec<ExtendedAddressDlTdoaRangingMeasurement>),
131
132 /// OWR for AoA measurement with short address.
133 ShortAddressOwrAoa(ShortAddressOwrAoaRangingMeasurement),
134
135 /// OWR for AoA measurement with extended address.
136 ExtendedAddressOwrAoa(ExtendedAddressOwrAoaRangingMeasurement),
137 }
138
139 /// The DATA_RCV packet
140 #[derive(Debug, Clone)]
141 pub struct DataRcvNotification {
142 /// The identifier of the session on which data transfer is happening.
143 pub session_token: SessionToken,
144
145 /// The status of the data rx.
146 pub status: DataRcvStatusCode,
147
148 /// The sequence number of the data packet.
149 pub uci_sequence_num: u32,
150
151 /// MacAddress of the sender of the application data.
152 pub source_address: UwbAddress,
153
154 /// Identifier for the source FiraComponent.
155 pub source_fira_component: FiraComponent,
156
157 /// Identifier for the destination FiraComponent.
158 pub dest_fira_component: FiraComponent,
159
160 /// Application Payload Data
161 pub payload: Vec<u8>,
162 }
163
164 impl TryFrom<uwb_uci_packets::UciDataPacket> for DataRcvNotification {
165 type Error = Error;
try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error>166 fn try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error> {
167 match evt.specialize() {
168 uwb_uci_packets::UciDataPacketChild::UciDataRcv(evt) => Ok(DataRcvNotification {
169 session_token: evt.get_session_token(),
170 status: evt.get_status(),
171 uci_sequence_num: evt.get_uci_sequence_number(),
172 source_address: UwbAddress::Extended(evt.get_source_mac_address().to_le_bytes()),
173 source_fira_component: evt.get_source_fira_component(),
174 dest_fira_component: evt.get_dest_fira_component(),
175 payload: evt.get_data().to_vec(),
176 }),
177 _ => {
178 error!("Unknown UciData packet: {:?}", evt);
179 Err(Error::Unknown)
180 }
181 }
182 }
183 }
184
185 impl UciNotification {
need_retry(&self) -> bool186 pub(crate) fn need_retry(&self) -> bool {
187 matches!(
188 self,
189 Self::Core(CoreNotification::GenericError(StatusCode::UciStatusCommandRetry))
190 )
191 }
192 }
193
194 impl TryFrom<uwb_uci_packets::UciNotification> for UciNotification {
195 type Error = Error;
try_from(evt: uwb_uci_packets::UciNotification) -> std::result::Result<Self, Self::Error>196 fn try_from(evt: uwb_uci_packets::UciNotification) -> std::result::Result<Self, Self::Error> {
197 use uwb_uci_packets::UciNotificationChild;
198 match evt.specialize() {
199 UciNotificationChild::CoreNotification(evt) => Ok(Self::Core(evt.try_into()?)),
200 UciNotificationChild::SessionConfigNotification(evt) => {
201 Ok(Self::Session(evt.try_into()?))
202 }
203 UciNotificationChild::SessionControlNotification(evt) => {
204 Ok(Self::Session(evt.try_into()?))
205 }
206 UciNotificationChild::AndroidNotification(evt) => evt.try_into(),
207 UciNotificationChild::UciVendor_9_Notification(evt) => vendor_notification(evt.into()),
208 UciNotificationChild::UciVendor_A_Notification(evt) => vendor_notification(evt.into()),
209 UciNotificationChild::UciVendor_B_Notification(evt) => vendor_notification(evt.into()),
210 UciNotificationChild::UciVendor_E_Notification(evt) => vendor_notification(evt.into()),
211 UciNotificationChild::UciVendor_F_Notification(evt) => vendor_notification(evt.into()),
212 UciNotificationChild::TestNotification(evt) => vendor_notification(evt.into()),
213 _ => {
214 error!("Unknown UciNotification: {:?}", evt);
215 Err(Error::Unknown)
216 }
217 }
218 }
219 }
220
221 impl TryFrom<uwb_uci_packets::CoreNotification> for CoreNotification {
222 type Error = Error;
try_from(evt: uwb_uci_packets::CoreNotification) -> std::result::Result<Self, Self::Error>223 fn try_from(evt: uwb_uci_packets::CoreNotification) -> std::result::Result<Self, Self::Error> {
224 use uwb_uci_packets::CoreNotificationChild;
225 match evt.specialize() {
226 CoreNotificationChild::DeviceStatusNtf(evt) => {
227 Ok(Self::DeviceStatus(evt.get_device_state()))
228 }
229 CoreNotificationChild::GenericError(evt) => Ok(Self::GenericError(evt.get_status())),
230 _ => {
231 error!("Unknown CoreNotification: {:?}", evt);
232 Err(Error::Unknown)
233 }
234 }
235 }
236 }
237
238 impl TryFrom<uwb_uci_packets::SessionConfigNotification> for SessionNotification {
239 type Error = Error;
try_from( evt: uwb_uci_packets::SessionConfigNotification, ) -> std::result::Result<Self, Self::Error>240 fn try_from(
241 evt: uwb_uci_packets::SessionConfigNotification,
242 ) -> std::result::Result<Self, Self::Error> {
243 use uwb_uci_packets::SessionConfigNotificationChild;
244 match evt.specialize() {
245 SessionConfigNotificationChild::SessionStatusNtf(evt) => Ok(Self::Status {
246 session_token: evt.get_session_token(),
247 session_state: evt.get_session_state(),
248 reason_code: evt.get_reason_code(),
249 }),
250 SessionConfigNotificationChild::SessionUpdateControllerMulticastListNtf(evt) => {
251 Ok(Self::UpdateControllerMulticastList {
252 session_token: evt.get_session_token(),
253 remaining_multicast_list_size: evt.get_remaining_multicast_list_size() as usize,
254 status_list: evt.get_controlee_status().clone(),
255 })
256 }
257 _ => {
258 error!("Unknown SessionConfigNotification: {:?}", evt);
259 Err(Error::Unknown)
260 }
261 }
262 }
263 }
264
265 impl TryFrom<uwb_uci_packets::SessionControlNotification> for SessionNotification {
266 type Error = Error;
try_from( evt: uwb_uci_packets::SessionControlNotification, ) -> std::result::Result<Self, Self::Error>267 fn try_from(
268 evt: uwb_uci_packets::SessionControlNotification,
269 ) -> std::result::Result<Self, Self::Error> {
270 use uwb_uci_packets::SessionControlNotificationChild;
271 match evt.specialize() {
272 SessionControlNotificationChild::SessionInfoNtf(evt) => evt.try_into(),
273 SessionControlNotificationChild::DataCreditNtf(evt) => Ok(Self::DataCredit {
274 session_token: evt.get_session_token(),
275 credit_availability: evt.get_credit_availability(),
276 }),
277 SessionControlNotificationChild::DataTransferStatusNtf(evt) => {
278 Ok(Self::DataTransferStatus {
279 session_token: evt.get_session_token(),
280 uci_sequence_number: evt.get_uci_sequence_number(),
281 status: evt.get_status(),
282 })
283 }
284 _ => {
285 error!("Unknown SessionControlNotification: {:?}", evt);
286 Err(Error::Unknown)
287 }
288 }
289 }
290 }
291
292 impl TryFrom<uwb_uci_packets::SessionInfoNtf> for SessionNotification {
293 type Error = Error;
try_from(evt: uwb_uci_packets::SessionInfoNtf) -> std::result::Result<Self, Self::Error>294 fn try_from(evt: uwb_uci_packets::SessionInfoNtf) -> std::result::Result<Self, Self::Error> {
295 let raw_ranging_data = evt.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
296 use uwb_uci_packets::SessionInfoNtfChild;
297 let ranging_measurements = match evt.specialize() {
298 SessionInfoNtfChild::ShortMacTwoWaySessionInfoNtf(evt) => {
299 RangingMeasurements::ShortAddressTwoWay(
300 evt.get_two_way_ranging_measurements().clone(),
301 )
302 }
303 SessionInfoNtfChild::ExtendedMacTwoWaySessionInfoNtf(evt) => {
304 RangingMeasurements::ExtendedAddressTwoWay(
305 evt.get_two_way_ranging_measurements().clone(),
306 )
307 }
308 SessionInfoNtfChild::ShortMacOwrAoaSessionInfoNtf(evt) => {
309 if evt.get_owr_aoa_ranging_measurements().clone().len() == 1 {
310 RangingMeasurements::ShortAddressOwrAoa(
311 match evt.get_owr_aoa_ranging_measurements().clone().pop() {
312 Some(r) => r,
313 None => {
314 error!(
315 "Unable to parse ShortAddress OwrAoA measurement: {:?}",
316 evt
317 );
318 return Err(Error::BadParameters);
319 }
320 },
321 )
322 } else {
323 error!("Wrong count of OwrAoA ranging measurements {:?}", evt);
324 return Err(Error::BadParameters);
325 }
326 }
327 SessionInfoNtfChild::ExtendedMacOwrAoaSessionInfoNtf(evt) => {
328 if evt.get_owr_aoa_ranging_measurements().clone().len() == 1 {
329 RangingMeasurements::ExtendedAddressOwrAoa(
330 match evt.get_owr_aoa_ranging_measurements().clone().pop() {
331 Some(r) => r,
332 None => {
333 error!(
334 "Unable to parse ExtendedAddress OwrAoA measurement: {:?}",
335 evt
336 );
337 return Err(Error::BadParameters);
338 }
339 },
340 )
341 } else {
342 error!("Wrong count of OwrAoA ranging measurements {:?}", evt);
343 return Err(Error::BadParameters);
344 }
345 }
346 SessionInfoNtfChild::ShortMacDlTDoASessionInfoNtf(evt) => {
347 match ShortAddressDlTdoaRangingMeasurement::parse(
348 evt.get_dl_tdoa_measurements(),
349 evt.get_no_of_ranging_measurements(),
350 ) {
351 Some(v) => {
352 if v.len() == evt.get_no_of_ranging_measurements().into() {
353 RangingMeasurements::ShortAddressDltdoa(v)
354 } else {
355 error!("Wrong count of ranging measurements {:?}", evt);
356 return Err(Error::BadParameters);
357 }
358 }
359 None => return Err(Error::BadParameters),
360 }
361 }
362 SessionInfoNtfChild::ExtendedMacDlTDoASessionInfoNtf(evt) => {
363 match ExtendedAddressDlTdoaRangingMeasurement::parse(
364 evt.get_dl_tdoa_measurements(),
365 evt.get_no_of_ranging_measurements(),
366 ) {
367 Some(v) => {
368 if v.len() == evt.get_no_of_ranging_measurements().into() {
369 RangingMeasurements::ExtendedAddressDltdoa(v)
370 } else {
371 error!("Wrong count of ranging measurements {:?}", evt);
372 return Err(Error::BadParameters);
373 }
374 }
375 None => return Err(Error::BadParameters),
376 }
377 }
378 _ => {
379 error!("Unknown SessionInfoNtf: {:?}", evt);
380 return Err(Error::Unknown);
381 }
382 };
383 Ok(Self::SessionInfo(SessionRangeData {
384 sequence_number: evt.get_sequence_number(),
385 session_token: evt.get_session_token(),
386 current_ranging_interval_ms: evt.get_current_ranging_interval(),
387 ranging_measurement_type: evt.get_ranging_measurement_type(),
388 ranging_measurements,
389 rcr_indicator: evt.get_rcr_indicator(),
390 raw_ranging_data,
391 }))
392 }
393 }
394
395 impl TryFrom<uwb_uci_packets::AndroidNotification> for UciNotification {
396 type Error = Error;
try_from( evt: uwb_uci_packets::AndroidNotification, ) -> std::result::Result<Self, Self::Error>397 fn try_from(
398 evt: uwb_uci_packets::AndroidNotification,
399 ) -> std::result::Result<Self, Self::Error> {
400 use uwb_uci_packets::AndroidNotificationChild;
401
402 // (b/241336806): Currently we don't process the diagnostic packet, just log it only.
403 if let AndroidNotificationChild::AndroidRangeDiagnosticsNtf(ntf) = evt.specialize() {
404 debug!("Received diagnostic packet: {:?}", parse_diagnostics_ntf(ntf));
405 } else {
406 error!("Received unknown AndroidNotification: {:?}", evt);
407 }
408 Err(Error::Unknown)
409 }
410 }
411
vendor_notification(evt: uwb_uci_packets::UciNotification) -> Result<UciNotification>412 fn vendor_notification(evt: uwb_uci_packets::UciNotification) -> Result<UciNotification> {
413 Ok(UciNotification::Vendor(RawUciMessage {
414 gid: evt.get_group_id().into(),
415 oid: evt.get_opcode().into(),
416 payload: get_vendor_uci_payload(evt)?,
417 }))
418 }
419
get_vendor_uci_payload(evt: uwb_uci_packets::UciNotification) -> Result<Vec<u8>>420 fn get_vendor_uci_payload(evt: uwb_uci_packets::UciNotification) -> Result<Vec<u8>> {
421 match evt.specialize() {
422 uwb_uci_packets::UciNotificationChild::UciVendor_9_Notification(evt) => {
423 match evt.specialize() {
424 uwb_uci_packets::UciVendor_9_NotificationChild::Payload(payload) => {
425 Ok(payload.to_vec())
426 }
427 uwb_uci_packets::UciVendor_9_NotificationChild::None => Ok(Vec::new()),
428 }
429 }
430 uwb_uci_packets::UciNotificationChild::UciVendor_A_Notification(evt) => {
431 match evt.specialize() {
432 uwb_uci_packets::UciVendor_A_NotificationChild::Payload(payload) => {
433 Ok(payload.to_vec())
434 }
435 uwb_uci_packets::UciVendor_A_NotificationChild::None => Ok(Vec::new()),
436 }
437 }
438 uwb_uci_packets::UciNotificationChild::UciVendor_B_Notification(evt) => {
439 match evt.specialize() {
440 uwb_uci_packets::UciVendor_B_NotificationChild::Payload(payload) => {
441 Ok(payload.to_vec())
442 }
443 uwb_uci_packets::UciVendor_B_NotificationChild::None => Ok(Vec::new()),
444 }
445 }
446 uwb_uci_packets::UciNotificationChild::UciVendor_E_Notification(evt) => {
447 match evt.specialize() {
448 uwb_uci_packets::UciVendor_E_NotificationChild::Payload(payload) => {
449 Ok(payload.to_vec())
450 }
451 uwb_uci_packets::UciVendor_E_NotificationChild::None => Ok(Vec::new()),
452 }
453 }
454 uwb_uci_packets::UciNotificationChild::UciVendor_F_Notification(evt) => {
455 match evt.specialize() {
456 uwb_uci_packets::UciVendor_F_NotificationChild::Payload(payload) => {
457 Ok(payload.to_vec())
458 }
459 uwb_uci_packets::UciVendor_F_NotificationChild::None => Ok(Vec::new()),
460 }
461 }
462 uwb_uci_packets::UciNotificationChild::TestNotification(evt) => match evt.specialize() {
463 uwb_uci_packets::TestNotificationChild::Payload(payload) => Ok(payload.to_vec()),
464 uwb_uci_packets::TestNotificationChild::None => Ok(Vec::new()),
465 },
466 _ => {
467 error!("Unknown UciVendor packet: {:?}", evt);
468 Err(Error::Unknown)
469 }
470 }
471 }
472
473 #[cfg(test)]
474 mod tests {
475 use super::*;
476
477 #[test]
test_ranging_measurements_trait()478 fn test_ranging_measurements_trait() {
479 let empty_short_ranging_measurements = RangingMeasurements::ShortAddressTwoWay(vec![]);
480 assert_eq!(empty_short_ranging_measurements, empty_short_ranging_measurements);
481 let extended_ranging_measurements = RangingMeasurements::ExtendedAddressTwoWay(vec![
482 ExtendedAddressTwoWayRangingMeasurement {
483 mac_address: 0x1234_5678_90ab,
484 status: StatusCode::UciStatusOk,
485 nlos: 0,
486 distance: 4,
487 aoa_azimuth: 5,
488 aoa_azimuth_fom: 6,
489 aoa_elevation: 7,
490 aoa_elevation_fom: 8,
491 aoa_destination_azimuth: 9,
492 aoa_destination_azimuth_fom: 10,
493 aoa_destination_elevation: 11,
494 aoa_destination_elevation_fom: 12,
495 slot_index: 0,
496 rssi: u8::MAX,
497 },
498 ]);
499 let extended_ranging_measurements_copy = extended_ranging_measurements.clone();
500 assert_eq!(extended_ranging_measurements, extended_ranging_measurements_copy);
501 let empty_extended_ranging_measurements =
502 RangingMeasurements::ExtendedAddressTwoWay(vec![]);
503 assert_eq!(empty_short_ranging_measurements, empty_short_ranging_measurements);
504 //short and extended measurements are unequal even if both are empty:
505 assert_ne!(empty_short_ranging_measurements, empty_extended_ranging_measurements);
506 }
507 #[test]
test_core_notification_casting_from_generic_error()508 fn test_core_notification_casting_from_generic_error() {
509 let generic_error_packet = uwb_uci_packets::GenericErrorBuilder {
510 status: uwb_uci_packets::StatusCode::UciStatusRejected,
511 }
512 .build();
513 let core_notification =
514 uwb_uci_packets::CoreNotification::try_from(generic_error_packet).unwrap();
515 let core_notification = CoreNotification::try_from(core_notification).unwrap();
516 let uci_notification_from_generic_error = UciNotification::Core(core_notification);
517 assert_eq!(
518 uci_notification_from_generic_error,
519 UciNotification::Core(CoreNotification::GenericError(
520 uwb_uci_packets::StatusCode::UciStatusRejected
521 ))
522 );
523 }
524 #[test]
test_core_notification_casting_from_device_status_ntf()525 fn test_core_notification_casting_from_device_status_ntf() {
526 let device_status_ntf_packet = uwb_uci_packets::DeviceStatusNtfBuilder {
527 device_state: uwb_uci_packets::DeviceState::DeviceStateActive,
528 }
529 .build();
530 let core_notification =
531 uwb_uci_packets::CoreNotification::try_from(device_status_ntf_packet).unwrap();
532 let uci_notification = CoreNotification::try_from(core_notification).unwrap();
533 let uci_notification_from_device_status_ntf = UciNotification::Core(uci_notification);
534 assert_eq!(
535 uci_notification_from_device_status_ntf,
536 UciNotification::Core(CoreNotification::DeviceStatus(
537 uwb_uci_packets::DeviceState::DeviceStateActive
538 ))
539 );
540 }
541
542 #[test]
test_session_notification_casting_from_extended_mac_two_way_session_info_ntf()543 fn test_session_notification_casting_from_extended_mac_two_way_session_info_ntf() {
544 let extended_measurement = uwb_uci_packets::ExtendedAddressTwoWayRangingMeasurement {
545 mac_address: 0x1234_5678_90ab,
546 status: StatusCode::UciStatusOk,
547 nlos: 0,
548 distance: 4,
549 aoa_azimuth: 5,
550 aoa_azimuth_fom: 6,
551 aoa_elevation: 7,
552 aoa_elevation_fom: 8,
553 aoa_destination_azimuth: 9,
554 aoa_destination_azimuth_fom: 10,
555 aoa_destination_elevation: 11,
556 aoa_destination_elevation_fom: 12,
557 slot_index: 0,
558 rssi: u8::MAX,
559 };
560 let extended_two_way_session_info_ntf =
561 uwb_uci_packets::ExtendedMacTwoWaySessionInfoNtfBuilder {
562 sequence_number: 0x10,
563 session_token: 0x11,
564 rcr_indicator: 0x12,
565 current_ranging_interval: 0x13,
566 two_way_ranging_measurements: vec![extended_measurement.clone()],
567 vendor_data: vec![],
568 }
569 .build();
570 let raw_ranging_data =
571 extended_two_way_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
572 let range_notification =
573 uwb_uci_packets::SessionInfoNtf::try_from(extended_two_way_session_info_ntf).unwrap();
574 let session_notification = SessionNotification::try_from(range_notification).unwrap();
575 let uci_notification_from_extended_two_way_session_info_ntf =
576 UciNotification::Session(session_notification);
577 assert_eq!(
578 uci_notification_from_extended_two_way_session_info_ntf,
579 UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
580 sequence_number: 0x10,
581 session_token: 0x11,
582 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::TwoWay,
583 current_ranging_interval_ms: 0x13,
584 ranging_measurements: RangingMeasurements::ExtendedAddressTwoWay(vec![
585 extended_measurement
586 ]),
587 rcr_indicator: 0x12,
588 raw_ranging_data,
589 }))
590 );
591 }
592
593 #[test]
test_session_notification_casting_from_short_mac_two_way_session_info_ntf()594 fn test_session_notification_casting_from_short_mac_two_way_session_info_ntf() {
595 let short_measurement = uwb_uci_packets::ShortAddressTwoWayRangingMeasurement {
596 mac_address: 0x1234,
597 status: StatusCode::UciStatusOk,
598 nlos: 0,
599 distance: 4,
600 aoa_azimuth: 5,
601 aoa_azimuth_fom: 6,
602 aoa_elevation: 7,
603 aoa_elevation_fom: 8,
604 aoa_destination_azimuth: 9,
605 aoa_destination_azimuth_fom: 10,
606 aoa_destination_elevation: 11,
607 aoa_destination_elevation_fom: 12,
608 slot_index: 0,
609 rssi: u8::MAX,
610 };
611 let short_two_way_session_info_ntf = uwb_uci_packets::ShortMacTwoWaySessionInfoNtfBuilder {
612 sequence_number: 0x10,
613 session_token: 0x11,
614 rcr_indicator: 0x12,
615 current_ranging_interval: 0x13,
616 two_way_ranging_measurements: vec![short_measurement.clone()],
617 vendor_data: vec![0x02, 0x01],
618 }
619 .build();
620 let raw_ranging_data =
621 short_two_way_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
622 let range_notification =
623 uwb_uci_packets::SessionInfoNtf::try_from(short_two_way_session_info_ntf).unwrap();
624 let session_notification = SessionNotification::try_from(range_notification).unwrap();
625 let uci_notification_from_short_two_way_session_info_ntf =
626 UciNotification::Session(session_notification);
627 assert_eq!(
628 uci_notification_from_short_two_way_session_info_ntf,
629 UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
630 sequence_number: 0x10,
631 session_token: 0x11,
632 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::TwoWay,
633 current_ranging_interval_ms: 0x13,
634 ranging_measurements: RangingMeasurements::ShortAddressTwoWay(vec![
635 short_measurement
636 ]),
637 rcr_indicator: 0x12,
638 raw_ranging_data,
639 }))
640 );
641 }
642
643 #[test]
test_session_notification_casting_from_extended_mac_owr_aoa_session_info_ntf()644 fn test_session_notification_casting_from_extended_mac_owr_aoa_session_info_ntf() {
645 let extended_measurement = uwb_uci_packets::ExtendedAddressOwrAoaRangingMeasurement {
646 mac_address: 0x1234_5678_90ab,
647 status: StatusCode::UciStatusOk,
648 nlos: 0,
649 frame_sequence_number: 1,
650 block_index: 1,
651 aoa_azimuth: 5,
652 aoa_azimuth_fom: 6,
653 aoa_elevation: 7,
654 aoa_elevation_fom: 8,
655 };
656 let extended_owr_aoa_session_info_ntf =
657 uwb_uci_packets::ExtendedMacOwrAoaSessionInfoNtfBuilder {
658 sequence_number: 0x10,
659 session_token: 0x11,
660 rcr_indicator: 0x12,
661 current_ranging_interval: 0x13,
662 owr_aoa_ranging_measurements: vec![extended_measurement.clone()],
663 vendor_data: vec![],
664 }
665 .build();
666 let raw_ranging_data =
667 extended_owr_aoa_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
668 let range_notification =
669 uwb_uci_packets::SessionInfoNtf::try_from(extended_owr_aoa_session_info_ntf).unwrap();
670 let session_notification = SessionNotification::try_from(range_notification).unwrap();
671 let uci_notification_from_extended_owr_aoa_session_info_ntf =
672 UciNotification::Session(session_notification);
673 assert_eq!(
674 uci_notification_from_extended_owr_aoa_session_info_ntf,
675 UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
676 sequence_number: 0x10,
677 session_token: 0x11,
678 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::OwrAoa,
679 current_ranging_interval_ms: 0x13,
680 ranging_measurements: RangingMeasurements::ExtendedAddressOwrAoa(
681 extended_measurement
682 ),
683 rcr_indicator: 0x12,
684 raw_ranging_data,
685 }))
686 );
687 }
688
689 #[test]
test_session_notification_casting_from_short_mac_owr_aoa_session_info_ntf()690 fn test_session_notification_casting_from_short_mac_owr_aoa_session_info_ntf() {
691 let short_measurement = uwb_uci_packets::ShortAddressOwrAoaRangingMeasurement {
692 mac_address: 0x1234,
693 status: StatusCode::UciStatusOk,
694 nlos: 0,
695 frame_sequence_number: 1,
696 block_index: 1,
697 aoa_azimuth: 5,
698 aoa_azimuth_fom: 6,
699 aoa_elevation: 7,
700 aoa_elevation_fom: 8,
701 };
702 let short_owr_aoa_session_info_ntf = uwb_uci_packets::ShortMacOwrAoaSessionInfoNtfBuilder {
703 sequence_number: 0x10,
704 session_token: 0x11,
705 rcr_indicator: 0x12,
706 current_ranging_interval: 0x13,
707 owr_aoa_ranging_measurements: vec![short_measurement.clone()],
708 vendor_data: vec![],
709 }
710 .build();
711 let raw_ranging_data =
712 short_owr_aoa_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
713 let range_notification =
714 uwb_uci_packets::SessionInfoNtf::try_from(short_owr_aoa_session_info_ntf).unwrap();
715 let session_notification = SessionNotification::try_from(range_notification).unwrap();
716 let uci_notification_from_short_owr_aoa_session_info_ntf =
717 UciNotification::Session(session_notification);
718 assert_eq!(
719 uci_notification_from_short_owr_aoa_session_info_ntf,
720 UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
721 sequence_number: 0x10,
722 session_token: 0x11,
723 ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::OwrAoa,
724 current_ranging_interval_ms: 0x13,
725 ranging_measurements: RangingMeasurements::ShortAddressOwrAoa(short_measurement),
726 rcr_indicator: 0x12,
727 raw_ranging_data,
728 }))
729 );
730 }
731
732 #[test]
test_session_notification_casting_from_session_status_ntf()733 fn test_session_notification_casting_from_session_status_ntf() {
734 let session_status_ntf = uwb_uci_packets::SessionStatusNtfBuilder {
735 session_token: 0x20,
736 session_state: uwb_uci_packets::SessionState::SessionStateActive,
737 reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
738 .into(),
739 }
740 .build();
741 let session_notification_packet =
742 uwb_uci_packets::SessionConfigNotification::try_from(session_status_ntf).unwrap();
743 let session_notification =
744 SessionNotification::try_from(session_notification_packet).unwrap();
745 let uci_notification_from_session_status_ntf =
746 UciNotification::Session(session_notification);
747 assert_eq!(
748 uci_notification_from_session_status_ntf,
749 UciNotification::Session(SessionNotification::Status {
750 session_token: 0x20,
751 session_state: uwb_uci_packets::SessionState::SessionStateActive,
752 reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
753 .into(),
754 })
755 );
756 }
757
758 #[test]
test_session_notification_casting_from_session_update_controller_multicast_list_ntf_packet()759 fn test_session_notification_casting_from_session_update_controller_multicast_list_ntf_packet()
760 {
761 let controlee_status = uwb_uci_packets::ControleeStatus {
762 mac_address: [0x0c, 0xa8],
763 subsession_id: 0x30,
764 status: uwb_uci_packets::MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
765 };
766 let another_controlee_status = uwb_uci_packets::ControleeStatus {
767 mac_address: [0x0c, 0xa9],
768 subsession_id: 0x31,
769 status: uwb_uci_packets::MulticastUpdateStatusCode::StatusErrorKeyFetchFail,
770 };
771 let session_update_controller_multicast_list_ntf =
772 uwb_uci_packets::SessionUpdateControllerMulticastListNtfBuilder {
773 session_token: 0x32,
774 remaining_multicast_list_size: 0x2,
775 controlee_status: vec![controlee_status.clone(), another_controlee_status.clone()],
776 }
777 .build();
778 let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
779 session_update_controller_multicast_list_ntf,
780 )
781 .unwrap();
782 let session_notification =
783 SessionNotification::try_from(session_notification_packet).unwrap();
784 let uci_notification_from_session_update_controller_multicast_list_ntf =
785 UciNotification::Session(session_notification);
786 assert_eq!(
787 uci_notification_from_session_update_controller_multicast_list_ntf,
788 UciNotification::Session(SessionNotification::UpdateControllerMulticastList {
789 session_token: 0x32,
790 remaining_multicast_list_size: 0x2,
791 status_list: vec![controlee_status, another_controlee_status],
792 })
793 );
794 }
795
796 #[test]
797 #[allow(non_snake_case)] //override snake case for vendor_A
test_vendor_notification_casting()798 fn test_vendor_notification_casting() {
799 let vendor_9_empty_notification: uwb_uci_packets::UciNotification =
800 uwb_uci_packets::UciVendor_9_NotificationBuilder { opcode: 0x40, payload: None }
801 .build()
802 .into();
803 let vendor_A_nonempty_notification: uwb_uci_packets::UciNotification =
804 uwb_uci_packets::UciVendor_A_NotificationBuilder {
805 opcode: 0x41,
806 payload: Some(bytes::Bytes::from_static(b"Placeholder notification.")),
807 }
808 .build()
809 .into();
810 let uci_notification_from_vendor_9 =
811 UciNotification::try_from(vendor_9_empty_notification).unwrap();
812 let uci_notification_from_vendor_A =
813 UciNotification::try_from(vendor_A_nonempty_notification).unwrap();
814 assert_eq!(
815 uci_notification_from_vendor_9,
816 UciNotification::Vendor(RawUciMessage {
817 gid: 0x9, // per enum GroupId in uci_packets.pdl
818 oid: 0x40,
819 payload: vec![],
820 })
821 );
822 assert_eq!(
823 uci_notification_from_vendor_A,
824 UciNotification::Vendor(RawUciMessage {
825 gid: 0xa,
826 oid: 0x41,
827 payload: b"Placeholder notification.".to_owned().into(),
828 })
829 );
830 }
831
832 #[test]
test_test_to_vendor_notification_casting()833 fn test_test_to_vendor_notification_casting() {
834 let test_notification: uwb_uci_packets::UciNotification =
835 uwb_uci_packets::TestNotificationBuilder { opcode: 0x22, payload: None }.build().into();
836 let test_uci_notification = UciNotification::try_from(test_notification).unwrap();
837 assert_eq!(
838 test_uci_notification,
839 UciNotification::Vendor(RawUciMessage {
840 gid: 0x0d, // per enum Test GroupId in uci_packets.pdl
841 oid: 0x22,
842 payload: vec![],
843 })
844 );
845 }
846 }
847