From 55be30526ad6401060b1255d365effe3b50314fd Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Fri, 2 Feb 2024 16:08:05 +0100 Subject: [PATCH 1/3] Make embedded-svc really optional --- Cargo.toml | 3 +- esp-wifi/Cargo.toml | 4 +- esp-wifi/automated-tests/open_access_point.rs | 23 +- esp-wifi/automated-tests/test_ble.rs | 3 +- esp-wifi/automated-tests/test_connect.rs | 23 +- esp-wifi/examples/access_point.rs | 23 +- esp-wifi/examples/access_point_with_sta.rs | 23 +- esp-wifi/examples/bench.rs | 3 +- esp-wifi/examples/ble.rs | 3 +- esp-wifi/examples/coex.rs | 3 +- esp-wifi/examples/dhcp.rs | 3 +- esp-wifi/examples/embassy_access_point.rs | 2 +- .../examples/embassy_access_point_with_sta.rs | 2 +- esp-wifi/examples/embassy_bench.rs | 2 +- esp-wifi/examples/embassy_ble.rs | 6 +- esp-wifi/examples/embassy_dhcp.rs | 2 +- esp-wifi/examples/static_ip.rs | 23 +- esp-wifi/src/ble/npl.rs | 14 +- esp-wifi/src/common_adapter/mod.rs | 4 +- esp-wifi/src/compat/common.rs | 8 +- esp-wifi/src/esp_now/mod.rs | 22 +- esp-wifi/src/lib.rs | 5 +- esp-wifi/src/preempt/preempt_riscv.rs | 3 +- esp-wifi/src/wifi/mod.rs | 1040 ++++++++++++++++- esp-wifi/src/wifi/os_adapter.rs | 6 +- esp-wifi/src/wifi_interface.rs | 17 +- 26 files changed, 1126 insertions(+), 144 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9090f7c4..71c26794 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ portable-atomic = { version = "1.5", default-features = false } portable_atomic_enum = { version = "0.3.0", features = ["portable-atomic"] } log = "0.4.20" embedded-svc = { version = "0.27.0", default-features = false, features = [] } +no-std-net = "0.6.0" enumset = { version = "1.1.3", default-features = false } linked_list_allocator = { version = "0.10.5", default-features = false, features = [ "const_mut_refs", @@ -51,7 +52,7 @@ embassy-net = { version = "0.4.0", features = [ "dhcpv4", "medium-ethernet", ] } -bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "0db8fcb", features = [ +bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "be90de7", features = [ "macros", ] } embassy-executor = { version = "0.5.0", package = "embassy-executor", features = [ diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index 3db54343..ee6401aa 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -42,6 +42,7 @@ fugit.workspace = true heapless = { workspace = true, default-features = false } num-derive = { workspace = true } num-traits = { workspace = true, default-features = false } +no-std-net = { workspace = true, optional = true } esp-wifi-sys = { version = "0.3.0", path = "../esp-wifi-sys" } embassy-sync = { workspace = true, optional = true } embassy-futures = { workspace = true, optional = true } @@ -115,7 +116,8 @@ dump-packets = [] smoltcp = [ "dep:smoltcp" ] utils = [ "smoltcp" ] enumset = [] -wifi = [ "dep:enumset", "dep:embedded-svc" ] +wifi = [ "dep:enumset", "dep:no-std-net" ] +embedded-svc = [ "dep:embedded-svc" ] ble = [ "esp32-hal?/bluetooth" ] phy-enable-usb = [] ps-min-modem = [] diff --git a/esp-wifi/automated-tests/open_access_point.rs b/esp-wifi/automated-tests/open_access_point.rs index 64079ea9..af8a5478 100644 --- a/esp-wifi/automated-tests/open_access_point.rs +++ b/esp-wifi/automated-tests/open_access_point.rs @@ -6,8 +6,7 @@ mod examples_util; use examples_util::hal; use embedded_io::*; -use embedded_svc::ipv4::Interface; -use embedded_svc::wifi::{AccessPointConfiguration, Configuration, Wifi}; +use esp_wifi::wifi::{AccessPointConfiguration, Configuration}; use esp_backtrace as _; use esp_println::println; @@ -64,16 +63,18 @@ fn main() -> ! { println!("{:?}", controller.get_capabilities()); wifi_stack - .set_iface_configuration(&embedded_svc::ipv4::Configuration::Client( - embedded_svc::ipv4::ClientConfiguration::Fixed(embedded_svc::ipv4::ClientSettings { - ip: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - subnet: embedded_svc::ipv4::Subnet { - gateway: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - mask: embedded_svc::ipv4::Mask(24), + .set_iface_configuration(&esp_wifi::wifi::ipv4::Configuration::Client( + esp_wifi::wifi::ipv4::ClientConfiguration::Fixed( + esp_wifi::wifi::ipv4::ClientSettings { + ip: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + subnet: esp_wifi::wifi::ipv4::Subnet { + gateway: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + mask: esp_wifi::wifi::ipv4::Mask(24), + }, + dns: None, + secondary_dns: None, }, - dns: None, - secondary_dns: None, - }), + ), )) .unwrap(); diff --git a/esp-wifi/automated-tests/test_ble.rs b/esp-wifi/automated-tests/test_ble.rs index 6b50d457..4c245d3f 100644 --- a/esp-wifi/automated-tests/test_ble.rs +++ b/esp-wifi/automated-tests/test_ble.rs @@ -85,7 +85,8 @@ fn main() -> ! { },], },]); - let mut srv = AttributeServer::new(&mut ble, &mut gatt_attributes); + let mut rng = bleps::no_rng::NoRng; + let mut srv = AttributeServer::new(&mut ble, &mut gatt_attributes, &mut rng); loop { match srv.do_work_with_notification(None) { diff --git a/esp-wifi/automated-tests/test_connect.rs b/esp-wifi/automated-tests/test_connect.rs index 11e4c0b7..776e62ef 100644 --- a/esp-wifi/automated-tests/test_connect.rs +++ b/esp-wifi/automated-tests/test_connect.rs @@ -6,8 +6,7 @@ mod examples_util; use examples_util::hal; use embedded_io::*; -use embedded_svc::ipv4::Interface; -use embedded_svc::wifi::{AccessPointInfo, AuthMethod, ClientConfiguration, Configuration, Wifi}; +use esp_wifi::wifi::{AccessPointInfo, AuthMethod, ClientConfiguration, Configuration}; use esp_backtrace as _; use esp_println::println; @@ -136,16 +135,18 @@ fn main() -> ! { println!("Setting static IP {}", STATIC_IP); wifi_stack - .set_iface_configuration(&embedded_svc::ipv4::Configuration::Client( - embedded_svc::ipv4::ClientConfiguration::Fixed(embedded_svc::ipv4::ClientSettings { - ip: embedded_svc::ipv4::Ipv4Addr::from(parse_ip(STATIC_IP)), - subnet: embedded_svc::ipv4::Subnet { - gateway: embedded_svc::ipv4::Ipv4Addr::from(parse_ip(GATEWAY_IP)), - mask: embedded_svc::ipv4::Mask(24), + .set_iface_configuration(&esp_wifi::wifi::ipv4::Configuration::Client( + esp_wifi::wifi::ipv4::ClientConfiguration::Fixed( + esp_wifi::wifi::ipv4::ClientSettings { + ip: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip(STATIC_IP)), + subnet: esp_wifi::wifi::ipv4::Subnet { + gateway: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip(GATEWAY_IP)), + mask: esp_wifi::wifi::ipv4::Mask(24), + }, + dns: None, + secondary_dns: None, }, - dns: None, - secondary_dns: None, - }), + ), )) .unwrap(); diff --git a/esp-wifi/examples/access_point.rs b/esp-wifi/examples/access_point.rs index de16c8ce..537b0fd0 100644 --- a/esp-wifi/examples/access_point.rs +++ b/esp-wifi/examples/access_point.rs @@ -6,8 +6,7 @@ mod examples_util; use examples_util::hal; use embedded_io::*; -use embedded_svc::ipv4::Interface; -use embedded_svc::wifi::{AccessPointConfiguration, Configuration, Wifi}; +use esp_wifi::wifi::{AccessPointConfiguration, Configuration}; use esp_backtrace as _; use esp_println::{print, println}; @@ -64,16 +63,18 @@ fn main() -> ! { println!("{:?}", controller.get_capabilities()); wifi_stack - .set_iface_configuration(&embedded_svc::ipv4::Configuration::Client( - embedded_svc::ipv4::ClientConfiguration::Fixed(embedded_svc::ipv4::ClientSettings { - ip: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - subnet: embedded_svc::ipv4::Subnet { - gateway: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - mask: embedded_svc::ipv4::Mask(24), + .set_iface_configuration(&esp_wifi::wifi::ipv4::Configuration::Client( + esp_wifi::wifi::ipv4::ClientConfiguration::Fixed( + esp_wifi::wifi::ipv4::ClientSettings { + ip: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + subnet: esp_wifi::wifi::ipv4::Subnet { + gateway: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + mask: esp_wifi::wifi::ipv4::Mask(24), + }, + dns: None, + secondary_dns: None, }, - dns: None, - secondary_dns: None, - }), + ), )) .unwrap(); diff --git a/esp-wifi/examples/access_point_with_sta.rs b/esp-wifi/examples/access_point_with_sta.rs index e2d69a4a..92637646 100644 --- a/esp-wifi/examples/access_point_with_sta.rs +++ b/esp-wifi/examples/access_point_with_sta.rs @@ -6,8 +6,7 @@ mod examples_util; use examples_util::hal; use embedded_io::*; -use embedded_svc::ipv4::Interface; -use embedded_svc::wifi::{AccessPointConfiguration, ClientConfiguration, Configuration, Wifi}; +use esp_wifi::wifi::{AccessPointConfiguration, ClientConfiguration, Configuration}; use esp_backtrace as _; use esp_println::{print, println}; @@ -93,16 +92,18 @@ fn main() -> ! { println!("{:?}", controller.get_capabilities()); wifi_ap_stack - .set_iface_configuration(&embedded_svc::ipv4::Configuration::Client( - embedded_svc::ipv4::ClientConfiguration::Fixed(embedded_svc::ipv4::ClientSettings { - ip: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - subnet: embedded_svc::ipv4::Subnet { - gateway: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - mask: embedded_svc::ipv4::Mask(24), + .set_iface_configuration(&esp_wifi::wifi::ipv4::Configuration::Client( + esp_wifi::wifi::ipv4::ClientConfiguration::Fixed( + esp_wifi::wifi::ipv4::ClientSettings { + ip: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + subnet: esp_wifi::wifi::ipv4::Subnet { + gateway: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + mask: esp_wifi::wifi::ipv4::Mask(24), + }, + dns: None, + secondary_dns: None, }, - dns: None, - secondary_dns: None, - }), + ), )) .unwrap(); diff --git a/esp-wifi/examples/bench.rs b/esp-wifi/examples/bench.rs index 202ba68c..bc6eecd7 100644 --- a/esp-wifi/examples/bench.rs +++ b/esp-wifi/examples/bench.rs @@ -6,8 +6,7 @@ mod examples_util; use examples_util::hal; use embedded_io::*; -use embedded_svc::ipv4::Interface; -use embedded_svc::wifi::{AccessPointInfo, ClientConfiguration, Configuration, Wifi}; +use esp_wifi::wifi::{AccessPointInfo, ClientConfiguration, Configuration}; use esp_backtrace as _; use esp_println::println; diff --git a/esp-wifi/examples/ble.rs b/esp-wifi/examples/ble.rs index 1fe30d19..78563fab 100644 --- a/esp-wifi/examples/ble.rs +++ b/esp-wifi/examples/ble.rs @@ -118,7 +118,8 @@ fn main() -> ! { ], },]); - let mut srv = AttributeServer::new(&mut ble, &mut gatt_attributes); + let mut rng = bleps::no_rng::NoRng; + let mut srv = AttributeServer::new(&mut ble, &mut gatt_attributes, &mut rng); loop { let mut notification = None; diff --git a/esp-wifi/examples/coex.rs b/esp-wifi/examples/coex.rs index 453a13e3..46cbde1e 100644 --- a/esp-wifi/examples/coex.rs +++ b/esp-wifi/examples/coex.rs @@ -19,8 +19,7 @@ use esp_wifi::{ }; use embedded_io::*; -use embedded_svc::ipv4::Interface; -use embedded_svc::wifi::{ClientConfiguration, Configuration, Wifi}; +use esp_wifi::wifi::{ClientConfiguration, Configuration}; use esp_backtrace as _; use esp_println::{print, println}; diff --git a/esp-wifi/examples/dhcp.rs b/esp-wifi/examples/dhcp.rs index 223c4a8e..6da1f4ad 100644 --- a/esp-wifi/examples/dhcp.rs +++ b/esp-wifi/examples/dhcp.rs @@ -6,8 +6,7 @@ mod examples_util; use examples_util::hal; use embedded_io::*; -use embedded_svc::ipv4::Interface; -use embedded_svc::wifi::{AccessPointInfo, ClientConfiguration, Configuration, Wifi}; +use esp_wifi::wifi::{AccessPointInfo, ClientConfiguration, Configuration}; use esp_backtrace as _; use esp_println::{print, println}; diff --git a/esp-wifi/examples/embassy_access_point.rs b/esp-wifi/examples/embassy_access_point.rs index a4832f84..c74a95ff 100644 --- a/esp-wifi/examples/embassy_access_point.rs +++ b/esp-wifi/examples/embassy_access_point.rs @@ -12,9 +12,9 @@ use examples_util::hal; use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; -use embedded_svc::wifi::{AccessPointConfiguration, Configuration, Wifi}; use esp_backtrace as _; use esp_println::{print, println}; +use esp_wifi::wifi::{AccessPointConfiguration, Configuration}; use esp_wifi::wifi::{WifiApDevice, WifiController, WifiDevice, WifiEvent, WifiState}; use esp_wifi::{initialize, EspWifiInitFor}; use hal::clock::ClockControl; diff --git a/esp-wifi/examples/embassy_access_point_with_sta.rs b/esp-wifi/examples/embassy_access_point_with_sta.rs index 4e0ebb86..ecfaf8b5 100644 --- a/esp-wifi/examples/embassy_access_point_with_sta.rs +++ b/esp-wifi/examples/embassy_access_point_with_sta.rs @@ -12,9 +12,9 @@ use examples_util::hal; use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; -use embedded_svc::wifi::{AccessPointConfiguration, ClientConfiguration, Configuration, Wifi}; use esp_backtrace as _; use esp_println::{print, println}; +use esp_wifi::wifi::{AccessPointConfiguration, ClientConfiguration, Configuration}; use esp_wifi::wifi::{ WifiApDevice, WifiController, WifiDevice, WifiEvent, WifiStaDevice, WifiState, }; diff --git a/esp-wifi/examples/embassy_bench.rs b/esp-wifi/examples/embassy_bench.rs index 07c7cb5a..13d1a78f 100644 --- a/esp-wifi/examples/embassy_bench.rs +++ b/esp-wifi/examples/embassy_bench.rs @@ -11,9 +11,9 @@ mod examples_util; use examples_util::hal; use embassy_time::{with_timeout, Duration, Timer}; -use embedded_svc::wifi::{ClientConfiguration, Configuration, Wifi}; use esp_backtrace as _; use esp_println::println; +use esp_wifi::wifi::{ClientConfiguration, Configuration}; use esp_wifi::wifi::{WifiApDevice, WifiController, WifiDevice, WifiEvent, WifiState}; use esp_wifi::{initialize, EspWifiInitFor}; use hal::clock::ClockControl; diff --git a/esp-wifi/examples/embassy_ble.rs b/esp-wifi/examples/embassy_ble.rs index d0be56f9..e33b33b6 100644 --- a/esp-wifi/examples/embassy_ble.rs +++ b/esp-wifi/examples/embassy_ble.rs @@ -75,6 +75,7 @@ async fn main(_spawner: Spawner) -> ! { println!("Connector created"); let pin_ref = RefCell::new(button); + let pin_ref = &pin_ref; loop { println!("{:?}", ble.init().await); @@ -137,9 +138,12 @@ async fn main(_spawner: Spawner) -> ! { ], },]); - let mut srv = AttributeServer::new(&mut ble, &mut gatt_attributes); + let mut rng = bleps::no_rng::NoRng; + let mut srv = AttributeServer::new(&mut ble, &mut gatt_attributes, &mut rng); let counter = RefCell::new(0u8); + let counter = &counter; + let mut notifier = async || { // TODO how to check if notifications are enabled for the characteristic? // maybe pass something into the closure which just can query the characterisic value diff --git a/esp-wifi/examples/embassy_dhcp.rs b/esp-wifi/examples/embassy_dhcp.rs index ca8697d9..c069c9ce 100644 --- a/esp-wifi/examples/embassy_dhcp.rs +++ b/esp-wifi/examples/embassy_dhcp.rs @@ -10,9 +10,9 @@ mod examples_util; use examples_util::hal; use embassy_time::{Duration, Timer}; -use embedded_svc::wifi::{ClientConfiguration, Configuration, Wifi}; use esp_backtrace as _; use esp_println::println; +use esp_wifi::wifi::{ClientConfiguration, Configuration}; use esp_wifi::wifi::{WifiController, WifiDevice, WifiEvent, WifiStaDevice, WifiState}; use esp_wifi::{initialize, EspWifiInitFor}; use hal::clock::ClockControl; diff --git a/esp-wifi/examples/static_ip.rs b/esp-wifi/examples/static_ip.rs index 86e5a100..284f0388 100644 --- a/esp-wifi/examples/static_ip.rs +++ b/esp-wifi/examples/static_ip.rs @@ -6,8 +6,7 @@ mod examples_util; use examples_util::hal; use embedded_io::*; -use embedded_svc::ipv4::Interface; -use embedded_svc::wifi::{AccessPointInfo, ClientConfiguration, Configuration, Wifi}; +use esp_wifi::wifi::{AccessPointInfo, ClientConfiguration, Configuration}; use esp_backtrace as _; use esp_println::{print, println}; @@ -99,16 +98,18 @@ fn main() -> ! { println!("Setting static IP {}", STATIC_IP); wifi_stack - .set_iface_configuration(&embedded_svc::ipv4::Configuration::Client( - embedded_svc::ipv4::ClientConfiguration::Fixed(embedded_svc::ipv4::ClientSettings { - ip: embedded_svc::ipv4::Ipv4Addr::from(parse_ip(STATIC_IP)), - subnet: embedded_svc::ipv4::Subnet { - gateway: embedded_svc::ipv4::Ipv4Addr::from(parse_ip(GATEWAY_IP)), - mask: embedded_svc::ipv4::Mask(24), + .set_iface_configuration(&esp_wifi::wifi::ipv4::Configuration::Client( + esp_wifi::wifi::ipv4::ClientConfiguration::Fixed( + esp_wifi::wifi::ipv4::ClientSettings { + ip: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip(STATIC_IP)), + subnet: esp_wifi::wifi::ipv4::Subnet { + gateway: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip(GATEWAY_IP)), + mask: esp_wifi::wifi::ipv4::Mask(24), + }, + dns: None, + secondary_dns: None, }, - dns: None, - secondary_dns: None, - }), + ), )) .unwrap(); diff --git a/esp-wifi/src/ble/npl.rs b/esp-wifi/src/ble/npl.rs index 5b09a4aa..bc05d396 100644 --- a/esp-wifi/src/ble/npl.rs +++ b/esp-wifi/src/ble/npl.rs @@ -1040,7 +1040,7 @@ pub(crate) fn ble_init() { ble_os_adapter_chip_specific::disable_sleep_mode(); - let res = esp_register_npl_funcs(&G_NPL_FUNCS as *const npl_funcs_t); + let res = esp_register_npl_funcs(core::ptr::addr_of!(G_NPL_FUNCS)); if res != 0 { panic!("esp_register_npl_funcs returned {}", res); } @@ -1180,8 +1180,8 @@ fn os_msys_init() { let rc = r_mem_init_mbuf_pool( OS_MSYS_INIT_1_DATA as *const c_void, - &OS_MSYS_INIT_1_MEMPOOL, - &OS_MSYS_INIT_1_MBUF_POOL, + addr_of!(OS_MSYS_INIT_1_MEMPOOL), + addr_of!(OS_MSYS_INIT_1_MBUF_POOL), OS_MSYS_1_BLOCK_COUNT, SYSINIT_MSYS_1_MEMBLOCK_SIZE, MSYS1 as *const _ as *const u8, @@ -1190,15 +1190,15 @@ fn os_msys_init() { panic!("r_mem_init_mbuf_pool failed"); } - let rc = r_os_msys_register(&OS_MSYS_INIT_1_MBUF_POOL); + let rc = r_os_msys_register(addr_of!(OS_MSYS_INIT_1_MBUF_POOL)); if rc != 0 { panic!("r_os_msys_register failed"); } let rc = r_mem_init_mbuf_pool( OS_MSYS_INIT_2_DATA as *const c_void, - &OS_MSYS_INIT_2_MEMPOOL, - &OS_MSYS_INIT_2_MBUF_POOL, + addr_of!(OS_MSYS_INIT_2_MEMPOOL), + addr_of!(OS_MSYS_INIT_2_MBUF_POOL), OS_MSYS_2_BLOCK_COUNT, SYSINIT_MSYS_2_MEMBLOCK_SIZE, MSYS2 as *const _ as *const u8, @@ -1207,7 +1207,7 @@ fn os_msys_init() { panic!("r_mem_init_mbuf_pool failed"); } - let rc = r_os_msys_register(&OS_MSYS_INIT_2_MBUF_POOL); + let rc = r_os_msys_register(addr_of!(OS_MSYS_INIT_2_MBUF_POOL)); if rc != 0 { panic!("r_os_msys_register failed"); } diff --git a/esp-wifi/src/common_adapter/mod.rs b/esp-wifi/src/common_adapter/mod.rs index 12b9c111..3c5e91ae 100644 --- a/esp-wifi/src/common_adapter/mod.rs +++ b/esp-wifi/src/common_adapter/mod.rs @@ -1,3 +1,5 @@ +use core::ptr::addr_of; + use crate::binary::include::esp_event_base_t; use crate::binary::include::esp_timer_create_args_t; use crate::binary::include::esp_timer_get_time; @@ -266,7 +268,7 @@ pub unsafe extern "C" fn pp_printf(s: *const u8, args: ...) { // #define ESP_EVENT_DEFINE_BASE(id) esp_event_base_t id = #id static mut EVT: i8 = 0; #[no_mangle] -static mut WIFI_EVENT: esp_event_base_t = unsafe { &EVT }; +static mut WIFI_EVENT: esp_event_base_t = unsafe { addr_of!(EVT) }; // stuff needed by wpa-supplicant #[no_mangle] diff --git a/esp-wifi/src/compat/common.rs b/esp-wifi/src/compat/common.rs index b2c78f62..9e2ab879 100644 --- a/esp-wifi/src/compat/common.rs +++ b/esp-wifi/src/compat/common.rs @@ -1,6 +1,10 @@ #![allow(unused)] -use core::{ffi::VaListImpl, fmt::Write, ptr::addr_of_mut}; +use core::{ + ffi::VaListImpl, + fmt::Write, + ptr::{addr_of, addr_of_mut}, +}; use super::queue::SimpleQueue; use crate::{ @@ -34,7 +38,7 @@ static mut MUTEXES: [Mutex; 10] = [Mutex { }; 10]; static mut MUTEX_IDX_CURRENT: usize = 0; -static mut FAKE_WIFI_QUEUE: &SimpleQueue<[u8; 8], 200> = unsafe { &REAL_WIFI_QUEUE }; +static mut FAKE_WIFI_QUEUE: *const SimpleQueue<[u8; 8], 200> = unsafe { addr_of!(REAL_WIFI_QUEUE) }; static mut REAL_WIFI_QUEUE: SimpleQueue<[u8; 8], 200> = SimpleQueue::new(); // first there is a ptr to the real queue - driver checks it's not null pub unsafe fn str_from_c<'a>(s: *const u8) -> &'a str { diff --git a/esp-wifi/src/esp_now/mod.rs b/esp-wifi/src/esp_now/mod.rs index 828991d9..fbee9f0b 100644 --- a/esp-wifi/src/esp_now/mod.rs +++ b/esp-wifi/src/esp_now/mod.rs @@ -266,7 +266,9 @@ pub fn enable_esp_now_with_wifi( (device, EspNowWithWifiCreateToken { _private: () }) } -pub struct EspNowManager<'d>(EspNowRc<'d>); +pub struct EspNowManager<'d> { + _rc: EspNowRc<'d>, +} impl<'d> EspNowManager<'d> { /// Set primary WiFi channel @@ -416,7 +418,9 @@ impl<'d> EspNowManager<'d> { /// **DO NOT USE** a lock implementation that disables interrupts since the /// completion of a sending requires waiting for a callback invoked in an /// interrupt. -pub struct EspNowSender<'d>(EspNowRc<'d>); +pub struct EspNowSender<'d> { + _rc: EspNowRc<'d>, +} impl<'d> EspNowSender<'d> { /// Send data to peer @@ -471,7 +475,9 @@ impl<'s> Drop for SendWaiter<'s> { /// This is the sender part of ESP-NOW. You can get this sender by splitting /// a `EspNow` instance. -pub struct EspNowReceiver<'d>(EspNowRc<'d>); +pub struct EspNowReceiver<'d> { + _rc: EspNowRc<'d>, +} impl<'d> EspNowReceiver<'d> { pub fn receive(&self) -> Option { @@ -568,9 +574,13 @@ impl<'d> EspNow<'d> { let espnow_rc = EspNowRc::new()?; let esp_now = EspNow { _device: device, - manager: EspNowManager(espnow_rc.clone()), - sender: EspNowSender(espnow_rc.clone()), - receiver: EspNowReceiver(espnow_rc), + manager: EspNowManager { + _rc: espnow_rc.clone(), + }, + sender: EspNowSender { + _rc: espnow_rc.clone(), + }, + receiver: EspNowReceiver { _rc: espnow_rc }, }; check_error!({ esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_STA) })?; check_error!({ esp_wifi_start() })?; diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index 32133670..a68b9477 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -1,16 +1,19 @@ #![no_std] +#![allow(async_fn_in_trait)] #![cfg_attr(target_arch = "xtensa", feature(asm_experimental_arch))] #![feature(c_variadic)] #![feature(linkage)] #![cfg_attr(feature = "async", allow(incomplete_features))] #![doc = include_str!("../README.md")] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] +#![allow(rustdoc::bare_urls)] // MUST be the first module mod fmt; use core::cell::RefCell; use core::mem::MaybeUninit; +use core::ptr::addr_of_mut; use common_adapter::RADIO_CLOCKS; use critical_section::Mutex; @@ -149,7 +152,7 @@ pub(crate) static HEAP: Mutex> = Mutex::new(RefCell::new(Heap::emp fn init_heap() { critical_section::with(|cs| { HEAP.borrow_ref_mut(cs) - .init_from_slice(unsafe { &mut HEAP_DATA }) + .init_from_slice(unsafe { &mut *addr_of_mut!(HEAP_DATA) as &mut [MaybeUninit] }) }); } diff --git a/esp-wifi/src/preempt/preempt_riscv.rs b/esp-wifi/src/preempt/preempt_riscv.rs index 67b2b7b8..872aeb33 100644 --- a/esp-wifi/src/preempt/preempt_riscv.rs +++ b/esp-wifi/src/preempt/preempt_riscv.rs @@ -1,6 +1,7 @@ use super::*; use crate::hal::interrupt::TrapFrame; +use core::ptr::addr_of; #[derive(Debug, Default, Clone, Copy)] pub struct Context { @@ -58,7 +59,7 @@ pub fn task_create(task: extern "C" fn()) { let task_stack_size = TASK_STACK_SIZE[i]; // stack must be aligned by 16 - let task_stack_ptr = &TASK_STACK as *const _ as usize + let task_stack_ptr = addr_of!(TASK_STACK) as usize + (task_stack_size as usize * i as usize) + task_stack_size as usize - 4; diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index 94358535..1a058872 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -21,16 +21,15 @@ use crate::EspWifiInitialization; use critical_section::{CriticalSection, Mutex}; -use embedded_svc::wifi::{ - AccessPointConfiguration, AccessPointInfo, AuthMethod, ClientConfiguration, Configuration, - Protocol, SecondaryChannel, Wifi, -}; - use enumset::EnumSet; use enumset::EnumSetType; use num_derive::FromPrimitive; use num_traits::FromPrimitive; +use core::convert::TryInto; +use core::fmt::Debug; +use core::mem; + #[doc(hidden)] pub use os_adapter::*; pub use state::*; @@ -74,6 +73,445 @@ use crate::{ compat::queue::SimpleQueue, }; +#[derive(EnumSetType, Debug, PartialOrd)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Default)] +pub enum AuthMethod { + None, + WEP, + WPA, + #[default] + WPA2Personal, + WPAWPA2Personal, + WPA2Enterprise, + WPA3Personal, + WPA2WPA3Personal, + WAPIPersonal, +} + +#[derive(EnumSetType, Debug, PartialOrd)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Default)] +pub enum Protocol { + P802D11B, + P802D11BG, + #[default] + P802D11BGN, + P802D11BGNLR, + P802D11LR, +} + +#[derive(EnumSetType, Debug, PartialOrd)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Default)] +pub enum SecondaryChannel { + // TODO: Need to extend that for 5GHz + #[default] + None, + Above, + Below, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct AccessPointInfo { + pub ssid: heapless::String<32>, + pub bssid: [u8; 6], + pub channel: u8, + pub secondary_channel: SecondaryChannel, + pub signal_strength: i8, + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub protocols: EnumSet, + pub auth_method: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct AccessPointConfiguration { + pub ssid: heapless::String<32>, + pub ssid_hidden: bool, + pub channel: u8, + pub secondary_channel: Option, + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub protocols: EnumSet, + pub auth_method: AuthMethod, + pub password: heapless::String<64>, + pub max_connections: u16, +} + +impl Default for AccessPointConfiguration { + fn default() -> Self { + Self { + ssid: "iot-device".try_into().unwrap(), + ssid_hidden: false, + channel: 1, + secondary_channel: None, + protocols: Protocol::P802D11B | Protocol::P802D11BG | Protocol::P802D11BGN, + auth_method: AuthMethod::None, + password: heapless::String::new(), + max_connections: 255, + } + } +} + +#[derive(Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))] +pub struct ClientConfiguration { + pub ssid: heapless::String<32>, + pub bssid: Option<[u8; 6]>, + //pub protocol: Protocol, + pub auth_method: AuthMethod, + pub password: heapless::String<64>, + pub channel: Option, +} + +impl Debug for ClientConfiguration { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ClientConfiguration") + .field("ssid", &self.ssid) + .field("bssid", &self.bssid) + .field("auth_method", &self.auth_method) + .field("channel", &self.channel) + .finish() + } +} + +impl Default for ClientConfiguration { + fn default() -> Self { + ClientConfiguration { + ssid: heapless::String::new(), + bssid: None, + auth_method: Default::default(), + password: heapless::String::new(), + channel: None, + } + } +} + +#[derive(EnumSetType, Debug, PartialOrd)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Capability { + Client, + AccessPoint, + Mixed, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Default)] +pub enum Configuration { + #[default] + None, + Client(ClientConfiguration), + AccessPoint(AccessPointConfiguration), + Mixed(ClientConfiguration, AccessPointConfiguration), +} + +impl Configuration { + pub fn as_client_conf_ref(&self) -> Option<&ClientConfiguration> { + match self { + Self::Client(client_conf) | Self::Mixed(client_conf, _) => Some(client_conf), + _ => None, + } + } + + pub fn as_ap_conf_ref(&self) -> Option<&AccessPointConfiguration> { + match self { + Self::AccessPoint(ap_conf) | Self::Mixed(_, ap_conf) => Some(ap_conf), + _ => None, + } + } + + pub fn as_client_conf_mut(&mut self) -> &mut ClientConfiguration { + match self { + Self::Client(client_conf) => client_conf, + Self::Mixed(_, _) => { + let prev = mem::replace(self, Self::None); + match prev { + Self::Mixed(client_conf, _) => { + *self = Self::Client(client_conf); + self.as_client_conf_mut() + } + _ => unreachable!(), + } + } + _ => { + *self = Self::Client(Default::default()); + self.as_client_conf_mut() + } + } + } + + pub fn as_ap_conf_mut(&mut self) -> &mut AccessPointConfiguration { + match self { + Self::AccessPoint(ap_conf) => ap_conf, + Self::Mixed(_, _) => { + let prev = mem::replace(self, Self::None); + match prev { + Self::Mixed(_, ap_conf) => { + *self = Self::AccessPoint(ap_conf); + self.as_ap_conf_mut() + } + _ => unreachable!(), + } + } + _ => { + *self = Self::AccessPoint(Default::default()); + self.as_ap_conf_mut() + } + } + } + + pub fn as_mixed_conf_mut( + &mut self, + ) -> (&mut ClientConfiguration, &mut AccessPointConfiguration) { + match self { + Self::Mixed(client_conf, ref mut ap_conf) => (client_conf, ap_conf), + Self::AccessPoint(_) => { + let prev = mem::replace(self, Self::None); + match prev { + Self::AccessPoint(ap_conf) => { + *self = Self::Mixed(Default::default(), ap_conf); + self.as_mixed_conf_mut() + } + _ => unreachable!(), + } + } + Self::Client(_) => { + let prev = mem::replace(self, Self::None); + match prev { + Self::Client(client_conf) => { + *self = Self::Mixed(client_conf, Default::default()); + self.as_mixed_conf_mut() + } + _ => unreachable!(), + } + } + _ => { + *self = Self::Mixed(Default::default(), Default::default()); + self.as_mixed_conf_mut() + } + } + } +} + +pub mod ipv4 { + use core::convert::TryFrom; + use core::fmt::Display; + use core::str::FromStr; + + pub use no_std_net::*; + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub struct Mask(pub u8); + + impl FromStr for Mask { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + s.parse::() + .map_err(|_| "Invalid subnet mask") + .map_or_else(Err, |mask| { + if (1..=32).contains(&mask) { + Ok(Mask(mask)) + } else { + Err("Mask should be a number between 1 and 32") + } + }) + } + } + + impl Display for Mask { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.0) + } + } + + impl TryFrom for Mask { + type Error = (); + + fn try_from(ip: Ipv4Addr) -> Result { + let octets = ip.octets(); + let addr: u32 = ((octets[0] as u32 & 0xff) << 24) + | ((octets[1] as u32 & 0xff) << 16) + | ((octets[2] as u32 & 0xff) << 8) + | (octets[3] as u32 & 0xff); + + if addr.leading_ones() + addr.trailing_zeros() == 32 { + Ok(Mask(addr.leading_ones() as u8)) + } else { + Err(()) + } + } + } + + impl From for Ipv4Addr { + fn from(mask: Mask) -> Self { + let addr: u32 = ((1 << (32 - mask.0)) - 1) ^ 0xffffffffu32; + + let (a, b, c, d) = ( + ((addr >> 24) & 0xff) as u8, + ((addr >> 16) & 0xff) as u8, + ((addr >> 8) & 0xff) as u8, + (addr & 0xff) as u8, + ); + + Ipv4Addr::new(a, b, c, d) + } + } + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub struct Subnet { + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub gateway: Ipv4Addr, + pub mask: Mask, + } + + impl Display for Subnet { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}/{}", self.gateway, self.mask) + } + } + + impl FromStr for Subnet { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + let mut split = s.split('/'); + if let Some(gateway_str) = split.next() { + if let Some(mask_str) = split.next() { + if split.next().is_none() { + if let Ok(gateway) = gateway_str.parse::() { + return mask_str.parse::().map(|mask| Self { gateway, mask }); + } else { + return Err("Invalid IP address format, expected XXX.XXX.XXX.XXX"); + } + } + } + } + + Err("Expected /") + } + } + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub struct ClientSettings { + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub ip: Ipv4Addr, + pub subnet: Subnet, + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub dns: Option, + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub secondary_dns: Option, + } + + impl Default for ClientSettings { + fn default() -> ClientSettings { + ClientSettings { + ip: Ipv4Addr::new(192, 168, 71, 200), + subnet: Subnet { + gateway: Ipv4Addr::new(192, 168, 71, 1), + mask: Mask(24), + }, + dns: Some(Ipv4Addr::new(8, 8, 8, 8)), + secondary_dns: Some(Ipv4Addr::new(8, 8, 4, 4)), + } + } + } + + #[derive(Default, Clone, Debug, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub struct DHCPClientSettings { + pub hostname: Option>, + } + + #[derive(Clone, Debug, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum ClientConfiguration { + DHCP(DHCPClientSettings), + Fixed(ClientSettings), + } + + impl ClientConfiguration { + pub fn as_fixed_settings_ref(&self) -> Option<&ClientSettings> { + match self { + Self::Fixed(client_settings) => Some(client_settings), + _ => None, + } + } + + pub fn as_fixed_settings_mut(&mut self) -> &mut ClientSettings { + match self { + Self::Fixed(client_settings) => client_settings, + _ => { + *self = ClientConfiguration::Fixed(Default::default()); + self.as_fixed_settings_mut() + } + } + } + } + + impl Default for ClientConfiguration { + fn default() -> ClientConfiguration { + ClientConfiguration::DHCP(Default::default()) + } + } + + #[derive(Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub struct RouterConfiguration { + pub subnet: Subnet, + pub dhcp_enabled: bool, + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub dns: Option, + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub secondary_dns: Option, + } + + impl Default for RouterConfiguration { + fn default() -> RouterConfiguration { + RouterConfiguration { + subnet: Subnet { + gateway: Ipv4Addr::new(192, 168, 71, 1), + mask: Mask(24), + }, + dhcp_enabled: true, + dns: Some(Ipv4Addr::new(8, 8, 8, 8)), + secondary_dns: Some(Ipv4Addr::new(8, 8, 4, 4)), + } + } + } + + #[derive(Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum Configuration { + Client(ClientConfiguration), + Router(RouterConfiguration), + } + + impl Default for Configuration { + fn default() -> Self { + Self::Client(Default::default()) + } + } + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub struct IpInfo { + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub ip: Ipv4Addr, + pub subnet: Subnet, + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub dns: Option, + #[cfg_attr(feature = "defmt", defmt(Debug2Format))] + pub secondary_dns: Option, + } +} + trait AuthMethodExt { fn to_raw(&self) -> wifi_auth_mode_t; fn from_raw(raw: wifi_auth_mode_t) -> Self; @@ -627,7 +1065,7 @@ pub(crate) fn wifi_init() -> Result<(), WifiError> { #[cfg(coex)] esp_wifi_result!(coex_init())?; - esp_wifi_result!(esp_wifi_init_internal(&G_CONFIG))?; + esp_wifi_result!(esp_wifi_init_internal(addr_of!(G_CONFIG)))?; esp_wifi_result!(esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_NULL))?; esp_wifi_result!(esp_supplicant_init())?; @@ -929,7 +1367,7 @@ pub(crate) fn wifi_start_scan( /// configuration. /// /// This function will panic if the configuration is not -/// [`Configuration::Client`] or [`Configuration::Station`]. +/// [`Configuration::Client`] or [`Configuration::AccessPoint`]. /// /// If you want to use AP-STA mode, use `[new_ap_sta]`. pub fn new_with_config<'d, MODE: WifiDeviceMode>( @@ -981,8 +1419,8 @@ pub fn new_ap_sta<'d>( pub fn new_ap_sta_with_config<'d>( inited: &EspWifiInitialization, device: impl Peripheral

+ 'd, - sta_config: embedded_svc::wifi::ClientConfiguration, - ap_config: embedded_svc::wifi::AccessPointConfiguration, + sta_config: crate::wifi::ClientConfiguration, + ap_config: crate::wifi::AccessPointConfiguration, ) -> Result< ( WifiDevice<'d, WifiApDevice>, @@ -1273,7 +1711,7 @@ fn convert_ap_info(record: &include::wifi_ap_record_t) -> AccessPointInfo { } } -/// A wifi controller implementing embedded_svc::Wifi traits +/// A wifi controller pub struct WifiController<'d> { _device: PeripheralRef<'d, crate::hal::peripherals::WIFI>, config: Configuration, @@ -1317,7 +1755,7 @@ impl<'d> WifiController<'d> { /// # Example: /// /// ``` - /// use embedded_svc::wifi::Protocol; + /// use esp_wifi::wifi::Protocol; /// use esp_wifi::wifi::WifiController; /// let mut wifi = WifiController::new(); /// wifi.set_mode(Protocol::P802D11BGNLR); @@ -1593,13 +2031,9 @@ fn apply_sta_config(config: &ClientConfiguration) -> Result<(), WifiError> { } } -impl Wifi for WifiController<'_> { - type Error = WifiError; - - /// This currently only supports the `Client` and `AccessPoint` capability. - fn get_capabilities(&self) -> Result, Self::Error> { - use embedded_svc::wifi::Capability; - +impl WifiController<'_> { + /// Get the supported capabilities of the controller. + pub fn get_capabilities(&self) -> Result, WifiError> { let caps = match self.config { Configuration::None => unreachable!(), Configuration::Client(_) => enumset::enum_set! { Capability::Client }, @@ -1612,21 +2046,13 @@ impl Wifi for WifiController<'_> { Ok(caps) } - /// A blocking wifi network scan with default scanning options. - fn scan_n( - &mut self, - ) -> Result<(heapless::Vec, usize), Self::Error> { - self.scan_with_config_sync(Default::default()) - } - /// Get the currently used configuration. - fn get_configuration(&self) -> Result { + pub fn get_configuration(&self) -> Result { Ok(self.config.clone()) } /// Set the configuration, you need to use Wifi::connect() for connecting to an AP - /// Trying anything but `Configuration::Client` or `Configuration::AccessPoint` will result in a panic! - fn set_configuration(&mut self, conf: &Configuration) -> Result<(), Self::Error> { + pub fn set_configuration(&mut self, conf: &Configuration) -> Result<(), WifiError> { match self.config { Configuration::None => self.config = conf.clone(), // initial config Configuration::Client(ref mut client) => { @@ -1676,23 +2102,19 @@ impl Wifi for WifiController<'_> { Ok(()) } - fn start(&mut self) -> Result<(), Self::Error> { - crate::wifi::wifi_start() - } - - fn stop(&mut self) -> Result<(), Self::Error> { + pub(crate) fn stop_impl(&mut self) -> Result<(), WifiError> { esp_wifi_result!(unsafe { esp_wifi_stop() }) } - fn connect(&mut self) -> Result<(), Self::Error> { + pub(crate) fn connect_impl(&mut self) -> Result<(), WifiError> { esp_wifi_result!(unsafe { esp_wifi_connect() }) } - fn disconnect(&mut self) -> Result<(), Self::Error> { + pub(crate) fn disconnect_impl(&mut self) -> Result<(), WifiError> { esp_wifi_result!(unsafe { esp_wifi_disconnect() }) } - fn is_started(&self) -> Result { + pub fn is_started(&self) -> Result { if matches!( crate::wifi::get_sta_state(), WifiState::StaStarted | WifiState::StaConnected | WifiState::StaDisconnected @@ -1705,7 +2127,7 @@ impl Wifi for WifiController<'_> { Ok(false) } - fn is_connected(&self) -> Result { + pub fn is_connected(&self) -> Result { match crate::wifi::get_sta_state() { crate::wifi::WifiState::StaConnected => Ok(true), crate::wifi::WifiState::StaDisconnected => Err(WifiError::Disconnected), @@ -1715,6 +2137,32 @@ impl Wifi for WifiController<'_> { } } +#[cfg(not(feature = "async"))] +impl WifiController<'_> { + /// A blocking wifi network scan with default scanning options. + pub fn scan_n( + &mut self, + ) -> Result<(heapless::Vec, usize), WifiError> { + self.scan_with_config_sync(Default::default()) + } + + pub fn start(&mut self) -> Result<(), WifiError> { + crate::wifi::wifi_start() + } + + pub fn stop(&mut self) -> Result<(), WifiError> { + self.stop_impl() + } + + pub fn connect(&mut self) -> Result<(), WifiError> { + self.connect_impl() + } + + pub fn disconnect(&mut self) -> Result<(), WifiError> { + self.disconnect_impl() + } +} + fn dump_packet_info(_buffer: &[u8]) { #[cfg(feature = "dump-packets")] { @@ -1823,7 +2271,7 @@ mod asynch { // TODO assumes STA mode only impl<'d> WifiController<'d> { - /// Async version of [`embedded_svc::wifi::Wifi`]'s `scan_n` method + /// Async version of [`crate::wifi::WifiController`]'s `scan_n` method pub async fn scan_n( &mut self, ) -> Result<(heapless::Vec, usize), WifiError> { @@ -1849,7 +2297,7 @@ mod asynch { Ok((result, count)) } - /// Async version of [`embedded_svc::wifi::Wifi`]'s `start` method + /// Async version of [`crate::wifi::WifiController`]'s `start` method pub async fn start(&mut self) -> Result<(), WifiError> { let mode = WifiMode::try_from(&self.config)?; @@ -1870,7 +2318,7 @@ mod asynch { Ok(()) } - /// Async version of [`embedded_svc::wifi::Wifi`]'s `stop` method + /// Async version of [`crate::wifi::WifiController`]'s `stop` method pub async fn stop(&mut self) -> Result<(), WifiError> { let mode = WifiMode::try_from(&self.config)?; @@ -1884,7 +2332,7 @@ mod asynch { Self::clear_events(events); - embedded_svc::wifi::Wifi::stop(self)?; + crate::wifi::WifiController::stop_impl(self)?; self.wait_for_all_events(events, false).await; @@ -1894,11 +2342,11 @@ mod asynch { Ok(()) } - /// Async version of [`embedded_svc::wifi::Wifi`]'s `connect` method + /// Async version of [`crate::wifi::WifiController`]'s `connect` method pub async fn connect(&mut self) -> Result<(), WifiError> { Self::clear_events(WifiEvent::StaConnected | WifiEvent::StaDisconnected); - let err = embedded_svc::wifi::Wifi::connect(self).err(); + let err = crate::wifi::WifiController::connect_impl(self).err(); if MultiWifiEventFuture::new(WifiEvent::StaConnected | WifiEvent::StaDisconnected) .await @@ -1910,10 +2358,10 @@ mod asynch { } } - /// Async version of [`embedded_svc::wifi::Wifi`]'s `Disconnect` method + /// Async version of [`crate::wifi::WifiController`]'s `Disconnect` method pub async fn disconnect(&mut self) -> Result<(), WifiError> { Self::clear_events(WifiEvent::StaDisconnected); - embedded_svc::wifi::Wifi::disconnect(self)?; + crate::wifi::WifiController::disconnect_impl(self)?; WifiEventFuture::new(WifiEvent::StaDisconnected).await; Ok(()) @@ -2129,3 +2577,505 @@ impl Drop for FreeApListOnDrop { } } } + +#[cfg(feature = "embedded-svc")] +mod embedded_svc_compat { + use super::*; + + impl Into for Capability { + fn into(self) -> embedded_svc::wifi::Capability { + match self { + Capability::Client => embedded_svc::wifi::Capability::Client, + Capability::AccessPoint => embedded_svc::wifi::Capability::AccessPoint, + Capability::Mixed => embedded_svc::wifi::Capability::Mixed, + } + } + } + + impl Into for AuthMethod { + fn into(self) -> embedded_svc::wifi::AuthMethod { + match self { + AuthMethod::None => embedded_svc::wifi::AuthMethod::None, + AuthMethod::WEP => embedded_svc::wifi::AuthMethod::WEP, + AuthMethod::WPA => embedded_svc::wifi::AuthMethod::WPA, + AuthMethod::WPA2Personal => embedded_svc::wifi::AuthMethod::WPA2Personal, + AuthMethod::WPAWPA2Personal => embedded_svc::wifi::AuthMethod::WPAWPA2Personal, + AuthMethod::WPA2Enterprise => embedded_svc::wifi::AuthMethod::WPA2Enterprise, + AuthMethod::WPA3Personal => embedded_svc::wifi::AuthMethod::WPA3Personal, + AuthMethod::WPA2WPA3Personal => embedded_svc::wifi::AuthMethod::WPA2WPA3Personal, + AuthMethod::WAPIPersonal => embedded_svc::wifi::AuthMethod::WAPIPersonal, + } + } + } + + impl From for AuthMethod { + fn from(value: embedded_svc::wifi::AuthMethod) -> Self { + match value { + embedded_svc::wifi::AuthMethod::None => AuthMethod::None, + embedded_svc::wifi::AuthMethod::WEP => AuthMethod::WEP, + embedded_svc::wifi::AuthMethod::WPA => AuthMethod::WPA, + embedded_svc::wifi::AuthMethod::WPA2Personal => AuthMethod::WPA2Personal, + embedded_svc::wifi::AuthMethod::WPAWPA2Personal => AuthMethod::WPAWPA2Personal, + embedded_svc::wifi::AuthMethod::WPA2Enterprise => AuthMethod::WPA2Enterprise, + embedded_svc::wifi::AuthMethod::WPA3Personal => AuthMethod::WPA3Personal, + embedded_svc::wifi::AuthMethod::WPA2WPA3Personal => AuthMethod::WPA2WPA3Personal, + embedded_svc::wifi::AuthMethod::WAPIPersonal => AuthMethod::WAPIPersonal, + } + } + } + + impl Into for Protocol { + fn into(self) -> embedded_svc::wifi::Protocol { + match self { + Protocol::P802D11B => embedded_svc::wifi::Protocol::P802D11B, + Protocol::P802D11BG => embedded_svc::wifi::Protocol::P802D11BG, + Protocol::P802D11BGN => embedded_svc::wifi::Protocol::P802D11BGN, + Protocol::P802D11BGNLR => embedded_svc::wifi::Protocol::P802D11BGNLR, + Protocol::P802D11LR => embedded_svc::wifi::Protocol::P802D11LR, + } + } + } + + impl From for Protocol { + fn from(value: embedded_svc::wifi::Protocol) -> Self { + match value { + embedded_svc::wifi::Protocol::P802D11B => Protocol::P802D11B, + embedded_svc::wifi::Protocol::P802D11BG => Protocol::P802D11BG, + embedded_svc::wifi::Protocol::P802D11BGN => Protocol::P802D11BGN, + embedded_svc::wifi::Protocol::P802D11BGNLR => Protocol::P802D11BGNLR, + embedded_svc::wifi::Protocol::P802D11LR => Protocol::P802D11LR, + } + } + } + + impl Into for Configuration { + fn into(self) -> embedded_svc::wifi::Configuration { + match self { + Configuration::None => embedded_svc::wifi::Configuration::None, + Configuration::Client(conf) => embedded_svc::wifi::Configuration::Client( + embedded_svc::wifi::ClientConfiguration { + ssid: conf.ssid, + bssid: conf.bssid, + auth_method: conf.auth_method.into(), + password: conf.password, + channel: conf.channel, + }, + ), + Configuration::AccessPoint(conf) => embedded_svc::wifi::Configuration::AccessPoint( + embedded_svc::wifi::AccessPointConfiguration { + ssid: conf.ssid, + ssid_hidden: conf.ssid_hidden, + channel: conf.channel, + secondary_channel: conf.secondary_channel, + protocols: { + let mut res = EnumSet::::new(); + conf.protocols.into_iter().for_each(|v| { + res.insert(v.into()); + }); + res + }, + auth_method: conf.auth_method.into(), + password: conf.password, + max_connections: conf.max_connections, + }, + ), + Configuration::Mixed(client, ap) => embedded_svc::wifi::Configuration::Mixed( + embedded_svc::wifi::ClientConfiguration { + ssid: client.ssid, + bssid: client.bssid, + auth_method: client.auth_method.into(), + password: client.password, + channel: client.channel, + }, + embedded_svc::wifi::AccessPointConfiguration { + ssid: ap.ssid, + ssid_hidden: ap.ssid_hidden, + channel: ap.channel, + secondary_channel: ap.secondary_channel, + protocols: { + let mut res = EnumSet::::new(); + ap.protocols.into_iter().for_each(|v| { + res.insert(v.into()); + }); + res + }, + + auth_method: ap.auth_method.into(), + password: ap.password, + max_connections: ap.max_connections, + }, + ), + } + } + } + + impl From<&embedded_svc::wifi::Configuration> for Configuration { + fn from(value: &embedded_svc::wifi::Configuration) -> Self { + match value { + embedded_svc::wifi::Configuration::None => Configuration::None, + embedded_svc::wifi::Configuration::Client(conf) => { + Configuration::Client(ClientConfiguration { + ssid: conf.ssid.clone(), + bssid: conf.bssid.clone(), + auth_method: conf.auth_method.into(), + password: conf.password.clone(), + channel: conf.channel.clone(), + }) + } + embedded_svc::wifi::Configuration::AccessPoint(conf) => { + Configuration::AccessPoint(AccessPointConfiguration { + ssid: conf.ssid.clone(), + ssid_hidden: conf.ssid_hidden, + channel: conf.channel, + secondary_channel: conf.secondary_channel, + protocols: { + let mut res = EnumSet::::new(); + conf.protocols.into_iter().for_each(|v| { + res.insert(v.into()); + }); + res + }, + auth_method: conf.auth_method.into(), + password: conf.password.clone(), + max_connections: conf.max_connections, + }) + } + embedded_svc::wifi::Configuration::Mixed(client, ap) => Configuration::Mixed( + ClientConfiguration { + ssid: client.ssid.clone(), + bssid: client.bssid.clone(), + auth_method: client.auth_method.into(), + password: client.password.clone(), + channel: client.channel, + }, + AccessPointConfiguration { + ssid: ap.ssid.clone(), + ssid_hidden: ap.ssid_hidden.clone(), + channel: ap.channel, + secondary_channel: ap.secondary_channel, + protocols: { + let mut res = EnumSet::::new(); + ap.protocols.into_iter().for_each(|v| { + res.insert(v.into()); + }); + res + }, + auth_method: ap.auth_method.into(), + password: ap.password.clone(), + max_connections: ap.max_connections, + }, + ), + } + } + } + + impl Into for AccessPointInfo { + fn into(self) -> embedded_svc::wifi::AccessPointInfo { + embedded_svc::wifi::AccessPointInfo { + ssid: self.ssid.clone(), + bssid: self.bssid.clone(), + channel: self.channel, + secondary_channel: self.secondary_channel.into(), + signal_strength: self.signal_strength, + protocols: { + let mut res = EnumSet::::new(); + self.protocols.into_iter().for_each(|v| { + res.insert(v.into()); + }); + res + }, + auth_method: self.auth_method.map(|v| v.into()), + } + } + } + + impl Into for SecondaryChannel { + fn into(self) -> embedded_svc::wifi::SecondaryChannel { + match self { + SecondaryChannel::None => embedded_svc::wifi::SecondaryChannel::None, + SecondaryChannel::Above => embedded_svc::wifi::SecondaryChannel::Above, + SecondaryChannel::Below => embedded_svc::wifi::SecondaryChannel::Below, + } + } + } + + impl Into for crate::wifi::ipv4::Subnet { + fn into(self) -> embedded_svc::ipv4::Subnet { + embedded_svc::ipv4::Subnet { + gateway: embedded_svc::ipv4::Ipv4Addr::from(self.gateway.octets()), + mask: embedded_svc::ipv4::Mask(self.mask.0), + } + } + } + + impl From for crate::wifi::ipv4::Subnet { + fn from(value: embedded_svc::ipv4::Subnet) -> Self { + Self { + gateway: super::ipv4::Ipv4Addr::from(value.gateway.octets()), + mask: super::ipv4::Mask(value.mask.0), + } + } + } + + impl Into for super::ipv4::IpInfo { + fn into(self) -> embedded_svc::ipv4::IpInfo { + embedded_svc::ipv4::IpInfo { + ip: embedded_svc::ipv4::Ipv4Addr::from(self.ip.octets()), + subnet: self.subnet.into(), + dns: self + .dns + .map(|v| embedded_svc::ipv4::Ipv4Addr::from(v.octets())), + secondary_dns: self + .secondary_dns + .map(|v| embedded_svc::ipv4::Ipv4Addr::from(v.octets())), + } + } + } + + impl From<&embedded_svc::ipv4::Configuration> for super::ipv4::Configuration { + fn from(value: &embedded_svc::ipv4::Configuration) -> Self { + match value { + embedded_svc::ipv4::Configuration::Client(client) => { + let config = match client { + embedded_svc::ipv4::ClientConfiguration::DHCP(dhcp) => { + super::ipv4::ClientConfiguration::DHCP( + super::ipv4::DHCPClientSettings { + hostname: dhcp.hostname.clone(), + }, + ) + } + embedded_svc::ipv4::ClientConfiguration::Fixed(fixed) => { + super::ipv4::ClientConfiguration::Fixed(super::ipv4::ClientSettings { + ip: super::ipv4::Ipv4Addr::from(fixed.ip.octets()), + subnet: fixed.subnet.into(), + dns: fixed.dns.map(|v| super::ipv4::Ipv4Addr::from(v.octets())), + secondary_dns: fixed + .secondary_dns + .map(|v| super::ipv4::Ipv4Addr::from(v.octets())), + }) + } + }; + super::ipv4::Configuration::Client(config) + } + embedded_svc::ipv4::Configuration::Router(router) => { + let config = super::ipv4::RouterConfiguration { + subnet: router.subnet.into(), + dhcp_enabled: router.dhcp_enabled, + dns: router.dns.map(|v| super::ipv4::Ipv4Addr::from(v.octets())), + secondary_dns: router + .secondary_dns + .map(|v| super::ipv4::Ipv4Addr::from(v.octets())), + }; + super::ipv4::Configuration::Router(config) + } + } + } + } + + impl Into for super::ipv4::Configuration { + fn into(self) -> embedded_svc::ipv4::Configuration { + match self { + super::ipv4::Configuration::Client(client) => { + let config = match client { + super::ipv4::ClientConfiguration::DHCP(dhcp) => { + embedded_svc::ipv4::ClientConfiguration::DHCP( + embedded_svc::ipv4::DHCPClientSettings { + hostname: dhcp.hostname.clone(), + }, + ) + } + super::ipv4::ClientConfiguration::Fixed(fixed) => { + embedded_svc::ipv4::ClientConfiguration::Fixed( + embedded_svc::ipv4::ClientSettings { + ip: embedded_svc::ipv4::Ipv4Addr::from(fixed.ip.octets()), + subnet: fixed.subnet.into(), + dns: fixed + .dns + .map(|v| embedded_svc::ipv4::Ipv4Addr::from(v.octets())), + secondary_dns: fixed + .secondary_dns + .map(|v| embedded_svc::ipv4::Ipv4Addr::from(v.octets())), + }, + ) + } + }; + embedded_svc::ipv4::Configuration::Client(config) + } + super::ipv4::Configuration::Router(router) => { + let config = embedded_svc::ipv4::RouterConfiguration { + subnet: router.subnet.into(), + dhcp_enabled: router.dhcp_enabled, + dns: router + .dns + .map(|v| embedded_svc::ipv4::Ipv4Addr::from(v.octets())), + secondary_dns: router + .secondary_dns + .map(|v| embedded_svc::ipv4::Ipv4Addr::from(v.octets())), + }; + embedded_svc::ipv4::Configuration::Router(config) + } + } + } + } + + #[cfg(not(feature = "async"))] + impl embedded_svc::wifi::Wifi for WifiController<'_> { + type Error = WifiError; + + fn get_capabilities(&self) -> Result, Self::Error> { + self.get_capabilities().map(|v| { + let mut res = EnumSet::::new(); + v.into_iter().for_each(|v| { + res.insert(v.into()); + }); + res + }) + } + + fn get_configuration(&self) -> Result { + self.get_configuration().map(|v| v.into()) + } + + fn set_configuration( + &mut self, + conf: &embedded_svc::wifi::Configuration, + ) -> Result<(), Self::Error> { + let conf = conf.into(); + self.set_configuration(&conf) + } + + fn start(&mut self) -> Result<(), Self::Error> { + self.start() + } + + fn stop(&mut self) -> Result<(), Self::Error> { + self.stop() + } + + fn connect(&mut self) -> Result<(), Self::Error> { + self.connect() + } + + fn disconnect(&mut self) -> Result<(), Self::Error> { + self.disconnect() + } + + fn is_started(&self) -> Result { + self.is_started() + } + + fn is_connected(&self) -> Result { + self.is_connected() + } + + fn scan_n( + &mut self, + ) -> Result<(heapless::Vec, usize), Self::Error> + { + self.scan_n::().map(|(v, l)| { + let mut res: heapless::Vec = + heapless::Vec::new(); + for ap in v { + res.push(ap.into()).ok(); + } + (res, l) + }) + } + } + + #[cfg(feature = "async")] + impl embedded_svc::wifi::asynch::Wifi for WifiController<'_> { + type Error = WifiError; + + async fn get_capabilities( + &self, + ) -> Result, Self::Error> { + self.get_capabilities().map(|v| { + let mut res = EnumSet::::new(); + v.into_iter().for_each(|v| { + res.insert(v.into()); + }); + res + }) + } + + async fn get_configuration( + &self, + ) -> Result { + WifiController::get_configuration(self).map(|v| v.into()) + } + + async fn set_configuration( + &mut self, + conf: &embedded_svc::wifi::Configuration, + ) -> Result<(), Self::Error> { + let conf = conf.into(); + self.set_configuration(&conf) + } + + async fn start(&mut self) -> Result<(), Self::Error> { + self.start().await + } + + async fn stop(&mut self) -> Result<(), Self::Error> { + self.stop().await + } + + async fn connect(&mut self) -> Result<(), Self::Error> { + self.connect().await + } + + async fn disconnect(&mut self) -> Result<(), Self::Error> { + self.disconnect().await + } + + async fn is_started(&self) -> Result { + self.is_started() + } + + async fn is_connected(&self) -> Result { + self.is_connected() + } + + async fn scan_n( + &mut self, + ) -> Result<(heapless::Vec, usize), Self::Error> + { + self.scan_n::().await.map(|(v, l)| { + let mut res: heapless::Vec = + heapless::Vec::new(); + for ap in v { + res.push(ap.into()).ok(); + } + (res, l) + }) + } + } + + impl<'a, MODE: WifiDeviceMode> embedded_svc::ipv4::Interface + for crate::wifi_interface::WifiStack<'a, MODE> + { + type Error = crate::wifi_interface::WifiStackError; + + fn get_iface_configuration( + &self, + ) -> Result { + self.get_iface_configuration().map(|v| v.into()) + } + + fn set_iface_configuration( + &mut self, + conf: &embedded_svc::ipv4::Configuration, + ) -> Result<(), Self::Error> { + self.set_iface_configuration(&super::ipv4::Configuration::from(conf)) + } + + fn is_iface_up(&self) -> bool { + self.is_iface_up() + } + + fn get_ip_info(&self) -> Result { + self.get_ip_info().map(|v| v.into()) + } + } +} diff --git a/esp-wifi/src/wifi/os_adapter.rs b/esp-wifi/src/wifi/os_adapter.rs index 09eeaaa7..29f9a938 100644 --- a/esp-wifi/src/wifi/os_adapter.rs +++ b/esp-wifi/src/wifi/os_adapter.rs @@ -7,7 +7,7 @@ #[cfg_attr(esp32s2, path = "os_adapter_esp32s2.rs")] pub(crate) mod os_adapter_chip_specific; -use core::cell::RefCell; +use core::{cell::RefCell, ptr::addr_of_mut}; use critical_section::Mutex; use enumset::EnumSet; @@ -171,9 +171,9 @@ pub unsafe extern "C" fn is_from_isr() -> bool { static mut FAKE_SPIN_LOCK: u8 = 1; pub unsafe extern "C" fn spin_lock_create() -> *mut crate::binary::c_types::c_void { // original: return (void *)1; - let ptr = &mut FAKE_SPIN_LOCK as *mut _ as *mut crate::binary::c_types::c_void; + let ptr = addr_of_mut!(FAKE_SPIN_LOCK); trace!("spin_lock_create {:?}", ptr); - ptr + ptr as *mut crate::binary::c_types::c_void } /**************************************************************************** diff --git a/esp-wifi/src/wifi_interface.rs b/esp-wifi/src/wifi_interface.rs index 82f932df..7247e084 100644 --- a/esp-wifi/src/wifi_interface.rs +++ b/esp-wifi/src/wifi_interface.rs @@ -7,7 +7,7 @@ use embedded_io::ErrorType; #[cfg(feature = "tcp")] use embedded_io::{Read, Write}; -use embedded_svc::ipv4; +use crate::wifi::ipv4; use smoltcp::iface::{Interface, SocketHandle, SocketSet}; #[cfg(feature = "dhcpv4")] use smoltcp::socket::dhcpv4::Socket as Dhcpv4Socket; @@ -517,22 +517,23 @@ pub fn timestamp() -> Instant { Instant::from_millis(current_millis() as i64) } -impl ipv4::Interface for WifiStack<'_, MODE> { - type Error = WifiStackError; - - fn get_iface_configuration(&self) -> Result { +impl WifiStack<'_, MODE> { + pub fn get_iface_configuration(&self) -> Result { Ok(self.network_config.borrow().clone()) } - fn set_iface_configuration(&mut self, conf: &ipv4::Configuration) -> Result<(), Self::Error> { + pub fn set_iface_configuration( + &mut self, + conf: &ipv4::Configuration, + ) -> Result<(), WifiStackError> { self.update_iface_configuration(conf) } - fn is_iface_up(&self) -> bool { + pub fn is_iface_up(&self) -> bool { self.ip_info.borrow().is_some() } - fn get_ip_info(&self) -> Result { + pub fn get_ip_info(&self) -> Result { self.ip_info.borrow().ok_or(WifiStackError::MissingIp) } } From c58739d297a24605d1a66647bad0028b10530b56 Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Mon, 5 Feb 2024 11:50:29 +0100 Subject: [PATCH 2/3] Update README.md --- esp-wifi/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/esp-wifi/README.md b/esp-wifi/README.md index 86761045..d5d58f15 100644 --- a/esp-wifi/README.md +++ b/esp-wifi/README.md @@ -90,6 +90,7 @@ Don't use this feature if you are _not_ using USB-SERIAL-JTAG as it might reduce | ps-max-modem | Enable maximum modem sleep. Only affects STA mode | | log | Route log output to the `log` crate | | defmt | Add `defmt::Format` implementation and output logs via `defmt` | +| embedded-svc | Implement the embedded-svc Wifi trait | Note that not all features are available on every MCU. For example, `ble` (and thus, `coex`) is not available on ESP32-S2. From 584e34ac7d2412d742cd737c4394ae10ec27675b Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Mon, 5 Feb 2024 12:00:35 +0100 Subject: [PATCH 3/3] CHANGELOG.md entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 013ff4b2..b95a85ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed ### Changed +- Users don't need embedded-svc to control wifi anymore. The wifi trait is optionally implemented now. (#429) ### Removed