//! Embassy DHCP Example //! //! //! 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 //% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] use embassy_executor::Spawner; use embassy_net::{tcp::TcpSocket, Ipv4Address, Stack, StackResources}; use embassy_time::{Duration, Timer}; use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::println; use esp_wifi::{ initialize, wifi::{ ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiStaDevice, WifiState, }, EspWifiInitFor, }; // 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) -> ! { esp_println::logger::init_logger_from_env(); let peripherals = esp_hal::init({ let mut config = esp_hal::Config::default(); config.cpu_clock = CpuClock::max(); config }); esp_alloc::heap_allocator!(72 * 1024); let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( EspWifiInitFor::Wifi, timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, ) .unwrap(); let wifi = peripherals.WIFI; let (wifi_interface, controller) = esp_wifi::wifi::new_with_mode(&init, wifi, WifiStaDevice).unwrap(); cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { let timg1 = TimerGroup::new(peripherals.TIMG1); esp_hal_embassy::init(timg1.timer0); } else { use esp_hal::timer::systimer::{SystemTimer, Target}; let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); esp_hal_embassy::init(systimer.alarm0); } } let config = embassy_net::Config::dhcpv4(Default::default()); let seed = 1234; // very random, very secure seed // Init network stack let stack = &*mk_static!( Stack>, Stack::new( wifi_interface, config, mk_static!(StackResources<3>, StackResources::<3>::new()), seed ) ); spawner.spawn(connection(controller)).ok(); spawner.spawn(net_task(&stack)).ok(); 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_v4() { println!("Got IP: {}", config.address); break; } Timer::after(Duration::from_millis(500)).await; } 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 = (Ipv4Address::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(3000)).await; } } #[embassy_executor::task] async fn connection(mut controller: WifiController<'static>) { 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.try_into().unwrap(), password: PASSWORD.try_into().unwrap(), ..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 }