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;
pub(crate) const WIFI_PHY_MODE_HT20: u32 = 4;
pub(crate) const WIFI_PHY_MODE_HT40: u32 = 5;
#[cfg(any(feature = "esp32c5", feature = "esp32c6"))]
pub(crate) 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 force_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_tx(WIFI_IF_AP, phymode);
if prev_mode != WIFI_MODE_AP {
let _ = esp_wifi_set_mode(prev_mode);
}
rc
}
}
fn tx_protocols(he: bool) -> Protocols {
let mut two = Protocol::B | Protocol::G | Protocol::N;
#[allow(unused_mut)]
let mut five = Protocol::A | Protocol::N;
if he {
two |= Protocol::AX;
five |= Protocol::AX;
}
let protocols = Protocols::default().with_2_4(two);
#[cfg(feature = "esp32c5")]
{
return protocols.with_5(five);
}
#[cfg(not(feature = "esp32c5"))]
{
let _ = five;
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_tx_protocols(controller: &mut WifiController<'_>, he: bool) {
let _ = controller.set_protocols(tx_protocols(he));
}
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;
}
}
#[cfg(any(feature = "esp32c5", feature = "esp32c6"))]
pub fn he20_csi_acquisition(raw: &mut RadioCsiConfig) {
raw.acquire_csi_su = 1;
raw.acquire_csi_mu = 1;
raw.acquire_csi_dcm = 1;
raw.acquire_csi_beamformed = 1;
raw.acquire_csi_he_stbc = 2;
raw.acquire_csi_legacy = 0;
raw.acquire_csi_ht20 = 0;
raw.acquire_csi_ht40 = 0;
raw.dump_ack_en = 0;
#[cfg(feature = "esp32c5")]
{
raw.acquire_csi_force_lltf = false;
raw.acquire_csi_vht = false;
}
}
pub(crate) fn force_tx_sta_before_start(phymode: u32) -> i32 {
force_tx(WIFI_IF_STA, phymode)
}
pub(crate) fn force_tx_ap(phymode: u32) -> i32 {
force_tx_ap_before_start(phymode)
}