esp-hal/examples/src/bin/wifi_access_point_with_sta.rs
Jesse Braham 891a12e13f
Derive Builder Lite pattern for HAL configuration, update examples/tests (#2645)
* Derive Builder Lite pattern for `esp_hal::Config` and `WatchdogConfig`

* User builder pattern for `esp_hal::Config` in examples/tests

* Update `CHANGELOG.md`
2024-12-02 14:45:05 +00:00

233 lines
7.4 KiB
Rust

//! Access point with station
//!
//! Set SSID and PASSWORD env variable before running this example.
//!
//! Gets an ip address via DHCP, creates an open access-point with SSID `esp-wifi`
//! 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 - the example will perform an HTTP get request to some "random" server
//!
//! 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`
//!
//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils
//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6
#![no_std]
#![no_main]
use blocking_network_stack::Stack;
use embedded_io::*;
use esp_alloc as _;
use esp_backtrace as _;
use esp_hal::{
prelude::*,
rng::Rng,
time::{self, Duration},
timer::timg::TimerGroup,
};
use esp_println::{print, println};
use esp_wifi::{
init,
wifi::{
utils::{create_ap_sta_network_interface, ApStaInterface},
AccessPointConfiguration,
ClientConfiguration,
Configuration,
},
};
use smoltcp::{
iface::{SocketSet, SocketStorage},
wire::{IpAddress, Ipv4Address},
};
const SSID: &str = env!("SSID");
const PASSWORD: &str = env!("PASSWORD");
#[entry]
fn main() -> ! {
esp_println::logger::init_logger(log::LevelFilter::Info);
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
esp_alloc::heap_allocator!(72 * 1024);
let timg0 = TimerGroup::new(peripherals.TIMG0);
let mut rng = Rng::new(peripherals.RNG);
let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap();
let wifi = peripherals.WIFI;
let ApStaInterface {
ap_interface,
sta_interface,
ap_device,
sta_device,
mut controller,
} = create_ap_sta_network_interface(&init, wifi).unwrap();
let now = || time::now().duration_since_epoch().to_millis();
let mut ap_socket_set_entries: [SocketStorage; 3] = Default::default();
let ap_socket_set = SocketSet::new(&mut ap_socket_set_entries[..]);
let mut ap_stack = Stack::new(ap_interface, ap_device, ap_socket_set, now, rng.random());
let mut sta_socket_set_entries: [SocketStorage; 3] = Default::default();
let mut sta_socket_set = SocketSet::new(&mut sta_socket_set_entries[..]);
sta_socket_set.add(smoltcp::socket::dhcpv4::Socket::new());
let sta_stack = Stack::new(sta_interface, sta_device, sta_socket_set, now, rng.random());
let client_config = Configuration::Mixed(
ClientConfiguration {
ssid: SSID.try_into().unwrap(),
password: PASSWORD.try_into().unwrap(),
..Default::default()
},
AccessPointConfiguration {
ssid: "esp-wifi".try_into().unwrap(),
..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!("{:?}", controller.capabilities());
ap_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!("wifi_connect {:?}", controller.connect());
// wait for STA getting an ip address
println!("Wait to get an ip address");
loop {
sta_stack.work();
if sta_stack.is_iface_up() {
println!("got ip {:?}", sta_stack.get_ip_info());
break;
}
}
println!("Start busy loop on main. Connect to the AP `esp-wifi` 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 ap_socket = ap_stack.get_socket(&mut rx_buffer, &mut tx_buffer);
let mut sta_rx_buffer = [0u8; 1536];
let mut sta_tx_buffer = [0u8; 1536];
let mut sta_socket = sta_stack.get_socket(&mut sta_rx_buffer, &mut sta_tx_buffer);
ap_socket.listen(8080).unwrap();
loop {
ap_socket.work();
if !ap_socket.is_open() {
ap_socket.listen(8080).unwrap();
}
if ap_socket.is_connected() {
println!("Connected");
let mut time_out = false;
let deadline = time::now() + Duration::secs(20);
let mut buffer = [0u8; 1024];
let mut pos = 0;
loop {
if let Ok(len) = ap_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;
} else {
break;
}
if time::now() > deadline {
println!("Timeout");
time_out = true;
break;
}
}
if !time_out {
println!("Making HTTP request");
sta_socket.work();
sta_socket
.open(IpAddress::Ipv4(Ipv4Address::new(142, 250, 185, 115)), 80)
.unwrap();
sta_socket
.write(b"GET / HTTP/1.0\r\nHost: www.mobile-j.de\r\n\r\n")
.unwrap();
sta_socket.flush().unwrap();
let deadline = time::now() + Duration::secs(20);
loop {
let mut buffer = [0u8; 512];
if let Ok(len) = sta_socket.read(&mut buffer) {
ap_socket.write_all(&buffer[..len]).unwrap();
ap_socket.flush().unwrap();
} else {
break;
}
if time::now() > deadline {
println!("Timeout");
break;
}
}
println!();
sta_socket.disconnect();
}
ap_socket.close();
println!("Done\n");
println!();
}
let deadline = time::now() + Duration::secs(5);
while time::now() < deadline {
ap_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
}