chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

ESP32/Rustの勉強、 http-clientサンプルでエラーになる

EspressifのTutorial; Embedded Rust on Espressif / HTTP client
Http Client - Embedded Rust on Espressif

エラーは、EspHttpRequestWriteにはsubmitというメソッドがないというもの

$ cargo build --target=riscv32imc-esp-espidf
   Compiling http-client v0.1.0 (espressif-trainings/intro/http-client)
warning: unused imports: `Headers`, `RequestWrite`, `Response`, `Status`, `io::Read`
 --> src/main.rs:6:35
  |
6 |         client::{Client, Request, RequestWrite, Response},
  |                                   ^^^^^^^^^^^^  ^^^^^^^^
7 |         Headers, Status,
  |         ^^^^^^^  ^^^^^^
8 |     },
9 |     io::Read,
  |     ^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused import: `EspHttpClientConfiguration`
  --> src/main.rs:12:48
   |
12 | use esp_idf_svc::http::client::{EspHttpClient, EspHttpClientConfiguration};
   |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0599]: no method named `submit` found for struct `EspHttpRequestWrite` in the current scope
  --> src/main.rs:55:27
   |
55 |     let response = writer.submit()?;
   |                           ^^^^^^ method not found in `EspHttpRequestWrite<'_>`

For more information about this error, try `rustc --explain E0599`.
warning: `http-client` (bin "http-client") generated 2 warnings
error: could not compile `http-client` due to previous error; 2 warnings emitted

サンプルソースは以下(抜粋;tutorialのままに作成)

use embedded_svc::{
    http::{
        client::{Client, Request, RequestWrite, Response},
        Headers, Status,
    },
    io::Read,
};

fn get(url: impl AsRef<str>) -> anyhow::Result<()> {
    let mut client = EspHttpClient::new_default()?;
    let request = client.get(url.as_ref())?;
    let writer = request.into_writer(0)?;
    let response = writer.submit()?;
    Ok(())
}

Cargo.toml抜粋

[package]
name = "http-client"
version = "0.1.0"
authors = ["Anatol Ulrich <anatol.ulrich@ferrous-systems.com>"]
edition = "2018"
resolver = "2"

EspHttpRequestWriteにメソッドが無いと怒られてるのだが、そもそも、EspHttpRequestWriteの定義が分からない。Gitで探しても見つけられず

Gitのembedded-svcを参照、Requestにsubmitメソッドは存在した。だから、、上位には存在すると。

embedded-svc/client.rs at master · esp-rs/embedded-svc · GitHub

先人のサンプルコード*1

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

        let mut body = [0_u8; 3048];

        let read = io::try_read_full(&mut response, &mut body).map_err(|err| err.0)?;

        info!(
            "Body (truncated to 3K):\n{:?}",
            String::from_utf8_lossy(&body[..read]).into_owned()
        );

        // Complete the response
        while response.read(&mut body)? > 0 {}

        Ok(())
    }

先人のサンプルと、Tutorialのサンプルを参考に以下と書いたらエラーは解消した

fn get(url: impl AsRef<str>) -> anyhow::Result<()> {

    let mut client = EspHttpClient::new_default()?;
    let mut response = client.get(&url)?.submit()?;
    let mut body = [0_u8; 3048];
    let status = response.status();
    let mut total_size = 0;
    println!("response code: {}\n", status);
    Ok(())
}

ビルドできたので以下のコマンドで書き込み、そのままモニタリング

$ cargo espflash --monitor  /dev/ttyACM0

以下の通り、200応答にはなった。

response code: 200

次はbody部の取得か・・・
body部の取得用メソッドがどうやってもコンパイルエラー解消できず一旦断念

■参考URL
esp-idf-svc/http_request.rs at master · esp-rs/esp-idf-svc · GitHub
GitHub - esp-rs/embedded-svc: Rust APIs and abstractions for various embedded services (WiFi, Network, Httpd, Logging, etc.)
ESP HTTP Client - ESP32 - — ESP-IDF Programming Guide latest documentation
esp-idf/esp_http_client_example.c at bb25d6abd3398d0f06fb09fdc9935b791f9344ff · espressif/esp-idf · GitHub

