awdl_frame_parser/
action_frame.rs1use macro_bits::serializable_enum;
2use scroll::{
3 ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
4 Endian, Pread, Pwrite,
5};
6
7use core::{fmt::Debug, time::Duration};
8
9use crate::tlvs::{ReadTLVs, AWDLTLV};
10
11serializable_enum! {
12 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
13 pub enum AWDLActionFrameSubType: u8 {
14 #[default]
15 PSF => 0x00,
17 MIF => 0x03
19 }
20}
21
22#[derive(Clone, PartialEq, Eq)]
23pub struct AWDLActionFrame<I> {
25 pub subtype: AWDLActionFrameSubType,
27
28 pub phy_tx_time: Duration,
30
31 pub target_tx_time: Duration,
33
34 pub tagged_data: I,
36}
37impl<I> AWDLActionFrame<I> {
38 pub fn tx_delta(&self) -> Duration {
40 self.phy_tx_time - self.target_tx_time
41 }
42}
43impl<'a, I: Debug, MACIterator, LabelIterator> Debug for AWDLActionFrame<I>
44where
45 AWDLTLV<'a, MACIterator, LabelIterator>: Debug,
46 I: IntoIterator<Item = AWDLTLV<'a, MACIterator, LabelIterator>> + Clone,
47{
48 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
49 f.debug_struct("AWDLActionFrame")
50 .field("subtype", &self.subtype)
51 .field("phy_tx_time", &self.phy_tx_time)
52 .field("target_tx_time", &self.target_tx_time)
53 .field("tagged_data", &self.tagged_data)
54 .finish()
55 }
56}
57impl<I: MeasureWith<()>> MeasureWith<()> for AWDLActionFrame<I>
58{
59 fn measure_with(&self, ctx: &()) -> usize {
60 12 + self
61 .tagged_data.measure_with(ctx)
62 }
63}
64
65impl<'a> TryFromCtx<'a> for AWDLActionFrame<ReadTLVs<'a>> {
66 type Error = scroll::Error;
67 fn try_from_ctx(from: &'a [u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
68 let mut offset = 0;
69 if from.gread::<u8>(&mut offset)? != 0x8u8 {
70 return Err(scroll::Error::BadInput {
71 size: offset,
72 msg: "AF didn't start with 0x8.",
73 });
74 }
75 if from.gread::<u8>(&mut offset)? != 0x10u8 {
76 return Err(scroll::Error::BadInput {
77 size: offset,
78 msg: "AF header version wasn't 1.0.",
79 });
80 }
81 let subtype = AWDLActionFrameSubType::from_bits(from.gread(&mut offset)?);
82 offset += 1;
83
84 let phy_tx_time =
85 Duration::from_micros(from.gread_with::<u32>(&mut offset, Endian::Little)? as u64);
86 let target_tx_time =
87 Duration::from_micros(from.gread_with::<u32>(&mut offset, Endian::Little)? as u64);
88 let tagged_data = ReadTLVs::new(&from[offset..]);
89
90 Ok((
91 Self {
92 subtype,
93 phy_tx_time,
94 target_tx_time,
95 tagged_data,
96 },
97 offset,
98 ))
99 }
100}
101impl<I: TryIntoCtx<(), Error = scroll::Error>> TryIntoCtx for AWDLActionFrame<I>
102{
103 type Error = scroll::Error;
104 fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
105 let mut offset = 0;
106 buf.gwrite(8u8, &mut offset)?;
107 buf.gwrite(0x10u8, &mut offset)?;
108 buf.gwrite(self.subtype.into_bits(), &mut offset)?;
109 offset += 1;
110 buf.gwrite_with(
111 self.phy_tx_time.as_micros() as u32,
112 &mut offset,
113 Endian::Little,
114 )?;
115 buf.gwrite_with(
116 self.target_tx_time.as_micros() as u32,
117 &mut offset,
118 Endian::Little,
119 )?;
120 buf.gwrite(self.tagged_data, &mut offset)?;
121 Ok(offset)
122 }
123}
124pub type DefaultAWDLActionFrame<'a> = AWDLActionFrame<ReadTLVs<'a>>;
126#[cfg(test)]
127#[test]
128fn test_action_frame() {
129 use alloc::vec;
130
131 let packet_bytes = include_bytes!("../test_bins/mif.bin");
132 let parsed_af = packet_bytes.pread::<DefaultAWDLActionFrame>(0).unwrap();
133 let mut buf = vec![0; parsed_af.measure_with(&())];
135 buf.pwrite(parsed_af, 0).unwrap();
136 assert_eq!(packet_bytes, buf.as_slice());
137}