Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AP-STA mode #299

Merged
merged 16 commits into from
Nov 6, 2023
Merged
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ jobs:
run: cd esp-wifi && cargo b${{ matrix.chip }} --features=async,wifi,esp-now,embassy-net,log,${{ matrix.chip }}-hal/embassy-time-timg0
- name: build (common features + defmt)
run: cd esp-wifi && cargo b${{ matrix.chip }} --no-default-features --features=async,wifi,esp-now,embassy-net,defmt,${{ matrix.chip }}-hal/embassy-time-timg0
- name: build (access_point)
run: cd esp-wifi && cargo b${{ matrix.chip }} --release --example=access_point --features=wifi
- name: build (access_point_with_sta)
run: cd esp-wifi && cargo b${{ matrix.chip }} --release --example=access_point_with_sta --features=wifi
- name: build (dhcp)
run: cd esp-wifi && cargo b${{ matrix.chip }} --release --example=dhcp --features=wifi
- name: build (bench)
Expand All @@ -81,6 +85,8 @@ jobs:
run: cd esp-wifi && cargo b${{ matrix.chip }} --release --example=embassy_bench --features=async,wifi,embassy-net,${{ matrix.chip }}-hal/embassy-time-timg0
- name: build (embassy_access_point)
run: cd esp-wifi && cargo b${{ matrix.chip }} --release --example=embassy_access_point --features=async,wifi,embassy-net,${{ matrix.chip }}-hal/embassy-time-timg0
- name: build (embassy_access_point_with_sta)
run: cd esp-wifi && cargo b${{ matrix.chip }} --release --example=embassy_access_point_with_sta --features=async,wifi,embassy-net,${{ matrix.chip }}-hal/embassy-time-timg0

- name: build (common features + ble)
if: ${{ matrix.chip != 'esp32s2' }}
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ See [Examples] for details.
## Missing / To be done

- Make CoEx work on ESP32 (it kind of works when commenting out setting the country in wifi_start, probably some mis-compilation since it then crashes in a totally different code path)
- Combined SoftAP/STA mode
- Support for non-open SoftAP
- Direct-boot mode isn't supported

Expand Down
22 changes: 22 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ cargo esp32c3 --release ...

`cargo $CHIP --example access_point --release --features "embedded-svc,wifi"`

### access_point_with_sta

- set SSID and PASSWORD env variable
- 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`

`cargo $CHIP --example access_point_with_sta --release --features "embedded-svc,wifi"`

### embassy_access_point

- creates an open access-point with SSID `esp-wifi`
Expand All @@ -100,6 +111,17 @@ cargo esp32c3 --release ...

`cargo $CHIP --example embassy_access_point --release --features "async,embedded-svc,wifi,embassy-net"`

### embassy_access_point_with_sta

- set SSID and PASSWORD env variable
- 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`

`cargo $CHIP --example embassy_access_point_with_sta --release --features "async,embedded-svc,wifi,embassy-net"`

## Benchmarking

