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}