Git Product home page Git Product logo

esp-idf-svc's Introduction

Safe Rust wrappers for the services in the ESP IDF SDK

CI crates.io Documentation Matrix Wokwi

Highlights

  • Supports almost all ESP IDF services: timers, event loop, Wifi, Ethernet, HTTP client & server, MQTT, WS, NVS, OTA, etc.
  • Implements the traits of embedded-svc
  • Blocking and async mode for each service (async support where feasible)
  • Re-exports esp-idf-hal and esp-idf-sys as esp_idf_svc::hal and esp_idf_svc::sys. You only need to depend on esp_idf_svc to get everything you need

You might want to also check out the ESP IDF Drivers wrappers, and the raw bindings to ESP IDF in the esp-idf-sys crate!

Build Prerequisites

Follow the Prerequisites section in the esp-idf-template crate.

Examples

The examples could be built and flashed conveniently with cargo-espflash. To run e.g. wifi on an e.g. ESP32-C3: (Swap the Rust target and example name with the target corresponding for your ESP32 MCU and with the example you would like to build)

with cargo-espflash:

$ MCU=esp32c3 cargo espflash flash --target riscv32imc-esp-espidf --example wifi --monitor
MCU "--target"
esp32c2 riscv32imc-esp-espidf
esp32c3 riscv32imc-esp-espidf
esp32c6 riscv32imac-esp-espidf
esp32h2 riscv32imac-esp-espidf
esp32p4 riscv32imafc-esp-espidf
esp32 xtensa-esp32-espidf
esp32s2 xtensa-esp32s2-espidf
esp32s3 xtensa-esp32s3-espidf

Setting up a "Hello, world!" binary crate with ESP IDF

Use the esp-idf-template project. Everything would be arranged and built for you automatically - no need to manually clone the ESP IDF repository.

More information

For more information, check out:

esp-idf-svc's People

Contributors

alyoshavasilieva avatar angelo13c avatar anthonygrondin avatar axos88 avatar davidventura avatar elwerene avatar halfvoxel avatar ivansanchez avatar ivmarkov avatar jendakol avatar jothan avatar kevinresol avatar mabezdev avatar martinbroers avatar owenthewizard avatar sergiogasquez avatar sirhcel avatar snapstromegon avatar ssnover avatar taunusflieger avatar teamplayer3 avatar torkleyy avatar truebrain avatar untrade avatar usbalbin avatar vollbrecht avatar weiying-chen avatar wzhd avatar xymist avatar zredshift avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

esp-idf-svc's Issues

posting to eventloop from interrupt broken

Somehow this change:

b5d8295

Broke posting from an interrupt. The post request returns EspError(258).

If I revert to the previous commit it builds fine.

This does not appear to be related to the new panic call. Rather it is because we call isr_post_raw instead of post_raw.

The following change fixes it:

diff --git a/src/eventloop.rs b/src/eventloop.rs
index 2be74f80..b10ce0f4 100644
--- a/src/eventloop.rs
+++ b/src/eventloop.rs
@@ -603,7 +603,7 @@ where
     fn post(&mut self, payload: &P, wait: Option<Duration>) -> Result<bool, Self::Error> {
         if interrupt::active() {
             #[cfg(esp_idf_esp_event_post_from_isr)]
-            let result = P::serialize(payload, |raw_event| self.isr_post_raw(raw_event));
+            let result = P::serialize(payload, |raw_event| self.post_raw(raw_event, wait));
 
             #[cfg(not(esp_idf_esp_event_post_from_isr))]
             let result = {

EspHttpServer doesn't close socket after processing request

After processing a http request the server calls the close_fd() function which should close the open raw socket, but it doesn't. THe socket number (fd) increases from request to request and after the limit of sockets is reached no further connections are processed

Error while building for esp32-c3

Hello! First of all I wanted to say that I really appreciate espressifs work in embedded rust, the ecosystem is really becoming convenient!

But while building my rust code for the esp32-c3-DevKitM I experienced the following compile error:

error[E0432]: unresolved imports `embedded_svc::ota`, `embedded_svc::ota`
  --> /Users/basti/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-svc-0.19.4/src/ota.rs:11:19
   |
11 | use embedded_svc::ota::{self, OtaUpdate};
   |                   ^^^   ^^^^ no `ota` in the root
   |                   |
   |                   could not find `ota` in `embedded_svc`

For more information about this error, try `rustc --explain E0432`.
error: could not compile `esp-idf-svc` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed

I want to build a project with my own code based on ivmarkov/rust-esp32-std-hello. Do you have an idea where the error originates from?

Implement wrappers for ESP-IDF's MQTT client

In the absence of a good story for Rust based TLS in ESP-IDF (yet), we need to expose the ESP-IDF MQTT client as a quick solution for folks asking for MQTT connectivity. Ideally, this should be done against a set of abstract interfaces for MQTT in embedded-svc.

Wifi Issues (ESP32)

Hello,
I'm hoping I'm in the right place to ask this.

I started with Rust on the ESP32 today and wanted to do some basic Web Server and Wifi for testing purpose.
The issue is, that my ESP32 disconnects from Wifi after it started. I get an IP Address but after that it completly shutdowns from Wifi.

My code is:

fn wifi_init() -> String {
    let mut wifi = EspWifi::new(
        Arc::new(EspNetifStack::new().unwrap()),
        Arc::new(EspSysLoopStack::new().unwrap()),
        Arc::new(EspDefaultNvs::new().unwrap())
    )
    .expect("Failed to initialize WiFi");

    wifi.set_configuration(&Configuration::Client(ClientConfiguration {
        ssid: env!("WIFI_SSID").into(),
        password: env!("WIFI_PASSWORD").into(),
        ..Default::default()
    })).unwrap();

    wifi.wait_status_with_timeout(Duration::from_secs(10), |s| {
        !s.is_transitional()
    }).expect("Could not connect to WiFi");

    let status = wifi.get_status();

    let ip = match status.0 {
        embedded_svc::wifi::ClientStatus::Started(ClientConnectionStatus::Connected(ClientIpStatus::Done(settings))) => format!("{}", settings.ip),
        _ => return Err(anyhow!("Not in Client Mode")).unwrap()
    };

    ip
}

and my main:

fn main() {
    esp_idf_sys::link_patches();
    let ip = wifi_init();
    println!("IP is {}", ip);
}

The output is following:

Opening COM3 with speed 115200
Resetting device... done
ets Jun  8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
flash read err, 1000
ets_main.c 371
ets Jun  8 2016 00:22:57
rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0048,len:12
ho 0 tail 12 room 4
load:0x3fff0054,len:4800
load:0x40078000,len:17448
load:0x4007c428,len:4840
entry 0x4007c6a0
I (418) cpu_start: Pro cpu up.
I (418) cpu_start: Starting app cpu, entry point is 0x40081254
I (0) cpu_start: App cpu up.
I (432) cpu_start: Pro cpu start user code
I (432) cpu_start: cpu freq: 160000000
I (432) cpu_start: Application information:
I (437) cpu_start: Project name:     libespidf
I (442) cpu_start: App version:      1
I (446) cpu_start: Compile time:     Apr  3 2022 14:47:57
I (452) cpu_start: ELF file SHA256:  0000000000000000...
I (458) cpu_start: ESP-IDF:          c29343e
I (463) heap_init: Initializing. RAM available for dynamic allocation:
I (470) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (476) heap_init: At 3FFB7408 len 00028BF8 (162 KiB): DRAM
I (483) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (489) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (495) heap_init: At 400933B0 len 0000CC50 (51 KiB): IRAM
I (503) spi_flash: detected chip: generic
I (506) spi_flash: flash io: dio
I (511) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (602) wifi:wifi driver task: 3ffc0b88, prio:23, stack:6656, core=0
I (602) system_api: Base MAC address is not set
I (602) system_api: read default base MAC address from EFUSE
I (602) wifi:wifi firmware version: 63017e0
I (612) wifi:wifi certification version: v7.0
I (612) wifi:config NVS flash: disabled
I (612) wifi:config nano formating: disabled
I (622) wifi:Init data frame dynamic rx buffer num: 32
I (622) wifi:Init management frame dynamic rx buffer num: 32
I (632) wifi:Init management short buffer num: 32
I (632) wifi:Init dynamic tx buffer num: 32
I (642) wifi:Init static rx buffer size: 1600
I (642) wifi:Init static rx buffer num: 10
I (642) wifi:Init dynamic rx buffer num: 32
I (652) wifi_init: rx ba win: 6
I (652) wifi_init: tcpip mbox: 32
I (662) wifi_init: udp mbox: 6
I (662) wifi_init: tcp mbox: 6
I (4022) esp_netif_handlers: sta ip: 192.168.178.32, mask: 255.255.255.0, gw: 192.168.178.1
I (4022) wifi:state: run -> init (0)
I (4022) wifi:pm stop, total sleep time: 452671 us / 761315 us
W (4022) wifi:<ba-del>idx
I (4032) wifi:new:<6,0>, old:<6,0>, ap:<255,255>, sta:<6,0>, prof:1
I (4042) wifi:flush txq
I (4042) wifi:stop sw txq
I (4042) wifi:lmac stop hw txq
W (4042) wifi:hmac tx: ifx0 stop, discard
I (4052) wifi:Deinit lldesc rx mblock:10
IP is 192.168.178.32

After research it sounds like it is a memory issue? Could this be? Because if yes, how could I make it better to work. I would really like to use this for some projects.

I appreciate any help!

EDIT:

With C++ Code with following Lib: #include <WiFi.h> it stays connected

EspWifi - Panic on wifi drop

Hello, i'm working with the Esp32_DevkitC_V4 board and iv been testing out allowing users to connect to the esp32 through a self created AP and having them interact with an HTTP server on the board to submit information about their home WiFi so the board can connect to their WiFi on reboot. Everything works well until the WiFi variable is dropped, where then the main thread panics.

My code

pub fn wifi_setup(nvs: Arc<EspDefaultNvs>) -> Result<(String, String), Box<dyn Error>> {
    let netif_stack: Arc<EspNetifStack> = Arc::new(EspNetifStack::new()?);
    let sys_loop_stack: Arc<EspSysLoopStack> = Arc::new(EspSysLoopStack::new()?);

    info!("Starting wifi");
    let mut wifi: Box<EspWifi> = Box::new(EspWifi::new(netif_stack, sys_loop_stack, nvs)?);

    wifi.set_configuration(&Configuration::AccessPoint(AccessPointConfiguration {
        ssid: "sensor_setup".into(),
        password: "Testing123".into(),
        max_connections: 3,
        auth_method: embedded_svc::wifi::AuthMethod::WPA2Personal,
        ip_conf: Some(RouterConfiguration {
            subnet: Subnet {
                gateway: Ipv4Addr::new(192, 168, 1, 1),
                mask: Mask(24),
            },
            dhcp_enabled: true,
            dns: Some(Ipv4Addr::new(192, 168, 1, 1)),
            secondary_dns: None,
        }),
        ..Default::default()
    }))?;

    info!("Starting setup server");
    let mut server = esp_idf_svc::http::server::EspHttpServer::new(&Default::default())?;
    let ssid: Arc<Mutex<String>> = Arc::new(Mutex::new(String::new()));
    let passwd: Arc<Mutex<String>> = Arc::new(Mutex::new(String::new()));

    let tmp_ssid = ssid.clone();
    let tmp_pass = passwd.clone();
    server
        .handle_get("/", |_req, resp| {
            resp.send_str(
                r#"
                <form method="post" action="setup">
                    <label for="ssid">WifiName:</label><br>
                    <input type="text" id="ssid" name="ssid"><br>
                    <label for="passwd">Password:</label><br>
                    <input type="password" id="passwd" name="passwd">
                    <input type="submit" value="Submit">
                </form> "#,
            )?;
            Ok(())
        })?
        .handle_post("/setup", move |mut req, resp| {
            //Process the form into the ssid and password
            let mut body = Vec::new();

            ToStd::new(req.reader()).read_to_end(&mut body)?;

            let ssid = url::form_urlencoded::parse(&body)
                .filter(|p| p.0 == "ssid")
                .map(|p| p.1.to_string())
                .next()
                .unwrap();
            let pass = url::form_urlencoded::parse(&body)
                .filter(|p| p.0 == "passwd")
                .map(|p| p.1.to_string())
                .next()
                .unwrap();

            *tmp_ssid.lock().unwrap() = ssid;
            *tmp_pass.lock().unwrap() = pass;

            resp.send_str(
                "Wifi setup completed, please reconnect to your home wifi to continue installation",
            )?;

            Ok(())
        })?;

    //Wait for the user to enter in their wifi's SSID and Pass, very janky but it gets the job done. 
    info!("waiting for configured AP info");
    while ssid.lock().unwrap().len() == 0 || passwd.lock().unwrap().len() == 0 {
        std::thread::sleep(Duration::from_millis(250));
    }

    let true_ssid = ssid.lock().unwrap().to_string();
    let true_pass = passwd.lock().unwrap().to_string();

    info!("Got AP info, killing wifi and server");
    drop(server);
    std::thread::sleep(Duration::from_millis(250));
    drop(wifi); //<Crash here
    Ok((true_ssid, true_pass))
}

The error (and things happening before that)

I (61590) iot_temp_firmware::wifi_setup: Got AP info, killing wifi and server
I (61590) esp_idf_svc::http::server: Unregistered Httpd server handler 3 for URI "/setup"
I (61590) esp_idf_svc::http::server: Unregistered Httpd server handler 1 for URI "/"
I (61700) esp_idf_svc::http::server: Httpd server stopped
I (61950) esp_idf_svc::wifi: Stopping
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: EspError(-1)', /home/esp/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-svc-0.42.0/src/wifi.rs:792:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
abort() was called at PC 0x400e1102 on core 0
Backtrace:0x40081caa:0x3ffba8500x40088a3d:0x3ffba870 0x4008edaa:0x3ffba890 0x400e1102:0x3ffba900 0x400e10f6:0x3ffba920 0x400fa7f6:0x3ffba940 0x400fb320:0x3ffba960 0x400faf51:0x3ffbaa00 0x400faf00:0x3ffbaa30 0x400fb679:0x3ffbaa50 0x400d6708:0x3ffbaa80 0x400d8717:0x3ffbaac0 0x400d4475:0x3ffbab20 0x400d5cb2:0x3ffbab70 0x4016337b:0x3ffbae80 0x400d5e17:0x3ffbaea0 0x400e04b9:0x3ffbaf30 0x4016706b:0x3ffbaf50 
ELF file SHA256: 0000000000000000
Rebooting...

It should be noted that before wifi was enabled the object esp_idf_svc::nvs_storage::EspNvsStorage was created so the flash memory could be checked to see if the wifi credentials were already stored on the system. After the check was done the object was dropped.

Thank you for your time.

Map ESP-IDF's mbedTLS to rust-native-tls

... or alternatively, map ESP-IDF's partial OpenSSL implementation to rust-openssl.

Both solutions would require a lot of work and will likely result in patches against one of these upstream crates.

`EspHttpClient` can't work with unknown-size data

If we will try to fetch some unknown-size data then this will not work.

let mut client = EspHttpClient::new(&EspHttpClientConfiguration {
    crt_bundle_attach: Some(esp_idf_sys::esp_crt_bundle_attach),
    ..Default::default()
})?;

let mut response = client.get(&url)?.submit()?;

let mut body = vec![
    0;
    response
        .content_len()
        .unwrap_or(0)
];

let (body, len) = io::read_max(response.reader(), &mut body)?;
info!("Read {} bytes", len);
// still some data left in reader

This happens due to the fact that content_len is not aware of chunked data, this is a possible fix:

fn content_len(&self) -> Option<usize> {
    let content_length = if unsafe { esp_http_client_is_chunked_response(self.client.raw) } {
        let mut len: i32 = 0;
        let res = unsafe { esp_http_client_get_chunk_length(self.client.raw, &mut len) };
        if res != 0 {
            0
        } else {
            len
        }
    } else {
        unsafe { esp_http_client_get_content_length(self.client.raw) }
    };
    if content_length >= 0 {
        Some(content_length as usize)
    } else {
        None
    }
}

But that will not work too because we still have more chunks left, so we need to somehow change Read implementation. We also probably want function like read_all.

Feature Request: Allow customization of httpd::Server configuration

Right now you can only set the http and https port of the httpd server.

Internally this gets resolved to a bigger configuration with more interesting options like max_uri_handlers or in my case uri_match_fn.

Usecase:
I want to build a static fileserver using rust-embed and for that I need/want a wildcard registration (which require the uri_match_fn) so I can lookup the file in a folder and serve that then.

In addition to this the embedded_svc::httpd::Request struct would benefit from a "uri" property (or similar) to get which uri this request belongs to (I didn't see it on first sight). I wanted to check in here first if that's at all wanted by the project.

Workaround currently possible:
Register a handler on "/" and use a query parameter. This feels really dirty, as this is incompatible with many other things like providing a rest API.

Can't configure internal response buffer size

Hello,

Please forgive me if I've missed something obvious, I consider myself decent with Rust, but I've still got a lot to learn.

I'm developing an application that makes use of EspHttpServer. In general it works quite well for me; however, the biggest problem I've encountered is not being able to increase the size of the internal response buffer. Based on how things are implemented it seems like there is no way around the default 64 byte buffer (default from embedded-svc).

If I understand things correctly, based on how the size is controlled by a trait generic, it is essentially constant and cant be changed. Would there be a way to make the size configurable at runtime? (like with a BufReader, something like ::with_capacity()). I'm sure that would require changes to both embedded-svc and esp-idf-svc though.

Thanks!

Documentation fails to build

The docs do not build on docs.rs

build log

# rustc version
rustc 1.57.0-nightly (5ecc8ad84 2021-09-19)
# docs.rs version
docsrs 0.6.0 (432e30a 2021-09-12)

# build log
[INFO] running `Command { std: "docker" "create" "-v" "/home/cratesfyi/workspace/builds/esp-idf-svc-0.20.1/target:/opt/rustwide/target:rw,Z" "-v" "/home/cratesfyi/workspace/builds/esp-idf-svc-0.20.1/source:/opt/rustwide/workdir:ro,Z" "-v" "/home/cratesfyi/workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/home/cratesfyi/workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "DOCS_RS=1" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "3221225472" "--cpus" "2" "--user" "1001:1001" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:a89201d6b5b9fd45c15d5952ece0a0129e7e80cb26ec023fd59cf09bc26f1604" "/opt/rustwide/cargo-home/bin/cargo" "+nightly" "rustdoc" "--lib" "-Zrustdoc-map" "-Zunstable-options" "--config=doc.extern-map.registries.crates-io=\"https://docs.rs/{pkg_name}/{version}/x86_64-unknown-linux-gnu\"" "-j2" "--" "-Z" "unstable-options" "--emit=invocation-specific" "--resource-suffix" "-20210919-1.57.0-nightly-5ecc8ad84" "--static-root-path" "/" "--cap-lints" "warn" "--disable-per-crate-search", kill_on_drop: false }`
[INFO] [stdout] f9c12e04431be89cc02118eae1b9c9eee59977444a9b61c055ef566694544387
[INFO] [stderr] WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.
[INFO] running `Command { std: "docker" "start" "-a" "f9c12e04431be89cc02118eae1b9c9eee59977444a9b61c055ef566694544387", kill_on_drop: false }`
[INFO] [stderr]    Compiling esp-idf-sys v0.20.0
[INFO] [stderr] error: failed to run custom build command for `esp-idf-sys v0.20.0`
[INFO] [stderr] 
[INFO] [stderr] Caused by:
[INFO] [stderr]   process didn't exit successfully: `/opt/rustwide/target/debug/build/esp-idf-sys-a2bf8941e6b245cc/build-script-build` (exit status: 1)
[INFO] [stderr]   --- stdout
[INFO] [stderr]   Installer version: 1.0.2
[INFO] [stderr]   Platform: Linux-5.4.0-1037-aws-x86_64-with-glibc2.29
[INFO] [stderr]   Python version: 3.8.10 (default, Jun  2 2021, 10:49:15) 
[INFO] [stderr]   [GCC 9.4.0]
[INFO] [stderr]   Python path: /usr/bin/python3
[INFO] [stderr]   Creating a virtual environment at /.platformio/penv
[INFO] [stderr]   /usr/bin/python3
[INFO] [stderr] 
[INFO] [stderr]   --- stderr
[INFO] [stderr]   Error: Compatible PlatformIO Core not found.
[INFO] [stderr]   Reason: PlatformIO executable not found in `/.platformio/penv/bin`
[INFO] [stderr]   Traceback (most recent call last):
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/urllib3/connection.py", line 169, in _new_conn
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/urllib3/util/connection.py", line 73, in create_connection
[INFO] [stderr]     File "/usr/lib/python3.8/socket.py", line 918, in getaddrinfo
[INFO] [stderr]       for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
[INFO] [stderr]   socket.gaierror: [Errno -3] Temporary failure in name resolution
[INFO] [stderr] 
[INFO] [stderr]   During handling of the above exception, another exception occurred:
[INFO] [stderr] 
[INFO] [stderr]   Traceback (most recent call last):
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/urllib3/connectionpool.py", line 699, in urlopen
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/urllib3/connectionpool.py", line 382, in _make_request
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/urllib3/connectionpool.py", line 1010, in _validate_conn
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/urllib3/connection.py", line 353, in connect
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/urllib3/connection.py", line 181, in _new_conn
[INFO] [stderr]   urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPSConnection object at 0x7f96e5f5b340>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution
[INFO] [stderr] 
[INFO] [stderr]   During handling of the above exception, another exception occurred:
[INFO] [stderr] 
[INFO] [stderr]   Traceback (most recent call last):
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/requests/adapters.py", line 439, in send
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/urllib3/connectionpool.py", line 755, in urlopen
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/urllib3/util/retry.py", line 574, in increment
[INFO] [stderr]   urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api.registry.platformio.org', port=443): Max retries exceeded with url: /v3/packages/platformio/tool/python-portable (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f96e5f5b340>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution'))
[INFO] [stderr] 
[INFO] [stderr]   During handling of the above exception, another exception occurred:
[INFO] [stderr] 
[INFO] [stderr]   Traceback (most recent call last):
[INFO] [stderr]     File "/tmp/.tmpJjdIul", line 68, in <module>
[INFO] [stderr]       main()
[INFO] [stderr]     File "/tmp/.tmpJjdIul", line 60, in main
[INFO] [stderr]       bootstrap()
[INFO] [stderr]     File "/tmp/.tmpJjdIul", line 46, in bootstrap
[INFO] [stderr]       pioinstaller.__main__.main()
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/pioinstaller/__main__.py", line 131, in main
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/click/core.py", line 829, in __call__
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/click/core.py", line 782, in main
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/click/core.py", line 1236, in invoke
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/click/core.py", line 1066, in invoke
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/click/core.py", line 610, in invoke
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/click/decorators.py", line 21, in new_func
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/pioinstaller/__main__.py", line 61, in cli
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/pioinstaller/core.py", line 67, in install_platformio_core
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/pioinstaller/core.py", line 95, in _install_platformio_core
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/pioinstaller/penv.py", line 58, in create_core_penv
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/pioinstaller/python.py", line 70, in fetch_portable_python
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/pioinstaller/python.py", line 97, in get_portable_python_url
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/requests/api.py", line 76, in get
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/requests/api.py", line 61, in request
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/requests/sessions.py", line 542, in request
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/requests/sessions.py", line 655, in send
[INFO] [stderr]     File "/tmp/.piocore-installer-pq16kjv6/tmphidq62b1/pioinstaller.zip/requests/adapters.py", line 516, in send
[INFO] [stderr]   requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.registry.platformio.org', port=443): Max retries exceeded with url: /v3/packages/platformio/tool/python-portable (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f96e5f5b340>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution'))
[INFO] [stderr]   Error: Compatible PlatformIO Core not found.
[INFO] [stderr]   Reason: PlatformIO executable not found in `/.platformio/penv/bin`
[INFO] [stderr]   Error: EOF while parsing a value at line 1 column 0
[INFO] running `Command { std: "docker" "inspect" "f9c12e04431be89cc02118eae1b9c9eee59977444a9b61c055ef566694544387", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "f9c12e04431be89cc02118eae1b9c9eee59977444a9b61c055ef566694544387", kill_on_drop: false }`
[INFO] [stdout] f9c12e04431be89cc02118eae1b9c9eee59977444a9b61c055ef566694544387

