• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Radar field lengths
57 pub const UCI_RADAR_SEQUENCE_NUMBER_LEN: usize = 4;
58 pub const UCI_RADAR_TIMESTAMP_LEN: usize = 4;
59 pub const UCI_RADAR_VENDOR_DATA_LEN_LEN: usize = 1;
60 
61 #[derive(Debug, Clone, PartialEq, FromPrimitive)]
62 pub enum TimeStampLength {
63     Timestamp40Bit = 0x0,
64     Timestamp64Bit = 0x1,
65 }
66 
67 #[derive(Debug, Clone, PartialEq, FromPrimitive)]
68 pub enum DTAnchorLocationType {
69     NotIncluded = 0x0,
70     Wgs84 = 0x1,
71     Relative = 0x2,
72 }
73 
74 #[allow(dead_code)]
75 #[derive(Debug, Clone, PartialEq)]
76 pub struct DlTdoaRangingMeasurement {
77     pub status: u8,
78     pub message_type: u8,
79     pub message_control: u16,
80     pub block_index: u16,
81     pub round_index: u8,
82     pub nlos: u8,
83     pub aoa_azimuth: u16,
84     pub aoa_azimuth_fom: u8,
85     pub aoa_elevation: u16,
86     pub aoa_elevation_fom: u8,
87     pub rssi: u8,
88     pub tx_timestamp: u64,
89     pub rx_timestamp: u64,
90     pub anchor_cfo: u16,
91     pub cfo: u16,
92     pub initiator_reply_time: u32,
93     pub responder_reply_time: u32,
94     pub initiator_responder_tof: u16,
95     pub dt_anchor_location: Vec<u8>,
96     pub ranging_rounds: Vec<u8>,
97     total_size: usize,
98 }
99 
100 impl DlTdoaRangingMeasurement {
parse_one(bytes: &[u8]) -> Option<Self>101     pub fn parse_one(bytes: &[u8]) -> Option<Self> {
102         let mut ptr = 0;
103         let status = extract_u8(bytes, &mut ptr, 1)?;
104         let message_type = extract_u8(bytes, &mut ptr, 1)?;
105         let message_control = extract_u16(bytes, &mut ptr, 2)?;
106         let block_index = extract_u16(bytes, &mut ptr, 2)?;
107         let round_index = extract_u8(bytes, &mut ptr, 1)?;
108         let nlos = extract_u8(bytes, &mut ptr, 1)?;
109         let aoa_azimuth = extract_u16(bytes, &mut ptr, 2)?;
110         let aoa_azimuth_fom = extract_u8(bytes, &mut ptr, 1)?;
111         let aoa_elevation = extract_u16(bytes, &mut ptr, 2)?;
112         let aoa_elevation_fom = extract_u8(bytes, &mut ptr, 1)?;
113         let rssi = extract_u8(bytes, &mut ptr, 1)?;
114         let tx_timestamp_length = (message_control >> 1) & 0x1;
115         let tx_timestamp = match TimeStampLength::from_u16(tx_timestamp_length)? {
116             TimeStampLength::Timestamp40Bit => extract_u64(bytes, &mut ptr, 5)?,
117             TimeStampLength::Timestamp64Bit => extract_u64(bytes, &mut ptr, 8)?,
118         };
119         let rx_timestamp_length = (message_control >> 3) & 0x1;
120         let rx_timestamp = match TimeStampLength::from_u16(rx_timestamp_length)? {
121             TimeStampLength::Timestamp40Bit => extract_u64(bytes, &mut ptr, 5)?,
122             TimeStampLength::Timestamp64Bit => extract_u64(bytes, &mut ptr, 8)?,
123         };
124         let anchor_cfo = extract_u16(bytes, &mut ptr, 2)?;
125         let cfo = extract_u16(bytes, &mut ptr, 2)?;
126         let initiator_reply_time = extract_u32(bytes, &mut ptr, 4)?;
127         let responder_reply_time = extract_u32(bytes, &mut ptr, 4)?;
128         let initiator_responder_tof = extract_u16(bytes, &mut ptr, 2)?;
129         let dt_location_type = (message_control >> 5) & 0x3;
130         let dt_anchor_location = match DTAnchorLocationType::from_u16(dt_location_type)? {
131             DTAnchorLocationType::Wgs84 => extract_vec(bytes, &mut ptr, 12)?,
132             DTAnchorLocationType::Relative => extract_vec(bytes, &mut ptr, 10)?,
133             _ => vec![],
134         };
135         let active_ranging_rounds = ((message_control >> 7) & 0xf) as u8;
136         let ranging_round = extract_vec(bytes, &mut ptr, active_ranging_rounds as usize)?;
137 
138         Some(DlTdoaRangingMeasurement {
139             status,
140             message_type,
141             message_control,
142             block_index,
143             round_index,
144             nlos,
145             aoa_azimuth,
146             aoa_azimuth_fom,
147             aoa_elevation,
148             aoa_elevation_fom,
149             rssi,
150             tx_timestamp,
151             rx_timestamp,
152             anchor_cfo,
153             cfo,
154             initiator_reply_time,
155             responder_reply_time,
156             initiator_responder_tof,
157             dt_anchor_location: dt_anchor_location.to_vec(),
158             ranging_rounds: ranging_round.to_vec(),
159             total_size: ptr,
160         })
161     }
get_total_size(&self) -> usize162     pub fn get_total_size(&self) -> usize {
163         self.total_size
164     }
165 }
166 
167 #[derive(Debug, Clone, PartialEq)]
168 pub struct ShortAddressDlTdoaRangingMeasurement {
169     pub mac_address: u16,
170     pub measurement: DlTdoaRangingMeasurement,
171 }
172 
173 impl ShortAddressDlTdoaRangingMeasurement {
174     /// Parse the `payload` byte buffer from PDL to the vector of measurement.
parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>>175     pub fn parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>> {
176         let mut ptr = 0;
177         let mut measurements = vec![];
178         let mut count = 0;
179         while (count < no_of_ranging_measurement) {
180             let mac_address = extract_u16(bytes, &mut ptr, 2)?;
181             let rem = &bytes[ptr..];
182             let measurement = DlTdoaRangingMeasurement::parse_one(rem);
183             match measurement {
184                 Some(measurement) => {
185                     ptr += measurement.get_total_size();
186                     measurements
187                         .push(ShortAddressDlTdoaRangingMeasurement { mac_address, measurement });
188                     count = count + 1;
189                 }
190                 None => return None,
191             }
192         }
193         Some(measurements)
194     }
195 }
196 
197 #[derive(Debug, Clone, PartialEq)]
198 pub struct ExtendedAddressDlTdoaRangingMeasurement {
199     pub mac_address: u64,
200     pub measurement: DlTdoaRangingMeasurement,
201 }
202 
203 impl ExtendedAddressDlTdoaRangingMeasurement {
204     /// Parse the `payload` byte buffer from PDL to the vector of measurement.
parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>>205     pub fn parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>> {
206         let mut ptr = 0;
207         let mut measurements = vec![];
208         let mut count = 0;
209         while (count < no_of_ranging_measurement) {
210             let mac_address = extract_u64(bytes, &mut ptr, 8)?;
211             let rem = &bytes[ptr..];
212             let measurement = DlTdoaRangingMeasurement::parse_one(rem);
213             match measurement {
214                 Some(measurement) => {
215                     ptr += measurement.get_total_size();
216                     measurements
217                         .push(ExtendedAddressDlTdoaRangingMeasurement { mac_address, measurement });
218                     count = count + 1;
219                 }
220                 None => return None,
221             }
222         }
223         Some(measurements)
224     }
225 }
226 
extract_vec(bytes: &[u8], ptr: &mut usize, consumed_size: usize) -> Option<Vec<u8>>227 pub fn extract_vec(bytes: &[u8], ptr: &mut usize, consumed_size: usize) -> Option<Vec<u8>> {
228     if bytes.len() < *ptr + consumed_size {
229         return None;
230     }
231 
232     let res = bytes[*ptr..*ptr + consumed_size].to_vec();
233     *ptr += consumed_size;
234     Some(res)
235 }
236 
237 /// Generate the function that extracts the value from byte buffers.
238 macro_rules! generate_extract_func {
239     ($func_name:ident, $type:ty) => {
240         /// Extract the value from |byte[ptr..ptr + consumed_size]| in little endian.
241         fn $func_name(bytes: &[u8], ptr: &mut usize, consumed_size: usize) -> Option<$type> {
242             const type_size: usize = std::mem::size_of::<$type>();
243             if consumed_size > type_size {
244                 return None;
245             }
246 
247             let extracted_bytes = extract_vec(bytes, ptr, consumed_size)?;
248             let mut le_bytes = [0; type_size];
249             le_bytes[0..consumed_size].copy_from_slice(&extracted_bytes);
250             Some(<$type>::from_le_bytes(le_bytes))
251         }
252     };
253 }
254 
255 generate_extract_func!(extract_u8, u8);
256 generate_extract_func!(extract_u16, u16);
257 generate_extract_func!(extract_u32, u32);
258 generate_extract_func!(extract_u64, u64);
259 
260 // The GroupIdOrDataPacketFormat enum has all the values defined in both the GroupId and
261 // DataPacketFormat enums. It represents the same bits in UCI packet header - the GID field in
262 // a UCI control packet, and the DataPacketFormat field in a UCI data packet. Hence the unwrap()
263 // calls in the conversions below should always succeed (as long as care is taken in future, to
264 // keep the two enums in sync, for any additional values defined in the UCI spec).
265 impl From<GroupId> for GroupIdOrDataPacketFormat {
from(gid: GroupId) -> Self266     fn from(gid: GroupId) -> Self {
267         GroupIdOrDataPacketFormat::try_from(u8::from(gid)).unwrap()
268     }
269 }
270 
271 impl From<GroupIdOrDataPacketFormat> for GroupId {
from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Self272     fn from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Self {
273         GroupId::try_from(u8::from(gid_or_dpf)).unwrap()
274     }
275 }
276 
277 impl From<DataPacketFormat> for GroupIdOrDataPacketFormat {
from(dpf: DataPacketFormat) -> Self278     fn from(dpf: DataPacketFormat) -> Self {
279         GroupIdOrDataPacketFormat::try_from(u8::from(dpf)).unwrap()
280     }
281 }
282 
283 // The GroupIdOrDataPacketFormat enum has more values defined (for the GroupId bits) than the
284 // DataPacketFormat enum. Hence this is implemented as TryFrom() instead of From().
285 impl TryFrom<GroupIdOrDataPacketFormat> for DataPacketFormat {
286     type Error = DecodeError;
287 
try_from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Result<Self, DecodeError>288     fn try_from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Result<Self, DecodeError> {
289         DataPacketFormat::try_from(u8::from(gid_or_dpf)).or(Err(DecodeError::InvalidPacketError))
290     }
291 }
292 
293 // Container for UCI packet header fields.
294 struct UciControlPacketHeader {
295     message_type: MessageType,
296     group_id: GroupId,
297     opcode: u8,
298 }
299 
300 impl UciControlPacketHeader {
new(message_type: MessageType, group_id: GroupId, opcode: u8) -> Result<Self, DecodeError>301     fn new(message_type: MessageType, group_id: GroupId, opcode: u8) -> Result<Self, DecodeError> {
302         if !is_uci_control_packet(message_type) {
303             return Err(DecodeError::InvalidPacketError);
304         }
305 
306         Ok(UciControlPacketHeader {
307             message_type: message_type,
308             group_id: group_id,
309             opcode: opcode,
310         })
311     }
312 }
313 
314 // Helper methods to extract the UCI Packet header fields.
get_mt_from_uci_packet(packet: &[u8]) -> u8315 fn get_mt_from_uci_packet(packet: &[u8]) -> u8 {
316     (packet[UCI_HEADER_MT_BYTE_POSITION] >> UCI_HEADER_MT_BIT_SHIFT) & UCI_HEADER_MT_MASK
317 }
318 
get_pbf_from_uci_packet(packet: &[u8]) -> u8319 fn get_pbf_from_uci_packet(packet: &[u8]) -> u8 {
320     (packet[UCI_HEADER_PBF_BYTE_POSITION] >> UCI_HEADER_PBF_BIT_SHIFT) & UCI_HEADER_PBF_MASK
321 }
322 
get_gid_from_uci_control_packet(packet: &[u8]) -> u8323 fn get_gid_from_uci_control_packet(packet: &[u8]) -> u8 {
324     packet[UCI_CONTROL_HEADER_GID_BYTE_POSITION] & UCI_CONTROL_HEADER_GID_MASK
325 }
326 
get_oid_from_uci_control_packet(packet: &[u8]) -> u8327 fn get_oid_from_uci_control_packet(packet: &[u8]) -> u8 {
328     packet[UCI_CONTROL_HEADER_OID_BYTE_POSITION] & UCI_CONTROL_HEADER_OID_MASK
329 }
330 
331 // This function parses the packet bytes to return the Control Packet Opcode (OID) field. The
332 // caller should check that the packet bytes represent a UCI control packet. The code will not
333 // panic because UciPacketHal::encode_to_bytes() should always be larger then the place we access.
get_opcode_from_uci_control_packet(packet: &UciPacketHal) -> u8334 fn get_opcode_from_uci_control_packet(packet: &UciPacketHal) -> u8 {
335     get_oid_from_uci_control_packet(&packet.encode_to_bytes().unwrap())
336 }
337 
is_uci_control_packet(message_type: MessageType) -> bool338 fn is_uci_control_packet(message_type: MessageType) -> bool {
339     match message_type {
340         MessageType::Command
341         | MessageType::Response
342         | MessageType::Notification
343         | MessageType::ReservedForTesting1
344         | MessageType::ReservedForTesting2 => true,
345         _ => false,
346     }
347 }
348 
build_uci_control_packet( message_type: MessageType, group_id: GroupId, opcode: u8, payload: Option<Bytes>, ) -> Option<UciControlPacket>349 pub fn build_uci_control_packet(
350     message_type: MessageType,
351     group_id: GroupId,
352     opcode: u8,
353     payload: Option<Bytes>,
354 ) -> Option<UciControlPacket> {
355     if !is_uci_control_packet(message_type) {
356         error!("Only control packets are allowed, MessageType: {message_type:?}");
357         return None;
358     }
359     Some(UciControlPacketBuilder { group_id, message_type, opcode, payload }.build())
360 }
361 
362 // Ensure that the new packet fragment belong to the same packet.
is_same_control_packet(header: &UciControlPacketHeader, packet: &UciPacketHal) -> bool363 fn is_same_control_packet(header: &UciControlPacketHeader, packet: &UciPacketHal) -> bool {
364     is_uci_control_packet(header.message_type)
365         && header.message_type == packet.get_message_type()
366         && header.group_id == packet.get_group_id_or_data_packet_format().into()
367         && header.opcode == get_opcode_from_uci_control_packet(packet)
368 }
369 
is_device_state_err_control_packet(packet: &UciPacketHal) -> bool370 fn is_device_state_err_control_packet(packet: &UciPacketHal) -> bool {
371     packet.get_message_type() == MessageType::Notification.into()
372         && packet.get_group_id_or_data_packet_format() == GroupIdOrDataPacketFormat::Core.into()
373         && get_opcode_from_uci_control_packet(packet) == CoreOpCode::CoreDeviceStatusNtf.into()
374         && packet.encode_to_vec().unwrap()[UCI_PACKET_HAL_HEADER_LEN]
375             == DeviceState::DeviceStateError.into()
376 }
377 
378 impl UciControlPacket {
379     // For some usage, we need to get the raw payload.
to_raw_payload(self) -> Vec<u8>380     pub fn to_raw_payload(self) -> Vec<u8> {
381         self.encode_to_bytes().unwrap().slice(UCI_PACKET_HEADER_LEN..).to_vec()
382     }
383 }
384 
385 // Helper to convert from vector of |UciPacketHal| to |UciControlPacket|. An example
386 // usage is to convert a list UciPacketHAL fragments to one UciPacket, during de-fragmentation.
387 impl TryFrom<Vec<UciPacketHal>> for UciControlPacket {
388     type Error = DecodeError;
389 
try_from(packets: Vec<UciPacketHal>) -> Result<Self, DecodeError>390     fn try_from(packets: Vec<UciPacketHal>) -> Result<Self, DecodeError> {
391         if packets.is_empty() {
392             return Err(DecodeError::InvalidPacketError);
393         }
394 
395         // Store header info from the first packet.
396         let header = UciControlPacketHeader::new(
397             packets[0].get_message_type(),
398             packets[0].get_group_id_or_data_packet_format().into(),
399             get_opcode_from_uci_control_packet(&packets[0]),
400         )?;
401 
402         // Create the reassembled payload.
403         let mut payload_buf = BytesMut::new();
404         for packet in packets {
405             // Ensure that the new fragment is part of the same packet.
406             if !is_same_control_packet(&header, &packet) {
407                 // if DEVICE_STATE_ERROR notification is received while waiting for remaining fragments,
408                 // process it and send to upper layer for device recovery
409                 if is_device_state_err_control_packet(&packet) {
410                     error!("Received device reset error: {:?}", packet);
411                     return UciControlPacket::parse(
412                         &UciControlPacketBuilder {
413                             message_type: packet.get_message_type(),
414                             group_id: packet.get_group_id_or_data_packet_format().into(),
415                             opcode: get_opcode_from_uci_control_packet(&packet),
416                             payload: Some(
417                                 packet
418                                     .encode_to_bytes()
419                                     .unwrap()
420                                     .slice(UCI_PACKET_HAL_HEADER_LEN..),
421                             ),
422                         }
423                         .build()
424                         .encode_to_bytes()
425                         .unwrap(),
426                     );
427                 }
428                 error!("Received unexpected fragment: {:?}", packet);
429                 return Err(DecodeError::InvalidPacketError);
430             }
431             // get payload by stripping the header.
432             payload_buf.extend_from_slice(
433                 &packet.encode_to_bytes().unwrap().slice(UCI_PACKET_HAL_HEADER_LEN..),
434             )
435         }
436 
437         // Create assembled |UciControlPacket| and convert to bytes again since we need to
438         // reparse the packet after defragmentation to get the appropriate message.
439         UciControlPacket::parse(
440             &UciControlPacketBuilder {
441                 message_type: header.message_type,
442                 group_id: header.group_id,
443                 opcode: header.opcode,
444                 payload: Some(payload_buf.into()),
445             }
446             .build()
447             .encode_to_bytes()
448             .unwrap(),
449         )
450     }
451 }
452 
453 #[derive(Debug, Clone)]
454 pub struct RawUciControlPacket {
455     pub mt: u8,
456     pub gid: u8,
457     pub oid: u8,
458     pub payload: Vec<u8>,
459 }
460 
461 impl RawUciControlPacket {
462     // Match the GID and OID to confirm the UCI packet (represented by header) is
463     // the same as the stored signature. We don't match the MT because they can be
464     // different (eg: CMD/RSP pair).
is_same_signature_bytes(&self, header: &[u8]) -> bool465     pub fn is_same_signature_bytes(&self, header: &[u8]) -> bool {
466         let gid = get_gid_from_uci_control_packet(header);
467         let oid = get_oid_from_uci_control_packet(header);
468         gid == self.gid && oid == self.oid
469     }
470 }
471 
is_uci_data_packet(message_type: MessageType) -> bool472 fn is_uci_data_packet(message_type: MessageType) -> bool {
473     message_type == MessageType::Data
474 }
475 
is_data_rcv_or_radar_format(data_packet_format: DataPacketFormat) -> bool476 fn is_data_rcv_or_radar_format(data_packet_format: DataPacketFormat) -> bool {
477     data_packet_format == DataPacketFormat::DataRcv
478         || data_packet_format == DataPacketFormat::RadarDataMessage
479 }
480 
try_into_data_payload( packet: UciPacketHal, expected_data_packet_format: DataPacketFormat, ) -> Result<Bytes, DecodeError>481 fn try_into_data_payload(
482     packet: UciPacketHal,
483     expected_data_packet_format: DataPacketFormat,
484 ) -> Result<Bytes, DecodeError> {
485     let dpf: DataPacketFormat = packet.get_group_id_or_data_packet_format().try_into()?;
486     if is_uci_data_packet(packet.get_message_type()) && dpf == expected_data_packet_format {
487         Ok(packet.encode_to_bytes().unwrap().slice(UCI_PACKET_HAL_HEADER_LEN..))
488     } else {
489         error!("Received unexpected data packet fragment: {:?}", packet);
490         Err(DecodeError::InvalidPacketError)
491     }
492 }
493 
494 // Helper to convert from vector of |UciPacketHal| to |UciDataPacket|. An example
495 // usage is to convert a list UciPacketHAL fragments to one UciPacket, during de-fragmentation.
496 impl TryFrom<Vec<UciPacketHal>> for UciDataPacket {
497     type Error = DecodeError;
498 
try_from(packets: Vec<UciPacketHal>) -> Result<Self, DecodeError>499     fn try_from(packets: Vec<UciPacketHal>) -> Result<Self, DecodeError> {
500         if packets.is_empty() {
501             return Err(DecodeError::InvalidPacketError);
502         }
503 
504         let dpf: DataPacketFormat = packets[0].get_group_id_or_data_packet_format().try_into()?;
505         if !is_data_rcv_or_radar_format(dpf) {
506             error!("Unexpected data packet format {:?}", dpf);
507         }
508 
509         // Create the reassembled payload.
510         let mut payload_buf = Bytes::new();
511         for packet in packets {
512             // Ensure that the fragment is a Data Rcv packet.
513             // Get payload by stripping the header.
514             payload_buf = [payload_buf, try_into_data_payload(packet, dpf)?].concat().into();
515         }
516 
517         // Create assembled |UciDataPacket| and convert to bytes again since we need to
518         // reparse the packet after defragmentation to get the appropriate message.
519         UciDataPacket::parse(
520             &UciDataPacketBuilder {
521                 message_type: MessageType::Data,
522                 data_packet_format: dpf,
523                 payload: Some(payload_buf.into()),
524             }
525             .build()
526             .encode_to_bytes()
527             .unwrap(),
528         )
529     }
530 }
531 
532 // Helper to convert from |UciControlPacket| to vector of |UciControlPacketHal|s. An
533 // example usage is to do this conversion for fragmentation (from Host to UWBS).
534 impl From<UciControlPacket> for Vec<UciControlPacketHal> {
from(packet: UciControlPacket) -> Self535     fn from(packet: UciControlPacket) -> Self {
536         // Store header info.
537         let header = match UciControlPacketHeader::new(
538             packet.get_message_type(),
539             packet.get_group_id(),
540             packet.get_opcode(),
541         ) {
542             Ok(hdr) => hdr,
543             _ => {
544                 error!(
545                     "Unable to parse UciControlPacketHeader from UciControlPacket: {:?}",
546                     packet
547                 );
548                 return Vec::new();
549             }
550         };
551 
552         let mut fragments = Vec::new();
553         // get payload by stripping the header.
554         let payload = packet.encode_to_bytes().unwrap().slice(UCI_PACKET_HEADER_LEN..);
555         if payload.is_empty() {
556             fragments.push(
557                 UciControlPacketHalBuilder {
558                     message_type: header.message_type,
559                     group_id_or_data_packet_format: header.group_id.into(),
560                     opcode: header.opcode,
561                     packet_boundary_flag: PacketBoundaryFlag::Complete,
562                     payload: None,
563                 }
564                 .build(),
565             );
566         } else {
567             let mut fragments_iter = payload.chunks(MAX_PAYLOAD_LEN).peekable();
568             while let Some(fragment) = fragments_iter.next() {
569                 // Set the last fragment complete if this is last fragment.
570                 let pbf = if let Some(nxt_fragment) = fragments_iter.peek() {
571                     PacketBoundaryFlag::NotComplete
572                 } else {
573                     PacketBoundaryFlag::Complete
574                 };
575                 fragments.push(
576                     UciControlPacketHalBuilder {
577                         message_type: header.message_type,
578                         group_id_or_data_packet_format: header.group_id.into(),
579                         opcode: header.opcode,
580                         packet_boundary_flag: pbf,
581                         payload: Some(Bytes::from(fragment.to_owned())),
582                     }
583                     .build(),
584                 );
585             }
586         }
587         fragments
588     }
589 }
590 
591 // Helper to convert From<UciDataSnd> into Vec<UciDataPacketHal>. An
592 // example usage is for fragmentation in the Data Packet Tx flow.
fragment_data_msg_send(packet: UciDataSnd, max_payload_len: usize) -> Vec<UciDataPacketHal>593 pub fn fragment_data_msg_send(packet: UciDataSnd, max_payload_len: usize) -> Vec<UciDataPacketHal> {
594     let mut fragments = Vec::new();
595     let dpf = packet.get_data_packet_format().into();
596 
597     // get payload by stripping the header.
598     let payload = packet.encode_to_bytes().unwrap().slice(UCI_DATA_SND_PACKET_HEADER_LEN..);
599     if payload.is_empty() {
600         fragments.push(
601             UciDataPacketHalBuilder {
602                 group_id_or_data_packet_format: dpf,
603                 packet_boundary_flag: PacketBoundaryFlag::Complete,
604                 payload: None,
605             }
606             .build(),
607         );
608     } else {
609         let mut fragments_iter = payload.chunks(max_payload_len).peekable();
610         while let Some(fragment) = fragments_iter.next() {
611             // Set the last fragment complete if this is last fragment.
612             let pbf = if let Some(nxt_fragment) = fragments_iter.peek() {
613                 PacketBoundaryFlag::NotComplete
614             } else {
615                 PacketBoundaryFlag::Complete
616             };
617             fragments.push(
618                 UciDataPacketHalBuilder {
619                     group_id_or_data_packet_format: dpf,
620                     packet_boundary_flag: pbf,
621                     payload: Some(Bytes::from(fragment.to_owned())),
622                 }
623                 .build(),
624             );
625         }
626     }
627     fragments
628 }
629 
630 #[derive(Default, Debug)]
631 pub struct PacketDefrager {
632     // Cache to store incoming fragmented packets in the middle of reassembly.
633     // Will be empty if there is no reassembly in progress.
634     // TODO(b/261762781): Prefer this to be UciControlPacketHal
635     control_fragment_cache: Vec<UciPacketHal>,
636     // TODO(b/261762781): Prefer this to be UciDataPacketHal
637     data_fragment_cache: Vec<UciPacketHal>,
638     // Raw packet payload bytes cache
639     raw_fragment_cache: Vec<u8>,
640 }
641 
642 pub enum UciDefragPacket {
643     Control(UciControlPacket),
644     Data(UciDataPacket),
645     Raw(Result<(), DecodeError>, RawUciControlPacket),
646 }
647 
648 impl PacketDefrager {
defragment_packet( &mut self, msg: &[u8], last_raw_cmd: Option<RawUciControlPacket>, ) -> Option<UciDefragPacket>649     pub fn defragment_packet(
650         &mut self,
651         msg: &[u8],
652         last_raw_cmd: Option<RawUciControlPacket>,
653     ) -> Option<UciDefragPacket> {
654         if let Some(raw_cmd) = last_raw_cmd {
655             let mt_u8 = get_mt_from_uci_packet(msg);
656             match MessageType::try_from(u8::from(mt_u8)) {
657                 Ok(mt) => match mt {
658                     // Parse only a UCI response packet as a Raw packet.
659                     MessageType::Response => {
660                         return self.defragment_raw_uci_response_packet(msg, raw_cmd);
661                     }
662                     _ => { /* Fallthrough to de-frag as a normal UCI packet below */ }
663                 },
664                 Err(_) => {
665                     error!("Rx packet from HAL has unrecognized MT={}", mt_u8);
666                     return Some(UciDefragPacket::Raw(
667                         Err(DecodeError::InvalidPacketError),
668                         RawUciControlPacket { mt: mt_u8, gid: 0, oid: 0, payload: Vec::new() },
669                     ));
670                 }
671             };
672         }
673 
674         let packet = UciPacketHal::parse(msg)
675             .or_else(|e| {
676                 error!("Failed to parse packet: {:?}", e);
677                 Err(e)
678             })
679             .ok()?;
680 
681         let pbf = packet.get_packet_boundary_flag();
682 
683         // TODO(b/261762781): The current implementation allows for the possibility that we receive
684         // interleaved Control/Data HAL packets, and so uses separate caches for them. In the
685         // future, if we determine that interleaving is not possible, this can be simplified.
686         if is_uci_control_packet(packet.get_message_type()) {
687             // Add the incoming fragment to the control packet cache.
688             self.control_fragment_cache.push(packet);
689             if pbf == PacketBoundaryFlag::NotComplete {
690                 // Wait for remaining fragments.
691                 return None;
692             }
693 
694             // All fragments received, defragment the control packet.
695             match self.control_fragment_cache.drain(..).collect::<Vec<_>>().try_into() {
696                 Ok(packet) => Some(UciDefragPacket::Control(packet)),
697                 Err(e) => {
698                     error!("Failed to defragment control packet: {:?}", e);
699                     None
700                 }
701             }
702         } else {
703             // Add the incoming fragment to the data packet cache.
704             self.data_fragment_cache.push(packet);
705             if pbf == PacketBoundaryFlag::NotComplete {
706                 // Wait for remaining fragments.
707                 return None;
708             }
709 
710             // All fragments received, defragment the data packet.
711             match self.data_fragment_cache.drain(..).collect::<Vec<_>>().try_into() {
712                 Ok(packet) => Some(UciDefragPacket::Data(packet)),
713                 Err(e) => {
714                     error!("Failed to defragment data packet: {:?}", e);
715                     None
716                 }
717             }
718         }
719     }
720 
defragment_raw_uci_response_packet( &mut self, msg: &[u8], raw_cmd: RawUciControlPacket, ) -> Option<UciDefragPacket>721     fn defragment_raw_uci_response_packet(
722         &mut self,
723         msg: &[u8],
724         raw_cmd: RawUciControlPacket,
725     ) -> Option<UciDefragPacket> {
726         let mt_u8 = get_mt_from_uci_packet(msg);
727         let pbf = get_pbf_from_uci_packet(msg);
728         let gid = get_gid_from_uci_control_packet(msg);
729         let oid = get_oid_from_uci_control_packet(msg);
730         if raw_cmd.is_same_signature_bytes(msg) {
731             // Store only the packet payload bytes (UCI header should not be stored).
732             self.raw_fragment_cache.extend_from_slice(&msg[UCI_PACKET_HAL_HEADER_LEN..]);
733 
734             if pbf == u8::from(PacketBoundaryFlag::NotComplete) {
735                 return None;
736             }
737 
738             // All fragments received, defragment and return the Raw packet's payload bytes.
739             return Some(UciDefragPacket::Raw(
740                 Ok(()),
741                 RawUciControlPacket {
742                     mt: mt_u8,
743                     gid,
744                     oid,
745                     payload: self.raw_fragment_cache.drain(..).collect(),
746                 },
747             ));
748         } else {
749             error!(
750                 "Rx packet from HAL (MT={}, PBF={}, GID={}, OID={}) has non-matching\
751                    RawCmd signature",
752                 mt_u8, pbf, gid, oid
753             );
754             return Some(UciDefragPacket::Raw(
755                 Err(DecodeError::InvalidPacketError),
756                 RawUciControlPacket { mt: mt_u8, gid, oid, payload: Vec::new() },
757             ));
758         }
759     }
760 }
761 
762 #[allow(dead_code)]
763 #[derive(Debug, Clone)]
764 pub struct ParsedDiagnosticNtfPacket {
765     session_token: u32,
766     sequence_number: u32,
767     frame_reports: Vec<ParsedFrameReport>,
768 }
769 
770 #[allow(dead_code)]
771 #[derive(Debug, Clone)]
772 pub struct ParsedFrameReport {
773     uwb_msg_id: u8,
774     action: u8,
775     antenna_set: u8,
776     rssi: Vec<u8>,
777     aoa: Vec<AoaMeasurement>,
778     cir: Vec<CirValue>,
779     segment_metrics: Vec<SegmentMetricsValue>,
780 }
781 
parse_diagnostics_ntf( evt: AndroidRangeDiagnosticsNtf, ) -> Result<ParsedDiagnosticNtfPacket, DecodeError>782 pub fn parse_diagnostics_ntf(
783     evt: AndroidRangeDiagnosticsNtf,
784 ) -> Result<ParsedDiagnosticNtfPacket, DecodeError> {
785     let session_token = evt.get_session_token();
786     let sequence_number = evt.get_sequence_number();
787     let mut parsed_frame_reports = Vec::new();
788     for report in evt.get_frame_reports() {
789         let mut rssi_vec = Vec::new();
790         let mut aoa_vec = Vec::new();
791         let mut cir_vec = Vec::new();
792         let mut segment_metrics_vec = Vec::new();
793         for tlv in &report.frame_report_tlvs {
794             match FrameReportTlvPacket::parse(
795                 &[vec![tlv.t as u8, tlv.v.len() as u8, (tlv.v.len() >> 8) as u8], tlv.v.clone()]
796                     .concat(),
797             ) {
798                 Ok(pkt) => match pkt.specialize() {
799                     FrameReportTlvPacketChild::Rssi(rssi) => {
800                         rssi_vec.append(&mut rssi.get_rssi().clone())
801                     }
802                     FrameReportTlvPacketChild::Aoa(aoa) => {
803                         aoa_vec.append(&mut aoa.get_aoa().clone())
804                     }
805                     FrameReportTlvPacketChild::Cir(cir) => {
806                         cir_vec.append(&mut cir.get_cir_value().clone())
807                     }
808                     FrameReportTlvPacketChild::SegmentMetrics(sm) => {
809                         segment_metrics_vec.append(&mut sm.get_segment_metrics().clone())
810                     }
811                     _ => return Err(DecodeError::InvalidPacketError),
812                 },
813                 Err(e) => {
814                     error!("Failed to parse the packet {:?}", e);
815                     return Err(DecodeError::InvalidPacketError);
816                 }
817             }
818         }
819         parsed_frame_reports.push(ParsedFrameReport {
820             uwb_msg_id: report.uwb_msg_id,
821             action: report.action,
822             antenna_set: report.antenna_set,
823             rssi: rssi_vec,
824             aoa: aoa_vec,
825             cir: cir_vec,
826             segment_metrics: segment_metrics_vec,
827         });
828     }
829     Ok(ParsedDiagnosticNtfPacket {
830         session_token,
831         sequence_number,
832         frame_reports: parsed_frame_reports,
833     })
834 }
835 
836 #[derive(Debug, Clone, PartialEq)]
837 pub enum Controlees {
838     NoSessionKey(Vec<Controlee>),
839     ShortSessionKey(Vec<Controlee_V2_0_16_Byte_Version>),
840     LongSessionKey(Vec<Controlee_V2_0_32_Byte_Version>),
841 }
842 
843 // TODO(ziyiw): Replace these functions after making uwb_uci_packets::Controlee::write_to() public.
write_controlee(controlee: &Controlee) -> BytesMut844 pub fn write_controlee(controlee: &Controlee) -> BytesMut {
845     let mut buffer = BytesMut::new();
846     buffer.extend_from_slice(&controlee.short_address);
847     let subsession_id = controlee.subsession_id;
848     buffer.extend_from_slice(&subsession_id.to_le_bytes()[0..4]);
849     buffer
850 }
851 
write_controlee_2_0_16byte(controlee: &Controlee_V2_0_16_Byte_Version) -> BytesMut852 pub fn write_controlee_2_0_16byte(controlee: &Controlee_V2_0_16_Byte_Version) -> BytesMut {
853     let mut buffer = BytesMut::new();
854     buffer.extend_from_slice(&controlee.short_address);
855     let subsession_id = controlee.subsession_id;
856     buffer.extend_from_slice(&subsession_id.to_le_bytes()[0..4]);
857     buffer.extend_from_slice(&controlee.subsession_key);
858     buffer
859 }
860 
write_controlee_2_0_32byte(controlee: &Controlee_V2_0_32_Byte_Version) -> BytesMut861 pub fn write_controlee_2_0_32byte(controlee: &Controlee_V2_0_32_Byte_Version) -> BytesMut {
862     let mut buffer = BytesMut::new();
863     buffer.extend_from_slice(&controlee.short_address);
864     let subsession_id = controlee.subsession_id;
865     buffer.extend_from_slice(&subsession_id.to_le_bytes()[0..4]);
866     buffer.extend_from_slice(&controlee.subsession_key);
867     buffer
868 }
869 
870 /// Generate the SessionUpdateControllerMulticastListCmd packet.
871 ///
872 /// This function can build the packet with/without message control, which
873 /// is indicated by action parameter.
build_session_update_controller_multicast_list_cmd( session_token: u32, action: UpdateMulticastListAction, controlees: Controlees, ) -> Result<SessionUpdateControllerMulticastListCmd, DecodeError>874 pub fn build_session_update_controller_multicast_list_cmd(
875     session_token: u32,
876     action: UpdateMulticastListAction,
877     controlees: Controlees,
878 ) -> Result<SessionUpdateControllerMulticastListCmd, DecodeError> {
879     let mut controlees_buf = BytesMut::new();
880     match controlees {
881         Controlees::NoSessionKey(controlee_v1) => {
882             controlees_buf.extend_from_slice(&(controlee_v1.len() as u8).to_le_bytes());
883             for controlee in controlee_v1 {
884                 controlees_buf.extend_from_slice(&write_controlee(&controlee));
885             }
886         }
887         Controlees::ShortSessionKey(controlee_v2)
888             if action == UpdateMulticastListAction::AddControleeWithShortSubSessionKey =>
889         {
890             controlees_buf.extend_from_slice(&(controlee_v2.len() as u8).to_le_bytes());
891             for controlee in controlee_v2 {
892                 controlees_buf.extend_from_slice(&write_controlee_2_0_16byte(&controlee));
893             }
894         }
895         Controlees::LongSessionKey(controlee_v2)
896             if action == UpdateMulticastListAction::AddControleeWithLongSubSessionKey =>
897         {
898             controlees_buf.extend_from_slice(&(controlee_v2.len() as u8).to_le_bytes());
899             for controlee in controlee_v2 {
900                 controlees_buf.extend_from_slice(&write_controlee_2_0_32byte(&controlee));
901             }
902         }
903         _ => return Err(DecodeError::InvalidPacketError),
904     }
905     Ok(SessionUpdateControllerMulticastListCmdBuilder {
906         session_token,
907         action,
908         payload: Some(controlees_buf.freeze()),
909     }
910     .build())
911 }
912 
913 /// building Data transfer phase config command
build_data_transfer_phase_config_cmd( session_token: u32, dtpcm_repetition: u8, data_transfer_control: u8, dtpml_size: u8, mac_address: Vec<u8>, slot_bitmap: Vec<u8>, ) -> Result<SessionDataTransferPhaseConfigCmd, DecodeError>914 pub fn build_data_transfer_phase_config_cmd(
915     session_token: u32,
916     dtpcm_repetition: u8,
917     data_transfer_control: u8,
918     dtpml_size: u8,
919     mac_address: Vec<u8>,
920     slot_bitmap: Vec<u8>,
921 ) -> Result<SessionDataTransferPhaseConfigCmd, DecodeError> {
922     let mut dtpml_buffer = BytesMut::new();
923 
924     //calculate mac address mode from data transfer control
925     let mac_address_mode = data_transfer_control & 0x01;
926 
927     // Calculate mac address size based on address mode
928     let mac_address_size = match mac_address_mode {
929         SHORT_ADDRESS => 2,
930         EXTENDED_ADDRESS => 8,
931         _ => return Err(DecodeError::InvalidPacketError),
932     };
933 
934     // Calculate slot bitmap size from data transfer control
935     let slot_bitmap_size = 1 << ((data_transfer_control & 0x0F) >> 1);
936 
937     // Prepare segmented vectors for mac_address
938     let mac_address_vec: Vec<_> =
939         mac_address.chunks(mac_address_size).map(|chunk| chunk.to_owned()).collect();
940 
941     // Prepare segmented vectors for slot_bitmap
942     let slot_bitmap_vec: Vec<_> =
943         slot_bitmap.chunks(slot_bitmap_size).map(|chunk| chunk.to_owned()).collect();
944 
945     // Validate sizes of mac_address and slot_bitmap
946     if slot_bitmap_vec.len() != dtpml_size.into() || mac_address_vec.len() != dtpml_size.into() {
947         return Err(DecodeError::InvalidPacketError);
948     }
949 
950     // Combine segmented vectors into dtpml_buffer
951     for (elem1, elem2) in mac_address_vec.into_iter().zip(slot_bitmap_vec.into_iter()) {
952         dtpml_buffer.extend_from_slice(&elem1);
953         dtpml_buffer.extend_from_slice(&elem2);
954     }
955 
956     Ok(SessionDataTransferPhaseConfigCmdBuilder {
957         session_token,
958         dtpcm_repetition,
959         data_transfer_control,
960         dtpml_size,
961         payload: Some(dtpml_buffer.freeze()),
962     }
963     .build())
964 }
965 
966 impl Drop for AppConfigTlv {
drop(&mut self)967     fn drop(&mut self) {
968         if self.cfg_id == AppConfigTlvType::VendorId || self.cfg_id == AppConfigTlvType::StaticStsIv
969         {
970             self.v.zeroize();
971         }
972     }
973 }
974 
975 #[derive(Debug, Clone, PartialEq)]
976 pub enum PhaseList {
977     ShortMacAddress(Vec<PhaseListShortMacAddress>),
978     ExtendedMacAddress(Vec<PhaseListExtendedMacAddress>),
979 }
980 
981 /// Generate the SessionSetHybridControllerConfig packet.
build_session_set_hybrid_controller_config_cmd( session_token: u32, message_control: u8, number_of_phases: u8, update_time: [u8; 8], phase_list: PhaseList, ) -> Result<SessionSetHybridControllerConfigCmd, DecodeError>982 pub fn build_session_set_hybrid_controller_config_cmd(
983     session_token: u32,
984     message_control: u8,
985     number_of_phases: u8,
986     update_time: [u8; 8],
987     phase_list: PhaseList,
988 ) -> Result<SessionSetHybridControllerConfigCmd, DecodeError> {
989     let mut phase_list_buffer = BytesMut::new();
990     match phase_list {
991         PhaseList::ShortMacAddress(phaseListShortMacAddressVec) => {
992             for phaseListShortMacAddress in phaseListShortMacAddressVec {
993                 phase_list_buffer.extend_from_slice(
994                     &(phaseListShortMacAddress.session_token.to_le_bytes()[0..4]),
995                 );
996                 phase_list_buffer.extend_from_slice(
997                     &(phaseListShortMacAddress.start_slot_index.to_le_bytes()[0..2]),
998                 );
999                 phase_list_buffer.extend_from_slice(
1000                     &(phaseListShortMacAddress.end_slot_index.to_le_bytes()[0..2]),
1001                 );
1002                 phase_list_buffer.extend_from_slice(std::slice::from_ref(
1003                     &phaseListShortMacAddress.phase_participation,
1004                 ));
1005                 phase_list_buffer.extend_from_slice(&phaseListShortMacAddress.mac_address);
1006             }
1007         }
1008         PhaseList::ExtendedMacAddress(phaseListExtendedMacAddressVec) => {
1009             for phaseListExtendedMacAddress in phaseListExtendedMacAddressVec {
1010                 phase_list_buffer.extend_from_slice(
1011                     &(phaseListExtendedMacAddress.session_token.to_le_bytes()[0..4]),
1012                 );
1013                 phase_list_buffer.extend_from_slice(
1014                     &(phaseListExtendedMacAddress.start_slot_index.to_le_bytes()[0..2]),
1015                 );
1016                 phase_list_buffer.extend_from_slice(
1017                     &(phaseListExtendedMacAddress.end_slot_index.to_le_bytes()[0..2]),
1018                 );
1019                 phase_list_buffer.extend_from_slice(std::slice::from_ref(
1020                     &phaseListExtendedMacAddress.phase_participation,
1021                 ));
1022                 phase_list_buffer.extend_from_slice(&phaseListExtendedMacAddress.mac_address);
1023             }
1024         }
1025         _ => return Err(DecodeError::InvalidPacketError),
1026     }
1027     Ok(SessionSetHybridControllerConfigCmdBuilder {
1028         session_token,
1029         message_control,
1030         number_of_phases,
1031         update_time,
1032         payload: Some(phase_list_buffer.freeze()),
1033     }
1034     .build())
1035 }
1036 
1037 // Radar data 'bits per sample' field isn't a raw value, instead it's an enum
1038 // that maps to the raw value. We need this mapping to get the max sample size
1039 // length.
radar_bytes_per_sample_value(bps: BitsPerSample) -> u81040 pub fn radar_bytes_per_sample_value(bps: BitsPerSample) -> u8 {
1041     match bps {
1042         BitsPerSample::Value32 => 4,
1043         BitsPerSample::Value48 => 6,
1044         BitsPerSample::Value64 => 8,
1045     }
1046 }
1047 
1048 #[cfg(test)]
1049 mod tests {
1050     use super::*;
1051 
1052     #[test]
test_parse_diagnostics_ntf()1053     fn test_parse_diagnostics_ntf() {
1054         let rssi_vec = vec![0x01, 0x02, 0x03];
1055         let rssi = RssiBuilder { rssi: rssi_vec.clone() }.build();
1056         let aoa_1 = AoaMeasurement { tdoa: 1, pdoa: 2, aoa: 3, fom: 4, t: 1 };
1057         let aoa_2 = AoaMeasurement { tdoa: 5, pdoa: 6, aoa: 7, fom: 8, t: 2 };
1058         let aoa = AoaBuilder { aoa: vec![aoa_1.clone(), aoa_2.clone()] }.build();
1059         let cir_vec = vec![CirValue {
1060             first_path_index: 1,
1061             first_path_snr: 2,
1062             first_path_ns: 3,
1063             peak_path_index: 4,
1064             peak_path_snr: 5,
1065             peak_path_ns: 6,
1066             first_path_sample_offset: 7,
1067             samples_number: 2,
1068             sample_window: vec![0, 1, 2, 3],
1069         }];
1070         let cir = CirBuilder { cir_value: cir_vec.clone() }.build();
1071         let segment_metrics_vec = vec![SegmentMetricsValue {
1072             receiver: 1,
1073             rf_noise_floor: 2,
1074             segment_rsl: 3,
1075             first_path_index: 4,
1076             first_path_rsl: 5,
1077             first_path_time_ns: 6,
1078             peak_path_index: 7,
1079             peak_path_rsl: 8,
1080             peak_path_time_ns: 9,
1081         }];
1082         let segment_metrics =
1083             SegmentMetricsBuilder { segment_metrics: segment_metrics_vec.clone() }.build();
1084         let mut frame_reports = Vec::new();
1085         let tlvs = vec![
1086             FrameReportTlv { t: rssi.get_t(), v: rssi.get_rssi().to_vec() },
1087             FrameReportTlv { t: aoa.get_t(), v: aoa.encode_to_vec().unwrap()[3..].to_vec() },
1088             FrameReportTlv { t: cir.get_t(), v: cir.encode_to_vec().unwrap()[3..].to_vec() },
1089             FrameReportTlv {
1090                 t: segment_metrics.get_t(),
1091                 v: segment_metrics.encode_to_vec().unwrap()[3..].to_vec(),
1092             },
1093         ];
1094         let frame_report =
1095             FrameReport { uwb_msg_id: 1, action: 1, antenna_set: 1, frame_report_tlvs: tlvs };
1096         frame_reports.push(frame_report);
1097         let packet = AndroidRangeDiagnosticsNtfBuilder {
1098             session_token: 1,
1099             sequence_number: 1,
1100             frame_reports,
1101         }
1102         .build();
1103         let mut parsed_packet = parse_diagnostics_ntf(packet).unwrap();
1104         let parsed_frame_report = parsed_packet.frame_reports.pop().unwrap();
1105         assert_eq!(rssi_vec, parsed_frame_report.rssi);
1106         assert_eq!(aoa_1, parsed_frame_report.aoa[0]);
1107         assert_eq!(aoa_2, parsed_frame_report.aoa[1]);
1108         assert_eq!(cir_vec, parsed_frame_report.cir);
1109         assert_eq!(segment_metrics_vec, parsed_frame_report.segment_metrics);
1110     }
1111 
1112     #[test]
test_write_controlee()1113     fn test_write_controlee() {
1114         let short_address: [u8; 2] = [2, 3];
1115         let controlee: Controlee = Controlee { short_address, subsession_id: 3 };
1116         let bytes = write_controlee(&controlee);
1117         let parsed_controlee = Controlee::parse(&bytes).unwrap();
1118         assert_eq!(controlee, parsed_controlee);
1119     }
1120 
1121     #[test]
test_build_multicast_update_packet()1122     fn test_build_multicast_update_packet() {
1123         let short_address: [u8; 2] = [0x12, 0x34];
1124         let controlee = Controlee { short_address, subsession_id: 0x1324_3546 };
1125         let packet: UciControlPacket = build_session_update_controller_multicast_list_cmd(
1126             0x1425_3647,
1127             UpdateMulticastListAction::AddControlee,
1128             Controlees::NoSessionKey(vec![controlee; 1]),
1129         )
1130         .unwrap()
1131         .into();
1132         let packet_fragments: Vec<UciControlPacketHal> = packet.into();
1133         let uci_packet = packet_fragments[0].encode_to_vec();
1134         assert_eq!(
1135             uci_packet,
1136             Ok(vec![
1137                 0x21, 0x07, 0x00, 0x0c, // 2(packet info), RFU, payload length(12)
1138                 0x47, 0x36, 0x25, 0x14, // 4(session id (LE))
1139                 0x00, 0x01, 0x12, 0x34, // action, # controlee, 2(short address (LE))
1140                 0x46, 0x35, 0x24, 0x13, // 4(subsession id (LE))
1141             ])
1142         );
1143     }
1144 
1145     #[test]
test_build_multicast_update_packet_v2_short_session_key()1146     fn test_build_multicast_update_packet_v2_short_session_key() {
1147         let short_address: [u8; 2] = [0x12, 0x34];
1148         let controlee = Controlee_V2_0_16_Byte_Version {
1149             short_address,
1150             subsession_id: 0x1324_3546,
1151             subsession_key: [
1152                 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab,
1153                 0xcd, 0xef,
1154             ],
1155         };
1156         let packet: UciControlPacket = build_session_update_controller_multicast_list_cmd(
1157             0x1425_3647,
1158             UpdateMulticastListAction::AddControleeWithShortSubSessionKey,
1159             Controlees::ShortSessionKey(vec![controlee; 1]),
1160         )
1161         .unwrap()
1162         .into();
1163         let packet_fragments: Vec<UciControlPacketHal> = packet.into();
1164         let uci_packet = packet_fragments[0].encode_to_vec();
1165         assert_eq!(
1166             uci_packet,
1167             Ok(vec![
1168                 0x21, 0x07, 0x00, 0x1c, // 2(packet info), RFU, payload length(28)
1169                 0x47, 0x36, 0x25, 0x14, // 4(session id (LE))
1170                 0x02, 0x01, 0x12, 0x34, // action, # controlee, 2(short address (LE))
1171                 0x46, 0x35, 0x24, 0x13, // 4(subsession id (LE))
1172                 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab,
1173                 0xcd, 0xef, // 16(subsession key(LE))
1174             ])
1175         );
1176     }
1177 
1178     #[test]
test_build_multicast_update_packet_v2_long_session_key()1179     fn test_build_multicast_update_packet_v2_long_session_key() {
1180         let short_address: [u8; 2] = [0x12, 0x34];
1181         let controlee = Controlee_V2_0_32_Byte_Version {
1182             short_address,
1183             subsession_id: 0x1324_3546,
1184             subsession_key: [
1185                 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab,
1186                 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78,
1187                 0x90, 0xab, 0xcd, 0xef,
1188             ],
1189         };
1190         let packet: UciControlPacket = build_session_update_controller_multicast_list_cmd(
1191             0x1425_3647,
1192             UpdateMulticastListAction::AddControleeWithLongSubSessionKey,
1193             Controlees::LongSessionKey(vec![controlee; 1]),
1194         )
1195         .unwrap()
1196         .into();
1197         let packet_fragments: Vec<UciControlPacketHal> = packet.into();
1198         let uci_packet = packet_fragments[0].encode_to_vec();
1199         assert_eq!(
1200             uci_packet,
1201             Ok(vec![
1202                 0x21, 0x07, 0x00, 0x2c, // 2(packet info), RFU, payload length(44)
1203                 0x47, 0x36, 0x25, 0x14, // 4(session id (LE))
1204                 0x03, 0x01, 0x12, 0x34, // action, # controlee, 2(short address (LE))
1205                 0x46, 0x35, 0x24, 0x13, // 4(subsession id (LE))
1206                 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab,
1207                 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78,
1208                 0x90, 0xab, 0xcd, 0xef, // 32(subsession key(LE))
1209             ])
1210         );
1211     }
1212 
1213     #[test]
test_to_raw_payload()1214     fn test_to_raw_payload() {
1215         let payload = vec![0x11, 0x22, 0x33];
1216         let payload_clone = payload.clone();
1217         let packet = UciControlPacketBuilder {
1218             group_id: GroupId::Test,
1219             message_type: MessageType::Response,
1220             opcode: 0x5,
1221             payload: Some(payload_clone.into()),
1222         }
1223         .build();
1224 
1225         assert_eq!(payload, packet.to_raw_payload());
1226     }
1227 
1228     #[test]
test_to_raw_payload_empty()1229     fn test_to_raw_payload_empty() {
1230         let payload: Vec<u8> = vec![];
1231         let packet = UciControlPacketBuilder {
1232             group_id: GroupId::Test,
1233             message_type: MessageType::Response,
1234             opcode: 0x5,
1235             payload: None,
1236         }
1237         .build();
1238 
1239         assert_eq!(payload, packet.to_raw_payload());
1240     }
1241 
1242     #[cfg(test)]
1243     mod tests {
1244         use crate::{extract_u16, extract_u32, extract_u64, extract_u8, extract_vec};
1245         #[test]
test_extract_func()1246         fn test_extract_func() {
1247             let bytes = [0x1, 0x3, 0x5, 0x7, 0x9, 0x2, 0x4, 0x05, 0x07, 0x09, 0x0a];
1248             let mut ptr = 0;
1249 
1250             let u8_val = extract_u8(&bytes, &mut ptr, 1);
1251             assert_eq!(u8_val, Some(0x1));
1252             assert_eq!(ptr, 1);
1253 
1254             let u16_val = extract_u16(&bytes, &mut ptr, 2);
1255             assert_eq!(u16_val, Some(0x0503));
1256             assert_eq!(ptr, 3);
1257 
1258             let u32_val = extract_u32(&bytes, &mut ptr, 3);
1259             assert_eq!(u32_val, Some(0x020907));
1260             assert_eq!(ptr, 6);
1261 
1262             let u64_val = extract_u64(&bytes, &mut ptr, 5);
1263             assert_eq!(u64_val, Some(0x0a09070504));
1264             assert_eq!(ptr, 11);
1265 
1266             let vec = extract_vec(&bytes, &mut ptr, 3);
1267             assert_eq!(vec, None);
1268             assert_eq!(ptr, 11);
1269         }
1270     }
1271 
1272     #[test]
test_short_dltdoa_ranging_measurement()1273     fn test_short_dltdoa_ranging_measurement() {
1274         let bytes = [
1275             // All Fields in Little Endian (LE)
1276             // First measurement
1277             0x0a, 0x01, 0x33, 0x05, // 2(Mac address), Status, Message Type
1278             0x53, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
1279             0x07, 0x09, 0x0a, 0x01, // Round Index, NLoS, 2(AoA Azimuth)
1280             0x02, 0x05, 0x07, 0x09, // AoA Azimuth FOM, 2(AoA Elevation), AoA Elevation FOM
1281             0x0a, 0x01, 0x02, 0x05, // RSSI, 3(Tx Timestamp..)
1282             0x07, 0x09, 0x0a, 0x01, // 4(Tx Timestamp..)
1283             0x02, 0x05, 0x07, 0x09, // Tx Timestamp, 3(Rx Timestamp..)
1284             0x05, 0x07, 0x09, 0x0a, // 2(Rx Timestamp), 2(Anchor Cfo)
1285             0x01, 0x02, 0x05, 0x07, // 2(Cfo), 2(Initiator Reply Time..)
1286             0x09, 0x05, 0x07, 0x09, // 2(Initiator Reply Time), 2(Responder Reply Time..)
1287             0x0a, 0x01, 0x02, 0x05, // 2(Responder Reply Time), 2(Initiator-Responder ToF)
1288             0x07, 0x09, 0x07, 0x09, // 4(Anchor Location..)
1289             0x05, 0x07, 0x09, 0x0a, // 4(Anchor Location..)
1290             0x01, 0x02, 0x05, 0x07, // 2(Anchor Location..), 2(Active Ranging Rounds..)
1291             0x09, 0x0a, 0x01, 0x02, // 4(Active Ranging Rounds..)
1292             0x05, 0x07, 0x09, 0x05, // 4(Active Ranging Rounds)
1293             // Second measurement
1294             0x0a, 0x01, 0x33, 0x05, // 2(Mac address), Status, Message Type
1295             0x33, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
1296             0x07, 0x09, 0x0a, 0x01, // Round Index, NLoS, 2(AoA Azimuth)
1297             0x02, 0x05, 0x07, 0x09, // AoA Azimuth FOM, 2(AoA Elevation), AoA Elevation FOM
1298             0x0a, 0x01, 0x02, 0x05, // RSSI, 3(Tx Timestamp..)
1299             0x07, 0x09, 0x0a, 0x01, // 4(Tx Timestamp..)
1300             0x02, 0x05, 0x07, 0x09, // Tx Timestamp, 3(Rx Timestamp..)
1301             0x05, 0x07, 0x09, 0x0a, // 2(Rx Timestamp), 2(Anchor Cfo)
1302             0x01, 0x02, 0x05, 0x07, // 2(Cfo), 2(Initiator Reply Time..)
1303             0x09, 0x05, 0x07, 0x09, // 2(Initiator Reply Time), 2(Responder Reply Time..)
1304             0x0a, 0x01, 0x02, 0x05, // 2(Responder Reply Time), 2(Initiator-Responder ToF)
1305             0x07, 0x09, 0x07, 0x09, // 4(Anchor Location..)
1306             0x05, 0x07, 0x09, 0x0a, // 4(Anchor Location..)
1307             0x01, 0x02, 0x01, 0x02, // 4(Anchor Location)
1308             0x05, 0x07, 0x09, 0x0a, // 4(Active Ranging Rounds..)
1309             0x01, 0x02, 0x05, 0x07, // 4(Active Ranging Rounds..)
1310             0x09, 0x05, // 2(Active Ranging Rounds)
1311         ];
1312 
1313         let measurements = ShortAddressDlTdoaRangingMeasurement::parse(&bytes, 2).unwrap();
1314         assert_eq!(measurements.len(), 2);
1315         let measurement_1 = &measurements[0].measurement;
1316         let mac_address_1 = &measurements[0].mac_address;
1317         assert_eq!(*mac_address_1, 0x010a);
1318         assert_eq!(measurement_1.status, 0x33);
1319         assert_eq!(measurement_1.message_type, 0x05);
1320         assert_eq!(measurement_1.message_control, 0x0553);
1321         assert_eq!(measurement_1.block_index, 0x0502);
1322         assert_eq!(measurement_1.round_index, 0x07);
1323         assert_eq!(measurement_1.nlos, 0x09);
1324         assert_eq!(measurement_1.aoa_azimuth, 0x010a);
1325         assert_eq!(measurement_1.aoa_azimuth_fom, 0x02);
1326         assert_eq!(measurement_1.aoa_elevation, 0x0705);
1327         assert_eq!(measurement_1.aoa_elevation_fom, 0x09);
1328         assert_eq!(measurement_1.rssi, 0x0a);
1329         assert_eq!(measurement_1.tx_timestamp, 0x02010a0907050201);
1330         assert_eq!(measurement_1.rx_timestamp, 0x0705090705);
1331         assert_eq!(measurement_1.anchor_cfo, 0x0a09);
1332         assert_eq!(measurement_1.cfo, 0x0201);
1333         assert_eq!(measurement_1.initiator_reply_time, 0x05090705);
1334         assert_eq!(measurement_1.responder_reply_time, 0x010a0907);
1335         assert_eq!(measurement_1.initiator_responder_tof, 0x0502);
1336         assert_eq!(
1337             measurement_1.dt_anchor_location,
1338             vec![0x07, 0x09, 0x07, 0x09, 0x05, 0x07, 0x09, 0x0a, 0x01, 0x02]
1339         );
1340         assert_eq!(
1341             measurement_1.ranging_rounds,
1342             vec![0x05, 0x07, 0x09, 0x0a, 0x01, 0x02, 0x05, 0x07, 0x09, 0x05,]
1343         );
1344 
1345         let measurement_2 = &measurements[1].measurement;
1346         let mac_address_2 = &measurements[1].mac_address;
1347         assert_eq!(*mac_address_2, 0x010a);
1348         assert_eq!(measurement_2.status, 0x33);
1349         assert_eq!(measurement_2.message_type, 0x05);
1350         assert_eq!(measurement_2.message_control, 0x0533);
1351         assert_eq!(measurement_2.block_index, 0x0502);
1352         assert_eq!(measurement_2.round_index, 0x07);
1353         assert_eq!(measurement_2.nlos, 0x09);
1354         assert_eq!(measurement_2.aoa_azimuth, 0x010a);
1355         assert_eq!(measurement_2.aoa_azimuth_fom, 0x02);
1356         assert_eq!(measurement_2.aoa_elevation, 0x0705);
1357         assert_eq!(measurement_2.aoa_elevation_fom, 0x09);
1358         assert_eq!(measurement_2.rssi, 0x0a);
1359         assert_eq!(measurement_2.tx_timestamp, 0x02010a0907050201);
1360         assert_eq!(measurement_2.rx_timestamp, 0x0705090705);
1361         assert_eq!(measurement_2.anchor_cfo, 0x0a09);
1362         assert_eq!(measurement_2.cfo, 0x0201);
1363         assert_eq!(measurement_2.initiator_reply_time, 0x05090705);
1364         assert_eq!(measurement_2.responder_reply_time, 0x010a0907);
1365         assert_eq!(measurement_2.initiator_responder_tof, 0x0502);
1366         assert_eq!(
1367             measurement_2.dt_anchor_location,
1368             vec![0x07, 0x09, 0x07, 0x09, 0x05, 0x07, 0x09, 0x0a, 0x01, 0x02, 0x01, 0x02]
1369         );
1370         assert_eq!(
1371             measurement_2.ranging_rounds,
1372             vec![0x05, 0x07, 0x09, 0x0a, 0x01, 0x02, 0x05, 0x07, 0x09, 0x05,]
1373         );
1374     }
1375 
1376     #[test]
test_extended_dltdoa_ranging_measurement()1377     fn test_extended_dltdoa_ranging_measurement() {
1378         let bytes = [
1379             // All Fields in Little Endian (LE)
1380             /* First measurement  */
1381             0x0a, 0x01, 0x33, 0x05, // 4(Mac address..)
1382             0x33, 0x05, 0x02, 0x05, // 4(Mac address)
1383             0x07, 0x09, 0x0a, 0x01, // Status, Message Type, 2(Message control),
1384             0x02, 0x05, 0x07, 0x09, // 2(Block Index), Round Index, NLoS,
1385             0x0a, 0x01, 0x02, 0x05, // 2(AoA Azimuth), AoA Azimuth FOM, 1(AoA Elevation..)
1386             0x07, 0x09, 0x0a, // 1(AoA Elevation), AoA Elevation FOM, RSSI,
1387             0x01, 0x02, 0x05, 0x07, // 4(Tx Timestamp..)
1388             0x09, 0x05, 0x07, 0x09, // 4(Tx Timestamp),
1389             0x0a, 0x01, 0x02, 0x05, // 4(Rx Timestamp..)
1390             0x07, 0x09, 0x05, 0x07, // 4(Rx Timestamp)
1391             0x09, 0x0a, 0x01, 0x02, // 2(Anchor Cfo), 2(Cfo),
1392             0x05, 0x07, 0x09, 0x05, // 4(Initiator Reply Time)
1393             0x07, 0x09, 0x0a, 0x01, // 4(Responder Reply Time),
1394             0x02, 0x05, 0x02, 0x05, // 2(Initiator-Responder ToF), 2(Active Ranging Rounds)
1395         ];
1396 
1397         let measurements = ExtendedAddressDlTdoaRangingMeasurement::parse(&bytes, 1).unwrap();
1398         assert_eq!(measurements.len(), 1);
1399         let measurement = &measurements[0].measurement;
1400         let mac_address = &measurements[0].mac_address;
1401         assert_eq!(*mac_address, 0x050205330533010a);
1402         assert_eq!(measurement.message_control, 0x010a);
1403         assert_eq!(measurement.block_index, 0x0502);
1404         assert_eq!(measurement.round_index, 0x07);
1405         assert_eq!(measurement.nlos, 0x09);
1406         assert_eq!(measurement.aoa_azimuth, 0x010a);
1407         assert_eq!(measurement.aoa_azimuth_fom, 0x02);
1408         assert_eq!(measurement.aoa_elevation, 0x0705);
1409         assert_eq!(measurement.aoa_elevation_fom, 0x09);
1410         assert_eq!(measurement.rssi, 0x0a);
1411         assert_eq!(measurement.tx_timestamp, 0x0907050907050201);
1412         assert_eq!(measurement.rx_timestamp, 0x070509070502010a);
1413         assert_eq!(measurement.anchor_cfo, 0x0a09);
1414         assert_eq!(measurement.cfo, 0x0201);
1415         assert_eq!(measurement.initiator_reply_time, 0x05090705);
1416         assert_eq!(measurement.responder_reply_time, 0x010a0907);
1417         assert_eq!(measurement.initiator_responder_tof, 0x0502);
1418         assert_eq!(measurement.dt_anchor_location, vec![]);
1419         assert_eq!(measurement.ranging_rounds, vec![0x02, 0x05]);
1420     }
1421 
1422     #[test]
test_build_data_transfer_phase_config_cmd()1423     fn test_build_data_transfer_phase_config_cmd() {
1424         let packet: UciControlPacket =
1425             build_data_transfer_phase_config_cmd(0x1234_5678, 0x0, 0x2, 1, vec![0, 1], vec![2, 3])
1426                 .unwrap()
1427                 .into();
1428         let packet_fragments: Vec<UciControlPacketHal> = packet.into();
1429         let uci_packet = packet_fragments[0].encode_to_vec();
1430         assert_eq!(
1431             uci_packet,
1432             Ok(vec![
1433                 0x21, 0x0e, 0x00, 0x0b, // 2(packet info), RFU, payload length(11)
1434                 0x78, 0x56, 0x34, 0x12, // 4(session id (LE))
1435                 0x00, 0x02, 0x01, // dtpcm_repetition, data_transfer_control, dtpml_size
1436                 0x00, 0x01, 0x02, 0x03, // payload
1437             ])
1438         );
1439     }
1440 
1441     #[test]
test_build_session_set_hybrid_controller_config_cmd_short_address()1442     fn test_build_session_set_hybrid_controller_config_cmd_short_address() {
1443         let phase_list_short_mac_address = PhaseListShortMacAddress {
1444             session_token: 0x1324_3546,
1445             start_slot_index: 0x1111,
1446             end_slot_index: 0x1121,
1447             phase_participation: 0x0,
1448             mac_address: [0x1, 0x2],
1449         };
1450         let packet: UciControlPacket = build_session_set_hybrid_controller_config_cmd(
1451             0x1234_5678,
1452             0x0,
1453             0x0,
1454             [1; 8],
1455             PhaseList::ShortMacAddress(vec![phase_list_short_mac_address]),
1456         )
1457         .unwrap()
1458         .into();
1459         let packet_fragments: Vec<UciControlPacketHal> = packet.into();
1460         let uci_packet = packet_fragments[0].encode_to_vec();
1461         assert_eq!(
1462             uci_packet,
1463             Ok(vec![
1464                 0x21, 0x0c, 0x00, 0x19, // 2(packet info), RFU, payload length(25)
1465                 0x78, 0x56, 0x34, 0x12, // 4(session id (LE))
1466                 0x00, 0x00, // message_control, number_of_phases
1467                 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // update_time
1468                 0x46, 0x35, 0x24, 0x13, // session id (LE)
1469                 0x11, 0x11, // start slot index (LE)
1470                 0x21, 0x11, // end slot index (LE)
1471                 0x00, // phase_participation
1472                 0x01, 0x02, // mac address
1473             ])
1474         );
1475     }
1476 
1477     #[test]
test_build_session_set_hybrid_controller_config_cmd_extended_address()1478     fn test_build_session_set_hybrid_controller_config_cmd_extended_address() {
1479         let phase_list_extended_mac_address = PhaseListExtendedMacAddress {
1480             session_token: 0x1324_3546,
1481             start_slot_index: 0x1111,
1482             end_slot_index: 0x1121,
1483             phase_participation: 0x0,
1484             mac_address: [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8],
1485         };
1486         let packet: UciControlPacket = build_session_set_hybrid_controller_config_cmd(
1487             0x1234_5678,
1488             0x0,
1489             0x0,
1490             [1; 8],
1491             PhaseList::ExtendedMacAddress(vec![phase_list_extended_mac_address]),
1492         )
1493         .unwrap()
1494         .into();
1495         let packet_fragments: Vec<UciControlPacketHal> = packet.into();
1496         let uci_packet = packet_fragments[0].encode_to_vec();
1497         assert_eq!(
1498             uci_packet,
1499             Ok(vec![
1500                 0x21, 0x0c, 0x00, 0x1f, // 2(packet info), RFU, payload length(31)
1501                 0x78, 0x56, 0x34, 0x12, // 4(session id (LE))
1502                 0x00, 0x00, // message_control, number_of_phases
1503                 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // update_time
1504                 0x46, 0x35, 0x24, 0x13, // session id (LE)
1505                 0x11, 0x11, // start slot index (LE)
1506                 0x21, 0x11, // end slot index (LE)
1507                 0x00, // phase_participation
1508                 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 // mac address
1509             ])
1510         );
1511     }
1512 }
1513