1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
use core::cell::RefCell;
use crate::esp_wifi_sys::include::wifi_pkt_rx_ctrl_t;
use embassy_sync::blocking_mutex;
use esp_hal::dma::DmaDescriptor;
use macro_bits::{bit, check_bit};
use crate::{
DefaultRawMutex,
async_driver::WiFi,
dma_list::DmaList,
ll::{INTERFACE_COUNT, LowLevelDriver},
rates::{HrDsssRate, HtRate, OfdmRate, RxPhyRate},
};
/// A buffer borrowed from the DMA list.
pub struct BorrowedBuffer<'res> {
pub(crate) dma_list: &'res blocking_mutex::Mutex<DefaultRawMutex, RefCell<DmaList>>,
pub(crate) dma_descriptor: &'res mut DmaDescriptor,
}
impl BorrowedBuffer<'_> {
/// The length of the hardware header.
pub const RX_CONTROL_HEADER_LENGTH: usize = size_of::<wifi_pkt_rx_ctrl_t>();
/// This returns the raw buffer, which is still padded with zeros to the nearest word boundary.
/// Apparently the Wi-Fi MAC only does transfers with word aligned lengths, so the remaining
/// bytes are filled with zeros. This buffer contains the RX control header and MPDU without
/// FCS or MIC.
pub fn padded_buffer(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(self.dma_descriptor.buffer, self.dma_descriptor.len())
}
}
/// See [Self::padded_buffer] for docs.
pub fn padded_buffer_mut(&mut self) -> &mut [u8] {
unsafe {
core::slice::from_raw_parts_mut(self.dma_descriptor.buffer, self.dma_descriptor.len())
}
}
/// Get a pointer to the RX control header.
pub const fn raw_header(&self) -> &wifi_pkt_rx_ctrl_t {
unsafe {
(self.dma_descriptor.buffer as *mut wifi_pkt_rx_ctrl_t)
.as_ref()
.unwrap()
}
}
/// Calculate the length of the trailer.
///
/// This includes MIC and FCS, which are conveniently all a multiple of 32 bits in length.
/// And all of that, since it apparently wasn't possible to put the correct length in the DMA
/// descriptor...
/// Frostie314159: This caused me such a fucking headache.
pub fn trailer_length(&self) -> usize {
let padded_len = self.dma_descriptor.len() - Self::RX_CONTROL_HEADER_LENGTH;
let delta = self.raw_header().sig_len() as usize - padded_len;
if delta & 0b11 == 0 {
delta
} else {
(delta & !0b11) + 4
}
}
/// Calculate the actual unpadded length of the buffer.
pub fn unpadded_buffer_len(&self) -> usize {
self.raw_header().sig_len() as usize - self.trailer_length()
+ Self::RX_CONTROL_HEADER_LENGTH
}
/// Returns the raw buffer returned by the hardware.
///
/// This includes the header added by the hardware.
pub fn raw_buffer(&self) -> &[u8] {
self.padded_buffer()
.get(..self.unpadded_buffer_len())
.unwrap_or_else(|| {
/*
defmt_or_log::warn!(
"Buffer was shorter then calculated length. Corrected len: {} Padded len: {} SIG len: {} Header: {:02x}",
self.unpadded_buffer_len(),
self.dma_descriptor.len(),
self.raw_header().sig_len(),
&self.padded_buffer()[..Self::RX_CONTROL_HEADER_LENGTH]
);*/
self.dma_list.lock(|dma_list| dma_list.borrow().log_stats());
self.padded_buffer()
})
}
/// Same as [Self::raw_buffer], but mutable.
pub fn raw_buffer_mut(&mut self) -> &mut [u8] {
let unpadded_len = self.unpadded_buffer_len();
&mut self.padded_buffer_mut()[..unpadded_len]
}
/// Returns the actual MPDU from the buffer excluding the prepended RX control header.
pub fn mpdu_buffer(&self) -> &[u8] {
&self.raw_buffer()[Self::RX_CONTROL_HEADER_LENGTH..]
}
/// Same as [Self::mpdu_buffer], but mutable.
pub fn mpdu_buffer_mut(&mut self) -> &mut [u8] {
&mut self.raw_buffer_mut()[Self::RX_CONTROL_HEADER_LENGTH..]
}
/// Returns the header attached by the hardware.
pub fn header_buffer(&self) -> &[u8] {
&self.padded_buffer()[..Self::RX_CONTROL_HEADER_LENGTH]
}
/// Same as [Self::header_buffer], but mutable.
pub fn header_buffer_mut(&mut self) -> &mut [u8] {
&mut self.padded_buffer_mut()[..Self::RX_CONTROL_HEADER_LENGTH]
}
/// The Received Signal Strength Indicator (RSSI).
pub fn rssi(&self) -> i8 {
let rssi = self.raw_header().rssi() as i8;
let offset = cfg_select! {
feature = "esp32" => {
-96
}
_ => {
0
}
};
rssi + offset
}
/// The time at which the packet was received in µs.
pub fn timestamp(&self) -> u32 {
self.raw_header().timestamp()
}
/// The time the packet was received, corrected for the difference between MAC and system
/// clock.
pub fn corrected_timestamp(&self) -> embassy_time::Instant {
embassy_time::Instant::from_micros(
self.timestamp() as u64 + LowLevelDriver::mac_time_offset().as_micros(),
)
}
/// Check if the frame is an A-MPDU.
pub fn aggregation(&self) -> bool {
check_bit!(self.header_buffer()[7], bit!(3))
}
/// The phy rate, at which this frame was transmitted.
pub fn phy_rate(&self) -> Option<RxPhyRate> {
let raw_header = self.raw_header();
let cbw40 = raw_header.cwb() == 1;
let short_gi = raw_header.sgi() == 1;
let mcs = raw_header.mcs() as u8;
let rate = raw_header.rate() as u8;
match raw_header.sig_mode() {
0 => {
if rate <= 7 {
HrDsssRate::new(rate % 4, rate / 4 == 1).map(RxPhyRate::HrDsss)
} else if rate <= 15 {
Some(RxPhyRate::Ofdm(match rate {
0x0b => OfdmRate::Mbits6,
0x0f => OfdmRate::Mbits9,
0x0a => OfdmRate::Mbits12,
0x0e => OfdmRate::Mbits18,
0x09 => OfdmRate::Mbits24,
0x0d => OfdmRate::Mbits36,
0x08 => OfdmRate::Mbits48,
0x0c => OfdmRate::Mbits54,
_ => unreachable!(),
}))
} else {
None
}
}
1 => HtRate::new(mcs, short_gi, cbw40).map(RxPhyRate::Ht),
_ => None,
}
}
/// Check if the frame is for the specified interface.
pub fn is_frame_for_interface(&self, interface: usize) -> bool {
WiFi::validate_interface(interface).is_ok()
&& check_bit!(self.header_buffer()[3], bit!(interface + 4))
}
/// Get an iterator over the interfaces, to which this frame is addressed.
pub fn interface_iterator(&self) -> impl Iterator<Item = usize> + '_ {
let byte = self.header_buffer()[3];
(0..INTERFACE_COUNT).filter(move |interface| check_bit!(byte, bit!(interface + 4)))
}
/// Unknown RX state.
///
/// We don't really know what this means, but it is presumably a bitmap. Currently this is only
/// intended for debugging purposes.
pub fn rx_state(&self) -> u8 {
self.header_buffer()[Self::RX_CONTROL_HEADER_LENGTH - 1]
}
/// Check if the contained MPDU is a fragment.
pub fn is_fragment(&self) -> bool {
self.raw_buffer()
.get(Self::RX_CONTROL_HEADER_LENGTH + 1)
.map(|byte| byte & 4 != 0)
.unwrap_or_default()
}
}
impl Drop for BorrowedBuffer<'_> {
fn drop(&mut self) {
self.dma_list.lock(|dma_list| {
dma_list.borrow_mut().recycle(self.dma_descriptor);
});
}
}