Open torntrousers opened 5 years ago
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.
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?
As this issue has been closed now should I open a new one for the Wifi question?
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.
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;
}
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?
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.
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);
?
@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?
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 very interesting that inline functions were the underlying problem... it seems like it would be useful for bindgen to support that use case...
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
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
andLED_BUILTIN
, where are they defined?How would I do something like start Wifi and connect to an access point?