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 #![allow(clippy::all)]
16 #![allow(non_upper_case_globals)]
17 #![allow(non_camel_case_types)]
18 #![allow(non_snake_case)]
19 #![allow(unused)]
20 #![allow(missing_docs)]
21
22 use std::cmp;
23
24 use log::error;
25 use num_derive::FromPrimitive;
26 use num_traits::FromPrimitive;
27 use zeroize::Zeroize;
28
29 include!(concat!(env!("OUT_DIR"), "/uci_packets.rs"));
30
31 const MAX_PAYLOAD_LEN: usize = 255;
32 // TODO: Use a PDL struct to represent the headers and avoid hardcoding
33 // lengths below.
34 // Real UCI packet header len.
35 pub const UCI_PACKET_HAL_HEADER_LEN: usize = 4;
36 // Unfragmented UCI packet header len.
37 pub const UCI_PACKET_HEADER_LEN: usize = 7;
38 // Unfragmented UCI DATA_MESSAGE_SND packet header len.
39 const UCI_DATA_SND_PACKET_HEADER_LEN: usize = 6;
40
41 // Opcode field byte position (within UCI packet header) and mask (of bits to be used).
42 const UCI_HEADER_MT_BYTE_POSITION: usize = 0;
43 const UCI_HEADER_MT_BIT_SHIFT: u8 = 5;
44 const UCI_HEADER_MT_MASK: u8 = 0x7;
45
46 const UCI_HEADER_PBF_BYTE_POSITION: usize = 0;
47 const UCI_HEADER_PBF_BIT_SHIFT: u8 = 4;
48 const UCI_HEADER_PBF_MASK: u8 = 0x1;
49
50 const UCI_CONTROL_HEADER_GID_BYTE_POSITION: usize = 0;
51 const UCI_CONTROL_HEADER_GID_MASK: u8 = 0xF;
52
53 const UCI_CONTROL_HEADER_OID_BYTE_POSITION: usize = 1;
54 const UCI_CONTROL_HEADER_OID_MASK: u8 = 0x3F;
55
56 #[derive(Debug, Clone, PartialEq, FromPrimitive)]
57 pub enum TimeStampLength {
58 Timestamp40Bit = 0x0,
59 Timestamp64Bit = 0x1,
60 }
61
62 #[derive(Debug, Clone, PartialEq, FromPrimitive)]
63 pub enum DTAnchorLocationType {
64 NotIncluded = 0x0,
65 Wgs84 = 0x1,
66 Relative = 0x2,
67 }
68
69 #[allow(dead_code)]
70 #[derive(Debug, Clone, PartialEq)]
71 pub struct DlTdoaRangingMeasurement {
72 pub status: u8,
73 pub message_type: u8,
74 pub message_control: u16,
75 pub block_index: u16,
76 pub round_index: u8,
77 pub nlos: u8,
78 pub aoa_azimuth: u16,
79 pub aoa_azimuth_fom: u8,
80 pub aoa_elevation: u16,
81 pub aoa_elevation_fom: u8,
82 pub rssi: u8,
83 pub tx_timestamp: u64,
84 pub rx_timestamp: u64,
85 pub anchor_cfo: u16,
86 pub cfo: u16,
87 pub initiator_reply_time: u32,
88 pub responder_reply_time: u32,
89 pub initiator_responder_tof: u16,
90 pub dt_anchor_location: Vec<u8>,
91 pub ranging_rounds: Vec<u8>,
92 total_size: usize,
93 }
94
95 impl DlTdoaRangingMeasurement {
parse_one(bytes: &[u8]) -> Option<Self>96 pub fn parse_one(bytes: &[u8]) -> Option<Self> {
97 let mut ptr = 0;
98 let status = extract_u8(bytes, &mut ptr, 1)?;
99 let message_type = extract_u8(bytes, &mut ptr, 1)?;
100 let message_control = extract_u16(bytes, &mut ptr, 2)?;
101 let block_index = extract_u16(bytes, &mut ptr, 2)?;
102 let round_index = extract_u8(bytes, &mut ptr, 1)?;
103 let nlos = extract_u8(bytes, &mut ptr, 1)?;
104 let aoa_azimuth = extract_u16(bytes, &mut ptr, 2)?;
105 let aoa_azimuth_fom = extract_u8(bytes, &mut ptr, 1)?;
106 let aoa_elevation = extract_u16(bytes, &mut ptr, 2)?;
107 let aoa_elevation_fom = extract_u8(bytes, &mut ptr, 1)?;
108 let rssi = extract_u8(bytes, &mut ptr, 1)?;
109 let tx_timestamp_length = (message_control >> 1) & 0x1;
110 let tx_timestamp = match TimeStampLength::from_u16(tx_timestamp_length)? {
111 TimeStampLength::Timestamp40Bit => extract_u64(bytes, &mut ptr, 5)?,
112 TimeStampLength::Timestamp64Bit => extract_u64(bytes, &mut ptr, 8)?,
113 };
114 let rx_timestamp_length = (message_control >> 3) & 0x1;
115 let rx_timestamp = match TimeStampLength::from_u16(rx_timestamp_length)? {
116 TimeStampLength::Timestamp40Bit => extract_u64(bytes, &mut ptr, 5)?,
117 TimeStampLength::Timestamp64Bit => extract_u64(bytes, &mut ptr, 8)?,
118 };
119 let anchor_cfo = extract_u16(bytes, &mut ptr, 2)?;
120 let cfo = extract_u16(bytes, &mut ptr, 2)?;
121 let initiator_reply_time = extract_u32(bytes, &mut ptr, 4)?;
122 let responder_reply_time = extract_u32(bytes, &mut ptr, 4)?;
123 let initiator_responder_tof = extract_u16(bytes, &mut ptr, 2)?;
124 let dt_location_type = (message_control >> 5) & 0x3;
125 let dt_anchor_location = match DTAnchorLocationType::from_u16(dt_location_type)? {
126 DTAnchorLocationType::Wgs84 => extract_vec(bytes, &mut ptr, 10)?,
127 DTAnchorLocationType::Relative => extract_vec(bytes, &mut ptr, 12)?,
128 _ => vec![],
129 };
130 let active_ranging_rounds = ((message_control >> 7) & 0xf) as u8;
131 let ranging_round = extract_vec(bytes, &mut ptr, active_ranging_rounds as usize)?;
132
133 Some(DlTdoaRangingMeasurement {
134 status,
135 message_type,
136 message_control,
137 block_index,
138 round_index,
139 nlos,
140 aoa_azimuth,
141 aoa_azimuth_fom,
142 aoa_elevation,
143 aoa_elevation_fom,
144 rssi,
145 tx_timestamp,
146 rx_timestamp,
147 anchor_cfo,
148 cfo,
149 initiator_reply_time,
150 responder_reply_time,
151 initiator_responder_tof,
152 dt_anchor_location: dt_anchor_location.to_vec(),
153 ranging_rounds: ranging_round.to_vec(),
154 total_size: ptr,
155 })
156 }
get_total_size(&self) -> usize157 pub fn get_total_size(&self) -> usize {
158 self.total_size
159 }
160 }
161
162 #[derive(Debug, Clone, PartialEq)]
163 pub struct ShortAddressDlTdoaRangingMeasurement {
164 pub mac_address: u16,
165 pub measurement: DlTdoaRangingMeasurement,
166 }
167
168 impl ShortAddressDlTdoaRangingMeasurement {
169 /// Parse the `payload` byte buffer from PDL to the vector of measurement.
parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>>170 pub fn parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>> {
171 let mut ptr = 0;
172 let mut measurements = vec![];
173 let mut count = 0;
174 while (count < no_of_ranging_measurement) {
175 let mac_address = extract_u16(bytes, &mut ptr, 2)?;
176 let rem = &bytes[ptr..];
177 let measurement = DlTdoaRangingMeasurement::parse_one(rem);
178 match measurement {
179 Some(measurement) => {
180 ptr += measurement.get_total_size();
181 measurements
182 .push(ShortAddressDlTdoaRangingMeasurement { mac_address, measurement });
183 count = count + 1;
184 }
185 None => return None,
186 }
187 }
188 Some(measurements)
189 }
190 }
191
192 #[derive(Debug, Clone, PartialEq)]
193 pub struct ExtendedAddressDlTdoaRangingMeasurement {
194 pub mac_address: u64,
195 pub measurement: DlTdoaRangingMeasurement,
196 }
197
198 impl ExtendedAddressDlTdoaRangingMeasurement {
199 /// Parse the `payload` byte buffer from PDL to the vector of measurement.
parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>>200 pub fn parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>> {
201 let mut ptr = 0;
202 let mut measurements = vec![];
203 let mut count = 0;
204 while (count < no_of_ranging_measurement) {
205 let mac_address = extract_u64(bytes, &mut ptr, 8)?;
206 let rem = &bytes[ptr..];
207 let measurement = DlTdoaRangingMeasurement::parse_one(rem);
208 match measurement {
209 Some(measurement) => {
210 ptr += measurement.get_total_size();
211 measurements
212 .push(ExtendedAddressDlTdoaRangingMeasurement { mac_address, measurement });
213 count = count + 1;
214 }
215 None => return None,
216 }
217 }
218 Some(measurements)
219 }
220 }
221
extract_vec(bytes: &[u8], ptr: &mut usize, consumed_size: usize) -> Option<Vec<u8>>222 pub fn extract_vec(bytes: &[u8], ptr: &mut usize, consumed_size: usize) -> Option<Vec<u8>> {
223 if bytes.len() < *ptr + consumed_size {
224 return None;
225 }
226
227 let res = bytes[*ptr..*ptr + consumed_size].to_vec();
228 *ptr += consumed_size;
229 Some(res)
230 }
231
232 /// Generate the function that extracts the value from byte buffers.
233 macro_rules! generate_extract_func {
234 ($func_name:ident, $type:ty) => {
235 /// Extract the value from |byte[ptr..ptr + consumed_size]| in little endian.
236 fn $func_name(bytes: &[u8], ptr: &mut usize, consumed_size: usize) -> Option<$type> {
237 const type_size: usize = std::mem::size_of::<$type>();
238 if consumed_size > type_size {
239 return None;
240 }
241
242 let extracted_bytes = extract_vec(bytes, ptr, consumed_size)?;
243 let mut le_bytes = [0; type_size];
244 le_bytes[0..consumed_size].copy_from_slice(&extracted_bytes);
245 Some(<$type>::from_le_bytes(le_bytes))
246 }
247 };
248 }
249
250 generate_extract_func!(extract_u8, u8);
251 generate_extract_func!(extract_u16, u16);
252 generate_extract_func!(extract_u32, u32);
253 generate_extract_func!(extract_u64, u64);
254
255 // The GroupIdOrDataPacketFormat enum has all the values defined in both the GroupId and
256 // DataPacketFormat enums. It represents the same bits in UCI packet header - the GID field in
257 // a UCI control packet, and the DataPacketFormat field in a UCI data packet. Hence the unwrap()
258 // calls in the conversions below should always succeed (as long as care is taken in future, to
259 // keep the two enums in sync, for any additional values defined in the UCI spec).
260 impl From<GroupId> for GroupIdOrDataPacketFormat {
from(gid: GroupId) -> Self261 fn from(gid: GroupId) -> Self {
262 GroupIdOrDataPacketFormat::try_from(u8::from(gid)).unwrap()
263 }
264 }
265
266 impl From<GroupIdOrDataPacketFormat> for GroupId {
from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Self267 fn from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Self {
268 GroupId::try_from(u8::from(gid_or_dpf)).unwrap()
269 }
270 }
271
272 impl From<DataPacketFormat> for GroupIdOrDataPacketFormat {
from(dpf: DataPacketFormat) -> Self273 fn from(dpf: DataPacketFormat) -> Self {
274 GroupIdOrDataPacketFormat::try_from(u8::from(dpf)).unwrap()
275 }
276 }
277
278 // The GroupIdOrDataPacketFormat enum has more values defined (for the GroupId bits) than the
279 // DataPacketFormat enum. Hence this is implemented as TryFrom() instead of From().
280 impl TryFrom<GroupIdOrDataPacketFormat> for DataPacketFormat {
281 type Error = Error;
282
try_from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Result<Self>283 fn try_from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Result<Self> {
284 DataPacketFormat::try_from(u8::from(gid_or_dpf)).or(Err(Error::InvalidPacketError))
285 }
286 }
287
288 // Container for UCI packet header fields.
289 struct UciControlPacketHeader {
290 message_type: MessageType,
291 group_id: GroupId,
292 opcode: u8,
293 }
294
295 impl UciControlPacketHeader {
new(message_type: MessageType, group_id: GroupId, opcode: u8) -> Result<Self>296 fn new(message_type: MessageType, group_id: GroupId, opcode: u8) -> Result<Self> {
297 if !is_uci_control_packet(message_type) {
298 return Err(Error::InvalidPacketError);
299 }
300
301 Ok(UciControlPacketHeader {
302 message_type: message_type,
303 group_id: group_id,
304 opcode: opcode,
305 })
306 }
307 }
308
309 // Helper methods to extract the UCI Packet header fields.
get_mt_from_uci_packet(packet: &[u8]) -> u8310 fn get_mt_from_uci_packet(packet: &[u8]) -> u8 {
311 (packet[UCI_HEADER_MT_BYTE_POSITION] >> UCI_HEADER_MT_BIT_SHIFT) & UCI_HEADER_MT_MASK
312 }
313
get_pbf_from_uci_packet(packet: &[u8]) -> u8314 fn get_pbf_from_uci_packet(packet: &[u8]) -> u8 {
315 (packet[UCI_HEADER_PBF_BYTE_POSITION] >> UCI_HEADER_PBF_BIT_SHIFT) & UCI_HEADER_PBF_MASK
316 }
317
get_gid_from_uci_control_packet(packet: &[u8]) -> u8318 fn get_gid_from_uci_control_packet(packet: &[u8]) -> u8 {
319 packet[UCI_CONTROL_HEADER_GID_BYTE_POSITION] & UCI_CONTROL_HEADER_GID_MASK
320 }
321
get_oid_from_uci_control_packet(packet: &[u8]) -> u8322 fn get_oid_from_uci_control_packet(packet: &[u8]) -> u8 {
323 packet[UCI_CONTROL_HEADER_OID_BYTE_POSITION] & UCI_CONTROL_HEADER_OID_MASK
324 }
325
326 // This function parses the packet bytes to return the Control Packet Opcode (OID) field. The
327 // caller should check that the packet bytes represent a UCI control packet. The code will not
328 // panic because UciPacketHal::to_bytes() should always be larger then the place we access.
get_opcode_from_uci_control_packet(packet: &UciPacketHal) -> u8329 fn get_opcode_from_uci_control_packet(packet: &UciPacketHal) -> u8 {
330 get_oid_from_uci_control_packet(&packet.clone().to_bytes())
331 }
332
is_uci_control_packet(message_type: MessageType) -> bool333 fn is_uci_control_packet(message_type: MessageType) -> bool {
334 match message_type {
335 MessageType::Command
336 | MessageType::Response
337 | MessageType::Notification
338 | MessageType::ReservedForTesting1
339 | MessageType::ReservedForTesting2 => true,
340 _ => false,
341 }
342 }
343
build_uci_control_packet( message_type: MessageType, group_id: GroupId, opcode: u8, payload: Option<Bytes>, ) -> Option<UciControlPacket>344 pub fn build_uci_control_packet(
345 message_type: MessageType,
346 group_id: GroupId,
347 opcode: u8,
348 payload: Option<Bytes>,
349 ) -> Option<UciControlPacket> {
350 if !is_uci_control_packet(message_type) {
351 error!("Only control packets are allowed, MessageType: {message_type:?}");
352 return None;
353 }
354 Some(UciControlPacketBuilder { group_id, message_type, opcode, payload }.build())
355 }
356
357 // Ensure that the new packet fragment belong to the same packet.
is_same_control_packet(header: &UciControlPacketHeader, packet: &UciPacketHal) -> bool358 fn is_same_control_packet(header: &UciControlPacketHeader, packet: &UciPacketHal) -> bool {
359 is_uci_control_packet(header.message_type)
360 && header.message_type == packet.get_message_type()
361 && header.group_id == packet.get_group_id_or_data_packet_format().into()
362 && header.opcode == get_opcode_from_uci_control_packet(packet)
363 }
364
365 impl UciControlPacket {
366 // For some usage, we need to get the raw payload.
to_raw_payload(self) -> Vec<u8>367 pub fn to_raw_payload(self) -> Vec<u8> {
368 self.to_bytes().slice(UCI_PACKET_HEADER_LEN..).to_vec()
369 }
370 }
371
372 // Helper to convert from vector of |UciPacketHal| to |UciControlPacket|. An example
373 // usage is to convert a list UciPacketHAL fragments to one UciPacket, during de-fragmentation.
374 impl TryFrom<Vec<UciPacketHal>> for UciControlPacket {
375 type Error = Error;
376
try_from(packets: Vec<UciPacketHal>) -> Result<Self>377 fn try_from(packets: Vec<UciPacketHal>) -> Result<Self> {
378 if packets.is_empty() {
379 return Err(Error::InvalidPacketError);
380 }
381
382 // Store header info from the first packet.
383 let header = UciControlPacketHeader::new(
384 packets[0].get_message_type(),
385 packets[0].get_group_id_or_data_packet_format().into(),
386 get_opcode_from_uci_control_packet(&packets[0]),
387 )?;
388
389 // Create the reassembled payload.
390 let mut payload_buf = BytesMut::new();
391 for packet in packets {
392 // Ensure that the new fragment is part of the same packet.
393 if !is_same_control_packet(&header, &packet) {
394 error!("Received unexpected fragment: {:?}", packet);
395 return Err(Error::InvalidPacketError);
396 }
397 // get payload by stripping the header.
398 payload_buf.extend_from_slice(&packet.to_bytes().slice(UCI_PACKET_HAL_HEADER_LEN..))
399 }
400
401 // Create assembled |UciControlPacket| and convert to bytes again since we need to
402 // reparse the packet after defragmentation to get the appropriate message.
403 UciControlPacket::parse(
404 &UciControlPacketBuilder {
405 message_type: header.message_type,
406 group_id: header.group_id,
407 opcode: header.opcode,
408 payload: Some(payload_buf.into()),
409 }
410 .build()
411 .to_bytes(),
412 )
413 }
414 }
415
416 #[derive(Debug, Clone)]
417 pub struct RawUciControlPacket {
418 pub mt: u8,
419 pub gid: u8,
420 pub oid: u8,
421 pub payload: Vec<u8>,
422 }
423
424 impl RawUciControlPacket {
425 // Match the GID and OID to confirm the UCI packet (represented by header) is
426 // the same as the stored signature. We don't match the MT because they can be
427 // different (eg: CMD/RSP pair).
is_same_signature_bytes(&self, header: &[u8]) -> bool428 pub fn is_same_signature_bytes(&self, header: &[u8]) -> bool {
429 let gid = get_gid_from_uci_control_packet(header);
430 let oid = get_oid_from_uci_control_packet(header);
431 gid == self.gid && oid == self.oid
432 }
433 }
434
435 // UCI Data packet functions.
is_uci_data_rcv_packet(message_type: MessageType, data_packet_format: DataPacketFormat) -> bool436 fn is_uci_data_rcv_packet(message_type: MessageType, data_packet_format: DataPacketFormat) -> bool {
437 message_type == MessageType::Data && data_packet_format == DataPacketFormat::DataRcv
438 }
439
try_into_data_payload(packet: UciPacketHal) -> Result<Bytes>440 fn try_into_data_payload(packet: UciPacketHal) -> Result<Bytes> {
441 if is_uci_data_rcv_packet(
442 packet.get_message_type(),
443 packet.get_group_id_or_data_packet_format().try_into()?,
444 ) {
445 Ok(packet.to_bytes().slice(UCI_PACKET_HAL_HEADER_LEN..))
446 } else {
447 error!("Received unexpected data packet fragment: {:?}", packet);
448 Err(Error::InvalidPacketError)
449 }
450 }
451
452 // Helper to convert from vector of |UciPacketHal| to |UciDataPacket|. An example
453 // usage is to convert a list UciPacketHAL fragments to one UciPacket, during de-fragmentation.
454 impl TryFrom<Vec<UciPacketHal>> for UciDataPacket {
455 type Error = Error;
456
try_from(packets: Vec<UciPacketHal>) -> Result<Self>457 fn try_from(packets: Vec<UciPacketHal>) -> Result<Self> {
458 if packets.is_empty() {
459 return Err(Error::InvalidPacketError);
460 }
461
462 // Create the reassembled payload.
463 let mut payload_buf = Bytes::new();
464 for packet in packets {
465 // Ensure that the fragment is a Data Rcv packet.
466 // Get payload by stripping the header.
467 payload_buf = [payload_buf, try_into_data_payload(packet)?].concat().into();
468 }
469
470 // Create assembled |UciDataPacket| and convert to bytes again since we need to
471 // reparse the packet after defragmentation to get the appropriate message.
472 UciDataPacket::parse(
473 &UciDataPacketBuilder {
474 message_type: MessageType::Data,
475 data_packet_format: DataPacketFormat::DataRcv,
476 payload: Some(payload_buf.into()),
477 }
478 .build()
479 .to_bytes(),
480 )
481 }
482 }
483
484 // Helper to convert from |UciControlPacket| to vector of |UciControlPacketHal|s. An
485 // example usage is to do this conversion for fragmentation (from Host to UWBS).
486 impl From<UciControlPacket> for Vec<UciControlPacketHal> {
from(packet: UciControlPacket) -> Self487 fn from(packet: UciControlPacket) -> Self {
488 // Store header info.
489 let header = match UciControlPacketHeader::new(
490 packet.get_message_type(),
491 packet.get_group_id(),
492 packet.get_opcode(),
493 ) {
494 Ok(hdr) => hdr,
495 _ => {
496 error!(
497 "Unable to parse UciControlPacketHeader from UciControlPacket: {:?}",
498 packet
499 );
500 return Vec::new();
501 }
502 };
503
504 let mut fragments = Vec::new();
505 // get payload by stripping the header.
506 let payload = packet.to_bytes().slice(UCI_PACKET_HEADER_LEN..);
507 if payload.is_empty() {
508 fragments.push(
509 UciControlPacketHalBuilder {
510 message_type: header.message_type,
511 group_id_or_data_packet_format: header.group_id.into(),
512 opcode: header.opcode,
513 packet_boundary_flag: PacketBoundaryFlag::Complete,
514 payload: None,
515 }
516 .build(),
517 );
518 } else {
519 let mut fragments_iter = payload.chunks(MAX_PAYLOAD_LEN).peekable();
520 while let Some(fragment) = fragments_iter.next() {
521 // Set the last fragment complete if this is last fragment.
522 let pbf = if let Some(nxt_fragment) = fragments_iter.peek() {
523 PacketBoundaryFlag::NotComplete
524 } else {
525 PacketBoundaryFlag::Complete
526 };
527 fragments.push(
528 UciControlPacketHalBuilder {
529 message_type: header.message_type,
530 group_id_or_data_packet_format: header.group_id.into(),
531 opcode: header.opcode,
532 packet_boundary_flag: pbf,
533 payload: Some(Bytes::from(fragment.to_owned())),
534 }
535 .build(),
536 );
537 }
538 }
539 fragments
540 }
541 }
542
543 // Helper to convert From<UciDataSnd> into Vec<UciDataPacketHal>. An
544 // example usage is for fragmentation in the Data Packet Tx flow.
545 impl From<UciDataSnd> for Vec<UciDataPacketHal> {
from(packet: UciDataSnd) -> Self546 fn from(packet: UciDataSnd) -> Self {
547 let mut fragments = Vec::new();
548 let dpf = packet.get_data_packet_format().into();
549
550 // get payload by stripping the header.
551 let payload = packet.to_bytes().slice(UCI_DATA_SND_PACKET_HEADER_LEN..);
552 if payload.is_empty() {
553 fragments.push(
554 UciDataPacketHalBuilder {
555 group_id_or_data_packet_format: dpf,
556 packet_boundary_flag: PacketBoundaryFlag::Complete,
557 payload: None,
558 }
559 .build(),
560 );
561 } else {
562 let mut fragments_iter = payload.chunks(MAX_PAYLOAD_LEN).peekable();
563 while let Some(fragment) = fragments_iter.next() {
564 // Set the last fragment complete if this is last fragment.
565 let pbf = if let Some(nxt_fragment) = fragments_iter.peek() {
566 PacketBoundaryFlag::NotComplete
567 } else {
568 PacketBoundaryFlag::Complete
569 };
570 fragments.push(
571 UciDataPacketHalBuilder {
572 group_id_or_data_packet_format: dpf,
573 packet_boundary_flag: pbf,
574 payload: Some(Bytes::from(fragment.to_owned())),
575 }
576 .build(),
577 );
578 }
579 }
580 fragments
581 }
582 }
583
584 #[derive(Default, Debug)]
585 pub struct PacketDefrager {
586 // Cache to store incoming fragmented packets in the middle of reassembly.
587 // Will be empty if there is no reassembly in progress.
588 // TODO(b/261762781): Prefer this to be UciControlPacketHal
589 control_fragment_cache: Vec<UciPacketHal>,
590 // TODO(b/261762781): Prefer this to be UciDataPacketHal
591 data_fragment_cache: Vec<UciPacketHal>,
592 // Raw packet payload bytes cache
593 raw_fragment_cache: Vec<u8>,
594 }
595
596 pub enum UciDefragPacket {
597 Control(UciControlPacket),
598 Data(UciDataPacket),
599 Raw(Result<()>, RawUciControlPacket),
600 }
601
602 impl PacketDefrager {
defragment_packet( &mut self, msg: &[u8], last_raw_cmd: Option<RawUciControlPacket>, ) -> Option<UciDefragPacket>603 pub fn defragment_packet(
604 &mut self,
605 msg: &[u8],
606 last_raw_cmd: Option<RawUciControlPacket>,
607 ) -> Option<UciDefragPacket> {
608 if let Some(raw_cmd) = last_raw_cmd {
609 let mt_u8 = get_mt_from_uci_packet(msg);
610 match MessageType::try_from(u8::from(mt_u8)) {
611 Ok(mt) => match mt {
612 // Parse only a UCI response packet as a Raw packet.
613 MessageType::Response => {
614 return self.defragment_raw_uci_response_packet(msg, raw_cmd);
615 }
616 _ => { /* Fallthrough to de-frag as a normal UCI packet below */ }
617 },
618 Err(_) => {
619 error!("Rx packet from HAL has unrecognized MT={}", mt_u8);
620 return Some(UciDefragPacket::Raw(
621 Err(Error::InvalidPacketError),
622 RawUciControlPacket { mt: mt_u8, gid: 0, oid: 0, payload: Vec::new() },
623 ));
624 }
625 };
626 }
627
628 let packet = UciPacketHal::parse(msg)
629 .or_else(|e| {
630 error!("Failed to parse packet: {:?}", e);
631 Err(e)
632 })
633 .ok()?;
634
635 let pbf = packet.get_packet_boundary_flag();
636
637 // TODO(b/261762781): The current implementation allows for the possibility that we receive
638 // interleaved Control/Data HAL packets, and so uses separate caches for them. In the
639 // future, if we determine that interleaving is not possible, this can be simplified.
640 if is_uci_control_packet(packet.get_message_type()) {
641 // Add the incoming fragment to the control packet cache.
642 self.control_fragment_cache.push(packet);
643 if pbf == PacketBoundaryFlag::NotComplete {
644 // Wait for remaining fragments.
645 return None;
646 }
647
648 // All fragments received, defragment the control packet.
649 match self.control_fragment_cache.drain(..).collect::<Vec<_>>().try_into() {
650 Ok(packet) => Some(UciDefragPacket::Control(packet)),
651 Err(e) => {
652 error!("Failed to defragment control packet: {:?}", e);
653 None
654 }
655 }
656 } else {
657 // Add the incoming fragment to the data packet cache.
658 self.data_fragment_cache.push(packet);
659 if pbf == PacketBoundaryFlag::NotComplete {
660 // Wait for remaining fragments.
661 return None;
662 }
663
664 // All fragments received, defragment the data packet.
665 match self.data_fragment_cache.drain(..).collect::<Vec<_>>().try_into() {
666 Ok(packet) => Some(UciDefragPacket::Data(packet)),
667 Err(e) => {
668 error!("Failed to defragment data packet: {:?}", e);
669 None
670 }
671 }
672 }
673 }
674
defragment_raw_uci_response_packet( &mut self, msg: &[u8], raw_cmd: RawUciControlPacket, ) -> Option<UciDefragPacket>675 fn defragment_raw_uci_response_packet(
676 &mut self,
677 msg: &[u8],
678 raw_cmd: RawUciControlPacket,
679 ) -> Option<UciDefragPacket> {
680 let mt_u8 = get_mt_from_uci_packet(msg);
681 let pbf = get_pbf_from_uci_packet(msg);
682 let gid = get_gid_from_uci_control_packet(msg);
683 let oid = get_oid_from_uci_control_packet(msg);
684 if raw_cmd.is_same_signature_bytes(msg) {
685 // Store only the packet payload bytes (UCI header should not be stored).
686 self.raw_fragment_cache.extend_from_slice(&msg[UCI_PACKET_HAL_HEADER_LEN..]);
687
688 if pbf == u8::from(PacketBoundaryFlag::NotComplete) {
689 return None;
690 }
691
692 // All fragments received, defragment and return the Raw packet's payload bytes.
693 return Some(UciDefragPacket::Raw(
694 Ok(()),
695 RawUciControlPacket {
696 mt: mt_u8,
697 gid,
698 oid,
699 payload: self.raw_fragment_cache.drain(..).collect(),
700 },
701 ));
702 } else {
703 error!(
704 "Rx packet from HAL (MT={}, PBF={}, GID={}, OID={}) has non-matching\
705 RawCmd signature",
706 mt_u8, pbf, gid, oid
707 );
708 return Some(UciDefragPacket::Raw(
709 Err(Error::InvalidPacketError),
710 RawUciControlPacket { mt: mt_u8, gid, oid, payload: Vec::new() },
711 ));
712 }
713 }
714 }
715
716 #[allow(dead_code)]
717 #[derive(Debug, Clone)]
718 pub struct ParsedDiagnosticNtfPacket {
719 session_token: u32,
720 sequence_number: u32,
721 frame_reports: Vec<ParsedFrameReport>,
722 }
723
724 #[allow(dead_code)]
725 #[derive(Debug, Clone)]
726 pub struct ParsedFrameReport {
727 uwb_msg_id: u8,
728 action: u8,
729 antenna_set: u8,
730 rssi: Vec<u8>,
731 aoa: Vec<AoaMeasurement>,
732 cir: Vec<CirValue>,
733 }
734
parse_diagnostics_ntf(evt: AndroidRangeDiagnosticsNtf) -> Result<ParsedDiagnosticNtfPacket>735 pub fn parse_diagnostics_ntf(evt: AndroidRangeDiagnosticsNtf) -> Result<ParsedDiagnosticNtfPacket> {
736 let session_token = evt.get_session_token();
737 let sequence_number = evt.get_sequence_number();
738 let mut parsed_frame_reports = Vec::new();
739 for report in evt.get_frame_reports() {
740 let mut rssi_vec = Vec::new();
741 let mut aoa_vec = Vec::new();
742 let mut cir_vec = Vec::new();
743 for tlv in &report.frame_report_tlvs {
744 match FrameReportTlvPacket::parse(
745 &[vec![tlv.t as u8, tlv.v.len() as u8, (tlv.v.len() >> 8) as u8], tlv.v.clone()]
746 .concat(),
747 ) {
748 Ok(pkt) => match pkt.specialize() {
749 FrameReportTlvPacketChild::Rssi(rssi) => {
750 rssi_vec.append(&mut rssi.get_rssi().clone())
751 }
752 FrameReportTlvPacketChild::Aoa(aoa) => {
753 aoa_vec.append(&mut aoa.get_aoa().clone())
754 }
755 FrameReportTlvPacketChild::Cir(cir) => {
756 cir_vec.append(&mut cir.get_cir_value().clone())
757 }
758 _ => return Err(Error::InvalidPacketError),
759 },
760 Err(e) => {
761 error!("Failed to parse the packet {:?}", e);
762 return Err(Error::InvalidPacketError);
763 }
764 }
765 }
766 parsed_frame_reports.push(ParsedFrameReport {
767 uwb_msg_id: report.uwb_msg_id,
768 action: report.action,
769 antenna_set: report.antenna_set,
770 rssi: rssi_vec,
771 aoa: aoa_vec,
772 cir: cir_vec,
773 });
774 }
775 Ok(ParsedDiagnosticNtfPacket {
776 session_token,
777 sequence_number,
778 frame_reports: parsed_frame_reports,
779 })
780 }
781
782 #[derive(Debug, Clone, PartialEq)]
783 pub enum Controlees {
784 NoSessionKey(Vec<Controlee>),
785 ShortSessionKey(Vec<Controlee_V2_0_16_Byte_Version>),
786 LongSessionKey(Vec<Controlee_V2_0_32_Byte_Version>),
787 }
788
789 // TODO(ziyiw): Replace these functions after making uwb_uci_packets::Controlee::write_to() public.
write_controlee(controlee: &Controlee) -> BytesMut790 pub fn write_controlee(controlee: &Controlee) -> BytesMut {
791 let mut buffer = BytesMut::new();
792 buffer.extend_from_slice(&controlee.short_address);
793 let subsession_id = controlee.subsession_id;
794 buffer.extend_from_slice(&subsession_id.to_le_bytes()[0..4]);
795 buffer
796 }
797
write_controlee_2_0_16byte(controlee: &Controlee_V2_0_16_Byte_Version) -> BytesMut798 pub fn write_controlee_2_0_16byte(controlee: &Controlee_V2_0_16_Byte_Version) -> BytesMut {
799 let mut buffer = BytesMut::new();
800 buffer.extend_from_slice(&controlee.short_address);
801 let subsession_id = controlee.subsession_id;
802 buffer.extend_from_slice(&subsession_id.to_le_bytes()[0..4]);
803 buffer.extend_from_slice(&controlee.subsession_key);
804 buffer
805 }
806
write_controlee_2_0_32byte(controlee: &Controlee_V2_0_32_Byte_Version) -> BytesMut807 pub fn write_controlee_2_0_32byte(controlee: &Controlee_V2_0_32_Byte_Version) -> BytesMut {
808 let mut buffer = BytesMut::new();
809 buffer.extend_from_slice(&controlee.short_address);
810 let subsession_id = controlee.subsession_id;
811 buffer.extend_from_slice(&subsession_id.to_le_bytes()[0..4]);
812 buffer.extend_from_slice(&controlee.subsession_key);
813 buffer
814 }
815
816 /// Generate the SessionUpdateControllerMulticastListCmd packet.
817 ///
818 /// This function can build the packet with/without message control, which
819 /// is indicated by action parameter.
build_session_update_controller_multicast_list_cmd( session_token: u32, action: UpdateMulticastListAction, controlees: Controlees, ) -> Result<SessionUpdateControllerMulticastListCmd>820 pub fn build_session_update_controller_multicast_list_cmd(
821 session_token: u32,
822 action: UpdateMulticastListAction,
823 controlees: Controlees,
824 ) -> Result<SessionUpdateControllerMulticastListCmd> {
825 let mut controlees_buf = BytesMut::new();
826 match controlees {
827 Controlees::NoSessionKey(controlee_v1)
828 if action == UpdateMulticastListAction::AddControlee
829 || action == UpdateMulticastListAction::RemoveControlee =>
830 {
831 controlees_buf.extend_from_slice(&(controlee_v1.len() as u8).to_le_bytes());
832 for controlee in controlee_v1 {
833 controlees_buf.extend_from_slice(&write_controlee(&controlee));
834 }
835 }
836 Controlees::ShortSessionKey(controlee_v2)
837 if action == UpdateMulticastListAction::AddControleeWithShortSubSessionKey =>
838 {
839 controlees_buf.extend_from_slice(&(controlee_v2.len() as u8).to_le_bytes());
840 for controlee in controlee_v2 {
841 controlees_buf.extend_from_slice(&write_controlee_2_0_16byte(&controlee));
842 }
843 }
844 Controlees::LongSessionKey(controlee_v2)
845 if action == UpdateMulticastListAction::AddControleeWithLongSubSessionKey =>
846 {
847 controlees_buf.extend_from_slice(&(controlee_v2.len() as u8).to_le_bytes());
848 for controlee in controlee_v2 {
849 controlees_buf.extend_from_slice(&write_controlee_2_0_32byte(&controlee));
850 }
851 }
852 _ => return Err(Error::InvalidPacketError),
853 }
854 Ok(SessionUpdateControllerMulticastListCmdBuilder {
855 session_token,
856 action,
857 payload: Some(controlees_buf.freeze()),
858 }
859 .build())
860 }
861
862 impl Drop for AppConfigTlv {
drop(&mut self)863 fn drop(&mut self) {
864 if self.cfg_id == AppConfigTlvType::VendorId || self.cfg_id == AppConfigTlvType::StaticStsIv
865 {
866 self.v.zeroize();
867 }
868 }
869 }
870
871 #[cfg(test)]
872 mod tests {
873 use super::*;
874
875 #[test]
test_parse_diagnostics_ntf()876 fn test_parse_diagnostics_ntf() {
877 let rssi_vec = vec![0x01, 0x02, 0x03];
878 let rssi = RssiBuilder { rssi: rssi_vec.clone() }.build();
879 let aoa_1 = AoaMeasurement { tdoa: 1, pdoa: 2, aoa: 3, fom: 4, t: 1 };
880 let aoa_2 = AoaMeasurement { tdoa: 5, pdoa: 6, aoa: 7, fom: 8, t: 2 };
881 let aoa = AoaBuilder { aoa: vec![aoa_1.clone(), aoa_2.clone()] }.build();
882 let cir_vec = vec![CirValue {
883 first_path_index: 1,
884 first_path_snr: 2,
885 first_path_ns: 3,
886 peak_path_index: 4,
887 peak_path_snr: 5,
888 peak_path_ns: 6,
889 first_path_sample_offset: 7,
890 samples_number: 2,
891 sample_window: vec![0, 1, 2, 3],
892 }];
893 let cir = CirBuilder { cir_value: cir_vec.clone() }.build();
894 let mut frame_reports = Vec::new();
895 let tlvs = vec![
896 FrameReportTlv { t: rssi.get_t(), v: rssi.get_rssi().to_vec() },
897 FrameReportTlv { t: aoa.get_t(), v: aoa.to_vec()[3..].to_vec() },
898 FrameReportTlv { t: cir.get_t(), v: cir.to_vec()[3..].to_vec() },
899 ];
900 let frame_report =
901 FrameReport { uwb_msg_id: 1, action: 1, antenna_set: 1, frame_report_tlvs: tlvs };
902 frame_reports.push(frame_report);
903 let packet = AndroidRangeDiagnosticsNtfBuilder {
904 session_token: 1,
905 sequence_number: 1,
906 frame_reports,
907 }
908 .build();
909 let mut parsed_packet = parse_diagnostics_ntf(packet).unwrap();
910 let parsed_frame_report = parsed_packet.frame_reports.pop().unwrap();
911 assert_eq!(rssi_vec, parsed_frame_report.rssi);
912 assert_eq!(aoa_1, parsed_frame_report.aoa[0]);
913 assert_eq!(aoa_2, parsed_frame_report.aoa[1]);
914 assert_eq!(cir_vec, parsed_frame_report.cir);
915 }
916
917 #[test]
test_write_controlee()918 fn test_write_controlee() {
919 let short_address: [u8; 2] = [2, 3];
920 let controlee: Controlee = Controlee { short_address, subsession_id: 3 };
921 let bytes = write_controlee(&controlee);
922 let parsed_controlee = Controlee::parse(&bytes).unwrap();
923 assert_eq!(controlee, parsed_controlee);
924 }
925
926 #[test]
test_build_multicast_update_packet()927 fn test_build_multicast_update_packet() {
928 let short_address: [u8; 2] = [0x12, 0x34];
929 let controlee = Controlee { short_address, subsession_id: 0x1324_3546 };
930 let packet: UciControlPacket = build_session_update_controller_multicast_list_cmd(
931 0x1425_3647,
932 UpdateMulticastListAction::AddControlee,
933 Controlees::NoSessionKey(vec![controlee; 1]),
934 )
935 .unwrap()
936 .into();
937 let packet_fragments: Vec<UciControlPacketHal> = packet.into();
938 let uci_packet: Vec<u8> = packet_fragments[0].clone().into();
939 assert_eq!(
940 uci_packet,
941 vec![
942 0x21, 0x07, 0x00, 0x0c, // 2(packet info), RFU, payload length(12)
943 0x47, 0x36, 0x25, 0x14, // 4(session id (LE))
944 0x00, 0x01, 0x12, 0x34, // action, # controlee, 2(short address (LE))
945 0x46, 0x35, 0x24, 0x13, // 4(subsession id (LE))
946 ]
947 );
948 }
949
950 #[test]
test_to_raw_payload()951 fn test_to_raw_payload() {
952 let payload = vec![0x11, 0x22, 0x33];
953 let payload_clone = payload.clone();
954 let packet = UciControlPacketBuilder {
955 group_id: GroupId::Test,
956 message_type: MessageType::Response,
957 opcode: 0x5,
958 payload: Some(payload_clone.into()),
959 }
960 .build();
961
962 assert_eq!(payload, packet.to_raw_payload());
963 }
964
965 #[test]
test_to_raw_payload_empty()966 fn test_to_raw_payload_empty() {
967 let payload: Vec<u8> = vec![];
968 let packet = UciControlPacketBuilder {
969 group_id: GroupId::Test,
970 message_type: MessageType::Response,
971 opcode: 0x5,
972 payload: None,
973 }
974 .build();
975
976 assert_eq!(payload, packet.to_raw_payload());
977 }
978
979 #[cfg(test)]
980 mod tests {
981 use crate::{extract_u16, extract_u32, extract_u64, extract_u8, extract_vec};
982 #[test]
test_extract_func()983 fn test_extract_func() {
984 let bytes = [0x1, 0x3, 0x5, 0x7, 0x9, 0x2, 0x4, 0x05, 0x07, 0x09, 0x0a];
985 let mut ptr = 0;
986
987 let u8_val = extract_u8(&bytes, &mut ptr, 1);
988 assert_eq!(u8_val, Some(0x1));
989 assert_eq!(ptr, 1);
990
991 let u16_val = extract_u16(&bytes, &mut ptr, 2);
992 assert_eq!(u16_val, Some(0x0503));
993 assert_eq!(ptr, 3);
994
995 let u32_val = extract_u32(&bytes, &mut ptr, 3);
996 assert_eq!(u32_val, Some(0x020907));
997 assert_eq!(ptr, 6);
998
999 let u64_val = extract_u64(&bytes, &mut ptr, 5);
1000 assert_eq!(u64_val, Some(0x0a09070504));
1001 assert_eq!(ptr, 11);
1002
1003 let vec = extract_vec(&bytes, &mut ptr, 3);
1004 assert_eq!(vec, None);
1005 assert_eq!(ptr, 11);
1006 }
1007 }
1008
1009 #[test]
test_short_dltdoa_ranging_measurement()1010 fn test_short_dltdoa_ranging_measurement() {
1011 let bytes = [
1012 // All Fields in Little Endian (LE)
1013 // First measurement
1014 0x0a, 0x01, 0x33, 0x05, // 2(Mac address), Status, Message Type
1015 0x33, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
1016 0x07, 0x09, 0x0a, 0x01, // Round Index, NLoS, 2(AoA Azimuth)
1017 0x02, 0x05, 0x07, 0x09, // AoA Azimuth FOM, 2(AoA Elevation), AoA Elevation FOM
1018 0x0a, 0x01, 0x02, 0x05, // RSSI, 3(Tx Timestamp..)
1019 0x07, 0x09, 0x0a, 0x01, // 4(Tx Timestamp..)
1020 0x02, 0x05, 0x07, 0x09, // Tx Timestamp, 3(Rx Timestamp..)
1021 0x05, 0x07, 0x09, 0x0a, // 2(Rx Timestamp), 2(Anchor Cfo)
1022 0x01, 0x02, 0x05, 0x07, // 2(Cfo), 2(Initiator Reply Time..)
1023 0x09, 0x05, 0x07, 0x09, // 2(Initiator Reply Time), 2(Responder Reply Time..)
1024 0x0a, 0x01, 0x02, 0x05, // 2(Responder Reply Time), 2(Initiator-Responder ToF)
1025 0x07, 0x09, 0x07, 0x09, // 4(Anchor Location..)
1026 0x05, 0x07, 0x09, 0x0a, // 4(Anchor Location..)
1027 0x01, 0x02, 0x05, 0x07, // 2(Anchor Location..), 2(Active Ranging Rounds..)
1028 0x09, 0x0a, 0x01, 0x02, // 4(Active Ranging Rounds..)
1029 0x05, 0x07, 0x09, 0x05, // 4(Active Ranging Rounds)
1030 // Second measurement
1031 0x0a, 0x01, 0x33, 0x05, // 2(Mac address), Status, Message Type
1032 0x33, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
1033 0x07, 0x09, 0x0a, 0x01, // Round Index, NLoS, 2(AoA Azimuth)
1034 0x02, 0x05, 0x07, 0x09, // AoA Azimuth FOM, 2(AoA Elevation), AoA Elevation FOM
1035 0x0a, 0x01, 0x02, 0x05, // RSSI, 3(Tx Timestamp..)
1036 0x07, 0x09, 0x0a, 0x01, // 4(Tx Timestamp..)
1037 0x02, 0x05, 0x07, 0x09, // Tx Timestamp, 3(Rx Timestamp..)
1038 0x05, 0x07, 0x09, 0x0a, // 2(Rx Timestamp), 2(Anchor Cfo)
1039 0x01, 0x02, 0x05, 0x07, // 2(Cfo), 2(Initiator Reply Time..)
1040 0x09, 0x05, 0x07, 0x09, // 2(Initiator Reply Time), 2(Responder Reply Time..)
1041 0x0a, 0x01, 0x02, 0x05, // 2(Responder Reply Time), 2(Initiator-Responder ToF)
1042 0x07, 0x09, 0x07, 0x09, // 4(Anchor Location..)
1043 0x05, 0x07, 0x09, 0x0a, // 4(Anchor Location..)
1044 0x01, 0x02, 0x05, 0x07, // 2(Anchor Location..), 2(Active Ranging Rounds..)
1045 0x09, 0x0a, 0x01, 0x02, // 4(Active Ranging Rounds..)
1046 0x05, 0x07, 0x09, 0x05, // 4(Active Ranging Rounds)
1047 ];
1048
1049 let measurements = ShortAddressDlTdoaRangingMeasurement::parse(&bytes, 2).unwrap();
1050 assert_eq!(measurements.len(), 2);
1051 let measurement_1 = &measurements[0].measurement;
1052 let mac_address_1 = &measurements[0].mac_address;
1053 assert_eq!(*mac_address_1, 0x010a);
1054 assert_eq!(measurement_1.status, 0x33);
1055 assert_eq!(measurement_1.message_type, 0x05);
1056 assert_eq!(measurement_1.message_control, 0x0533);
1057 assert_eq!(measurement_1.block_index, 0x0502);
1058 assert_eq!(measurement_1.round_index, 0x07);
1059 assert_eq!(measurement_1.nlos, 0x09);
1060 assert_eq!(measurement_1.aoa_azimuth, 0x010a);
1061 assert_eq!(measurement_1.aoa_azimuth_fom, 0x02);
1062 assert_eq!(measurement_1.aoa_elevation, 0x0705);
1063 assert_eq!(measurement_1.aoa_elevation_fom, 0x09);
1064 assert_eq!(measurement_1.rssi, 0x0a);
1065 assert_eq!(measurement_1.tx_timestamp, 0x02010a0907050201);
1066 assert_eq!(measurement_1.rx_timestamp, 0x0705090705);
1067 assert_eq!(measurement_1.anchor_cfo, 0x0a09);
1068 assert_eq!(measurement_1.cfo, 0x0201);
1069 assert_eq!(measurement_1.initiator_reply_time, 0x05090705);
1070 assert_eq!(measurement_1.responder_reply_time, 0x010a0907);
1071 assert_eq!(measurement_1.initiator_responder_tof, 0x0502);
1072 assert_eq!(
1073 measurement_1.dt_anchor_location,
1074 vec![0x07, 0x09, 0x07, 0x09, 0x05, 0x07, 0x09, 0x0a, 0x01, 0x02]
1075 );
1076 assert_eq!(
1077 measurement_1.ranging_rounds,
1078 vec![0x05, 0x07, 0x09, 0x0a, 0x01, 0x02, 0x05, 0x07, 0x09, 0x05,]
1079 );
1080
1081 let measurement_2 = &measurements[1].measurement;
1082 let mac_address_2 = &measurements[1].mac_address;
1083 assert_eq!(*mac_address_2, 0x010a);
1084 assert_eq!(measurement_2.status, 0x33);
1085 assert_eq!(measurement_2.message_type, 0x05);
1086 assert_eq!(measurement_2.message_control, 0x0533);
1087 assert_eq!(measurement_2.block_index, 0x0502);
1088 assert_eq!(measurement_2.round_index, 0x07);
1089 assert_eq!(measurement_2.nlos, 0x09);
1090 assert_eq!(measurement_2.aoa_azimuth, 0x010a);
1091 assert_eq!(measurement_2.aoa_azimuth_fom, 0x02);
1092 assert_eq!(measurement_2.aoa_elevation, 0x0705);
1093 assert_eq!(measurement_2.aoa_elevation_fom, 0x09);
1094 assert_eq!(measurement_2.rssi, 0x0a);
1095 assert_eq!(measurement_2.tx_timestamp, 0x02010a0907050201);
1096 assert_eq!(measurement_2.rx_timestamp, 0x0705090705);
1097 assert_eq!(measurement_2.anchor_cfo, 0x0a09);
1098 assert_eq!(measurement_2.cfo, 0x0201);
1099 assert_eq!(measurement_2.initiator_reply_time, 0x05090705);
1100 assert_eq!(measurement_2.responder_reply_time, 0x010a0907);
1101 assert_eq!(measurement_2.initiator_responder_tof, 0x0502);
1102 assert_eq!(
1103 measurement_1.dt_anchor_location,
1104 vec![0x07, 0x09, 0x07, 0x09, 0x05, 0x07, 0x09, 0x0a, 0x01, 0x02]
1105 );
1106 assert_eq!(
1107 measurement_1.ranging_rounds,
1108 vec![0x05, 0x07, 0x09, 0x0a, 0x01, 0x02, 0x05, 0x07, 0x09, 0x05,]
1109 );
1110 }
1111
1112 #[test]
test_extended_dltdoa_ranging_measurement()1113 fn test_extended_dltdoa_ranging_measurement() {
1114 let bytes = [
1115 // All Fields in Little Endian (LE)
1116 /* First measurement */
1117 0x0a, 0x01, 0x33, 0x05, // 4(Mac address..)
1118 0x33, 0x05, 0x02, 0x05, // 4(Mac address)
1119 0x07, 0x09, 0x0a, 0x01, // Status, Message Type, 2(Message control),
1120 0x02, 0x05, 0x07, 0x09, // 2(Block Index), Round Index, NLoS,
1121 0x0a, 0x01, 0x02, 0x05, // 2(AoA Azimuth), AoA Azimuth FOM, 1(AoA Elevation..)
1122 0x07, 0x09, 0x0a, // 1(AoA Elevation), AoA Elevation FOM, RSSI,
1123 0x01, 0x02, 0x05, 0x07, // 4(Tx Timestamp..)
1124 0x09, 0x05, 0x07, 0x09, // 4(Tx Timestamp),
1125 0x0a, 0x01, 0x02, 0x05, // 4(Rx Timestamp..)
1126 0x07, 0x09, 0x05, 0x07, // 4(Rx Timestamp)
1127 0x09, 0x0a, 0x01, 0x02, // 2(Anchor Cfo), 2(Cfo),
1128 0x05, 0x07, 0x09, 0x05, // 4(Initiator Reply Time)
1129 0x07, 0x09, 0x0a, 0x01, // 4(Responder Reply Time),
1130 0x02, 0x05, 0x02, 0x05, // 2(Initiator-Responder ToF), 2(Active Ranging Rounds)
1131 ];
1132
1133 let measurements = ExtendedAddressDlTdoaRangingMeasurement::parse(&bytes, 1).unwrap();
1134 assert_eq!(measurements.len(), 1);
1135 let measurement = &measurements[0].measurement;
1136 let mac_address = &measurements[0].mac_address;
1137 assert_eq!(*mac_address, 0x050205330533010a);
1138 assert_eq!(measurement.message_control, 0x010a);
1139 assert_eq!(measurement.block_index, 0x0502);
1140 assert_eq!(measurement.round_index, 0x07);
1141 assert_eq!(measurement.nlos, 0x09);
1142 assert_eq!(measurement.aoa_azimuth, 0x010a);
1143 assert_eq!(measurement.aoa_azimuth_fom, 0x02);
1144 assert_eq!(measurement.aoa_elevation, 0x0705);
1145 assert_eq!(measurement.aoa_elevation_fom, 0x09);
1146 assert_eq!(measurement.rssi, 0x0a);
1147 assert_eq!(measurement.tx_timestamp, 0x0907050907050201);
1148 assert_eq!(measurement.rx_timestamp, 0x070509070502010a);
1149 assert_eq!(measurement.anchor_cfo, 0x0a09);
1150 assert_eq!(measurement.cfo, 0x0201);
1151 assert_eq!(measurement.initiator_reply_time, 0x05090705);
1152 assert_eq!(measurement.responder_reply_time, 0x010a0907);
1153 assert_eq!(measurement.initiator_responder_tof, 0x0502);
1154 assert_eq!(measurement.dt_anchor_location, vec![]);
1155 assert_eq!(measurement.ranging_rounds, vec![0x02, 0x05]);
1156 }
1157 }
1158