Skip to content

Commit

Permalink
Expose CSI API in esp-wifi (#2422)
Browse files Browse the repository at this point in the history
* feat: (WIP) add CSI api

* feat: Enable G_CONFIG.csi_enable and update example

* fix: Allow user to set the dessired cb method

* fix: Clippy warnings

* fix: Add missing doccomments

* feat: Add csi_enable config

* refactor: Update CsiConfiguration c6 struct

* feat: Create set_csi WifiController and EspNowManager methods

* docs: Update changelog

* refactor: Rename CsiConfig struct

* docs: Document c6 version of CsiConfig

* feat: impl From<CsiConfig> for crate::include::wifi_csi_config_t

* style: Rustfmt

* docs: Fix comment

Co-authored-by: Dániel Buga <bugadani@gmail.com>

* docs: Fix typo

Co-authored-by: Juraj Sadel <jurajsadel@gmail.com>

* feat: Enable CSI on examples by default

* feat: Handle errors

* style: Rustfmt

* feat: Update error

* feat: Panic if csi config is not enabled

* feat: Cfg CSI stuff when CSI is disabled instead of panicing

* fix: Clippy lints

* feat: Fix signed bitfields

* feat: Pass the cb via ctx

* feat: Update CSI callback to use closures

* refactor: Rename promiscuous_csi_rx_cb to csi_rx_cb

* feat: Move extra boxing inside set_receive_cb

* feat: Refactor CSI callback to use generic types

* refactor: Remove Sized bound from CsiCallback trait

* feat: Add csi_enable field to EspWifiConfig and update CsiCallback trait for conditional compilation

* feat: Remove unnecessary boxes

* feat: Update callback type in set_csi to require Send trait

Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com>

---------

Co-authored-by: Dániel Buga <bugadani@gmail.com>
Co-authored-by: Juraj Sadel <jurajsadel@gmail.com>
Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com>
  • Loading branch information
4 people authored Nov 8, 2024
1 parent 3c4b7f0 commit 7402ad6
Show file tree
Hide file tree
Showing 8 changed files with 393 additions and 1 deletion.
1 change: 1 addition & 0 deletions esp-wifi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Added `serde` support through the `serde` feature (#2346)
- Added `PowerSaveMode` and `set_power_saving` methods on `EspNowManager` & `WifiController` (#2446)
- Added CSI support (#2422)

### Changed

Expand Down
1 change: 1 addition & 0 deletions esp-wifi/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ fn main() -> Result<(), Box<dyn Error>> {
("dynamic_rx_buf_num", Value::UnsignedInteger(32), "WiFi dynamic RX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"),
("static_tx_buf_num", Value::UnsignedInteger(0), "WiFi static TX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"),
("dynamic_tx_buf_num", Value::UnsignedInteger(32), "WiFi dynamic TX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"),
("csi_enable", Value::Bool(false), "WiFi channel state information enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"),
("ampdu_rx_enable", Value::Bool(true), "WiFi AMPDU RX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"),
("ampdu_tx_enable", Value::Bool(true), "WiFi AMPDU TX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"),
("amsdu_tx_enable", Value::Bool(false), "WiFi AMSDU TX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"),
Expand Down
1 change: 1 addition & 0 deletions esp-wifi/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub(crate) struct EspWifiConfig {
pub(crate) dynamic_rx_buf_num: usize,
pub(crate) static_tx_buf_num: usize,
pub(crate) dynamic_tx_buf_num: usize,
pub(crate) csi_enable: bool,
pub(crate) ampdu_rx_enable: bool,
pub(crate) ampdu_tx_enable: bool,
pub(crate) amsdu_tx_enable: bool,
Expand Down
16 changes: 16 additions & 0 deletions esp-wifi/src/esp_now/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use portable_atomic::{AtomicBool, AtomicU8, Ordering};

#[cfg(not(coex))]
use crate::config::PowerSaveMode;
#[cfg(csi_enable)]
use crate::wifi::CsiConfig;
use crate::{
binary::include::*,
hal::peripheral::{Peripheral, PeripheralRef},
Expand Down Expand Up @@ -369,6 +371,20 @@ impl EspNowManager<'_> {
check_error!({ esp_now_add_peer(&raw_peer as *const _) })
}

/// Set CSI configuration and register the receiving callback.
#[cfg(csi_enable)]
pub fn set_csi(
&mut self,
mut csi: CsiConfig,
cb: impl FnMut(crate::wifi::wifi_csi_info_t) + Send,
) -> Result<(), WifiError> {
csi.apply_config()?;
csi.set_receive_cb(cb)?;
csi.set_csi(true)?;

Ok(())
}

/// Remove the given peer.
pub fn remove_peer(&self, peer_address: &[u8; 6]) -> Result<(), EspNowError> {
check_error!({ esp_now_del_peer(peer_address.as_ptr()) })
Expand Down
29 changes: 29 additions & 0 deletions esp-wifi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,42 @@ const _: () = {
};
};

#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Tunable parameters for the WiFi driver
#[allow(unused)] // currently there are no ble tunables
struct Config {
rx_queue_size: usize,
tx_queue_size: usize,
static_rx_buf_num: usize,
dynamic_rx_buf_num: usize,
static_tx_buf_num: usize,
dynamic_tx_buf_num: usize,
csi_enable: bool,
ampdu_rx_enable: bool,
ampdu_tx_enable: bool,
amsdu_tx_enable: bool,
rx_ba_win: usize,
max_burst_size: usize,
country_code: &'static str,
country_code_operating_class: u8,
mtu: usize,
tick_rate_hz: u32,
listen_interval: u16,
beacon_timeout: u16,
ap_beacon_timeout: u16,
failure_retry_cnt: u8,
scan_method: u32,
}

pub(crate) const CONFIG: config::EspWifiConfig = config::EspWifiConfig {
rx_queue_size: esp_config_int!(usize, "ESP_WIFI_RX_QUEUE_SIZE"),
tx_queue_size: esp_config_int!(usize, "ESP_WIFI_TX_QUEUE_SIZE"),
static_rx_buf_num: esp_config_int!(usize, "ESP_WIFI_STATIC_RX_BUF_NUM"),
dynamic_rx_buf_num: esp_config_int!(usize, "ESP_WIFI_DYNAMIC_RX_BUF_NUM"),
static_tx_buf_num: esp_config_int!(usize, "ESP_WIFI_STATIC_TX_BUF_NUM"),
dynamic_tx_buf_num: esp_config_int!(usize, "ESP_WIFI_DYNAMIC_TX_BUF_NUM"),
csi_enable: esp_config_bool!("ESP_WIFI_CSI_ENABLE"),
ampdu_rx_enable: esp_config_bool!("ESP_WIFI_AMPDU_RX_ENABLE"),
ampdu_tx_enable: esp_config_bool!("ESP_WIFI_AMPDU_TX_ENABLE"),
amsdu_tx_enable: esp_config_bool!("ESP_WIFI_AMSDU_TX_ENABLE"),
Expand Down
212 changes: 211 additions & 1 deletion esp-wifi/src/wifi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ pub mod utils;
#[cfg(coex)]
use include::{coex_adapter_funcs_t, coex_pre_init, esp_coex_adapter_register};

#[cfg(all(csi_enable, esp32c6))]
use crate::binary::include::wifi_csi_acquire_config_t;
#[cfg(csi_enable)]
pub use crate::binary::include::wifi_csi_info_t;
#[cfg(csi_enable)]
use crate::binary::include::{
esp_wifi_set_csi,
esp_wifi_set_csi_config,
esp_wifi_set_csi_rx_cb,
wifi_csi_config_t,
};
use crate::binary::{
c_types,
include::{
Expand Down Expand Up @@ -340,6 +351,191 @@ impl Default for ClientConfiguration {
}
}

#[cfg(csi_enable)]
pub(crate) trait CsiCallback: FnMut(crate::binary::include::wifi_csi_info_t) {}

#[cfg(csi_enable)]
impl<T> CsiCallback for T where T: FnMut(crate::binary::include::wifi_csi_info_t) {}

#[cfg(csi_enable)]
unsafe extern "C" fn csi_rx_cb<C: CsiCallback>(
ctx: *mut crate::wifi::c_types::c_void,
data: *mut crate::binary::include::wifi_csi_info_t,
) {
let csi_callback = unsafe { &mut *(ctx as *mut C) };
csi_callback(*data);
}

#[derive(Clone, PartialEq, Eq)]
// https://github.com/esp-rs/esp-wifi-sys/blob/main/esp-wifi-sys/headers/local/esp_wifi_types_native.h#L94
/// Channel state information(CSI) configuration
#[cfg(all(not(esp32c6), csi_enable))]
pub struct CsiConfig {
/// Enable to receive legacy long training field(lltf) data.
pub lltf_en: bool,
/// Enable to receive HT long training field(htltf) data.
pub htltf_en: bool,
/// Enable to receive space time block code HT long training
/// field(stbc-htltf2) data.
pub stbc_htltf2_en: bool,
/// Enable to generate htlft data by averaging lltf and ht_ltf data when
/// receiving HT packet. Otherwise, use ht_ltf data directly.
pub ltf_merge_en: bool,
/// Enable to turn on channel filter to smooth adjacent sub-carrier. Disable
/// it to keep independence of adjacent sub-carrier.
pub channel_filter_en: bool,
/// Manually scale the CSI data by left shifting or automatically scale the
/// CSI data. If set true, please set the shift bits. false: automatically.
/// true: manually.
pub manu_scale: bool,
/// Manually left shift bits of the scale of the CSI data. The range of the
/// left shift bits is 0~15.
pub shift: u8,
/// Enable to dump 802.11 ACK frame.
pub dump_ack_en: bool,
}

#[derive(Clone, PartialEq, Eq)]
#[cfg(all(esp32c6, csi_enable))]
// See https://github.com/esp-rs/esp-wifi-sys/blob/2a466d96fe8119d49852fc794aea0216b106ba7b/esp-wifi-sys/src/include/esp32c6.rs#L5702-L5705
pub struct CsiConfig {
/// Enable to acquire CSI.
pub enable: u32,
/// Enable to acquire L-LTF when receiving a 11g PPDU.
pub acquire_csi_legacy: u32,
/// Enable to acquire HT-LTF when receiving an HT20 PPDU.
pub acquire_csi_ht20: u32,
/// Enable to acquire HT-LTF when receiving an HT40 PPDU.
pub acquire_csi_ht40: u32,
/// Enable to acquire HE-LTF when receiving an HE20 SU PPDU.
pub acquire_csi_su: u32,
/// Enable to acquire HE-LTF when receiving an HE20 MU PPDU.
pub acquire_csi_mu: u32,
/// Enable to acquire HE-LTF when receiving an HE20 DCM applied PPDU.
pub acquire_csi_dcm: u32,
/// Enable to acquire HE-LTF when receiving an HE20 Beamformed applied PPDU.
pub acquire_csi_beamformed: u32,
/// Wwhen receiving an STBC applied HE PPDU, 0- acquire the complete
/// HE-LTF1, 1- acquire the complete HE-LTF2, 2- sample evenly among the
/// HE-LTF1 and HE-LTF2.
pub acquire_csi_he_stbc: u32,
/// Vvalue 0-3.
pub val_scale_cfg: u32,
/// Enable to dump 802.11 ACK frame, default disabled.
pub dump_ack_en: u32,
/// Reserved.
pub reserved: u32,
}

#[cfg(csi_enable)]
impl Default for CsiConfig {
#[cfg(not(esp32c6))]
fn default() -> Self {
Self {
lltf_en: true,
htltf_en: true,
stbc_htltf2_en: true,
ltf_merge_en: true,
channel_filter_en: true,
manu_scale: false,
shift: 0,
dump_ack_en: false,
}
}

#[cfg(esp32c6)]
fn default() -> Self {
// https://github.com/esp-rs/esp-wifi-sys/blob/2a466d96fe8119d49852fc794aea0216b106ba7b/esp-wifi-sys/headers/esp_wifi_he_types.h#L67-L82
Self {
enable: 1,
acquire_csi_legacy: 1,
acquire_csi_ht20: 1,
acquire_csi_ht40: 1,
acquire_csi_su: 1,
acquire_csi_mu: 1,
acquire_csi_dcm: 1,
acquire_csi_beamformed: 1,
acquire_csi_he_stbc: 2,
val_scale_cfg: 2,
dump_ack_en: 1,
reserved: 19,
}
}
}

#[cfg(csi_enable)]
impl From<CsiConfig> for wifi_csi_config_t {
fn from(config: CsiConfig) -> Self {
#[cfg(not(esp32c6))]
{
wifi_csi_config_t {
lltf_en: config.lltf_en,
htltf_en: config.htltf_en,
stbc_htltf2_en: config.stbc_htltf2_en,
ltf_merge_en: config.ltf_merge_en,
channel_filter_en: config.channel_filter_en,
manu_scale: config.manu_scale,
shift: config.shift,
dump_ack_en: config.dump_ack_en,
}
}
#[cfg(esp32c6)]
{
wifi_csi_acquire_config_t {
_bitfield_align_1: [0; 0],
_bitfield_1: wifi_csi_acquire_config_t::new_bitfield_1(
config.enable,
config.acquire_csi_legacy,
config.acquire_csi_ht20,
config.acquire_csi_ht40,
config.acquire_csi_su,
config.acquire_csi_mu,
config.acquire_csi_dcm,
config.acquire_csi_beamformed,
config.acquire_csi_he_stbc,
config.val_scale_cfg,
config.dump_ack_en,
config.reserved,
),
}
}
}
}

#[cfg(csi_enable)]
impl CsiConfig {
/// Set CSI data configuration
pub(crate) fn apply_config(&self) -> Result<(), WifiError> {
let conf: wifi_csi_config_t = self.clone().into();

unsafe {
esp_wifi_result!(esp_wifi_set_csi_config(&conf))?;
}
Ok(())
}

/// Register the RX callback function of CSI data. Each time a CSI data is
/// received, the callback function will be called.
pub(crate) fn set_receive_cb<C: CsiCallback>(&mut self, cb: C) -> Result<(), WifiError> {
let cb = alloc::boxed::Box::new(cb);
let cb_ptr = alloc::boxed::Box::into_raw(cb) as *mut crate::wifi::c_types::c_void;

unsafe {
esp_wifi_result!(esp_wifi_set_csi_rx_cb(Some(csi_rx_cb::<C>), cb_ptr))?;
}
Ok(())
}

/// Enable or disable CSI
pub(crate) fn set_csi(&self, enable: bool) -> Result<(), WifiError> {
// https://github.com/esp-rs/esp-wifi-sys/blob/2a466d96fe8119d49852fc794aea0216b106ba7b/esp-wifi-sys/headers/esp_wifi.h#L1241
unsafe {
esp_wifi_result!(esp_wifi_set_csi(enable))?;
}
Ok(())
}
}

/// Configuration for EAP-FAST authentication protocol.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
Expand Down Expand Up @@ -1524,7 +1720,7 @@ static mut G_CONFIG: wifi_init_config_t = wifi_init_config_t {
rx_mgmt_buf_type: esp_wifi_sys::include::CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF as i32,
rx_mgmt_buf_num: esp_wifi_sys::include::CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF as i32,
cache_tx_buf_num: esp_wifi_sys::include::WIFI_CACHE_TX_BUFFER_NUM as i32,
csi_enable: esp_wifi_sys::include::WIFI_CSI_ENABLED as i32,
csi_enable: crate::CONFIG.csi_enable as i32,
ampdu_rx_enable: crate::CONFIG.ampdu_rx_enable as i32,
ampdu_tx_enable: crate::CONFIG.ampdu_tx_enable as i32,
amsdu_tx_enable: crate::CONFIG.amsdu_tx_enable as i32,
Expand Down Expand Up @@ -2536,6 +2732,20 @@ impl<'d> WifiController<'d> {
}
}

/// Set CSI configuration and register the receiving callback.
#[cfg(csi_enable)]
pub fn set_csi(
&mut self,
mut csi: CsiConfig,
cb: impl FnMut(crate::wifi::wifi_csi_info_t) + Send,
) -> Result<(), WifiError> {
csi.apply_config()?;
csi.set_receive_cb(cb)?;
csi.set_csi(true)?;

Ok(())
}

/// Set the wifi protocol.
///
/// This will set the wifi protocol to the desired protocol, the default for
Expand Down
1 change: 1 addition & 0 deletions examples/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ PASSWORD = "PASSWORD"
STATIC_IP = "1.1.1.1 "
GATEWAY_IP = "1.1.1.1"
HOST_IP = "1.1.1.1"
ESP_WIFI_CSI_ENABLE = "true"

[unstable]
build-std = ["alloc", "core"]
Loading

0 comments on commit 7402ad6

Please sign in to comment.