From 748bd92010080b8a8d800546519408af5573b8b0 Mon Sep 17 00:00:00 2001 From: Avii Date: Tue, 8 Jul 2025 15:53:23 +0200 Subject: [PATCH] WiFi Example --- .cargo/config.toml | 2 + Cargo.lock | 115 ++++++++++++++++++++++++++++ Cargo.toml | 12 ++- src/main.rs | 187 ++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 296 insertions(+), 20 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index d9cfa86..e9d1ad5 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -4,6 +4,8 @@ runner = "espflash flash --monitor" [env] ESP_LOG = "info" +SSID = "ssid" +PASSWORD = "password" [build] rustflags = ["-C", "link-arg=-nostartfiles", "-C", "link-arg=-Wl,-Tlinkall.x"] diff --git a/Cargo.lock b/Cargo.lock index 013946d..05a5455 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,6 +263,29 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" +[[package]] +name = "embassy-net" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940c4b9fe5c1375b09a0c6722c0100d6b2ed46a717a34f632f26e8d7327c4383" +dependencies = [ + "document-features", + "embassy-net-driver", + "embassy-sync", + "embassy-time", + "embedded-io-async", + "embedded-nal-async", + "heapless", + "managed", + "smoltcp", +] + +[[package]] +name = "embassy-net-driver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d" + [[package]] name = "embassy-sync" version = "0.6.2" @@ -361,6 +384,25 @@ dependencies = [ "embedded-io", ] +[[package]] +name = "embedded-nal" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56a28be191a992f28f178ec338a0bf02f63d7803244add736d026a471e6ed77" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "embedded-nal-async" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76959917cd2b86f40a98c28dd5624eddd1fa69d746241c8257eac428d83cb211" +dependencies = [ + "embedded-io-async", + "embedded-nal", +] + [[package]] name = "embedded-storage" version = "0.3.1" @@ -601,6 +643,43 @@ dependencies = [ "riscv-rt-macros", ] +[[package]] +name = "esp-wifi" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3700028d3d2ee57e6d2a5c5f60544711052f8d394e73a6f534b538fbfb9d058c" +dependencies = [ + "allocator-api2", + "cfg-if", + "critical-section", + "document-features", + "embassy-net-driver", + "embedded-io", + "embedded-io-async", + "enumset", + "esp-alloc", + "esp-build", + "esp-config", + "esp-hal", + "esp-metadata", + "esp-wifi-sys", + "num-derive", + "num-traits", + "portable-atomic", + "portable_atomic_enum", + "rand_core 0.9.3", + "xtensa-lx-rt", +] + +[[package]] +name = "esp-wifi-sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6b5438361891c431970194a733415006fb3d00b6eb70b3dcb66fd58f04d9b39" +dependencies = [ + "anyhow", +] + [[package]] name = "esp32" version = "0.37.0" @@ -783,17 +862,21 @@ name = "keypad-rs" version = "0.1.0" dependencies = [ "embassy-executor", + "embassy-net", "embassy-time", "embedded-io", + "embedded-io-async", "esp-alloc", "esp-backtrace", "esp-bootloader-esp-idf", "esp-hal", "esp-hal-embassy", "esp-println", + "esp-wifi", "heapless", "log", "smoltcp", + "static_cell", ] [[package]] @@ -869,6 +952,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -908,6 +1002,27 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "portable_atomic_enum" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d48f60c43e0120bb2bb48589a16d4bed2f4b911be41e299f2d0fc0e0e20885" +dependencies = [ + "portable-atomic", + "portable_atomic_enum_macros", +] + +[[package]] +name = "portable_atomic_enum_macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33fa6ec7f2047f572d49317cca19c87195de99c6e5b6ee492da701cfe02b053" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro-crate" version = "3.3.0" diff --git a/Cargo.toml b/Cargo.toml index 572511d..b38e4c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,8 @@ esp-println = { version = "0.14.0", features = ["esp32", "log-04"] } log = { version = "0.4.27" } esp-alloc = { version = "0.8.0" } embedded-io = "0.6.1" -# esp-wifi = { version = "0.14.1", features = ["esp32", "wifi"] } +embedded-io-async = { version = "0.6.1" } +esp-wifi = { version = "0.14.1", features = ["esp32", "wifi"] } heapless = { version = "0.8.0", default-features = false } smoltcp = { version = "0.12.0", default-features = false, features = [ "medium-ethernet", @@ -30,11 +31,20 @@ smoltcp = { version = "0.12.0", default-features = false, features = [ "socket-udp", ] } +static_cell = { version = "2.1.0", features = ["nightly"] } + embassy-executor = { version = "0.7", features = ["task-arena-size-20480"] } embassy-time = { version = "0.4" } +embassy-net = { version = "0.7", features = [ + "tcp", + "udp", + "dhcpv4", + "medium-ethernet", +] } esp-hal-embassy = { version = "0.8.1", features = ["esp32", "executors"] } esp-bootloader-esp-idf = { version = "0.1" } + [profile.dev] # Rust debug is too slow. # For debug builds always builds with some optimization diff --git a/src/main.rs b/src/main.rs index 55edb80..301e22d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,43 +1,192 @@ -//! embassy hello world +//! Embassy DHCP Example //! -//! This is an example of running the embassy executor with multiple tasks -//! concurrently. +//! +//! Set SSID and PASSWORD env variable before running this example. +//! +//! This gets an ip address via DHCP then performs an HTTP get request to some +//! "random" server +//! +//! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: embassy esp-hal/unstable +//% FEATURES: embassy esp-wifi esp-wifi/wifi esp-hal/unstable +//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] use embassy_executor::Spawner; +use embassy_net::{Runner, StackResources}; use embassy_time::{Duration, Timer}; +use esp_alloc as _; use esp_backtrace as _; -use esp_hal::timer::timg::TimerGroup; +use esp_hal::{clock::CpuClock, rng::Rng, timer::timg::TimerGroup}; +use esp_println::println; +use esp_wifi::{ + init, + wifi::{ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState}, + EspWifiController, +}; esp_bootloader_esp_idf::esp_app_desc!(); -#[embassy_executor::task] -async fn run() { - loop { - esp_println::println!("Hello world from embassy using esp-hal-async!"); - Timer::after(Duration::from_millis(1_000)).await; - } +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +macro_rules! mk_static { + ($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 + }}; } +const SSID: &str = env!("SSID"); +const PASSWORD: &str = env!("PASSWORD"); + #[esp_hal_embassy::main] -async fn main(spawner: Spawner) { +async fn main(spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env(); - let peripherals = esp_hal::init(esp_hal::Config::default()); + let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); + let peripherals = esp_hal::init(config); - esp_println::println!("Init!"); + esp_alloc::heap_allocator!(size: 72 * 1024); let timg0 = TimerGroup::new(peripherals.TIMG0); - esp_hal_embassy::init(timg0.timer0); + let mut rng = Rng::new(peripherals.RNG); - spawner.spawn(run()).ok(); + let esp_wifi_ctrl = &*mk_static!( + EspWifiController<'static>, + init(timg0.timer0, rng, peripherals.RADIO_CLK).unwrap() + ); + + let (controller, interfaces) = esp_wifi::wifi::new(esp_wifi_ctrl, peripherals.WIFI).unwrap(); + + let wifi_interface = interfaces.sta; + + let timg1 = TimerGroup::new(peripherals.TIMG1); + esp_hal_embassy::init(timg1.timer0); + + let config = embassy_net::Config::dhcpv4(Default::default()); + + let seed = (rng.random() as u64) << 32 | rng.random() as u64; + + // Init network stack + let (stack, runner) = embassy_net::new( + wifi_interface, + config, + mk_static!(StackResources<3>, StackResources::<3>::new()), + seed, + ); + + spawner.spawn(connection(controller)).ok(); + spawner.spawn(net_task(runner)).ok(); loop { - esp_println::println!("Bing!"); - Timer::after(Duration::from_millis(5_000)).await; + 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_v4() { + println!("Got IP: {}", config.address); + break; + } + Timer::after(Duration::from_millis(500)).await; + } + + loop { + Timer::after(Duration::from_millis(1_000)).await; + // do nothing + } + + // let mut rx_buffer = [0; 4096]; + // let mut tx_buffer = [0; 4096]; + // use core::net::Ipv4Addr; + // use embassy_net::tcp::TcpSocket; + // loop { + // Timer::after(Duration::from_millis(1_000)).await; + + // let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + + // socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); + + // let remote_endpoint = (Ipv4Addr::new(142, 250, 185, 115), 80); + // println!("connecting..."); + // let r = socket.connect(remote_endpoint).await; + // if let Err(e) = r { + // println!("connect error: {:?}", e); + // continue; + // } + // println!("connected!"); + // let mut buf = [0; 1024]; + // loop { + // use embedded_io_async::Write; + // let r = socket + // .write_all(b"GET / HTTP/1.0\r\nHost: www.mobile-j.de\r\n\r\n") + // .await; + // if let Err(e) = r { + // println!("write error: {:?}", e); + // break; + // } + // let n = match socket.read(&mut buf).await { + // Ok(0) => { + // println!("read EOF"); + // break; + // } + // Ok(n) => n, + // Err(e) => { + // println!("read error: {:?}", e); + // break; + // } + // }; + // println!("{}", core::str::from_utf8(&buf[..n]).unwrap()); + // } + // Timer::after(Duration::from_millis(30000)).await; + // } +} + +#[embassy_executor::task] +async fn connection(mut controller: WifiController<'static>) { + println!("start connection task"); + println!("Device capabilities: {:?}", controller.capabilities()); + loop { + if esp_wifi::wifi::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_async().await.unwrap(); + println!("Wifi started!"); + + println!("Scan"); + let result = controller.scan_n_async(10).await.unwrap(); + for ap in result { + println!("{:?}", ap); + } + } + println!("About to connect..."); + + match controller.connect_async().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(mut runner: Runner<'static, WifiDevice<'static>>) { + runner.run().await +}