From 2be6a04105184979da3b9e0399dc9bd6138413ba Mon Sep 17 00:00:00 2001 From: ivmarkov Date: Wed, 29 Jan 2025 10:36:09 +0000 Subject: [PATCH] Bugfixing for esp32; bugfixing for Alexa scanning during commissioning --- examples/README.md | 91 ++++++++++++++++++++++ examples/esp/Cargo.toml | 21 +----- examples/esp/src/bin/light.rs | 62 ++++++++++----- examples/esp/src/bin/light_eth.rs | 120 +++++++++--------------------- rs-matter-embassy/README.md | 64 +++++++++++----- rs-matter-embassy/src/ble.rs | 10 ++- rs-matter-embassy/src/wireless.rs | 70 +++++++++++++---- 7 files changed, 279 insertions(+), 159 deletions(-) create mode 100644 examples/README.md diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..8461fac --- /dev/null +++ b/examples/README.md @@ -0,0 +1,91 @@ +# Examples for Espressif MCUs + +The examples are tested and _should_ work on the rPI Pico W, esp32, esp32s3, esp32c3 and esp32c6 + +With that said, it is still early days for both `rs-matter` and `trouble` +(the bare-metal BLE stack in use) so you might face issues during initial commissioning. + +Please [report]() those! + +## Matter Controller + +You need one of: +* Google: + * Google Home/Nest or other Google Matter Controller + * The Google Home app on your phone +* Alexa + * Alexa Echo Hub, Echo Dot or other Amazon Matter Controller + * The Alexa app on your phone +* Apple + * Apple TV or other Apple Matter Controller + * An iPhone with the Apple HomeKit app + +Once you build and flash the firmware, follow the instructions in the phone app. + +To start the commissioning process, all apps will ask you to take a screenshot of the QR code which is printed by the firmware when it starts. +Once you do that, you should see a bunch of logs for the commissioning process. + +NOTE: Since the firmware is not certified, the app will warn you about that. Disregard and let it proceed anyway. + +Upon successful commissioning, you should end up with a Light device which you can turn on/off, and which will also turn on/off by itself every 5 secs. + +## How to build and flash + +### rPI Pico W + +(Support for the stock rPI via the W5500 ethernet adapter coming later.) + +```sh +cd rp +cargo +nightly build + +probe-rs run --chip rp2040 target/thumbv6m-none-eabi/debug/light +``` + +### Espressif MCUs + +#### esp32 + +```sh +cargo install espup +espup update + +cd esp +cargo +esp build --target xtensa-esp32-none-elf --no-default-features --features esp32 + +espflash flash target/xtensa-esp32-none-elf/debug/light --baud 1500000 +espflash monitor --elf target/xtensa-esp32-none-elf/debug/light +``` + +#### esp32s3 + +```sh +cargo install espup +espup update + +cd esp +cargo +esp build --target xtensa-esp32s3-none-elf --no-default-features --features esp32s3 + +espflash flash target/xtensa-esp32s3-none-elf/debug/light --baud 1500000 +espflash monitor --elf target/xtensa-esp32s3-none-elf/debug/light +``` + +#### esp32c3 + +```sh +cd esp +cargo +nightly build --target riscv32imc-unknown-none-elf --no-default-features --features esp32c3 + +espflash flash target/riscv32imc-unknown-none-elf/debug/light --baud 1500000 +espflash monitor --elf target/riscv32imc-unknown-none-elf/debug/light +``` + +#### esp32c6 + +```sh +cd esp +cargo +nightly build --target riscv32imac-unknown-none-elf --no-default-features --features esp32c6 + +espflash flash target/riscv32imac-unknown-none-elf/debug/light --baud 1500000 +espflash monitor --elf target/riscv32imac-unknown-none-elf/debug/light +``` diff --git a/examples/esp/Cargo.toml b/examples/esp/Cargo.toml index 378d262..11ad1fb 100644 --- a/examples/esp/Cargo.toml +++ b/examples/esp/Cargo.toml @@ -39,37 +39,20 @@ portable-atomic = "1" [features] default = ["esp32c3"] - -# trouble-example-apps/esp: -# -# 'esp-hal' likely has a bug, causing _some_ ESP32 chips to give "Invalid HCI Command Parameters" BLE errors at launch, -# if the L2CAP MTU is set low enough. -# -# The error producing ranges go: -# - ESP32-C6: x..<255 // examples with 128, 251 would fail -# - ESP32-C2: RANGE NOT KNOWN // not having the hardware -# - ESP32-H2: RANGE NOT KNOWN // not having the hardware -# - ESP32, -C3, -S2, -S3: claimed not to be affected [1], so the behaviour-altering feature is not enabled for them. -# -# [1]: https://github.com/embassy-rs/trouble/pull/236#issuecomment-2586457641 -# esp32 = ["esp-hal/esp32", "esp-backtrace/esp32", "esp-hal-embassy/esp32", "esp-println/esp32", "esp-wifi/esp32", "portable-atomic/critical-section"] esp32c2 = ["esp-hal/esp32c2", "esp-backtrace/esp32c2", "esp-hal-embassy/esp32c2", "esp-println/esp32c2", "esp-wifi/esp32c2", "portable-atomic/critical-section"] esp32c3 = ["esp-hal/esp32c3", "esp-backtrace/esp32c3", "esp-hal-embassy/esp32c3", "esp-println/esp32c3", "esp-wifi/esp32c3", "portable-atomic/unsafe-assume-single-core"] esp32c6 = ["esp-hal/esp32c6", "esp-backtrace/esp32c6", "esp-hal-embassy/esp32c6", "esp-println/esp32c6", "esp-wifi/esp32c6", "portable-atomic/critical-section"] -esp32h2 = ["esp-hal/esp32h2", "esp-backtrace/esp32h2", "esp-hal-embassy/esp32h2", "esp-println/esp32h2", "esp-wifi/esp32h2", "portable-atomic/critical-section"] esp32s3 = ["esp-hal/esp32s3", "esp-backtrace/esp32s3", "esp-hal-embassy/esp32s3", "esp-println/esp32s3", "esp-wifi/esp32s3", "portable-atomic/critical-section"] [profile.dev] # Rust debug is too slow. # For debug builds always builds with some optimization -opt-level = "s" +opt-level = "z" [profile.release] codegen-units = 1 # LLVM can perform better optimizations using a single thread debug = 2 debug-assertions = false -incremental = false -lto = 'thin' -opt-level = 3 +opt-level = "s" overflow-checks = false diff --git a/examples/esp/src/bin/light.rs b/examples/esp/src/bin/light.rs index 43a383b..bd8a496 100644 --- a/examples/esp/src/bin/light.rs +++ b/examples/esp/src/bin/light.rs @@ -11,8 +11,10 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; use core::pin::pin; +use alloc::boxed::Box; use embassy_executor::Spawner; use embassy_futures::select::select; use embassy_time::{Duration, Timer}; @@ -41,20 +43,7 @@ use rs_matter_embassy::wireless::wifi::esp::EspWifiDriverProvider; use rs_matter_embassy::wireless::wifi::{EmbassyWifi, EmbassyWifiMatterStack}; use rs_matter_embassy::wireless::EmbassyBle; -macro_rules! mk_static { - ($t:ty) => {{ - static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); - #[deny(unused_attributes)] - let x = STATIC_CELL.uninit(); - x - }}; - ($t:ty,$val:expr) => {{ - static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); - #[deny(unused_attributes)] - let x = STATIC_CELL.uninit().write(($val)); - x - }}; -} +extern crate alloc; #[esp_hal_embassy::main] async fn main(_s: Spawner) { @@ -62,6 +51,11 @@ async fn main(_s: Spawner) { info!("Starting..."); + // Heap strictly necessary only for Wifi and for the only Matter dependency which needs (~4KB) alloc - `x509` + // However since `esp32` specifically has a disjoint heap which causes bss size troubles, it is easier + // to allocate the statics once from heap as well + init_heap(); + // == Step 1: == // Necessary `esp-hal` and `esp-wifi` initialization boilerplate @@ -71,9 +65,6 @@ async fn main(_s: Spawner) { config }); - // For Wifi and for the only Matter dependency which needs (~4KB) alloc - `x509` - esp_alloc::heap_allocator!(100 * 1024); - let timg0 = TimerGroup::new(peripherals.TIMG0); let rng = esp_hal::rng::Rng::new(peripherals.RNG); @@ -95,10 +86,10 @@ async fn main(_s: Spawner) { } // == Step 2: == - // Statically allocate the Matter stack. + // Allocate the Matter stack. // For MCUs, it is best to allocate it statically, so as to avoid program stack blowups (its memory footprint is ~ 35 to 50KB). // It is also (currently) a mandatory requirement when the wireless stack variation is used. - let stack = &*mk_static!(EmbassyWifiMatterStack<()>).init_with(EmbassyWifiMatterStack::init( + let stack = &*Box::leak(Box::new_uninit()).init_with(EmbassyWifiMatterStack::<()>::init( &BasicInfoConfig { vid: TEST_VID, pid: TEST_PID, @@ -204,3 +195,36 @@ const NODE: Node = Node { }, ], }; + +#[allow(static_mut_refs)] +fn init_heap() { + fn add_region(region: &'static mut MaybeUninit<[u8; N]>) { + unsafe { + esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new( + region.as_mut_ptr() as *mut u8, + N, + esp_alloc::MemoryCapability::Internal.into(), + )); + } + } + + #[cfg(feature = "esp32")] + { + // The esp32 has two disjoint memory regions for heap + // Also, it has 64KB reserved for the BT stack in the first region, so we can't use that + + static mut HEAP1: MaybeUninit<[u8; 30 * 1024]> = MaybeUninit::uninit(); + #[link_section = ".dram2_uninit"] + static mut HEAP2: MaybeUninit<[u8; 96 * 1024]> = MaybeUninit::uninit(); + + add_region(unsafe { &mut HEAP1 }); + add_region(unsafe { &mut HEAP2 }); + } + + #[cfg(not(feature = "esp32"))] + { + static mut HEAP: MaybeUninit<[u8; 186 * 1024]> = MaybeUninit::uninit(); + + add_region(unsafe { &mut HEAP }); + } +} diff --git a/examples/esp/src/bin/light_eth.rs b/examples/esp/src/bin/light_eth.rs index 3f8d92b..1b523e5 100644 --- a/examples/esp/src/bin/light_eth.rs +++ b/examples/esp/src/bin/light_eth.rs @@ -10,8 +10,11 @@ #![no_main] use core::env; +use core::mem::MaybeUninit; use core::pin::pin; +use alloc::boxed::Box; + use embassy_executor::Spawner; use embassy_futures::select::select4; use embassy_time::{Duration, Timer}; @@ -43,27 +46,14 @@ use rs_matter_embassy::stack::utils::futures::IntoFaillble; use rs_matter_embassy::stack::MdnsType; use rs_matter_embassy::EmbassyEthMatterStack; +extern crate alloc; + const WIFI_SSID: &str = env!("WIFI_SSID"); const WIFI_PASS: &str = env!("WIFI_PASS"); -macro_rules! mk_static { - ($t:ty) => {{ - static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); - #[deny(unused_attributes)] - let x = STATIC_CELL.uninit(); - x - }}; - ($t:ty,$val:expr) => {{ - static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); - #[deny(unused_attributes)] - let x = STATIC_CELL.uninit().write(($val)); - x - }}; -} - #[esp_hal_embassy::main] async fn main(_s: Spawner) { - logger::init_logger(true, log::LevelFilter::Info); + esp_println::logger::init_logger(log::LevelFilter::Info); info!("Starting..."); @@ -76,8 +66,10 @@ async fn main(_s: Spawner) { config }); - // For Wifi and for the only Matter dependency which needs (~4KB) alloc - `x509` - esp_alloc::heap_allocator!(80 * 1024); + // Heap strictly necessary only for Wifi and for the only Matter dependency which needs (~4KB) alloc - `x509` + // However since `esp32` specifically has a disjoint heap which causes bss size troubles, it is easier + // to allocate the statics once from heap as well + init_heap(); let timg0 = TimerGroup::new(peripherals.TIMG0); let mut rng = esp_hal::rng::Rng::new(peripherals.RNG); @@ -99,7 +91,7 @@ async fn main(_s: Spawner) { esp_hal_embassy::init(timg0.timer1); } - let stack = mk_static!(EmbassyEthMatterStack<()>).init_with(EmbassyEthMatterStack::init( + let stack = Box::leak(Box::new_uninit()).init_with(EmbassyEthMatterStack::<()>::init( &BasicInfoConfig { vid: TEST_VID, pid: TEST_PID, @@ -126,7 +118,7 @@ async fn main(_s: Spawner) { let (net_stack, mut net_runner) = create_net_stack( wifi_interface, ((rng.random() as u64) << 32) | rng.random() as u64, - mk_static!(MatterStackResources, MatterStackResources::new()), + Box::leak(Box::new_uninit()).init_with(MatterStackResources::new()), ); // Our "light" on-off cluster. @@ -162,7 +154,7 @@ async fn main(_s: Spawner) { // The Matter stack needs to open two UDP sockets Udp::new( net_stack, - mk_static!(MatterUdpBuffers, MatterUdpBuffers::new()) + Box::leak(Box::new_uninit()).init_with(MatterUdpBuffers::new()) ), // The Matter stack needs a persister to store its state // `EmbassyPersist`+`EmbassyKvBlobStore` saves to a user-supplied NOR Flash region @@ -260,77 +252,35 @@ const NODE: Node = Node { ], }; -/// The default `EspLogger` from `esp_println` is not used as it does not -/// print a timestamp and the module name. This custom logger is used instead. -mod logger { - #![allow(unexpected_cfgs)] - - use core::cell::Cell; - - use embassy_sync::blocking_mutex::{raw::CriticalSectionRawMutex, Mutex}; - use esp_println::println; - - static COLORED: Mutex> = Mutex::new(Cell::new(true)); - - /// Initialize the logger with the given maximum log level. - pub fn init_logger(colored: bool, level: log::LevelFilter) { - COLORED.lock(|c| c.set(colored)); - - unsafe { log::set_logger_racy(&EspIdfLikeLogger) }.unwrap(); +#[allow(static_mut_refs)] +fn init_heap() { + fn add_region(region: &'static mut MaybeUninit<[u8; N]>) { unsafe { - log::set_max_level_racy(level); + esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new( + region.as_mut_ptr() as *mut u8, + N, + esp_alloc::MemoryCapability::Internal.into(), + )); } } - struct EspIdfLikeLogger; + #[cfg(feature = "esp32")] + { + // The esp32 has two disjoint memory regions for heap + // Also, it has 64KB reserved for the BT stack in the first region, so we can't use that - impl log::Log for EspIdfLikeLogger { - fn enabled(&self, _metadata: &log::Metadata) -> bool { - true - } + static mut HEAP1: MaybeUninit<[u8; 30 * 1024]> = MaybeUninit::uninit(); + #[link_section = ".dram2_uninit"] + static mut HEAP2: MaybeUninit<[u8; 96 * 1024]> = MaybeUninit::uninit(); - #[allow(unused)] - fn log(&self, record: &log::Record) { - if !self.enabled(record.metadata()) { - return; - } + add_region(unsafe { &mut HEAP1 }); + add_region(unsafe { &mut HEAP2 }); + } - const RESET: &str = "\u{001B}[0m"; - const RED: &str = "\u{001B}[31m"; - const GREEN: &str = "\u{001B}[32m"; - const YELLOW: &str = "\u{001B}[33m"; - const BLUE: &str = "\u{001B}[34m"; - const CYAN: &str = "\u{001B}[35m"; - - let colored = COLORED.lock(|c| c.get()); - - let (color, reset) = if colored { - ( - match record.level() { - log::Level::Error => RED, - log::Level::Warn => YELLOW, - log::Level::Info => GREEN, - log::Level::Debug => BLUE, - log::Level::Trace => CYAN, - }, - RESET, - ) - } else { - ("", "") - }; - - println!( - //"{}{:.1} ({}) {}: {}{}", - "{}{:.1} {}: {}{}", - color, - record.level(), - //UtcTimestamp::new((&NOW).now()), - record.metadata().target(), - record.args(), - reset - ); - } + #[cfg(not(feature = "esp32"))] + { + static mut HEAP: MaybeUninit<[u8; 186 * 1024]> = MaybeUninit::uninit(); - fn flush(&self) {} + add_region(unsafe { &mut HEAP }); } } diff --git a/rs-matter-embassy/README.md b/rs-matter-embassy/README.md index 802294e..e6c76b1 100644 --- a/rs-matter-embassy/README.md +++ b/rs-matter-embassy/README.md @@ -13,7 +13,7 @@ Everything necessary to run [`rs-matter`](https://github.com/project-chip/rs-mat ## Example -(See also [All examples](examples)) +(See [All examples and how to build them](examples)) ```rust //! An example utilizing the `EmbassyWifiMatterStack` struct. @@ -29,8 +29,10 @@ Everything necessary to run [`rs-matter`](https://github.com/project-chip/rs-mat #![no_std] #![no_main] +use core::mem::MaybeUninit; use core::pin::pin; +use alloc::boxed::Box; use embassy_executor::Spawner; use embassy_futures::select::select; use embassy_time::{Duration, Timer}; @@ -59,20 +61,7 @@ use rs_matter_embassy::wireless::wifi::esp::EspWifiDriverProvider; use rs_matter_embassy::wireless::wifi::{EmbassyWifi, EmbassyWifiMatterStack}; use rs_matter_embassy::wireless::EmbassyBle; -macro_rules! mk_static { - ($t:ty) => {{ - static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); - #[deny(unused_attributes)] - let x = STATIC_CELL.uninit(); - x - }}; - ($t:ty,$val:expr) => {{ - static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); - #[deny(unused_attributes)] - let x = STATIC_CELL.uninit().write(($val)); - x - }}; -} +extern crate alloc; #[esp_hal_embassy::main] async fn main(_s: Spawner) { @@ -80,6 +69,11 @@ async fn main(_s: Spawner) { info!("Starting..."); + // Heap strictly necessary only for Wifi and for the only Matter dependency which needs (~4KB) alloc - `x509` + // However since `esp32` specifically has a disjoint heap which causes bss size troubles, it is easier + // to allocate the statics once from heap as well + init_heap(); + // == Step 1: == // Necessary `esp-hal` and `esp-wifi` initialization boilerplate @@ -89,9 +83,6 @@ async fn main(_s: Spawner) { config }); - // For Wifi and for the only Matter dependency which needs (~4KB) alloc - `x509` - esp_alloc::heap_allocator!(100 * 1024); - let timg0 = TimerGroup::new(peripherals.TIMG0); let rng = esp_hal::rng::Rng::new(peripherals.RNG); @@ -113,10 +104,10 @@ async fn main(_s: Spawner) { } // == Step 2: == - // Statically allocate the Matter stack. + // Allocate the Matter stack. // For MCUs, it is best to allocate it statically, so as to avoid program stack blowups (its memory footprint is ~ 35 to 50KB). // It is also (currently) a mandatory requirement when the wireless stack variation is used. - let stack = &*mk_static!(EmbassyWifiMatterStack<()>).init_with(EmbassyWifiMatterStack::init( + let stack = &*Box::leak(Box::new_uninit()).init_with(EmbassyWifiMatterStack::<()>::init( &BasicInfoConfig { vid: TEST_VID, pid: TEST_PID, @@ -222,6 +213,39 @@ const NODE: Node = Node { }, ], }; + +#[allow(static_mut_refs)] +fn init_heap() { + fn add_region(region: &'static mut MaybeUninit<[u8; N]>) { + unsafe { + esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new( + region.as_mut_ptr() as *mut u8, + N, + esp_alloc::MemoryCapability::Internal.into(), + )); + } + } + + #[cfg(feature = "esp32")] + { + // The esp32 has two disjoint memory regions for heap + // Also, it has 64KB reserved for the BT stack in the first region, so we can't use that + + static mut HEAP1: MaybeUninit<[u8; 30 * 1024]> = MaybeUninit::uninit(); + #[link_section = ".dram2_uninit"] + static mut HEAP2: MaybeUninit<[u8; 96 * 1024]> = MaybeUninit::uninit(); + + add_region(unsafe { &mut HEAP1 }); + add_region(unsafe { &mut HEAP2 }); + } + + #[cfg(not(feature = "esp32"))] + { + static mut HEAP: MaybeUninit<[u8; 186 * 1024]> = MaybeUninit::uninit(); + + add_region(unsafe { &mut HEAP }); + } +} ``` ## Future diff --git a/rs-matter-embassy/src/ble.rs b/rs-matter-embassy/src/ble.rs index 7cd6711..626dd81 100644 --- a/rs-matter-embassy/src/ble.rs +++ b/rs-matter-embassy/src/ble.rs @@ -21,7 +21,7 @@ use log::{debug, info, warn}; use rs_matter_stack::matter::error::{Error, ErrorCode}; use rs_matter_stack::matter::transport::network::btp::{ AdvData, GattPeripheral, GattPeripheralEvent, C1_CHARACTERISTIC_UUID, C2_CHARACTERISTIC_UUID, - MATTER_BLE_SERVICE_UUID16, MAX_BTP_SESSIONS, + MATTER_BLE_SERVICE_UUID16, }; use rs_matter_stack::matter::transport::network::BtAddr; use rs_matter_stack::matter::utils::init::{init, Init}; @@ -33,10 +33,14 @@ use trouble_host::att::{AttReq, AttRsp}; use trouble_host::prelude::*; use trouble_host::{self, Address, BleHostError, Controller, HostResources}; -const MAX_CONNECTIONS: usize = MAX_BTP_SESSIONS; -// esp32c6 has a bug so we can't go lower than 255 +const MAX_CONNECTIONS: usize = 1; +// Issue with esp32c6: we can't go lower than 255 on it +// Issue with esp32: we can't go lower than 251 on it // TODO: Make the MTU size a feature in future +#[cfg(any(target_arch = "riscv32", target_arch = "xtensa"))] const MAX_MTU_SIZE: usize = 255; +#[cfg(not(any(target_arch = "riscv32", target_arch = "xtensa")))] +const MAX_MTU_SIZE: usize = 131; const MAX_CHANNELS: usize = 2; const ADV_SETS: usize = 1; diff --git a/rs-matter-embassy/src/wireless.rs b/rs-matter-embassy/src/wireless.rs index cddb414..9ee7569 100644 --- a/rs-matter-embassy/src/wireless.rs +++ b/rs-matter-embassy/src/wireless.rs @@ -460,9 +460,11 @@ pub mod wifi { #[cfg(feature = "rp")] pub mod rp { - use cyw43::{Control, JoinOptions, ScanOptions, ScanType}; + use cyw43::{Control, JoinOptions, ScanOptions}; - use crate::matter::data_model::sdm::nw_commissioning::WiFiSecurity; + use log::{error, info}; + + use crate::matter::data_model::sdm::nw_commissioning::{WiFiSecurity, WifiBand}; use crate::matter::error::{Error, ErrorCode}; use crate::matter::tlv::OctetsOwned; use crate::matter::utils::storage::Vec; @@ -496,8 +498,10 @@ pub mod wifi { where F: FnMut(Option<&::ScanResult>) -> Result<(), Error>, { + info!("Wifi scan request"); + let mut scan_options = ScanOptions::default(); - scan_options.scan_type = ScanType::Active; + //scan_options.scan_type = ScanType::Active; if let Some(network_id) = network_id { scan_options.ssid = Some(network_id.0.as_str().try_into().unwrap()); @@ -505,8 +509,10 @@ pub mod wifi { let mut scanner = self.0.scan(scan_options).await; + info!("Wifi scan started"); + while let Some(ap) = scanner.next().await { - callback(Some(&WifiScanResult { + let result = WifiScanResult { ssid: WifiSsid( core::str::from_utf8(&ap.ssid[..ap.ssid_len as _]) .unwrap() @@ -518,13 +524,19 @@ pub mod wifi { }, channel: ap.chanspec, rssi: Some(ap.rssi as _), - band: None, + band: Some(WifiBand::B3G4), // TODO security: WiFiSecurity::Wpa2Personal, // TODO - }))?; + }; + + callback(Some(&result))?; + + info!("Scan result {:?}", result); } callback(None)?; + info!("Wifi scan complete"); + Ok(()) } @@ -535,6 +547,7 @@ pub mod wifi { self.1 = None; self.0.leave().await; + info!("Disconnected from current Wifi AP (if any)"); self.0 .join( @@ -543,8 +556,13 @@ pub mod wifi { ) .await .map_err(to_err)?; + + info!("Wifi connected"); + self.1 = Some(creds.ssid.clone()); + info!("Wifi connect complete"); + Ok(()) } @@ -564,7 +582,8 @@ pub mod wifi { } } - fn to_err(_: cyw43::ControlError) -> Error { + fn to_err(e: cyw43::ControlError) -> Error { + error!("Wifi error: {:?}", e); Error::new(ErrorCode::NoNetworkInterface) } } @@ -583,7 +602,9 @@ pub mod wifi { WifiError, WifiStaDevice, }; - use crate::matter::data_model::sdm::nw_commissioning::WiFiSecurity; + use log::{error, info}; + + use crate::matter::data_model::sdm::nw_commissioning::{WiFiSecurity, WifiBand}; use crate::matter::error::{Error, ErrorCode}; use crate::matter::tlv::OctetsOwned; use crate::matter::utils::storage::Vec; @@ -664,8 +685,11 @@ pub mod wifi { where F: FnMut(Option<&::ScanResult>) -> Result<(), Error>, { + info!("Wifi scan request"); + if !self.0.is_started().map_err(to_err)? { self.0.start_async().await.map_err(to_err)?; + info!("Wifi started"); } let mut scan_config = ScanConfig::default(); @@ -673,21 +697,26 @@ pub mod wifi { scan_config.ssid = Some(network_id.0.as_str()); } - let (aps, _) = self + let (aps, len) = self .0 .scan_with_config_async::(scan_config) .await .map_err(to_err)?; + info!( + "Wifi scan complete, reporting {} results out of {len} total", + aps.len() + ); + for ap in aps { - callback(Some(&WifiScanResult { + let result = WifiScanResult { ssid: WifiSsid(ap.ssid), bssid: OctetsOwned { vec: Vec::from_slice(&ap.bssid).unwrap(), }, channel: ap.channel as _, rssi: Some(ap.signal_strength), - band: None, + band: Some(WifiBand::B3G4), // TODO security: match ap.auth_method { Some(AuthMethod::None) => WiFiSecurity::Unencrypted, Some(AuthMethod::WEP) => WiFiSecurity::Wep, @@ -695,11 +724,17 @@ pub mod wifi { Some(AuthMethod::WPA3Personal) => WiFiSecurity::Wpa3Personal, _ => WiFiSecurity::Wpa2Personal, }, - }))?; + }; + + callback(Some(&result))?; + + info!("Scan result {:?}", result); } callback(None)?; + info!("Wifi scan complete"); + Ok(()) } @@ -711,6 +746,7 @@ pub mod wifi { if self.0.is_started().map_err(to_err)? { self.0.stop_async().await.map_err(to_err)?; + info!("Wifi stopped"); } self.0 @@ -720,16 +756,23 @@ pub mod wifi { ..Default::default() })) .map_err(to_err)?; + info!("Wifi configuration updated"); self.0.start_async().await.map_err(to_err)?; + info!("Wifi started"); + self.0.connect_async().await.map_err(to_err)?; + info!("Wifi connected"); + self.1 = self .0 .is_connected() .map_err(to_err)? .then_some(creds.ssid.clone()); + info!("Wifi connect complete"); + Ok(()) } @@ -749,7 +792,8 @@ pub mod wifi { } } - fn to_err(_: WifiError) -> Error { + fn to_err(e: WifiError) -> Error { + error!("Wifi error: {:?}", e); Error::new(ErrorCode::NoNetworkInterface) } }