A prerequisite to running the benchmark examples is to run the benchmark server on your local machine. Simply run the following commands to do so.
Expand Down
4 changes: 2 additions & 2 deletions esp-wifi/examples/access_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use esp_backtrace as _;
use esp_println::{print, println};
use esp_wifi::initialize;
use esp_wifi::wifi::utils::create_network_interface;
use esp_wifi::wifi::WifiMode;
use esp_wifi::wifi::WifiApDevice;
use esp_wifi::wifi_interface::WifiStack;
use esp_wifi::{current_millis, EspWifiInitFor};
use hal::clock::ClockControl;
Expand Down Expand Up @@ -48,7 +48,7 @@ fn main() -> ! {
let wifi = peripherals.WIFI;
let mut socket_set_entries: [SocketStorage; 3] = Default::default();
let (iface, device, mut controller, sockets) =
create_network_interface(&init, wifi, WifiMode::Ap, &mut socket_set_entries).unwrap();
create_network_interface(&init, wifi, WifiApDevice, &mut socket_set_entries).unwrap();
let mut wifi_stack = WifiStack::new(iface, device, sockets, current_millis);

let client_config = Configuration::AccessPoint(AccessPointConfiguration {
Expand Down
224 changes: 224 additions & 0 deletions esp-wifi/examples/access_point_with_sta.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
#![no_std]
#![no_main]

#[path = "../../examples-util/util.rs"]
mod examples_util;
use examples_util::hal;

use embedded_io::*;
use embedded_svc::ipv4::Interface;
use embedded_svc::wifi::{AccessPointConfiguration, ClientConfiguration, Configuration, Wifi};

use esp_backtrace as _;
use esp_println::{print, println};
use esp_wifi::initialize;
use esp_wifi::wifi::utils::{create_ap_sta_network_interface, ApStaInterface};
use esp_wifi::wifi_interface::WifiStack;
use esp_wifi::{current_millis, EspWifiInitFor};
use hal::clock::ClockControl;
use hal::Rng;
use hal::{peripherals::Peripherals, prelude::*};

use smoltcp::iface::SocketStorage;
use smoltcp::wire::IpAddress;
use smoltcp::wire::Ipv4Address;

const SSID: &str = env!("SSID");
const PASSWORD: &str = env!("PASSWORD");

#[entry]
fn main() -> ! {
#[cfg(feature = "log")]
esp_println::logger::init_logger(log::LevelFilter::Info);

let peripherals = Peripherals::take();

let system = peripherals.SYSTEM.split();
let clocks = ClockControl::max(system.clock_control).freeze();

#[cfg(target_arch = "xtensa")]
let timer = hal::timer::TimerGroup::new(peripherals.TIMG1, &clocks).timer0;
#[cfg(target_arch = "riscv32")]
let timer = hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0;
let init = initialize(
EspWifiInitFor::Wifi,
timer,
Rng::new(peripherals.RNG),
system.radio_clock_control,
&clocks,
)
.unwrap();

let wifi = peripherals.WIFI;

let mut ap_socket_set_entries: [SocketStorage; 3] = Default::default();
let mut sta_socket_set_entries: [SocketStorage; 3] = Default::default();

let ApStaInterface {
ap_interface,
sta_interface,
ap_device,
sta_device,
mut controller,
ap_socket_set,
sta_socket_set,
} = create_ap_sta_network_interface(
&init,
wifi,
&mut ap_socket_set_entries,
&mut sta_socket_set_entries,
)
.unwrap();

let mut wifi_ap_stack = WifiStack::new(ap_interface, ap_device, ap_socket_set, current_millis);
let wifi_sta_stack = WifiStack::new(sta_interface, sta_device, sta_socket_set, current_millis);

let client_config = Configuration::Mixed(
ClientConfiguration {
ssid: SSID.into(),
password: PASSWORD.into(),
..Default::default()
},
AccessPointConfiguration {
ssid: "esp-wifi".into(),
..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.get_capabilities());

wifi_ap_stack
.set_iface_configuration(&embedded_svc::ipv4::Configuration::Client(
embedded_svc::ipv4::ClientConfiguration::Fixed(embedded_svc::ipv4::ClientSettings {
ip: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")),
subnet: embedded_svc::ipv4::Subnet {
gateway: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")),
mask: embedded_svc::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 {
wifi_sta_stack.work();

if wifi_sta_stack.is_iface_up() {
println!("got ip {:?}", wifi_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 = wifi_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 = wifi_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 wait_end = current_millis() + 20 * 1000;
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 current_millis() > wait_end {
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 wait_end = current_millis() + 20 * 1000;
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 current_millis() > wait_end {
println!("Timeout");
break;
}
}
println!();

sta_socket.disconnect();
}

ap_socket.close();

println!("Done\n");
println!();
}

let wait_end = current_millis() + 5 * 1000;
while current_millis() < wait_end {
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
}
10 changes: 5 additions & 5 deletions esp-wifi/examples/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use embedded_svc::wifi::{AccessPointInfo, ClientConfiguration, Configuration, Wi
use esp_backtrace as _;
use esp_println::println;
use esp_wifi::wifi::utils::create_network_interface;
use esp_wifi::wifi::{WifiError, WifiMode};
use esp_wifi::wifi::{WifiError, WifiStaDevice};
use esp_wifi::wifi_interface::WifiStack;
use esp_wifi::{current_millis, initialize, EspWifiInitFor};
use hal::clock::ClockControl;
Expand Down Expand Up @@ -62,7 +62,7 @@ fn main() -> ! {
let wifi = peripherals.WIFI;
let mut socket_set_entries: [SocketStorage; 3] = Default::default();
let (iface, device, mut controller, sockets) =
create_network_interface(&init, wifi, WifiMode::Sta, &mut socket_set_entries).unwrap();
create_network_interface(&init, wifi, WifiStaDevice, &mut socket_set_entries).unwrap();
let wifi_stack = WifiStack::new(iface, device, sockets, current_millis);

let client_config = Configuration::Client(ClientConfiguration {
Expand Down Expand Up @@ -137,7 +137,7 @@ fn main() -> ! {

fn test_download<'a>(
server_address: Ipv4Address,
socket: &mut esp_wifi::wifi_interface::Socket<'a, 'a>,
socket: &mut esp_wifi::wifi_interface::Socket<'a, 'a, WifiStaDevice>,
) {
println!("Testing download...");
socket.work();
Expand Down Expand Up @@ -171,7 +171,7 @@ fn test_download<'a>(

fn test_upload<'a>(
server_address: Ipv4Address,
socket: &mut esp_wifi::wifi_interface::Socket<'a, 'a>,
socket: &mut esp_wifi::wifi_interface::Socket<'a, 'a, WifiStaDevice>,
) {
println!("Testing upload...");
socket.work();
Expand Down Expand Up @@ -205,7 +205,7 @@ fn test_upload<'a>(

fn test_upload_download<'a>(
server_address: Ipv4Address,
socket: &mut esp_wifi::wifi_interface::Socket<'a, 'a>,
socket: &mut esp_wifi::wifi_interface::Socket<'a, 'a, WifiStaDevice>,
) {
println!("Testing upload+download...");
socket.work();
Expand Down
4 changes: 2 additions & 2 deletions esp-wifi/examples/coex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use bleps::{
};

use esp_wifi::{
ble::controller::BleConnector, current_millis, wifi::WifiMode, wifi_interface::WifiStack,
ble::controller::BleConnector, current_millis, wifi::WifiStaDevice, wifi_interface::WifiStack,
EspWifiInitFor,
};

Expand Down Expand Up @@ -61,7 +61,7 @@ fn main() -> ! {

let mut socket_set_entries: [SocketStorage; 3] = Default::default();
let (iface, device, mut controller, sockets) =
create_network_interface(&init, wifi, WifiMode::Sta, &mut socket_set_entries).unwrap();
create_network_interface(&init, wifi, WifiStaDevice, &mut socket_set_entries).unwrap();
let wifi_stack = WifiStack::new(iface, device, sockets, current_millis);

let client_config = Configuration::Client(ClientConfiguration {
Expand Down
4 changes: 2 additions & 2 deletions esp-wifi/examples/dhcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use embedded_svc::wifi::{AccessPointInfo, ClientConfiguration, Configuration, Wi
use esp_backtrace as _;
use esp_println::{print, println};
use esp_wifi::wifi::utils::create_network_interface;
use esp_wifi::wifi::{WifiError, WifiMode};
use esp_wifi::wifi::{WifiError, WifiStaDevice};
use esp_wifi::wifi_interface::WifiStack;
use esp_wifi::{current_millis, initialize, EspWifiInitFor};
use hal::clock::ClockControl;
Expand Down Expand Up @@ -51,7 +51,7 @@ fn main() -> ! {
let wifi = peripherals.WIFI;
let mut socket_set_entries: [SocketStorage; 3] = Default::default();
let (iface, device, mut controller, sockets) =
create_network_interface(&init, wifi, WifiMode::Sta, &mut socket_set_entries).unwrap();
create_network_interface(&init, wifi, WifiStaDevice, &mut socket_set_entries).unwrap();
let wifi_stack = WifiStack::new(iface, device, sockets, current_millis);

let client_config = Configuration::Client(ClientConfiguration {
Expand Down
Loading
Loading