diff --git a/esp-radio/CHANGELOG.md b/esp-radio/CHANGELOG.md
index 2e3814609..a32ea68d9 100644
--- a/esp-radio/CHANGELOG.md
+++ b/esp-radio/CHANGELOG.md
@@ -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
diff --git a/esp-radio/MIGRATING-0.15.0.md b/esp-radio/MIGRATING-0.15.0.md
index 34f247fb0..984294e6e 100644
--- a/esp-radio/MIGRATING-0.15.0.md
+++ b/esp-radio/MIGRATING-0.15.0.md
@@ -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
diff --git a/esp-radio/esp_config.yml b/esp-radio/esp_config.yml
index 08a8e52e2..27c51994d 100644
--- a/esp-radio/esp_config.yml
+++ b/esp-radio/esp_config.yml
@@ -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.
- 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 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
- 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."
- 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.
- 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.
- 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)'
diff --git a/esp-radio/src/wifi/internal.rs b/esp-radio/src/wifi/internal.rs
index 97fb61893..beba05f60 100644
--- a/esp-radio/src/wifi/internal.rs
+++ b/esp-radio/src/wifi/internal.rs
@@ -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() };
diff --git a/esp-radio/src/wifi/mod.rs b/esp-radio/src/wifi/mod.rs
index 67755b6b2..2498b7b2a 100644
--- a/esp-radio/src/wifi/mod.rs
+++ b/esp-radio/src/wifi/mod.rs
@@ -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> =
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,
diff --git a/examples/esp-now/embassy_esp_now/src/main.rs b/examples/esp-now/embassy_esp_now/src/main.rs
index 53c786baa..75860c1f0 100644
--- a/examples/esp-now/embassy_esp_now/src/main.rs
+++ b/examples/esp-now/embassy_esp_now/src/main.rs
@@ -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();
diff --git a/examples/esp-now/embassy_esp_now_duplex/src/main.rs b/examples/esp-now/embassy_esp_now_duplex/src/main.rs
index 55cbfafba..4ee856b97 100644
--- a/examples/esp-now/embassy_esp_now_duplex/src/main.rs
+++ b/examples/esp-now/embassy_esp_now_duplex/src/main.rs
@@ -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();
diff --git a/examples/esp-now/esp_now/src/main.rs b/examples/esp-now/esp_now/src/main.rs
index 60b2ddc89..7e78b6b6b 100644
--- a/examples/esp-now/esp_now/src/main.rs
+++ b/examples/esp-now/esp_now/src/main.rs
@@ -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();
diff --git a/examples/wifi/80211_tx/src/main.rs b/examples/wifi/80211_tx/src/main.rs
index ddbf988b3..56118c4ce 100644
--- a/examples/wifi/80211_tx/src/main.rs
+++ b/examples/wifi/80211_tx/src/main.rs
@@ -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();
diff --git a/examples/wifi/access_point/src/main.rs b/examples/wifi/access_point/src/main.rs
index abf84271d..51e26ee9d 100644
--- a/examples/wifi/access_point/src/main.rs
+++ b/examples/wifi/access_point/src/main.rs
@@ -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);
diff --git a/examples/wifi/access_point_with_sta/src/main.rs b/examples/wifi/access_point_with_sta/src/main.rs
index ff2e92dab..ec0808d14 100644
--- a/examples/wifi/access_point_with_sta/src/main.rs
+++ b/examples/wifi/access_point_with_sta/src/main.rs
@@ -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);
diff --git a/examples/wifi/coex/src/main.rs b/examples/wifi/coex/src/main.rs
index 170c0444a..be4eed3c3 100644
--- a/examples/wifi/coex/src/main.rs
+++ b/examples/wifi/coex/src/main.rs
@@ -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);
diff --git a/examples/wifi/dhcp/src/main.rs b/examples/wifi/dhcp/src/main.rs
index c705d5463..7cc6f0e7f 100644
--- a/examples/wifi/dhcp/src/main.rs
+++ b/examples/wifi/dhcp/src/main.rs
@@ -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);
diff --git a/examples/wifi/embassy_access_point/src/main.rs b/examples/wifi/embassy_access_point/src/main.rs
index 70b5c7d53..7820165f8 100644
--- a/examples/wifi/embassy_access_point/src/main.rs
+++ b/examples/wifi/embassy_access_point/src/main.rs
@@ -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;
diff --git a/examples/wifi/embassy_access_point_with_sta/src/main.rs b/examples/wifi/embassy_access_point_with_sta/src/main.rs
index 08ec0f366..b552bbbeb 100644
--- a/examples/wifi/embassy_access_point_with_sta/src/main.rs
+++ b/examples/wifi/embassy_access_point_with_sta/src/main.rs
@@ -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;
diff --git a/examples/wifi/embassy_dhcp/src/main.rs b/examples/wifi/embassy_dhcp/src/main.rs
index fa5326406..7fcd80718 100644
--- a/examples/wifi/embassy_dhcp/src/main.rs
+++ b/examples/wifi/embassy_dhcp/src/main.rs
@@ -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;
diff --git a/examples/wifi/sniffer/src/main.rs b/examples/wifi/sniffer/src/main.rs
index e10e78b7d..eda5ab3ac 100644
--- a/examples/wifi/sniffer/src/main.rs
+++ b/examples/wifi/sniffer/src/main.rs
@@ -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();
diff --git a/examples/wifi/sntp/src/main.rs b/examples/wifi/sntp/src/main.rs
index 9c188c7ee..f598d6805 100644
--- a/examples/wifi/sntp/src/main.rs
+++ b/examples/wifi/sntp/src/main.rs
@@ -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;
diff --git a/examples/wifi/static_ip/src/main.rs b/examples/wifi/static_ip/src/main.rs
index da2028544..8b7eeb327 100644
--- a/examples/wifi/static_ip/src/main.rs
+++ b/examples/wifi/static_ip/src/main.rs
@@ -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);
diff --git a/hil-test/tests/esp_radio_init.rs b/hil-test/tests/esp_radio_init.rs
index b5c9605e2..3f7d1c9ee 100644
--- a/hil-test/tests/esp_radio_init.rs
+++ b/hil-test/tests/esp_radio_init.rs
@@ -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]
diff --git a/qa-test/src/bin/embassy_wifi_bench.rs b/qa-test/src/bin/embassy_wifi_bench.rs
index 3a32c9fd6..996cd1db3 100644
--- a/qa-test/src/bin/embassy_wifi_bench.rs
+++ b/qa-test/src/bin/embassy_wifi_bench.rs
@@ -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;
diff --git a/qa-test/src/bin/wifi_bench.rs b/qa-test/src/bin/wifi_bench.rs
index 2d1663a02..746ac537c 100644
--- a/qa-test/src/bin/wifi_bench.rs
+++ b/qa-test/src/bin/wifi_bench.rs
@@ -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);
diff --git a/qa-test/src/bin/wifi_csi.rs b/qa-test/src/bin/wifi_csi.rs
index 7b5b71043..f7b23c4e4 100644
--- a/qa-test/src/bin/wifi_csi.rs
+++ b/qa-test/src/bin/wifi_csi.rs
@@ -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);