GithubHelp home page GithubHelp logo

edge-net's Issues

ESP32 Web Socket Listener, TCP Server

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.
image

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 = ""

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.