esp-csi-rs 0.6.2

ESP CSI Driver for Rust
Documentation
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
//! CSI packet types and frame-format definitions.
//!
//! Defines the wire-level [`CSIDataPacket`] emitted to host tooling and the
//! [`RxCSIFmt`] enumeration mirroring Espressif's HT/non-HT/HE-SU receive
//! mode classification used to decode CSI tones.

use heapless::Vec;
use postcard::experimental::max_size::MaxSize;
use serde::{Deserialize, Serialize};
use crate::time::DateTime;

/// A mapping of the different possible recieved CSI data formats supported by the Espressif WiFi driver.
/// `RxCSIFmt`` encodes the different formats (each column in the table) in one byte to save space when transmitting back CSI data.
/// The driver can be found here:
/// <https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/wifi.html#wi-fi-channel-state-information>
#[derive(Debug, Clone, Serialize, Deserialize, MaxSize)]
#[repr(u8)]
pub enum RxCSIFmt {
    /// Sec Chnl = None, Sig Mode = non-Ht, Chnl BW = 20MHz, non-STBC
    Bw20,
    /// Sec Chnl = None, Sig Mode = Ht, Chnl BW = 20MHz, non-STBC         
    HtBw20,
    /// Sec Chnl = None, Sig Mode = Ht, Chnl BW = 20MHz, STBC
    HtBw20Stbc,
    /// Sec Chnl = Below, Sig Mode = non-Ht, Chnl BW = 20MHz, non-STBC
    SecbBw20,
    /// Sec Chnl = Below, Sig Mode = Ht, Chnl BW = 20MHz, non-STBC
    SecbHtBw20,
    /// Sec Chnl = Below, Sig Mode = Ht, Chnl BW = 20MHz, STBC
    SecbHtBw20Stbc,
    /// Sec Chnl = Below, Sig Mode = Ht, Chnl BW = 40MHz, non-STBC
    SecbHtBw40,
    /// Sec Chnl = Below, Sig Mode = Ht, Chnl BW = 40MHz, STBC
    SecbHtBw40Stbc,
    /// Sec Chnl = Above, Sig Mode = non-Ht, Chnl BW = 20MHz, non-STBC
    SecaBw20,
    /// Sec Chnl = Above, Sig Mode = Ht, Chnl BW = 20MHz, non-STBC
    SecaHtBw20,
    /// Sec Chnl = Above, Sig Mode = Ht, Chnl BW = 20MHz, STBC
    SecaHtBw20Stbc,
    /// Sec Chnl = Above, Sig Mode = Ht, Chnl BW = 40MHz, non-STBC
    SecaHtBw40,
    /// Sec Chnl = Above, Sig Mode = Ht, Chnl BW = 40MHz, STBC
    SecaHtBw40Stbc,
    /// Not a defined format
    Undefined,
}

// CSI Received Packet Radio Metadata Header Value Interpretations for non-ESP32-C6 devices

// rssi: Received Signal Strength Indicator(RSSI) of packet. unit: dBm.
// rate: PHY rate encoding of the packet. Only valid for non HT(11bg) packet.
// sig_mode: Protocol of the received packet, 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet.
// mcs: Modulation Coding Scheme. If is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76).
// cwb: Channel Bandwidth of the packet. 0: 20MHz; 1: 40MHz.
// 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.
// 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.
// aggregation: Aggregation. 0: MPDU packet; 1: AMPDU packet
// stbc: Space Time Block Code(STBC). 0: non STBC packet; 1: STBC packet.
// fec_coding: Forward Error Correction (FEC). Flag is set for 11n packets which are LDPC.
// sgi: Short Guide Interval (SGI). 0: Long GI; 1: Short GI.
// noise_floor: noise floor of Radio Frequency Module(RF). unit: dBm.
// ampdu_cnt: The number of subframes aggregated in AMPDU.
// channel: Primary channel on which this packet is received.
// secondary_channel: Secondary channel on which this packet is received. 0: none; 1: above; 2: below.
// 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.
// noise_floor: Noise floor of Radio Frequency Module(RF). unit: dBm.
// ant: Antenna number from which this packet is received. 0: WiFi antenna 0; 1: WiFi antenna 1.
// noise_floor: Noise floor of Radio Frequency Module(RF). unit: dBm.
// sig_len: Length of packet including Frame Check Sequence(FCS).
// rx_state: State of the packet. 0: no error; others: error numbers which are not public.

// CSI Received Packet Radio Metadata Header Value Interpretations for ESP32-C6 devices

