diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index a1b50729..f977edfd 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -33,6 +33,7 @@ num-derive = { version = "0.3", features = ["full-syntax"] } num-traits = { version = "0.2", default-features = false } esp-wifi-sys = { version = "0.1.0", path = "../esp-wifi-sys" } embassy-sync = { version = "0.1.0", optional = true } +embassy-futures = { version = "0.1.0", optional = true } embassy-net = { git = "https://github.com/embassy-rs/embassy", rev = "26474ce6eb759e5add1c137f3417845e0797df3a", features = ["nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"], optional = true } embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "26474ce6eb759e5add1c137f3417845e0797df3a", optional = true } @@ -81,7 +82,7 @@ esp32c2-async = [ "esp32c2-hal/embassy", "esp32c2-hal/embassy-time-timg0", "asyn esp32-async = [ "esp32-hal/embassy", "esp32-hal/embassy-time-timg0", "async" ] esp32s2-async = [ "esp32s2-hal/embassy", "esp32s2-hal/embassy-time-timg0", "async" ] esp32s3-async = [ "esp32s3-hal/embassy", "esp32s3-hal/embassy-time-timg0", "async" ] -async = [ "dep:embassy-sync", "embedded-io/async"] +async = [ "dep:embassy-sync", "dep:embassy-futures", "embedded-io/async"] embassy-net = ["dep:embassy-net", "dep:embassy-net-driver", "async"] # misc features diff --git a/esp-wifi/examples/coex.rs b/esp-wifi/examples/coex.rs index 7062c0e6..fcaffcd8 100644 --- a/esp-wifi/examples/coex.rs +++ b/esp-wifi/examples/coex.rs @@ -72,8 +72,9 @@ fn main() -> ! { rtc.rwdt.disable(); let mut socket_set_entries: [SocketStorage; 3] = Default::default(); - let (iface, device, sockets) = create_network_interface(&mut socket_set_entries); - let mut wifi_stack = WifiStack::new(iface, device, sockets, current_millis); + let (iface, device, mut controller, sockets) = + create_network_interface(&mut socket_set_entries); + let wifi_stack = WifiStack::new(iface, device, sockets, current_millis); #[cfg(feature = "esp32c3")] { @@ -88,32 +89,32 @@ fn main() -> ! { initialize(timg1.timer0, Rng::new(peripherals.RNG), &clocks).unwrap(); } - println!("is wifi started: {:?}", wifi_stack.is_started()); + let client_config = Configuration::Client(ClientConfiguration { + ssid: SSID.into(), + password: PASSWORD.into(), + ..Default::default() + }); + let res = controller.set_configuration(&client_config); + println!("wifi_set_configuration returned {:?}", res); + + controller.start().unwrap(); + println!("is wifi started: {:?}", controller.is_started()); println!("Start Wifi Scan"); - let res: Result<(heapless::Vec, usize), WifiError> = wifi_stack.scan_n(); + let res: Result<(heapless::Vec, usize), WifiError> = controller.scan_n(); if let Ok((res, _count)) = res { for ap in res { println!("{:?}", ap); } } - println!("Call wifi_connect"); - let client_config = Configuration::Client(ClientConfiguration { - ssid: SSID.into(), - password: PASSWORD.into(), - ..Default::default() - }); - let res = wifi_stack.set_configuration(&client_config); - println!("wifi_connect returned {:?}", res); - - println!("{:?}", wifi_stack.get_capabilities()); - println!("wifi_connect {:?}", wifi_stack.connect()); + println!("{:?}", controller.get_capabilities()); + println!("wifi_connect {:?}", controller.connect()); // wait to get connected println!("Wait to get connected"); loop { - let res = wifi_stack.is_connected(); + let res = controller.is_connected(); match res { Ok(connected) => { if connected { @@ -126,7 +127,7 @@ fn main() -> ! { } } } - println!("{:?}", wifi_stack.is_connected()); + println!("{:?}", controller.is_connected()); // wait for getting an ip address println!("Wait to get an ip address"); diff --git a/esp-wifi/examples/dhcp.rs b/esp-wifi/examples/dhcp.rs index 9ddd2306..6b279d2e 100644 --- a/esp-wifi/examples/dhcp.rs +++ b/esp-wifi/examples/dhcp.rs @@ -70,8 +70,9 @@ fn main() -> ! { rtc.rwdt.disable(); let mut socket_set_entries: [SocketStorage; 3] = Default::default(); - let (iface, device, sockets) = create_network_interface(&mut socket_set_entries); - let mut wifi_stack = WifiStack::new(iface, device, sockets, current_millis); + let (iface, device, mut controller, sockets) = + create_network_interface(&mut socket_set_entries); + let wifi_stack = WifiStack::new(iface, device, sockets, current_millis); #[cfg(any(feature = "esp32c3", feature = "esp32c2"))] { @@ -86,32 +87,32 @@ fn main() -> ! { initialize(timg1.timer0, Rng::new(peripherals.RNG), &clocks).unwrap(); } - println!("is wifi started: {:?}", wifi_stack.is_started()); + let client_config = Configuration::Client(ClientConfiguration { + ssid: SSID.into(), + password: PASSWORD.into(), + ..Default::default() + }); + let res = controller.set_configuration(&client_config); + println!("wifi_set_configuration returned {:?}", res); + + controller.start().unwrap(); + println!("is wifi started: {:?}", controller.is_started()); println!("Start Wifi Scan"); - let res: Result<(heapless::Vec, usize), WifiError> = wifi_stack.scan_n(); + let res: Result<(heapless::Vec, usize), WifiError> = controller.scan_n(); if let Ok((res, _count)) = res { for ap in res { println!("{:?}", ap); } } - println!("Call wifi_connect"); - let client_config = Configuration::Client(ClientConfiguration { - ssid: SSID.into(), - password: PASSWORD.into(), - ..Default::default() - }); - let res = wifi_stack.set_configuration(&client_config); - println!("wifi_set_configuration returned {:?}", res); - - println!("{:?}", wifi_stack.get_capabilities()); - println!("wifi_connect {:?}", wifi_stack.connect()); + println!("{:?}", controller.get_capabilities()); + println!("wifi_connect {:?}", controller.connect()); // wait to get connected println!("Wait to get connected"); loop { - let res = wifi_stack.is_connected(); + let res = controller.is_connected(); match res { Ok(connected) => { if connected { @@ -124,7 +125,7 @@ fn main() -> ! { } } } - println!("{:?}", wifi_stack.is_connected()); + println!("{:?}", controller.is_connected()); // wait for getting an ip address println!("Wait to get an ip address"); diff --git a/esp-wifi/examples/embassy_dhcp.rs b/esp-wifi/examples/embassy_dhcp.rs index 94fb94fc..7883291f 100644 --- a/esp-wifi/examples/embassy_dhcp.rs +++ b/esp-wifi/examples/embassy_dhcp.rs @@ -20,12 +20,12 @@ use esp32s3_hal as hal; use embassy_executor::Executor; use embassy_time::{Duration, Timer}; -use embedded_svc::wifi::{AccessPointInfo, ClientConfiguration, Configuration, Wifi}; +use embedded_svc::wifi::{ClientConfiguration, Configuration, Wifi}; use esp_backtrace as _; use esp_println::logger::init_logger; use esp_println::println; use esp_wifi::initialize; -use esp_wifi::wifi::{WifiDevice, WifiError}; +use esp_wifi::wifi::{WifiController, WifiDevice, WifiEvent, WifiState}; use hal::clock::{ClockControl, CpuClock}; use hal::Rng; use hal::{embassy, peripherals::Peripherals, prelude::*, timer::TimerGroup, Rtc}; @@ -92,48 +92,7 @@ fn main() -> ! { initialize(timg1.timer0, Rng::new(peripherals.RNG), &clocks).unwrap(); } - let mut wifi_interface = WifiDevice::new(); - - println!("is wifi started: {:?}", wifi_interface.is_started()); - - println!("Start Wifi Scan"); - let res: Result<(heapless::Vec, usize), WifiError> = - wifi_interface.scan_n(); - if let Ok((res, _count)) = res { - for ap in res { - println!("{:?}", ap); - } - } - - println!("Call wifi_connect"); - let client_config = Configuration::Client(ClientConfiguration { - ssid: SSID.into(), - password: PASSWORD.into(), - ..Default::default() - }); - let res = wifi_interface.set_configuration(&client_config); - println!("wifi_set_configuration returned {:?}", res); - - println!("{:?}", wifi_interface.get_capabilities()); - println!("wifi_connect {:?}", wifi_interface.connect()); - - // wait to get connected - println!("Wait to get connected"); - loop { - let res = wifi_interface.is_connected(); - match res { - Ok(connected) => { - if connected { - break; - } - } - Err(err) => { - println!("{:?}", err); - loop {} - } - } - } - println!("{:?}", wifi_interface.is_connected()); + let (wifi_interface, controller) = esp_wifi::wifi::new(); let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); embassy::init(&clocks, timer_group0.timer0); @@ -152,11 +111,48 @@ fn main() -> ! { let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { + spawner.spawn(connection(controller)).ok(); spawner.spawn(net_task(&stack)).ok(); spawner.spawn(task(&stack)).ok(); }); } +#[embassy_executor::task] +async fn connection(mut controller: WifiController) { + println!("start connection task"); + println!("Device capabilities: {:?}", controller.get_capabilities()); + loop { + match esp_wifi::wifi::get_wifi_state() { + WifiState::StaConnected => { + // wait until we're no longer connected + controller.wait_for_event(WifiEvent::StaDisconnected).await; + Timer::after(Duration::from_millis(5000)).await + } + _ => {} + } + if !matches!(controller.is_started(), Ok(true)) { + let client_config = Configuration::Client(ClientConfiguration { + ssid: SSID.into(), + password: PASSWORD.into(), + ..Default::default() + }); + controller.set_configuration(&client_config).unwrap(); + println!("Starting wifi"); + controller.start().await.unwrap(); + println!("Wifi started!"); + } + println!("About to connect..."); + + match controller.connect().await { + Ok(_) => println!("Wifi connected!"), + Err(e) => { + println!("Failed to connect to wifi: {e:?}"); + Timer::after(Duration::from_millis(5000)).await + } + } + } +} + #[embassy_executor::task] async fn net_task(stack: &'static Stack) { stack.run().await @@ -167,6 +163,13 @@ async fn task(stack: &'static Stack) { let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; + loop { + if stack.is_link_up() { + break; + } + Timer::after(Duration::from_millis(500)).await; + } + println!("Waiting to get IP address..."); loop { if let Some(config) = stack.config() { @@ -214,6 +217,6 @@ async fn task(stack: &'static Stack) { }; println!("{}", core::str::from_utf8(&buf[..n]).unwrap()); } - Timer::after(Duration::from_millis(1000)).await; + Timer::after(Duration::from_millis(3000)).await; } } diff --git a/esp-wifi/examples/static_ip.rs b/esp-wifi/examples/static_ip.rs index 32ce223b..3076fe2e 100644 --- a/esp-wifi/examples/static_ip.rs +++ b/esp-wifi/examples/static_ip.rs @@ -71,7 +71,8 @@ fn main() -> ! { rtc.rwdt.disable(); let mut socket_set_entries: [SocketStorage; 3] = Default::default(); - let (iface, device, sockets) = create_network_interface(&mut socket_set_entries); + let (iface, device, mut controller, sockets) = + create_network_interface(&mut socket_set_entries); let mut wifi_stack = WifiStack::new(iface, device, sockets, current_millis); #[cfg(any(feature = "esp32c3", feature = "esp32c2"))] @@ -87,32 +88,32 @@ fn main() -> ! { initialize(timg1.timer0, Rng::new(peripherals.RNG), &clocks).unwrap(); } - println!("is wifi started: {:?}", wifi_stack.is_started()); + let client_config = Configuration::Client(ClientConfiguration { + ssid: SSID.into(), + password: PASSWORD.into(), + ..Default::default() + }); + let res = controller.set_configuration(&client_config); + println!("wifi_set_configuration returned {:?}", res); + + controller.start().unwrap(); + println!("is wifi started: {:?}", controller.is_started()); println!("Start Wifi Scan"); - let res: Result<(heapless::Vec, usize), WifiError> = wifi_stack.scan_n(); + let res: Result<(heapless::Vec, usize), WifiError> = controller.scan_n(); if let Ok((res, _count)) = res { for ap in res { println!("{:?}", ap); } } - println!("Call wifi_connect"); - let client_config = Configuration::Client(ClientConfiguration { - ssid: SSID.into(), - password: PASSWORD.into(), - ..Default::default() - }); - let res = wifi_stack.set_configuration(&client_config); - println!("wifi_set_configuration returned {:?}", res); - - println!("{:?}", wifi_stack.get_capabilities()); - println!("wifi_connect {:?}", wifi_stack.connect()); + println!("{:?}", controller.get_capabilities()); + println!("wifi_connect {:?}", controller.connect()); // wait to get connected println!("Wait to get connected"); loop { - let res = wifi_stack.is_connected(); + let res = controller.is_connected(); match res { Ok(connected) => { if connected { @@ -125,7 +126,7 @@ fn main() -> ! { } } } - println!("{:?}", wifi_stack.is_connected()); + println!("{:?}", controller.is_connected()); println!("Setting static IP {}", STATIC_IP); diff --git a/esp-wifi/src/esp_now/mod.rs b/esp-wifi/src/esp_now/mod.rs index 7560cd91..b2a3e8e4 100644 --- a/esp-wifi/src/esp_now/mod.rs +++ b/esp-wifi/src/esp_now/mod.rs @@ -221,6 +221,8 @@ impl EspNowCreator { /// After this the broadcast address is already added as a peer. pub fn initialize(self) -> Result { let mut esp_now = EspNow { _private: () }; + check_error!({ esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_STA) }); + check_error!({ esp_wifi_start() }); check_error!({ esp_now_init() }); check_error!({ esp_now_register_recv_cb(Some(rcv_cb)) }); diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index 8d445fe1..2566d09a 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -87,7 +87,7 @@ pub fn current_millis() -> u64 { } #[cfg(not(coex))] -const HEAP_SIZE: usize = 42 * 1024; +const HEAP_SIZE: usize = 64 * 1024; #[cfg(coex)] const HEAP_SIZE: usize = 64 * 1024; @@ -143,7 +143,6 @@ pub fn initialize( log::debug!("wifi init"); // wifi init crate::wifi::wifi_init()?; - crate::wifi::wifi_start()?; } #[cfg(feature = "ble")] @@ -217,7 +216,6 @@ pub fn initialize( { log::debug!("wifi init"); crate::wifi::wifi_init()?; - crate::wifi::wifi_start()?; } #[cfg(feature = "ble")] diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index ce6b04c5..8b19fab4 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -9,6 +9,16 @@ use crate::esp_wifi_result; use critical_section::Mutex; use embedded_svc::wifi::{AccessPointInfo, AuthMethod, SecondaryChannel}; use enumset::EnumSet; +use enumset::EnumSetType; +use esp_wifi_sys::include::esp_wifi_disconnect; +use esp_wifi_sys::include::wifi_auth_mode_t_WIFI_AUTH_WAPI_PSK; +use esp_wifi_sys::include::wifi_auth_mode_t_WIFI_AUTH_WEP; +use esp_wifi_sys::include::wifi_auth_mode_t_WIFI_AUTH_WPA2_ENTERPRISE; +use esp_wifi_sys::include::wifi_auth_mode_t_WIFI_AUTH_WPA2_PSK; +use esp_wifi_sys::include::wifi_auth_mode_t_WIFI_AUTH_WPA2_WPA3_PSK; +use esp_wifi_sys::include::wifi_auth_mode_t_WIFI_AUTH_WPA3_PSK; +use esp_wifi_sys::include::wifi_auth_mode_t_WIFI_AUTH_WPA_PSK; +use esp_wifi_sys::include::wifi_auth_mode_t_WIFI_AUTH_WPA_WPA2_PSK; use num_derive::FromPrimitive; use num_traits::FromPrimitive; @@ -100,31 +110,30 @@ pub enum WifiError { Disconnected, } #[repr(i32)] -#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive)] +#[derive(Debug, FromPrimitive, EnumSetType)] pub enum WifiEvent { - WifiEventWifiReady = 0, - WifiEventScanDone, - WifiEventStaStart, - WifiEventStaStop, - WifiEventStaConnected, - WifiEventStaDisconnected, - WifiEventStaAuthmodeChange, - WifiEventStaWpsErSuccess, - WifiEventStaWpsErFailed, - WifiEventStaWpsErTimeout, - WifiEventStaWpsErPin, - WifiEventStaWpsErPbcOverlap, - WifiEventApStart, - WifiEventApStop, - WifiEventApStaconnected, - WifiEventApStadisconnected, - WifiEventApProbereqrecved, - WifiEventFtmReport, - WifiEventStaBssRssiLow, - WifiEventActionTxStatus, - WifiEventRocDone, - WifiEventStaBeaconTimeout, - WifiEventMax, + WifiReady = 0, + ScanDone, + StaStart, + StaStop, + StaConnected, + StaDisconnected, + StaAuthmodeChange, + StaWpsErSuccess, + StaWpsErFailed, + StaWpsErTimeout, + StaWpsErPin, + StaWpsErPbcOverlap, + ApStart, + ApStop, + ApStaconnected, + ApStadisconnected, + ApProbereqrecved, + FtmReport, + StaBssRssiLow, + ActionTxStatus, + RocDone, + StaBeaconTimeout, } #[repr(i32)] @@ -506,37 +515,6 @@ pub fn wifi_init() -> Result<(), WifiError> { crate::wifi_set_log_verbose(); esp_wifi_result!(esp_supplicant_init())?; - esp_wifi_result!(esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_STA))?; - - let mut cfg = wifi_config_t { - sta: wifi_sta_config_t { - ssid: [0; 32], - password: [0; 64], - scan_method: wifi_scan_method_t_WIFI_FAST_SCAN, - bssid_set: false, - bssid: [0; 6], - channel: 0, - listen_interval: 3, - sort_method: wifi_sort_method_t_WIFI_CONNECT_AP_BY_SIGNAL, - threshold: wifi_scan_threshold_t { - rssi: 20, - authmode: wifi_auth_mode_t_WIFI_AUTH_OPEN, - }, - pmf_cfg: wifi_pmf_config_t { - capable: false, - required: false, - }, - sae_pwe_h2e: 3, - _bitfield_align_1: [0u16; 0], - _bitfield_1: __BindgenBitfieldUnit::new([0u8; 4usize]), - failure_retry_cnt: 1, - _bitfield_align_2: [0u8; 0], - _bitfield_2: __BindgenBitfieldUnit::new([0u8; 1usize]), - __bindgen_padding_0: 0u16, - }, - }; - esp_wifi_result!(esp_wifi_set_config(wifi_interface_t_WIFI_IF_STA, &mut cfg))?; - esp_wifi_result!(esp_wifi_set_tx_done_cb(Some(esp_wifi_tx_done_cb)))?; esp_wifi_result!(esp_wifi_internal_reg_rxcb( @@ -627,7 +605,7 @@ unsafe extern "C" fn coex_register_start_cb( 0 } -pub fn wifi_start_scan() -> i32 { +pub fn wifi_start_scan(block: bool) -> i32 { let scan_time = wifi_scan_time_t { active: wifi_active_scan_time_t { min: 10, max: 20 }, passive: 20, @@ -642,67 +620,168 @@ pub fn wifi_start_scan() -> i32 { scan_time: scan_time, }; - unsafe { esp_wifi_scan_start(&scan_config, true) } + unsafe { esp_wifi_scan_start(&scan_config, block) } } -pub fn wifi_connect(ssid: &str, password: &str) -> Result<(), WifiError> { - unsafe { - let mut cfg = wifi_config_t { - sta: wifi_sta_config_t { - ssid: [0; 32], - password: [0; 64], - scan_method: wifi_scan_method_t_WIFI_FAST_SCAN, - bssid_set: false, - bssid: [0; 6], - channel: 0, - listen_interval: 3, - sort_method: wifi_sort_method_t_WIFI_CONNECT_AP_BY_SIGNAL, - threshold: wifi_scan_threshold_t { - rssi: -99, - authmode: wifi_auth_mode_t_WIFI_AUTH_OPEN, - }, - pmf_cfg: wifi_pmf_config_t { - capable: true, - required: false, - }, - sae_pwe_h2e: 3, - _bitfield_align_1: [0u16; 0], - _bitfield_1: __BindgenBitfieldUnit::new([0u8; 4usize]), - failure_retry_cnt: 1, - _bitfield_align_2: [0u8; 0], - _bitfield_2: __BindgenBitfieldUnit::new([0u8; 1usize]), - __bindgen_padding_0: 0u16, - }, - }; - - cfg.sta.ssid[0..(ssid.len())].copy_from_slice(ssid.as_bytes()); - cfg.sta.password[0..(password.len())].copy_from_slice(password.as_bytes()); - - esp_wifi_result!(esp_wifi_set_config(wifi_interface_t_WIFI_IF_STA, &mut cfg))?; - - esp_wifi_result!(esp_wifi_connect()) - } +pub fn new_with_config(config: embedded_svc::wifi::Configuration) -> (WifiDevice, WifiController) { + (WifiDevice::new(), WifiController::new_with_config(config)) } -pub fn wifi_stop() -> Result<(), WifiError> { - unsafe { esp_wifi_result!(esp_wifi_stop()) } +pub fn new() -> (WifiDevice, WifiController) { + (WifiDevice::new(), WifiController::new()) } /// A wifi device implementing smoltcp's Device trait. pub struct WifiDevice { - config: embedded_svc::wifi::Configuration, + _private: (), } impl WifiDevice { - pub fn new_with_config(config: embedded_svc::wifi::Configuration) -> WifiDevice { - WifiDevice { config } + pub(crate) fn new() -> WifiDevice { + Self { _private: () } } +} + +/// A wifi controller implementing embedded_svc::Wifi traits +pub struct WifiController { + config: embedded_svc::wifi::Configuration, +} - pub fn new() -> WifiDevice { +impl WifiController { + pub(crate) fn new_with_config(config: embedded_svc::wifi::Configuration) -> Self { + Self { config } + } + + pub(crate) fn new() -> Self { Self { config: Default::default(), } } + + fn is_sta_enabled(&self) -> Result { + let mut mode: esp_wifi_sys::include::wifi_mode_t = 0; + esp_wifi_result!(unsafe { esp_wifi_sys::include::esp_wifi_get_mode(&mut mode) })?; + + Ok(mode == wifi_mode_t_WIFI_MODE_STA) + } + + fn scan_results( + &mut self, + ) -> Result<(heapless::Vec, usize), WifiError> { + let scan = || -> Result<(heapless::Vec, usize), WifiError> { + let mut scanned = heapless::Vec::::new(); + let mut bss_total: u16 = N as u16; + + unsafe { + esp_wifi_result!(crate::binary::include::esp_wifi_scan_get_ap_num( + &mut bss_total + ))?; + if bss_total as usize > N { + bss_total = N as u16; + } + + let mut records = [crate::binary::include::wifi_ap_record_t { + bssid: [0u8; 6], + ssid: [0u8; 33], + primary: 0u8, + second: 0u32, + rssi: 0i8, + authmode: 0u32, + pairwise_cipher: 0u32, + group_cipher: 0u32, + ant: 0u32, + _bitfield_align_1: [0u32; 0], + _bitfield_1: crate::binary::include::__BindgenBitfieldUnit::new([0u8; 4usize]), + country: crate::binary::include::wifi_country_t { + cc: [0; 3], + schan: 0u8, + nchan: 0u8, + max_tx_power: 0i8, + policy: 0u32, + }, + he_ap: crate::binary::include::wifi_he_ap_info_t { + _bitfield_align_1: [0u8; 0], + _bitfield_1: crate::binary::include::wifi_he_ap_info_t::new_bitfield_1( + 0, 0, 0, + ), + bssid_index: 0, + }, + }; N]; + + esp_wifi_result!(crate::binary::include::esp_wifi_scan_get_ap_records( + &mut bss_total, + &mut records as *mut crate::binary::include::wifi_ap_record_t, + ))?; + + for i in 0..bss_total { + let record = records[i as usize]; + let ssid_strbuf = + crate::compat::common::StrBuf::from(&record.ssid as *const u8); + + let auth_method = match record.authmode { + crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_OPEN => AuthMethod::None, + crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WEP => AuthMethod::WEP, + crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA_PSK => { + AuthMethod::WPA + } + crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA2_PSK => { + AuthMethod::WPA2Personal + } + crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA_WPA2_PSK => { + AuthMethod::WPAWPA2Personal + } + crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA2_ENTERPRISE => { + AuthMethod::WPA2Enterprise + } + crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA3_PSK => { + AuthMethod::WPA3Personal + } + crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA2_WPA3_PSK => { + AuthMethod::WPA2WPA3Personal + } + crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WAPI_PSK => { + AuthMethod::WAPIPersonal + } + _ => panic!(), + }; + + let mut ssid = heapless::String::<32>::new(); + ssid.push_str(ssid_strbuf.as_str_ref()).ok(); + + let ap_info = AccessPointInfo { + ssid: ssid, + bssid: record.bssid, + channel: record.primary, + secondary_channel: match record.second { + crate::binary::include::wifi_second_chan_t_WIFI_SECOND_CHAN_NONE => { + SecondaryChannel::None + } + crate::binary::include::wifi_second_chan_t_WIFI_SECOND_CHAN_ABOVE => { + SecondaryChannel::Above + } + crate::binary::include::wifi_second_chan_t_WIFI_SECOND_CHAN_BELOW => { + SecondaryChannel::Below + } + _ => panic!(), + }, + signal_strength: record.rssi, + protocols: EnumSet::empty(), // TODO + auth_method: auth_method, + }; + + scanned.push(ap_info).ok(); + } + } + + Ok((scanned, bss_total as usize)) + }; + + scan().map_err(|e| { + // upon scan failure, list should be cleared to avoid memory leakage + unsafe { crate::binary::include::esp_wifi_clear_ap_list() }; + e + }) + } } // see https://docs.rs/smoltcp/0.7.1/smoltcp/phy/index.html @@ -809,14 +888,13 @@ pub fn send_data_if_needed() { } log::trace!("esp_wifi_internal_tx {}", _res); } + #[cfg(feature = "embassy-net")] + embassy::TRANSMIT_WAKER.wake(); } - - #[cfg(feature = "embassy-net")] - embassy::TRANSMIT_WAKER.wake(); }); } -impl embedded_svc::wifi::Wifi for WifiDevice { +impl embedded_svc::wifi::Wifi for WifiController { type Error = WifiError; /// This currently only supports the `Client` capability. @@ -831,108 +909,8 @@ impl embedded_svc::wifi::Wifi for WifiDevice { fn scan_n( &mut self, ) -> Result<(heapless::Vec, usize), Self::Error> { - esp_wifi_result!(crate::wifi::wifi_start_scan())?; - - let mut scanned = heapless::Vec::::new(); - let mut bss_total: u16 = N as u16; - - unsafe { - esp_wifi_result!(crate::binary::include::esp_wifi_scan_get_ap_num( - &mut bss_total - ))?; - if bss_total as usize > N { - bss_total = N as u16; - } - - let mut records = [crate::binary::include::wifi_ap_record_t { - bssid: [0u8; 6], - ssid: [0u8; 33], - primary: 0u8, - second: 0u32, - rssi: 0i8, - authmode: 0u32, - pairwise_cipher: 0u32, - group_cipher: 0u32, - ant: 0u32, - _bitfield_align_1: [0u32; 0], - _bitfield_1: crate::binary::include::__BindgenBitfieldUnit::new([0u8; 4usize]), - country: crate::binary::include::wifi_country_t { - cc: [0; 3], - schan: 0u8, - nchan: 0u8, - max_tx_power: 0i8, - policy: 0u32, - }, - he_ap: crate::binary::include::wifi_he_ap_info_t { - _bitfield_align_1: [0u8; 0], - _bitfield_1: crate::binary::include::wifi_he_ap_info_t::new_bitfield_1(0, 0, 0), - bssid_index: 0, - }, - }; N]; - - esp_wifi_result!(crate::binary::include::esp_wifi_scan_get_ap_records( - &mut bss_total, - &mut records as *mut crate::binary::include::wifi_ap_record_t, - ))?; - - for i in 0..bss_total { - let record = records[i as usize]; - let ssid_strbuf = crate::compat::common::StrBuf::from(&record.ssid as *const u8); - - let auth_method = match record.authmode { - crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_OPEN => AuthMethod::None, - crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WEP => AuthMethod::WEP, - crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA_PSK => AuthMethod::WPA, - crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA2_PSK => { - AuthMethod::WPA2Personal - } - crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA_WPA2_PSK => { - AuthMethod::WPAWPA2Personal - } - crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA2_ENTERPRISE => { - AuthMethod::WPA2Enterprise - } - crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA3_PSK => { - AuthMethod::WPA3Personal - } - crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WPA2_WPA3_PSK => { - AuthMethod::WPA2WPA3Personal - } - crate::binary::include::wifi_auth_mode_t_WIFI_AUTH_WAPI_PSK => { - AuthMethod::WAPIPersonal - } - _ => panic!(), - }; - - let mut ssid = heapless::String::<32>::new(); - ssid.push_str(ssid_strbuf.as_str_ref()).ok(); - - let ap_info = AccessPointInfo { - ssid: ssid, - bssid: record.bssid, - channel: record.primary, - secondary_channel: match record.second { - crate::binary::include::wifi_second_chan_t_WIFI_SECOND_CHAN_NONE => { - SecondaryChannel::None - } - crate::binary::include::wifi_second_chan_t_WIFI_SECOND_CHAN_ABOVE => { - SecondaryChannel::Above - } - crate::binary::include::wifi_second_chan_t_WIFI_SECOND_CHAN_BELOW => { - SecondaryChannel::Below - } - _ => panic!(), - }, - signal_strength: record.rssi, - protocols: EnumSet::empty(), // TODO - auth_method: auth_method, - }; - - scanned.push(ap_info).ok(); - } - } - - Ok((scanned, bss_total as usize)) + esp_wifi_result!(crate::wifi::wifi_start_scan(true))?; + self.scan_results() } /// Get the currently used configuration. @@ -950,7 +928,68 @@ impl embedded_svc::wifi::Wifi for WifiDevice { match conf { embedded_svc::wifi::Configuration::None => panic!(), - embedded_svc::wifi::Configuration::Client(_) => {} + embedded_svc::wifi::Configuration::Client(config) => { + esp_wifi_result!(unsafe { esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_STA) })?; + + debug!("Wifi mode STA set"); + let bssid: [u8; 6] = match &config.bssid { + Some(bssid_ref) => *bssid_ref, + None => [0; 6], + }; + + let mut cfg = wifi_config_t { + sta: wifi_sta_config_t { + ssid: [0; 32], + password: [0; 64], + scan_method: wifi_scan_method_t_WIFI_FAST_SCAN, + bssid_set: config.bssid.is_some(), + bssid, + channel: config.channel.unwrap_or(0u8), + listen_interval: 3, + sort_method: wifi_sort_method_t_WIFI_CONNECT_AP_BY_SIGNAL, + threshold: wifi_scan_threshold_t { + rssi: -99, + authmode: match config.auth_method { + AuthMethod::None => wifi_auth_mode_t_WIFI_AUTH_OPEN, + AuthMethod::WEP => wifi_auth_mode_t_WIFI_AUTH_WEP, + AuthMethod::WPA => wifi_auth_mode_t_WIFI_AUTH_WPA_PSK, + AuthMethod::WPA2Personal => wifi_auth_mode_t_WIFI_AUTH_WPA2_PSK, + AuthMethod::WPAWPA2Personal => { + wifi_auth_mode_t_WIFI_AUTH_WPA_WPA2_PSK + } + AuthMethod::WPA2Enterprise => { + wifi_auth_mode_t_WIFI_AUTH_WPA2_ENTERPRISE + } + AuthMethod::WPA3Personal => wifi_auth_mode_t_WIFI_AUTH_WPA3_PSK, + AuthMethod::WPA2WPA3Personal => { + wifi_auth_mode_t_WIFI_AUTH_WPA2_WPA3_PSK + } + AuthMethod::WAPIPersonal => wifi_auth_mode_t_WIFI_AUTH_WAPI_PSK, + }, + }, + pmf_cfg: wifi_pmf_config_t { + capable: true, + required: false, + }, + sae_pwe_h2e: 3, + _bitfield_align_1: [0u16; 0], + _bitfield_1: __BindgenBitfieldUnit::new([0u8; 4usize]), + failure_retry_cnt: 1, + _bitfield_align_2: [0u8; 0], + _bitfield_2: __BindgenBitfieldUnit::new([0u8; 1usize]), + __bindgen_padding_0: 0u16, + }, + }; + + unsafe { + cfg.sta.ssid[0..(config.ssid.len())].copy_from_slice(config.ssid.as_bytes()); + cfg.sta.password[0..(config.password.len())] + .copy_from_slice(config.password.as_bytes()); + } + esp_wifi_result!(unsafe { + esp_wifi_set_config(wifi_interface_t_WIFI_IF_STA, &mut cfg) + })?; + } embedded_svc::wifi::Configuration::AccessPoint(_) => panic!(), embedded_svc::wifi::Configuration::Mixed(_, _) => panic!(), }; @@ -963,30 +1002,19 @@ impl embedded_svc::wifi::Wifi for WifiDevice { } fn stop(&mut self) -> Result<(), Self::Error> { - crate::wifi::wifi_stop() + esp_wifi_result!(unsafe { esp_wifi_stop() }) } fn connect(&mut self) -> Result<(), Self::Error> { - if let embedded_svc::wifi::Configuration::Client(config) = &self.config { - crate::wifi::wifi_connect(&config.ssid, &config.password)?; - } else { - panic!(); - } - Ok(()) + esp_wifi_result!(unsafe { esp_wifi_connect() }) } fn disconnect(&mut self) -> Result<(), Self::Error> { - //FIXME: Is there a way to disconnect from Wifi? - Ok(()) + esp_wifi_result!(unsafe { esp_wifi_disconnect() }) } fn is_started(&self) -> Result { - match crate::wifi::get_wifi_state() { - crate::wifi::WifiState::StaStart => Ok(true), - crate::wifi::WifiState::StaConnected => Ok(true), - //FIXME: Should any of the enum values trigger an error instead of returning false? - _ => Ok(false), - } + self.is_sta_enabled() // TODO handle AP mode when we support that } fn is_connected(&self) -> Result { @@ -1076,6 +1104,7 @@ pub(crate) mod embassy { pub(crate) static TRANSMIT_WAKER: AtomicWaker = AtomicWaker::new(); pub(crate) static RECEIVE_WAKER: AtomicWaker = AtomicWaker::new(); + pub(crate) static LINK_STATE: AtomicWaker = AtomicWaker::new(); impl RxToken for WifiRxToken { fn consume(self, f: F) -> R @@ -1155,10 +1184,13 @@ pub(crate) mod embassy { }) } - fn link_state(&mut self, _cx: &mut core::task::Context) -> embassy_net_driver::LinkState { - // TODO once we have an async way of connecting to wifi, use here - // for now just assume the link is up - embassy_net_driver::LinkState::Up + fn link_state(&mut self, cx: &mut core::task::Context) -> embassy_net_driver::LinkState { + LINK_STATE.register(cx.waker()); + if matches!(get_wifi_state(), WifiState::StaConnected) { + embassy_net_driver::LinkState::Up + } else { + embassy_net_driver::LinkState::Down + } } fn capabilities(&self) -> Capabilities { @@ -1175,3 +1207,202 @@ pub(crate) mod embassy { } } } + +#[cfg(feature = "async")] +mod asynch { + use core::task::Poll; + + use embassy_sync::waitqueue::AtomicWaker; + use num_traits::FromPrimitive; + + use super::*; + + // TODO assumes STA mode only + impl WifiController { + /// Async version of [`embedded_svc::wifi::Wifi`]'s `scan_n` method + pub async fn scan_n( + &mut self, + ) -> Result<(heapless::Vec, usize), WifiError> { + critical_section::with(|cs| WIFI_EVENTS.borrow_ref_mut(cs).remove(WifiEvent::ScanDone)); + esp_wifi_result!(crate::wifi::wifi_start_scan(false))?; + WifiEventFuture::new(WifiEvent::ScanDone).await; + self.scan_results() + } + + /// Async version of [`embedded_svc::wifi::Wifi`]'s `start` method + pub async fn start(&mut self) -> Result<(), WifiError> { + critical_section::with(|cs| WIFI_EVENTS.borrow_ref_mut(cs).remove(WifiEvent::StaStart)); + wifi_start()?; + WifiEventFuture::new(WifiEvent::StaStart).await; + Ok(()) + } + + /// Async version of [`embedded_svc::wifi::Wifi`]'s `stop` method + pub async fn stop(&mut self) -> Result<(), WifiError> { + critical_section::with(|cs| WIFI_EVENTS.borrow_ref_mut(cs).remove(WifiEvent::StaStop)); + embedded_svc::wifi::Wifi::stop(self)?; + WifiEventFuture::new(WifiEvent::StaStop).await; + Ok(()) + } + + /// Async version of [`embedded_svc::wifi::Wifi`]'s `connect` method + pub async fn connect(&mut self) -> Result<(), WifiError> { + critical_section::with(|cs| { + WIFI_EVENTS + .borrow_ref_mut(cs) + .remove_all(WifiEvent::StaConnected | WifiEvent::StaDisconnected) + }); + let err = embedded_svc::wifi::Wifi::connect(self).err(); + match embassy_futures::select::select( + WifiEventFuture::new(WifiEvent::StaConnected), + WifiEventFuture::new(WifiEvent::StaDisconnected), + ) + .await + { + embassy_futures::select::Either::First(_) => Ok(()), + embassy_futures::select::Either::Second(_) => { + Err(err.unwrap_or(WifiError::Disconnected)) + } + } + } + + /// Async version of [`embedded_svc::wifi::Wifi`]'s `Disconnect` method + pub async fn disconnect(&mut self) -> Result<(), WifiError> { + critical_section::with(|cs| { + WIFI_EVENTS + .borrow_ref_mut(cs) + .remove(WifiEvent::StaDisconnected) + }); + embedded_svc::wifi::Wifi::disconnect(self)?; + WifiEventFuture::new(WifiEvent::StaDisconnected).await; + Ok(()) + } + + /// Wait for a [`WifiEvent`]. + pub async fn wait_for_event(&mut self, event: WifiEvent) { + critical_section::with(|cs| WIFI_EVENTS.borrow_ref_mut(cs).remove(event)); + WifiEventFuture::new(event).await; + } + } + + impl WifiEvent { + pub(crate) fn waker(&self) -> &'static AtomicWaker { + match self { + WifiEvent::ScanDone => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaStart => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaConnected => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaDisconnected => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaStop => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::WifiReady => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaAuthmodeChange => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaWpsErSuccess => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaWpsErFailed => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaWpsErTimeout => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaWpsErPin => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaWpsErPbcOverlap => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::ApStart => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::ApStop => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::ApStaconnected => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::ApStadisconnected => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::ApProbereqrecved => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::FtmReport => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaBssRssiLow => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::ActionTxStatus => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::RocDone => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + WifiEvent::StaBeaconTimeout => { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } + } + } + } + + pub(crate) struct WifiEventFuture { + event: WifiEvent, + } + + impl WifiEventFuture { + pub fn new(event: WifiEvent) -> Self { + Self { event } + } + } + + impl core::future::Future for WifiEventFuture { + type Output = (); + + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> Poll { + self.event.waker().register(cx.waker()); + if critical_section::with(|cs| WIFI_EVENTS.borrow_ref(cs).contains(self.event)) { + Poll::Ready(()) + } else { + Poll::Pending + } + } + } +} diff --git a/esp-wifi/src/wifi/os_adapter.rs b/esp-wifi/src/wifi/os_adapter.rs index b69ac767..8ec41540 100644 --- a/esp-wifi/src/wifi/os_adapter.rs +++ b/esp-wifi/src/wifi/os_adapter.rs @@ -5,6 +5,10 @@ #[cfg_attr(feature = "esp32s2", path = "os_adapter_esp32s2.rs")] pub(crate) mod os_adapter_chip_specific; +use core::cell::RefCell; + +use critical_section::Mutex; +use enumset::EnumSet; use log::{debug, trace}; use crate::{ @@ -24,7 +28,13 @@ use crate::{ #[cfg(feature = "esp32c3")] use crate::compat::common::syslog; -pub static mut WIFI_STATE: i32 = -1; +use super::WifiEvent; + +pub(crate) static mut WIFI_STATE: i32 = -1; + +// useful for waiting for events - clear and wait for the event bit to be set again +pub(crate) static WIFI_EVENTS: Mutex>> = + Mutex::new(RefCell::new(enumset::enum_set!())); pub fn is_connected() -> bool { unsafe { WIFI_STATE == wifi_event_t_WIFI_EVENT_STA_CONNECTED as i32 } @@ -896,21 +906,21 @@ pub unsafe extern "C" fn event_post( event_data_size, ticks_to_wait ); - - // probably also need to look at event_base - #[allow(non_upper_case_globals)] - let take_state = match event_id as u32 { - wifi_event_t_WIFI_EVENT_WIFI_READY => true, - wifi_event_t_WIFI_EVENT_STA_START => true, - wifi_event_t_WIFI_EVENT_STA_STOP => true, - wifi_event_t_WIFI_EVENT_STA_CONNECTED => true, - wifi_event_t_WIFI_EVENT_STA_DISCONNECTED => true, - _ => { - use num_traits::FromPrimitive; - log::info!( - "Unhandled event: {:?}", - crate::wifi::WifiEvent::from_i32(event_id) - ); + use num_traits::FromPrimitive; + + let event = WifiEvent::from_i32(event_id).unwrap(); + log::trace!("EVENT: {:?}", event); + critical_section::with(|cs| WIFI_EVENTS.borrow_ref_mut(cs).insert(event)); + + let take_state = match event { + WifiEvent::StaConnected + | WifiEvent::StaDisconnected + | WifiEvent::StaStart + | WifiEvent::StaStop + | WifiEvent::WifiReady + | WifiEvent::ScanDone => true, + other => { + log::info!("Unhandled event: {:?}", other); false } }; @@ -919,6 +929,14 @@ pub unsafe extern "C" fn event_post( WIFI_STATE = event_id; } + #[cfg(feature = "async")] + event.waker().wake(); + + #[cfg(feature = "embassy-net")] + if matches!(event, WifiEvent::StaConnected | WifiEvent::StaDisconnected) { + crate::wifi::embassy::LINK_STATE.wake(); + } + memory_fence(); 0 diff --git a/esp-wifi/src/wifi/utils.rs b/esp-wifi/src/wifi/utils.rs index 3eaf2b4f..a39306e0 100644 --- a/esp-wifi/src/wifi/utils.rs +++ b/esp-wifi/src/wifi/utils.rs @@ -7,20 +7,20 @@ use smoltcp::{ use crate::wifi::get_sta_mac; -use super::WifiDevice; +use super::{WifiController, WifiDevice}; /// Convenient way to create an `smoltcp` ethernet interface /// You can use the provided macros to create and pass a suitable backing storage. pub fn create_network_interface<'a>( storage: &'a mut [SocketStorage<'a>], -) -> (Interface, WifiDevice, SocketSet<'a>) { +) -> (Interface, WifiDevice, WifiController, SocketSet<'a>) { let socket_set_entries = storage; let mut mac = [0u8; 6]; get_sta_mac(&mut mac); let hw_address = EthernetAddress::from_bytes(&mac); - let mut device = WifiDevice::new(); + let (mut device, controller) = crate::wifi::new(); let mut config = Config::new(); @@ -35,5 +35,5 @@ pub fn create_network_interface<'a>( let dhcp_socket = Dhcpv4Socket::new(); socket_set.add(dhcp_socket); - (iface, device, socket_set) + (iface, device, controller, socket_set) } diff --git a/esp-wifi/src/wifi_interface.rs b/esp-wifi/src/wifi_interface.rs index c0e58b17..7a320df3 100644 --- a/esp-wifi/src/wifi_interface.rs +++ b/esp-wifi/src/wifi_interface.rs @@ -4,8 +4,6 @@ use embedded_io::blocking::{Read, Write}; use embedded_io::Io; use embedded_svc::ipv4; -use embedded_svc::wifi::AccessPointInfo; -use enumset::EnumSet; use smoltcp::iface::{Interface, SocketHandle, SocketSet}; use smoltcp::socket::{dhcpv4::Socket as Dhcpv4Socket, tcp::Socket as TcpSocket}; use smoltcp::storage::PacketMetadata; @@ -229,55 +227,6 @@ impl Display for WifiStackError { } } -impl embedded_svc::wifi::Wifi for WifiStack<'_> { - type Error = crate::wifi::WifiError; - - fn get_capabilities(&self) -> Result, Self::Error> { - self.device.borrow_mut().get_capabilities() - } - - fn get_configuration(&self) -> Result { - self.device.borrow_mut().get_configuration() - } - - fn set_configuration( - &mut self, - conf: &embedded_svc::wifi::Configuration, - ) -> Result<(), Self::Error> { - self.device.borrow_mut().set_configuration(conf) - } - - fn start(&mut self) -> Result<(), Self::Error> { - self.device.borrow_mut().start() - } - - fn stop(&mut self) -> Result<(), Self::Error> { - self.device.borrow_mut().stop() - } - - fn connect(&mut self) -> Result<(), Self::Error> { - self.device.borrow_mut().connect() - } - - fn disconnect(&mut self) -> Result<(), Self::Error> { - self.device.borrow_mut().disconnect() - } - - fn is_started(&self) -> Result { - self.device.borrow_mut().is_started() - } - - fn is_connected(&self) -> Result { - self.device.borrow_mut().is_connected() - } - - fn scan_n( - &mut self, - ) -> Result<(heapless::Vec, usize), Self::Error> { - self.device.borrow_mut().scan_n::() - } -} - pub fn timestamp() -> Instant { Instant::from_millis(current_millis() as i64) }