-
I'm trying to figure out both why and how I'm corrupting my stack with this code. It's mostly based off of wifi_embassy_access_point. I'm trying to set up a wifi access point that I can allow some other device to connect to and open up TCP socket for communication with the ESP32 device to control it's peripherals from a laptop computer. I don't yet want to report it as a bug as this may be either the ESP32-PICO-D4 doesn't have enough stack memory, I could have set this up wrong, or some other issue that I'm unfamiliar with. Any assistance for this would be greatly appreciated and I'm willing to work further with JTAG debugging, I'm honestly just not familiar with how to debug stack corruption and want to know best next steps. Most of my code is from either the examples or esp-generate and it's as follows: #![no_std]
#![no_main]
use core::str::FromStr;
use embassy_executor::Spawner;
use embassy_net::tcp::TcpSocket;
use embassy_net::{IpListenEndpoint, Ipv4Address, Stack, StackResources};
use embassy_net::{Ipv4Cidr, StaticConfigV4};
use embassy_time::{Duration, Timer};
use esp_alloc::heap_allocator;
use esp_backtrace as _;
use esp_hal::{prelude::*, timer::timg::TimerGroup};
use esp_println::println;
use esp_wifi::wifi::{
AccessPointConfiguration, Configuration, WifiApDevice, WifiController, WifiDevice, WifiEvent,
WifiState,
};
use esp_wifi::EspWifiController;
use log::info;
extern crate alloc;
mod built;
use built::wifi_config::wifi_config;
// 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
}};
}
#[main]
async fn main(spawner: Spawner) {
heap_allocator!(72 * 1024);
let peripherals = esp_hal::init({
let mut config = esp_hal::Config::default();
config.cpu_clock = CpuClock::max();
config
});
esp_println::logger::init_logger_from_env();
// Initialize embassy timer from timer 0 in timer group 1
let timer_g1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init(timer_g1.timer0);
info!("Embassy initialized!");
// Initialize wifi control timer from timer 0 in timer group 0
let timer_g0 = TimerGroup::new(peripherals.TIMG0);
let wifi_cont = mk_static!(
EspWifiController<'static>,
esp_wifi::init(
timer_g0.timer0,
esp_hal::rng::Rng::new(peripherals.RNG),
peripherals.RADIO_CLK,
)
.expect("Failed to initialize wifi controller")
);
let wifi = peripherals.WIFI;
let (wifi_interface, mut controller) =
esp_wifi::wifi::new_with_mode(wifi_cont, wifi, WifiApDevice).unwrap();
// Configuration as an access point meaning that other devices access it as a router
controller
.set_configuration(&Configuration::AccessPoint(wifi_config()))
.unwrap();
let gw_ip_addr_str = "192.168.2.1";
let gw_ip_addr = Ipv4Address::from_str(gw_ip_addr_str).expect("failed to parse gateway ip");
let config = embassy_net::Config::ipv4_static(StaticConfigV4 {
address: Ipv4Cidr::new(gw_ip_addr, 24), // Creates a subnet with mask /24 (255.255.255.0)
gateway: Some(gw_ip_addr), // Sets the gateway IP
dns_servers: Default::default(), // No DNS servers configured
});
let seed = 1234; // Used for generating TCP/IP sequence numbers
// Init network stack
let stack = &*mk_static!(
Stack<WifiDevice<'_, WifiApDevice>>,
Stack::new(
wifi_interface,
config,
mk_static!(StackResources<64>, StackResources::<64>::new()),
seed
)
);
let mut rx_buffer = [0; 128];
let mut tx_buffer = [0; 128];
loop {
if stack.is_link_up() {
break;
}
Timer::after(Duration::from_millis(500)).await;
}
println!(
"Connect to the AP `esp-wifi` and point your browser to http://{gw_ip_addr_str}:8080/"
);
println!("DHCP is enabled so there's no need to configure a static IP, just in case:");
while !stack.is_config_up() {
Timer::after(Duration::from_millis(100)).await
}
stack
.config_v4()
.inspect(|c| println!("ipv4 config: {c:?}"));
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
loop {
println!("Wait for connection...");
let r = socket
.accept(IpListenEndpoint {
addr: None,
port: 8080,
})
.await;
println!("Connected...");
if let Err(e) = r {
println!("connect error: {:?}", e);
continue;
}
use embedded_io_async::Write;
let mut buffer = [0u8; 1024];
let mut pos = 0;
loop {
match socket.read(&mut buffer).await {
Ok(0) => {
println!("read EOF");
break;
}
Ok(len) => {
let to_print =
unsafe { core::str::from_utf8_unchecked(&buffer[..(pos + len)]) };
if to_print.contains("\r\n\r\n") {
println!("{}", to_print);
break;
}
pos += len;
}
Err(e) => {
println!("read error: {:?}", e);
break;
}
};
}
let r = socket
.write_all(
b"HTTP/1.0 200 OK\r\n\r\n\
<html>\
<body>\
<h1>Hello Rust! Hello esp-wifi!</h1>\
</body>\
</html>\r\n\
",
)
.await;
if let Err(e) = r {
println!("write error: {:?}", e);
}
let r = socket.flush().await;
if let Err(e) = r {
println!("flush error: {:?}", e);
}
Timer::after(Duration::from_millis(1000)).await;
socket.close();
Timer::after(Duration::from_millis(1000)).await;
socket.abort();
}
}
#[embassy_executor::task]
async fn run_dhcp(
stack: &'static Stack<WifiDevice<'static, WifiApDevice>>,
gw_ip_addr: &'static str,
) {
use core::net::{Ipv4Addr, SocketAddrV4};
use edge_dhcp::{
io::{self, DEFAULT_SERVER_PORT},
server::{Server, ServerOptions},
};
use edge_nal::UdpBind;
use edge_nal_embassy::{Udp, UdpBuffers};
let ip = Ipv4Addr::from_str(gw_ip_addr).expect("dhcp task failed to parse gw ip");
let mut buf = [0u8; 1500];
let mut gw_buf = [Ipv4Addr::UNSPECIFIED];
let buffers = UdpBuffers::<3, 1024, 1024, 10>::new();
let unbound_socket = Udp::new(stack, &buffers);
let mut bound_socket = unbound_socket
.bind(core::net::SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::UNSPECIFIED,
DEFAULT_SERVER_PORT,
)))
.await
.unwrap();
loop {
_ = io::server::run(
&mut Server::<64>::new(ip),
&ServerOptions::new(ip, Some(&mut gw_buf)),
&mut bound_socket,
&mut buf,
)
.await
.inspect_err(|e| log::warn!("DHCP server error: {e:?}"));
Timer::after(Duration::from_millis(500)).await;
}
}
#[embassy_executor::task]
async fn connection(mut controller: WifiController<'static>) {
println!("start connection task");
println!("Device capabilities: {:?}", controller.capabilities());
loop {
match esp_wifi::wifi::wifi_state() {
WifiState::ApStarted => {
// wait until we're no longer connected
controller.wait_for_event(WifiEvent::ApStop).await;
Timer::after(Duration::from_millis(5000)).await
}
_ => {}
}
if !matches!(controller.is_started(), Ok(true)) {
let client_config = Configuration::AccessPoint(AccessPointConfiguration {
ssid: "esp-wifi".try_into().unwrap(),
..Default::default()
});
controller.set_configuration(&client_config).unwrap();
println!("Starting wifi");
controller.start_async().await.unwrap();
println!("Wifi started!");
}
}
}
#[embassy_executor::task]
async fn net_task(stack: &'static Stack<WifiDevice<'static, WifiApDevice>>) {
stack.run().await
} Related wifi module to set wifi configurations (I hope to use it to allow a RON file to set WIFI settings): use core::str::FromStr;
use esp_wifi::wifi::{AccessPointConfiguration, AuthMethod, Protocol};
use heapless::String;
pub fn wifi_config() -> AccessPointConfiguration {
AccessPointConfiguration {
ssid: String::<32>::from_str("Test_Point").expect("SSID Error"),
ssid_hidden: false,
channel: 1,
secondary_channel: None,
protocols: (Protocol::P802D11BGNAX).into(),
auth_method: AuthMethod::WPA2Personal,
password: String::<64>::from_str("PassTest").expect("Password Error"),
max_connections: 2,
}
} additionally my Cargo.toml file is: [package]
name = "esp-aranya"
version = "0.1.0"
edition = "2021"
[dependencies]
esp-backtrace = { version = "0.14.2", features = [
"esp32",
"exception-handler",
"panic-handler",
"println",
]}
esp-hal = { version = "0.22.0", features = [
"esp32",
] }
esp-println = { version = "0.12.0", features = ["esp32", "log"] }
log = { version = "0.4.21" }
esp-alloc = { version = "0.5.0" }
embedded-io = "0.6.1"
embedded-io-async = "0.6.1"
embassy-net = { version = "0.4.0", features = [ "tcp", "udp", "dhcpv4", "medium-ethernet"] }
esp-wifi = { version = "0.11.0", default-features=false, features = [
"esp32",
"utils",
"wifi",
"esp-alloc",
"log",
] }
heapless = { version = "0.8.0", default-features = false }
smoltcp = { version = "0.11.0", default-features = false, features = [
"medium-ethernet",
"proto-dhcpv4",
"proto-igmp",
"proto-ipv4",
"socket-dhcpv4",
"socket-icmp",
"socket-raw",
"socket-tcp",
"socket-udp",
] }
embassy-executor = { version = "0.6.0", features = [
"task-arena-size-12288",
] }
embassy-time = { version = "0.3.1", features = ["generic-queue-8"] }
esp-hal-embassy = { version = "0.5.0", features = ["esp32"] }
static_cell = { version = "2.1.0", features = ["nightly"] }
enumset = "1.1.5"
edge-dhcp = "0.3.0"
edge-nal = "0.3.0"
edge-nal-embassy = "0.3.0"
critical-section = "1.2.0"
# esp-storage = { version = "0.4.0", features = ["critical-section","storage","esp32"] }
[build-dependencies]
ron = "0.8.1"
serde = {version = "1.0.215", features = ["derive"] }
[profile.dev]
# Rust debug is too slow.
# For debug builds always builds with some optimization
opt-level = "s"
[profile.release]
codegen-units = 1 # LLVM can perform better optimizations using a single thread
debug = 2
debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 3
overflow-checks = false .config.toml [target.xtensa-esp32-none-elf]
runner = "espflash flash --monitor"
[env]
ESP_LOG="INFO"
[build]
rustflags = [
"-C", "link-arg=-nostartfiles",
"-C", "link-arg=-Tlinkall.x",
"-Z", "stack-protector=all",
]
target = "xtensa-esp32-none-elf"
[unstable]
build-std = ["alloc", "core"] Outside of these files I don't think anything else could be the cause but I also don't see anything wrong with any of them and I'm truly at a bit of a loss for debugging, or really understanding what esp-wifi is doing at a fundamental level so any help or direction to go in this regard would be greatly appreciated. |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 2 replies
-
Further the full log is:
|
Beta Was this translation helpful? Give feedback.
-
Not seeing anything obviously wrong. If you don't enable the stack protector does your program function correctly? I'm wondering if the stack protector is setup incorrectly. |
Beta Was this translation helpful? Give feedback.
-
If you don't mind, are you able to push the whole code to some repository? |
Beta Was this translation helpful? Give feedback.
-
Seems like the stack-protector is doing a good job here. From a brief look I'd say reserving memory for 64 sockets is a lot ( You can try to reduce that. You can also use the otherwise unused memory used by the 2nd stage bootloader during boot for the heap. To do that replace #[link_section = ".dram2_uninit"]
static mut HEAP2: core::mem::MaybeUninit<[u8; 64 * 1024]> = core::mem::MaybeUninit::uninit();
unsafe {
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
HEAP2.as_mut_ptr() as *mut u8,
core::mem::size_of_val(&*core::ptr::addr_of!(HEAP2)),
esp_alloc::MemoryCapability::Internal.into(),
));
} That might give you enough free memory |
Beta Was this translation helpful? Give feedback.
Seems like the stack-protector is doing a good job here.
From a brief look I'd say reserving memory for 64 sockets is a lot (
StackResources<64>
)You can try to reduce that.
You can also use the otherwise unused memory used by the 2nd stage bootloader during boot for the heap.
To do that replace
heap_allocator!(72 * 1024);
with