It seems that the docs.rs build environment does not have a networking stack available, so the platformio installation script fails. Is there any way to provide fallback information in the build.rs script so that the docs can be built without networking? I'm also not able to build the docs locally:

error: failed to run custom build command for `esp-idf-sys v0.20.1 (/Users/lily/projects/github.com/esp-rs/esp-idf-sys)`

Caused by:
  process didn't exit successfully: `/Users/lily/projects/github.com/esp-rs/esp-idf-sys/target/debug/build/esp-idf-sys-84056bef3f12ccb1/build-script-build` (exit status: 1)
  --- stdout
  Found compatible PlatformIO Core 5.2.0 -> /Users/lily/.platformio/penv/bin/platformio

  --- stderr
  Error: Cannot derive default PIO platform, MCU and frameworks for target 'aarch64-apple-darwin'

ESP32-C3: Wifi access point remains in `is_transitional` state, causing an infinite loop

I'm trying to put my NodeMCU ESP32-C3M-Kit into Access Point mode.
This seems to work correctly, because I can see the AP in my list of networks, connect to the AP, and get assigned an IP address via DHCP.

However, it seems that the Wifi status remains in the is_transitional state, which causes an infinite loop in EspWifi::wait_status_with_timeout, and eventually a reboot of the device.

This is the code I'm using:

pub fn access_point() -> Result<Box<impl Wifi>> {
    let mut wifi = Box::new(EspWifi::new(
        Arc::new(EspNetif::new()?),
        Arc::new(EspSysLoop::new()?),
        Arc::new(EspDefaultNvs::new()?),
    )?);

    wifi.set_configuration(&Configuration::AccessPoint(AccessPointConfiguration {
        max_connections: 16,
        ..Default::default()
    }))?;

    // we never get here...
    debug!("Wifi access point started");
    Ok(wifi)
}

Relevant output:

