esp-csi-rs 0.8.2

ESP CSI Driver for Rust
Documentation
//! 802.11ax HE20 Wi-Fi bring-up (ESP32-C5 / C6).
//!
//! `esp-radio`'s `set_config` applies embedded `protocols` (default B|G|N, no AX).
//! Pre-start `set_protocols` is a no-op while mode is NULL, so B|G|N|AX must be
//! re-applied after `set_config`. AP forced HE TX needs `WIFI_MODE_AP` set first.

use esp_radio::wifi::{Bandwidth, Protocol, Protocols, WifiController};

const WIFI_IF_STA: u32 = 0;
const WIFI_IF_AP: u32 = 1;
const WIFI_MODE_AP: u32 = 2;
const WIFI_PHY_MODE_HE20: u32 = 6;
const WIFI_PHY_RATE_MCS0_LGI: u32 = 16;

#[repr(C)]
struct WifiTxRateConfig {
    phymode: u32,
    rate: u32,
    ersu: bool,
    dcm: bool,
}

unsafe extern "C" {
    fn esp_wifi_config_80211_tx(ifx: u32, config: *mut WifiTxRateConfig) -> i32;
    fn esp_wifi_get_mode(mode: *mut u32) -> i32;
    fn esp_wifi_set_mode(mode: u32) -> i32;
}

fn he20_protocols() -> Protocols {
    let protocols = Protocols::default().with_2_4(
        Protocol::B | Protocol::G | Protocol::N | Protocol::AX,
    );
    #[cfg(feature = "esp32c5")]
    {
        return protocols.with_5(Protocol::A | Protocol::N | Protocol::AX);
    }
    #[cfg(not(feature = "esp32c5"))]
    protocols
}

fn force_he20_tx(ifx: u32) {
    let mut cfg = WifiTxRateConfig {
        phymode: WIFI_PHY_MODE_HE20,
        rate: WIFI_PHY_RATE_MCS0_LGI,
        ersu: false,
        dcm: false,
    };
    unsafe {
        let _ = esp_wifi_config_80211_tx(ifx, &mut cfg);
    }
}

/// Lock 2.4 GHz to 20 MHz (HE20).
pub fn apply_he20_bandwidth(controller: &mut WifiController<'_>) {
    if let Ok(bw) = controller.bandwidths() {
        let _ = controller.set_bandwidths(bw.with_2_4(Bandwidth::_20MHz));
    }
}

/// Re-apply B|G|N|AX after `set_config` (which embeds default B|G|N-only protocols).
pub fn apply_he20_protocols(controller: &mut WifiController<'_>) {
    let _ = controller.set_protocols(he20_protocols());
}

/// HE20 radio setup for promiscuous sniffer (bandwidth + protocols after channel lock).
pub fn apply_he20_sniffer_radio(controller: &mut WifiController<'_>) {
    apply_he20_bandwidth(controller);
    apply_he20_protocols(controller);
}

/// Force HE20 TX on STA; call immediately before `set_config(Station)`.
pub fn force_he20_tx_sta_before_start() {
    force_he20_tx(WIFI_IF_STA);
}

/// Force HE20 TX on AP; call immediately before `set_config(AccessPoint)`.
pub fn force_he20_tx_ap_before_start() {
    let mut prev_mode = 0u32;
    unsafe {
        let _ = esp_wifi_get_mode(&mut prev_mode);
        if prev_mode != WIFI_MODE_AP {
            let _ = esp_wifi_set_mode(WIFI_MODE_AP);
        }
        force_he20_tx(WIFI_IF_AP);
        if prev_mode != WIFI_MODE_AP {
            let _ = esp_wifi_set_mode(prev_mode);
        }
    }
}