//! Access point //! //! Creates an open access-point with SSID `esp-radio`. //! You can connect to it using a static IP in range 192.168.2.2 .. //! 192.168.2.255, gateway 192.168.2.1 //! //! Open http://192.168.2.1:8080/ in your browser //! //! On Android you might need to choose _Keep Accesspoint_ when it tells you the //! WiFi has no internet connection, Chrome might not want to load the URL - you //! can use a shell and try `curl` and `ping` #![no_std] #![no_main] use blocking_network_stack::Stack; use embedded_io::*; use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ clock::CpuClock, main, rng::Rng, time::{self, Duration}, timer::timg::TimerGroup, }; use esp_println::{print, println}; use esp_radio::wifi::{ AccessPointConfig, Config, event::{self, EventExt}, }; use smoltcp::iface::{SocketSet, SocketStorage}; esp_bootloader_esp_idf::esp_app_desc!(); #[main] fn main() -> ! { esp_println::logger::init_logger_from_env(); let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); let peripherals = esp_hal::init(config); esp_alloc::heap_allocator!(size: 72 * 1024); let timg0 = TimerGroup::new(peripherals.TIMG0); esp_preempt::start(timg0.timer0); // Set event handlers for wifi before init to avoid missing any. let mut connections = 0u32; _ = event::ApStart::replace_handler(|_| println!("ap start event")); event::ApStaConnected::update_handler(move |event| { connections += 1; esp_println::println!("connected {}, mac: {:?}", connections, event.mac()); }); event::ApStaConnected::update_handler(|event| { esp_println::println!("connected aid: {}", event.aid()); }); event::ApStaDisconnected::update_handler(|event| { println!( "disconnected mac: {:?}, reason: {:?}", event.mac(), event.reason() ); }); let esp_radio_ctrl = esp_radio::init().unwrap(); let (mut controller, interfaces) = esp_radio::wifi::new(&esp_radio_ctrl, peripherals.WIFI).unwrap(); let mut device = interfaces.ap; let iface = create_interface(&mut device); let now = || time::Instant::now().duration_since_epoch().as_millis(); let rng = Rng::new(); let mut socket_set_entries: [SocketStorage; 3] = Default::default(); let socket_set = SocketSet::new(&mut socket_set_entries[..]); let mut stack = Stack::new(iface, device, socket_set, now, rng.random()); let ap_config = Config::AccessPoint(AccessPointConfig::default().with_ssid("esp-radio".into())); let res = controller.set_config(&ap_config); println!("wifi_set_configuration returned {:?}", res); controller.start().unwrap(); println!("is wifi started: {:?}", controller.is_started()); println!("{:?}", controller.capabilities()); stack .set_iface_configuration(&blocking_network_stack::ipv4::Configuration::Client( blocking_network_stack::ipv4::ClientConfiguration::Fixed( blocking_network_stack::ipv4::ClientSettings { ip: blocking_network_stack::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), subnet: blocking_network_stack::ipv4::Subnet { gateway: blocking_network_stack::ipv4::Ipv4Addr::from(parse_ip( "192.168.2.1", )), mask: blocking_network_stack::ipv4::Mask(24), }, dns: None, secondary_dns: None, }, ), )) .unwrap(); println!( "Start busy loop on main. Connect to the AP `esp-radio` and point your browser to http://192.168.2.1:8080/" ); println!("Use a static IP in the range 192.168.2.2 .. 192.168.2.255, use gateway 192.168.2.1"); let mut rx_buffer = [0u8; 1536]; let mut tx_buffer = [0u8; 1536]; let mut socket = stack.get_socket(&mut rx_buffer, &mut tx_buffer); socket.listen(8080).unwrap(); loop { socket.work(); if !socket.is_open() { socket.listen(8080).unwrap(); } if socket.is_connected() { println!("Connected"); let mut time_out = false; let deadline = time::Instant::now() + Duration::from_secs(20); let mut buffer = [0u8; 1024]; let mut pos = 0; while let Ok(len) = socket.read(&mut buffer[pos..]) { let to_print = unsafe { core::str::from_utf8_unchecked(&buffer[..(pos + len)]) }; if to_print.contains("\r\n\r\n") { print!("{}", to_print); println!(); break; } pos += len; if time::Instant::now() > deadline { println!("Timeout"); time_out = true; break; } } if !time_out { socket .write_all( b"HTTP/1.0 200 OK\r\n\r\n\ \ \

Hello Rust! Hello esp-radio!

\ \ \r\n\ ", ) .unwrap(); socket.flush().unwrap(); } socket.close(); println!("Done\n"); println!(); } let start = time::Instant::now(); while start.elapsed() < Duration::from_secs(5) { socket.work(); } } } fn parse_ip(ip: &str) -> [u8; 4] { let mut result = [0u8; 4]; for (idx, octet) in ip.split(".").into_iter().enumerate() { result[idx] = u8::from_str_radix(octet, 10).unwrap(); } result } // some smoltcp boilerplate fn timestamp() -> smoltcp::time::Instant { smoltcp::time::Instant::from_micros( esp_hal::time::Instant::now() .duration_since_epoch() .as_micros() as i64, ) } pub fn create_interface(device: &mut esp_radio::wifi::WifiDevice) -> smoltcp::iface::Interface { // users could create multiple instances but since they only have one WifiDevice // they probably can't do anything bad with that smoltcp::iface::Interface::new( smoltcp::iface::Config::new(smoltcp::wire::HardwareAddress::Ethernet( smoltcp::wire::EthernetAddress::from_bytes(&device.mac_address()), )), device, timestamp(), ) }