use esp_radio::wifi::csi::CsiConfig as RadioCsiConfig;
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_HT20: u32 = 4;
const WIFI_PHY_MODE_HT40: u32 = 5;
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 force_ht_tx(ifx: u32, phymode: u32) -> i32 {
let mut cfg = WifiTxRateConfig {
phymode,
rate: WIFI_PHY_RATE_MCS0_LGI,
ersu: false,
dcm: false,
};
unsafe { esp_wifi_config_80211_tx(ifx, &mut cfg) }
}
fn force_tx_ap_before_start(phymode: u32) -> i32 {
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);
}
let rc = force_ht_tx(WIFI_IF_AP, phymode);
if prev_mode != WIFI_MODE_AP {
let _ = esp_wifi_set_mode(prev_mode);
}
rc
}
}
fn ht_protocols() -> Protocols {
let protocols = Protocols::default().with_2_4(Protocol::B | Protocol::G | Protocol::N);
#[cfg(feature = "esp32c5")]
{
return protocols.with_5(Protocol::A | Protocol::N);
}
#[cfg(not(feature = "esp32c5"))]
protocols
}
pub fn apply_ht_bandwidth(controller: &mut WifiController<'_>, forty: bool) {
if let Ok(bw) = controller.bandwidths() {
let width = if forty {
Bandwidth::_40MHz
} else {
Bandwidth::_20MHz
};
let _ = controller.set_bandwidths(bw.with_2_4(width));
}
}
pub fn apply_ht_protocols(controller: &mut WifiController<'_>) {
let _ = controller.set_protocols(ht_protocols());
}
pub fn ht_csi_acquisition(raw: &mut RadioCsiConfig, forty: bool) {
#[cfg(any(feature = "esp32c5", feature = "esp32c6"))]
{
raw.acquire_csi_legacy = 0;
raw.acquire_csi_ht20 = 1;
raw.acquire_csi_ht40 = if forty { 1 } else { 0 };
raw.acquire_csi_su = 0;
raw.acquire_csi_mu = 0;
raw.acquire_csi_dcm = 0;
raw.acquire_csi_beamformed = 0;
raw.dump_ack_en = 0;
#[cfg(feature = "esp32c5")]
{
raw.acquire_csi_force_lltf = false;
raw.acquire_csi_vht = false;
}
}
#[cfg(not(any(feature = "esp32c5", feature = "esp32c6")))]
{
let _ = forty;
raw.lltf_en = true;
raw.htltf_en = true;
raw.stbc_htltf2_en = true;
raw.ltf_merge_en = false;
raw.dump_ack_en = false;
}
}
pub fn force_ht20_tx_sta_before_start() -> i32 {
force_ht_tx(WIFI_IF_STA, WIFI_PHY_MODE_HT20)
}
pub fn force_ht40_tx_sta_before_start() -> i32 {
force_ht_tx(WIFI_IF_STA, WIFI_PHY_MODE_HT40)
}
pub fn force_ht20_tx_ap_before_start() -> i32 {
force_tx_ap_before_start(WIFI_PHY_MODE_HT20)
}
pub fn force_ht40_tx_ap_before_start() -> i32 {
force_tx_ap_before_start(WIFI_PHY_MODE_HT40)
}