Skip to main content

openipc_core/
realtek.rs

1pub const RX_DESC_SIZE: usize = 24;
2pub const DEFAULT_RX_TRANSFER_SIZE: usize = 32 * 1024;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum RxPacketType {
6    NormalRx,
7    C2hPacket,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct RxPacketAttrib {
12    pub pkt_len: u16,
13    pub physt: bool,
14    pub drvinfo_sz: u8,
15    pub shift_sz: u8,
16    pub qos: bool,
17    pub priority: u8,
18    pub mdata: bool,
19    pub seq_num: u16,
20    pub frag_num: u8,
21    pub mfrag: bool,
22    pub bdecrypted: bool,
23    pub encrypt: u8,
24    pub crc_err: bool,
25    pub icv_err: bool,
26    pub tsfl: u32,
27    pub data_rate: u8,
28    pub bw: u8,
29    pub stbc: u8,
30    pub ldpc: u8,
31    pub sgi: u8,
32    pub scrambler: u8,
33    pub rssi: [u8; 4],
34    pub snr: [i8; 4],
35    pub evm: [i8; 4],
36    pub pkt_rpt_type: RxPacketType,
37}
38
39impl Default for RxPacketAttrib {
40    fn default() -> Self {
41        Self {
42            pkt_len: 0,
43            physt: false,
44            drvinfo_sz: 0,
45            shift_sz: 0,
46            qos: false,
47            priority: 0,
48            mdata: false,
49            seq_num: 0,
50            frag_num: 0,
51            mfrag: false,
52            bdecrypted: false,
53            encrypt: 0,
54            crc_err: false,
55            icv_err: false,
56            tsfl: 0,
57            data_rate: 0,
58            bw: 0,
59            stbc: 0,
60            ldpc: 0,
61            sgi: 0,
62            scrambler: 0,
63            rssi: [0; 4],
64            snr: [0; 4],
65            evm: [0; 4],
66            pkt_rpt_type: RxPacketType::NormalRx,
67        }
68    }
69}
70
71#[derive(Debug, Clone, Copy)]
72pub struct RealtekRxPacket<'a> {
73    pub attrib: RxPacketAttrib,
74    pub data: &'a [u8],
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub enum AggregateError {
79    DescriptorTooShort,
80    InvalidPacketLength {
81        pkt_len: u16,
82        pkt_offset: usize,
83        remaining: usize,
84    },
85}
86
87impl std::fmt::Display for AggregateError {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        match self {
90            Self::DescriptorTooShort => write!(f, "RX descriptor is shorter than {RX_DESC_SIZE} bytes"),
91            Self::InvalidPacketLength {
92                pkt_len,
93                pkt_offset,
94                remaining,
95            } => write!(
96                f,
97                "invalid RX packet length: pkt_len={pkt_len}, pkt_offset={pkt_offset}, remaining={remaining}"
98            ),
99        }
100    }
101}
102
103impl std::error::Error for AggregateError {}
104
105pub fn parse_rx_descriptor(desc: &[u8]) -> Result<RxPacketAttrib, AggregateError> {
106    if desc.len() < RX_DESC_SIZE {
107        return Err(AggregateError::DescriptorTooShort);
108    }
109
110    let d0 = le32(desc, 0);
111    let d1 = le32(desc, 4);
112    let d2 = le32(desc, 8);
113    let d3 = le32(desc, 12);
114    let d4 = le32(desc, 16);
115    let d5 = le32(desc, 20);
116
117    Ok(RxPacketAttrib {
118        pkt_len: bits(d0, 0, 14) as u16,
119        crc_err: bits(d0, 14, 1) != 0,
120        icv_err: bits(d0, 15, 1) != 0,
121        drvinfo_sz: (bits(d0, 16, 4) * 8) as u8,
122        encrypt: bits(d0, 20, 3) as u8,
123        qos: bits(d0, 23, 1) != 0,
124        shift_sz: bits(d0, 24, 2) as u8,
125        physt: bits(d0, 26, 1) != 0,
126        bdecrypted: bits(d0, 27, 1) == 0,
127        priority: bits(d1, 8, 4) as u8,
128        mdata: bits(d1, 26, 1) != 0,
129        mfrag: bits(d1, 27, 1) != 0,
130        seq_num: bits(d2, 0, 12) as u16,
131        frag_num: bits(d2, 12, 4) as u8,
132        pkt_rpt_type: if bits(d2, 28, 1) != 0 {
133            RxPacketType::C2hPacket
134        } else {
135            RxPacketType::NormalRx
136        },
137        data_rate: bits(d3, 0, 7) as u8,
138        sgi: bits(d4, 0, 1) as u8,
139        ldpc: bits(d4, 1, 1) as u8,
140        stbc: bits(d4, 2, 1) as u8,
141        bw: bits(d4, 4, 2) as u8,
142        scrambler: bits(d4, 9, 7) as u8,
143        tsfl: d5,
144        ..Default::default()
145    })
146}
147
148pub fn parse_rx_aggregate(buf: &[u8]) -> Result<Vec<RealtekRxPacket<'_>>, AggregateError> {
149    let mut packets = Vec::new();
150    let mut offset = 0usize;
151
152    while offset < buf.len() {
153        let remaining = buf.len() - offset;
154        if remaining < RX_DESC_SIZE {
155            break;
156        }
157
158        let desc = &buf[offset..offset + RX_DESC_SIZE];
159        let mut attrib = parse_rx_descriptor(desc)?;
160        let data_start =
161            offset + RX_DESC_SIZE + attrib.drvinfo_sz as usize + attrib.shift_sz as usize;
162        let pkt_offset = RX_DESC_SIZE
163            + attrib.drvinfo_sz as usize
164            + attrib.shift_sz as usize
165            + attrib.pkt_len as usize;
166        if attrib.pkt_len == 0 || pkt_offset > remaining {
167            return Err(AggregateError::InvalidPacketLength {
168                pkt_len: attrib.pkt_len,
169                pkt_offset,
170                remaining,
171            });
172        }
173
174        if attrib.pkt_rpt_type == RxPacketType::NormalRx {
175            let phy_start = offset + RX_DESC_SIZE;
176            let phy_end = phy_start + attrib.drvinfo_sz as usize;
177            parse_phy_status(&mut attrib, &buf[phy_start..phy_end]);
178        }
179
180        let data_end = data_start + attrib.pkt_len as usize;
181        packets.push(RealtekRxPacket {
182            attrib,
183            data: &buf[data_start..data_end],
184        });
185
186        let aligned = round_up_8(pkt_offset);
187        if aligned >= remaining {
188            break;
189        }
190        offset += aligned;
191    }
192
193    Ok(packets)
194}
195
196const fn round_up_8(value: usize) -> usize {
197    (value + 7) & !7
198}
199
200fn le32(bytes: &[u8], offset: usize) -> u32 {
201    u32::from_le_bytes(
202        bytes[offset..offset + 4]
203            .try_into()
204            .expect("descriptor length checked"),
205    )
206}
207
208const fn bits(word: u32, offset: u8, len: u8) -> u32 {
209    if len == 32 {
210        word
211    } else {
212        (word >> offset) & ((1u32 << len) - 1)
213    }
214}
215
216fn parse_phy_status(attrib: &mut RxPacketAttrib, phy: &[u8]) {
217    if phy.len() < 2 {
218        return;
219    }
220
221    attrib.rssi[0] = phy[0];
222    attrib.rssi[1] = phy[1];
223
224    if phy.len() < 28 {
225        return;
226    }
227
228    attrib.rssi[2] = phy[23];
229    attrib.rssi[3] = phy[24];
230    attrib.snr[0] = phy[15] as i8;
231    attrib.snr[1] = phy[16] as i8;
232    attrib.snr[2] = phy[21] as i8;
233    attrib.snr[3] = phy[22] as i8;
234    attrib.evm[0] = phy[13] as i8;
235    attrib.evm[1] = phy[14] as i8;
236    attrib.evm[2] = phy[19] as i8;
237    attrib.evm[3] = phy[20] as i8;
238}
239
240#[cfg(test)]
241mod tests {
242    use super::*;
243
244    fn put_bits(word: &mut u32, offset: u8, len: u8, value: u32) {
245        let mask = ((1u32 << len) - 1) << offset;
246        *word = (*word & !mask) | ((value << offset) & mask);
247    }
248
249    fn descriptor(pkt_len: u16, drvinfo_units: u8, shift: u8, seq: u16) -> [u8; RX_DESC_SIZE] {
250        let mut desc = [0; RX_DESC_SIZE];
251        let mut d0 = 0u32;
252        put_bits(&mut d0, 0, 14, pkt_len as u32);
253        put_bits(&mut d0, 16, 4, drvinfo_units as u32);
254        put_bits(&mut d0, 24, 2, shift as u32);
255        let mut d2 = 0u32;
256        put_bits(&mut d2, 0, 12, seq as u32);
257        desc[0..4].copy_from_slice(&d0.to_le_bytes());
258        desc[8..12].copy_from_slice(&d2.to_le_bytes());
259        desc
260    }
261
262    #[test]
263    fn parses_single_rx_packet() {
264        let mut aggregate = Vec::new();
265        aggregate.extend_from_slice(&descriptor(4, 0, 0, 77));
266        aggregate.extend_from_slice(&[1, 2, 3, 4]);
267
268        let packets = parse_rx_aggregate(&aggregate).unwrap();
269        assert_eq!(packets.len(), 1);
270        assert_eq!(packets[0].attrib.pkt_len, 4);
271        assert_eq!(packets[0].attrib.seq_num, 77);
272        assert_eq!(packets[0].data, &[1, 2, 3, 4]);
273    }
274
275    #[test]
276    fn advances_by_jaguar_eight_byte_alignment() {
277        let mut aggregate = Vec::new();
278        aggregate.extend_from_slice(&descriptor(5, 0, 0, 1));
279        aggregate.extend_from_slice(&[1, 2, 3, 4, 5]);
280        aggregate.extend_from_slice(&[0, 0, 0]);
281        aggregate.extend_from_slice(&descriptor(3, 0, 0, 2));
282        aggregate.extend_from_slice(&[6, 7, 8]);
283
284        let packets = parse_rx_aggregate(&aggregate).unwrap();
285        assert_eq!(packets.len(), 2);
286        assert_eq!(packets[0].data, &[1, 2, 3, 4, 5]);
287        assert_eq!(packets[1].data, &[6, 7, 8]);
288    }
289}