ESP32+Rustでネット接続している例(こちらはちゃんと動いている・・まぁプロの方々だし)
M5PaperでRemo/Remo Eのセンサデータを表示する - Nature Engineering Blog

embedded-svc http client esp32 rust - Google 検索
https://github.com/ivmarkov/rust-esp32-std-demo#flash
ESP-MQTT - ESP32 - — ESP-IDF Programming Guide latest documentation

defaultがnightlyになっているべき??

$ rustup toolchain list
stable-aarch64-unknown-linux-gnu (default)
nightly-2022-03-10-aarch64-unknown-linux-gnu

■追記
Espressifの公式Tutorialを見ているがどうもエラーが解消できず、Gitに置かれたdemoプログラムもエラーが出る。根本的な原因は、ライブラリの参照のところがよくわかっておらず、ソースにあるのになぜundefiedになってしまうのか?が分からない。Pythonだったらインすペクトして調べられるけど、Rustでそんなことできるのだろうか。。zennやQiita等には、Espressifでない人がESP32+Rustで動かしている例があるようなので、そちらを見ながらサンプルを動かすことにする。
Rust (std) on ESP32-C3 で OSC からシリアル LED (WS2812 / SK6812) を動かす

■追記
以下は正常にビルド、動作した

// https://github.com/ivmarkov/rust-esp32-std-demo

git clone https://github.com/ivmarkov/rust-esp32-std-demo
rustup install nightly

export RUST_ESP32_STD_DEMO_WIFI_SSID=xxxxxx
export RUST_ESP32_STD_DEMO_WIFI_PASS=yyyyy

cargo build --target riscv32imc-esp-espidf

espflash /dev/ttyACM0 target/riscv32imc-esp-espidf/debug/rust-esp32-std-demo
espflash serial-monitor /dev/ttyACM0

うまく行った時の設定等

$ rustup show
Default host: aarch64-unknown-linux-gnu
rustup home:  /home/sumi/.rustup

installed toolchains
--------------------

stable-aarch64-unknown-linux-gnu
nightly-2022-03-10-aarch64-unknown-linux-gnu
nightly-aarch64-unknown-linux-gnu (default)
esp

active toolchain
----------------

nightly-aarch64-unknown-linux-gnu (default)
rustc 1.69.0-nightly (5b8f28453 2023-02-12)


file: config.toml 
[build]
target = "xtensa-esp32-espidf"

[target.xtensa-esp32-espidf]
linker = "ldproxy"

[target.xtensa-esp32s2-espidf]
linker = "ldproxy"

[target.xtensa-esp32s3-espidf]
linker = "ldproxy"

[target.riscv32imc-esp-espidf]
linker = "ldproxy"
rustflags = ["-C", "default-linker-libraries"]

[unstable]
build-std = ["std", "panic_abort"]

[env]
ESP_IDF_VERSION = "release/v4.4"
ESP_IDF_SDKCONFIG_DEFAULTS = "sdkconfig.defaults;sdkconfig.defaults.esp32;sdkconfig.defaults.esp32s2"

バイナリのサイズを確認

sumi@sumi:~/lang/rust/tutorial/rust-esp32-std-demo$ size target/riscv32imc-esp-espidf/release/rust-esp32-std-demo
   text	   data	    bss	    dec	    hex	filename
1178686	 288400	1195338	2662424	 28a018	target/riscv32imc-esp-espidf/release/rust-esp32-std-demo
sumi@sumi:~/lang/rust/tutorial/rust-esp32-std-demo$ size target/riscv32imc-esp-espidf/debug/rust-esp32-std-demo
   text	   data	    bss	    dec	    hex	filename
1295394	 439472	1326410	3061276	 2eb61c	target/riscv32imc-esp-espidf/debug/rust-esp32-std-demo

WSL上のUbuntuは以下でビルド(リソース不足なのか途中で止まるのだが)

rustup install nightly 
cargo install ldproxy
git clone https://github.com/ivmarkov/rust-esp32-std-demo
cd rust-esp32-std-demo
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
cargo build --target riscv32imc-esp-espidf