// rssi: Received Signal Strength Indicator (RSSI) of the packet, in dBm.
// rate: PHY rate encoding of the packet. Only valid for non-HT (802.11b/g) packets.
// sig_len: Length of the received packet including the Frame Check Sequence (FCS).
// rx_state: Reception state of the packet: 0 for no error, others indicate error codes.
// dump_len: Length of the dump buffer.
// he_sigb_len: Length of HE-SIG-B field (802.11ax).
// cur_single_mpdu: Indicates if this is a single MPDU.
// cur_bb_format: Current baseband format.
// rx_channel_estimate_info_vld: Channel estimation validity.
// rx_channel_estimate_len: Length of the channel estimation.
// second: Timing information in seconds.
// channel: Primary channel on which the packet is received.
// noise_floor: Noise floor of the Radio Frequency module, in dBm.
// is_group: Indicates if this is a group-addressed frame.
// rxend_state: End state of the packet reception.
// rxmatch3: Indicate whether the reception frame is from interface 3.
// rxmatch2: Indicate whether the reception frame is from interface 2.
// rxmatch1: Indicate whether the reception frame is from interface 1.
// rxmatch0: Indicate whether the reception frame is from interface 0.

/// CSI Received Packet w/ Radio Metadata
#[cfg(not(any(feature = "esp32c5", feature = "esp32c6")))]
#[derive(Debug, Clone, Serialize, Deserialize, MaxSize)]
pub struct CSIDataPacket {
    /// MAC address of the sender.
    pub mac: [u8; 6],
    /// Received Signal Strength Indicator.
    pub rssi: i32,
    /// Local Timestamp of Recieved Packet (microseconds)  .                 
    pub timestamp: u32,
    /// PHY rate encoding of the packet. Only valid for non HT(11bg) packet.              
    pub rate: u32,
    /// Short Guide Interval (SGI). 0: Long GI; 1: Short GI.
    pub sgi: u32,
    /// Secondary Channel on which the Packet was Received.
    /// 0: none; 1: above; 2: below.
    pub secondary_channel: u32,
    /// Primary channel on which the Packet was Received.
    pub channel: u32,
    /// Channel Bandwidth of the packet.
    /// 0: 20MHz; 1: 40MHz.
    pub bandwidth: u32,
    /// Antenna number from which this packet is received.
    /// 0: WiFi antenna 0; 1: WiFi antenna 1.
    pub antenna: u32,
    /// Protocol of the received packet.
    /// 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet.
    pub sig_mode: u32,
    /// Modulation Coding Scheme.
    /// If Packet is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76).
    pub mcs: u32,
    /// Set to 1 indicates that channel estimate smoothing is recommended.
    /// Set to 0 indicates that only per-carrier independent (unsmoothed) channel estimate is recommended.
    pub smoothing: u32,
    /// Sounding PPDU is used for channel estimation by the request receiver.
    /// Set to 0 indicates that PPDU is a sounding PPDU.
    /// Set to 1 indicates that the PPDU is not a sounding PPDU.
    pub not_sounding: u32,
    /// Aggregation.
    /// 0: MPDU packet; 1: AMPDU packet
    pub aggregation: u32,
    /// Space-Time Block Coding.
    /// 0: non STBC packet; 1: STBC packet.
    pub stbc: u32,
    /// Forward Error Correction (FEC).
    /// Flag is set for 11n packets which are LDPC.
    pub fec_coding: u32,
    /// The number of subframes aggregated in AMPDU.
    pub ampdu_cnt: u32,
    /// Noise floor of Radio Frequency Module(RF).
    /// unit: dBm.
    pub noise_floor: i32,
    /// RX state.
    /// 0: no error; others: error numbers which are not public.
    pub rx_state: u32,
    /// Length of packet including Frame Check Sequence(FCS).
    pub sig_len: u32,
    /// Optional NTP-based Timestamp Indicating the Time CSI Captured.
    pub date_time: Option<DateTime>,
    /// Sequence Number Associated with the Packet that triggered a CSI capture.
    pub sequence_number: u16,
    /// Data format of the recieved CSI.
    /// RxCSIFmt is a Compact Representation of the Different Recieved CSI Data Format Options as defined in the ESP WiFi Driver.
    pub data_format: RxCSIFmt,
    /// Length of CSI data.
    pub csi_data_len: u16,
    /// Raw CSI data, largest case size is 612 bytes.
    pub csi_data: Vec<i8, 612>,
}

#[cfg(not(any(feature = "esp32c5", feature = "esp32c6")))]
impl CSIDataPacket {
    /// Prints Recieved CSI Data Packet with it's Metadata.
    ///
    /// Consumes the packet — passes it directly to `log_csi` without a clone.
    pub fn print_csi_w_metadata(self) {
        use crate::logging::logging::log_csi;

        log_csi(self);
    }