I (586) esp_idf_svc::wifi: Driver initialized
I (586) esp_idf_svc::wifi: Event handlers registered
I (596) esp_idf_svc::wifi: Initialization complete
I (606) esp_idf_svc::wifi: Setting configuration: AccessPoint(AccessPointConfiguration { ssid: "iot-device", ssid_hidden: false, channel: 1, secondary_channel: None, protocols: EnumSet(P802D11B | P802D11BG | P802D11BGN), auth_method: None, password: "", max_connections: 16, ip_conf: Some(RouterConfiguration { subnet: Subnet { gateway: 192.168.71.1, mask: Mask(24) }, dhcp_enabled: true, dns: Some(8.8.8.8), secondary_dns: Some(8.8.4.4) }) })
I (636) esp_idf_svc::wifi: Stopping
I (646) esp_idf_svc::wifi: Disconnect requested
I (646) esp_idf_svc::wifi: Stop requested
I (656) esp_idf_svc::wifi: About to wait for status
I (656) esp_idf_svc::wifi: Providing status: Status(Stopped, Stopped)
I (666) esp_idf_svc::wifi: Waiting for status done - success
I (676) esp_idf_svc::wifi: Stopped
I (676) esp_idf_svc::wifi: Wifi mode AP set
I (686) esp_idf_svc::wifi: Setting AP configuration: AccessPointConfiguration { ssid: "iot-device", ssid_hidden: false, channel: 1, secondary_channel: None, protocols: EnumSet(P802D11B | P802D11BG | P802D11BGN), auth_method: None, password: "", max_connections: 16, ip_conf: Some(RouterConfiguration { subnet: Subnet { gateway: 192.168.71.1, mask: Mask(24) }, dhcp_enabled: true, dns: Some(8.8.8.8), secondary_dns: Some(8.8.4.4) }) }
I (726) esp_idf_svc::wifi: Setting AP IP configuration: RouterConfiguration { subnet: Subnet { gateway: 192.168.71.1, mask: Mask(24) }, dhcp_enabled: true, dns: Some(8.8.8.8), secondary_dns: Some(8.8.4.4) }
I (736) esp_idf_svc::wifi: AP netif allocated: 0x3fca4e88
I (746) esp_idf_svc::wifi: AP IP configuration done
I (756) esp_idf_svc::wifi: AP configuration done
I (756) esp_idf_svc::wifi: Starting with status: Status(Stopped, Starting)
I (766) esp_idf_svc::wifi: Status is of operating type, starting
I (776) phy_init: phy_version 500,985899c,Apr 19 2021,16:05:08
I (886) wifi:set rx active PTI: 0, rx ack PTI: 0, and default PTI: 0
I (886) wifi:mode : softAP (7c:df:a1:a4:44:c1)
I (886) wifi:Total power save buffer number: 16
I (896) wifi:Init max length of beacon: 752/752
I (896) wifi:Init max length of beacon: 752/752
I (906) esp_idf_svc::wifi: Got wifi event: 12 
I (906) esp_idf_svc::wifi: Set status: Status(Stopped, Started(Waiting))
I (916) esp_idf_svc::wifi: Wifi event 12 handled
I (916) esp_idf_svc::wifi: Start requested
I (926) esp_idf_svc::wifi: About to wait for status with timeout 10s
I (926) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (5936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (10936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (15936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (20936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (25936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (30936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (35936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (40936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (45936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (50936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (55936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (60936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (65936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (70936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (75936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (80936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (85936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (90936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (95936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (100936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (105936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (105936) esp_idf_svc::wifi: Timeout while waiting for status
I (105936) esp_idf_svc::wifi: Timeout while waiting for the requested state

Full output:

$ cargo +esp espmonitor --release --speed 115200 /dev/cu.usbserial-1440
Opening /dev/cu.usbserial-1440 with speed 115200
WARNING: Flash image /Users/tomk/Projects/Git/3rdparty/rust-esp32-std-hello/target/xtensa-esp32-none-elf/release/rust-esp32-std-hello does not exist (you may need to build it)
Resetting device... done
ESP-ROM:esp32c3-api�ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:2
load:0x3fcd6100,len:0x1758
load:0x403ce000,len:0x894
load:0x403d0000,len:0x2c5c
entry 0x403ce000
I (53) boot: ESP-IDF v4.3-beta3 2nd stage bootloader
I (53) boot: compile time 18:22:41
I (53) boot: chip revision: 3
I (55) boot.esp32c3: SPI Speed      : 40MHz
I (60) boot.esp32c3: SPI Mode       : DIO
I (65) boot.esp32c3: SPI Flash Size : 4MB
I (70) boot: Enabling RNG early entropy source...
I (75) boot: Partition Table:
I (79) boot: ## Label            Usage          Type ST Offset   Length
I (86) boot:  0 phy_init         RF data          01 01 0000f000 00001000
I (93) boot:  1 otadata          OTA data         01 00 00010000 00002000
I (101) boot:  2 nvs              WiFi data        01 02 00012000 0000e000
I (108) boot:  3 at_customize     unknown          40 00 00020000 000e0000
I (116) boot:  4 ota_0            OTA app          00 10 00100000 00180000
I (123) boot:  5 ota_1            OTA app          00 11 00280000 00180000
I (131) boot: End of partition table
E (135) boot: ota data partition invalid and no factory, will try all partitions
I (143) boot_comm: chip revision: 3, min. application chip revision: 0
I (150) esp_image: segment 0: paddr=00100020 vaddr=3c0b0020 size=1f890h (129168) map
I (187) esp_image: segment 1: paddr=0011f8b8 vaddr=3fc8e000 size=00760h (  1888) load
I (188) esp_image: segment 2: paddr=00120020 vaddr=42000020 size=a59fch (678396) map
I (339) esp_image: segment 3: paddr=001c5a24 vaddr=3fc8e760 size=02db8h ( 11704) load
I (342) esp_image: segment 4: paddr=001c87e4 vaddr=40380000 size=0de7ch ( 56956) load
I (358) esp_image: segment 5: paddr=001d6668 vaddr=50000000 size=00010h (    16) load
I (363) boot: Loaded app from partition at offset 0x100000
I (363) boot: Disabling RNG early entropy source...
I (378) cpu_start: Pro cpu up.
I (391) cpu_start: Pro cpu start user code
I (391) cpu_start: cpu freq: 160000000
I (391) cpu_start: Application information:
I (394) cpu_start: Project name:     esp-idf
I (399) cpu_start: App version:      b1339d8-dirty
I (404) cpu_start: Compile time:     Jul 29 2021 21:38:04
I (410) cpu_start: ELF file SHA256:  0000000000000000...
I (416) cpu_start: ESP-IDF:          4.3.0
I (421) heap_init: Initializing. RAM available for dynamic allocation:
I (428) heap_init: At 3FC960E0 len 00029F20 (167 KiB): DRAM
I (434) heap_init: At 3FCC0000 len 0001F060 (124 KiB): STACK/DRAM
I (441) heap_init: At 50000010 len 00001FF0 (7 KiB): RTCRAM
I (448) spi_flash: detected chip: generic
I (452) spi_flash: flash io: dio
I (457) sleep: Configure to isolate all GPIO pins in sleep state
I (463) sleep: Enable automatic switching of GPIO sleep configuration
I (470) cpu_start: Starting scheduler.
I (476) pp: pp rom version: 9387209
I (476) net80211: net80211 rom version: 9387209
I (486) wifi:wifi driver task: 3fc9fb24, prio:23, stack:6656, core=0
I (486) system_api: Base MAC address is not set
I (496) system_api: read default base MAC address from EFUSE
I (496) wifi:wifi firmware version: c7d0450
I (506) wifi:wifi certification version: v7.0
I (506) wifi:config NVS flash: disabled
I (506) wifi:config nano formating: disabled
I (516) wifi:Init data frame dynamic rx buffer num: 32
I (516) wifi:Init management frame dynamic rx buffer num: 32
I (526) wifi:Init management short buffer num: 32
I (526) wifi:Init dynamic tx buffer num: 32
I (536) wifi:Init static tx FG buffer num: 2
I (536) wifi:Init static rx buffer size: 1600
I (536) wifi:Init static rx buffer num: 10
I (546) wifi:Init dynamic rx buffer num: 32
I (546) wifi_init: rx ba win: 6
I (556) wifi_init: tcpip mbox: 32
I (556) wifi_init: udp mbox: 6
I (556) wifi_init: tcp mbox: 6
I (566) wifi_init: tcp tx win: 5744
I (566) wifi_init: tcp rx win: 5744
I (576) wifi_init: tcp mss: 1440
I (576) wifi_init: WiFi IRAM OP enabled
I (576) wifi_init: WiFi RX IRAM OP enabled
I (586) esp_idf_svc::wifi: Driver initialized
I (586) esp_idf_svc::wifi: Event handlers registered
I (596) esp_idf_svc::wifi: Initialization complete
I (606) esp_idf_svc::wifi: Setting configuration: AccessPoint(AccessPointConfiguration { ssid: "iot-device", ssid_hidden: false, channel: 1, secondary_channel: None, protocols: EnumSet(P802D11B | P802D11BG | P802D11BGN), auth_method: None, password: "", max_connections: 16, ip_conf: Some(RouterConfiguration { subnet: Subnet { gateway: 192.168.71.1, mask: Mask(24) }, dhcp_enabled: true, dns: Some(8.8.8.8), secondary_dns: Some(8.8.4.4) }) })
I (636) esp_idf_svc::wifi: Stopping
I (646) esp_idf_svc::wifi: Disconnect requested
I (646) esp_idf_svc::wifi: Stop requested
I (656) esp_idf_svc::wifi: About to wait for status
I (656) esp_idf_svc::wifi: Providing status: Status(Stopped, Stopped)
I (666) esp_idf_svc::wifi: Waiting for status done - success
I (676) esp_idf_svc::wifi: Stopped
I (676) esp_idf_svc::wifi: Wifi mode AP set
I (686) esp_idf_svc::wifi: Setting AP configuration: AccessPointConfiguration { ssid: "iot-device", ssid_hidden: false, channel: 1, secondary_channel: None, protocols: EnumSet(P802D11B | P802D11BG | P802D11BGN), auth_method: None, password: "", max_connections: 16, ip_conf: Some(RouterConfiguration { subnet: Subnet { gateway: 192.168.71.1, mask: Mask(24) }, dhcp_enabled: true, dns: Some(8.8.8.8), secondary_dns: Some(8.8.4.4) }) }
I (726) esp_idf_svc::wifi: Setting AP IP configuration: RouterConfiguration { subnet: Subnet { gateway: 192.168.71.1, mask: Mask(24) }, dhcp_enabled: true, dns: Some(8.8.8.8), secondary_dns: Some(8.8.4.4) }
I (736) esp_idf_svc::wifi: AP netif allocated: 0x3fca4e88
I (746) esp_idf_svc::wifi: AP IP configuration done
I (756) esp_idf_svc::wifi: AP configuration done
I (756) esp_idf_svc::wifi: Starting with status: Status(Stopped, Starting)
I (766) esp_idf_svc::wifi: Status is of operating type, starting
I (776) phy_init: phy_version 500,985899c,Apr 19 2021,16:05:08
I (886) wifi:set rx active PTI: 0, rx ack PTI: 0, and default PTI: 0
I (886) wifi:mode : softAP (7c:df:a1:a4:44:c1)
I (886) wifi:Total power save buffer number: 16
I (896) wifi:Init max length of beacon: 752/752
I (896) wifi:Init max length of beacon: 752/752
I (906) esp_idf_svc::wifi: Got wifi event: 12 
I (906) esp_idf_svc::wifi: Set status: Status(Stopped, Started(Waiting))
I (916) esp_idf_svc::wifi: Wifi event 12 handled
I (916) esp_idf_svc::wifi: Start requested
I (926) esp_idf_svc::wifi: About to wait for status with timeout 10s
I (926) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (5936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (10936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (15936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (20936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (25936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (30936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (35936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (40936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (45936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (50936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (55936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (60936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (65936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (70936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (75936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (80936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (85936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (90936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (95936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (100936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (105936) esp_idf_svc::wifi: Providing status: Status(Stopped, Started(Waiting))
I (105936) esp_idf_svc::wifi: Timeout while waiting for status
I (105936) esp_idf_svc::wifi: Timeout while waiting for the requested state

abort() was called at PC 0x420893e1 on core 0
Core  0 register dump:
MEPC    : 0x40385838  RA      : 0x40385f8a  SP      : 0x3fc98530  GP      : 0x3fc8e800  
TP      : 0x3fc79720  T0      : 0x37363534  T1      : 0x7271706f  T2      : 0x33323130  
S0/FP   : 0x00000004  S1      : 0x3fc98594  A0      : 0x3fc9855c  A1      : 0x3fc98592  
A2      : 0x00000000  A3      : 0x3fc98589  A4      : 0x00000001  A5      : 0x3fc96000  
A6      : 0x7a797877  A7      : 0x76757473  S2      : 0x3fc98c20  S3      : 0x42089de8  
S4      : 0x00000000  S5      : 0x00000000  S6      : 0x00000000  S7      : 0x00000000  
S8      : 0x00000000  S9      : 0x00000000  S10     : 0x00000000  S11     : 0x00000000  
T3      : 0x6e6d6c6b  T4      : 0x6a696867  T5      : 0x66656463  T6      : 0x62613938  
MSTATUS : 0x40385838  MTVEC   : 0x40380001  MCAUSE  : 0x00000007  MTVAL   : 0x00000000  
MHARTID : 0x00000000  

Stack memory:
3fc98530: 0x42045064 0x42045fa2 0x3fc98590 0x4038ca46 0x3fc79720 0x00000000 0x3fc9d574 0x3fc90b24
3fc98550: 0x3fc98594 0x3fc90b40 0x3fc98590 0x726f6261 0x20292874 0x20736177 0x6c6c6163 0x61206465
3fc98570: 0x43502074 0x34783020 0x39383032 0x20316533 0x63206e6f 0x2065726f 0x00000030 0x00000000
3fc98590: 0x00000030 0x38303234 0x31653339 0x42089d00 0x3fc98c20 0x420107c4 0x3fc98824 0x420893e4
3fc985b0: 0x3fc96c78 0x3fc98780 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc985d0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc985f0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98610: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98630: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98650: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98670: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98690: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc986b0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc986d0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc986f0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98710: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98730: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98750: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98770: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98790: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc987b0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc987d0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc987f0: 0x00000000 0x00000000 0x00000000 0x00000000 0xffffffff 0x3fca5f84 0x3fc960e0 0x3fc98c20
3fc98810: 0x420108a8 0x00000005 0x3fc8e050 0x42089de8 0x3fc967c0 0x00000000 0x00000000 0x00000000
3fc98830: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98850: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98870: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98890: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc988b0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc988d0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc988f0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc98910: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000



ELF file SHA256: 0000000000000000

Rebooting...

Let me know if you need more information, or if I can help in any way.

panic_abort when connecting to wifi with logger enabled

Hi!

I found that when connecting to a wifi and having logging enabled things go wrong.

assert failed: spinlock_acquire spinlock.h:122 (result == core_id || result == SPINLOCK_FREE)
Backtrace:0x40081bb6 [panic_abort:/home/decahe/iot/.embuild/espressif/esp-idf/release-v4.4/components/esp_system/panic.c:402]:0x3ffbd4b00x40087d49 [esp_system_abort:/home/decahe/iot/.embuild/espressif/esp-idf/release-v4.4/components/esp_system/esp_system.c:128]:0x3ffbd4d0 0x4008e165 [__assert_func:/home/decahe/iot/.embuild/espressif/esp-idf/release-v4.4/components/newlib/assert.c:85]:0x3ffbd4f0 0x4008aaa3 [spinlock_acquire:/home/decahe/iot/.embuild/espressif/esp-idf/release-v4.4/components/esp_hw_support/include/soc/spinlock.h:122]:0x3ffbd610 0x400887a1 [vPortEnterCritical:/home/decahe/iot/.embuild/espressif/esp-idf/release-v4.4/components/freertos/port/xtensa/include/freertos/portmacro.h:578]:0x3ffbd630 0x4008891d [xQueueGiveMutexRecursive:/home/decahe/iot/.embuild/espressif/esp-idf/release-v4.4/components/freertos/queue.c:685]:0x3ffbd670 0x4016c32d [esp_event_loop_run:/home/decahe/iot/.embuild/espressif/esp-idf/release-v4.4/components/esp_event/esp_event.c:628]:0x3ffbd690 0x4016c340 [esp_event_loop_run_task:/home/decahe/iot/.embuild/espressif/esp-idf/release-v4.4/components/esp_event/esp_event.c:115]:0x3ffbd6e0 

Output with logging
Output without logging

Am I missing something or is this a bug?

use embedded_svc::httpd::{Request, Response};
use embedded_svc::ipv4;
use embedded_svc::storage::Storage;
use embedded_svc::wifi::{
    AuthMethod, Wifi,
};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use embedded_hal::can::nb::Can;
use embedded_hal::delay::blocking::DelayUs;
use embedded_hal::nb;
use embedded_svc::wifi;
use esp_idf_hal::can::{self, CAN};
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::gpio::{InputPin, OutputPin};
use esp_idf_svc::{netif, nvs, nvs_storage, sysloop, wifi as esp_wifi};
use esp_idf_sys::{self as _, EspError}; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use unwrap_infallible::UnwrapInfallible;

static HOSTNAME: &str = "thing-123";

fn main() -> Result<(), EspError> {
    esp_idf_sys::link_patches();

    esp_idf_svc::log::EspLogger::initialize_default(); // Everything is fine when removing this line

    let wifi_interface =
        Arc::new(netif::EspNetifStack::new().unwrap());
    let system_loop =
        Arc::new(sysloop::EspSysLoopStack::new().unwrap());
    let storage = Arc::new(
        nvs::EspDefaultNvs::new().unwrap(),
    );
    let mut wifi = esp_wifi::EspWifi::new(wifi_interface, system_loop, Arc::clone(&storage))
        .unwrap();

    wifi.set_configuration(&wifi::Configuration::Client(wifi::ClientConfiguration{
        ssid: String::from("some SSID"),
        password: String::from("the password"),
        auth_method: AuthMethod::WPA2Personal,
        ip_conf: Some(ipv4::ClientConfiguration::DHCP(ipv4::DHCPClientSettings{ hostname: Some(String::from(HOSTNAME))})),
        ..Default::default()
    })).unwrap();

    loop {
        println!("{:?}", wifi.get_status());
        FreeRtos.delay_ms(1000).unwrap_infallible();
    }
}
$ git log

commit aaad3f5ce8749fd1996cdb2842a4de47a0a8e053 (HEAD -> master, upstream/master)
Merge: 1e66deff 7500afac
Author: Scott Mabin <[email protected]>
Date:   Wed May 4 14:21:00 2022 +0200

    Merge pull request #72 from bakery/http-client-buffer-size-tx

    Add support for buffer_size_tx config option in HTTP Client

could not find `nvs` in the crate root

HI

in esp-idf-svc, comma need to be add.
#[cfg(esp32s3)]
pin!(Gpio17:17, IO, RTC:17, ADC2:6, NODAC:0 NOTOUCH:0);

if I use this repo esp-idf-template with cmake.

my configuration of cargo.toml is:
...
[lib]
crate-type = ["staticlib"]

[profile.release]
opt-level = "s"

[profile.dev]
debug = true # Symbols are nice and they don't increase the size on Flash
opt-level = "z"

[dependencies]
log = "0.4"
esp-idf-sys = { version = "0.28.1", features = ["native"] }
esp-idf-svc = { version = "0.34.1" }
esp-idf-hal = "0.29.3"
embedded-svc = "0.15.4"

[build-dependencies]
embuild = "0.26"
anyhow = "1"

I got this error, if I add some wifi codes into rust lib, those codes are the same in example-std.

...
let netif_stack = Arc::new(EspNetifStack::new()?);
let sys_loop_stack = Arc::new(EspSysLoopStack::new()?);
let default_nvs = Arc::new(EspDefaultNvs::new()?);
let mut wifi = wifi(
netif_stack.clone(),
sys_loop_stack.clone(),
default_nvs.clone(),
)?;
....
image

BLE support missing

I am trying to use the esp32 Wifi+Bluetooth module. Although the wifi functionality is working I did not find any way of getting the Bluetooth to work using Rust.

It would be great to have this option as well since many IoT projects require Bluetooth support.

using wifi with async/await (AsyncEventBus)

I try to use the wifi wait_status_with_timeout() function in an async task. As I understand, the experimental feature as_async() can be used to archive this.

So, to get an event change asynchronously, I use it like so:

wifi.set_configuration(...);

{
    let mut wifi = wifi.as_async();
    let mut sub = wifi.subscribe().unwrap();
    sub.recv().await?;
}

let status = wifi.get_status();

But, after running this, it waits forever at sub.recv().await?;.

Do I have to use it differently, or do I have to configure something to use it? Are there any plans to provide wait_status_with_timeout() as an async version?

esp_netif_obj isn't thread safe

I was trying to access the wifi object within a thread but it is throwing this error:

202 |     thread::Builder::new().stack_size(32768).spawn(move || {
    |                                              ^^^^^ `*mut esp_netif_obj` cannot be sent between threads safely
    |
    = help: within `EspWifi`, the trait `Send` is not implemented for `*mut esp_netif_obj`
    = note: required because it appears within the type `EspNetif`
    = note: required because it appears within the type `std::option::Option<EspNetif>`
    = note: required because it appears within the type `EspWifi`
    = note: required because of the requirements on the impl of `Sync` for `std::sync::Mutex<EspWifi>`
    = note: required because of the requirements on the impl of `Send` for `Arc<std::sync::Mutex<EspWifi>>`
    = note: required because it appears within the type `[closure@src/main.rs:202:52: 204:6]`
note: required by a bound in `Builder::spawn`
   --> /Users/username/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/thread/mod.rs:379:12
    |
379 |         F: Send + 'static,
    |            ^^^^ required by this bound in `Builder::spawn`

This happens after I wrapped wifi object inside a mutex and arc.

    let wifi = EspWifi::new(netif_stack, sys_loop_stack, default_nvs).expect("Need wifi");
    let wifi_arc = Arc::new(Mutex::new(wifi));

    thread::Builder::new().stack_size(32768).spawn(move || {
        let status = wifi_arc.clone().lock().unwrap().get_status();
    });

Commented Storage for EspNvsStorage implementation. No get/put functions on EspNvsStorage.

Hi,
I'm new to esp-rs and I'm trying to play a little.

I saw, thanks to github examples, that the version esp-idf-svc = "0.36.1", has convenient api for the storage.

let nvs = Arc::new(EspDefaultNvs::new()?);
let mut storage = EspNvsStorage::new_default(nvs.clone(), "config", true)?;

if !storage.contains("configured")? {
    storage.put(WIFI_SSID_KEY, &env!("WIFI_SSID"))?;
    storage.put(WIFI_PASS_KEY, &env!("WIFI_PASS"))?;
    storage.put("configured", &"true")?;
    info!("stored creds");
}

let ssid: String = storage.get(WIFI_SSID_KEY)?.unwrap();
let password: String = storage.get(WIFI_PASS_KEY)?.unwrap();

But the latest version esp-idf-svc = "0.42.1", the one that I'm using now, the implementation of the Storage for EspNvsStorage has been commented with a TODO.

// TODO
// impl Storage for EspNvsStorage {
//     fn get<'a, T>(&'a self, name: &str) -> Result<Option<T>, Self::Error>
//     where
//         T: serde::Deserialize<'a> {
//         todo!()
//     }

//     fn set<T>(&mut self, name: &str, value: &T) -> Result<bool, Self::Error>
//     where
//         T: serde::Serialize {
//         todo!()
//     }
// }

Is this because there is a different way to use those functions? In this case, an example will be super useful.

SNTP fails with default 0.pool.ntp.org servers

This seems to be because 0.pool.ntp.org returns 4 A records. It seems DNS resolution fails if more than one record is returned. Setting the time succeeds after changing the NTP server to ntp.rit.edu, which only returns one A record.

EspHttpClient doesn't support `keep-alive`

Description

The current implementation of EspHttpClient doesn't support the keep-alive functionnality of HTTP connections.

According to the documentation, we can specify the following attributes to esp_http_client_config_t:

Also, the current implementation doesn't call esp_http_client_close after the keep-alive timeout or max as been reached.

Expected behavior

We should be able to pass the keep-alive attributes to EspHttpClientConfiguration either by specifiying each attributes, or by passing a struct, that contains the properties, whichever is the most idiomatic.

esp_http_client_close should also be called, after the connection has been idle for the number of seconds specified in timeout, or after reaching the maximum number of requests that can be sent on this connection.

External documentation

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive

How should MQTT resubscriptions be made for reconnections?

When the MQTT client has to reconnect and resubscribe on a disconnection, how should this be achieved? The client instance is required to subscribe again, but this is not available (as far as I'm aware of) inside the callback provided to the EspMqttClient.new function. Is there a way to achieve this?

EspTimer panics as soon as it elapses (tries to call the callback)

I would like to use a countdown timer. Callback in current implementation is mandatory, although my use case does not need it. I need it to implement timeout of a blocking operation (nb::Error::WouldBlock and timer.is_scheduled()).

In any case, I cannot get it to work - the timer panics as soon as it times out and tries to call the callback.

Started.                                                                                                                                                                [59/1275]
Guru Meditation Error: Core  0 panic'ed (Illegal instruction). Exception was unhandled.                                                                                          
Core  0 register dump:                                                                                                                                                           
MEPC    : 0x4200037a  RA      : 0x420061f8  SP      : 0x3fc8fbc0  GP      : 0x3fc8ba00           
TP      : 0x3fc861d0  T0      : 0x00000000  T1      : 0x00000000  T2      : 0x00000000           
S0/FP   : 0x3fc91a34  S1      : 0x4200036c  A0      : 0x00000000  A1      : 0x00000000           
A2      : 0x0023d166  A3      : 0x60023044  A4      : 0x3fc8e000  A5      : 0x600c2000           
A6      : 0x00000000  A7      : 0x00000000  S2      : 0x00000000  S3      : 0x00000000           
S4      : 0x0023d16f  S5      : 0x00000000  S6      : 0x00000000  S7      : 0x00000000           
S8      : 0x00000000  S9      : 0x00000000  S10     : 0x00000000  S11     : 0x00000000           
T3      : 0x00000000  T4      : 0x00000000  T5      : 0x00000000  T6      : 0x00000000           
MSTATUS : 0x00001881  MTVEC   : 0x40380001  MCAUSE  : 0x00000002  MTVAL   : 0x00000000           
MHARTID : 0x00000000   
Stack memory:                                                                                                                                                                    
3fc8fbc0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x420062b8
3fc8fbe0: 0x00000000 0x00000000 0x00000000 0x40386a20 0x00000000 0x00000000 0x00000000 0x00000000
3fc8fc00: 0x00000000 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0x27146414 0x01010107 0x00000001 0x00000000
3fc8fc20: 0xffffffff 0x7fefffff 0x00000000 0x3fc00000 0x00000000 0x40300000 0x00000000 0x3fe00000
3fc8fc40: 0x00000000 0x3ff80000 0x636f4361 0x3fd287a7 0x8b60c8b3 0x3fc68a28 0x509f79fb 0x3fd34413
3fc8fc60: 0x00000000 0x3ff00000 0x00000000 0x40240000 0x00000000 0x401c0000 0x00000000 0x40140000
3fc8fc80: 0x00000000 0x43500000 0x3fc8b200 0x00001c74 0xa5a5a5a5 0x00000154 0x3fc8fb40 0x3fc8dea4
3fc8fca0: 0x3fc8d670 0x3fc8d670 0x3fc8fc98 0x3fc8d668 0x00000003 0x130f9a0c 0x43369cfe 0x3fc8fc98
3fc8fcc0: 0x00000000 0x00000016 0x3fc8ec94 0x5f707365 0x656d6974 0xd4210072 0x00f4ebf0 0x00000000
3fc8fce0: 0x3fc8fc90 0x00000016 0x00000000 0x00000000 0x00000000 0x00000000 0x3fc8e6bc 0x3fc8e724
3fc8fd00: 0x3fc8e78c 0x00000000 0x00000000 0x00000001 0x00000000 0x00000000 0x00000000 0x42009f5c
3fc8fd20: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc8fd40: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc8fd60: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc8fd80: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc8fda0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc8fdc0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc8fde0: 0x00000000 0x00000000 0x3fc80000 0x0000000c 0x3fc8fe00 0x00000000 0x3fc8fde8 0x0000000c
3fc8fe00: 0x09c4000a 0x00000000 0x3fc8fe20 0x0000000c 0x3fc930c0 0x00000000 0x3fc8fe08 0x0000000c
3fc8fe20: 0x0c86000a 0x00000000 0x3fc9309c 0x00001d58 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8fe40: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8fe60: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8fe80: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8fea0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8fec0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8fee0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8ff00: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8ff20: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8ff40: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8ff60: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8ff80: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
3fc8ffa0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
ELF file SHA256: 0000000000000000
Rebooting...
ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0xc (RTC_SW_CPU_RST),boot:0xe (SPI_FAST_FLASH_BOOT)
Saved PC:0x40382250
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6100,len:0x172c
load:0x403ce000,len:0x928
load:0x403d0000,len:0x2ce0
entry 0x403ce000

The code:

use embedded_hal_0_2::prelude::*;
use embedded_svc::timer::{Timer, TimerConfiguration, TimerService};
use esp_idf_hal::delay;
use esp_idf_svc::timer::EspTimerService;
use esp_idf_sys::EspError;
use std::time::Duration;

fn timer_elapsed() -> Result<(), EspError> {
    Ok(())
}

fn run_timer() -> Result<(), EspError> {
    let timer_service = EspTimerService::new()?;
    let timer_config = TimerConfiguration {
        name: None,
        skip_unhandled_events: true,
    };
    let mut timer = timer_service.timer(&timer_config, &timer_elapsed)?;
    timer.once(Duration::from_millis(2000))?;

    let mut delay = delay::FreeRtos;
    delay.delay_ms(3000_u32);

    Ok(())
}

fn main() {
    esp_idf_sys::link_patches();
    println!("Started.");
    println!("FINISHED: {:?}", run_timer());
}

What am I doing wrong?

The library calls esp_timer_create with locally (on stack) allocated reference arg: &unsafe_callback as *const _ as *mut _,, which gets garbage collected.
https://github.com/esp-rs/esp-idf-svc/blob/master/src/timer.rs#L104-L111

The state of EspNvsStorage

Could you please help me understand what the state of affairs is with the NVS storage part, @ivmarkov ? Looking to contribute.

  1. Why does the RawStorage impl utilise both u64 and blob? Is it just more space-efficient to store with u64 if the blob is 8 bytes or less?
  2. For the future Storage impl, are we to allow the user to choose a serialization format, or should we just impl with something efficient and embedded-friendly like postcard?
  3. Should the Storage trait have its own associated error type, separate from that of StorageBase, in order to encompass (de)serialization errors?

mqtt client panics

Trying to get the experimental MQTT client to work, but having no luck.

The following code leads to the panic below, however no actually useful error message describing the panic is printed. Decoding the backtrace leads into the mqtt client internals.

fn main() -> Result<()> {
    // Temporary. Will disappear once ESP-IDF 4.4 is released, but for now it is necessary to call this function once,
    // or else some patches to the runtime implemented by esp-idf-sys might not link properly.
    esp_idf_sys::link_patches();

    // setup logging
    esp_idf_svc::log::EspLogger::initialize_default();

    let netif_stack = Arc::new(EspNetifStack::new()?);
    let sys_loop_stack = Arc::new(EspSysLoopStack::new()?);
    let default_nvs = Arc::new(EspDefaultNvs::new()?);
    let wifi = wifi(netif_stack, sys_loop_stack, default_nvs);

    let mqtt_cfg = MqttConfig {
        client_id: Some("foobar"),

        ..Default::default()
    };

    EspMqttClient::new("mqtt://broker:1883", &mqtt_cfg);
    return Ok(());
}

Running leads to the following panic:

Guru Meditation Error: Core  1 panic'ed (Unhandled debug exception). 
Debug exception reason: BREAK instr 
Core  1 register dump:
PC      : 0x401760c3  PS      : 0x00060436  A0      : 0x800dbf91  A1      : 0x3ffcc590  
A2      : 0x3f40325c  A3      : 0x0000002b  A4      : 0x3ffcc5b0  A5      : 0x3f40324c  
A6      : 0x3f40332c  A7      : 0x00060b23  A8      : 0x8008c7c8  A9      : 0x3ffcc570  
A10     : 0x00000003  A11     : 0x00060423  A12     : 0x00060420  A13     : 0x3ffc8014  
A14     : 0x3ffc9afc  A15     : 0x00000000  SAR     : 0x00000018  EXCCAUSE: 0x00000001  
EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  
Backtrace:0x401760c0:0x3ffcc590 0x400dbf8e:0x3ffcc5b0 0x400dc028:0x3ffcc5e0 0x400d5fe0:0x3ffcc610 0x400dbfa2:0x3ffcc630 0x4017a87a:0x3ffcc650 0x4017a2e9:0x3ffcc680 0x400ef733:0x3ffcc6c0 0x400ef751:0x3ffcc6e0 0x400f021d:0x3ffcc700 0x4008c539:0x3ffcc730
ELF file SHA256: 0000000000000000
Rebooting...

Decoding using addr2line gives:

~/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/panicking.rs:87
~/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/result.rs:1298
~/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-svc-0.36.3/src/mqtt/client.rs:371
~/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-svc-0.36.3/src/mqtt/client.rs:101
~/.rustup/toolchains/esp/lib/rustlib/src/rust/library/alloc/src/boxed.rs:1705
~/work/diox-rs/.embuild/platformio/packages/framework-espidf/components/esp_event/esp_event.c:145
~/work/diox-rs/.embuild/platformio/packages/framework-espidf/components/esp_event/esp_event.c:582 (discriminator 3)
~/work/diox-rs/.embuild/platformio/packages/framework-espidf/components/mqtt/esp-mqtt/mqtt_client.c:926
~/work/diox-rs/.embuild/platformio/packages/framework-espidf/components/mqtt/esp-mqtt/mqtt_client.c:913
~/work/diox-rs/.embuild/platformio/packages/framework-espidf/components/mqtt/esp-mqtt/mqtt_client.c:1371
~/work/diox-rs/.embuild/platformio/packages/framework-espidf/components/freertos/port/xtensa/port.c:168

Feature request - Set client wifi config without restarting

Hi!

First of, Thank you all for the awesome set of esp related crates :)


I am trying to setup a device for the following scenario.

  1. Device is not configured, start in AP-mode (likely Mixed to allow scanning)
  2. The user connects to the AP using a phone or similar and in a web interface hosted by the device configure what Wifi the device should be connected to (need ability to scan)
  3. The device tries to connect to the selected network (while maintaining connection to the phone through the AP)
  4. If step 3 succeeded, turn of AP. Otherwise maintain connection with phone and allow for another try

First off, is this a scenario that should be supported by esp-idf-svc/embedded-svc?

Looking at the code I have stumbled upon some questions:

  • Wifi::scan() restarts the wifi? Does it have to do that? or could something like fn scan_with_optional_restart(restart: bool) be exposed?
  • Wifi::set_configuration(wifi::Configuration::Mixed()) can not start without a client config (can not scan in Ap-mode)
    Calling EspWifi::set_configuration(wifi::Configuration::Mixed(Default::default(), ap_config)) fails with ESP-IDF ERROR: ESP_ERR_WIFI_SSID

I tried these changes and they seem to make make it possible to use EspWifi::set_configuration(wifi::Configuration::Mixed(Default::default(), ap_config)) to enter Mixed (and probably Client) without specifying client settings:

    fn set_client_conf(&mut self, conf: &ClientConfiguration) -> Result<(), EspError> {
         info!("Setting STA configuration: {:?}", conf);

-        let mut wifi_config = wifi_config_t {
-            sta: Newtype::<wifi_sta_config_t>::from(conf).0,
+        let mut wifi_config = if conf.ssid.is_empty() {
+            // Empty config
+            unsafe { core::mem::zeroed() }
+        } else {
+            wifi_config_t {
+                sta: Newtype::<wifi_sta_config_t>::from(conf).0,
+            }
         };

         esp!(unsafe { esp_wifi_set_config(wifi_interface_t_WIFI_IF_STA, &mut wifi_config) })?;

-        self.set_client_ip_conf(&conf.ip_conf)?;
+        if !conf.ssid.is_empty() {
+            self.set_client_ip_conf(&conf.ip_conf)?;
+        }

         info!("STA configuration done");

Also, would there be any way to expose some way to change client settings without affecting the Ap connection? Perhaps something like(pseudo code)

pub fn foo(&mut self, conf: &ClientConfiguration) -> Result<(), ErrorNotInMixedOrClientMode | EspError> {
    if not in Mixed or Client mode {
        return Err(ErrorNotInMixedOrClientMode);
    }
    wifi.set_client_conf(conf);
    if conf.ssid.is_empty() {
        status.client_status = Stopped;
    } else {
        status.client_status = Started;
    }
}

Please let me know if you would like me to split this into multiple issues and if you would be interested in a PR

Wi-Fi provisioning support

Hi, is there any way to do Wi-Fi provisioning from Rust (ideally via BLE)? If not, is it possible to do it from C while still using Rust code?

Can't import chrono

Hello there, when I try to add chrono to my project I get the following error message:

Compiling time v0.1.43
error[E0609]: no field `tm_gmtoff` on type `tm`
   --> /home/some_pc/.cargo/registry/src/[github.com](http://github.com/)-1ecc6299db9ec823/time-0.1.43/src/[sys.rs:314](http://sys.rs:314/)
:30
    |
314 |             let gmtoff = [out.tm](http://out.tm/)_gmtoff;
    |                              ^^^^^^^^^ unknown field
    |
    = note: available fields are: `tm_sec`, `tm_min`, `tm_hour`, `tm_mday`, `tm_mon` ... and 4 others

For more information about this error, try `rustc --explain E0609`.
error: could not compile `time` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed

any idea on how to solve that?
Thanks in advance,
David

Panic while scanning WiFi APs

Hi all, I'm fairly new to Rust on ESP, so apologies if I'm doing something wrong or this has been covered already. I'm starting a small project and I'm trying to connect to my WiFi network, however during the scan a panic occurs:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ()', /Users/josh/.cargo/registry/src/github.com-1ecc6299db9ec823/heapless-0.7.15/src/string.rs:295:25

My Machine: MacOS 12.5 (M1 MBP)
Toolchain version: esp-1.62.1.0
Target: xtensa-esp32-espidf (ESP32-CAM board)

My project was generated using the cargo template and selected idf version 4.4. Here's my main.rs

use anyhow::bail;
use embedded_svc::ipv4;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use embedded_svc::ping::Ping;
use embedded_svc::wifi::{
    ApStatus, ClientConfiguration, ClientConnectionStatus, ClientIpStatus, ClientStatus,
    Configuration, Status, Wifi,
};
use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported

use esp_idf_svc::netif::EspNetifStack;
use esp_idf_svc::nvs::EspDefaultNvs;
use esp_idf_svc::sysloop::EspSysLoopStack;
use esp_idf_svc::wifi::EspWifi;

use esp_idf_svc::ping;

use log::*;

#[allow(dead_code)]
#[cfg(not(feature = "qemu"))]
const SSID: &str = env!("RUST_ESP32_WIFI_SSID");
#[allow(dead_code)]
#[cfg(not(feature = "qemu"))]
const PASS: &str = env!("RUST_ESP32_WIFI_PASS");

fn main() -> anyhow::Result<()> {
    // Temporary. Will disappear once ESP-IDF 4.4 is released, but for now it is necessary to call this function once,
    // or else some patches to the runtime implemented by esp-idf-sys might not link properly.
    esp_idf_sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    // enable anyhow stack traces
    std::env::set_var("RUST_BACKTRACE", "1");

    info!("Creating netif stack");
    let netif_stack = Arc::new(EspNetifStack::new()?);
    info!("Creating sys loop stack");
    let sys_loop_stack = Arc::new(EspSysLoopStack::new()?);
    info!("Creating nvs");
    let default_nvs = Arc::new(EspDefaultNvs::new()?);
    info!("Initializing WiFi");
    let _wifi = wifi(netif_stack, sys_loop_stack, default_nvs)?;
    loop {
        info!("useless loop!");
        thread::sleep(Duration::from_secs(10));
    }
}

fn ping(ip_settings: &ipv4::ClientSettings) -> anyhow::Result<()> {
    info!("About to do some pings for {:?}", ip_settings);

    let ping_summary =
        ping::EspPing::default().ping(ip_settings.subnet.gateway, &Default::default())?;
    if ping_summary.transmitted != ping_summary.received {
        bail!(
            "Pinging gateway {} resulted in timeouts",
            ip_settings.subnet.gateway
        );
    }

    info!("Pinging done");

    Ok(())
}

#[cfg(not(feature = "qemu"))]
// #[allow(dead_code)]
fn wifi(
    netif_stack: Arc<EspNetifStack>,
    sys_loop_stack: Arc<EspSysLoopStack>,
    default_nvs: Arc<EspDefaultNvs>,
) -> anyhow::Result<Box<EspWifi>> {
    let mut wifi = Box::new(EspWifi::new(netif_stack, sys_loop_stack, default_nvs)?);

    info!("Wifi created, about to scan");

    let ap_infos = wifi.scan()?;

    let ours = ap_infos.into_iter().find(|a| a.ssid == SSID);

    let channel = if let Some(ours) = ours {
        info!(
            "Found configured access point {} on channel {}",
            SSID, ours.channel
        );
        Some(ours.channel)
    } else {
        info!(
            "Configured access point {} not found during scanning, will go with unknown channel",
            SSID
        );
        None
    };

    wifi.set_configuration(&Configuration::Client(ClientConfiguration {
        ssid: SSID.into(),
        password: PASS.into(),
        channel,
        ..Default::default()
    }))?;

    info!("Wifi configuration set, about to get status");

    wifi.wait_status_with_timeout(Duration::from_secs(20), |status| !status.is_transitional())
        .map_err(|e| anyhow::anyhow!("Unexpected Wifi status: {:?}", e))?;

    let status = wifi.get_status();

    if let Status(
        ClientStatus::Started(ClientConnectionStatus::Connected(ClientIpStatus::Done(ip_settings))),
        ApStatus::Stopped,
    ) = status
    {
        info!("Wifi connected");
        ping(&ip_settings)?;
    } else {
        bail!("Unexpected Wifi status: {:?}", status);
    }

    Ok(wifi)
}

And log output:

...

I (3351) esp_idf_svc::wifi: Found 18 access points
I (3351) esp_idf_svc::wifi: About to get info for found access points
I (3351) esp_idf_svc::wifi: Got info for 18 access points
I (3351) esp_idf_svc::wifi: Found access point AccessPointInfo { ssid: "joshnet", bssid: [176, 106, 65, 202, 45, 158], channel: 1, secondary_channel: None, signal_strength: 202, protocols: EnumSet(), auth_method: WPA2Personal }
I (3371) esp_idf_svc::wifi: Found access point AccessPointInfo { ssid: "SpectrumSetup-5B", bssid: [136, 222, 124, 105, 26, 89], channel: 6, secondary_channel: None, signal_strength: 202, protocols: EnumSet(), auth_method: WPA2Personal }
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ()', /Users/josh/.cargo/registry/src/github.com-1ecc6299db9ec823/heapless-0.7.15/src/string.rs:295:25
stack backtrace:
abort() was called at PC 0x4012b9b2 [abort_return<int>:/Users/josh/Git/esp32-mqtt-node/.embuild/espressif/esp-idf/release-v4.4/components/cxx/cxx_exception_stubs.cpp:33] on core 0
Backtrace:0x40081b9e [panic_abort:/Users/josh/Git/esp32-mqtt-node/.embuild/espressif/esp-idf/release-v4.4/components/esp_system/panic.c:402]:0x3ffbd7600x40087e59 [esp_system_abort:/Users/josh/Git/esp32-mqtt-node/.embuild/espressif/esp-idf/release-v4.4/components/esp_system/esp_system.c:128]:0x3ffbd780 0x4008e3fe [abort:/Users/josh/Git/esp32-mqtt-node/.embuild/espressif/esp-idf/release-v4.4/components/newlib/abort.c:46]:0x3ffbd7a0 0x4012b9b2 [abort_return<int>:/Users/josh/Git/esp32-mqtt-node/.embuild/espressif/esp-idf/release-v4.4/components/cxx/cxx_exception_stubs.cpp:33]:0x3ffbd810 0x400fbae7 [std::backtrace_rs::backtrace::libunwind::trace:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93]:0x3ffbd830 0x400f8004 [std::sys_common::backtrace::_print_fmt:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:66]:0x3ffbd860 0x401097ce [core::fmt::write:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:1196]:0x3ffbd8d0 0x400e6fa8 [std::io::Write::write_fmt:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/io/mod.rs:1654]:0x3ffbd920 0x400f7f2b [std::sys_common::backtrace::_print:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:48]:0x3ffbd970 0x400efadb [std::panicking::default_hook::{{closure}}:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/panicking.rs:??]:0x3ffbd9c0 0x400ef978 [std::panicking::default_hook:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/panicking.rs:314]:0x3ffbda20 0x400efc83 [std::panicking::rust_panic_with_hook:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/panicking.rs:698]:0x3ffbda90 0x400f81cf [std::panicking::begin_panic_handler::{{closure}}:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/panicking.rs:??]:0x3ffbdb00 0x400f8095 [std::sys_common::backtrace::__rust_end_short_backtrace:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:138]:0x3ffbdb30 0x400efb68 [rust_begin_unwind:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/panicking.rs:584]:0x3ffbdb60 0x4010a4a8 [core::panicking::panic_fmt:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/panicking.rs:142]:0x3ffbdb90 0x4010c083 [core::result::unwrap_failed:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/result.rs:1785]:0x3ffbdbd0 0x400dc6fd [core::result::Result<T,E>::unwrap:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/result.rs:1078]:0x3ffbdc30 0x400dc7be [<heapless::string::String<_> as core::convert::From<&str>>::from:/Users/josh/.cargo/registry/src/github.com-1ecc6299db9ec823/heapless-0.7.15/src/string.rs:295]:0x3ffbdc60 0x400dc198 [<T as core::convert::Into<U>>::into:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/convert/mod.rs:550]:0x3ffbdc80 0x400d8489 [esp_idf_svc::wifi::<impl core::convert::From<esp_idf_svc::private::common::Newtype<&esp_idf_sys::bindings::wifi_ap_record_t>> for embedded_svc::wifi::AccessPointInfo>::from:/Users/josh/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-svc-0.42.1/src/wifi.rs:170]:0x3ffbdca0 0x400d79ed [<T as core::convert::Into<U>>::into:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/convert/mod.rs:550]:0x3ffbdcf0 0x400d5c58 [esp32_mqtt_node::wifi:/Users/josh/Git/esp32-mqtt-node/src/main.rs:83]:0x3ffbddc0 0x4017220b [core::ops::function::FnOnce::call_once:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/ops/function.rs:248]:0x3ffbe100 0x400d56b4 [std::rt::lang_start::{{closure}}:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/rt.rs:145]:0x3ffbe120 0x400e6c65 [core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/ops/function.rs:280]:0x3ffbe140 0x400d56a2 [std::rt::lang_start:/Users/josh/.rustup/toolchains/esp/lib/rustlib/src/rust/library/std/src/rt.rs:144]:0x3ffbe160 0x400d62b5 [main:??:??]:0x3ffbe190 0x400db877 [app_main:/Users/josh/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-sys-0.31.6/src/start.rs:46]:0x3ffbe1b0 0x40176887 [main_task:/Users/josh/Git/esp32-mqtt-node/.embuild/espressif/esp-idf/release-v4.4/components/freertos/port/port_common.c:141]:0x3ffbe1d0
ELF file SHA256: 0000000000000000
Rebooting...

...

EspWifi::wait_status_with_timeout() seems not resetting after deep sleep.

Hi, I'm working with a code for ESP32-C3 (RISC-V core) that uses a wifi client connection to send some data to a HTTP server and then goes to deep sleep for 10 seconds. I'm using wait_status_with_timeout() to wait for the connection to be operating or timeout after 40 seconds, and drop() to stop the wifi and shut down the connection gracefully before the call to esp_deep_sleep().

Powering or resetting the device, it actually works for 3 deep sleep cycles after which wait_status_with_timeout() immediately returns claiming a timeout that is not occurred (few ms are elapsed after the call to the function instead of 40 seconds).

It seems to me that wait_status_with_timeout() timer is initialized at the first call after the device reset but that is not stopped during the sleep and cleared after the wake up, still keeping to run (the timeout occurs exactly after more than 40 second after the device powering or reset).
There's some errors in my code or it is a bug?

This is an excerpt of the code that runs on ESP32-C3:

//#[allow(unused_imports)]
use std::time::Duration;

use embedded_svc::http::{client::*, Status};
use embedded_svc::wifi;
use embedded_svc::wifi::{Wifi, ApStatus, ClientStatus, ClientConnectionStatus, ClientIpStatus};
use embedded_svc::wifi::{ClientConfiguration, Configuration};

use esp_idf_svc::wifi::EspWifi;
use esp_idf_svc::netif::*;
use esp_idf_svc::sysloop::*;
use esp_idf_svc::nvs::*;
use esp_idf_svc::http::client::*;

fn main() -> Result<(), anyhow::Error> {
    esp_idf_svc::log::EspLogger::initialize_default();

    let netif_stack = Arc::new(EspNetifStack::new()?);
    let sys_loop_stack = Arc::new(EspSysLoopStack::new()?);
    let default_nvs = Arc::new(EspDefaultNvs::new()?);

    let mut wifi = EspWifi::new(
        netif_stack,
        sys_loop_stack,
        default_nvs).unwrap();

    wifi.set_configuration(&Configuration::Client(
        ClientConfiguration {
            ssid: "wifinet".into(),
            password: "wifipass".to_string(),
            ..Default::default()
        }
    ))?;    
            
    wifi.wait_status_with_timeout(Duration::from_secs(40), |status| !status.is_transitional())
        .map_err(|e| error!("Unexpected Wifi status: {:?}", e));
    
    let status = wifi.get_status();
    
    if let wifi::Status(
        ClientStatus::Started(ClientConnectionStatus::Connected(ClientIpStatus::Done(_ip_settings))),
        ApStatus::Stopped
    ) = wifi.get_status() {
        println!("Wifi is connected.");
    } else {
        error!("Unexpected Wifi status: {:?}", status);
    } 
        
    let http_url = format!("http://192.168.1.100:8080/");
    let http_line = format!("Hello, World!");
    println!("sending data {} to {}", http_line, http_url);

    let mut client = EspHttpClient::new_default()?;

    let request = client.post(&http_url)?;

    match request.send_str(http_line) {
        Ok(response) =>
            match response.status() {
                100..200 => error!("Unexpected HTTP response code: {}", response.status()),
                200..400 => debug!("Message sent: {}", response.status()),
                400..600 => error!("HTTP error code {}", response.status()),
                _ => println!("HTTP Response: {}", response.status()),
            }
        Err(_e) => { error!("HTTP Error"); }
    }

    println!("Turning off Wifi.");
    drop(wifi);
    println!("Going to sleep.");
    unsafe {
        esp_idf_sys::esp_deep_sleep(1000_0000);
    }

    #[allow(unreachable_code)]
    Ok(())
}

Massimo.

P.S.: in the code above, I found that I must set the deep sleep for 1000_000 usec in order to get a 10 seconds sleep time. Why?

Allow usage in a CMake-based build

Hi (cross-linking from espressif/rust-esp32-example#34)

thanks so much for your work on embedded rust, and in particular on ESP chips :)

We're a company using ESP on our hardware, and we'd love to move our codebase to Rust. Because that move will be incremental, we'd like to compile our C/C++ codebase and switch some modules to Rust incrementally. For this, it seems more natural to use a "CMake-based" build that would compile our Rust modules as a library, and link our code to it. And of course, we'd love to use esp-idf-svc :)

For now, we saw https://github.com/ivmarkov/rust-esp32-std-hello which uses esp-idf-svc, but uses a "cargo-first" build which seems less natural for us.

Would it be possible to allow building esp-idf-svc using a CMake build so that it can be included in a CMake project like for instance https://github.com/espressif/rust-esp32-example ?

Bug: ScanDone Wifi events don't reach subscribers

When subscribing to wifi events on EspWifi, some events that don't change the state of the connection are not passed to subscribers.

The example for me is the ScanDone event. This happens because of this check: https://github.com/esp-rs/esp-idf-svc/blob/master/src/wifi.rs#L1065

What is the reason why this check exists (and similar on the IpEvent subscription)?
I think all events should reach the subscribers who then can filter them themselves (the IpEvent is okay to filter on the station).

set_hostname isnt working.

set_hostname doesn't seem to be working. The connected ESP32's hostname is still coming as espressif.

code snippet:

        let netif_stack = Arc::new(EspNetifStack::new()?);

        let netif_stack_clone = Arc::<esp_idf_svc::netif::EspNetifStack>::clone(&netif_stack);
        let interface_stack_config = InterfaceStack::Sta.get_default_configuration();
        let esp_netif = EspNetif::new(netif_stack_clone, &interface_stack_config)?; 
        esp_netif.set_hostname("my-device-host-name")?;

        let sys_loop_stack = Arc::new(EspSysLoopStack::new()?);
        let default_nvs = Arc::new(EspDefaultNvs::new()?);

        let esp_wifi = EspWifi::new(netif_stack, sys_loop_stack, default_nvs)?;

The output of esp_netif.set_hostname("my-device-host-name") is coming as OK()

[dependencies]
esp-idf-svc = "0.37.3"
esp-idf-hal = { version = "0.33.2" }
embedded-svc = "0.17.4"
esp-idf-sys = { version = "0.30.6", features = ["binstart"] }
embedded-hal = "0.2.7"
ESP_IDF_VERSION = { value = "branch:release/v4.4" }

Logger panics if output contains null bytes

The offending line:

let coutput = CString::new(output).unwrap();

I don't believe it should be up to the caller to ensure the log record doesn't contain null bytes - this occurs safely in Rust. I think we should post-process output to remove null bytes (they'd be invisible anyway) before conversion to CString.

Thoughts?

ESP32-C3-DevKitM-1: Boot loop when scanning for wifi APs

Hello, I am following along with the instructions to run https://github.com/ivmarkov/rust-esp32-std-hello on my ESP32-C3-DevKitM-1.

I was able to build and flash the demo application to my board.

Unfortunately, it appears to boot loop when scanning for access points. Here is the full output from a single loop iteration:

ESP-ROM:esp32c3-20200918
Build:Sep 18 2020
rst:0xc (RTC_SW_CPU_RST),boot:0xc (SPI_FAST_FLASH_BOOT)
Saved PC:0x403842e6
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6100,len:0x14
load:0x3fcd6114,len:0x17dc
load:0x403ce000,len:0x86c
load:0x403d0000,len:0x29b4
entry 0x403ce000
I (31) boot: ESP-IDF qa-test-v4.3-20201113-876-gd6a9 2nd stage bootloader
I (31) boot: compile time 19:39:33
I (32) boot: chip revision: 0
I (41) boot.esp32c3: SPI Speed      : 80MHz
I (41) boot.esp32c3: SPI Mode       : DIO
I (45) boot.esp32c3: SPI Flash Size : 4MB
I (50) boot: Enabling RNG early entropy source...
W (55) bootloader_random: RNG for ESP32-C3 not currently supported
I (62) boot: Partition Table:
I (65) boot: ## Label            Usage          Type ST Offset   Length
I (73) boot:  0 sec_cert         unknown          3f 00 0000d000 00003000
I (80) boot:  1 nvs              WiFi data        01 02 00010000 00006000
I (88) boot:  2 otadata          OTA data         01 00 00016000 00002000
I (95) boot:  3 phy_init         RF data          01 01 00018000 00001000
I (103) boot:  4 ota_0            OTA app          00 10 00020000 00190000
I (110) boot:  5 ota_1            OTA app          00 11 001b0000 00190000
I (118) boot:  6 fctry            WiFi data        01 02 00340000 00006000
I (125) boot:  7 coredump         Unknown data     01 03 00350000 00010000
I (133) boot: End of partition table
I (137) esp_image: segment 0: paddr=0x00020020 vaddr=0x3c0c0020 size=0x296b8 (169656) map
I (174) esp_image: segment 1: paddr=0x000496e0 vaddr=0x3fc8e200 size=0x03500 ( 13568) load
I (177) esp_image: segment 2: paddr=0x0004cbe8 vaddr=0x40380000 size=0x03430 ( 13360) load
I (183) esp_image: segment 3: paddr=0x00050020 vaddr=0x42000020 size=0xb3a90 (735888) map
I (311) esp_image: segment 4: paddr=0x00103ab8 vaddr=0x40383430 size=0x0ad2c ( 44332) load
I (321) esp_image: segment 5: paddr=0x0010e7ec vaddr=0x50000000 size=0x00010 (    16) load
I (326) boot: Loaded app from partition at offset 0x20000
I (326) boot: Disabling RNG early entropy source...
W (330) bootloader_random: RNG for ESP32-C3 not currently supported
I (348) cpu_start: Pro cpu up.
I (360) cpu_start: Pro cpu start user code
I (360) cpu_start: cpu freq: 160000000
I (360) cpu_start: Application information:
I (363) cpu_start: Project name:     esp-idf
I (368) cpu_start: App version:      29b6481-dirty
I (374) cpu_start: Compile time:     Aug 24 2021 13:13:42
I (380) cpu_start: ELF file SHA256:  0000000000000000...
I (386) cpu_start: ESP-IDF:          4.3.0
I (390) heap_init: Initializing. RAM available for dynamic allocation:
I (398) heap_init: At 3FC96300 len 00029D00 (167 KiB): DRAM
I (404) heap_init: At 3FCC0000 len 0001F260 (124 KiB): STACK/DRAM
I (411) heap_init: At 50000010 len 00001FF0 (7 KiB): RTCRAM
I (417) spi_flash: detected chip: generic
I (422) spi_flash: flash io: dio
I (426) sleep: Configure to isolate all GPIO pins in sleep state
I (432) sleep: Enable automatic switching of GPIO sleep configuration
I (440) cpu_start: Starting scheduler.
Hello, world from Rust!
More complex print ["foo", "bar"]
Result: 0, 1
Rust main thread: Thread { id: ThreadId(1), name: Some("main"), .. }
This is thread number 0, Thread { id: ThreadId(2), name: None, .. }
This is thread number 1, Thread { id: ThreadId(3), name: None, .. }
This is thread number 2, Thread { id: ThreadId(4), name: None, .. }
This is thread number 3, Thread { id: ThreadId(5), name: None, .. }
This is thread number 4, Thread { id: ThreadId(6), name: None, .. }
About to join the threads. If ESP-IDF was patched successfully, joining will NOT crash
Joins were successful.
I (2556) pp: pp rom version: 8459080
I (2556) net80211: net80211 rom version: 8459080
I (2566) wifi:wifi driver task: 3fc9ff30, prio:23, stack:6656, core=0
I (2566) system_api: Base MAC address is not set
I (2566) system_api: read default base MAC address from EFUSE
I (2566) wifi:wifi firmware version: c7d0450
I (2576) wifi:wifi certification version: v7.0
I (2576) wifi:config NVS flash: disabled
I (2576) wifi:config nano formating: disabled
I (2586) wifi:Init data frame dynamic rx buffer num: 32
I (2586) wifi:Init management frame dynamic rx buffer num: 32
I (2596) wifi:Init management short buffer num: 32
I (2596) wifi:Init dynamic tx buffer num: 32
I (2606) wifi:Init static tx FG buffer num: 2
I (2606) wifi:Init static rx buffer size: 1600
I (2616) wifi:Init static rx buffer num: 10
I (2616) wifi:Init dynamic rx buffer num: 32
I (2616) wifi_init: rx ba win: 6
I (2626) wifi_init: tcpip mbox: 32
I (2626) wifi_init: udp mbox: 6
I (2636) wifi_init: tcp mbox: 6
I (2636) wifi_init: tcp tx win: 5744
I (2636) wifi_init: tcp rx win: 5744
I (2646) wifi_init: tcp mss: 1440
I (2646) wifi_init: WiFi IRAM OP enabled
I (2656) wifi_init: WiFi RX IRAM OP enabled
I (2656) esp_idf_svc::wifi: Driver initialized
I (2666) esp_idf_svc::wifi: Event handlers registered
I (2666) esp_idf_svc::wifi: Initialization complete
I (2676) rust_esp32_std_hello: Wifi created, about to scan
I (2676) esp_idf_svc::wifi: About to scan for access points
I (2686) esp_idf_svc::wifi: Stopping
I (2686) esp_idf_svc::wifi: Disconnect requested
I (2696) esp_idf_svc::wifi: Stop requested
I (2696) esp_idf_svc::wifi: About to wait for status
I (2706) esp_idf_svc::wifi: Providing status: Status(Stopped, Stopped)
I (2716) esp_idf_svc::wifi: Waiting for status done - success
I (2716) esp_idf_svc::wifi: Stopped
I (2726) phy_init: phy_version 500,985899c,Apr 19 2021,16:05:08
Guru Meditation Error: Core  0 panic'ed (Illegal instruction). Exception was unhandled.

Core  0 register dump:
MEPC    : 0x40001be4  RA      : 0x42091c7c  SP      : 0x3fc9fd10  GP      : 0x3fc8ea00
TP      : 0x3fc76868  T0      : 0x40057fa6  T1      : 0x0000000f  T2      : 0xffffffff
S0/FP   : 0x3fc955b4  S1      : 0x3fc955b0  A0      : 0x3fc8f684  A1      : 0x40001a8c
A2      : 0x3fc8f000  A3      : 0x400019f0  A4      : 0x40001964  A5      : 0x3fcdf4f8
A6      : 0x42052ca0  A7      : 0x0000000a  S2      : 0x3fc955b0  S3      : 0x00000002
S4      : 0x3fc92ee0  S5      : 0x3fce0000  S6      : 0x3fce0000  S7      : 0x3fce0000
S8      : 0x3ff1b000  S9      : 0x3fce0000  S10     : 0x3fcdf8d4  S11     : 0x00000000
T3      : 0x00000000  T4      : 0xffffffff  T5      : 0xffffffff  T6      : 0xffffffff
MSTATUS : 0x00001881  MTVEC   : 0x40380001  MCAUSE  : 0x00000002  MTVAL   : 0x00000000
MHARTID : 0x00000000

Stack memory:
3fc9fd10: 0x3c0d1f60 0x3fca5284 0x3fca5284 0x42092540 0x50500000 0x484c4c50 0x4448484c 0x4246464a
3fc9fd30: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc9fd50: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc9fd70: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc9fd90: 0x00000000 0x00000000 0x00000000 0x00000000 0x3fc90eec 0x3fce0000 0x3fc92ee0 0x3fc93000
3fc9fdb0: 0x00000000 0x3fc92ee0 0x3fca5284 0x42028664 0xffffffff 0x3fc92ee0 0x3fce0000 0x42028732
3fc9fdd0: 0x00000000 0x3fc92ee0 0x3fc92ee0 0x420744ce 0x00000002 0x00000000 0x3fc92ee0 0x00000001
3fc9fdf0: 0x00000001 0x00000000 0x3fc92ee0 0x420745e2 0x3fca5214 0x00000000 0x00000000 0x3fc8e8e0
3fc9fe10: 0x3fca5214 0x00000008 0x00000001 0x42071764 0x00000000 0x3fcdf918 0x3fce0000 0x3ff1b594
3fc9fe30: 0x00000000 0x3fcdf918 0x3fce0000 0x4003fe8a 0x00000000 0x00000000 0x00000006 0x3fca5214
3fc9fe50: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc9fe70: 0x00000000 0x00000000 0x00000000 0x4038967a 0x00000000 0x00000000 0x00000000 0x00000000
3fc9fe90: 0x00000000 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0x27146414 0x00000000 0x00000000 0x01010107
3fc9feb0: 0x00000001 0x00000000 0xffffffff 0x7fefffff 0x00000000 0x3fc00000 0x00000000 0x40300000
3fc9fed0: 0x00000000 0x3fe00000 0x00000000 0x3ff80000 0x636f4361 0x3fd287a7 0x8b60c8b3 0x3fc68a28
3fc9fef0: 0x509f79fb 0x3fd34413 0x00000000 0x3ff00000 0x00000000 0x40240000 0x00000000 0x401c0000
3fc9ff10: 0x00000000 0x40140000 0x00000000 0x43500000 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0x00000154
3fc9ff30: 0x3fc9fd60 0x3fc96314 0x3fc91f24 0x3fc91f24 0x3fc9ff30 0x3fc91f1c 0x00000002 0x3fc9de68
3fc9ff50: 0x3fc9de68 0x3fc9ff30 0x00000000 0x00000017 0x3fc9e52c 0x69666977 0x5f1a5600 0xc88e8184
3fc9ff70: 0x00212e8e 0x00000000 0x3fc9ff20 0x00000017 0x00000001 0x00000000 0x00000000 0x00000000
3fc9ff90: 0x3fc96b2c 0x3fc96b94 0x3fc96bfc 0x00000000 0x00000000 0x00000001 0x00000000 0x00000000
3fc9ffb0: 0x00000000 0x42099f0c 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc9ffd0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc9fff0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fca0010: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fca0030: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fca0050: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fca0070: 0x00000000 0x00000000 0x00000000 0x00000000 0x3fc90000 0x00000054 0x3fca0088 0x3fca0088
3fca0090: 0x3fca0088 0x3fca0088 0x00000000 0x3fca00a0 0xffffffff 0x3fca00a0 0x3fca00a0 0x00000000
3fca00b0: 0x3fca00b4 0xffffffff 0x3fca00b4 0x3fca00b4 0x00000000 0x00000001 0x00000000 0xf400ffff
3fca00d0: 0x00000000 0x6d5a935a 0x3fca0080 0x00000054 0x00000000 0x3fca00e0 0x00000000 0x00000000
3fca00f0: 0x00000000 0x3fca00f8 0xffffffff 0x3fca00f8 0x3fca00f8 0x00000000 0x3fca010c 0xffffffff



ELF file SHA256: 0000000000000000

Rebooting...

Any insight into what could be going on would be appreciated. I am able to provide any further details if it is helpful.

HTTP headers wrongly treated as case-sensitive by client

EspHttpResponse defines headers as BTreeMap<String, String>:

pub struct EspHttpResponse<'a> {
client: &'a mut EspHttpClient,
headers: BTreeMap<String, String>,
}

If a server sends Content-Type: something, then resp.content_type() returns None because embedded_svc asks for content-type and EspHttpResponse does a case-sensitive search:

self.headers
.get(name.as_ref())
.map(|s| Cow::Borrowed(s.as_str()))

I think the fix is replacing the String key with something like Uncased

Crypto support

Hi!

I have been messing around w/ the esp and would like to add a hal impl for the hardware hmac signing / DS on the esp32 c3 (and more). I assume that would happen in esp-idf-svc, but I'm opening this issue to make sure I'm targeting the right place.

As a side note, really enjoying working w/ this ecosystem! 🎉

Can't disable color logging

I'm not sure if this should go here or in esp-idf-sys. I've been trying to disable the generation of terminal color control sequences when logging, and so in sdkconfig I have # CONFIG_LOG_COLORS is not set rather than CONFIG_LOG_COLORS=y. Doing this causes esp-idf-sys to generate without a const CONFIG_LOG_COLORS and I get a compiler error since esp-idf-svc expects it to be defined but equal to 0 in the case of disabling color logs.

error[E0425]: cannot find value `CONFIG_LOG_COLORS` in this scope
   --> /home/zac/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-svc-0.41.3/src/log.rs:107:12
    |
107 |         if CONFIG_LOG_COLORS == 0 {
    |            ^^^^^^^^^^^^^^^^^ not found in this scope

For more information about this error, try `rustc --explain E0425`.
error: could not compile `esp-idf-svc` due to previous error

I've tried this with both rust-esp32-std-demo and also a platformio based build and it's the same error in both. Has this branch ever executed? If so what am I doing wrong?

espnow missing some functions to get going

Initially I wanted to make a PR for this, but before I do it might be better to check if I am overlooking something.

While trying out ESPNow, I noticed a few missing pieces:

  • There is no helper function to get the MAC address to use for ESPNow. Of course esp-idf-sys has it, but that is less nice. Currently I did: esp!(esp_wifi_get_mac(wifi_mode_t_WIFI_MODE_NULL, &mut mac as *mut c_types::c_uchar))?;. I think a nice helper function either in espnow or in wifi would greatly help the next guy trying out ESPNow.
  • I couldn't find a function that does an esp_wifi_start() in STA, without actually connecting to an AP. set_configuration does a lot more than is needed for ESPNow. For now I settled on:
        esp!(esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_STA))?;
        esp!(esp_wifi_start())?;

But here too it might be useful to have a simple wrapper function.

Am I overlooking something, or would it be fine if I make a PR to wrap both in a nice little function?
I was thinking of putting the first one in espnow, as there are several MAC addresses assigned to an ESP, but only one works with ESPNow. The second I guess belongs in wifi, so something like start_sta() or something?

Tnx :)

Feature Request / RFC: Allow subscribing to wifi and ip event seperately

At the moment the callback for EspWifi::subscribe does not pass the event into the callback, because the Subscription is to a combination of WifiEvent and IpEvent.

For some applications it would be useful to get the event instead of just an info that something happened.

To achieve this, I see two options, which are possible to implement together and I'd be willing to create a PR for this.

Option 1: Two subscribe_* methods

This options contains adding two new methods to the esp_idf_svc::wifi::EspWifi struct:

  1. subscribe_wifi_events(&mut self, callback: impl for<'a> FnMut(&'a WifiEvent) + Send + 'static) -> Result<Self::Subscription, Self::Error>)
  2. subscribe_ip_events(&mut self, callback: impl for<'a> FnMut(&'a IpEvent) + Send + 'static) -> Result<Self::Subscription, Self::Error>)

This would allow users to clearly define which events they want to listen on and also provide a way to actually receive the triggering events.

This approach can be implemented without making a breaking change.

Option 2: Changing the subscribe signature

This option would change the current method signature in a way, that allows returning the events. This could be achieved like this:

  1. Change the callback param to (Option<&WifiEvent>, Option<&IpEvent>) and fill the corresponding
  2. Add a new type enum EspWifiEvent { Wifi(&WifiEvent), Ip(&IpEvent) } (simplified) and using that as the callback argument

This would be a breaking change to the API.

Currently possible options:

ATM you could of course subscribe to the corresponding event bus yourself and reimplement the logic inside of esp-idf-svc, but I think this is neither ergonomic, nor a good pattern.

Question: How to obtain Mac Address of Wifi Adapter?

This is probably an easy one:

I'm trying to write a custom WifiMgr which handles wifi reconnects and creating an Wifi AP if no WiFI is available.
To avoid SSID duplicates and keep them identifyable, I want to use the last 3 bytes of the mac as hex in the SSID.

What I want to do:

Get the default Mac Address of the Wifi Interface before starting a connection/AP.

What I've tried:

I've tried some different variations of this already:

let netif = EspNetif::new(
    Arc::new(EspNetifStack::new()?),
    &InterfaceConfiguration {
        interface_stack: InterfaceStack::Sta,
        ..Default::default()
    },
)?;
println!("Netif: {:?}", netif.get_mac());

What I get:

But this always prints the mac as only zeros.

I also tried this:

let mut wifi = EspWifi::new(
  Arc::new(EspNetifStack::new()?),
  Arc::new(EspSysLoopStack::new()?),
  Arc::new(EspDefaultNvs::new()?)
)?;

let status = wifi.get_status();
let wifi_config = wifi.get_configuration();
println!("Status: {status:?}, wifi config: {wifi_config:?}");

Used Hardware:

M5StampC3 - ESP32-C3 based board

I'm probably close, but the docs don't really help me out and I feel a little lost.

Feature request: implement esp_wifi_set_country

Hi!

First of, Thank you all for the awesome set of esp related crates :)

I'm porting a little c app from esp-idf to rust and search a simple way to call

    const wifi_country_t cc = {
            .cc = "fr",
            .schan = 1,
            .nchan = 14,
            .max_tx_power = 255,
    };
    ESP_ERROR_CHECK(esp_wifi_set_country(&cc));

from rust, but i'm a bit stuck

Any clues are welcomed

ESP32-C3 stack overflow for wifi in a thread

Hi

I'm getting a stackoverflow when trying to connect to wifi in a thread on the C3.
See https://github.com/BrendanBall/light-switch/blob/wifi_in_thread/src/main.rs . It is mostly copied from the demo project.

monitor output:

➜  light-switch git:(master) ✗ cargo espmonitor --chip esp32c3 /dev/ttyUSB0
ESPMonitor 0.5.2

Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

Opening /dev/ttyUSB0 with speed 115200
WARNING: Flash image /home/brendan/dev/projects/light-switch/target/riscv32imc-unknown-none-elf/debug/light-switch does not exist (you may need to build it)
Resetting device... done
2) spi_flash: �ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6100,len:0x172c
load:0x403ce000,len:0x928
load:0x403d0000,len:0x2ce0
entry 0x403ce000
I (30) boot: ESP-IDF v4.4-dev-2825-gb63ec47238 2nd stage bootloader
I (30) boot: compile time 12:10:40
I (30) boot: chip revision: 3
I (33) boot_comm: chip revision: 3, min. bootloader chip revision: 0
I (40) boot.esp32c3: SPI Speed      : 80MHz
I (45) boot.esp32c3: SPI Mode       : DIO
I (50) boot.esp32c3: SPI Flash Size : 4MB
I (55) boot: Enabling RNG early entropy source...
I (60) boot: Partition Table:
I (64) boot: ## Label            Usage          Type ST Offset   Length
I (71) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (78) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (86) boot:  2 factory          factory app      00 00 00010000 003f0000
I (93) boot: End of partition table
I (98) boot_comm: chip revision: 3, min. application chip revision: 0
I (105) esp_image: segment 0: paddr=00010020 vaddr=3c0a0020 size=1e4d0h (124112) map
I (132) esp_image: segment 1: paddr=0002e4f8 vaddr=3fc8e800 size=01b20h (  6944) load
I (133) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=968d8h (616664) map
I (230) esp_image: segment 3: paddr=000c6900 vaddr=3fc90320 size=01830h (  6192) load
I (231) esp_image: segment 4: paddr=000c8138 vaddr=40380000 size=0e604h ( 58884) load
I (247) esp_image: segment 5: paddr=000d6744 vaddr=50000000 size=00010h (    16) load
I (251) boot: Loaded app from partition at offset 0x10000
I (251) boot: Disabling RNG early entropy source...
I (267) cpu_start: Pro cpu up.
I (280) cpu_start: Pro cpu start user code
I (280) cpu_start: cpu freq: 160000000
I (280) cpu_start: Application information:
I (282) cpu_start: Project name:     esp-idf
I (287) cpu_start: App version:      e596c0d-dirty
I (293) cpu_start: Compile time:     Dec 27 2021 16:32:26
I (299) cpu_start: ELF file SHA256:  0000000000000000...
I (305) cpu_start: ESP-IDF:          4.3.1
I (310) heap_init: Initializing. RAM available for dynamic allocation:
I (317) heap_init: At 3FC95C10 len 0002A3F0 (168 KiB): DRAM
I (323) heap_init: At 3FCC0000 len 0001F060 (124 KiB): STACK/DRAM
I (330) heap_init: At 50000010 len 00001FF0 (7 KiB): RTCRAM
I (337) spi_flash: detected chip: generic
I (341) spi_flash: flash io: dio
I (345) sleep: Configure to isolate all GPIO pins in sleep state
I (352) sleep: Enable automatic switching of GPIO sleep configuration
I (359) cpu_start: Starting scheduler.
I (364) pp: pp rom version: 9387209
I (364) net80211: net80211 rom version: 9387209
***ERROR*** A stack overflow in task pthread has been detected.
Core  0 register dump:
MEPC    : 0x403858a2  RA      : 0x40386018  SP      : 0x3fc92100  GP      : 0x3fc8f000
TP      : 0x3fc80314  T0      : 0x4005890e  T1      : 0x0000000f  T2      : 0x00000001
S0/FP   : 0x00000003  S1      : 0x00000001  A0      : 0x3fc92118  A1      : 0x3c0aab28
A2      : 0x00000003  A3      : 0x3fc92145  A4      : 0x00000001  A5      : 0x3fc96000
A6      : 0x40140000  A7      : 0x00000000  S2      : 0x00001881  S3      : 0x00000001
S4      : 0x00000000  S5      : 0x3c0aa314  S6      : 0x00000000  S7      : 0x00000017
S8      : 0x3fcdf928  S9      : 0x00000000  S10     : 0x00000000  S11     : 0x00000000
T3      : 0x00000000  T4      : 0x00000000  T5      : 0x00000001  T6      : 0x3ff00000
MSTATUS : 0x00001801  MTVEC   : 0x40380001  MCAUSE  : 0x00000007  MTVAL   : 0x00000000
MHARTID : 0x00000000
Stack memory:
3fc92100: 0x00000000 0x00000000 0x00000000 0x40389936 0x00000000 0x00000000 0x452a2a2a 0x524f5252
3fc92120: 0x202a2a2a 0x74732041 0x206b6361 0x7265766f 0x776f6c66 0x206e6920 0x6b736174 0x68747020
3fc92140: 0x64616572 0x73616820 0x65656220 0x6564206e 0x74636574 0x002e6465 0x00000000 0x00000000
3fc92160: 0x00000000 0x3c0aaaec 0x3fc9e734 0x3c0aab14 0x00000000 0x80000003 0x00000000 0x4038803a
3fc92180: 0x00000000 0x80000003 0x3fca107c 0x4038911e 0x403801ba 0x00000000 0x00000000 0x4038019e
3fc921a0: 0x00000001 0x3fc921a8 0xffffffff 0x3fc9a314 0x3fc9a314 0x00000001 0x3fc998b8 0xffffffff
3fc921c0: 0x3fc998b8 0x3fc998b8 0x00000000 0x3fc921d0 0xffffffff 0x3fc921d0 0x3fc921d0 0x00000000
3fc921e0: 0x3fc921e4 0xffffffff 0x3fc921e4 0x3fc921e4 0x00000000 0x3fc921f8 0xffffffff 0x3fc921f8
3fc92200: 0x3fc921f8 0x00000001 0x3fc9e704 0xffffffff 0x3fc9e704 0x3fc9e704 0x00000000 0x3fc92220
3fc92220: 0xffffffff 0x3fc92220 0x3fc92220 0x00000000 0x3fc92234 0xffffffff 0x3fc92234 0x3fc92234
3fc92240: 0x00000000 0x3fc92248 0xffffffff 0x3fc92248 0x3fc92248 0x00000000 0x3fc9225c 0xffffffff
3fc92260: 0x3fc9225c 0x3fc9225c 0x00000000 0x3fc92270 0xffffffff 0x3fc92270 0x3fc92270 0x00000000
3fc92280: 0x3fc92284 0xffffffff 0x3fc92284 0x3fc92284 0x00000000 0x3fc92298 0xffffffff 0x3fc92298
3fc922a0: 0x3fc92298 0x00000000 0x3fc922ac 0xffffffff 0x3fc922ac 0x3fc922ac 0x00000000 0x3fc922c0
3fc922c0: 0xffffffff 0x3fc922c0 0x3fc922c0 0x00000000 0x3fc922d4 0xffffffff 0x3fc922d4 0x3fc922d4
3fc922e0: 0x00000000 0x3fc922e8 0xffffffff 0x3fc922e8 0x3fc922e8 0x00000000 0x3fc922fc 0xffffffff
3fc92300: 0x3fc922fc 0x3fc922fc 0x00000000 0x3fc92310 0xffffffff 0x3fc92310 0x3fc92310 0x00000000
3fc92320: 0x3fc92324 0xffffffff 0x3fc92324 0x3fc92324 0x00000000 0x3fc92338 0xffffffff 0x3fc92338
3fc92340: 0x3fc92338 0x00000000 0x3fc9234c 0xffffffff 0x3fc9234c 0x3fc9234c 0x00000000 0x3fc92360
3fc92360: 0xffffffff 0x3fc92360 0x3fc92360 0x00000001 0x3fc92374 0xffffffff 0x3fca1080 0x3fca1080
3fc92380: 0x00000000 0x3fc92388 0xffffffff 0x3fc92388 0x3fc92388 0x00000001 0x3fc9239c 0xffffffff
3fc923a0: 0x3fc9c158 0x3fc9c158 0x00000000 0x3fc923b0 0xffffffff 0x3fc923b0 0x3fc923b0 0x00000000
3fc923c0: 0x3fc923c4 0xffffffff 0x3fc923c4 0x3fc923c4 0x00000003 0x3fc923d8 0xffffffff 0x3fc979c4
3fc923e0: 0x3fc9d1a8 0x00000000 0x3fc923ec 0xffffffff 0x3fc923ec 0x3fc923ec 0x3c0b2610 0x00000005
3fc92400: 0x3c0a9eb4 0x0000000d 0x3c0a9aac 0x00000015 0x3c0b0f38 0x0000001d 0x3c0b47c0 0x00000025
3fc92420: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc92440: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc92460: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc92480: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc924a0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc924c0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
3fc924e0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
ELF file SHA256: 0000000000000000

Build failure when building with bluetooth enabled

Hey,

I'm having issues including esp-idf-svc into my project, due to a conflict with the log crate?

   Compiling embedded-svc v0.21.1
error[E0659]: `log` is ambiguous
 --> C:\Users\Afonso\.cargo\registry\src\github.com-1ecc6299db9ec823\esp-idf-svc-0.41.1\src\espnow.rs:1:5
  |
1 | use log::info;
  |     ^^^ ambiguous name
  |
  = note: ambiguous because of multiple potential import sources
  = note: `log` could refer to a crate passed with `--extern`
  = help: use `::log` to refer to this crate unambiguously
note: `log` could also refer to the struct imported here
 --> C:\Users\Afonso\.cargo\registry\src\github.com-1ecc6299db9ec823\esp-idf-svc-0.41.1\src\espnow.rs:6:5
  |
6 | use esp_idf_sys::*;
  |     ^^^^^^^^^^^^^^
  = help: use `self::log` to refer to this struct unambiguously

error[E0659]: `log` is ambiguous
 --> C:\Users\Afonso\.cargo\registry\src\github.com-1ecc6299db9ec823\esp-idf-svc-0.41.1\src\sntp.rs:4:5
  |
4 | use log::*;
  |     ^^^ ambiguous name
  |
  = note: ambiguous because of multiple potential import sources
  = note: `log` could refer to a crate passed with `--extern`
  = help: use `::log` to refer to this crate unambiguously
note: `log` could also refer to the struct imported here
 --> C:\Users\Afonso\.cargo\registry\src\github.com-1ecc6299db9ec823\esp-idf-svc-0.41.1\src\sntp.rs:8:5
  |
8 | use esp_idf_sys::*;
  |     ^^^^^^^^^^^^^^
  = help: use `self::log` to refer to this struct unambiguously

For more information about this error, try `rustc --explain E0659`.
error: could not compile `esp-idf-svc` due to 2 previous errors
warning: build failed, waiting for other jobs to finish...

There doesen't seem to be multiple versions of the log crate in use

I've created a example repo that demonstrates this issue here.

The repo is essentially just the esp-idf-template with some additional dependencies and slightly different configs.

The issue goes away if I remove these lines from the sdkconfig.defaults, delete target and .embuild and rebuild:

# Enable Bluetooth
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_BLUEDROID_ENABLED=n

Corrupted HTTP Request due to usage of httpd_resp_set_status

The implementation of EspHttpResponseHeaders::send is corrupting the HTTP response. The implementation uses httpd_resp_set_status() which requires that the provided raw pointer is valid until the response is send. This is with the current implementation not the case. The lifetime of the dereferenced raw c++ pointer is to short (only valid within the EspHttpResponseHeaders::send() function, but no longer when the response gets transmitted.

I'm not aware that Rust allows lifetimes for raw pointer, so I assume the best solution would be to refactor the EspHttpResponseHeaders::send() function and move the code into the EspHttpResponseWrite::write function to ensure that the lifetime of the raw pointer can be managed as required by the ESP_IDF api.

See details for the API https://docs.espressif.com/projects/esp-idf/en/v4.2.2/esp32/api-reference/protocols/esp_http_server.html

Specific the note: "Make sure that the lifetime of the status string is valid till send function is called."

esp!(unsafe { httpd_resp_set_status(raw_req, c_status.as_ptr() as _) })?;

Multiple Content-Type headers in response

Hi,

I've succeeded in making my ESP32 go online and present stuff using the esp-idf-svc httpd implementation, however, using the embedded_svc::httpd functionality to render a response, like this:

      Response::ok().content_type("application/json").body(include_str!("result.json").into())

Then upon curl'ing into my app, I get:

< HTTP/1.1 200
< Content-Type: text/html
< Content-Length: 61
< content-type: application/json
<
....

I seem to be getting two content-type headers :/ -- I can't seem to find 'text/html' in the Rust bindings, so I assume the stuff is being put in by the esp-idf code itself.

Do you have any idea how to fix this?

How to get access point IP address?

Is it possible to get the IP address that ESP chose to give itself while in AP mode? Or will it always be the subnet's gateway IP address as given in embedded_svc::ipv4::RouterConfiguration.subnet?

Sorry if this is a dumb question. I'm learning the ropes and haven't even fired up my ESP32C3 as an access point yet. I'm just trying to make sense of the APIs.

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.