diff --git a/esp-radio/CHANGELOG.md b/esp-radio/CHANGELOG.md index 3339beb8d..9110fa59c 100644 --- a/esp-radio/CHANGELOG.md +++ b/esp-radio/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `AccessPointInfo::country` to access the Country Code from the Wi-Fi scan results (#3837) - +- `unstable` feature to opt into `ble`, `esp-now`, `csi`, `sniffer`, `esp-ieee802154` and `smoltcp` APIs (#3865) ### Changed @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `EspWifi` prefix from structs in the package codebase. (#3869) - Rename `esp-wifi` to `esp-radio`. (#3858) - `esp-ieee802154` package has been folded into `esp-radio`. (#3861) +- `ble`, `esp-now`, `csi`, `sniffer`, `esp-ieee802154` and `smoltcp` features and APIs marked as unstable (#3865) ### Fixed diff --git a/esp-radio/Cargo.toml b/esp-radio/Cargo.toml index ca2683505..5a53a0351 100644 --- a/esp-radio/Cargo.toml +++ b/esp-radio/Cargo.toml @@ -25,8 +25,8 @@ enumset = { version = "1.1.6", default-features = false, optional = true } embedded-io = { version = "0.6.1", default-features = false } embedded-io-async = { version = "0.6.1" } esp-radio-preempt-driver = { version = "0.0.1", path = "../esp-radio-preempt-driver" } -rand_core = "0.9.3" heapless = "0.8.0" +instability = "0.3.9" # Unstable dependencies that are not (strictly) part of the public API allocator-api2 = { version = "0.3.0", default-features = false, features = ["alloc"] } @@ -158,6 +158,17 @@ log-04 = ["dep:log-04", "esp-hal/log-04", "esp-wifi-sys/log"] ## Enable logging output using `defmt` and implement `defmt::Format` on certain types. defmt = ["dep:defmt", "smoltcp?/defmt", "esp-hal/defmt", "bt-hci?/defmt", "esp-wifi-sys/defmt", "enumset/defmt"] +#! ### Unstable APIs +#! Unstable APIs are drivers and features that are not yet ready for general use. +#! They may be incomplete, have bugs, or be subject to change without notice. +unstable = [] + +## Libraries that depend on `esp-radio` should enable this feature to indicate their use of unstable APIs. +## However, they must **not** enable the `unstable` feature themselves. +## +## For development you can enable the `unstable` and the chip feature by adding esp-radio as a dev-dependency. +requires-unstable = [] + [package.metadata.docs.rs] features = [ "esp32c3", diff --git a/esp-radio/build.rs b/esp-radio/build.rs index 2e98d490f..2fed5b06a 100644 --- a/esp-radio/build.rs +++ b/esp-radio/build.rs @@ -21,6 +21,27 @@ fn main() -> Result<(), Box> { // Define all necessary configuration symbols for the configured device: chip.define_cfgs(); + // If some library required unstable make sure unstable is actually enabled. + if cfg!(feature = "requires-unstable") && !cfg!(feature = "unstable") { + panic!( + "\n\nThe `unstable` feature is required by a dependent crate but is not enabled.\n\n" + ); + } + + if (cfg!(feature = "ble") + || cfg!(feature = "coex") + || cfg!(feature = "csi") + || cfg!(feature = "esp-now") + || cfg!(feature = "ieee802154") + || cfg!(feature = "smoltcp") + || cfg!(feature = "sniffer")) + && !cfg!(feature = "unstable") + { + panic!( + "\n\nThe `unstable` feature was not provided, but is required for the following features: `ble`, `coex`, `csi`, `esp-now`, `ieee802154`, `smoltcp`, `sniffer`.\n\n" + ) + } + // Log and defmt are mutually exclusive features. The main technical reason is // that allowing both would make the exact panicking behaviour a fragile // implementation detail. diff --git a/esp-radio/src/ble/btdm.rs b/esp-radio/src/ble/btdm.rs index 33d0e5424..51bf1c2b3 100644 --- a/esp-radio/src/ble/btdm.rs +++ b/esp-radio/src/ble/btdm.rs @@ -468,7 +468,8 @@ pub(crate) fn ble_deinit() { crate::common_adapter::chip_specific::phy_disable(); } } - +/// Sends HCI data to the BLE controller. +#[instability::unstable] pub fn send_hci(data: &[u8]) { let hci_out = unsafe { (*addr_of_mut!(HCI_OUT_COLLECTOR)).assume_init_mut() }; hci_out.push(data); diff --git a/esp-radio/src/ble/controller/mod.rs b/esp-radio/src/ble/controller/mod.rs index f94033473..8adef84db 100644 --- a/esp-radio/src/ble/controller/mod.rs +++ b/esp-radio/src/ble/controller/mod.rs @@ -4,6 +4,7 @@ use super::{read_hci, read_next, send_hci}; use crate::Controller; /// A blocking HCI connector +#[instability::unstable] pub struct BleConnector<'d> { _device: crate::hal::peripherals::BT<'d>, } @@ -15,6 +16,8 @@ impl Drop for BleConnector<'_> { } impl<'d> BleConnector<'d> { + /// Create and init a new BLE connector. + #[instability::unstable] pub fn new( _init: &'d Controller<'d>, device: crate::hal::peripherals::BT<'d>, @@ -24,12 +27,16 @@ impl<'d> BleConnector<'d> { Self { _device: device } } + /// Read the next HCI packet from the BLE controller. + #[instability::unstable] pub fn next(&mut self, buf: &mut [u8]) -> Result { Ok(read_next(buf)) } } #[derive(Debug)] +/// Error type for the BLE connector. +#[instability::unstable] pub enum BleConnectorError { Unknown, } diff --git a/esp-radio/src/ble/mod.rs b/esp-radio/src/ble/mod.rs index b15cc8382..b8ebef4cf 100644 --- a/esp-radio/src/ble/mod.rs +++ b/esp-radio/src/ble/mod.rs @@ -19,7 +19,9 @@ use self::btdm as ble; #[cfg(any(esp32c2, esp32c6, esp32h2))] use self::npl as ble; -pub mod controller; +unstable_module! { + pub mod controller; +} pub(crate) unsafe extern "C" fn malloc(size: u32) -> *mut crate::binary::c_types::c_void { unsafe { crate::compat::malloc::malloc(size as usize).cast() } @@ -108,7 +110,10 @@ impl HciOutCollector { static BLE_HCI_READ_DATA: Mutex>> = Mutex::new(RefCell::new(Vec::new())); #[derive(Debug, Clone)] +/// Represents a received BLE packet. +#[instability::unstable] pub struct ReceivedPacket { + /// The data of the received packet. pub data: Box<[u8]>, } @@ -119,6 +124,8 @@ impl defmt::Format for ReceivedPacket { } } +/// Checks if there is any HCI data available to read. +#[instability::unstable] pub fn have_hci_read_data() -> bool { critical_section::with(|cs| { let queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); @@ -141,6 +148,8 @@ pub(crate) fn read_next(data: &mut [u8]) -> usize { }) } +/// Reads the next HCI packet from the BLE controller. +#[instability::unstable] pub fn read_hci(data: &mut [u8]) -> usize { critical_section::with(|cs| { let mut hci_read_data = BLE_HCI_READ_DATA.borrow_ref_mut(cs); diff --git a/esp-radio/src/ble/npl.rs b/esp-radio/src/ble/npl.rs index c7cec24fc..ea9463253 100644 --- a/esp-radio/src/ble/npl.rs +++ b/esp-radio/src/ble/npl.rs @@ -138,7 +138,7 @@ impl OsMbufPool { /// Chained memory buffer. #[repr(C)] -pub struct OsMbuf { +pub(crate) struct OsMbuf { /// Current pointer to data in the structure om_data: *const u8, /// Flags associated with this buffer, see OS_MBUF_F_* defintions @@ -279,7 +279,8 @@ unsafe extern "C" { } #[repr(C)] -pub struct ExtFuncsT { +/// Contains pointers to external functions used by the BLE stack. +pub(crate) struct ExtFuncsT { ext_version: u32, esp_intr_alloc: Option< unsafe extern "C" fn( @@ -428,7 +429,8 @@ unsafe extern "C" fn esp_intr_free(_ret_handle: *mut *mut c_void) -> i32 { } #[repr(C)] -pub struct npl_funcs_t { +/// Contains pointers to functions used by the BLE NPL (Non-Preemptive Layer). +pub(crate) struct npl_funcs_t { p_ble_npl_os_started: Option bool>, p_ble_npl_get_current_task_id: Option *const c_void>, p_ble_npl_eventq_init: Option, @@ -564,7 +566,8 @@ static mut G_NPL_FUNCS: npl_funcs_t = npl_funcs_t { }; #[repr(C)] -pub struct OsiCoexFuncsT { +/// Contains pointers to functions used for BLE coexistence with Wi-Fi. +pub(crate) struct OsiCoexFuncsT { magic: u32, version: u32, coex_wifi_sleep_set: Option, @@ -1053,7 +1056,8 @@ unsafe extern "C" fn ble_npl_os_started() -> bool { } #[repr(C)] -pub struct BleNplCountInfoT { +/// Contains information about the BLE NPL (Non-Preemptive Layer) elements. +pub(crate) struct BleNplCountInfoT { evt_count: u16, evtq_count: u16, co_count: u16, @@ -1400,6 +1404,8 @@ unsafe extern "C" fn ble_hs_rx_data(om: *const OsMbuf, arg: *const c_void) -> i3 0 } +/// Sends HCI data to the Bluetooth controller. +#[instability::unstable] pub fn send_hci(data: &[u8]) { let hci_out = unsafe { (*addr_of_mut!(HCI_OUT_COLLECTOR)).assume_init_mut() }; hci_out.push(data); diff --git a/esp-radio/src/ble/os_adapter_esp32.rs b/esp-radio/src/ble/os_adapter_esp32.rs index dedae96e3..7d827c76b 100644 --- a/esp-radio/src/ble/os_adapter_esp32.rs +++ b/esp-radio/src/ble/os_adapter_esp32.rs @@ -16,17 +16,17 @@ use crate::{ hal::{interrupt, peripherals::Interrupt}, }; -pub static mut ISR_INTERRUPT_5: ( +pub(crate) static mut ISR_INTERRUPT_5: ( *mut crate::binary::c_types::c_void, *mut crate::binary::c_types::c_void, ) = (core::ptr::null_mut(), core::ptr::null_mut()); -pub static mut ISR_INTERRUPT_8: ( +pub(crate) static mut ISR_INTERRUPT_8: ( *mut crate::binary::c_types::c_void, *mut crate::binary::c_types::c_void, ) = (core::ptr::null_mut(), core::ptr::null_mut()); -pub static mut ISR_INTERRUPT_7: ( +pub(crate) static mut ISR_INTERRUPT_7: ( *mut crate::binary::c_types::c_void, *mut crate::binary::c_types::c_void, ) = (core::ptr::null_mut(), core::ptr::null_mut()); diff --git a/esp-radio/src/ble/os_adapter_esp32s3.rs b/esp-radio/src/ble/os_adapter_esp32s3.rs index 5534709d0..a133208cb 100644 --- a/esp-radio/src/ble/os_adapter_esp32s3.rs +++ b/esp-radio/src/ble/os_adapter_esp32s3.rs @@ -4,12 +4,12 @@ use crate::{ hal::{interrupt, peripherals::Interrupt}, }; -pub static mut ISR_INTERRUPT_5: ( +pub(crate) static mut ISR_INTERRUPT_5: ( *mut crate::binary::c_types::c_void, *mut crate::binary::c_types::c_void, ) = (core::ptr::null_mut(), core::ptr::null_mut()); -pub static mut ISR_INTERRUPT_8: ( +pub(crate) static mut ISR_INTERRUPT_8: ( *mut crate::binary::c_types::c_void, *mut crate::binary::c_types::c_void, ) = (core::ptr::null_mut(), core::ptr::null_mut()); diff --git a/esp-radio/src/esp_now/mod.rs b/esp-radio/src/esp_now/mod.rs index 3464379a3..13c951724 100644 --- a/esp-radio/src/esp_now/mod.rs +++ b/esp-radio/src/esp_now/mod.rs @@ -10,11 +10,18 @@ //! For more information see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html use alloc::{boxed::Box, collections::vec_deque::VecDeque}; -use core::{cell::RefCell, fmt::Debug, marker::PhantomData}; +use core::{ + cell::RefCell, + fmt::Debug, + marker::PhantomData, + task::{Context, Poll}, +}; use critical_section::Mutex; +use esp_hal::asynch::AtomicWaker; use portable_atomic::{AtomicBool, AtomicU8, Ordering}; +use super::*; #[cfg(feature = "csi")] use crate::wifi::CsiConfig; use crate::{ @@ -69,6 +76,7 @@ macro_rules! check_error_expect { #[repr(u32)] #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[instability::unstable] pub enum Error { /// ESP-NOW is not initialized. NotInitialized = 12389, @@ -100,6 +108,7 @@ pub enum Error { } impl Error { + #[instability::unstable] pub fn from_code(code: u32) -> Error { match code { 12389 => Error::NotInitialized, @@ -118,6 +127,7 @@ impl Error { /// Common errors that can occur while using ESP-NOW driver. #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[instability::unstable] pub enum EspNowError { /// Internal Error. Error(Error), @@ -138,6 +148,7 @@ impl From for EspNowError { /// Holds the count of peers in an ESP-NOW communication context. #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[instability::unstable] pub struct PeerCount { /// The total number of peers. pub total_count: i32, @@ -149,6 +160,7 @@ pub struct PeerCount { /// ESP-NOW rate of specified interface. #[repr(u32)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[instability::unstable] pub enum WifiPhyRate { /// < 1 Mbps with long preamble Rate1mL = 0, @@ -223,6 +235,7 @@ pub enum WifiPhyRate { /// ESP-NOW peer information parameters. #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[instability::unstable] pub struct PeerInfo { /// Interface to use pub interface: EspNowWifiInterface, @@ -245,6 +258,7 @@ pub struct PeerInfo { /// Information about a received packet. #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[instability::unstable] pub struct ReceiveInfo { /// The source address of the received packet. pub src_address: [u8; 6], @@ -259,6 +273,7 @@ pub struct ReceiveInfo { /// Stores information about the received data, including the packet content and /// associated information. #[derive(Clone)] +#[instability::unstable] pub struct ReceivedData { data: Box<[u8]>, pub info: ReceiveInfo, @@ -266,6 +281,7 @@ pub struct ReceivedData { impl ReceivedData { /// Returns the received payload. + #[instability::unstable] pub fn data(&self) -> &[u8] { &self.data } @@ -290,6 +306,7 @@ impl Debug for ReceivedData { /// The interface to use for this peer #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[instability::unstable] pub enum EspNowWifiInterface { /// Use the AP interface Ap, @@ -317,6 +334,7 @@ impl EspNowWifiInterface { } /// Manages the `EspNow` instance lifecycle while ensuring it remains active. +#[instability::unstable] pub struct EspNowManager<'d> { _rc: EspNowRc<'d>, } @@ -324,11 +342,13 @@ pub struct EspNowManager<'d> { impl EspNowManager<'_> { /// Set primary WiFi channel. /// Should only be used when using ESP-NOW without AP or STA. + #[instability::unstable] pub fn set_channel(&self, channel: u8) -> Result<(), EspNowError> { check_error!({ esp_wifi_set_channel(channel, 0) }) } /// Get the version of ESP-NOW. + #[instability::unstable] pub fn version(&self) -> Result { let mut version = 0u32; check_error!({ esp_now_get_version(&mut version as *mut u32) })?; @@ -336,6 +356,7 @@ impl EspNowManager<'_> { } /// Add a peer to the list of known peers. + #[instability::unstable] pub fn add_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> { let raw_peer = esp_now_peer_info_t { peer_addr: peer.peer_address, @@ -350,6 +371,7 @@ impl EspNowManager<'_> { /// Set CSI configuration and register the receiving callback. #[cfg(feature = "csi")] + #[instability::unstable] pub fn set_csi( &mut self, mut csi: CsiConfig, @@ -363,11 +385,13 @@ impl EspNowManager<'_> { } /// Remove the given peer. + #[instability::unstable] pub fn remove_peer(&self, peer_address: &[u8; 6]) -> Result<(), EspNowError> { check_error!({ esp_now_del_peer(peer_address.as_ptr()) }) } /// Modify a peer information. + #[instability::unstable] pub fn modify_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> { let raw_peer = esp_now_peer_info_t { peer_addr: peer.peer_address, @@ -381,6 +405,7 @@ impl EspNowManager<'_> { } /// Get peer by MAC address. + #[instability::unstable] pub fn peer(&self, peer_address: &[u8; 6]) -> Result { let mut raw_peer = esp_now_peer_info_t { peer_addr: [0u8; 6], @@ -414,6 +439,7 @@ impl EspNowManager<'_> { /// Only returns peers which address is unicast, for multicast/broadcast /// addresses, the function will skip the entry and find the next in the /// peer list. + #[instability::unstable] pub fn fetch_peer(&self, from_head: bool) -> Result { let mut raw_peer = esp_now_peer_info_t { peer_addr: [0u8; 6], @@ -443,11 +469,13 @@ impl EspNowManager<'_> { } /// Check is peer is known. + #[instability::unstable] pub fn peer_exists(&self, peer_address: &[u8; 6]) -> bool { unsafe { esp_now_is_peer_exist(peer_address.as_ptr()) } } /// Get the number of peers. + #[instability::unstable] pub fn peer_count(&self) -> Result { let mut peer_num = esp_now_peer_num_t { total_num: 0, @@ -462,6 +490,7 @@ impl EspNowManager<'_> { } /// Set the primary master key. + #[instability::unstable] pub fn set_pmk(&self, pmk: &[u8; 16]) -> Result<(), EspNowError> { check_error!({ esp_now_set_pmk(pmk.as_ptr()) }) } @@ -470,11 +499,13 @@ impl EspNowManager<'_> { /// /// Window is milliseconds the chip keep waked each interval, from 0 to /// 65535. + #[instability::unstable] pub fn set_wake_window(&self, wake_window: u16) -> Result<(), EspNowError> { check_error!({ esp_now_set_wake_window(wake_window) }) } /// Configure ESP-NOW rate. + #[instability::unstable] pub fn set_rate(&self, rate: WifiPhyRate) -> Result<(), EspNowError> { check_error!({ esp_wifi_config_espnow_rate(wifi_interface_t_WIFI_IF_STA, rate as u32,) }) } @@ -487,6 +518,7 @@ impl EspNowManager<'_> { /// **DO NOT USE** a lock implementation that disables interrupts since the /// completion of a sending requires waiting for a callback invoked in an /// interrupt. +#[instability::unstable] pub struct EspNowSender<'d> { _rc: EspNowRc<'d>, } @@ -495,6 +527,7 @@ impl EspNowSender<'_> { /// Send data to peer /// /// The peer needs to be added to the peer list first. + #[instability::unstable] pub fn send<'s>( &'s mut self, dst_addr: &[u8; 6], @@ -519,11 +552,13 @@ impl EspNowSender<'_> { /// since the callback which signals the completion of sending will never be /// invoked. #[must_use] +#[instability::unstable] pub struct SendWaiter<'s>(PhantomData<&'s mut EspNowSender<'s>>); impl SendWaiter<'_> { /// Wait for the previous sending to complete, i.e. the send callback is /// invoked with status of the sending. + #[instability::unstable] pub fn wait(self) -> Result<(), EspNowError> { // prevent redundant waiting since we waits for the callback in the Drop // implementation @@ -548,12 +583,14 @@ impl Drop for SendWaiter<'_> { /// This is the receiver part of ESP-NOW. You can get this receiver by splitting /// an `EspNow` instance. +#[instability::unstable] pub struct EspNowReceiver<'d> { _rc: EspNowRc<'d>, } impl EspNowReceiver<'_> { /// Receives data from the ESP-NOW queue. + #[instability::unstable] pub fn receive(&self) -> Option { critical_section::with(|cs| { let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs); @@ -613,6 +650,7 @@ impl Drop for EspNowRc<'_> { /// /// For convenience, by default there will be a broadcast peer added on the STA /// interface. +#[instability::unstable] pub struct EspNow<'d> { manager: EspNowManager<'d>, sender: EspNowSender<'d>, @@ -659,37 +697,44 @@ impl<'d> EspNow<'d> { /// Splits the `EspNow` instance into its manager, sender, and receiver /// components. + #[instability::unstable] pub fn split(self) -> (EspNowManager<'d>, EspNowSender<'d>, EspNowReceiver<'d>) { (self.manager, self.sender, self.receiver) } /// Set primary WiFi channel. /// Should only be used when using ESP-NOW without AP or STA. + #[instability::unstable] pub fn set_channel(&self, channel: u8) -> Result<(), EspNowError> { self.manager.set_channel(channel) } /// Get the version of ESP-NOW. + #[instability::unstable] pub fn version(&self) -> Result { self.manager.version() } /// Add a peer to the list of known peers. + #[instability::unstable] pub fn add_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> { self.manager.add_peer(peer) } /// Remove the given peer. + #[instability::unstable] pub fn remove_peer(&self, peer_address: &[u8; 6]) -> Result<(), EspNowError> { self.manager.remove_peer(peer_address) } /// Modify a peer information. + #[instability::unstable] pub fn modify_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> { self.manager.modify_peer(peer) } /// Get peer by MAC address. + #[instability::unstable] pub fn peer(&self, peer_address: &[u8; 6]) -> Result { self.manager.peer(peer_address) } @@ -699,21 +744,25 @@ impl<'d> EspNow<'d> { /// Only returns peers which address is unicast, for multicast/broadcast /// addresses, the function will skip the entry and find the next in the /// peer list. + #[instability::unstable] pub fn fetch_peer(&self, from_head: bool) -> Result { self.manager.fetch_peer(from_head) } /// Check is peer is known. + #[instability::unstable] pub fn peer_exists(&self, peer_address: &[u8; 6]) -> bool { self.manager.peer_exists(peer_address) } /// Get the number of peers. + #[instability::unstable] pub fn peer_count(&self) -> Result { self.manager.peer_count() } /// Set the primary master key. + #[instability::unstable] pub fn set_pmk(&self, pmk: &[u8; 16]) -> Result<(), EspNowError> { self.manager.set_pmk(pmk) } @@ -722,11 +771,13 @@ impl<'d> EspNow<'d> { /// /// Window is milliseconds the chip keep waked each interval, from 0 to /// 65535. + #[instability::unstable] pub fn set_wake_window(&self, wake_window: u16) -> Result<(), EspNowError> { self.manager.set_wake_window(wake_window) } /// Configure ESP-NOW rate. + #[instability::unstable] pub fn set_rate(&self, rate: WifiPhyRate) -> Result<(), EspNowError> { self.manager.set_rate(rate) } @@ -734,6 +785,7 @@ impl<'d> EspNow<'d> { /// Send data to peer. /// /// The peer needs to be added to the peer list first. + #[instability::unstable] pub fn send<'s>( &'s mut self, dst_addr: &[u8; 6], @@ -743,6 +795,7 @@ impl<'d> EspNow<'d> { } /// Receive data. + #[instability::unstable] pub fn receive(&self) -> Option { self.receiver.receive() } @@ -755,7 +808,7 @@ unsafe extern "C" fn send_cb(_mac_addr: *const u8, status: esp_now_send_status_t ESP_NOW_SEND_CB_INVOKED.store(true, Ordering::Release); - asynch::ESP_NOW_TX_WAKER.wake(); + ESP_NOW_TX_WAKER.wake(); }) } @@ -805,123 +858,119 @@ unsafe extern "C" fn rcv_cb( queue.push_back(ReceivedData { data, info }); - asynch::ESP_NOW_RX_WAKER.wake(); + ESP_NOW_RX_WAKER.wake(); }); } -pub use asynch::SendFuture; +pub(super) static ESP_NOW_TX_WAKER: AtomicWaker = AtomicWaker::new(); +pub(super) static ESP_NOW_RX_WAKER: AtomicWaker = AtomicWaker::new(); -mod asynch { - use core::task::{Context, Poll}; - - use esp_hal::asynch::AtomicWaker; - - use super::*; - - pub(super) static ESP_NOW_TX_WAKER: AtomicWaker = AtomicWaker::new(); - pub(super) static ESP_NOW_RX_WAKER: AtomicWaker = AtomicWaker::new(); - - impl EspNowReceiver<'_> { - /// This function takes mutable reference to self because the - /// implementation of `ReceiveFuture` is not logically thread - /// safe. - pub fn receive_async(&mut self) -> ReceiveFuture<'_> { - ReceiveFuture(PhantomData) - } +impl EspNowReceiver<'_> { + /// This function takes mutable reference to self because the + /// implementation of `ReceiveFuture` is not logically thread + /// safe. + #[instability::unstable] + pub fn receive_async(&mut self) -> ReceiveFuture<'_> { + ReceiveFuture(PhantomData) } +} - impl EspNowSender<'_> { - /// Sends data asynchronously to a peer (using its MAC) using ESP-NOW. - pub fn send_async<'s, 'r>( - &'s mut self, - addr: &'r [u8; 6], - data: &'r [u8], - ) -> SendFuture<'s, 'r> { - SendFuture { - _sender: PhantomData, - addr, - data, - sent: false, - } - } - } - - impl EspNow<'_> { - /// This function takes mutable reference to self because the - /// implementation of `ReceiveFuture` is not logically thread - /// safe. - pub fn receive_async(&mut self) -> ReceiveFuture<'_> { - self.receiver.receive_async() - } - - /// The returned future must not be dropped before it's ready to avoid - /// getting wrong status for sendings. - pub fn send_async<'s, 'r>( - &'s mut self, - dst_addr: &'r [u8; 6], - data: &'r [u8], - ) -> SendFuture<'s, 'r> { - self.sender.send_async(dst_addr, data) - } - } - - /// A `future` representing the result of an asynchronous ESP-NOW send - /// operation. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct SendFuture<'s, 'r> { - _sender: PhantomData<&'s mut EspNowSender<'s>>, +impl EspNowSender<'_> { + /// Sends data asynchronously to a peer (using its MAC) using ESP-NOW. + #[instability::unstable] + pub fn send_async<'s, 'r>( + &'s mut self, addr: &'r [u8; 6], data: &'r [u8], - sent: bool, - } - - impl core::future::Future for SendFuture<'_, '_> { - type Output = Result<(), EspNowError>; - - fn poll(mut self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if !self.sent { - ESP_NOW_TX_WAKER.register(cx.waker()); - ESP_NOW_SEND_CB_INVOKED.store(false, Ordering::Release); - if let Err(e) = check_error!({ - esp_now_send(self.addr.as_ptr(), self.data.as_ptr(), self.data.len()) - }) { - return Poll::Ready(Err(e)); - } - self.sent = true; - } - - if !ESP_NOW_SEND_CB_INVOKED.load(Ordering::Acquire) { - Poll::Pending - } else { - Poll::Ready(if ESP_NOW_SEND_STATUS.load(Ordering::Relaxed) { - Ok(()) - } else { - Err(EspNowError::SendFailed) - }) - } - } - } - - /// It's not logically safe to poll multiple instances of `ReceiveFuture` - /// simultaneously since the callback can only wake one future, leaving - /// the rest of them unwakable. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct ReceiveFuture<'r>(PhantomData<&'r mut EspNowReceiver<'r>>); - - impl core::future::Future for ReceiveFuture<'_> { - type Output = ReceivedData; - - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - ESP_NOW_RX_WAKER.register(cx.waker()); - - if let Some(data) = critical_section::with(|cs| { - let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs); - queue.pop_front() - }) { - Poll::Ready(data) - } else { - Poll::Pending - } + ) -> SendFuture<'s, 'r> { + SendFuture { + _sender: PhantomData, + addr, + data, + sent: false, + } + } +} + +impl EspNow<'_> { + /// This function takes mutable reference to self because the + /// implementation of `ReceiveFuture` is not logically thread + /// safe. + #[instability::unstable] + pub fn receive_async(&mut self) -> ReceiveFuture<'_> { + self.receiver.receive_async() + } + + /// The returned future must not be dropped before it's ready to avoid + /// getting wrong status for sendings. + #[instability::unstable] + pub fn send_async<'s, 'r>( + &'s mut self, + dst_addr: &'r [u8; 6], + data: &'r [u8], + ) -> SendFuture<'s, 'r> { + self.sender.send_async(dst_addr, data) + } +} + +/// A `future` representing the result of an asynchronous ESP-NOW send +/// operation. +#[must_use = "futures do nothing unless you `.await` or poll them"] +#[instability::unstable] +pub struct SendFuture<'s, 'r> { + _sender: PhantomData<&'s mut EspNowSender<'s>>, + addr: &'r [u8; 6], + data: &'r [u8], + sent: bool, +} + +impl core::future::Future for SendFuture<'_, '_> { + type Output = Result<(), EspNowError>; + + fn poll(mut self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if !self.sent { + ESP_NOW_TX_WAKER.register(cx.waker()); + ESP_NOW_SEND_CB_INVOKED.store(false, Ordering::Release); + if let Err(e) = check_error!({ + esp_now_send(self.addr.as_ptr(), self.data.as_ptr(), self.data.len()) + }) { + return Poll::Ready(Err(e)); + } + self.sent = true; + } + + if !ESP_NOW_SEND_CB_INVOKED.load(Ordering::Acquire) { + Poll::Pending + } else { + Poll::Ready(if ESP_NOW_SEND_STATUS.load(Ordering::Relaxed) { + Ok(()) + } else { + Err(EspNowError::SendFailed) + }) + } + } +} + +/// It's not logically safe to poll multiple instances of `ReceiveFuture` +/// simultaneously since the callback can only wake one future, leaving +/// the rest of them unwakable. +#[must_use = "futures do nothing unless you `.await` or poll them"] +#[instability::unstable] +pub struct ReceiveFuture<'r>(PhantomData<&'r mut EspNowReceiver<'r>>); + +impl core::future::Future for ReceiveFuture<'_> { + type Output = ReceivedData; + + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + ESP_NOW_RX_WAKER.register(cx.waker()); + + if let Some(data) = critical_section::with(|cs| { + let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs); + queue.pop_front() + }) { + Poll::Ready(data) + } else { + Poll::Pending } } } diff --git a/esp-radio/src/lib.rs b/esp-radio/src/lib.rs index 19289883e..adfdd2e50 100644 --- a/esp-radio/src/lib.rs +++ b/esp-radio/src/lib.rs @@ -99,6 +99,7 @@ ble or wifi." ) )] +#![cfg_attr(docsrs, feature(doc_cfg, custom_inner_attributes, proc_macro_hygiene))] #[macro_use] extern crate esp_metadata_generated; @@ -129,6 +130,28 @@ use crate::{ tasks::init_tasks, }; +// can't use instability on inline module definitions, see https://github.com/rust-lang/rust/issues/54727 +#[doc(hidden)] +macro_rules! unstable_module { + ($( + $(#[$meta:meta])* + pub mod $module:ident; + )*) => { + $( + $(#[$meta])* + #[cfg(feature = "unstable")] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] + pub mod $module; + + $(#[$meta])* + #[cfg(not(feature = "unstable"))] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] + #[allow(unused)] + pub(crate) mod $module; + )* + }; +} + mod binary { pub use esp_wifi_sys::*; } @@ -137,18 +160,19 @@ mod compat; mod radio; mod time; +pub(crate) use unstable_module; + #[cfg(feature = "wifi")] pub mod wifi; -#[cfg(feature = "ble")] -pub mod ble; - -#[cfg(feature = "esp-now")] -pub mod esp_now; - -#[cfg(feature = "ieee802154")] -pub mod ieee802154; - +unstable_module! { + #[cfg(feature = "esp-now")] + pub mod esp_now; + #[cfg(feature = "ble")] + pub mod ble; + #[cfg(feature = "ieee802154")] + pub mod ieee802154; +} pub mod config; pub(crate) mod common_adapter; @@ -202,6 +226,7 @@ pub(crate) const CONFIG: config::Config = config::Config { #[derive(Debug, PartialEq, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Controller for the ESP Radio driver. pub struct Controller<'d> { _inner: PhantomData<&'d ()>, } @@ -319,6 +344,7 @@ impl From for InitializationError { /// Enable verbose logging within the WiFi driver /// Does nothing unless the `sys-logs` feature is enabled. +#[instability::unstable] pub fn wifi_set_log_verbose() { #[cfg(all(feature = "sys-logs", not(esp32h2)))] unsafe { diff --git a/esp-radio/src/wifi/event.rs b/esp-radio/src/wifi/event.rs index 8ebc1b8e0..bb7424eca 100644 --- a/esp-radio/src/wifi/event.rs +++ b/esp-radio/src/wifi/event.rs @@ -16,6 +16,7 @@ pub(crate) mod sealed { } } /// The type of handlers of events. +#[instability::unstable] pub type Handler = dyn FnMut(&T) + Sync + Send; fn default_handler() -> Box> { @@ -40,6 +41,7 @@ fn default_handler() -> Box> { // ``` // event::update_handler::(...) // ``` +#[instability::unstable] pub trait EventExt: sealed::Event + Sized + 'static { /// Get the handler for this event, replacing it with the default handler. fn take_handler() -> Box> { @@ -162,6 +164,7 @@ impl_wifi_event!(HomeChannelChange, wifi_event_home_channel_change_t); impl_wifi_event!(StaNeighborRep, wifi_event_neighbor_report_t); /// Handle the given event using the registered event handlers. +#[instability::unstable] pub fn handle(event_data: &Event) -> bool { Event::handler().with(|handler| { if let Some(handler) = handler { diff --git a/esp-radio/src/wifi/mod.rs b/esp-radio/src/wifi/mod.rs index 10b000b45..dcaf39fc3 100644 --- a/esp-radio/src/wifi/mod.rs +++ b/esp-radio/src/wifi/mod.rs @@ -43,7 +43,8 @@ use esp_wifi_sys::include::{ wifi_pkt_rx_ctrl_t, wifi_scan_channel_bitmap_t, }; -#[cfg(feature = "sniffer")] +#[cfg(all(feature = "sniffer", feature = "unstable"))] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] use esp_wifi_sys::include::{ esp_wifi_80211_tx, esp_wifi_set_promiscuous, @@ -57,7 +58,8 @@ pub(crate) use os_adapter::*; use portable_atomic::{AtomicUsize, Ordering}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -#[cfg(feature = "smoltcp")] +#[cfg(all(feature = "smoltcp", feature = "unstable"))] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] use smoltcp::phy::{Device, DeviceCapabilities, RxToken, TxToken}; pub use state::*; @@ -75,8 +77,10 @@ const MTU: usize = crate::CONFIG.mtu; #[cfg(all(feature = "csi", esp32c6))] use crate::binary::include::wifi_csi_acquire_config_t; #[cfg(feature = "csi")] +#[instability::unstable] pub use crate::binary::include::wifi_csi_info_t; #[cfg(feature = "csi")] +#[instability::unstable] use crate::binary::include::{ esp_wifi_set_csi, esp_wifi_set_csi_config, @@ -2060,7 +2064,8 @@ impl RxControlInfo { } } /// Represents a Wi-Fi packet in promiscuous mode. -#[cfg(feature = "sniffer")] +#[cfg(all(feature = "sniffer", feature = "unstable"))] +#[instability::unstable] pub struct PromiscuousPkt<'a> { /// Control information related to packet reception. pub rx_cntl: RxControlInfo, @@ -2071,7 +2076,8 @@ pub struct PromiscuousPkt<'a> { /// Data contained in the received packet. pub data: &'a [u8], } -#[cfg(feature = "sniffer")] +#[cfg(all(feature = "sniffer", feature = "unstable"))] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] impl PromiscuousPkt<'_> { /// # Safety /// When calling this, you have to ensure, that `buf` points to a valid @@ -2096,10 +2102,10 @@ impl PromiscuousPkt<'_> { } } -#[cfg(feature = "sniffer")] +#[cfg(all(feature = "sniffer", feature = "unstable"))] static SNIFFER_CB: Locked)>> = Locked::new(None); -#[cfg(feature = "sniffer")] +#[cfg(all(feature = "sniffer", feature = "unstable"))] unsafe extern "C" fn promiscuous_rx_cb(buf: *mut core::ffi::c_void, frame_type: u32) { unsafe { if let Some(sniffer_callback) = SNIFFER_CB.with(|callback| *callback) { @@ -2109,12 +2115,13 @@ unsafe extern "C" fn promiscuous_rx_cb(buf: *mut core::ffi::c_void, frame_type: } } -#[cfg(feature = "sniffer")] +#[cfg(all(feature = "sniffer", feature = "unstable"))] +#[instability::unstable] /// A wifi sniffer. #[non_exhaustive] pub struct Sniffer {} -#[cfg(feature = "sniffer")] +#[cfg(all(feature = "sniffer", feature = "unstable"))] impl Sniffer { pub(crate) fn new() -> Self { // This shouldn't fail, since the way this is created, means that wifi will @@ -2125,11 +2132,13 @@ impl Sniffer { Self {} } /// Set promiscuous mode enabled or disabled. + #[instability::unstable] pub fn set_promiscuous_mode(&self, enabled: bool) -> Result<(), WifiError> { esp_wifi_result!(unsafe { esp_wifi_set_promiscuous(enabled) })?; Ok(()) } /// Transmit a raw frame. + #[instability::unstable] pub fn send_raw_frame( &mut self, use_sta_interface: bool, @@ -2150,13 +2159,15 @@ impl Sniffer { }) } /// Set the callback for receiving a packet. + #[instability::unstable] pub fn set_receive_cb(&mut self, cb: fn(PromiscuousPkt<'_>)) { SNIFFER_CB.with(|callback| *callback = Some(cb)); } } // see https://docs.rs/smoltcp/0.7.1/smoltcp/phy/index.html -#[cfg(feature = "smoltcp")] +#[cfg(all(feature = "smoltcp", feature = "unstable"))] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] impl Device for WifiDevice<'_> { type RxToken<'a> = WifiRxToken @@ -2223,7 +2234,8 @@ impl WifiRxToken { } } -#[cfg(feature = "smoltcp")] +#[cfg(all(feature = "smoltcp", feature = "unstable"))] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] impl RxToken for WifiRxToken { fn consume(self, f: F) -> R where @@ -2263,7 +2275,8 @@ impl WifiTxToken { } } -#[cfg(feature = "smoltcp")] +#[cfg(all(feature = "smoltcp", feature = "unstable"))] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] impl TxToken for WifiTxToken { fn consume(self, len: usize, f: F) -> R where @@ -2633,13 +2646,16 @@ impl Drop for FreeApListOnDrop { } } +/// Represents the Wi-Fi controller and its associated interfaces. #[non_exhaustive] pub struct Interfaces<'d> { pub sta: WifiDevice<'d>, pub ap: WifiDevice<'d>, - #[cfg(feature = "esp-now")] + #[cfg(all(feature = "esp-now", feature = "unstable"))] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] pub esp_now: crate::esp_now::EspNow<'d>, - #[cfg(feature = "sniffer")] + #[cfg(all(feature = "sniffer", feature = "unstable"))] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] pub sniffer: Sniffer, } @@ -2695,9 +2711,9 @@ pub fn new<'d>( _phantom: Default::default(), mode: WifiDeviceMode::Ap, }, - #[cfg(feature = "esp-now")] + #[cfg(all(feature = "esp-now", feature = "unstable"))] esp_now: crate::esp_now::EspNow::new_internal(), - #[cfg(feature = "sniffer")] + #[cfg(all(feature = "sniffer", feature = "unstable"))] sniffer: Sniffer::new(), }, )) @@ -2723,6 +2739,7 @@ impl Drop for WifiController<'_> { impl WifiController<'_> { /// Set CSI configuration and register the receiving callback. #[cfg(feature = "csi")] + #[instability::unstable] pub fn set_csi( &mut self, mut csi: CsiConfig, diff --git a/esp-radio/src/wifi/state.rs b/esp-radio/src/wifi/state.rs index 5180bbf18..eac66f87b 100644 --- a/esp-radio/src/wifi/state.rs +++ b/esp-radio/src/wifi/state.rs @@ -38,11 +38,13 @@ pub(crate) static STA_STATE: AtomicWifiState = AtomicWifiState::new(WifiState::I pub(crate) static AP_STATE: AtomicWifiState = AtomicWifiState::new(WifiState::Invalid); /// Get the current state of the AP +#[instability::unstable] pub fn ap_state() -> WifiState { AP_STATE.load(Ordering::Relaxed) } /// Get the current state of the STA +#[instability::unstable] pub fn sta_state() -> WifiState { STA_STATE.load(Ordering::Relaxed) } diff --git a/examples/src/bin/ieee802154_receive_all_frames.rs b/examples/src/bin/ieee802154_receive_all_frames.rs index bd67c9fef..7ee032178 100644 --- a/examples/src/bin/ieee802154_receive_all_frames.rs +++ b/examples/src/bin/ieee802154_receive_all_frames.rs @@ -1,5 +1,5 @@ //% CHIPS: esp32c6 esp32h2 -//% FEATURES: esp-hal/unstable esp-radio/ieee802154 +//% FEATURES: esp-hal/unstable esp-radio/ieee802154 esp-radio/unstable #![no_std] #![no_main] diff --git a/examples/src/bin/ieee802154_receive_frame.rs b/examples/src/bin/ieee802154_receive_frame.rs index 98a62c8db..a417b5187 100644 --- a/examples/src/bin/ieee802154_receive_frame.rs +++ b/examples/src/bin/ieee802154_receive_frame.rs @@ -1,5 +1,5 @@ //% CHIPS: esp32c6 esp32h2 -//% FEATURES: esp-hal/unstable esp-radio/ieee802154 +//% FEATURES: esp-hal/unstable esp-radio/ieee802154 esp-radio/unstable #![no_std] #![no_main] diff --git a/examples/src/bin/ieee802154_send_broadcast_frame.rs b/examples/src/bin/ieee802154_send_broadcast_frame.rs index ce6fb42c4..34de5feda 100644 --- a/examples/src/bin/ieee802154_send_broadcast_frame.rs +++ b/examples/src/bin/ieee802154_send_broadcast_frame.rs @@ -1,5 +1,5 @@ //% CHIPS: esp32c6 esp32h2 -//% FEATURES: esp-hal/unstable esp-radio/ieee802154 +//% FEATURES: esp-hal/unstable esp-radio/ieee802154 esp-radio/unstable #![no_std] #![no_main] diff --git a/examples/src/bin/ieee802154_send_frame.rs b/examples/src/bin/ieee802154_send_frame.rs index b616d746f..6a24047eb 100644 --- a/examples/src/bin/ieee802154_send_frame.rs +++ b/examples/src/bin/ieee802154_send_frame.rs @@ -1,5 +1,5 @@ //% CHIPS: esp32c6 esp32h2 -//% FEATURES: esp-hal/unstable esp-radio/ieee802154 +//% FEATURES: esp-hal/unstable esp-radio/ieee802154 esp-radio/unstable #![no_std] #![no_main] diff --git a/examples/src/bin/ieee802154_sniffer.rs b/examples/src/bin/ieee802154_sniffer.rs index 0d7237d86..2c8438251 100644 --- a/examples/src/bin/ieee802154_sniffer.rs +++ b/examples/src/bin/ieee802154_sniffer.rs @@ -5,7 +5,7 @@ //! identical to ieee802154_receive_all_frames //% CHIPS: esp32c6 esp32h2 -//% FEATURES: esp-hal/unstable esp-radio/ieee802154 +//% FEATURES: esp-hal/unstable esp-radio/ieee802154 esp-radio/unstable #![no_std] #![no_main] diff --git a/examples/src/bin/wifi_80211_tx.rs b/examples/src/bin/wifi_80211_tx.rs index 22ef75b8e..a05caf4d9 100644 --- a/examples/src/bin/wifi_80211_tx.rs +++ b/examples/src/bin/wifi_80211_tx.rs @@ -2,7 +2,7 @@ //! //! Periodically transmits a beacon frame. -//% FEATURES: esp-radio esp-radio/wifi esp-radio/sniffer esp-hal/unstable +//% FEATURES: esp-radio esp-radio/wifi esp-radio/sniffer esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_access_point.rs b/examples/src/bin/wifi_access_point.rs index 748fae8df..89f5337ba 100644 --- a/examples/src/bin/wifi_access_point.rs +++ b/examples/src/bin/wifi_access_point.rs @@ -10,7 +10,7 @@ //! WiFi has no internet connection, Chrome might not want to load the URL - you //! can use a shell and try `curl` and `ping` -//% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-hal/unstable +//% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_access_point_with_sta.rs b/examples/src/bin/wifi_access_point_with_sta.rs index 46aefbb92..2a9862add 100644 --- a/examples/src/bin/wifi_access_point_with_sta.rs +++ b/examples/src/bin/wifi_access_point_with_sta.rs @@ -10,7 +10,7 @@ //! WiFi has no internet connection, Chrome might not want to load the URL - you //! can use a shell and try `curl` and `ping` -//% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-hal/unstable +//% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_bench.rs b/examples/src/bin/wifi_bench.rs index 2046740c7..d9142bba3 100644 --- a/examples/src/bin/wifi_bench.rs +++ b/examples/src/bin/wifi_bench.rs @@ -10,7 +10,7 @@ //! variable. E.g `HOST_IP="192.168.0.24"` and also set SSID and PASSWORD env //! variable before running this example. -//% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-hal/unstable +//% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_ble.rs b/examples/src/bin/wifi_ble.rs index 44d8cc910..b0f42a2ed 100644 --- a/examples/src/bin/wifi_ble.rs +++ b/examples/src/bin/wifi_ble.rs @@ -5,7 +5,7 @@ //! read/write/notify) //! - pressing the boot-button on a dev-board will send a notification if it is subscribed -//% FEATURES: esp-radio esp-radio/ble esp-hal/unstable +//% FEATURES: esp-radio esp-radio/ble esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 esp32h2 #![no_std] diff --git a/examples/src/bin/wifi_coex.rs b/examples/src/bin/wifi_coex.rs index 8408a9bd8..52f1efad8 100644 --- a/examples/src/bin/wifi_coex.rs +++ b/examples/src/bin/wifi_coex.rs @@ -10,7 +10,7 @@ //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 //% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-radio/ble esp-radio/coex -//% FEATURES: esp-hal/unstable +//% FEATURES: esp-radio/unstable esp-hal/unstable #![no_std] #![no_main] diff --git a/examples/src/bin/wifi_csi.rs b/examples/src/bin/wifi_csi.rs index 828110c0d..e5a7d40c3 100644 --- a/examples/src/bin/wifi_csi.rs +++ b/examples/src/bin/wifi_csi.rs @@ -5,7 +5,7 @@ //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 //% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-radio/log-04 esp-radio/csi -//% FEATURES: esp-hal/unstable +//% FEATURES: esp-radio/unstable esp-hal/unstable #![no_std] #![no_main] diff --git a/examples/src/bin/wifi_dhcp.rs b/examples/src/bin/wifi_dhcp.rs index 1c12d40d5..5b9af90f2 100644 --- a/examples/src/bin/wifi_dhcp.rs +++ b/examples/src/bin/wifi_dhcp.rs @@ -6,7 +6,7 @@ //! This gets an ip address via DHCP then performs an HTTP get request to some //! "random" server -//% FEATURES: esp-radio esp-radio/wifi esp-hal/unstable esp-radio/smoltcp +//% FEATURES: esp-radio esp-radio/wifi esp-hal/unstable esp-radio/smoltcp esp-radio/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 // esp-radio/utils diff --git a/examples/src/bin/wifi_embassy_access_point.rs b/examples/src/bin/wifi_embassy_access_point.rs index a03b3c11b..7432e23ab 100644 --- a/examples/src/bin/wifi_embassy_access_point.rs +++ b/examples/src/bin/wifi_embassy_access_point.rs @@ -10,7 +10,7 @@ //! WiFi has no internet connection, Chrome might not want to load the URL - you //! can use a shell and try `curl` and `ping` -//% FEATURES: embassy esp-radio esp-radio/wifi esp-hal/unstable +//% FEATURES: embassy esp-radio esp-radio/wifi esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_embassy_access_point_with_sta.rs b/examples/src/bin/wifi_embassy_access_point_with_sta.rs index 8c5b36bdd..56cf0b80e 100644 --- a/examples/src/bin/wifi_embassy_access_point_with_sta.rs +++ b/examples/src/bin/wifi_embassy_access_point_with_sta.rs @@ -16,7 +16,7 @@ //! WiFi has no internet connection, Chrome might not want to load the URL - you //! can use a shell and try `curl` and `ping` -//% FEATURES: embassy esp-radio esp-radio/wifi esp-hal/unstable +//% FEATURES: embassy esp-radio esp-radio/wifi esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index 0a32b82a7..b0b2ac3a2 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -13,7 +13,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 //! and ESP32-C2 -//% FEATURES: embassy esp-radio esp-radio/wifi esp-hal/unstable +//% FEATURES: embassy esp-radio esp-radio/wifi esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c3 esp32c6 #![allow(static_mut_refs)] diff --git a/examples/src/bin/wifi_embassy_ble.rs b/examples/src/bin/wifi_embassy_ble.rs index eddb1b709..c6f70777f 100644 --- a/examples/src/bin/wifi_embassy_ble.rs +++ b/examples/src/bin/wifi_embassy_ble.rs @@ -5,7 +5,7 @@ //! read/write/notify) //! - pressing the boot-button on a dev-board will send a notification if it is subscribed -//% FEATURES: embassy esp-radio esp-radio/ble esp-hal/unstable +//% FEATURES: embassy esp-radio esp-radio/ble esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 esp32h2 // Embassy offers another compatible BLE crate [trouble](https://github.com/embassy-rs/trouble/tree/main/examples/esp32) with esp32 examples. diff --git a/examples/src/bin/wifi_embassy_esp_now.rs b/examples/src/bin/wifi_embassy_esp_now.rs index c00dac489..b8e9e3088 100644 --- a/examples/src/bin/wifi_embassy_esp_now.rs +++ b/examples/src/bin/wifi_embassy_esp_now.rs @@ -4,7 +4,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: embassy esp-radio esp-radio/esp-now esp-hal/unstable +//% FEATURES: embassy esp-radio esp-radio/esp-now esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_embassy_esp_now_duplex.rs b/examples/src/bin/wifi_embassy_esp_now_duplex.rs index df71683c6..be3a1b90d 100644 --- a/examples/src/bin/wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/wifi_embassy_esp_now_duplex.rs @@ -5,7 +5,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: embassy esp-radio esp-radio/esp-now esp-hal/unstable +//% FEATURES: embassy esp-radio esp-radio/esp-now esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_esp_now.rs b/examples/src/bin/wifi_esp_now.rs index 93f2c385b..2f761a97d 100644 --- a/examples/src/bin/wifi_esp_now.rs +++ b/examples/src/bin/wifi_esp_now.rs @@ -2,7 +2,7 @@ //! //! Broadcasts, receives and sends messages via esp-now -//% FEATURES: esp-radio esp-radio/wifi esp-radio/esp-now esp-hal/unstable +//% FEATURES: esp-radio esp-radio/wifi esp-radio/esp-now esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_sniffer.rs b/examples/src/bin/wifi_sniffer.rs index 3012bd802..57047430e 100644 --- a/examples/src/bin/wifi_sniffer.rs +++ b/examples/src/bin/wifi_sniffer.rs @@ -2,7 +2,7 @@ //! //! Sniffs for beacon frames. -//% FEATURES: esp-radio esp-radio/wifi esp-radio/sniffer esp-hal/unstable +//% FEATURES: esp-radio esp-radio/wifi esp-radio/sniffer esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_static_ip.rs b/examples/src/bin/wifi_static_ip.rs index 356504e99..a9d70836b 100644 --- a/examples/src/bin/wifi_static_ip.rs +++ b/examples/src/bin/wifi_static_ip.rs @@ -6,7 +6,7 @@ //! - uses the given static IP //! - responds with some HTML content when connecting to port 8080 -//% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-hal/unstable +//% FEATURES: esp-radio esp-radio/wifi esp-radio/smoltcp esp-radio/unstable esp-hal/unstable //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/hil-test/tests/esp_radio_ble_controller.rs b/hil-test/tests/esp_radio_ble_controller.rs index df0158cfb..860129f13 100644 --- a/hil-test/tests/esp_radio_ble_controller.rs +++ b/hil-test/tests/esp_radio_ble_controller.rs @@ -11,7 +11,7 @@ //! THIS DOESN'T ACTUALLY TEST THE RADIO HOWEVER. //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s3 -//% FEATURES: unstable esp-radio esp-alloc esp-radio/ble +//% FEATURES: unstable esp-radio esp-alloc esp-radio/ble esp-radio/unstable #![no_std] #![no_main] diff --git a/hil-test/tests/esp_radio_floats.rs b/hil-test/tests/esp_radio_floats.rs index 63aa89ba8..f91ec600d 100644 --- a/hil-test/tests/esp_radio_floats.rs +++ b/hil-test/tests/esp_radio_floats.rs @@ -1,7 +1,7 @@ //! Cp0Disable exception regression test //% CHIPS: esp32 esp32s2 esp32s3 -//% FEATURES: unstable esp-radio esp-alloc esp-radio/wifi +//% FEATURES: unstable esp-radio esp-alloc esp-radio/wifi esp-radio/unstable #![no_std] #![no_main] diff --git a/hil-test/tests/esp_radio_init.rs b/hil-test/tests/esp_radio_init.rs index 55d08f3d4..522b07957 100644 --- a/hil-test/tests/esp_radio_init.rs +++ b/hil-test/tests/esp_radio_init.rs @@ -2,7 +2,7 @@ //! disabled in common ways //% CHIPS: esp32 esp32s2 esp32c2 esp32c3 esp32c6 esp32s3 -//% FEATURES: unstable esp-radio esp-alloc esp-radio/wifi embassy +//% FEATURES: unstable esp-radio esp-alloc esp-radio/wifi esp-radio/unstable embassy #![no_std] #![no_main] diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 726453b92..5392a514d 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -211,6 +211,11 @@ impl Package { if config.contains("wifi") && config.contains("bt") { features.push("coex".to_owned()); } + if features.iter().any(|f| { + f == "csi" || f == "ble" || f == "esp-now" || f == "sniffer" || f == "coex" + }) { + features.push("unstable".to_owned()); + } } Package::EspHalProcmacros => { features.push("embassy".to_owned()); @@ -248,7 +253,7 @@ impl Package { } /// Additional feature rules to test subsets of features for a package. - pub fn lint_feature_rules(&self, _config: &Config) -> Vec> { + pub fn lint_feature_rules(&self, config: &Config) -> Vec> { let mut cases = Vec::new(); match self { @@ -265,6 +270,14 @@ impl Package { Package::EspRadio => { // Minimal set of features that when enabled _should_ still compile: cases.push(vec!["esp-hal/rt".to_owned(), "esp-hal/unstable".to_owned()]); + // This tests if `wifi` feature works without `unstable` + if config.contains("wifi") { + cases.push(vec![ + "esp-hal/rt".to_owned(), + "esp-hal/unstable".to_owned(), + "wifi".to_owned(), + ]); + } } Package::EspMetadataGenerated => { cases.push(vec!["build-script".to_owned()]);