    /// Derive and set `data_format` from captured radio metadata fields.
    ///
    /// Retrieves `RxCSIFmt` for a `CSIDataPacket`
    // The RxCSIFmt enum is a mapping of the different possible recieved CSI data formats supported by the Espressif WiFi driver.
    // RxCSIFmt encodes the different formats (each column in the table) in one byte to save space
    // More details on the different data formats can be found in the ESP CSI WiFi driver here:
    // https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/wifi.html#wi-fi-channel-state-information
    //
    // The encoding is as follows:
    // Bw20 => 0.              Secondary Channel = None, Signal Mode = non-HT, Channel BW = 20MHz, non-STBC
    // HtBw20 => 1             Secondary Channel = None, Signal Mode = HT, Channel BW = 20MHz, non-STBC
    // HtBw20Stbc => 2         Secondary Channel = None, Signal Mode = HT, Channel BW = 20MHz, STBC
    // SecbBw20 => 3           Secondary Channel = Below, Signal Mode = non-HT, Channel BW = 20MHz, non-STBC
    // SecbHtBw20 => 4         Secondary Channel = Below, Signal Mode = HT, Channel BW = 20MHz, non-STBC
    // SecbHtBw20Stbc => 5     Secondary Channel = Below, Signal Mode = HT, Channel BW = 20MHz, STBC
    // SecbHtBw40 => 6         Secondary Channel = Below, Signal Mode = HT, Channel BW = 40MHz, non-STBC
    // SecbHtBw40Stbc  => 7    Secondary Channel = Below, Signal Mode = HT, Channel BW = 40MHz, STBC
    // SecaBw20 => 8           Secondary Channel = Above, Signal Mode = non-HT, Channel BW = 20MHz, non-STBC
    // SecaHtBw20 => 9         Secondary Channel = Above, Signal Mode = HT, Channel BW = 20MHz, non-STBC
    // SecaHtBw20Stbc => 10    Secondary Channel = Above, Signal Mode = HT, Channel BW = 20MHz, STBC
    // SecaHtBw40 => 11        Secondary Channel = Above, Signal Mode = HT, Channel BW = 40MHz, non-STBC
    // SecaHtBw40Stbc => 12    Secondary Channel = Above, Signal Mode = HT, Channel BW = 40MHz, STBC
    // Undefined => 13
    pub fn csi_fmt_from_params(&mut self) {
        match self.secondary_channel {
            // None
            0 => {
                match self.sig_mode {
                    // non-HTc
                    0 => self.data_format = RxCSIFmt::Bw20,
                    // HT
                    1 => {
                        match self.stbc {
                            // non-STBC
                            0 => self.data_format = RxCSIFmt::HtBw20,
                            // STBC
                            1 => self.data_format = RxCSIFmt::HtBw20Stbc,
                            _ => self.data_format = RxCSIFmt::Undefined,
                        }
                    }
                    _ => self.data_format = RxCSIFmt::Undefined,
                }
            }
            // Above
            1 => {
                match self.sig_mode {
                    // non-HT
                    0 => self.data_format = RxCSIFmt::SecaBw20,
                    // HT
                    1 => {
                        match self.bandwidth {
                            // 20MHz
                            0 => {
                                match self.stbc {
                                    // non-STBC
                                    0 => self.data_format = RxCSIFmt::SecaHtBw20,
                                    // STBC
                                    1 => self.data_format = RxCSIFmt::SecaHtBw20Stbc,
                                    _ => self.data_format = RxCSIFmt::Undefined,
                                }
                            }
                            // 40MHz
                            1 => {
                                match self.stbc {
                                    // non-STBC
                                    0 => self.data_format = RxCSIFmt::SecaHtBw40,
                                    // STBC
                                    1 => self.data_format = RxCSIFmt::SecaHtBw40Stbc,
                                    _ => self.data_format = RxCSIFmt::Undefined,
                                }
                            }
                            _ => self.data_format = RxCSIFmt::Undefined,
                        }
                    }
                    _ => self.data_format = RxCSIFmt::Undefined,
                }
            }
            // Below
            2 => {
                match self.sig_mode {
                    // non-HT
                    0 => self.data_format = RxCSIFmt::SecbBw20,
                    // HT
                    1 => {
                        match self.bandwidth {
                            // 20MHz
                            0 => {
                                match self.stbc {
                                    // non-STBC
                                    0 => self.data_format = RxCSIFmt::SecbHtBw20,
                                    // STBC
                                    1 => self.data_format = RxCSIFmt::SecbHtBw20Stbc,
                                    _ => self.data_format = RxCSIFmt::Undefined,
                                }
                            }
                            // 40MHz
                            1 => {
                                match self.stbc {
                                    // non-STBC
                                    0 => self.data_format = RxCSIFmt::SecbHtBw40,
                                    // STBC
                                    1 => self.data_format = RxCSIFmt::SecbHtBw40Stbc,
                                    _ => self.data_format = RxCSIFmt::Undefined,
                                }
                            }
                            _ => self.data_format = RxCSIFmt::Undefined,
                        }
                    }
                    _ => self.data_format = RxCSIFmt::Undefined,
                }
            }
            _ => self.data_format = RxCSIFmt::Undefined,
        }
    }

