diff --git a/.github/workflows/ci-esp-idf-next.yml b/.github/workflows/ci-esp-idf-next.yml index 755eec284d5..e0b34bb8ab1 100644 --- a/.github/workflows/ci-esp-idf-next.yml +++ b/.github/workflows/ci-esp-idf-next.yml @@ -25,7 +25,7 @@ jobs: - xtensa-esp32s2-espidf - xtensa-esp32s3-espidf idf-version: - - v5.3.2 + - release/v5.3 - release/v5.4 - master steps: @@ -55,28 +55,28 @@ jobs: env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" run: cargo clippy --features nightly,experimental --no-deps --target ${{ matrix.target }} -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort -- -Dwarnings - name: Build | Compile env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" run: cargo build --target ${{ matrix.target }} -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort - name: Build | Compile, experimental, nightly, no_std env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" run: cargo build --no-default-features --features nightly,experimental --target ${{ matrix.target }} -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort - name: Build | Compile, experimental, nightly, alloc env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" run: cargo build --no-default-features --features nightly,experimental,alloc --target ${{ matrix.target }} -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort - name: Setup | ldproxy @@ -87,11 +87,10 @@ jobs: chmod a+x $HOME/.cargo/bin/ldproxy - name: Build | Examples - if: matrix.target != 'riscv32imac-esp-espidf' env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }} ${{ '-C default-linker-libraries' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" WIFI_SSID: "ssid" WIFI_PASS: "pass" ESP_DEVICE_IP: "192.168.1.250" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3548079148f..20e65e3462f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,9 +29,7 @@ jobs: - v4.4.8 - v5.1.2 - v5.2.3 -# Commented out until this gets resolved: -# https://github.com/espressif/esp-idf/issues/14174#issuecomment-2558527855 -# - v5.3.2 + - v5.3.2 steps: - name: Setup | Checkout uses: actions/checkout@v3 @@ -53,34 +51,39 @@ jobs: default: true - name: Build | Fmt Check + if: matrix.target != 'riscv32imac-esp-espidf' || matrix.idf-version != 'v4.4.8' run: cargo fmt -- --check - name: Build | Clippy + if: matrix.target != 'riscv32imac-esp-espidf' || matrix.idf-version != 'v4.4.8' env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" run: cargo clippy --features nightly,experimental --no-deps --target ${{ matrix.target }} -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort -- -Dwarnings - name: Build | Compile + if: matrix.target != 'riscv32imac-esp-espidf' || matrix.idf-version != 'v4.4.8' env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" run: cargo build --target ${{ matrix.target }} -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort - name: Build | Compile, experimental, nightly, no_std + if: matrix.target != 'riscv32imac-esp-espidf' || matrix.idf-version != 'v4.4.8' env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" run: cargo build --no-default-features --features nightly,experimental --target ${{ matrix.target }} -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort - name: Build | Compile, experimental, nightly, alloc + if: matrix.target != 'riscv32imac-esp-espidf' || matrix.idf-version != 'v4.4.8' env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" run: cargo build --no-default-features --features nightly,experimental,alloc --target ${{ matrix.target }} -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort - name: Setup | ldproxy @@ -91,11 +94,11 @@ jobs: chmod a+x $HOME/.cargo/bin/ldproxy - name: Build | Examples - if: matrix.target != 'riscv32imac-esp-espidf' + if: matrix.target != 'riscv32imac-esp-espidf' || matrix.idf-version != 'v4.4.8' env: ESP_IDF_VERSION: ${{ matrix.idf-version }} ESP_IDF_SDKCONFIG_DEFAULTS: "${{ github.workspace }}/.github/configs/sdkconfig.defaults" - RUSTFLAGS: "${{ startsWith(matrix.idf-version, 'v5') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }} ${{ '-C default-linker-libraries' }}" + RUSTFLAGS: "${{ !startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time64' || startsWith(matrix.idf-version, 'v4') && '--cfg espidf_time32' }}" WIFI_SSID: "ssid" WIFI_PASS: "pass" ESP_DEVICE_IP: "192.168.1.250" diff --git a/CHANGELOG.md b/CHANGELOG.md index bc96f699031..672e2a26897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.50.0] - 2025-01-02 ### Deprecated - `EspFirmwareInfoLoader` use `EspFirmwareInfoLoad` instead @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Expose src_addr and dst_addr in espnow recv cb (#525) ### Added +- Compatibility with ESP-IDF v5.3.X - feat(eth): Implement alternative polling mode (#452) - SD Card driver; SD Card host drivers (SPI and SDMMC) (#454) - Make EspAsyncMqttClient::wrap public. (#462) @@ -34,6 +35,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add option to specify initial caps for the MQTT async adaptor vectors - Allow using esp timer with skip_unhandled_events (#526) - OTA - Implements a new type `EspFirmwareInfoLoad` that has a reduced memory consumption (#531) +- Added set_promiscuous function in EthDriver (#246) +- Added set_promiscuous, is_promiscuous functions in WifiDriver (#246) +- Blocking and buffered StdIo (#541) - i.e. easy reading/input from `std::io::stdin` +- Added source_ipv4, source_ipv6 function in EspHttpRawConnection (#538) ### Fixed - The alloc::Vec version stomps the scan state from Done to Idle. (#459) @@ -52,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bugfix: crash on MQTT async client restart - Fix missing newline if CONFIG_LOG_COLORS=n is set (#521) - gatekeep mdns ipv6 behind feature flag (#523) +- Fix emac_rx stack overflow when log verbosity is increased (#535) ## [0.49.1] - 2024-07-09 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index e7930acf182..65a4afa91b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-idf-svc" -version = "0.49.1" +version = "0.50.0" authors = ["Ivan Markov "] edition = "2021" resolver = "2" @@ -18,11 +18,6 @@ rust-version = "1.77" [lib] harness = false -[patch.crates-io] -embuild = { git = "https://github.com/esp-rs/embuild" } -esp-idf-hal = { git = "https://github.com/esp-rs/esp-idf-hal" } -esp-idf-sys = { git = "https://github.com/esp-rs/esp-idf-sys" } - [features] default = ["std", "binstart"] @@ -52,18 +47,18 @@ log = { version = "0.4", default-features = false } uncased = { version = "0.9.7", default-features = false } embedded-hal-async = { version = "1", default-features = false } embedded-svc = { version = "0.28", default-features = false } -esp-idf-hal = { version = "0.44", default-features = false } +esp-idf-hal = { version = "0.45", default-features = false } embassy-time-driver = { version = "0.1", optional = true, features = ["tick-hz-1_000_000"] } embassy-futures = "0.1" embedded-storage = { version = "0.3", optional = true } futures-io = { version = "0.3", optional = true } [build-dependencies] -embuild = "0.32" +embuild = "0.33" [dev-dependencies] anyhow = "1" -esp-idf-sys = { version = "0.35", features = ["binstart"] } +esp-idf-sys = { version = "0.36", features = ["binstart"] } futures = "0.3" serde = { version = "1", default-features = false, features = ["derive"] } serde_json = { version = "1", default-features = false, features = ["alloc"] } diff --git a/examples/stdin_read.rs b/examples/stdin_read.rs new file mode 100644 index 00000000000..bace7f429e9 --- /dev/null +++ b/examples/stdin_read.rs @@ -0,0 +1,52 @@ +//! A simple example of how to read from the ESP-IDF console + +use esp_idf_hal::gpio::AnyIOPin; +use esp_idf_svc::hal::peripherals::Peripherals; +use esp_idf_svc::hal::uart::UartDriver; +use esp_idf_svc::io::vfs::BlockingStdIo; +use esp_idf_svc::sys::EspError; + +use std::io::Write; + +fn main() -> Result<(), EspError> { + esp_idf_svc::sys::link_patches(); + esp_idf_svc::log::EspLogger::initialize_default(); + + // NOTE: This example assumes that the console configuration is not altered by the user + // by using non-default `CONFIG_ESP_CONSOLE_*` settings in `sdkconfig.defaults` + // + // The default configuration is: + // - UART0 + // - 115200 baud rate + // - 8N1 + // - RTS/CTS disabled + // - No flow control + // - The default TX/RX pins for UART0 (1 & 3 for ESP32, 17 & 16 for ESP32-S2 and so on.) + + let peripherals = Peripherals::take()?; + + let uart_driver = UartDriver::new( + peripherals.uart0, + // Change this to the correct UART0 TX pin for your MCU if you are not using esp32 + peripherals.pins.gpio1, + // Change this to the correct UART0 RX pin for your MCU if you are not using esp32 + peripherals.pins.gpio3, + Option::::None, + Option::::None, + &Default::default(), + )?; + + // Keep it around till the end of your program + // If you drop it, the console will go back to non-blocking UART mode + let _blocking_io = BlockingStdIo::uart(uart_driver)?; + + loop { + print!("Enter a message: "); + std::io::stdout().flush().unwrap(); + + let mut buffer = String::new(); + std::io::stdin().read_line(&mut buffer).unwrap(); + + println!("You entered: {}", buffer); + } +} diff --git a/src/bt.rs b/src/bt.rs index 031e7bc13cc..45eddb258e4 100644 --- a/src/bt.rs +++ b/src/bt.rs @@ -685,7 +685,8 @@ where #[cfg(esp32c2)] version_num: unsafe { crate::sys::esp_ble_get_chip_rev_version() }, #[cfg(esp32c6)] - version_num: unsafe { crate::sys::efuse_hal_chip_revision() }, + #[allow(clippy::unnecessary_cast)] + version_num: unsafe { crate::sys::efuse_hal_chip_revision() as _ }, #[cfg(not(esp32c2))] cpu_freq_mhz: crate::sys::CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ as _, ignore_wl_for_direct_adv: 0, diff --git a/src/eth.rs b/src/eth.rs index 41ae3f8578d..6ef219c001d 100644 --- a/src/eth.rs +++ b/src/eth.rs @@ -1032,6 +1032,29 @@ impl<'d, T> EthDriver<'d, T> { Ok(()) } + /// Enables or disables promiscuous mode for the [`EthDriver`]. + /// + /// When promiscuous mode is enabled, the driver captures all Ethernet frames + /// on the network, regardless of their destination MAC address. This is useful for + /// debugging or monitoring purposes. + pub fn set_promiscuous(&mut self, state: bool) -> Result<(), EspError> { + esp!(unsafe { + esp_eth_ioctl( + self.handle(), + esp_eth_io_cmd_t_ETH_CMD_S_PROMISCUOUS, + &raw const state as *mut _, + ) + })?; + + if state { + log::info!("Driver set in promiscuous mode"); + } else { + log::info!("Driver set in non-promiscuous mode"); + } + + Ok(()) + } + fn eth_default_config(mac: *mut esp_eth_mac_t, phy: *mut esp_eth_phy_t) -> esp_eth_config_t { esp_eth_config_t { mac, @@ -1071,7 +1094,7 @@ impl<'d, T> EthDriver<'d, T> { fn eth_mac_default_config(_mdc: i32, _mdio: i32) -> eth_mac_config_t { eth_mac_config_t { sw_reset_timeout_ms: 100, - rx_task_stack_size: 2048, + rx_task_stack_size: 4096, rx_task_prio: 15, flags: 0, } diff --git a/src/http/server.rs b/src/http/server.rs index 82b9e8914df..1324d6eb4e2 100644 --- a/src/http/server.rs +++ b/src/http/server.rs @@ -35,6 +35,10 @@ use core::cell::UnsafeCell; use core::fmt::Debug; use core::marker::PhantomData; +#[cfg(esp_idf_lwip_ipv4)] +use core::net::Ipv4Addr; +#[cfg(esp_idf_lwip_ipv6)] +use core::net::Ipv6Addr; use core::sync::atomic::{AtomicBool, Ordering}; use core::time::*; use core::{ffi, ptr}; @@ -801,6 +805,62 @@ impl EspHttpRawConnection<'_> { Ok(()) } + + /// Retrieves the source IPv4 of the request. + /// + /// The IPv4 is retrieved using the underlying session socket. + #[cfg(esp_idf_lwip_ipv4)] + pub fn source_ipv4(&self) -> Result { + unsafe { + let sockfd = httpd_req_to_sockfd(self.handle()); + + if sockfd == -1 { + return Err(EspError::from_infallible::()); + } + + let mut addr = sockaddr_in { + sin_len: core::mem::size_of::() as _, + sin_family: AF_INET as _, + ..Default::default() + }; + + esp!(lwip_getpeername( + sockfd, + &mut addr as *mut _ as *mut _, + &mut core::mem::size_of::() as *mut _ as *mut _, + ))?; + + Ok(Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr))) + } + } + + /// Retrieves the source IPv6 of the request. + /// + /// The IPv6 is retrieved using the underlying session socket. + #[cfg(esp_idf_lwip_ipv6)] + pub fn source_ipv6(&self) -> Result { + unsafe { + let sockfd = httpd_req_to_sockfd(self.handle()); + + if sockfd == -1 { + return Err(EspError::from_infallible::()); + } + + let mut addr = sockaddr_in6 { + sin6_len: core::mem::size_of::() as _, + sin6_family: AF_INET6 as _, + ..Default::default() + }; + + esp!(lwip_getpeername( + sockfd, + &mut addr as *mut _ as *mut _, + &mut core::mem::size_of::() as *mut _ as *mut _, + ))?; + + Ok(Ipv6Addr::from(addr.sin6_addr.un.u8_addr)) + } + } } impl RawHandle for EspHttpRawConnection<'_> { diff --git a/src/io.rs b/src/io.rs index 30251369338..fd1196902a1 100644 --- a/src/io.rs +++ b/src/io.rs @@ -3,7 +3,17 @@ pub use esp_idf_hal::io::*; #[cfg(esp_idf_comp_vfs_enabled)] pub mod vfs { - use crate::sys; + use core::borrow::BorrowMut; + use core::marker::PhantomData; + + use crate::hal::uart::UartDriver; + #[cfg(esp_idf_soc_usb_serial_jtag_supported)] + use crate::hal::usb_serial::UsbSerialDriver; + use crate::sys::{ + self, esp_vfs_dev_uart_use_driver, esp_vfs_dev_uart_use_nonblocking, EspError, + }; + #[cfg(esp_idf_soc_usb_serial_jtag_supported)] + use crate::sys::{esp_vfs_usb_serial_jtag_use_driver, esp_vfs_usb_serial_jtag_use_nonblocking}; #[cfg(all(feature = "experimental", feature = "alloc"))] extern crate alloc; @@ -258,4 +268,82 @@ pub mod vfs { } } } + + /// A utility for setting up a buffered and blocking communication for the Rust `stdio` subsystem. + /// + /// By default, all communication via `std::io:stdin` / `std::io::stdout` on the ESP-IDF is non-blocking. + /// One consequence of this, is that if the user wants to read from `std::io::stdin`, she has to constantly + /// poll the driver, since the respective hardware FIFO buffers are relatively small-ish. + /// Also the user would have to handle `WouldBlock` errors on every call, which is not very ergonomic. + /// + /// Instantiating the `BlockingStdIo` instructs the ESP-IDF VFS (Virtual File System) to use the + /// interrupt-driven drivers instead, as well as their blocking read / write functions. + pub struct BlockingStdIo<'d, T> { + uart_port: Option, + _driver: T, + _t: PhantomData<&'d mut ()>, + } + + impl<'d, T> BlockingStdIo<'d, T> + where + T: BorrowMut>, + { + /// Create a `BlockingStdIo` instance for a UART driver + /// + /// Arguments: + /// - `driver`: The UART driver to use (i.e. a `UartDriver` instance that can be mutably borrowed) + pub fn uart(driver: T) -> Result { + unsafe { esp_vfs_dev_uart_use_driver(driver.borrow().port() as _) } + + Ok(Self { + uart_port: Some(driver.borrow().port()), + _driver: driver, + _t: PhantomData, + }) + } + } + + #[cfg(esp_idf_soc_usb_serial_jtag_supported)] + impl<'d, T> BlockingStdIo<'d, T> + where + T: BorrowMut>, + { + /// Create a `BlockingStdIo` instance for a USB-SERIAL driver + /// + /// NOTE: By default, `println!` and `log!` output will be redirected to it in case + /// no UART connection is established to a Host PC. The peripheral is initialized at + /// startup and is using the ESP console slot 2 by default. + /// + /// NOTE: ESP console slot 2 cannot be used to read from the HOST, only writing is supported. + /// If reading from the HOST is necessary, reconfigure the ESP console by setting + /// the following into your projects sdkconfig.default file: + /// ``` + /// CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y + /// ``` + /// + /// Arguments: + /// - `driver`: The USB-SERIAL driver to use (i.e. a `UsbSerialDriver` instance that can be mutably borrowed) + pub fn usb_serial(driver: T) -> Result { + unsafe { esp_vfs_usb_serial_jtag_use_driver() } + + Ok(Self { + uart_port: None, + _driver: driver, + _t: PhantomData, + }) + } + } + + impl Drop for BlockingStdIo<'_, T> { + fn drop(&mut self) { + if let Some(port) = self.uart_port { + unsafe { esp_vfs_dev_uart_use_nonblocking(port as _) } + } else { + #[cfg(esp_idf_soc_usb_serial_jtag_supported)] + { + unsafe { esp_vfs_usb_serial_jtag_use_nonblocking() } + } + } + } + } } diff --git a/src/nvs.rs b/src/nvs.rs index 67d44952226..d69236a2e22 100644 --- a/src/nvs.rs +++ b/src/nvs.rs @@ -33,27 +33,33 @@ pub trait NvsPartitionId { pub struct NvsDefault(()); impl NvsDefault { - fn new() -> Result { + fn new(reinit: bool) -> Result { let mut taken = DEFAULT_TAKEN.lock(); if *taken { return Err(EspError::from_infallible::()); } - let default_nvs = Self::init()?; + let default_nvs = Self::init(reinit)?; *taken = true; Ok(default_nvs) } - fn init() -> Result { + fn init(reinit: bool) -> Result { if let Some(err) = EspError::from(unsafe { nvs_flash_init() }) { match err.code() { - ESP_ERR_NVS_NO_FREE_PAGES | ESP_ERR_NVS_NEW_VERSION_FOUND => { + ESP_ERR_NVS_NO_FREE_PAGES | ESP_ERR_NVS_NEW_VERSION_FOUND if reinit => { + if err.code() == ESP_ERR_NVS_NEW_VERSION_FOUND { + warn!("NVS partition has a new version, erasing and re-initializing the partition"); + } else { + warn!("NVS partition has no free pages, erasing and re-initializing the partition"); + } + esp!(unsafe { nvs_flash_erase() })?; esp!(unsafe { nvs_flash_init() })?; } - _ => (), + _ => Err(err)?, } } @@ -219,8 +225,17 @@ impl NvsPartitionId for NvsEncrypted { pub struct EspNvsPartition(Arc); impl EspNvsPartition { + /// Take the default NVS partition, initializing it if full or if a new version is detected pub fn take() -> Result { - Ok(Self(Arc::new(NvsDefault::new()?))) + Self::take_with(true) + } + + /// Take the default NVS partition + /// + /// # Arguments + /// - `reinit`: Whether to reinitialize the partition if full or if a new version is detected + pub fn take_with(reinit: bool) -> Result { + Ok(Self(Arc::new(NvsDefault::new(reinit)?))) } } diff --git a/src/tls.rs b/src/tls.rs index 0efcaf0a7d5..1f6d5a8e320 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -240,14 +240,25 @@ mod esptls { rcfg.keep_alive_cfg = &mut raw_kac as *mut _; } - let mut raw_psk: sys::psk_key_hint; - if let Some(psk) = &self.psk_hint_key { - raw_psk = sys::psk_key_hint { - key: psk.key.as_ptr(), - key_size: psk.key.len(), - hint: psk.hint.as_ptr(), - }; - rcfg.psk_hint_key = &mut raw_psk as *mut _; + #[cfg(any( + esp_idf_esp_tls_psk_verification, + esp_idf_version_major = "4", + esp_idf_version = "5.0", + esp_idf_version = "5.1", + esp_idf_version = "5.2", + esp_idf_version = "5.3", + esp_idf_version = "5.4", + ))] + { + let mut raw_psk: sys::psk_key_hint; + if let Some(psk) = &self.psk_hint_key { + raw_psk = sys::psk_key_hint { + key: psk.key.as_ptr(), + key_size: psk.key.len(), + hint: psk.hint.as_ptr(), + }; + rcfg.psk_hint_key = &mut raw_psk as *mut _; + } } #[cfg(esp_idf_mbedtls_certificate_bundle)] diff --git a/src/wifi.rs b/src/wifi.rs index 551365459dc..27f6b8898ad 100644 --- a/src/wifi.rs +++ b/src/wifi.rs @@ -1192,6 +1192,37 @@ impl<'d> WifiDriver<'d> { Ok(()) } + /// Enables or disables promiscuous mode for the [`WifiDriver`]. + /// + /// When promiscuous mode is enabled, the driver captures all Wifi frames + /// on the network, regardless of their destination MAC address. This is useful for + /// debugging or monitoring purposes. + pub fn set_promiscuous(&mut self, state: bool) -> Result<(), EspError> { + esp!(unsafe { esp_wifi_set_promiscuous(state) })?; + + if state { + log::info!("Driver set in promiscuous mode"); + } else { + log::info!("Driver set in non-promiscuous mode"); + } + + Ok(()) + } + + /// Gets the state of the promiscuous mode for the [`WifiDriver`]. + pub fn is_promiscuous(&self) -> Result { + let mut en: bool = false; + + esp!(unsafe { esp_wifi_get_promiscuous(&mut en) })?; + + Ok(en) + } + + //TODO: add safe wrappers for these three functions + //https://docs.esp-rs.org/esp-idf-sys/esp_idf_sys/fn.esp_wifi_set_promiscuous_ctrl_filter.html + //https://docs.esp-rs.org/esp-idf-sys/esp_idf_sys/fn.esp_wifi_set_promiscuous_filter.html + //https://docs.esp-rs.org/esp-idf-sys/esp_idf_sys/fn.esp_wifi_set_promiscuous_rx_cb.html + /// Gets the WPS status as a [`WPS Event`] and disables WPS. fn stop_wps(&mut self) -> Result { let mut status = self.status.lock();