esp-rs icon indicating copy to clipboard operation
esp-rs copied to clipboard

How to find what API's are available?

Open torntrousers opened this issue 6 years ago • 12 comments

Now that I finally have this compiling, how do I find what ESP8266 API's are available to use from Rust?

The generated example uses things like esp8266_hal::OutputPin and LED_BUILTIN, where are they defined?

How would I do something like start Wifi and connect to an access point?

torntrousers avatar Jan 01 '19 17:01 torntrousers

These are calling bindings to the ESP8266 Arduino SDK that are generated automatically using bindgen. You should in theory be able to use any function in the SDK but in practice I've found that bindgen doesn't always succeed. Try looking up ESP8266 Arduino tutorials and calling the same functions from Rust. The build script should know based on what you use which bindings are needed.

emosenkis avatar Jan 01 '19 17:01 emosenkis

Thanks for the quick reply. Ok, so a simple ESP8266/Arduino example might connect to Wifi with:

    WiFi.mode(WIFI_STA);
    WiFi.begin("someSSID", "somePassword");

So I add those to the lib.rs example and it fails with:

Running cargo check
    Checking my-project v0.1.0 (/ant/my-project)
error[E0425]: cannot find value `WiFi` in this scope
  --> src/lib.rs:25:5
   |
25 |     WiFi.mode(WIFI_STA);
   |     ^^^^ not found in this scope

error[E0425]: cannot find value `WIFI_STA` in this scope
  --> src/lib.rs:25:15
   |
25 |     WiFi.mode(WIFI_STA);
   |               ^^^^^^^^ not found in this scope

error[E0425]: cannot find value `WiFi` in this scope
  --> src/lib.rs:26:5
   |
