esp_csi_rs/csi.rs
1#[cfg(feature = "println")]
2use esp_println as _;
3#[cfg(feature = "println")]
4use esp_println::println;
5
6#[cfg(feature = "defmt")]
7use defmt::info;
8#[cfg(feature = "defmt")]
9use defmt::println;
10
11use heapless::Vec;
12
13use crate::{DateTime, RxCSIFmt};
14
15// CSI Received Packet Radio Metadata Header Value Interpretations for non-ESP32-C6 devices
16
17// rssi: Received Signal Strength Indicator(RSSI) of packet. unit: dBm.
18// rate: PHY rate encoding of the packet. Only valid for non HT(11bg) packet.
19// sig_mode: Protocol of the received packet, 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet.
20// mcs: Modulation Coding Scheme. If is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76).
21// cwb: Channel Bandwidth of the packet. 0: 20MHz; 1: 40MHz.
22// smoothing: Set to 1 indicates that channel estimate smoothing is recommended. Set to 0 indicates that only per-carrier independent (unsmoothed) channel estimate is recommended.
23// not_sounding: Set to 0 indicates that PPDU is a sounding PPDU. Set to 1 indicates that the PPDU is not a sounding PPDU. Sounding PPDU is used for channel estimation by the request receiver.
24// aggregation: Aggregation. 0: MPDU packet; 1: AMPDU packet
25// stbc: Space Time Block Code(STBC). 0: non STBC packet; 1: STBC packet.
26// fec_coding: Forward Error Correction (FEC). Flag is set for 11n packets which are LDPC.
27// sgi: Short Guide Interval (SGI). 0: Long GI; 1: Short GI.
28// noise_floor: noise floor of Radio Frequency Module(RF). unit: dBm.
29// ampdu_cnt: The number of subframes aggregated in AMPDU.
30// channel: Primary channel on which this packet is received.
31// secondary_channel: Secondary channel on which this packet is received. 0: none; 1: above; 2: below.
32// timestamp: Timestamp. The local time when this packet is received. It is precise only if modem sleep or light sleep is not enabled. The timer is started when controller.start() is returned. unit: microsecond.
33// noise_floor: Noise floor of Radio Frequency Module(RF). unit: dBm.
34// ant: Antenna number from which this packet is received. 0: WiFi antenna 0; 1: WiFi antenna 1.
35// noise_floor: Noise floor of Radio Frequency Module(RF). unit: dBm.
36// sig_len: Length of packet including Frame Check Sequence(FCS).
37// rx_state: State of the packet. 0: no error; others: error numbers which are not public.
38
39// CSI Received Packet Radio Metadata Header Value Interpretations for ESP32-C6 devices
40
41// rssi: Received Signal Strength Indicator (RSSI) of the packet, in dBm.
42// rate: PHY rate encoding of the packet. Only valid for non-HT (802.11b/g) packets.
43// sig_len: Length of the received packet including the Frame Check Sequence (FCS).
44// rx_state: Reception state of the packet: 0 for no error, others indicate error codes.
45// dump_len: Length of the dump buffer.
46// he_sigb_len: Length of HE-SIG-B field (802.11ax).
47// cur_single_mpdu: Indicates if this is a single MPDU.
48// cur_bb_format: Current baseband format.
49// rx_channel_estimate_info_vld: Channel estimation validity.
50// rx_channel_estimate_len: Length of the channel estimation.
51// second: Timing information in seconds.
52// channel: Primary channel on which the packet is received.
53// noise_floor: Noise floor of the Radio Frequency module, in dBm.
54// is_group: Indicates if this is a group-addressed frame.
55// rxend_state: End state of the packet reception.
56// rxmatch3: Indicate whether the reception frame is from interface 3.
57// rxmatch2: Indicate whether the reception frame is from interface 2.
58// rxmatch1: Indicate whether the reception frame is from interface 1.
59// rxmatch0: Indicate whether the reception frame is from interface 0.
60
61/// CSI Received Packet w/ Radio Metadata
62#[cfg(not(feature = "esp32c6"))]
63#[derive(Debug, Clone)]
64pub struct CSIDataPacket {
65 /// MAC address of the sender.
66 pub mac: [u8; 6],
67 /// Received Signal Strength Indicator.
68 pub rssi: i32,
69 /// Local Timestamp of Recieved Packet (microseconds) .
70 pub timestamp: u32,
71 /// PHY rate encoding of the packet. Only valid for non HT(11bg) packet.
72 pub rate: u32,
73 /// Short Guide Interval (SGI). 0: Long GI; 1: Short GI.
74 pub sgi: u32,
75 /// Secondary Channel on which the Packet was Received.
76 /// 0: none; 1: above; 2: below.
77 pub secondary_channel: u32,
78 /// Primary channel on which the Packet was Received.
79 pub channel: u32,
80 /// Channel Bandwidth of the packet.
81 /// 0: 20MHz; 1: 40MHz.
82 pub bandwidth: u32,
83 /// Antenna number from which this packet is received.
84 /// 0: WiFi antenna 0; 1: WiFi antenna 1.
85 pub antenna: u32,
86 /// Protocol of the received packet.
87 /// 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet.
88 pub sig_mode: u32,
89 /// Modulation Coding Scheme.
90 /// If Packet is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76).
91 pub mcs: u32,
92 /// Set to 1 indicates that channel estimate smoothing is recommended.
93 /// Set to 0 indicates that only per-carrier independent (unsmoothed) channel estimate is recommended.
94 pub smoothing: u32,
95 /// Sounding PPDU is used for channel estimation by the request receiver.
96 /// Set to 0 indicates that PPDU is a sounding PPDU.
97 /// Set to 1 indicates that the PPDU is not a sounding PPDU.
98 pub not_sounding: u32,
99 /// Aggregation.
100 /// 0: MPDU packet; 1: AMPDU packet
101 pub aggregation: u32,
102 /// Space-Time Block Coding.
103 /// 0: non STBC packet; 1: STBC packet.
104 pub stbc: u32,
105 /// Forward Error Correction (FEC).
106 /// Flag is set for 11n packets which are LDPC.
107 pub fec_coding: u32,
108 /// The number of subframes aggregated in AMPDU.
109 pub ampdu_cnt: u32,
110 /// Noise floor of Radio Frequency Module(RF).
111 /// unit: dBm.
112 pub noise_floor: i32,
113 /// RX state.
114 /// 0: no error; others: error numbers which are not public.
115 pub rx_state: u32,
116 /// Length of packet including Frame Check Sequence(FCS).
117 pub sig_len: u32,
118 /// Optional NTP-based Timestamp Indicating the Time CSI Captured.
119 pub date_time: Option<DateTime>,
120 /// Sequence Number Associated with the ICMP Echo Request Packet that triggered a CSI capture.
121 pub sequence_number: u16,
122 /// Data format of the recieved CSI.
123 /// RxCSIFmt is a Compact Representation of the Different Recieved CSI Data Format Options as defined in the ESP WiFi Driver.
124 pub data_format: RxCSIFmt,
125 /// Length of CSI data.
126 pub csi_data_len: u16,
127 /// Raw CSI data, largest case size is 612 bytes.
128 pub csi_data: Vec<i8, 612>,
129}
130
131#[cfg(not(feature = "esp32c6"))]
132impl CSIDataPacket {
133 /// Prints Recieved CSI Data Packet with it's Metadata
134 pub fn print_csi_w_metadata(&self) {
135 if let Some(date_time) = &self.date_time {
136 println!(
137 "Recieved at {:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}",
138 date_time.year,
139 date_time.month,
140 date_time.day,
141 date_time.hour,
142 date_time.minute,
143 date_time.second,
144 date_time.millisecond
145 );
146 }
147 println!(
148 "mac: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
149 self.mac[0], self.mac[1], self.mac[2], self.mac[3], self.mac[4], self.mac[5]
150 );
151 println!("rssi: {}", self.rssi);
152 println!("rate: {}", self.rate);
153 println!("noise floor: {}", self.noise_floor);
154 println!("channel: {}", self.channel);
155 println!("timestamp: {}", self.timestamp);
156 println!("sig len: {}", self.sig_len);
157 println!("rx state: {}", self.rx_state);
158 println!("secondary channel: {}", self.secondary_channel);
159 println!("sgi: {}", self.sgi);
160 println!("ant: {}", self.antenna);
161 println!("ampdu cnt: {}", self.ampdu_cnt);
162 println!("sig_mode: {}", self.sig_mode);
163 println!("mcs: {}", self.mcs);
164 println!("cwb: {}", self.bandwidth);
165 println!("smoothing: {}", self.smoothing);
166 println!("not sounding: {}", self.not_sounding);
167 println!("aggregation: {}", self.aggregation);
168 println!("stbc: {}", self.stbc);
169 println!("fec coding: {}", self.fec_coding);
170 println!("sig_len: {}", self.sig_len);
171 println!("data length: {}", self.csi_data_len);
172 println!("csi raw data:");
173 #[cfg(feature = "defmt")]
174 println!("{=[?]}", self.csi_data);
175 #[cfg(feature = "println")]
176 println!("{:?}", self.csi_data);
177 }
178
179 // Retrieves `RxCSIFmt` for a `CSIDataPacket`
180 // The RxCSIFmt enum is a mapping of the different possible recieved CSI data formats supported by the Espressif WiFi driver.
181 // RxCSIFmt encodes the different formats (each column in the table) in one byte to save space
182 // More details on the different data formats can be found in the ESP CSI WiFi driver here:
183 // https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/wifi.html#wi-fi-channel-state-information
184 //
185 // The encoding is as follows:
186 // Bw20 => 0. Secondary Channel = None, Signal Mode = non-HT, Channel BW = 20MHz, non-STBC
187 // HtBw20 => 1 Secondary Channel = None, Signal Mode = HT, Channel BW = 20MHz, non-STBC
188 // HtBw20Stbc => 2 Secondary Channel = None, Signal Mode = HT, Channel BW = 20MHz, STBC
189 // SecbBw20 => 3 Secondary Channel = Below, Signal Mode = non-HT, Channel BW = 20MHz, non-STBC
190 // SecbHtBw20 => 4 Secondary Channel = Below, Signal Mode = HT, Channel BW = 20MHz, non-STBC
191 // SecbHtBw20Stbc => 5 Secondary Channel = Below, Signal Mode = HT, Channel BW = 20MHz, STBC
192 // SecbHtBw40 => 6 Secondary Channel = Below, Signal Mode = HT, Channel BW = 40MHz, non-STBC
193 // SecbHtBw40Stbc => 7 Secondary Channel = Below, Signal Mode = HT, Channel BW = 40MHz, STBC
194 // SecaBw20 => 8 Secondary Channel = Above, Signal Mode = non-HT, Channel BW = 20MHz, non-STBC
195 // SecaHtBw20 => 9 Secondary Channel = Above, Signal Mode = HT, Channel BW = 20MHz, non-STBC
196 // SecaHtBw20Stbc => 10 Secondary Channel = Above, Signal Mode = HT, Channel BW = 20MHz, STBC
197 // SecaHtBw40 => 11 Secondary Channel = Above, Signal Mode = HT, Channel BW = 40MHz, non-STBC
198 // SecaHtBw40Stbc => 12 Secondary Channel = Above, Signal Mode = HT, Channel BW = 40MHz, STBC
199 // Undefined => 13
200 pub fn csi_fmt_from_params(&mut self) {
201 match self.secondary_channel {
202 // None
203 0 => {
204 match self.sig_mode {
205 // non-HTc
206 0 => self.data_format = RxCSIFmt::Bw20,
207 // HT
208 1 => {
209 match self.stbc {
210 // non-STBC
211 0 => self.data_format = RxCSIFmt::HtBw20,
212 // STBC
213 1 => self.data_format = RxCSIFmt::HtBw20Stbc,
214 _ => self.data_format = RxCSIFmt::Undefined,
215 }
216 }
217 _ => self.data_format = RxCSIFmt::Undefined,
218 }
219 }
220 // Above
221 1 => {
222 match self.sig_mode {
223 // non-HT
224 0 => self.data_format = RxCSIFmt::SecaBw20,
225 // HT
226 1 => {
227 match self.bandwidth {
228 // 20MHz
229 0 => {
230 match self.stbc {
231 // non-STBC
232 0 => self.data_format = RxCSIFmt::SecaHtBw20,
233 // STBC
234 1 => self.data_format = RxCSIFmt::SecaHtBw20Stbc,
235 _ => self.data_format = RxCSIFmt::Undefined,
236 }
237 }
238 // 40MHz
239 1 => {
240 match self.stbc {
241 // non-STBC
242 0 => self.data_format = RxCSIFmt::SecaHtBw40,
243 // STBC
244 1 => self.data_format = RxCSIFmt::SecaHtBw40Stbc,
245 _ => self.data_format = RxCSIFmt::Undefined,
246 }
247 }
248 _ => self.data_format = RxCSIFmt::Undefined,
249 }
250 }
251 _ => self.data_format = RxCSIFmt::Undefined,
252 }
253 }
254 // Below
255 2 => {
256 match self.sig_mode {
257 // non-HT
258 0 => self.data_format = RxCSIFmt::SecbBw20,
259 // HT
260 1 => {
261 match self.bandwidth {
262 // 20MHz
263 0 => {
264 match self.stbc {
265 // non-STBC
266 0 => self.data_format = RxCSIFmt::SecbHtBw20,
267 // STBC
268 1 => self.data_format = RxCSIFmt::SecbHtBw20Stbc,
269 _ => self.data_format = RxCSIFmt::Undefined,
270 }
271 }
272 // 40MHz
273 1 => {
274 match self.stbc {
275 // non-STBC
276 0 => self.data_format = RxCSIFmt::SecbHtBw40,
277 // STBC
278 1 => self.data_format = RxCSIFmt::SecbHtBw40Stbc,
279 _ => self.data_format = RxCSIFmt::Undefined,
280 }
281 }
282 _ => self.data_format = RxCSIFmt::Undefined,
283 }
284 }
285 _ => self.data_format = RxCSIFmt::Undefined,
286 }
287 }
288 _ => self.data_format = RxCSIFmt::Undefined,
289 }
290 }
291
292 pub fn mac(&self) -> &[u8; 6] {
293 &self.mac
294 }
295 pub fn rssi(&self) -> i32 {
296 self.rssi
297 }
298 pub fn timestamp(&self) -> u32 {
299 self.timestamp
300 }
301 pub fn rate(&self) -> u32 {
302 self.rate
303 }
304 pub fn sgi(&self) -> u32 {
305 self.sgi
306 }
307 pub fn secondary_channel(&self) -> u32 {
308 self.secondary_channel
309 }
310 pub fn channel(&self) -> u32 {
311 self.channel
312 }
313 pub fn bandwidth(&self) -> u32 {
314 self.bandwidth
315 }
316 pub fn antenna(&self) -> u32 {
317 self.antenna
318 }
319 pub fn sig_mode(&self) -> u32 {
320 self.sig_mode
321 }
322 pub fn mcs(&self) -> u32 {
323 self.mcs
324 }
325 pub fn smoothing(&self) -> u32 {
326 self.smoothing
327 }
328 pub fn not_sounding(&self) -> u32 {
329 self.not_sounding
330 }
331 pub fn aggregation(&self) -> u32 {
332 self.aggregation
333 }
334 pub fn stbc(&self) -> u32 {
335 self.stbc
336 }
337 pub fn fec_coding(&self) -> u32 {
338 self.fec_coding
339 }
340 pub fn ampdu_cnt(&self) -> u32 {
341 self.ampdu_cnt
342 }
343 pub fn noise_floor(&self) -> i32 {
344 self.noise_floor
345 }
346 pub fn rx_state(&self) -> u32 {
347 self.rx_state
348 }
349 pub fn sig_len(&self) -> u32 {
350 self.sig_len
351 }
352 pub fn date_time(&self) -> Option<&DateTime> {
353 self.date_time.as_ref()
354 }
355 pub fn sequence_number(&self) -> u16 {
356 self.sequence_number
357 }
358 pub fn data_format(&self) -> RxCSIFmt {
359 self.data_format.clone()
360 }
361 pub fn csi_data_len(&self) -> u16 {
362 self.csi_data_len
363 }
364 pub fn csi_data(&self) -> &[i8] {
365 self.csi_data.as_slice()
366 }
367}
368
369#[cfg(feature = "esp32c6")]
370#[derive(Debug, Clone)]
371pub struct CSIDataPacket {
372 /// MAC address of the sender.
373 pub mac: [u8; 6],
374 /// Received Signal Strength Indicator.
375 pub rssi: i32,
376 /// Local Timestamp of Recieved Packet (microseconds).
377 pub timestamp: u32,
378 /// PHY rate encoding of the packet.
379 pub rate: u32,
380 /// Noise floor of Radio Frequency Module(RF).
381 /// unit: dBm.
382 pub noise_floor: i32,
383 /// Length of packet including Frame Check Sequence(FCS).
384 pub sig_len: u32,
385 /// Reception state of the packet.
386 /// 0 for no error, others indicate error codes.
387 pub rx_state: u32,
388 /// Length of dump buffer.
389 pub dump_len: u32,
390 /// Length of HE-SIG-B field (802.11ax).
391 pub he_sigb_len: u32,
392 /// Indicates if this is a single MPDU.
393 pub cur_single_mpdu: u32,
394 /// Current baseband format.
395 pub cur_bb_format: u32,
396 /// Channel estimation validity.
397 pub rx_channel_estimate_info_vld: u32,
398 /// Length of the channel estimation.
399 pub rx_channel_estimate_len: u32,
400 /// Timing information in seconds.
401 pub second: u32,
402 /// Primary channel on which the packet is received.
403 pub channel: u32,
404 /// Indicates if this is a group-addressed frame.
405 pub is_group: u32,
406 /// End state of the packet reception.
407 pub rxend_state: u32,
408 /// Indicate whether the reception frame is from interface 3.
409 pub rxmatch3: u32,
410 /// Indicate whether the reception frame is from interface 2.
411 pub rxmatch2: u32,
412 /// Indicate whether the reception frame is from interface 1.
413 pub rxmatch1: u32,
414 /// Indicate whether the reception frame is from interface 0.
415 pub rxmatch0: u32,
416 /// Optional NTP-based Timestamp Indicating the Time CSI Captured.
417 pub date_time: Option<DateTime>,
418 /// Sequence number associated with packet.
419 pub sequence_number: u16,
420 /// Length of CSI data.
421 pub csi_data_len: u16,
422 /// Data format of the recieved CSI.
423 /// RxCSIFmt is a Compact Representation of the Different Recieved CSI Data Format Options as defined in the ESP WiFi Driver.
424 pub data_format: RxCSIFmt,
425 /// Raw CSI data, largest case size is 612 bytes.
426 pub csi_data: Vec<i8, 612>,
427}
428
429#[cfg(feature = "esp32c6")]
430impl CSIDataPacket {
431 pub fn print_csi_w_metadata(&self) {
432 // Calculate Elapsed time here and add offset to date_time then call to calculate new time
433 if let Some(date_time) = &self.date_time {
434 println!(
435 "Recieved at {:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}",
436 date_time.year,
437 date_time.month,
438 date_time.day,
439 date_time.hour,
440 date_time.minute,
441 date_time.second,
442 date_time.millisecond
443 );
444 }
445 println!(
446 "mac: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
447 self.mac[0], self.mac[1], self.mac[2], self.mac[3], self.mac[4], self.mac[5]
448 );
449 println!("rssi: {}", self.rssi);
450 println!("rate: {}", self.rate);
451 println!("noise floor: {}", self.noise_floor);
452 println!("channel: {}", self.channel);
453 println!("timestamp: {}", self.timestamp);
454 println!("rx state: {}", self.rx_state);
455 println!("dump len: {}", self.dump_len);
456 println!("he sigb len: {}", self.he_sigb_len);
457 println!("cur single mpdu: {}", self.cur_single_mpdu);
458 println!("cur bb format: {}", self.cur_bb_format);
459 println!(
460 "rx channel estimate info vld: {}",
461 self.rx_channel_estimate_info_vld
462 );
463 println!("rx channel estimate len: {}", self.rx_channel_estimate_len);
464 println!("second: {}", self.second);
465 println!("is group: {}", self.is_group);
466 println!("rxend state: {}", self.rxend_state);
467 println!("rxmatch3: {}", self.rxmatch3);
468 println!("rxmatch2: {}", self.rxmatch2);
469 println!("rxmatch1: {}", self.rxmatch1);
470 println!("rxmatch0: {}", self.rxmatch0);
471 println!("sig len: {}", self.sig_len);
472 println!("data length: {}", self.csi_data_len);
473 println!("csi raw data:");
474 #[cfg(feature = "defmt")]
475 println!("{=[?]}", self.csi_data);
476 #[cfg(feature = "println")]
477 println!("{:?}", self.csi_data);
478 }
479 pub fn csi_fmt_from_params(&mut self) {
480 self.data_format = RxCSIFmt::Undefined;
481 }
482
483 pub fn mac(&self) -> &[u8; 6] {
484 &self.mac
485 }
486
487 pub fn rssi(&self) -> i32 {
488 self.rssi
489 }
490 pub fn timestamp(&self) -> u32 {
491 self.timestamp
492 }
493 pub fn rate(&self) -> u32 {
494 self.rate
495 }
496 pub fn noise_floor(&self) -> i32 {
497 self.noise_floor
498 }
499 pub fn sig_len(&self) -> u32 {
500 self.sig_len
501 }
502 pub fn rx_state(&self) -> u32 {
503 self.rx_state
504 }
505 pub fn dump_len(&self) -> u32 {
506 self.dump_len
507 }
508 pub fn he_sigb_len(&self) -> u32 {
509 self.he_sigb_len
510 }
511 pub fn cur_single_mpdu(&self) -> u32 {
512 self.cur_single_mpdu
513 }
514 pub fn cur_bb_format(&self) -> u32 {
515 self.cur_bb_format
516 }
517 pub fn rx_channel_estimate_info_vld(&self) -> u32 {
518 self.rx_channel_estimate_info_vld
519 }
520 pub fn rx_channel_estimate_len(&self) -> u32 {
521 self.rx_channel_estimate_len
522 }
523 pub fn second(&self) -> u32 {
524 self.second
525 }
526 pub fn channel(&self) -> u32 {
527 self.channel
528 }
529 pub fn is_group(&self) -> u32 {
530 self.is_group
531 }
532 pub fn rxend_state(&self) -> u32 {
533 self.rxend_state
534 }
535 pub fn rxmatch3(&self) -> u32 {
536 self.rxmatch3
537 }
538 pub fn rxmatch2(&self) -> u32 {
539 self.rxmatch2
540 }
541 pub fn rxmatch1(&self) -> u32 {
542 self.rxmatch1
543 }
544 pub fn rxmatch0(&self) -> u32 {
545 self.rxmatch0
546 }
547 pub fn csi_data(&self) -> &[i8] {
548 self.csi_data.as_slice()
549 }
550 pub fn csi_data_len(&self) -> u16 {
551 self.csi_data_len
552 }
553}