ivmarkov / edge-net Goto Github PK
View Code? Open in Web Editor NEWasync + no_std + no-alloc implementations of various network protocols
License: Apache License 2.0
async + no_std + no-alloc implementations of various network protocols
License: Apache License 2.0
Compilation for no_std
targets fails due to the httparse dependency which enables std
by default.
Line 26 in 233f632
[features]
default = ["std"]
std = []
Quite easy to reproduce - just build master and you will see many errors involving libc.
Hi
I am trying, and failing, to use the edge-net stack on top of esp-idf for an ESP32.
Between stack overflows, watch dog timeouts and mutex access violations, I am stuck trying to implement the basic example for https://crates.io/crates/edge-ws over WiFi. I have tried to use a lot of ideas from ruwm
to get this to run, but I'm just not having luck. (For added context, I can get the esp-idf-svc
http server to run and process web sockets requests, but it is very finicky, often reporting and error on could not get second packet
, even after having received the full message, so I thought I would go the same route as ruwm
(i'm building a power meter)).
The current error I am seeing pops up from ESP land, but I have no idea how to interpret it.
Here is my code:
main.rs:
use edge_http::io::server::{Connection, DefaultServer, Handler};
use edge_http::ws::MAX_BASE64_KEY_RESPONSE_LEN;
use edge_http::Method;
use edge_ws::{FrameHeader, FrameType};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::signal::Signal;
use embassy_time::Timer;
use embedded_io_async::{Read, Write};
use embedded_nal_async_xtra::TcpListen;
use enumset::enum_set;
use esp_idf_svc::eventloop::EspSystemEventLoop;
use esp_idf_svc::hal::cpu::Core;
use esp_idf_svc::hal::delay::FreeRtos;
use esp_idf_svc::hal::peripherals::Peripherals;
use esp_idf_svc::hal::task::block_on;
use esp_idf_svc::hal::task::watchdog::TWDTConfig;
use esp_idf_svc::nvs::EspDefaultNvsPartition;
use esp_idf_svc::sys::EspError;
use esp_idf_svc::wifi;
use esp_idf_svc::wifi::{AuthMethod, BlockingWifi, ClientConfiguration, EspWifi};
use log::{error, info};
const SSID: &str = env!("WIFI_SSID");
const PASSWORD: &str = env!("WIFI_PASS");
// ws
pub static QUIT: Signal<CriticalSectionRawMutex, u32> = Signal::new();
const WS_MAX_CONNECTIONS: usize = 2;
// const
fn main() -> Result<(), EspError> {
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
esp_idf_svc::timer::embassy_time_driver::link();
esp_idf_svc::sys::link_patches();
// Bind the log crate to the ESP Logging facilities
esp_idf_svc::log::EspLogger::initialize_default();
esp_idf_svc::io::vfs::initialize_eventfd(5)?;
let sys_loop = EspSystemEventLoop::take().unwrap();
let peripherals = Peripherals::take().unwrap();
let nvs = EspDefaultNvsPartition::take().unwrap();
let mut wifi = BlockingWifi::wrap(
EspWifi::new(peripherals.modem, sys_loop.clone(), Some(nvs)).unwrap(),
sys_loop,
)
.unwrap();
log::warn!("wifi got");
let wifi_configuration = wifi::Configuration::Client(ClientConfiguration {
ssid: SSID.try_into().unwrap(),
auth_method: AuthMethod::WPA2Personal,
password: PASSWORD.try_into().unwrap(),
..Default::default()
});
log::warn!("wifi config");
let config = TWDTConfig {
duration: Duration::from_secs(2),
panic_on_trigger: true,
subscribed_idle_tasks: enum_set!(Core::Core0),
};
let mut driver = esp_idf_svc::hal::task::watchdog::TWDTDriver::new(peripherals.twdt, &config)?;
let mut watchdog = driver.watch_current_task()?;
wifi.set_configuration(&wifi_configuration).unwrap();
log::warn!("config set");
wifi.wifi_mut().start();
loop {
if (wifi.is_started()?) {
break;
}
watchdog.feed();
FreeRtos::delay_ms(200);
}
log::warn!("started ");
wifi.wifi_mut().connect();
loop {
if (wifi.is_connected()?) {
break;
}
watchdog.feed();
FreeRtos::delay_ms(200);
}
log::warn!("coonnected");
watchdog.feed();
loop {
if (wifi.is_up()?) {
break;
}
watchdog.feed();
FreeRtos::delay_ms(200);
}
info!(
"Created Wi-Fi with WIFI_SSID `{}` and WIFI_PASS `{}`",
SSID, PASSWORD
);
for i in 0..5 {
FreeRtos::delay_ms(500);
watchdog.feed();
}
let handle = std::thread::spawn(thread_fn);
// handle.join().unwrap();
loop {
watchdog.feed();
// unsafe {
// esp_idf_svc::sys::esp_task_wdt_reset();
// }
FreeRtos::delay_ms(500);
}
// handle.join().unwrap();
Ok(())
}
fn thread_fn() {
info!("About to make server");
let mut server = DefaultServer::new();
info!("made server");
match block_on(run(&mut server)) {
Ok(x) => (),
Err(x) => error!("err {x}"),
};
// futures_lite::future::block_on(run(&mut server)).unwrap();
}
pub async fn run(server: &mut DefaultServer) -> Result<(), anyhow::Error> {
let addr = "0.0.0.0:8881";
info!("Running HTTP server on {addr}");
let acceptor = edge_std_nal_async::Stack::new()
.listen(addr.parse().unwrap())
.await?;
server.run(acceptor, WsHandler, None).await?;
loop {
Timer::after(embassy_time::Duration::from_millis(1000)).await
}
Ok(())
}
struct WsHandler;
impl<'b, T, const N: usize> Handler<'b, T, N> for WsHandler
where
T: Read + Write,
T::Error: Send + Sync + std::error::Error + 'static,
{
type Error = anyhow::Error;
async fn handle(&self, conn: &mut Connection<'b, T, N>) -> Result<(), Self::Error> {
let headers = conn.headers()?;
if matches!(headers.method, Some(Method::Get)) {
conn.initiate_response(405, Some("Method not allowed"), &[])
.await?;
} else if !matches!(headers.path, Some("/")) {
conn.initiate_response(404, Some("Not found"), &[]).await?;
} else if !conn.is_ws_upgrade_request()? {
conn.initiate_response(200, Some("OK"), &[("Content-Type", "text/plain")])
.await?;
conn.write_all(b"Initiate upgrade").await?;
} else {
let mut buf = [0u8; MAX_BASE64_KEY_RESPONSE_LEN];
conn.initiate_ws_upgrade_response(&mut buf).await?;
conn.complete().await?;
let mut socket = conn.unbind()?;
let mut buff = [0u8; 8192];
loop {
let mut header = FrameHeader::recv(&mut socket).await?;
let payload = header.recv_payload(&mut socket, &mut buff).await?;
match header.frame_type {
edge_ws::FrameType::Text(x) => {
info!(
"Got (fragmented? {x}) {header} with payload {} ",
core::str::from_utf8(payload).unwrap()
);
}
edge_ws::FrameType::Binary(x) => {
info!("Got {header} with payload {payload:?}");
}
edge_ws::FrameType::Close => {
info!("Got {header}, client closed the connection cleanly.");
}
_ => {
info!("Got {header}");
}
}
// server never mask the payload?
header.mask_key = None;
if matches!(header.frame_type, FrameType::Ping) {
header.frame_type = FrameType::Pong;
}
info!("Echoing back as {header}");
header.send(&mut socket).await;
header.send_payload(&mut socket, payload).await?;
}
}
Ok(())
}
}
sdkconfig.defaults
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
CONFIG_ESP_MAIN_TASK_STACK_SIZE=20000
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=60000
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=4096
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=9216
#CONFIG_ESP_TASK_WDT_EN=n
# CONFIG_HTTPD_WS_SUPPORT=y
# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
# This allows to use 1 ms granuality for thread sleeps (10 ms by default).
#CONFIG_FREERTOS_HZ=1000
# Workaround for https://github.com/espressif/esp-idf/issues/7631
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n
Cargo.toml
[package]
name = "websockets-play"
version = "0.1.0"
authors = ["Dane Slattery <[email protected]>"]
edition = "2021"
resolver = "2"
rust-version = "1.71"
[profile.release]
opt-level = "s"
[profile.dev]
debug = true # Symbols are nice and they don't increase the size on Flash
opt-level = "z"
[features]
default = [
"std",
"embassy",
"esp-idf-svc/native",
"channel-bridge/embedded-svc",
]
pio = ["esp-idf-svc/pio"]
std = ["alloc", "esp-idf-svc/binstart", "esp-idf-svc/std"]
alloc = ["esp-idf-svc/alloc"]
nightly = ["esp-idf-svc/nightly"]
experimental = ["esp-idf-svc/experimental"]
embassy = [
"esp-idf-svc/embassy-sync",
"esp-idf-svc/critical-section",
"esp-idf-svc/embassy-time-driver",
]
[dependencies]
log = { version = "0.4", default-features = false }
esp-idf-svc = { version = "0.48", default-features = false }
channel-bridge = { version = "*", features = ["embedded-svc"] }
embassy-sync = { version = "*", features = ["std"] }
edge-executor = "*"
edge-http = { version = "*", features = ["std"] }
edge-std-nal-async = "*"
edge-ws = { version = "*", features = ["std"] }
embedded-nal-async-xtra = "*"
anyhow = "*"
embedded-io-async = { version = "*" }
embassy-time = { version = "0.3.0", features = ["generic-queue"] }
async-io = "*"
enumset = "*"
futures-lite = "*"
[build-dependencies]
embuild = "0.31.3"
.cargo/config.toml
[build]
target = "xtensa-esp32s3-espidf"
[target.xtensa-esp32s3-espidf]
linker = "ldproxy"
# runner = "espflash --monitor" # Select this runner for espflash v1.x.x
runner = "espflash flash --monitor" # Select this runner for espflash v2.x.x
rustflags = [
"--cfg",
"espidf_time64",
] # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110
[unstable]
build-std = ["std", "panic_abort"]
[env]
MCU = "esp32s3"
# Note: this variable is not used by the pio builder (`cargo build --features pio`)
ESP_IDF_VERSION = "v5.1.3"
WIFI_SSID = ""
WIFI_PASS = ""
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.