esp-rs / esp-idf-svc

Type-Safe Rust Wrappers for various ESP-IDF services (WiFi, Network, Httpd, Logging, etc.)
https://docs.esp-rs.org/esp-idf-svc/
Apache License 2.0
333 stars 183 forks source link

Is it possible to get nng or zeromq working with esp-idf-svc? #372

Open wzab opened 9 months ago

wzab commented 9 months ago

I have got the tcp-async example working with Wokwi simulator (see archive tcp-async-1.zip). However, I need my ESP to communicate with a server by sending structured messages. Therefore, I wanted to use either nng or zeromq crate working in my project. However, as soon as I tried to include nng (see archive tcp-async-2.zip),

use nng::{Socket,Protocol};
[...]
async fn tcp_client() -> Result<(), anyhow::Error> {
    info!("About to open a TCP connection to host.wokwi.internal:4300");

    const ADDRESS: &'static str = "host.wokwi.internal:4300";
    let client = Socket::new(Protocol::Req0)?;
    client.dial(ADDRESS)?;

    // Send the request from the client to the server. In general, it will be
    // better to directly use a `Message` to enable zero-copy, but that doesn't
    // matter here.
    client.send("Hello, it's me, your ESP.\n".as_bytes()).unwrap();

    // Wait for the response from the server.
    let msg = client.recv()?;
    println!("Server returned: {:?}",msg);
    Ok(())
}

I get the error:

  = note: [ldproxy] Running ldproxy
          Error: Linker /home/emb/rust-on-esp/tcp-async-2/.embuild/espressif/tools/xtensa-esp32-elf/esp-12.2.0_20230208/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc failed: exit status: 1
          STDERR OUTPUT:
          /home/emb/rust-on-esp/tcp-async-2/.embuild/espressif/tools/xtensa-esp32-elf/esp-12.2.0_20230208/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/12.2.0/../../../../xtensa-esp32-elf/bin/ld: /home/emb/rust-on-esp/tcp-async-2/target/xtensa-esp32-espidf/debug/deps/libnng_sys-80d16e2b9aeb9d95.rlib: error adding symbols: file format not recognized
          collect2: error: ld returned 1 exit status

          Stack backtrace:
             0: anyhow::error::<impl anyhow::Error>::msg
             1: ldproxy::main
             2: std::sys_common::backtrace::__rust_begin_short_backtrace
             3: std::rt::lang_start::{{closure}}
             4: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once
                       at /rustc/5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3/library/core/src/ops/function.rs:284:13
             5: std::panicking::try::do_call
                       at /rustc/5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3/library/std/src/panicking.rs:500:40
             6: std::panicking::try
                       at /rustc/5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3/library/std/src/panicking.rs:464:19
             7: std::panic::catch_unwind
                       at /rustc/5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3/library/std/src/panic.rs:142:14
             8: std::rt::lang_start_internal::{{closure}}
                       at /rustc/5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3/library/std/src/rt.rs:148:48
             9: std::panicking::try::do_call
                       at /rustc/5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3/library/std/src/panicking.rs:500:40
            10: std::panicking::try
                       at /rustc/5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3/library/std/src/panicking.rs:464:19
            11: std::panic::catch_unwind
                       at /rustc/5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3/library/std/src/panic.rs:142:14
            12: std::rt::lang_start_internal
                       at /rustc/5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3/library/std/src/rt.rs:148:20
            13: main
            14: __libc_start_call_main
                       at ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
            15: __libc_start_main_impl
                       at ./csu/../csu/libc-start.c:360:3
            16: _start

warning: `tcp-async-1` (bin "tcp-async-1") generated 1 warning
error: could not compile `tcp-async-1` (bin "tcp-async-1") due to 1 previous error; 1 warning emitted 

If I try to use zeromq (see archive tcp-async-3.zip),

use zmq::{Context,REQ};
[...]
async fn tcp_client() -> Result<(), anyhow::Error> {
    info!("About to open a TCP connection to host.wokwi.internal:4300");

    const ADDRESS: &'static str = "";
    let ctx = zmq::Context::new();

    let socket = ctx.socket(zmq::REQ).unwrap();
    socket.connect("tcp://host.wokwi.internal:4300").unwrap();
    socket.send("Hello, it's me, your ESP.\n", 0).unwrap();
    let msg = socket.recv().unwrap();
    println!("Server returned: {:?}",msg);
    Ok(())
}

I get quite a lot of error messages zmq_error.zip.

The main problem seems to be unavailability of the platform.hpp file:

  cargo:warning=/home/emb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/zeromq-src-0.2.6+4.3.4/vendor/src/precompiled.hpp:43:10: fatal error: platform.hpp: No such file or directory
  cargo:warning=   43 | #include "platform.hpp"
  cargo:warning=      |          ^~~~~~~~~~~~~~
  cargo:warning=compilation terminated.

Is it possible to get nng or zeromq working with Rust on ESP32 platform? If not is there any other embedded Rust compatible library that I could use instead? Of course, I can work it arround by sending:

* MAGIC_HEADER (e.g., 0xabba),
* u32 with the length of the message,
* the message itself,
* the CRC of the message 

but it looks like unnecessary reinventing the wheel...

### Tasks