mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-26 20:00:32 +00:00
esp-wifi: Add unstable feature, mark ble
, esp-now
, csi
, sniffer
, and smoltcp
features and APIs as unstable (#3865)
* esp-wifi: Add unstable feature, mark ble, esp-now and csi features and APIs as unstable * changelog * fix hils * rebase and reviews * rebase * Make at least wifi_embassy_dhcp work without unstable feature * remove rand_core * rebase * Check if a feature is selected which needs unstable * reviews and fix ci * reviews
This commit is contained in:
parent
dfd66be8ab
commit
0fbbe2d22c
@ -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
|
||||
|
||||
|
@ -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",
|
||||
|
@ -21,6 +21,27 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
// 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.
|
||||
|
@ -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);
|
||||
|
@ -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<usize, BleConnectorError> {
|
||||
Ok(read_next(buf))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Error type for the BLE connector.
|
||||
#[instability::unstable]
|
||||
pub enum BleConnectorError {
|
||||
Unknown,
|
||||
}
|
||||
|
@ -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<RefCell<Vec<u8>>> = 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);
|
||||
|
@ -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<unsafe extern "C" fn() -> bool>,
|
||||
p_ble_npl_get_current_task_id: Option<unsafe extern "C" fn() -> *const c_void>,
|
||||
p_ble_npl_eventq_init: Option<unsafe extern "C" fn(queue: *const ble_npl_eventq)>,
|
||||
@ -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<unsafe extern "C" fn(sleep: bool)>,
|
||||
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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<WifiError> 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<u32, EspNowError> {
|
||||
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<PeerInfo, EspNowError> {
|
||||
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<PeerInfo, EspNowError> {
|
||||
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<PeerCount, EspNowError> {
|
||||
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<ReceivedData> {
|
||||
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<u32, EspNowError> {
|
||||
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<PeerInfo, EspNowError> {
|
||||
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<PeerInfo, EspNowError> {
|
||||
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<PeerCount, EspNowError> {
|
||||
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<ReceivedData> {
|
||||
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<Self::Output> {
|
||||
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<Self::Output> {
|
||||
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<Self::Output> {
|
||||
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<Self::Output> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<WifiError> 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 {
|
||||
|
@ -16,6 +16,7 @@ pub(crate) mod sealed {
|
||||
}
|
||||
}
|
||||
/// The type of handlers of events.
|
||||
#[instability::unstable]
|
||||
pub type Handler<T> = dyn FnMut(&T) + Sync + Send;
|
||||
|
||||
fn default_handler<Event: 'static>() -> Box<Handler<Event>> {
|
||||
@ -40,6 +41,7 @@ fn default_handler<Event: 'static>() -> Box<Handler<Event>> {
|
||||
// ```
|
||||
// event::update_handler::<event::ApStaconnected, _>(...)
|
||||
// ```
|
||||
#[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<Handler<Self>> {
|
||||
@ -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: EventExt>(event_data: &Event) -> bool {
|
||||
Event::handler().with(|handler| {
|
||||
if let Some(handler) = handler {
|
||||
|
@ -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<Option<fn(PromiscuousPkt<'_>)>> = 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<R, F>(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<R, F>(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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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)]
|
||||
|
@ -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.
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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<Vec<String>> {
|
||||
pub fn lint_feature_rules(&self, config: &Config) -> Vec<Vec<String>> {
|
||||
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()]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user