    /// Return the source MAC address.
    pub fn mac(&self) -> &[u8; 6] {
        &self.mac
    }
    /// Return packet RSSI in dBm.
    pub fn rssi(&self) -> i32 {
        self.rssi
    }
    /// Return local receive timestamp in microseconds.
    pub fn timestamp(&self) -> u32 {
        self.timestamp
    }
    /// Return PHY rate encoding.
    pub fn rate(&self) -> u32 {
        self.rate
    }
    /// Return SGI flag (0 = long GI, 1 = short GI).
    pub fn sgi(&self) -> u32 {
        self.sgi
    }
    /// Return secondary-channel indicator.
    pub fn secondary_channel(&self) -> u32 {
        self.secondary_channel
    }
    /// Return primary Wi-Fi channel.
    pub fn channel(&self) -> u32 {
        self.channel
    }
    /// Return channel bandwidth encoding.
    pub fn bandwidth(&self) -> u32 {
        self.bandwidth
    }
    /// Return receiving antenna index.
    pub fn antenna(&self) -> u32 {
        self.antenna
    }
    /// Return signal mode encoding.
    pub fn sig_mode(&self) -> u32 {
        self.sig_mode
    }
    /// Return MCS index.
    pub fn mcs(&self) -> u32 {
        self.mcs
    }
    /// Return channel-smoothing recommendation flag.
    pub fn smoothing(&self) -> u32 {
        self.smoothing
    }
    /// Return sounding indicator flag.
    pub fn not_sounding(&self) -> u32 {
        self.not_sounding
    }
    /// Return MPDU/AMPDU aggregation flag.
    pub fn aggregation(&self) -> u32 {
        self.aggregation
    }
    /// Return STBC flag.
    pub fn stbc(&self) -> u32 {
        self.stbc
    }
    /// Return FEC coding flag.
    pub fn fec_coding(&self) -> u32 {
        self.fec_coding
    }
    /// Return AMPDU subframe count.
    pub fn ampdu_cnt(&self) -> u32 {
        self.ampdu_cnt
    }
    /// Return RF noise floor in dBm.
    pub fn noise_floor(&self) -> i32 {
        self.noise_floor
    }
    /// Return RX state code.
    pub fn rx_state(&self) -> u32 {
        self.rx_state
    }
    /// Return packet length including FCS.
    pub fn sig_len(&self) -> u32 {
        self.sig_len
    }
    /// Return optional capture date/time metadata.
    pub fn date_time(&self) -> Option<&DateTime> {
        self.date_time.as_ref()
    }
    /// Return trigger sequence number.
    pub fn sequence_number(&self) -> u16 {
        self.sequence_number
    }
    /// Return interpreted CSI data format.
    pub fn data_format(&self) -> RxCSIFmt {
        self.data_format.clone()
    }
    /// Return CSI payload length in bytes.
    pub fn csi_data_len(&self) -> u16 {
        self.csi_data_len
    }
    /// Return a slice of raw CSI values.
    pub fn csi_data(&self) -> &[i8] {
        self.csi_data.as_slice()
    }
}

