Runtime wifi config options (#4121)

* Turn country code and default power mode into runtime configs

* Move G_CONFIG setup to wifi::new

* Turn most configs into runtime options

* Set core ID to current one

* Mark most options unstable
This commit is contained in:
Dániel Buga 2025-09-17 10:13:18 +02:00 committed by GitHub
parent 321ae5ef1b
commit 646495eb16
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 364 additions and 237 deletions

View File

@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `BuilderLite` pattern to `AccessPointConfig`, `ClientConfig`, and `EapClientConfig` (#4017, #4115)
- lifetime to `Sniffer` (#4017)
- `dtim_period` parameter for `PowerSaveMode` (#4040)
- `WifiConfig`, `CountryInfo` and `OperatingClass` (#4121)
### Changed
@ -43,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The memory allocation functions expected by `esp_radio` have been renamed and extended (#3890, #4043)
- Updated radio related drivers to ESP-IDF 5.5.1 (#4113)
- Event handlers are now passed the event by reference (#4113)
- Some build-time configuration options have been replaced by runtime options in `WifiConfig` (#4121)
### Fixed

View File

@ -2,12 +2,12 @@
## Initialization
The `builtin-scheduler` feature has been removed. The functionality has been moved to `esp_preempt_baremetal`.
`esp_preempt_baremetal` needs to be initialized before calling `esp_radio::init`. Failure to do so will result in an error.
The `builtin-scheduler` feature has been removed. The functionality has been moved to `esp_preempt`.
`esp_preempt` needs to be initialized before calling `esp_radio::init`. Failure to do so will result in an error.
Depending on your chosen OS, you may need to use other `esp_preempt` implementations.
Furthermore, `esp_wifi::init` no longer requires `RNG` or a timer.
Furthermore, `esp_radio::init` no longer requires `RNG` or a timer.
```diff
-let esp_wifi_ctrl = esp_wifi::init(timg0.timer0, Rng::new()).unwrap();
@ -57,6 +57,20 @@ The `scan_with_config_sync_max`, `scan_with_config_sync_max`, `scan_n`, and `sca
## Configuration
`esp_radio::wifi::new` now takes a `WifiConfig` struct. The default configuration matches the previous build-time configuration defaults. The corresponding build-time configuration options have been removed.
```diff
# .cargo/config.toml:
[env]
-ESP_RADIO_CONFIG_RX_QUEUE_SIZE = 27
# main.rs
-let (controller, ifaces) = esp_wifi::wifi::new(&ctrl, p.WIFI).unwrap();
+let config = esp_radio::wifi::WifiConfig::default()
+ .with_rx_queue_size(27);
+let (controller, ifaces) = esp_radio::wifi::new(&ctrl, p.WIFI, config).unwrap();
```
The `Configuration`, `ClientConfiguration`, `AccessPointConfiguration`, and `EapClientConfiguration` enums have been renamed to `Config`, `ClientConfig`, `AccessPointConfig`, and `EapClientConfig`:
```diff

View File

@ -1,142 +1,13 @@
crate: esp-radio
options:
- name: rx_queue_size
description: Size of the RX queue in frames
default:
- value: 5
constraints:
- type:
validator: positive_integer
- name: tx_queue_size
description: Size of the TX queue in frames
default:
- value: 3
constraints:
- type:
validator: positive_integer
- name: static_rx_buf_num
description: "Max number of WiFi static RX buffers.<br>
Each buffer takes approximately 1.6KB of RAM.
The static rx buffers are allocated when esp_wifi_init is called, they are not freed
until esp_wifi_deinit is called.<br>
WiFi hardware use these buffers to receive all 802.11 frames.
A higher number may allow higher throughput but increases memory use. If ESP_WIFI_AMPDU_RX_ENABLED
is enabled, this value is recommended to set equal or bigger than ESP_WIFI_RX_BA_WIN in order to
achieve better throughput and compatibility with both stations and APs."
default:
- value: 10
constraints:
- type:
validator: integer_in_range
value:
start: 0
end: 129
- name: dynamic_rx_buf_num
description: "Max number of WiFi dynamic RX buffers<br>
Set the number of WiFi dynamic RX buffers, 0 means unlimited RX buffers will be allocated
(provided sufficient free RAM). The size of each dynamic RX buffer depends on the size of
the received data frame.<br>
For each received data frame, the WiFi driver makes a copy to an RX buffer and then delivers
it to the high layer TCP/IP stack. The dynamic RX buffer is freed after the higher layer has
successfully received the data frame.<br>
For some applications, WiFi data frames may be received faster than the application can
process them. In these cases we may run out of memory if RX buffer number is unlimited (0).<br>
If a dynamic RX buffer limit is set, it should be at least the number of static RX buffers."
default:
- value: 32
constraints:
- type:
validator: integer_in_range
value:
start: 0
end: 1025
- name: static_tx_buf_num
description: "Set the number of WiFi static TX buffers. Each buffer takes approximately 1.6KB of RAM.
The static RX buffers are allocated when esp_wifi_init() is called, they are not released
until esp_wifi_deinit() is called.<br>
For each transmitted data frame from the higher layer TCP/IP stack, the WiFi driver makes a
copy of it in a TX buffer. For some applications especially UDP applications, the upper
layer can deliver frames faster than WiFi layer can transmit. In these cases, we may run out
of TX buffers."
default:
- value: 0
constraints:
- type:
validator: integer_in_range
value:
start: 0
end: 65
- name: dynamic_tx_buf_num
description: "Set the number of WiFi dynamic TX buffers. The size of each dynamic TX buffer is not fixed,
it depends on the size of each transmitted data frame.<br>
For each transmitted frame from the higher layer TCP/IP stack, the WiFi driver makes a copy
of it in a TX buffer. For some applications, especially UDP applications, the upper layer
can deliver frames faster than WiFi layer can transmit. In these cases, we may run out of TX
buffers."
default:
- value: 32
constraints:
- type:
validator: integer_in_range
value:
start: 0
end: 129
- name: ampdu_rx_enable
description: "Select this option to enable AMPDU RX feature"
default:
- value: true
- name: ampdu_tx_enable
description: "Select this option to enable AMPDU TX feature"
default:
- value: true
- name: amsdu_tx_enable
description: "Select this option to enable AMSDU TX feature. (If ESP_WIFI_CONFIG_CACHE_TX_BUFFER_NUM >= 2)"
default:
- value: false
- name: rx_ba_win
description: "Set the size of WiFi Block Ack RX window. Generally a bigger value means higher throughput and better
compatibility but more memory. Most of time we should NOT change the default value unless special
reason, e.g. test the maximum UDP RX throughput with iperf etc. For iperf test in shieldbox, the
recommended value is 9~12. If PSRAM is used and WiFi memory is preferred to allocate in PSRAM first,
the default and minimum value should be 16 to achieve better throughput and compatibility with both
stations and APs."
default:
- value: 6
constraints:
- type:
validator: integer_in_range
value:
start: 2
end: 65
- name: max_burst_size
# TODO these could also be runtime configurable
- name: wifi_max_burst_size
description: See [smoltcp's documentation](https://docs.rs/smoltcp/0.10.0/smoltcp/phy/struct.DeviceCapabilities.html#structfield.max_burst_size)
default:
- value: 1
- name: country_code
description: "Country code. See
[ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-country-code)"
default:
- value: '"CN"'
- name: country_code_operating_class
description: 'If not 0: Operating Class table number. See
[ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-country-code)'
default:
- value: 0
- name: mtu
- name: wifi_mtu
description: "MTU, see [smoltcp's documentation](https://docs.rs/smoltcp/0.10.0/smoltcp/phy/struct.DeviceCapabilities.html#structfield.max_transmission_unit)"
default:
- value: 1492
@ -144,6 +15,7 @@ options:
- type:
validator: positive_integer
# TODO Should be part of ClientConfig
- name: listen_interval
description: 'Interval for station to listen to beacon from AP.
The unit of listen interval is one beacon interval.
@ -152,6 +24,7 @@ options:
default:
- value: 3
# TODO Should be part of ClientConfig
- name: beacon_timeout
description: 'For Station, If the station does not receive a beacon frame
from the connected SoftAP during the inactive time, disconnect from SoftAP.
@ -165,12 +38,14 @@ options:
start: 6
end: 31
# TODO Should be part of ApConfig
- name: ap_beacon_timeout
description: "For SoftAP, If the SoftAP doesn't receive any data from the connected STA
during inactive time, the SoftAP will force deauth the STA. Default is 300s"
default:
- value: 300
# TODO Should be part of ClientConfig
- name: failure_retry_cnt
description: "Number of connection retries station will do before moving to next AP.
scan_method should be set as WIFI_ALL_CHANNEL_SCAN to use this config.
@ -182,6 +57,7 @@ options:
- type:
validator: positive_integer
# TODO: this is a scan API argument
- name: scan_method
description: "0 = WIFI_FAST_SCAN, 1 = WIFI_ALL_CHANNEL_SCAN, defaults to 0"
default:
@ -198,6 +74,7 @@ options:
default:
- value: false
# TODO: Should these be esp_radio::init config options?
- name: phy_enable_usb
description: "Keeps USB running when using WiFi.
This allows debugging and log messages via USB Serial JTAG.
@ -215,6 +92,7 @@ options:
default:
- value: true
# TODO: This could be a config option for Ieee802154::new
- name: ieee802154_rx_queue_size
description: Size of the RX queue in frames
default:
@ -222,7 +100,3 @@ options:
constraints:
- type:
validator: positive_integer
checks:
- 'ESP_RADIO_CONFIG_RX_BA_WIN < ESP_RADIO_CONFIG_DYNAMIC_RX_BUF_NUM'
- 'ESP_RADIO_CONFIG_RX_BA_WIN < (ESP_RADIO_CONFIG_STATIC_RX_BUF_NUM * 2)'

View File

@ -1,11 +1,8 @@
use esp_config::{esp_config_bool, esp_config_int};
use esp_wifi_sys::include::{
ESP_WIFI_OS_ADAPTER_MAGIC,
ESP_WIFI_OS_ADAPTER_VERSION,
WIFI_INIT_CONFIG_MAGIC,
wifi_init_config_t,
wifi_osi_funcs_t,
wpa_crypto_funcs_t,
};
use super::os_adapter::{self, *};
@ -88,7 +85,7 @@ unsafe extern "C" fn is_in_isr_wrapper() -> i32 {
}
#[unsafe(no_mangle)]
static __ESP_RADIO_G_WIFI_OSI_FUNCS: wifi_osi_funcs_t = wifi_osi_funcs_t {
pub(crate) static __ESP_RADIO_G_WIFI_OSI_FUNCS: wifi_osi_funcs_t = wifi_osi_funcs_t {
_version: ESP_WIFI_OS_ADAPTER_VERSION as i32,
_env_is_chip: Some(env_is_chip),
_set_intr: Some(set_intr),
@ -246,46 +243,4 @@ const WIFI_FEATURE_CAPS: u64 = WIFI_ENABLE_WPA3_SAE | WIFI_ENABLE_ENTERPRISE;
#[unsafe(no_mangle)]
pub(super) static mut __ESP_RADIO_G_WIFI_FEATURE_CAPS: u64 = WIFI_FEATURE_CAPS;
pub(super) static mut G_CONFIG: wifi_init_config_t = wifi_init_config_t {
osi_funcs: core::ptr::addr_of!(__ESP_RADIO_G_WIFI_OSI_FUNCS).cast_mut(),
// dummy for now - populated in init
wpa_crypto_funcs: wpa_crypto_funcs_t {
size: 0,
version: 1,
hmac_sha256_vector: None,
pbkdf2_sha1: None,
aes_128_encrypt: None,
aes_128_decrypt: None,
omac1_aes_128: None,
ccmp_decrypt: None,
ccmp_encrypt: None,
aes_gmac: None,
sha256_vector: None,
},
static_rx_buf_num: esp_config_int!(i32, "ESP_RADIO_CONFIG_RX_QUEUE_SIZE"),
dynamic_rx_buf_num: esp_config_int!(i32, "ESP_RADIO_CONFIG_DYNAMIC_RX_BUF_NUM"),
tx_buf_type: esp_wifi_sys::include::CONFIG_ESP_WIFI_TX_BUFFER_TYPE as i32,
static_tx_buf_num: esp_config_int!(i32, "ESP_RADIO_CONFIG_STATIC_TX_BUF_NUM"),
dynamic_tx_buf_num: esp_config_int!(i32, "ESP_RADIO_CONFIG_DYNAMIC_TX_BUF_NUM"),
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: cfg!(feature = "csi") as i32,
ampdu_rx_enable: esp_config_bool!("ESP_RADIO_CONFIG_AMPDU_RX_ENABLE") as i32,
ampdu_tx_enable: esp_config_bool!("ESP_RADIO_CONFIG_AMPDU_TX_ENABLE") as i32,
amsdu_tx_enable: esp_config_bool!("ESP_RADIO_CONFIG_AMSDU_TX_ENABLE") as i32,
nvs_enable: 0,
nano_enable: 0,
rx_ba_win: esp_config_int!(i32, "ESP_RADIO_CONFIG_RX_BA_WIN"),
wifi_task_core_id: 0,
beacon_max_len: esp_wifi_sys::include::WIFI_SOFTAP_BEACON_MAX_LEN as i32,
mgmt_sbuf_num: esp_wifi_sys::include::WIFI_MGMT_SBUF_NUM as i32,
feature_caps: WIFI_FEATURE_CAPS,
sta_disconnected_pm: false,
espnow_max_encrypt_num: esp_wifi_sys::include::CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM as i32,
tx_hetb_queue_num: 3,
dump_hesigb_enable: false,
magic: WIFI_INIT_CONFIG_MAGIC as i32,
};
pub(super) static mut G_CONFIG: wifi_init_config_t = unsafe { core::mem::zeroed() };

View File

@ -17,12 +17,13 @@ use core::{
};
use enumset::{EnumSet, EnumSetType};
use esp_config::{esp_config_int, esp_config_str};
use esp_hal::asynch::AtomicWaker;
use esp_config::esp_config_int;
use esp_hal::{asynch::AtomicWaker, system::Cpu};
use esp_sync::NonReentrantMutex;
#[cfg(all(any(feature = "sniffer", feature = "esp-now"), feature = "unstable"))]
use esp_wifi_sys::include::wifi_pkt_rx_ctrl_t;
use esp_wifi_sys::include::{
WIFI_INIT_CONFIG_MAGIC,
WIFI_PROTOCOL_11AX,
WIFI_PROTOCOL_11B,
WIFI_PROTOCOL_11G,
@ -30,6 +31,7 @@ use esp_wifi_sys::include::{
WIFI_PROTOCOL_LR,
esp_wifi_connect_internal,
esp_wifi_disconnect_internal,
wifi_init_config_t,
wifi_scan_channel_bitmap_t,
};
#[cfg(feature = "wifi-eap")]
@ -82,7 +84,7 @@ use crate::{
wifi::private::PacketBuffer,
};
const MTU: usize = esp_config_int!(usize, "ESP_RADIO_CONFIG_MTU");
const MTU: usize = esp_config_int!(usize, "ESP_RADIO_CONFIG_WIFI_MTU");
#[cfg(all(feature = "csi", esp32c6))]
use crate::binary::include::wifi_csi_acquire_config_t;
@ -1119,8 +1121,8 @@ impl CsiConfig {
}
}
const RX_QUEUE_SIZE: usize = esp_config_int!(usize, "ESP_RADIO_CONFIG_RX_QUEUE_SIZE");
const TX_QUEUE_SIZE: usize = esp_config_int!(usize, "ESP_RADIO_CONFIG_TX_QUEUE_SIZE");
static RX_QUEUE_SIZE: AtomicUsize = AtomicUsize::new(0);
static TX_QUEUE_SIZE: AtomicUsize = AtomicUsize::new(0);
pub(crate) static DATA_QUEUE_RX_AP: NonReentrantMutex<VecDeque<PacketBuffer>> =
NonReentrantMutex::new(VecDeque::new());
@ -1370,9 +1372,6 @@ pub fn sta_mac() -> [u8; 6] {
pub(crate) fn wifi_init() -> Result<(), WifiError> {
unsafe {
internal::G_CONFIG.wpa_crypto_funcs = g_wifi_default_wpa_crypto_funcs;
internal::G_CONFIG.feature_caps = internal::__ESP_RADIO_G_WIFI_FEATURE_CAPS;
#[cfg(coex)]
esp_wifi_result!(coex_init())?;
@ -1456,7 +1455,7 @@ unsafe extern "C" fn recv_cb_sta(
// the function will try to trigger a context switch, which will fail if we
// are in an interrupt-free context.
match DATA_QUEUE_RX_STA.with(|queue| {
if queue.len() < RX_QUEUE_SIZE {
if queue.len() < RX_QUEUE_SIZE.load(Ordering::Relaxed) {
queue.push_back(packet);
Ok(())
} else {
@ -1487,7 +1486,7 @@ unsafe extern "C" fn recv_cb_ap(
// the function will try to trigger a context switch, which will fail if we
// are in an interrupt-free context.
match DATA_QUEUE_RX_AP.with(|queue| {
if queue.len() < RX_QUEUE_SIZE {
if queue.len() < RX_QUEUE_SIZE.load(Ordering::Relaxed) {
queue.push_back(packet);
Ok(())
} else {
@ -1763,7 +1762,7 @@ impl WifiDeviceMode {
}
fn can_send(&self) -> bool {
WIFI_TX_INFLIGHT.load(Ordering::SeqCst) < TX_QUEUE_SIZE
WIFI_TX_INFLIGHT.load(Ordering::SeqCst) < TX_QUEUE_SIZE.load(Ordering::Relaxed)
}
fn increase_in_flight_counter(&self) {
@ -2197,10 +2196,14 @@ impl Device for WifiDevice<'_> {
fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = MTU;
caps.max_burst_size = if esp_config_int!(usize, "ESP_RADIO_CONFIG_MAX_BURST_SIZE") == 0 {
caps.max_burst_size = if esp_config_int!(usize, "ESP_RADIO_CONFIG_WIFI_MAX_BURST_SIZE") == 0
{
None
} else {
Some(esp_config_int!(usize, "ESP_RADIO_CONFIG_MAX_BURST_SIZE"))
Some(esp_config_int!(
usize,
"ESP_RADIO_CONFIG_WIFI_MAX_BURST_SIZE"
))
};
caps
}
@ -2627,12 +2630,15 @@ pub(crate) mod embassy {
fn capabilities(&self) -> Capabilities {
let mut caps = Capabilities::default();
caps.max_transmission_unit = MTU;
caps.max_burst_size = if esp_config_int!(usize, "ESP_RADIO_CONFIG_MAX_BURST_SIZE") == 0
{
None
} else {
Some(esp_config_int!(usize, "ESP_RADIO_CONFIG_MAX_BURST_SIZE"))
};
caps.max_burst_size =
if esp_config_int!(usize, "ESP_RADIO_CONFIG_WIFI_MAX_BURST_SIZE") == 0 {
None
} else {
Some(esp_config_int!(
usize,
"ESP_RADIO_CONFIG_WIFI_MAX_BURST_SIZE"
))
};
caps
}
@ -2644,7 +2650,8 @@ pub(crate) mod embassy {
/// Power saving mode settings for the modem.
#[non_exhaustive]
#[derive(Default)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PowerSaveMode {
/// No power saving.
#[default]
@ -2700,6 +2707,242 @@ pub struct Interfaces<'d> {
pub sniffer: Sniffer<'d>,
}
/// Wi-Fi operating class.
///
/// Refer to Annex E of IEEE Std 802.11-2020.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub enum OperatingClass {
/// The regulations under which the station/AP is operating encompass all environments for the
/// current frequency band in the country.
AllEnvironments,
/// The regulations under which the station/AP is operating are for an outdoor environment only.
Outdoors,
/// The regulations under which the station/AP is operating are for an indoor environment only.
Indoors,
/// The station/AP is operating under a noncountry entity. The first two octets of the
/// noncountry entity is two ASCII XX characters.
NonCountryEntity,
/// Binary representation of the Operating Class table number currently in use. Refer to Annex E
/// of IEEE Std 802.11-2020.
Repr(u8),
}
impl Default for OperatingClass {
fn default() -> Self {
OperatingClass::Repr(0) // TODO: is this valid?
}
}
impl OperatingClass {
fn into_code(self) -> u8 {
match self {
OperatingClass::AllEnvironments => b' ',
OperatingClass::Outdoors => b'O',
OperatingClass::Indoors => b'I',
OperatingClass::NonCountryEntity => b'X',
OperatingClass::Repr(code) => code,
}
}
}
/// Country information.
///
/// Defaults to China (CN) with Operating Class "0".
///
/// To create a [`CountryInfo`] instance, use the `from` method first, then set additional
/// properties using the builder methods.
///
/// ## Example
///
/// ```rust,no_run
/// use esp_radio::wifi::{CountryInfo, OperatingClass};
///
/// let country_info = CountryInfo::from(*b"CN").operating_class(OperatingClass::Indoors);
/// ```
///
/// For more information, see the [Wi-Fi Country Code in the ESP-IDF documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-country-code).
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CountryInfo {
/// Country code.
#[builder_lite(skip)]
country: [u8; 2],
/// Operating class.
#[builder_lite(unstable)]
operating_class: OperatingClass,
}
impl From<[u8; 2]> for CountryInfo {
fn from(country: [u8; 2]) -> Self {
Self {
country,
operating_class: OperatingClass::default(),
}
}
}
impl CountryInfo {
fn into_blob(self) -> wifi_country_t {
wifi_country_t {
cc: [
self.country[0],
self.country[1],
self.operating_class.into_code(),
],
// TODO: these may be valid defaults, but they should be configurable.
schan: 1,
nchan: 13,
max_tx_power: 20,
policy: wifi_country_policy_t_WIFI_COUNTRY_POLICY_MANUAL,
}
}
}
/// Wi-Fi configuration.
#[derive(Clone, Copy, BuilderLite, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct WifiConfig {
/// Power save mode.
power_save_mode: PowerSaveMode,
/// Country code.
#[builder_lite(into)]
#[builder_lite(unstable)]
country_code: CountryInfo,
/// Size of the RX queue in frames.
#[builder_lite(unstable)]
rx_queue_size: usize,
/// Size of the TX queue in frames.
#[builder_lite(unstable)]
tx_queue_size: usize,
/// Max number of WiFi static RX buffers.
///
/// Each buffer takes approximately 1.6KB of RAM. The static rx buffers are allocated when
/// esp_wifi_init is called, they are not freed until esp_wifi_deinit is called.
///
/// WiFi hardware use these buffers to receive all 802.11 frames. A higher number may allow
/// higher throughput but increases memory use. If [`Self::ampdu_rx_enable`] is enabled,
/// this value is recommended to set equal or bigger than [`Self::rx_ba_win`] in order to
/// achieve better throughput and compatibility with both stations and APs.
#[builder_lite(unstable)]
static_rx_buf_num: u8,
/// Max number of WiFi dynamic RX buffers
///
/// Set the number of WiFi dynamic RX buffers, 0 means unlimited RX buffers will be allocated
/// (provided sufficient free RAM). The size of each dynamic RX buffer depends on the size of
/// the received data frame.
///
/// For each received data frame, the WiFi driver makes a copy to an RX buffer and then
/// delivers it to the high layer TCP/IP stack. The dynamic RX buffer is freed after the
/// higher layer has successfully received the data frame.
///
/// For some applications, WiFi data frames may be received faster than the application can
/// process them. In these cases we may run out of memory if RX buffer number is unlimited
/// (0).
///
/// If a dynamic RX buffer limit is set, it should be at least the number of
/// static RX buffers.
#[builder_lite(unstable)]
dynamic_rx_buf_num: u16,
/// Set the number of WiFi static TX buffers.
///
/// Each buffer takes approximately 1.6KB of RAM.
/// The static RX buffers are allocated when esp_wifi_init() is called, they are not released
/// until esp_wifi_deinit() is called.
///
/// For each transmitted data frame from the higher layer TCP/IP stack, the WiFi driver makes a
/// copy of it in a TX buffer.
///
/// For some applications especially UDP applications, the upper layer can deliver frames
/// faster than WiFi layer can transmit. In these cases, we may run out of TX buffers.
#[builder_lite(unstable)]
static_tx_buf_num: u8,
/// Set the number of WiFi dynamic TX buffers.
///
/// The size of each dynamic TX buffer is not fixed,
/// it depends on the size of each transmitted data frame.
///
/// For each transmitted frame from the higher layer TCP/IP stack, the WiFi driver makes a copy
/// of it in a TX buffer.
///
/// For some applications, especially UDP applications, the upper layer can deliver frames
/// faster than WiFi layer can transmit. In these cases, we may run out of TX buffers.
#[builder_lite(unstable)]
dynamic_tx_buf_num: u16,
/// Select this option to enable AMPDU RX feature.
#[builder_lite(unstable)]
ampdu_rx_enable: bool,
/// Select this option to enable AMPDU TX feature.
#[builder_lite(unstable)]
ampdu_tx_enable: bool,
/// Select this option to enable AMSDU TX feature.
#[builder_lite(unstable)]
amsdu_tx_enable: bool,
/// Set the size of WiFi Block Ack RX window.
///
/// Generally a bigger value means higher throughput and better compatibility but more memory.
/// Most of time we should NOT change the default value unless special reason, e.g. test
/// the maximum UDP RX throughput with iperf etc. For iperf test in shieldbox, the
/// recommended value is 9~12.
///
/// If PSRAM is used and WiFi memory is preferred to allocate in PSRAM first, the default and
/// minimum value should be 16 to achieve better throughput and compatibility with both
/// stations and APs.
#[builder_lite(unstable)]
rx_ba_win: u8,
}
impl Default for WifiConfig {
fn default() -> Self {
Self {
power_save_mode: PowerSaveMode::default(),
country_code: CountryInfo::from(*b"CN"),
rx_queue_size: 5,
tx_queue_size: 3,
static_rx_buf_num: 10,
dynamic_rx_buf_num: 32,
static_tx_buf_num: 0,
dynamic_tx_buf_num: 32,
ampdu_rx_enable: true,
ampdu_tx_enable: true,
amsdu_tx_enable: false,
rx_ba_win: 6,
}
}
}
impl WifiConfig {
fn validate(&self) {
if self.rx_ba_win as u16 >= self.dynamic_rx_buf_num {
warn!("RX BA window size should be less than the number of dynamic RX buffers.");
}
if self.rx_ba_win as u16 >= 2 * (self.static_rx_buf_num as u16) {
warn!("RX BA window size should be less than twice the number of static RX buffers.");
}
}
}
/// Create a Wi-Fi controller and it's associated interfaces.
///
/// Dropping the controller will deinitialize / stop Wi-Fi.
@ -2709,25 +2952,56 @@ pub struct Interfaces<'d> {
pub fn new<'d>(
_inited: &'d Controller<'d>,
_device: crate::hal::peripherals::WIFI<'d>,
config: WifiConfig,
) -> Result<(WifiController<'d>, Interfaces<'d>), WifiError> {
if crate::is_interrupts_disabled() {
return Err(WifiError::Unsupported);
}
config.validate();
unsafe {
internal::G_CONFIG = wifi_init_config_t {
osi_funcs: (&raw const internal::__ESP_RADIO_G_WIFI_OSI_FUNCS).cast_mut(),
wpa_crypto_funcs: g_wifi_default_wpa_crypto_funcs,
static_rx_buf_num: config.static_rx_buf_num as _,
dynamic_rx_buf_num: config.dynamic_rx_buf_num as _,
tx_buf_type: esp_wifi_sys::include::CONFIG_ESP_WIFI_TX_BUFFER_TYPE as i32,
static_tx_buf_num: config.static_tx_buf_num as _,
dynamic_tx_buf_num: config.dynamic_tx_buf_num as _,
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: cfg!(feature = "csi") as i32,
ampdu_rx_enable: config.ampdu_rx_enable as _,
ampdu_tx_enable: config.ampdu_tx_enable as _,
amsdu_tx_enable: config.amsdu_tx_enable as _,
nvs_enable: 0,
nano_enable: 0,
rx_ba_win: config.rx_ba_win as _,
wifi_task_core_id: Cpu::current() as _,
beacon_max_len: esp_wifi_sys::include::WIFI_SOFTAP_BEACON_MAX_LEN as i32,
mgmt_sbuf_num: esp_wifi_sys::include::WIFI_MGMT_SBUF_NUM as i32,
feature_caps: internal::__ESP_RADIO_G_WIFI_FEATURE_CAPS,
sta_disconnected_pm: false,
espnow_max_encrypt_num: esp_wifi_sys::include::CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM
as i32,
tx_hetb_queue_num: 3,
dump_hesigb_enable: false,
magic: WIFI_INIT_CONFIG_MAGIC as i32,
};
RX_QUEUE_SIZE.store(config.rx_queue_size, Ordering::Relaxed);
TX_QUEUE_SIZE.store(config.tx_queue_size, Ordering::Relaxed);
};
crate::wifi::wifi_init()?;
let mut cntry_code = [0u8; 3];
cntry_code[..esp_config_str!("ESP_RADIO_CONFIG_COUNTRY_CODE").len()]
.copy_from_slice(esp_config_str!("ESP_RADIO_CONFIG_COUNTRY_CODE").as_bytes());
cntry_code[2] = esp_config_int!(u8, "ESP_RADIO_CONFIG_COUNTRY_CODE_OPERATING_CLASS");
unsafe {
let country = wifi_country_t {
cc: cntry_code,
schan: 1,
nchan: 13,
max_tx_power: 20,
policy: wifi_country_policy_t_WIFI_COUNTRY_POLICY_MANUAL,
};
let country = config.country_code.into_blob();
esp_wifi_result!(esp_wifi_set_country(&country))?;
}
@ -2740,7 +3014,7 @@ pub fn new<'d>(
_phantom: Default::default(),
};
controller.set_power_saving(PowerSaveMode::default())?;
controller.set_power_saving(config.power_save_mode)?;
Ok((
controller,

View File

@ -45,7 +45,8 @@ async fn main(_spawner: Spawner) -> ! {
let esp_radio_ctrl = &*mk_static!(Controller<'static>, esp_radio::init().unwrap());
let wifi = peripherals.WIFI;
let (mut controller, interfaces) = esp_radio::wifi::new(&esp_radio_ctrl, wifi).unwrap();
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, wifi, Default::default()).unwrap();
controller.set_mode(esp_radio::wifi::WifiMode::Sta).unwrap();
controller.start().unwrap();

View File

@ -46,7 +46,8 @@ async fn main(spawner: Spawner) -> ! {
let esp_radio_ctrl = &*mk_static!(Controller<'static>, esp_radio::init().unwrap());
let wifi = peripherals.WIFI;
let (mut controller, interfaces) = esp_radio::wifi::new(&esp_radio_ctrl, wifi).unwrap();
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, wifi, Default::default()).unwrap();
controller.set_mode(esp_radio::wifi::WifiMode::Sta).unwrap();
controller.start().unwrap();

View File

@ -32,7 +32,8 @@ fn main() -> ! {
let esp_radio_ctrl = esp_radio::init().unwrap();
let wifi = peripherals.WIFI;
let (mut controller, interfaces) = esp_radio::wifi::new(&esp_radio_ctrl, wifi).unwrap();
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, wifi, Default::default()).unwrap();
controller.set_mode(esp_radio::wifi::WifiMode::Sta).unwrap();
controller.start().unwrap();

View File

@ -44,7 +44,7 @@ fn main() -> ! {
// We must initialize some kind of interface and start it.
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
controller.set_mode(wifi::WifiMode::Sta).unwrap();
controller.start().unwrap();

View File

@ -66,7 +66,7 @@ fn main() -> ! {
let esp_radio_ctrl = esp_radio::init().unwrap();
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let mut device = interfaces.ap;
let iface = create_interface(&mut device);

View File

@ -52,7 +52,7 @@ fn main() -> ! {
let esp_radio_ctrl = esp_radio::init().unwrap();
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let mut ap_device = interfaces.ap;
let ap_interface = create_interface(&mut ap_device);

View File

@ -99,7 +99,7 @@ fn main() -> ! {
println!("started advertising");
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let mut device = interfaces.sta;
let iface = create_interface(&mut device);

View File

@ -49,7 +49,7 @@ fn main() -> ! {
let esp_radio_ctrl = esp_radio::init().unwrap();
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let mut device = interfaces.sta;
let iface = create_interface(&mut device);

View File

@ -62,7 +62,8 @@ async fn main(spawner: Spawner) -> ! {
let esp_radio_ctrl = &*mk_static!(Controller<'static>, esp_radio::init().unwrap());
let (controller, interfaces) = esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
let (controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let device = interfaces.ap;

View File

@ -78,7 +78,7 @@ async fn main(spawner: Spawner) -> ! {
let esp_radio_ctrl = &*mk_static!(Controller<'static>, esp_radio::init().unwrap());
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let wifi_ap_device = interfaces.ap;
let wifi_sta_device = interfaces.sta;

View File

@ -53,7 +53,8 @@ async fn main(spawner: Spawner) -> ! {
let esp_radio_ctrl = &*mk_static!(Controller<'static>, esp_radio::init().unwrap());
let (controller, interfaces) = esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
let (controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let wifi_interface = interfaces.sta;

View File

@ -39,7 +39,7 @@ fn main() -> ! {
// We must initialize some kind of interface and start it.
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
controller.set_mode(wifi::WifiMode::Sta).unwrap();
controller.start().unwrap();

View File

@ -85,7 +85,8 @@ async fn main(spawner: Spawner) -> ! {
let esp_radio_ctrl = &*mk_static!(Controller<'static>, esp_radio::init().unwrap());
let (controller, interfaces) = esp_radio::wifi::new(esp_radio_ctrl, peripherals.WIFI).unwrap();
let (controller, interfaces) =
esp_radio::wifi::new(esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let wifi_interface = interfaces.sta;

View File

@ -46,7 +46,7 @@ fn main() -> ! {
let esp_radio_ctrl = esp_radio::init().unwrap();
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let mut device = interfaces.sta;
let iface = create_interface(&mut device);

View File

@ -121,11 +121,13 @@ mod tests {
&*mk_static!(esp_radio::Controller<'static>, esp_radio::init().unwrap());
// Initialize, then de-initialize wifi
let wifi = esp_radio::wifi::new(&esp_radio_ctrl, p.WIFI.reborrow()).unwrap();
let wifi =
esp_radio::wifi::new(&esp_radio_ctrl, p.WIFI.reborrow(), Default::default()).unwrap();
drop(wifi);
// Now, can we do it again?
let _wifi = esp_radio::wifi::new(&esp_radio_ctrl, p.WIFI.reborrow()).unwrap();
let _wifi =
esp_radio::wifi::new(&esp_radio_ctrl, p.WIFI.reborrow(), Default::default()).unwrap();
}
#[test]

View File

@ -81,7 +81,7 @@ async fn main(spawner: Spawner) -> ! {
let esp_radio_ctrl = &*mk_static!(Controller<'static>, esp_radio::init().unwrap());
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let wifi_interface = interfaces.sta;

View File

@ -67,7 +67,7 @@ fn main() -> ! {
let esp_radio_ctrl = esp_radio::init().unwrap();
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let mut device = interfaces.sta;
let iface = create_interface(&mut device);

View File

@ -41,7 +41,7 @@ fn main() -> ! {
let esp_radio_ctrl = esp_radio::init().unwrap();
let (mut controller, interfaces) =
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap();
esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let mut device = interfaces.sta;
let iface = create_interface(&mut device);