From 521506a6f7d55d53212b778664ba37c9ff09254d Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Tue, 26 May 2026 12:46:18 +0100 Subject: [PATCH 1/6] remove unused config options from docs - make dtim_period and max_conns unstable --- esp-radio/src/wifi/ap.rs | 2 ++ esp-radio/src/wifi/mod.rs | 8 -------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/esp-radio/src/wifi/ap.rs b/esp-radio/src/wifi/ap.rs index a100c3903e5..bbc70d9dbaa 100644 --- a/esp-radio/src/wifi/ap.rs +++ b/esp-radio/src/wifi/ap.rs @@ -53,8 +53,10 @@ pub struct AccessPointConfig { #[builder_lite(reference)] pub(crate) password: String, /// The maximum number of connections allowed on the access point. + #[builder_lite(unstable)] pub(crate) max_connections: u16, /// Dtim period of the access point (Range: 1 ~ 10). + #[builder_lite(unstable)] pub(crate) dtim_period: u8, /// Time to force deauth the station if the Soft-AccessPoint doesn't receive any data. #[builder_lite(unstable)] diff --git a/esp-radio/src/wifi/mod.rs b/esp-radio/src/wifi/mod.rs index 1d3e6b32aa4..37f4af3e9c3 100644 --- a/esp-radio/src/wifi/mod.rs +++ b/esp-radio/src/wifi/mod.rs @@ -37,14 +37,6 @@ //! //! Please note that the configuration keys are usually named slightly different and not all //! configuration keys apply. -//! -//! By default the power-saving mode is [PowerSaveMode::None] -//! and `ESP_PHY_CONFIG_PHY_ENABLE_USB` is enabled by default. -//! -//! In addition pay attention to these configuration keys: -//! - `ESP_RADIO_CONFIG_RX_QUEUE_SIZE` -//! - `ESP_RADIO_CONFIG_TX_QUEUE_SIZE` -//! - `ESP_RADIO_CONFIG_MAX_BURST_SIZE` use alloc::{borrow::ToOwned, collections::vec_deque::VecDeque, str, vec::Vec}; use core::{ From baf3bebc68f97761e765983160e7daf9a69253bd Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Tue, 26 May 2026 12:58:02 +0100 Subject: [PATCH 2/6] move type to sta/ap modules where appropriate --- esp-radio/src/wifi/ap.rs | 40 ++++++++- esp-radio/src/wifi/mod.rs | 82 ++----------------- esp-radio/src/wifi/sta/mod.rs | 34 +++++++- .../wifi/embassy_access_point/src/main.rs | 4 +- .../embassy_access_point_with_sta/src/main.rs | 4 +- 5 files changed, 85 insertions(+), 79 deletions(-) diff --git a/esp-radio/src/wifi/ap.rs b/esp-radio/src/wifi/ap.rs index bbc70d9dbaa..4b149d4da09 100644 --- a/esp-radio/src/wifi/ap.rs +++ b/esp-radio/src/wifi/ap.rs @@ -7,7 +7,7 @@ use procmacros::BuilderLite; #[cfg(feature = "unstable")] use super::CountryInfo; -use super::{AuthenticationMethod, Protocols, SecondaryChannel, Ssid}; +use super::{AuthenticationMethod, DisconnectReason, Protocols, SecondaryChannel, Ssid}; use crate::{WifiError, sys::include::wifi_ap_record_t}; /// Information about a detected Wi-Fi access point. @@ -151,6 +151,44 @@ impl defmt::Format for AccessPointConfig { } } +/// Information about a station connected to the access point. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct AccessPointStationConnectedInfo { + /// The MAC address. + pub mac: [u8; 6], + /// The Association ID (AID) of the connected station. + pub aid: u16, + /// If this is a mesh child. + pub is_mesh_child: bool, +} + +/// Information about a station disconnected from the access point. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct AccessPointStationDisconnectedInfo { + /// The MAC address. + pub mac: [u8; 6], + /// The Association ID (AID) of the connected station. + pub aid: u16, + /// If this is a mesh child. + pub is_mesh_child: bool, + /// The disconnect reason. + pub reason: DisconnectReason, +} + +/// Either the [AccessPointStationConnectedInfo] or [AccessPointStationDisconnectedInfo]. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum AccessPointStationEventInfo { + /// Information about a station connected to the access point. + Connected(AccessPointStationConnectedInfo), + /// Information about a station disconnected from the access point. + Disconnected(AccessPointStationDisconnectedInfo), +} + #[allow(non_upper_case_globals)] pub(crate) fn convert_ap_info(record: &wifi_ap_record_t) -> AccessPointInfo { let str_len = record diff --git a/esp-radio/src/wifi/mod.rs b/esp-radio/src/wifi/mod.rs index 37f4af3e9c3..07bee868eb8 100644 --- a/esp-radio/src/wifi/mod.rs +++ b/esp-radio/src/wifi/mod.rs @@ -65,10 +65,17 @@ use self::sniffer::Sniffer; #[cfg(feature = "wifi-eap")] use self::sta::eap::EapStationConfig; use self::{ - ap::{AccessPointConfig, AccessPointInfo, convert_ap_info}, + ap::{ + AccessPointConfig, + AccessPointInfo, + AccessPointStationConnectedInfo, + AccessPointStationDisconnectedInfo, + AccessPointStationEventInfo, + convert_ap_info, + }, private::PacketBuffer, scan::{FreeApListOnDrop, ScanConfig, ScanResults, ScanTypeConfig}, - sta::StationConfig, + sta::{ConnectedStationInfo, DisconnectedStationInfo, StationConfig}, state::*, }; use crate::{ @@ -799,77 +806,6 @@ impl From<&[u8]> for Ssid { } } -/// Information about a connected station. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub struct ConnectedStationInfo { - /// The SSID of the connected station. - pub ssid: Ssid, - /// The BSSID of the connected station. - pub bssid: [u8; 6], - /// The channel of the connected station. - pub channel: u8, - /// The authmode of the connected station. - pub authmode: AuthenticationMethod, - /// The Association ID (AID) of the connected station. - pub aid: u16, -} - -/// Information about a disconnected station. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub struct DisconnectedStationInfo { - /// The SSID of the disconnected station. - pub ssid: Ssid, - /// The BSSID of the disconnected station. - pub bssid: [u8; 6], - /// The disconnect reason. - // should we introduce an enum? - pub reason: DisconnectReason, - /// The RSSI. - pub rssi: i8, -} - -/// Information about a station connected to the access point. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub struct AccessPointStationConnectedInfo { - /// The MAC address. - pub mac: [u8; 6], - /// The Association ID (AID) of the connected station. - pub aid: u16, - /// If this is a mesh child. - pub is_mesh_child: bool, -} - -/// Information about a station disconnected from the access point. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub struct AccessPointStationDisconnectedInfo { - /// The MAC address. - pub mac: [u8; 6], - /// The Association ID (AID) of the connected station. - pub aid: u16, - /// If this is a mesh child. - pub is_mesh_child: bool, - /// The disconnect reason. - pub reason: DisconnectReason, -} - -/// Either the [AccessPointStationConnectedInfo] or [AccessPointStationDisconnectedInfo]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum AccessPointStationEventInfo { - /// Information about a station connected to the access point. - Connected(AccessPointStationConnectedInfo), - /// Information about a station disconnected from the access point. - Disconnected(AccessPointStationDisconnectedInfo), -} - static TX_QUEUE_SIZE: AtomicUsize = AtomicUsize::new(0); /// A receive packet queue. diff --git a/esp-radio/src/wifi/sta/mod.rs b/esp-radio/src/wifi/sta/mod.rs index 16c700d96b7..9a2ad54c3c8 100644 --- a/esp-radio/src/wifi/sta/mod.rs +++ b/esp-radio/src/wifi/sta/mod.rs @@ -5,7 +5,7 @@ use core::fmt; use procmacros::BuilderLite; -use super::{AuthenticationMethod, Protocols, Ssid}; +use super::{AuthenticationMethod, DisconnectReason, Protocols, Ssid}; use crate::WifiError; unstable_module!( @@ -156,3 +156,35 @@ impl defmt::Format for StationConfig { ) } } + +/// Information about a connected station. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct ConnectedStationInfo { + /// The SSID of the connected station. + pub ssid: Ssid, + /// The BSSID of the connected station. + pub bssid: [u8; 6], + /// The channel of the connected station. + pub channel: u8, + /// The authmode of the connected station. + pub authmode: AuthenticationMethod, + /// The Association ID (AID) of the connected station. + pub aid: u16, +} + +/// Information about a disconnected station. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct DisconnectedStationInfo { + /// The SSID of the disconnected station. + pub ssid: Ssid, + /// The BSSID of the disconnected station. + pub bssid: [u8; 6], + /// The disconnect reason. + pub reason: DisconnectReason, + /// The RSSI. + pub rssi: i8, +} diff --git a/examples/wifi/embassy_access_point/src/main.rs b/examples/wifi/embassy_access_point/src/main.rs index fa8713ba98a..ec85927a690 100644 --- a/examples/wifi/embassy_access_point/src/main.rs +++ b/examples/wifi/embassy_access_point/src/main.rs @@ -234,7 +234,7 @@ async fn connection(controller: WifiController<'static>) { .wait_for_access_point_connected_event_async() .await; match ev { - Ok(esp_radio::wifi::AccessPointStationEventInfo::Connected( + Ok(esp_radio::wifi::ap::AccessPointStationEventInfo::Connected( access_point_station_connected_info, )) => { println!( @@ -242,7 +242,7 @@ async fn connection(controller: WifiController<'static>) { access_point_station_connected_info ); } - Ok(esp_radio::wifi::AccessPointStationEventInfo::Disconnected( + Ok(esp_radio::wifi::ap::AccessPointStationEventInfo::Disconnected( access_point_station_disconnected_info, )) => { println!( 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 9dd19ad0a04..ec83aefcb4f 100644 --- a/examples/wifi/embassy_access_point_with_sta/src/main.rs +++ b/examples/wifi/embassy_access_point_with_sta/src/main.rs @@ -346,7 +346,7 @@ async fn connection(mut controller: WifiController<'static>) { Either::Second(event) => { if let Ok(event) = event { match event { - esp_radio::wifi::AccessPointStationEventInfo::Connected( + esp_radio::wifi::ap::AccessPointStationEventInfo::Connected( access_point_station_connected_info, ) => { println!( @@ -354,7 +354,7 @@ async fn connection(mut controller: WifiController<'static>) { access_point_station_connected_info ); } - esp_radio::wifi::AccessPointStationEventInfo::Disconnected( + esp_radio::wifi::ap::AccessPointStationEventInfo::Disconnected( access_point_station_disconnected_info, ) => { println!( From 609f34fc2ca5e965ee1e3b527f5ebbd983da1c9e Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Tue, 26 May 2026 13:03:00 +0100 Subject: [PATCH 3/6] replace new() with WifiController::new() --- esp-radio/src/lib.rs | 2 +- esp-radio/src/wifi/event.rs | 3 +- esp-radio/src/wifi/mod.rs | 241 +++++++++--------- examples/esp-now/embassy_esp_now/src/main.rs | 2 +- .../embassy_esp_now_duplex/src/main.rs | 2 +- examples/wifi/80211_tx/src/main.rs | 3 +- .../wifi/embassy_access_point/src/main.rs | 2 +- .../embassy_access_point_with_sta/src/main.rs | 2 +- examples/wifi/embassy_coex/src/main.rs | 2 +- examples/wifi/embassy_dhcp/src/main.rs | 2 +- examples/wifi/embassy_sntp/src/main.rs | 2 +- examples/wifi/sniffer/src/main.rs | 3 +- hil-test/src/bin/esp_radio/init_tests.rs | 25 +- hil-test/src/bin/esp_radio/wifi_controller.rs | 5 +- qa-test/src/bin/embassy_scan_after_sleep.rs | 3 +- qa-test/src/bin/embassy_wifi_bench.rs | 2 +- qa-test/src/bin/embassy_wifi_csi.rs | 2 +- qa-test/src/bin/embassy_wifi_drop.rs | 4 +- qa-test/src/bin/embassy_wifi_i2s.rs | 2 +- qa-test/src/bin/embassy_wifi_stress.rs | 3 +- qa-test/src/bin/wifi_survives_ble_drop.rs | 2 +- qa-test/src/bin/wifi_syslog.rs | 2 +- 22 files changed, 166 insertions(+), 150 deletions(-) diff --git a/esp-radio/src/lib.rs b/esp-radio/src/lib.rs index 0058405cb3f..678cc920a0e 100644 --- a/esp-radio/src/lib.rs +++ b/esp-radio/src/lib.rs @@ -46,7 +46,7 @@ wifi_driver_supported, doc = r#" -if let Ok(controller) = esp_radio::wifi::new( +if let Ok(controller) = esp_radio::wifi::WifiController::new( peripherals.WIFI, Default::default(), ) {} diff --git a/esp-radio/src/wifi/event.rs b/esp-radio/src/wifi/event.rs index 5e75a224821..36b3fc24b9c 100644 --- a/esp-radio/src/wifi/event.rs +++ b/esp-radio/src/wifi/event.rs @@ -1289,7 +1289,8 @@ pub fn enable_wifi_events(events: EnumSet) { /// - [WifiEvent::AccessPointStationDisconnected] /// - [WifiEvent::ScanDone] /// -/// [crate::wifi::new] always enables these events, even if they were disabled beforehand. +/// [crate::wifi::WifiController::new] always enables these events, even if they were disabled +/// beforehand. #[instability::unstable] pub fn disable_wifi_events(events: EnumSet) { WIFI_EVENT_ENABLE_MASK.with(|mask| *mask &= !events); diff --git a/esp-radio/src/wifi/mod.rs b/esp-radio/src/wifi/mod.rs index 07bee868eb8..65d417bd612 100644 --- a/esp-radio/src/wifi/mod.rs +++ b/esp-radio/src/wifi/mod.rs @@ -1317,7 +1317,7 @@ pub(super) fn release(bit: u8) { /// Each interface mode (station, access point) is a singleton — only one /// instance of each can exist at a time. Create interfaces via /// [`Interface::station()`] or [`Interface::access_point()`] before or after -/// calling [`new()`]. Dropping the interface releases the singleton so it can +/// calling [`WifiController::new()`]. Dropping the interface releases the singleton so it can /// be created again. #[derive(Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1379,7 +1379,7 @@ impl Interface { /// /// ```rust,no_run /// # {before_snippet} - /// let _controller = esp_radio::wifi::new(peripherals.WIFI, Default::default())?; + /// let _controller = esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; /// /// let station = esp_radio::wifi::Interface::station(); /// let mac = station.mac_address(); @@ -2241,116 +2241,8 @@ impl ControllerConfig { } } -#[procmacros::doc_replace] -/// Create a Wi-Fi controller. The default initial configuration is -/// [Config::Station(StationConfig::default())]. -/// -/// Dropping the controller will deinitialize / stop Wi-Fi. -/// -/// Create [`Interface`]s separately via [`Interface::station()`] / -/// [`Interface::access_point()`]. ESP-NOW and sniffer instances are -/// available through the controller's [`WifiController::esp_now()`] and -/// [`WifiController::sniffer()`] methods. -/// -/// Make sure to **not** call this function while interrupts are disabled, or IEEE 802.15.4 is -/// currently in use. -/// -/// ## Example -/// -/// ```rust,no_run -/// # {before_snippet} -/// let controller = esp_radio::wifi::new(peripherals.WIFI, Default::default())?; -/// let sta = esp_radio::wifi::Interface::station(); -/// # {after_snippet} -/// ``` -pub fn new<'d>( - device: crate::hal::peripherals::WIFI<'d>, - config: ControllerConfig, -) -> Result, WifiError> { - let _guard = RadioRefGuard::new(); - - config.validate(); - - event::enable_wifi_events( - WifiEvent::StationStart - | WifiEvent::StationStop - | WifiEvent::StationConnected - | WifiEvent::StationDisconnected - | WifiEvent::AccessPointStart - | WifiEvent::AccessPointStop - | WifiEvent::AccessPointStationConnected - | WifiEvent::AccessPointStationDisconnected - | WifiEvent::ScanDone, - ); - - 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: crate::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: crate::sys::include::CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF as i32, - rx_mgmt_buf_num: crate::sys::include::CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF as i32, - cache_tx_buf_num: crate::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: crate::sys::include::WIFI_SOFTAP_BEACON_MAX_LEN as i32, - mgmt_sbuf_num: crate::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: crate::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, - }; - } - - DATA_QUEUE_RX_AP.with(|queue| queue.change_capacity(config.rx_queue_size))?; - DATA_QUEUE_RX_STA.with(|queue| queue.change_capacity(config.rx_queue_size))?; - - TX_QUEUE_SIZE.store(config.tx_queue_size, Ordering::Relaxed); - - crate::wifi::wifi_init(device)?; - - // At some point the "High-speed ADC" entropy source became available. - #[cfg(all(rng_trng_supported, feature = "unstable"))] - unsafe { - esp_hal::rng::TrngSource::increase_entropy_source_counter() - }; - - // Only create WifiController after we've enabled TRNG - otherwise returning an error from this - // function will cause panic because WifiController::drop tries to disable the TRNG. - let mut controller = WifiController { - _guard, - _phantom: Default::default(), - }; - - controller.set_country_info(&config.country_info)?; - // Set a sane default power saving mode. The blob default is not the best for bandwidth. - controller.set_power_saving(PowerSaveMode::default())?; - - controller.set_config(&config.initial_config)?; - - Ok(controller) -} - /// Wi-Fi controller. /// -/// Calling [new] starts the controller. -/// /// When the controller is dropped, the Wi-Fi driver is /// deinitialized and Wi-Fi is stopped. #[derive(Debug)] @@ -2378,6 +2270,115 @@ impl Drop for WifiController<'_> { } } +impl<'d> WifiController<'d> { + #[procmacros::doc_replace] + /// Create a Wi-Fi controller. The default initial configuration is + /// [`Config::Station`]`(`[`StationConfig::default()`]`)`. + /// + /// Dropping the controller will deinitialize / stop Wi-Fi. + /// + /// Create [`Interface`]s separately via [`Interface::station()`] / + /// [`Interface::access_point()`]. ESP-NOW and sniffer instances are + /// available through the controller's [`WifiController::esp_now()`] and + /// [`WifiController::sniffer()`] methods. + /// + /// Make sure to **not** call this function while interrupts are disabled, or IEEE 802.15.4 is + /// currently in use. + /// + /// ## Example + /// + /// ```rust,no_run + /// # {before_snippet} + /// let controller = esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; + /// let sta = esp_radio::wifi::Interface::station(); + /// # {after_snippet} + /// ``` + pub fn new( + device: crate::hal::peripherals::WIFI<'d>, + config: ControllerConfig, + ) -> Result { + let _guard = RadioRefGuard::new(); + + config.validate(); + + event::enable_wifi_events( + WifiEvent::StationStart + | WifiEvent::StationStop + | WifiEvent::StationConnected + | WifiEvent::StationDisconnected + | WifiEvent::AccessPointStart + | WifiEvent::AccessPointStop + | WifiEvent::AccessPointStationConnected + | WifiEvent::AccessPointStationDisconnected + | WifiEvent::ScanDone, + ); + + 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: crate::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: crate::sys::include::CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF as i32, + rx_mgmt_buf_num: crate::sys::include::CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF as i32, + cache_tx_buf_num: crate::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: crate::sys::include::WIFI_SOFTAP_BEACON_MAX_LEN as i32, + mgmt_sbuf_num: crate::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: crate::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, + }; + } + + DATA_QUEUE_RX_AP.with(|queue| queue.change_capacity(config.rx_queue_size))?; + DATA_QUEUE_RX_STA.with(|queue| queue.change_capacity(config.rx_queue_size))?; + + TX_QUEUE_SIZE.store(config.tx_queue_size, Ordering::Relaxed); + + crate::wifi::wifi_init(device)?; + + // At some point the "High-speed ADC" entropy source became available. + #[cfg(all(rng_trng_supported, feature = "unstable"))] + unsafe { + esp_hal::rng::TrngSource::increase_entropy_source_counter() + }; + + // Only create WifiController after we've enabled TRNG - otherwise returning an + // error from this function will cause panic because WifiController::drop tries + // to disable the TRNG. + let mut controller = WifiController { + _guard, + _phantom: Default::default(), + }; + + controller.set_country_info(&config.country_info)?; + // Set a sane default power saving mode. The blob default is not the best for bandwidth. + controller.set_power_saving(PowerSaveMode::default())?; + + controller.set_config(&config.initial_config)?; + + Ok(controller) + } +} + impl WifiController<'_> { /// Returns an ESP-NOW instance tied to this controller's lifetime. /// @@ -2435,7 +2436,8 @@ impl WifiController<'_> { /// let controller_config = ControllerConfig::default().with_initial_config(Config::AccessPoint( /// AccessPointConfig::default().with_ssid("esp-radio"), /// )); - /// let mut wifi_controller = esp_radio::wifi::new(peripherals.WIFI, controller_config)?; + /// let mut wifi_controller = + /// esp_radio::wifi::WifiController::new(peripherals.WIFI, controller_config)?; /// /// wifi_controller.set_protocols(Protocols::default()); /// # {after_snippet} @@ -2474,7 +2476,8 @@ impl WifiController<'_> { /// ```rust,no_run /// # {before_snippet} /// # use esp_radio::wifi::PowerSaveMode; - /// let mut controller = esp_radio::wifi::new(peripherals.WIFI, Default::default())?; + /// let mut controller = + /// esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; /// controller.set_power_saving(PowerSaveMode::Maximum)?; /// # {after_snippet} /// ``` @@ -2505,7 +2508,7 @@ impl WifiController<'_> { /// /// ```rust,no_run /// # {before_snippet} - /// # let controller = esp_radio::wifi::new(peripherals.WIFI, Default::default())?; + /// # let controller = esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; /// // Assume the station has already been started and connected /// match controller.rssi() { /// Ok(rssi) => { @@ -2546,7 +2549,7 @@ impl WifiController<'_> { /// /// ```rust,no_run /// # {before_snippet} - /// # let controller = esp_radio::wifi::new(peripherals.WIFI, Default::default())?; + /// # let controller = esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; /// // Assume the station has already been started and connected /// match controller.ap_info() { /// Ok(info) => { @@ -2595,7 +2598,7 @@ impl WifiController<'_> { /// # {before_snippet} /// # use esp_radio::wifi::{Config, sta::StationConfig}; /// # let mut controller = - /// # esp_radio::wifi::new(peripherals.WIFI, Default::default())?; + /// # esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; /// let station_config = Config::Station( /// StationConfig::default() /// .with_ssid("SSID") @@ -2823,7 +2826,7 @@ ignored." /// ```rust,no_run /// # {before_snippet} /// # use esp_radio::wifi::WifiError; - /// # let controller = esp_radio::wifi::new(peripherals.WIFI, Default::default())?; + /// # let controller = esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; /// if controller.is_connected() { /// println!("Station is connected"); /// } else { @@ -2853,7 +2856,7 @@ ignored." /// ```rust,no_run /// # {before_snippet} /// # use esp_radio::wifi::{WifiController, scan::ScanConfig}; - /// # let mut controller = esp_radio::wifi::new(peripherals.WIFI, Default::default())?; + /// # let mut controller = esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; /// // Create a scan configuration (e.g., scan up to 10 APs) /// let scan_config = ScanConfig::default().with_max(10); /// let result = controller.scan_async(&scan_config).await.unwrap(); @@ -2910,7 +2913,7 @@ ignored." /// # use esp_radio::wifi::{Config, sta::StationConfig}; /// /// # let mut controller = - /// # esp_radio::wifi::new(peripherals.WIFI, Default::default())?; + /// # esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; /// /// match controller.connect_async().await { /// Ok(_) => { @@ -2984,7 +2987,7 @@ ignored." /// # use esp_radio::wifi::{Config, sta::StationConfig}; /// /// # let mut controller = - /// # esp_radio::wifi::new(peripherals.WIFI, Default::default())?; + /// # esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default())?; /// match controller.disconnect_async().await { /// Ok(info) => { /// println!("Station disconnected successfully. {info:?}"); diff --git a/examples/esp-now/embassy_esp_now/src/main.rs b/examples/esp-now/embassy_esp_now/src/main.rs index add1de37eea..4acd7d5c277 100644 --- a/examples/esp-now/embassy_esp_now/src/main.rs +++ b/examples/esp-now/embassy_esp_now/src/main.rs @@ -33,7 +33,7 @@ async fn main(_spawner: Spawner) -> ! { esp_rtos::start(timg0.timer0, sw_int.software_interrupt0); let wifi = peripherals.WIFI; - let controller = esp_radio::wifi::new(wifi, Default::default()).unwrap(); + let controller = esp_radio::wifi::WifiController::new(wifi, Default::default()).unwrap(); let mut esp_now = controller.esp_now(); esp_now.set_channel(11).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 b6c1c4d059b..c9aa5ab4d67 100644 --- a/examples/esp-now/embassy_esp_now_duplex/src/main.rs +++ b/examples/esp-now/embassy_esp_now_duplex/src/main.rs @@ -52,7 +52,7 @@ async fn main(spawner: Spawner) -> ! { let wifi = peripherals.WIFI; let controller = mk_static!( esp_radio::wifi::WifiController<'static>, - esp_radio::wifi::new(wifi, Default::default()).unwrap() + esp_radio::wifi::WifiController::new(wifi, Default::default()).unwrap() ); let esp_now = controller.esp_now(); diff --git a/examples/wifi/80211_tx/src/main.rs b/examples/wifi/80211_tx/src/main.rs index 49473e24e5a..63ef3260a1d 100644 --- a/examples/wifi/80211_tx/src/main.rs +++ b/examples/wifi/80211_tx/src/main.rs @@ -50,7 +50,8 @@ async fn main(_spawner: embassy_executor::Spawner) -> ! { // The sniffer borrows the controller, so we only need the controller here — // no station/AP `Interface` is required for raw 802.11 transmit. - let controller = esp_radio::wifi::new(peripherals.WIFI, Default::default()).unwrap(); + let controller = + esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default()).unwrap(); let mut sniffer = controller.sniffer(); diff --git a/examples/wifi/embassy_access_point/src/main.rs b/examples/wifi/embassy_access_point/src/main.rs index ec85927a690..3bd4d691fba 100644 --- a/examples/wifi/embassy_access_point/src/main.rs +++ b/examples/wifi/embassy_access_point/src/main.rs @@ -67,7 +67,7 @@ async fn main(spawner: Spawner) -> ! { println!("Starting wifi"); let device = esp_radio::wifi::Interface::access_point(); - let controller = esp_radio::wifi::new( + let controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(access_point_config), ) 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 ec83aefcb4f..21f782c292e 100644 --- a/examples/wifi/embassy_access_point_with_sta/src/main.rs +++ b/examples/wifi/embassy_access_point_with_sta/src/main.rs @@ -97,7 +97,7 @@ async fn main(spawner: Spawner) -> ! { println!("Starting wifi"); let wifi_ap_device = esp_radio::wifi::Interface::access_point(); let wifi_sta_device = esp_radio::wifi::Interface::station(); - let controller = esp_radio::wifi::new( + let controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(access_point_station_config), ) diff --git a/examples/wifi/embassy_coex/src/main.rs b/examples/wifi/embassy_coex/src/main.rs index cf4d08b22e8..e03f4a68a3b 100644 --- a/examples/wifi/embassy_coex/src/main.rs +++ b/examples/wifi/embassy_coex/src/main.rs @@ -115,7 +115,7 @@ async fn main(spawner: Spawner) -> ! { println!("Starting wifi"); let wifi_interface = esp_radio::wifi::Interface::station(); - let mut controller = esp_radio::wifi::new( + let mut controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(station_config), ) diff --git a/examples/wifi/embassy_dhcp/src/main.rs b/examples/wifi/embassy_dhcp/src/main.rs index 7a5eb0270e5..167e9574652 100644 --- a/examples/wifi/embassy_dhcp/src/main.rs +++ b/examples/wifi/embassy_dhcp/src/main.rs @@ -98,7 +98,7 @@ async fn main(spawner: Spawner) -> ! { println!("Starting wifi"); let wifi_interface = esp_radio::wifi::Interface::station(); - let mut controller = esp_radio::wifi::new( + let mut controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(station_config), ) diff --git a/examples/wifi/embassy_sntp/src/main.rs b/examples/wifi/embassy_sntp/src/main.rs index e8898ea3cf7..8ff676f4431 100644 --- a/examples/wifi/embassy_sntp/src/main.rs +++ b/examples/wifi/embassy_sntp/src/main.rs @@ -103,7 +103,7 @@ async fn main(spawner: Spawner) -> ! { println!("Starting wifi"); let wifi_interface = esp_radio::wifi::Interface::station(); - let mut controller = esp_radio::wifi::new( + let mut controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(station_config), ) diff --git a/examples/wifi/sniffer/src/main.rs b/examples/wifi/sniffer/src/main.rs index 172b6cfc828..633582735b4 100644 --- a/examples/wifi/sniffer/src/main.rs +++ b/examples/wifi/sniffer/src/main.rs @@ -41,7 +41,8 @@ async fn main(_spawner: embassy_executor::Spawner) -> ! { // The sniffer borrows the controller, so we only need the controller here — // no station/AP `Interface` is required for promiscuous capture. - let controller = esp_radio::wifi::new(peripherals.WIFI, Default::default()).unwrap(); + let controller = + esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default()).unwrap(); let mut sniffer = controller.sniffer(); sniffer.set_promiscuous_mode(true).unwrap(); diff --git a/hil-test/src/bin/esp_radio/init_tests.rs b/hil-test/src/bin/esp_radio/init_tests.rs index 88dfc3bbe0e..171490a3556 100644 --- a/hil-test/src/bin/esp_radio/init_tests.rs +++ b/hil-test/src/bin/esp_radio/init_tests.rs @@ -28,7 +28,7 @@ mod init_tests { signal: &'static Signal>, wifi_peripheral: WIFI<'static>, ) { - match esp_radio::wifi::new(wifi_peripheral, Default::default()) { + match esp_radio::wifi::WifiController::new(wifi_peripheral, Default::default()) { Ok(_) => signal.signal(None), Err(err) => signal.signal(Some(err)), } @@ -50,7 +50,7 @@ mod init_tests { #[cfg(soc_has_wifi)] fn test_init_fails_without_scheduler(p: Peripherals) { // esp-rtos must be initialized before esp-radio. - let _ = esp_radio::wifi::new(p.WIFI, Default::default()); + let _ = esp_radio::wifi::WifiController::new(p.WIFI, Default::default()); } #[test] @@ -61,7 +61,9 @@ mod init_tests { let sw_ints = SoftwareInterruptControl::new(p.SW_INTERRUPT); esp_rtos::start(timg0.timer0, sw_ints.software_interrupt0); - let _ = critical_section::with(|_| esp_radio::wifi::new(p.WIFI, Default::default())); + let _ = critical_section::with(|_| { + esp_radio::wifi::WifiController::new(p.WIFI, Default::default()) + }); } #[test] @@ -72,7 +74,7 @@ mod init_tests { let sw_ints = SoftwareInterruptControl::new(p.SW_INTERRUPT); esp_rtos::start(timg0.timer0, sw_ints.software_interrupt0); - let _ = interrupt_free(|| esp_radio::wifi::new(p.WIFI, Default::default())); + let _ = interrupt_free(|| esp_radio::wifi::WifiController::new(p.WIFI, Default::default())); } #[test] @@ -105,11 +107,13 @@ mod init_tests { esp_rtos::start(timg0.timer0, sw_ints.software_interrupt0); // Initialize, then de-initialize wifi - let wifi = esp_radio::wifi::new(p.WIFI.reborrow(), Default::default()).unwrap(); + let wifi = + esp_radio::wifi::WifiController::new(p.WIFI.reborrow(), Default::default()).unwrap(); drop(wifi); // Now, can we do it again? - let _wifi = esp_radio::wifi::new(p.WIFI.reborrow(), Default::default()).unwrap(); + let _wifi = + esp_radio::wifi::WifiController::new(p.WIFI.reborrow(), Default::default()).unwrap(); } #[test] @@ -122,7 +126,8 @@ mod init_tests { // Initialize BLE and WiFi then drop BLE let connector = BleConnector::new(p.BT.reborrow(), Default::default()).unwrap(); - let wifi = esp_radio::wifi::new(p.WIFI.reborrow(), Default::default()).unwrap(); + let wifi = + esp_radio::wifi::WifiController::new(p.WIFI.reborrow(), Default::default()).unwrap(); drop(connector); // Re-initialize BLE and drop WiFi and BLE @@ -140,14 +145,16 @@ mod init_tests { esp_rtos::start(timg0.timer0, sw_ints.software_interrupt0); // Initialize WiFi and BLE then drop BLE and WiFi - let wifi = esp_radio::wifi::new(p.WIFI.reborrow(), Default::default()).unwrap(); + let wifi = + esp_radio::wifi::WifiController::new(p.WIFI.reborrow(), Default::default()).unwrap(); let connector = BleConnector::new(p.BT.reborrow(), Default::default()).unwrap(); drop(connector); drop(wifi); // Re-initialize WiFi and BLE then drop WiFi - let wifi = esp_radio::wifi::new(p.WIFI.reborrow(), Default::default()).unwrap(); + let wifi = + esp_radio::wifi::WifiController::new(p.WIFI.reborrow(), Default::default()).unwrap(); let _connector = BleConnector::new(p.BT.reborrow(), Default::default()).unwrap(); drop(wifi); diff --git a/hil-test/src/bin/esp_radio/wifi_controller.rs b/hil-test/src/bin/esp_radio/wifi_controller.rs index d467ec8c498..fe261e9e9b3 100644 --- a/hil-test/src/bin/esp_radio/wifi_controller.rs +++ b/hil-test/src/bin/esp_radio/wifi_controller.rs @@ -26,7 +26,7 @@ mod tests { let _source = esp_hal::rng::TrngSource::new(p.RNG, p.ADC1); - let _controller = esp_radio::wifi::new(p.WIFI, Default::default()).unwrap(); + let _controller = esp_radio::wifi::WifiController::new(p.WIFI, Default::default()).unwrap(); } // If this turns out to be too flaky or time-consuming, @@ -38,7 +38,8 @@ mod tests { let sw_ints = SoftwareInterruptControl::new(p.SW_INTERRUPT); esp_rtos::start(timg0.timer0, sw_ints.software_interrupt0); - let mut controller = esp_radio::wifi::new(p.WIFI, Default::default()).unwrap(); + let mut controller = + esp_radio::wifi::WifiController::new(p.WIFI, Default::default()).unwrap(); // scanning all channels takes a (too) long time - even more for dual-band capable targets let scan_config = ScanConfig::default().with_max(1).with_channel(13); diff --git a/qa-test/src/bin/embassy_scan_after_sleep.rs b/qa-test/src/bin/embassy_scan_after_sleep.rs index 9cc391b8b5e..e743cf3b4dc 100644 --- a/qa-test/src/bin/embassy_scan_after_sleep.rs +++ b/qa-test/src/bin/embassy_scan_after_sleep.rs @@ -50,7 +50,8 @@ async fn main(_spawner: Spawner) { esp_println::println!("Done sleeping"); // WiFi - let mut controller = esp_radio::wifi::new(peripherals.WIFI, Default::default()).unwrap(); + let mut controller = + esp_radio::wifi::WifiController::new(peripherals.WIFI, Default::default()).unwrap(); let res = controller .scan_async(&esp_radio::wifi::scan::ScanConfig::default()) diff --git a/qa-test/src/bin/embassy_wifi_bench.rs b/qa-test/src/bin/embassy_wifi_bench.rs index 259293b2edf..b7a7ec4b4fb 100644 --- a/qa-test/src/bin/embassy_wifi_bench.rs +++ b/qa-test/src/bin/embassy_wifi_bench.rs @@ -86,7 +86,7 @@ async fn main(spawner: Spawner) -> ! { println!("Starting wifi"); let wifi_interface = esp_radio::wifi::Interface::station(); - let mut controller = esp_radio::wifi::new( + let mut controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(station_config), ) diff --git a/qa-test/src/bin/embassy_wifi_csi.rs b/qa-test/src/bin/embassy_wifi_csi.rs index 1de242aeba5..ac5b88adb03 100644 --- a/qa-test/src/bin/embassy_wifi_csi.rs +++ b/qa-test/src/bin/embassy_wifi_csi.rs @@ -67,7 +67,7 @@ async fn main(spawner: Spawner) -> ! { println!("Starting wifi"); let wifi_interface = esp_radio::wifi::Interface::station(); - let mut controller = esp_radio::wifi::new( + let mut controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(station_config), ) diff --git a/qa-test/src/bin/embassy_wifi_drop.rs b/qa-test/src/bin/embassy_wifi_drop.rs index 35ffda12b6b..9a8e93a4684 100644 --- a/qa-test/src/bin/embassy_wifi_drop.rs +++ b/qa-test/src/bin/embassy_wifi_drop.rs @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) { ); let mut wifi_interface = esp_radio::wifi::Interface::station(); - let mut controller = esp_radio::wifi::new( + let mut controller = esp_radio::wifi::WifiController::new( wifi.reborrow(), ControllerConfig::default().with_initial_config(station_config), ) @@ -82,7 +82,7 @@ async fn main(_spawner: Spawner) { ); let mut wifi_interface = esp_radio::wifi::Interface::station(); - let mut controller = esp_radio::wifi::new( + let mut controller = esp_radio::wifi::WifiController::new( wifi.reborrow(), ControllerConfig::default().with_initial_config(station_config), ) diff --git a/qa-test/src/bin/embassy_wifi_i2s.rs b/qa-test/src/bin/embassy_wifi_i2s.rs index ce521a6c1aa..dc048367e68 100644 --- a/qa-test/src/bin/embassy_wifi_i2s.rs +++ b/qa-test/src/bin/embassy_wifi_i2s.rs @@ -208,7 +208,7 @@ async fn main(spawner: Spawner) { println!("Starting wifi"); let wifi_interface = esp_radio::wifi::Interface::station(); - let controller = esp_radio::wifi::new( + let controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(station_config), ) diff --git a/qa-test/src/bin/embassy_wifi_stress.rs b/qa-test/src/bin/embassy_wifi_stress.rs index 2765c43e716..0bd5220dcb8 100644 --- a/qa-test/src/bin/embassy_wifi_stress.rs +++ b/qa-test/src/bin/embassy_wifi_stress.rs @@ -61,7 +61,8 @@ async fn main(_spawner: Spawner) { println!("Wifi stack setup (STA)"); let mut controller = - esp_radio::wifi::new(peripherals.WIFI.reborrow(), Default::default()).unwrap(); + esp_radio::wifi::WifiController::new(peripherals.WIFI.reborrow(), Default::default()) + .unwrap(); { println!("Connecting to WiFi SSID: {}", SSID); diff --git a/qa-test/src/bin/wifi_survives_ble_drop.rs b/qa-test/src/bin/wifi_survives_ble_drop.rs index bb892af504d..31426b66230 100644 --- a/qa-test/src/bin/wifi_survives_ble_drop.rs +++ b/qa-test/src/bin/wifi_survives_ble_drop.rs @@ -85,7 +85,7 @@ async fn main(spawner: Spawner) -> ! { println!("Starting wifi"); let wifi_interface = esp_radio::wifi::Interface::station(); - let mut controller = esp_radio::wifi::new( + let mut controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(station_config), ) diff --git a/qa-test/src/bin/wifi_syslog.rs b/qa-test/src/bin/wifi_syslog.rs index 43abbe150d4..cce6af82d6b 100644 --- a/qa-test/src/bin/wifi_syslog.rs +++ b/qa-test/src/bin/wifi_syslog.rs @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) { println!("Creating wifi controller with print-logs-from-driver enabled"); - let mut controller = esp_radio::wifi::new( + let mut controller = esp_radio::wifi::WifiController::new( peripherals.WIFI, ControllerConfig::default().with_initial_config(station_config), ) From cb60e47d975af9682953e9b3fb16c58814a4049b Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Tue, 26 May 2026 16:21:16 +0100 Subject: [PATCH 4/6] rework lib.rs docs --- esp-radio/src/lib.rs | 77 ++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/esp-radio/src/lib.rs b/esp-radio/src/lib.rs index 678cc920a0e..7db8708cba4 100644 --- a/esp-radio/src/lib.rs +++ b/esp-radio/src/lib.rs @@ -6,27 +6,31 @@ //! //! This documentation is built for the #![doc = concat!("**", chip_pretty!(), "**")] -//! . Please ensure you are reading the correct [documentation](https://docs.espressif.com/projects/rust/esp-radio/latest/) for your target +//! . Please ensure you are reading the correct [documentation] for your target //! device. //! -//! ## Usage +//! ## Overview //! -//! ### Importing +//! esp-radio provides Wi-Fi, Bluetooth Low Energy (BLE), ESP-NOW and IEEE +//! 802.15.4 drivers for Espressif microcontrollers. It builds on top of +//! [esp-hal] and the vendor binary blobs to provide wireless connectivity in a +//! `no_std` environment. //! -//! Enabling the `unstable` feature on `esp-radio` requires you to also enable -//! the `unstable` feature on `esp-hal` in the final binary crate. -//! -//! Ensure that the right features are enabled for your chip. See [Examples](https://github.com/esp-rs/esp-hal/tree/main/examples#examples) for more examples. -//! -//! You will also need a dynamic memory allocator, and a preemptive task scheduler in your -//! application. For the dynamic allocator, we recommend using `esp-alloc`. For the task scheduler, -//! the simplest option that is supported by us is `esp-rtos`, but you may use Ariel -//! OS or other operating systems as well. +//! Wi-Fi and BLE require a dynamic memory allocator and a preemptive task +//! scheduler at runtime. We recommend [`esp-alloc`] and [`esp-rtos`] for this, +//! though any allocator or RTOS (such as Ariel OS) that implements the required +//! interfaces will work. #![cfg_attr( feature = "ieee802154", - doc = "
Hint: The scheduler is not required for the 802.15.4.
" + doc = "
Hint: The scheduler is not required for IEEE 802.15.4.
" )] -#![doc = ""] +//! Drivers that don't currently have a stable API are marked as `unstable` in +//! the documentation. Enabling the `unstable` feature on `esp-radio` requires +//! you to also enable the `unstable` feature on `esp-hal` in the final binary +//! crate. +//! +//! ### Quick start +//! //! ```rust, no_run #![doc = esp_hal::before_snippet!()] //! use esp_hal::interrupt::software::SoftwareInterruptControl; @@ -72,26 +76,43 @@ if let Ok(controller) = BleConnector::new(peripherals.BT, Default::default()) {} #![doc = concat!(r#"features = [""#, chip!(), r#""]"#)] //! ``` //! -//! ### Optimization Level +//! ## Examples //! -//! It is necessary to build with optimization level 2 or 3 since otherwise, it -//! might not even be able to connect or advertise. +//! We have a number of [examples] in the esp-hal repository. We use +//! an [xtask] to automate the building, running, and testing of code and +//! examples within esp-hal. //! -//! To make it work also for your debug builds add this to your `Cargo.toml` +//! Invoke the following command in the root of the esp-hal repository to get +//! started: +//! ```bash +//! cargo xtask help +//! ``` +//! +//! We have a [book] that explains the full esp-hal ecosystem +//! and how to get started, and a [training] that covers some common +//! scenarios with examples. +//! +//! ## Optimization level +//! +//! The radio blobs require optimization level 2 or 3 to function correctly. +//! Without it, Wi-Fi may fail to connect and BLE may fail to advertise. +//! +//! To apply this only to esp-radio in debug builds, add to your `Cargo.toml`: //! ```toml //! [profile.dev.package.esp-radio] //! opt-level = 3 //! ``` -//! ## Globally disable logging +//! +//! ## Disabling logging //! -//! `esp-radio` contains a lot of trace-level logging statements. -//! For maximum performance you might want to disable logging via -//! a feature flag of the `log` crate. See [documentation](https://docs.rs/log/0.4.19/log/#compile-time-filters). -//! You should set it to `release_max_level_off`. +//! `esp-radio` contains trace-level logging statements that may impact +//! performance. To disable them, use the `log` crate's compile-time +//! [filters](https://docs.rs/log/latest/log/#compile-time-filters) and set +//! `release_max_level_off`. #![cfg_attr( multi_core, doc = concat!( - "### Running on the Second Core", + "## Running on the second core", "\n\n", "BLE and Wi-Fi can also be run on the second core.", "\n\n", @@ -122,6 +143,14 @@ if let Ok(controller) = BleConnector::new(peripherals.BT, Default::default()) {} //! for this crate: #![doc = ""] #![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_radio_config_table.md"))] +//! [documentation]: https://docs.espressif.com/projects/rust/esp-radio/latest/ +//! [esp-hal]: https://docs.espressif.com/projects/rust/esp-hal/latest/ +//! [`esp-alloc`]: https://docs.espressif.com/projects/rust/esp-alloc/latest/ +//! [`esp-rtos`]: https://docs.espressif.com/projects/rust/esp-rtos/latest/ +//! [examples]: https://github.com/esp-rs/esp-hal/tree/main/examples +//! [xtask]: https://github.com/matklad/cargo-xtask +//! [book]: https://docs.espressif.com/projects/rust/book/ +//! [training]: https://docs.espressif.com/projects/rust/no_std-training/ #![doc(html_logo_url = "https://docs.espressif.com/projects/rust/esp-rs-grey-bg.svg")] #![no_std] #![cfg_attr(xtensa, feature(asm_experimental_arch))] From bd6aafac8f852e18557533fbc10206f872d54c82 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Tue, 26 May 2026 16:48:06 +0100 Subject: [PATCH 5/6] drop ap/sta prefixes from some structs --- esp-radio/src/wifi/ap.rs | 12 ++-- esp-radio/src/wifi/mod.rs | 55 ++++++++----------- esp-radio/src/wifi/sta/mod.rs | 4 +- .../wifi/embassy_access_point/src/main.rs | 18 ++---- .../embassy_access_point_with_sta/src/main.rs | 18 ++---- 5 files changed, 38 insertions(+), 69 deletions(-) diff --git a/esp-radio/src/wifi/ap.rs b/esp-radio/src/wifi/ap.rs index 4b149d4da09..711fcf21b1a 100644 --- a/esp-radio/src/wifi/ap.rs +++ b/esp-radio/src/wifi/ap.rs @@ -155,7 +155,7 @@ impl defmt::Format for AccessPointConfig { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] -pub struct AccessPointStationConnectedInfo { +pub struct ConnectedInfo { /// The MAC address. pub mac: [u8; 6], /// The Association ID (AID) of the connected station. @@ -168,7 +168,7 @@ pub struct AccessPointStationConnectedInfo { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] -pub struct AccessPointStationDisconnectedInfo { +pub struct DisconnectedInfo { /// The MAC address. pub mac: [u8; 6], /// The Association ID (AID) of the connected station. @@ -179,14 +179,14 @@ pub struct AccessPointStationDisconnectedInfo { pub reason: DisconnectReason, } -/// Either the [AccessPointStationConnectedInfo] or [AccessPointStationDisconnectedInfo]. +/// Either the [ConnectedInfo] or [DisconnectedInfo]. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum AccessPointStationEventInfo { +pub enum EventInfo { /// Information about a station connected to the access point. - Connected(AccessPointStationConnectedInfo), + Connected(ConnectedInfo), /// Information about a station disconnected from the access point. - Disconnected(AccessPointStationDisconnectedInfo), + Disconnected(DisconnectedInfo), } #[allow(non_upper_case_globals)] diff --git a/esp-radio/src/wifi/mod.rs b/esp-radio/src/wifi/mod.rs index 65d417bd612..e071cbb9268 100644 --- a/esp-radio/src/wifi/mod.rs +++ b/esp-radio/src/wifi/mod.rs @@ -65,17 +65,10 @@ use self::sniffer::Sniffer; #[cfg(feature = "wifi-eap")] use self::sta::eap::EapStationConfig; use self::{ - ap::{ - AccessPointConfig, - AccessPointInfo, - AccessPointStationConnectedInfo, - AccessPointStationDisconnectedInfo, - AccessPointStationEventInfo, - convert_ap_info, - }, + ap::{AccessPointConfig, AccessPointInfo, convert_ap_info}, private::PacketBuffer, scan::{FreeApListOnDrop, ScanConfig, ScanResults, ScanTypeConfig}, - sta::{ConnectedStationInfo, DisconnectedStationInfo, StationConfig}, + sta::StationConfig, state::*, }; use crate::{ @@ -879,7 +872,7 @@ static DATA_QUEUE_RX_STA: NonReentrantMutex = #[non_exhaustive] pub enum WifiError { /// The device disconnected from the network or failed to connect to it. - Disconnected(DisconnectedStationInfo), + Disconnected(sta::DisconnectedInfo), /// Unsupported operation or mode. Unsupported, @@ -2924,7 +2917,7 @@ ignored." /// } /// } /// # {after_snippet} - pub async fn connect_async(&mut self) -> Result { + pub async fn connect_async(&mut self) -> Result { let mut subscriber = EVENT_CHANNEL .subscriber() .expect("Unable to subscribe to events - consider increasing the internal event channel subscriber count"); @@ -2953,7 +2946,7 @@ ignored." channel, authmode, aid, - } => Ok(ConnectedStationInfo { + } => Ok(sta::ConnectedInfo { ssid, bssid, channel, @@ -2965,7 +2958,7 @@ ignored." bssid, reason, rssi, - } => Err(WifiError::Disconnected(DisconnectedStationInfo { + } => Err(WifiError::Disconnected(sta::DisconnectedInfo { ssid, bssid, reason: DisconnectReason::from_raw(reason), @@ -2997,7 +2990,7 @@ ignored." /// } /// } /// # {after_snippet} - pub async fn disconnect_async(&mut self) -> Result { + pub async fn disconnect_async(&mut self) -> Result { // If not connected it would wait forever for a `StationDisconnected` event that will never // happen. Return early instead of hanging. if !self.is_connected() { @@ -3020,7 +3013,7 @@ ignored." rssi, } = event { - break Ok(DisconnectedStationInfo { + break Ok(sta::DisconnectedInfo { ssid, bssid, reason: DisconnectReason::from_raw(reason), @@ -3031,7 +3024,7 @@ ignored." } /// Wait until the station gets disconnected from the AP. - pub async fn wait_for_disconnect_async(&self) -> Result { + pub async fn wait_for_disconnect_async(&self) -> Result { // If not connected it would wait forever for a `StationDisconnected` event that will never // happen. Return early instead of hanging. if !self.is_connected() { @@ -3052,7 +3045,7 @@ ignored." rssi, } = event { - break Ok(DisconnectedStationInfo { + break Ok(sta::DisconnectedInfo { ssid, bssid, reason: DisconnectReason::from_raw(reason), @@ -3065,7 +3058,7 @@ ignored." /// Wait for connected / disconnected events. pub async fn wait_for_access_point_connected_event_async( &self, - ) -> Result { + ) -> Result { let mut subscriber = EVENT_CHANNEL .subscriber() .expect("Unable to subscribe to events - consider increasing the internal event channel subscriber count"); @@ -3079,13 +3072,11 @@ ignored." aid, is_mesh_child, } => { - break Ok(AccessPointStationEventInfo::Connected( - AccessPointStationConnectedInfo { - mac, - aid, - is_mesh_child, - }, - )); + break Ok(ap::EventInfo::Connected(ap::ConnectedInfo { + mac, + aid, + is_mesh_child, + })); } event::EventInfo::AccessPointStationDisconnected { mac, @@ -3093,14 +3084,12 @@ ignored." is_mesh_child, reason, } => { - break Ok(AccessPointStationEventInfo::Disconnected( - AccessPointStationDisconnectedInfo { - mac, - aid: aid as u16, - is_mesh_child, - reason: DisconnectReason::from_raw(reason), - }, - )); + break Ok(ap::EventInfo::Disconnected(ap::DisconnectedInfo { + mac, + aid: aid as u16, + is_mesh_child, + reason: DisconnectReason::from_raw(reason), + })); } _ => (), } diff --git a/esp-radio/src/wifi/sta/mod.rs b/esp-radio/src/wifi/sta/mod.rs index 9a2ad54c3c8..d93ed326cea 100644 --- a/esp-radio/src/wifi/sta/mod.rs +++ b/esp-radio/src/wifi/sta/mod.rs @@ -161,7 +161,7 @@ impl defmt::Format for StationConfig { #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] -pub struct ConnectedStationInfo { +pub struct ConnectedInfo { /// The SSID of the connected station. pub ssid: Ssid, /// The BSSID of the connected station. @@ -178,7 +178,7 @@ pub struct ConnectedStationInfo { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] -pub struct DisconnectedStationInfo { +pub struct DisconnectedInfo { /// The SSID of the disconnected station. pub ssid: Ssid, /// The BSSID of the disconnected station. diff --git a/examples/wifi/embassy_access_point/src/main.rs b/examples/wifi/embassy_access_point/src/main.rs index 3bd4d691fba..b77903b98ca 100644 --- a/examples/wifi/embassy_access_point/src/main.rs +++ b/examples/wifi/embassy_access_point/src/main.rs @@ -234,21 +234,11 @@ async fn connection(controller: WifiController<'static>) { .wait_for_access_point_connected_event_async() .await; match ev { - Ok(esp_radio::wifi::ap::AccessPointStationEventInfo::Connected( - access_point_station_connected_info, - )) => { - println!( - "Station connected: {:?}", - access_point_station_connected_info - ); + Ok(esp_radio::wifi::ap::EventInfo::Connected(info)) => { + println!("Station connected: {:?}", info); } - Ok(esp_radio::wifi::ap::AccessPointStationEventInfo::Disconnected( - access_point_station_disconnected_info, - )) => { - println!( - "Station disconnected: {:?}", - access_point_station_disconnected_info - ); + Ok(esp_radio::wifi::ap::EventInfo::Disconnected(info)) => { + println!("Station disconnected: {:?}", info); } _ => (), } 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 21f782c292e..6e3d44067b3 100644 --- a/examples/wifi/embassy_access_point_with_sta/src/main.rs +++ b/examples/wifi/embassy_access_point_with_sta/src/main.rs @@ -346,21 +346,11 @@ async fn connection(mut controller: WifiController<'static>) { Either::Second(event) => { if let Ok(event) = event { match event { - esp_radio::wifi::ap::AccessPointStationEventInfo::Connected( - access_point_station_connected_info, - ) => { - println!( - "Station connected: {:?}", - access_point_station_connected_info - ); + esp_radio::wifi::ap::EventInfo::Connected(info) => { + println!("Station connected: {:?}", info); } - esp_radio::wifi::ap::AccessPointStationEventInfo::Disconnected( - access_point_station_disconnected_info, - ) => { - println!( - "Station disconnected: {:?}", - access_point_station_disconnected_info - ); + esp_radio::wifi::ap::EventInfo::Disconnected(info) => { + println!("Station disconnected: {:?}", info); } } } From 3a1cba87e42614579a23b24d40be53dc97753fcb Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Tue, 26 May 2026 16:55:21 +0100 Subject: [PATCH 6/6] fixup docs --- esp-radio/src/lib.rs | 17 +++++++++-------- esp-radio/src/wifi/sta/mod.rs | 18 +++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/esp-radio/src/lib.rs b/esp-radio/src/lib.rs index 7db8708cba4..8fd65d61e1b 100644 --- a/esp-radio/src/lib.rs +++ b/esp-radio/src/lib.rs @@ -109,6 +109,15 @@ if let Ok(controller) = BleConnector::new(peripherals.BT, Default::default()) {} //! performance. To disable them, use the `log` crate's compile-time //! [filters](https://docs.rs/log/latest/log/#compile-time-filters) and set //! `release_max_level_off`. +//! +//! [documentation]: https://docs.espressif.com/projects/rust/esp-radio/latest/ +//! [esp-hal]: https://docs.espressif.com/projects/rust/esp-hal/latest/ +//! [`esp-alloc`]: https://docs.espressif.com/projects/rust/esp-alloc/latest/ +//! [`esp-rtos`]: https://docs.espressif.com/projects/rust/esp-rtos/latest/ +//! [examples]: https://github.com/esp-rs/esp-hal/tree/main/examples +//! [xtask]: https://github.com/matklad/cargo-xtask +//! [book]: https://docs.espressif.com/projects/rust/book/ +//! [training]: https://docs.espressif.com/projects/rust/no_std-training/ #![cfg_attr( multi_core, doc = concat!( @@ -143,14 +152,6 @@ if let Ok(controller) = BleConnector::new(peripherals.BT, Default::default()) {} //! for this crate: #![doc = ""] #![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_radio_config_table.md"))] -//! [documentation]: https://docs.espressif.com/projects/rust/esp-radio/latest/ -//! [esp-hal]: https://docs.espressif.com/projects/rust/esp-hal/latest/ -//! [`esp-alloc`]: https://docs.espressif.com/projects/rust/esp-alloc/latest/ -//! [`esp-rtos`]: https://docs.espressif.com/projects/rust/esp-rtos/latest/ -//! [examples]: https://github.com/esp-rs/esp-hal/tree/main/examples -//! [xtask]: https://github.com/matklad/cargo-xtask -//! [book]: https://docs.espressif.com/projects/rust/book/ -//! [training]: https://docs.espressif.com/projects/rust/no_std-training/ #![doc(html_logo_url = "https://docs.espressif.com/projects/rust/esp-rs-grey-bg.svg")] #![no_std] #![cfg_attr(xtensa, feature(asm_experimental_arch))] diff --git a/esp-radio/src/wifi/sta/mod.rs b/esp-radio/src/wifi/sta/mod.rs index d93ed326cea..d5ede924798 100644 --- a/esp-radio/src/wifi/sta/mod.rs +++ b/esp-radio/src/wifi/sta/mod.rs @@ -157,31 +157,31 @@ impl defmt::Format for StationConfig { } } -/// Information about a connected station. +/// Information about the access point the station connected to. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub struct ConnectedInfo { - /// The SSID of the connected station. + /// The SSID of the access point. pub ssid: Ssid, - /// The BSSID of the connected station. + /// The BSSID of the access point. pub bssid: [u8; 6], - /// The channel of the connected station. + /// The channel of the access point. pub channel: u8, - /// The authmode of the connected station. + /// The authentication method used. pub authmode: AuthenticationMethod, - /// The Association ID (AID) of the connected station. + /// The Association ID (AID) assigned by the access point. pub aid: u16, } -/// Information about a disconnected station. +/// Information about the access point the station disconnected from. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub struct DisconnectedInfo { - /// The SSID of the disconnected station. + /// The SSID of the access point. pub ssid: Ssid, - /// The BSSID of the disconnected station. + /// The BSSID of the access point. pub bssid: [u8; 6], /// The disconnect reason. pub reason: DisconnectReason,