#[cfg(any(feature = "esp32c5", feature = "esp32c6"))]
#[derive(Debug, Clone, Serialize, Deserialize, MaxSize)]
pub struct CSIDataPacket {
    /// MAC address of the sender.
    pub mac: [u8; 6],
    /// Received Signal Strength Indicator.
    pub rssi: i32,
    /// Local Timestamp of Recieved Packet (microseconds).
    pub timestamp: u32,
    /// PHY rate encoding of the packet.
    pub rate: u32,
    /// Noise floor of Radio Frequency Module(RF).
    /// unit: dBm.
    pub noise_floor: i32,
    /// Length of packet including Frame Check Sequence(FCS).
    pub sig_len: u32,
    /// Reception state of the packet.
    /// 0 for no error, others indicate error codes.
    pub rx_state: u32,
    /// Length of dump buffer.
    pub dump_len: u32,
    /// Length of HE-SIG-B field (802.11ax).
    #[cfg(feature = "esp32c6")]
    pub he_sigb_len: u32,
    /// Indicates if this is a single MPDU.
    #[cfg(feature = "esp32c6")]
    pub cur_single_mpdu: u32,
    /// Current baseband format.
    pub cur_bb_format: u32,
    /// Channel estimation validity.
    pub rx_channel_estimate_info_vld: u32,
    /// Length of the channel estimation.
    pub rx_channel_estimate_len: u32,
    /// Timing information in seconds.
    pub second: u32,
    /// Primary channel on which the packet is received.
    pub channel: u32,
    /// Indicates if this is a group-addressed frame.
    pub is_group: u32,
    /// End state of the packet reception.
    pub rxend_state: u32,
    /// Indicate whether the reception frame is from interface 3.
    pub rxmatch3: u32,
    /// Indicate whether the reception frame is from interface 2.
    pub rxmatch2: u32,
    /// Indicate whether the reception frame is from interface 1.
    pub rxmatch1: u32,
    /// Indicate whether the reception frame is from interface 0.
    #[cfg(feature = "esp32c6")]
    pub rxmatch0: u32,
    /// Optional NTP-based Timestamp Indicating the Time CSI Captured.
    pub date_time: Option<DateTime>,
    /// Sequence number associated with packet.
    pub sequence_number: u16,
    /// Length of CSI data.
    pub csi_data_len: u16,
    /// Data format of the recieved CSI.
    /// RxCSIFmt is a Compact Representation of the Different Recieved CSI Data Format Options as defined in the ESP WiFi Driver.
    pub data_format: RxCSIFmt,
    /// Raw CSI data, largest case size is 612 bytes.
    pub csi_data: Vec<i8, 612>,
}

#[cfg(any(feature = "esp32c5", feature = "esp32c6"))]
impl CSIDataPacket {
    /// Prints Recieved CSI Data Packet with it's Metadata.
    ///
    /// Consumes the packet — passes it directly to `log_csi` without a clone.
    pub fn print_csi_w_metadata(self) {
        use crate::logging::logging::log_csi;

        log_csi(self);
    }
    pub fn csi_fmt_from_params(&mut self) {
        self.data_format = RxCSIFmt::Undefined;
    }

    pub fn mac(&self) -> &[u8; 6] {
        &self.mac
    }

    pub fn rssi(&self) -> i32 {
        self.rssi
    }
    pub fn timestamp(&self) -> u32 {
        self.timestamp
    }
    pub fn rate(&self) -> u32 {
        self.rate
    }
    pub fn noise_floor(&self) -> i32 {
        self.noise_floor
    }
    pub fn sig_len(&self) -> u32 {
        self.sig_len
    }
    pub fn rx_state(&self) -> u32 {
        self.rx_state
    }
    pub fn dump_len(&self) -> u32 {
        self.dump_len
    }
    #[cfg(feature = "esp32c6")]
    pub fn he_sigb_len(&self) -> u32 {
        self.he_sigb_len
    }
    #[cfg(feature = "esp32c6")]
    pub fn cur_single_mpdu(&self) -> u32 {
        self.cur_single_mpdu
    }
    pub fn cur_bb_format(&self) -> u32 {
        self.cur_bb_format
    }
    pub fn rx_channel_estimate_info_vld(&self) -> u32 {
        self.rx_channel_estimate_info_vld
    }
    pub fn rx_channel_estimate_len(&self) -> u32 {
        self.rx_channel_estimate_len
    }
    pub fn second(&self) -> u32 {
        self.second
    }
    pub fn channel(&self) -> u32 {
        self.channel
    }
    pub fn is_group(&self) -> u32 {
        self.is_group
    }
    pub fn rxend_state(&self) -> u32 {
        self.rxend_state
    }
    pub fn rxmatch3(&self) -> u32 {
        self.rxmatch3
    }
    pub fn rxmatch2(&self) -> u32 {
        self.rxmatch2
    }
    pub fn rxmatch1(&self) -> u32 {
        self.rxmatch1
    }
    #[cfg(feature = "esp32c6")]
    pub fn rxmatch0(&self) -> u32 {
        self.rxmatch0
    }
    pub fn csi_data(&self) -> &[i8] {
        self.csi_data.as_slice()
    }
    pub fn csi_data_len(&self) -> u16 {
        self.csi_data_len
    }
}