26 |     WiFi.begin("someSSID", "somePassword");
   |     ^^^^ not found in this scope

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0425`.
error: Could not compile `my-project`.

What am I doing wrong?

torntrousers avatar Jan 01 '19 17:01 torntrousers

As this issue has been closed now should I open a new one for the Wifi question?

torntrousers avatar Jan 02 '19 07:01 torntrousers

Did you run build.sh again? What's in bindings.rs now?

I don't have much time to invest in supporting this project right now so if anyone else is able to help, please jump in.

emosenkis avatar Jan 02 '19 16:01 emosenkis

Yes I did run build.sh again. This is whats in bindings.rs:

root@240e8789861a:/ant/my-project# find . | grep binding
./src/bindings.rs
./vendor/esp8266-hal/src/bindings.rs
root@240e8789861a:/ant/my-project# cat ./src/bindings.rs
/* automatically generated by rust-bindgen */

#![allow(non_snake_case,non_camel_case_types,non_upper_case_globals)]
extern crate libc;

pub const LED_BUILTIN: u32 = 16;
extern "C" {
    pub fn delay(arg1: libc::c_ulong);
}
root@240e8789861a:/ant/my-project# cat ./vendor/esp8266-hal/src/bindings.rs
/* automatically generated by rust-bindgen */

#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
extern crate libc;

pub const HIGH: libc::c_uint = 1;
pub const LOW: libc::c_uint = 0;
pub const INPUT: libc::c_uint = 0;
pub const OUTPUT: libc::c_uint = 1;
pub type __uint8_t = libc::c_uchar;
extern "C" {
    pub fn pinMode(pin: u8, mode: u8);
}
extern "C" {
    pub fn digitalWrite(pin: u8, val: u8);
}
extern "C" {
    pub fn digitalRead(pin: u8) -> libc::c_int;
}

torntrousers avatar Jan 02 '19 16:01 torntrousers

Is it because this only supports the digital pin operations so any other ESP8266 functions would need some similar code implemented in somewhere like the esp8266-hal crate?

torntrousers avatar Jan 02 '19 19:01 torntrousers

No, that's just a crate of wrappers for convenience and compatibility with the embedded-hal ecosystem. It's written using the same build script and its bindings are generated in exactly the same way.

emosenkis avatar Jan 02 '19 20:01 emosenkis

I'm a bit of a Rust newbie. I've no idea how this works, so can you or someone give me any hints?

I can have WiFi.mode(WIFI_STA); in my Arduino C program because I also have #include <ESP8266WiFi.h> which drags in this file, which includes a bunch of other things including this which defines the mode function implementation.

How is Rust supposed to work out from just WiFi.mode(WIFI_STA); in my Rust src that its supposed to call the mode function from ESP8266WiFiGeneric.cpp? It feels like I'm missing something and need more than just WiFi.mode in my Rust source, (making up some syntax) something like ESP8266WiFi::WiFi.mode(WIFI_STA); ?

torntrousers avatar Jan 02 '19 20:01 torntrousers

@emosenkis @torntrousers I've also tried to get the WiFi example running. So far, I'm out of luck.

What I could gather so far is that build.sh is grep-ing all #include in src/main.ino, and feeding them into bindgen, which then supposedely should create bindings but will fail miserably.

First I had to upgrade the SDK to 2.4.2 (force pip2 and add parallel builds to not wait for ages on each full rebuild)

diff --git a/build.sh b/build.sh
index 1862853..e3996fc 100755
--- a/build.sh
+++ b/build.sh
@@ -3,7 +3,7 @@
 set -e -u -o pipefail
 
 readonly MRUSTC_VER='b5b7089'
-readonly SDK_VER='2.4.1'
+readonly SDK_VER='2.4.2'
 
 readonly INSTALL_DIR="${HOME}/.esp-rs"
 readonly MRUSTC_DIR="${INSTALL_DIR}/mrustc"
@@ -57,7 +57,7 @@ function install_toolchain() {
     fi
     if ! platformio --version &>/dev/null; then
         echo 'Installing platformio...'
-        pip install platformio --user
+        pip2 install platformio --user
     fi
     if ! [[ -d "${INSTALL_DIR}" ]]; then
         mkdir "${INSTALL_DIR}"
@@ -65,7 +65,7 @@ function install_toolchain() {
 
     checkout_git_revision 'https://github.com/thepowersgang/mrustc.git' "${MRUSTC_VER}" "${MRUSTC_DIR}" 'mrustc'
     echo "Building mrustc/minicargo@${MRUSTC_VER}"
-    ( cd "${MRUSTC_DIR}" && make RUSTCSRC && make -f minicargo.mk PARLEVEL=$(nproc) LIBS )
+    ( cd "${MRUSTC_DIR}" && make RUSTCSRC -j $(nproc) && make -f minicargo.mk -j$(nproc) PARLEVEL=$(nproc) LIBS )
     checkout_git_revision 'https://github.com/esp8266/Arduino.git' "${SDK_VER}" "${SDK_ROOT}" 'ESP8266 Arduino SDK'
     if ! [[ -d "${TOOLCHAIN_ROOT}" ]]; then
         echo 'Installing PlatformIO ESP8266 Arduino SDK...'

I specifically had to add a bunch of defines in

lib/generated/generated.h:

#define TCP_MSS 0
#define LWIP_IPV6 0
#define LWIP_FEATURES 0
#define LWIP_OPEN_SRC 0

for bindgen to continue parsing.

The main.ino looks hacky at best as well:

// Include an empty header to make platformio compile the generated code

#include <generated.h>
extern "C" {
    #include "../lib/generated/libesp_rs_project-0_1_0.hir.o.c"
}

#include <lwipopts.h>
#include <lwip/opt.h>
#include <IPAddress.h>

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

decltype(setup_rs()) main;

void setup() {
    main = setup_rs();
}

void loop() {
    loop_rs(&main);
}

The resulting log of the execution of build.sh shows more issues:

/home/someuser/.platformio/packages/framework-arduinoespressif8266/cores/esp8266/Client.h:37:22: warning: 'Client::flush' hides overloaded virtual function [-Woverloaded-virtual]
/home/someuser/.platformio/packages/framework-arduinoespressif8266/cores/esp8266/Print.h:93:22: note: hidden overloaded virtual function 'Print::flush' declared here: different number of parameters (0 vs 1)
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h:47:12: warning: 'BearSSL::WiFiClientSecure::write' hides overloaded virtual function [-Woverloaded-virtual]
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClient.h:59:18: note: hidden overloaded virtual function 'WiFiClient::write' declared here: type mismatch at 1st parameter ('uint8_t' (aka 'unsigned char') vs 'const char *')
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h:53:12: warning: 'BearSSL::WiFiClientSecure::write' hides overloaded virtual function [-Woverloaded-virtual]
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClient.h:59:18: note: hidden overloaded virtual function 'WiFiClient::write' declared here: type mismatch at 1st parameter ('uint8_t' (aka 'unsigned char') vs 'Stream &')
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h:51:34: error: use of undeclared identifier 'strlen_P'
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h:80:7: error: use of undeclared identifier 'memcpy_P'
tools/sdk/libc/xtensa-lx106-elf/include/stdlib.h:122:44: warning: unknown attribute '__warning__' ignored [-Wunknown-attributes], err: false
tools/sdk/libc/xtensa-lx106-elf/include/stdlib.h:133:65: warning: unknown attribute '__warning__' ignored [-Wunknown-attributes], err: false
tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h:59:3: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register], err: false
tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h:66:3: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register], err: false
/home/someuser/.platformio/packages/framework-arduinoespressif8266/cores/esp8266/Client.h:37:22: warning: 'Client::flush' hides overloaded virtual function [-Woverloaded-virtual], err: false
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h:47:12: warning: 'BearSSL::WiFiClientSecure::write' hides overloaded virtual function [-Woverloaded-virtual], err: false
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h:53:12: warning: 'BearSSL::WiFiClientSecure::write' hides overloaded virtual function [-Woverloaded-virtual], err: false
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h:51:34: error: use of undeclared identifier 'strlen_P', err: true
/home/someuser/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h:80:7: error: use of undeclared identifier 'memcpy_P', err: true

I doubt this is how the project is supposed to be used. Are there more current pointers?

apriori avatar Apr 09 '19 21:04 apriori

Further analysis shows we hit a limitation of rust-bindgen here. It cannot bind to inline functions. So I guess we kind of have to rewrite this C++ stuff from scratch, maybe using C dependencies.

apriori avatar Apr 12 '19 21:04 apriori

@apriori very interesting that inline functions were the underlying problem... it seems like it would be useful for bindgen to support that use case...

emosenkis avatar May 27 '19 10:05 emosenkis

It looks like it actually does have some options for making inline functions work: https://rust-lang.github.io/rust-bindgen/faq.html#why-isnt-bindgen-generating-bindings-to-inline-functions

emosenkis avatar May 27 '19 10:05 emosenkis