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
326 stars 182 forks source link

Ethernet to WiFi bridge: where to start? #508

Open FrigoEU opened 1 month ago

FrigoEU commented 1 month ago

Hi,

This isn't an issue but rather a request for a nudge in the right direction. I've made a fairly large application in Rust running on the ESP32. So far it's been fairly smooth sailing. But the next feature I'd like to build is to me quite difficult to get started on.

The situation: my ESP32 will be plugged into Ethernet. When connection is successful (and it's configured as such) it should start a WiFi access point (with pre-configured ssid/password) and allow another device to connect to the WiFi and connect to the internet via the ESP32's Ethernet connection. I feel in theory this should be possible but I've found only very limited information/examples online (especially in the Rust language).

I'd greatly appreciate it if somebody could point me in the right direction to get started on this.

Simon

ivmarkov commented 1 month ago

A quick googling reveals this C ESP IDF example which should be your starting point, and seems to do exactly what you want: https://github.com/espressif/esp-idf/tree/release/v5.2/examples/network/bridge

Informally speaking, how it operates is as follows:

Apparently, this is something new in ESP IDF 5. ESP IDF 4.4 did not support layer-2 bridging, only layer3 IP packet forwarding (which is still supported in the esp-idf-* crates btw)

How to do it in Rust?

Now the non-trivial part: Once the above laborious excercise is done, you need to create - as per the C example - an extra netif, and configure it as a bridge. The configuration currently cannot be 100% done with safe Rust calls, because the ESP IDF bridge APIs are not yet exposed in a safe manner in esp-idf-svc (as in the esp_netif_br_* structs and glue functions). Until this is available in Rust, you can just do it with unsafe calls into esp_idf_svc::sys::*.

Once you have this, I would appreciate if you publish it as I can use it as a template to expose the bridge APIs in a safe way in esp-idf-svc.

The bridge configuration stuff in the example starts from here. All above (ethernet and wifi conf) can be done with safe Rust.

Hope that helps.

FrigoEU commented 4 weeks ago

Hi @ivmarkov ,

This helps so much! I plan to get started on this next week and I'll report my findings. Thank you so much for this, I don't think I would have been able to figure this out in a reasonable time myself. Many thanks!

Simon

ivmarkov commented 4 weeks ago

Np. Actually, since you have one and only one Eth instance, your work would be simpler. Where I said:

Create N (N > 0) EspEth instances (these are a combination of phy (EthDriver) + netif (EspNetif). For their netifs, use a custom NetworkConfiguration, so that you can assign a different netif key and different distance to each ethernet netif. In each ethernet EspEth instance, you need to set the same Ethernet Mac address, as per the example. There is a public API for that, I think, otherwise unsafely call into esp_idf_svc::sys::esp_eth_ioctl as per the example

... the custom network configuration is only necessary if you have multiple eth interfaces, as then each needs to have its own unique key and distance. Since you'll have only one, none of this is necessary.

Only the step where you assign the same MAC address to both your eth and the netif bridge is necessary.

FrigoEU commented 3 weeks ago

Hey @ivmarkov,

I've been getting some work done on and this and have been slowly porting the C code from the example to Rust. However, I got stuck on the last part that uses the esp_netif_brglue* types and structs and functions. I can't seem to find these anywhere on the rust side. Not in esp-idf-svc, nor in esp-idf-sys. Is this just missing for now or am I looking in the wrong place?

FrigoEU commented 2 weeks ago

Hey @ivmarkov,

Just checking if you've already looked at this. I don't have much experience making Rust bindings for C so I'm (for now at least) hoping you can point me in the right direction :P.

Simon

ivmarkov commented 2 weeks ago

@FrigoEU Thanksd for reminding me! I just pushed to esp-idf-sys master a small change that should expose the netif bridge raw bindings you are looking for.

Just make sure to add the following in your Cargo.toml:

[patch.crates-io]
esp-idf-svc = { git = "https://github.com/esp-rs/esp-idf-svc" }
esp-idf-hal = { git = "https://github.com/esp-rs/esp-idf-hal" }
esp-idf-sys = { git = "https://github.com/esp-rs/esp-idf-sys" }
cmake = { git = "https://github.com/ivmarkov/cmake-rs" }
ivmarkov commented 2 weeks ago

And in your sdkconfig.defaults:

CONFIG_ESP_NETIF_TCPIP_LWIP=y
CONFIG_ESP_NETIF_BRIDGE_EN=y

CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=1

... as per the C example.

FrigoEU commented 2 weeks ago

Thank you very much! I'll continue with this next week.

ivmarkov commented 2 weeks ago

You should look for the raw bindings in esp_idf_svc::sys which re-exports esp_idf_sys.