Announcing a new Rust-based crate bringing WiFi to RP2040 Series Microcontrollers
Introducing the ESP32-WROOM-RP crate
The Rust Never Sleeps open source community1 is pleased to announce a Rust-based driver crate that provides WiFi functionality to RP2040 series microcontrollers via Espressif ESP32-WROOM-32U/UE WiFi co-processor boards. Most ESP32 controllers that support Arduino’s NINA-W102 firmware should function with this crate, although not all have been tested.
This means consumers of the crate can now connect many different RP2040 boards to a WiFi network and communicate over the internet using Rust! Example uses include remote-sensing, edge-processing, robotics, integration into cloud systems, etc.
A little history
A year ago, our project team began designing an embedded system to aggregate environmental and atmospheric data to a cloud-based application we call Ambi. We began with two primary use cases in mind:
Sample environmental characteristics around an embedded sensing device so that users can monitor ambient air conditions in their homes, at work, etc.
Sample altitude, pressure, and other aviation related data so that paraglider pilots can make inferences about their in-air local flying conditions.
An early identified requirement of the embedded system was to be able to transport data generated on the device to other systems. For example, being able to send aggregated device data over the internet to a cloud-based web application that can present our visual model with a meaningful frontend.
We also wanted the system to be entirely written in Rust as a great way of learning embedded development using Rust.
In our design explorations, we chose the Raspberry PI Pico as our primary reference processing board, along with a BME280 atmospheric sensing board, and Adafruit’s ESP32 Airlift as our reference WiFi co-processor board. We were able to use an existing Rust driver for the BME280, but quickly realized that Rust lacked a driver for communicating with ESP32 WiFi co-processor boards. And we determined that this was an excellent opportunity both to learn and to make a contribution to the Rust ecosystem by creating this driver ourselves. One year later, we are proud to introduce ESP32-WROOM-RP v0.3.1 for general release to the greater embedded Rust community.
What can you do with the crate?
As of v0.3.1 users of the crate can:
Perform DNS lookup given a hostname and the IP of a known DNS server
Connect to a known TCP server given a hostname (performs DNS lookup under the hood)
Here’s an example of how you can utilize these features to send an HTTP request over the internet from your RP2040 microcontroller to a remote HTTP server. You can find the full example here.
let mut wifi = Wifi::init(spi_device, esp_pins, &mut delay).unwrap();
let result = wifi.join(SSID, PASSPHRASE);
let mut sleep: u32 = 1500;
loop {
match wifi.get_connection_status() {
Ok(status) => {
if status == ConnectionStatus::Connected {
// The IPAddresses of two DNS servers to resolve hostnames with.
let ip1: IpAddress = [9, 9, 9, 9];
let ip2: IpAddress = [8, 8, 8, 8];
let dns_result = wifi.set_dns(ip1, Some(ip2));
defmt::info!("set_dns result: {:?}", dns_result);
let hostname = "github.com";
// let ip_address: IpAddress = [140, 82, 114, 3]; // github.com
let port: Port = 80;
let mode: TransportMode = TransportMode::Tcp;
let mut http_document: String<MAX_HTTP_DOC_LENGTH> = String::from("");
// write!(http_document, "GET / HTTP/1.1\r\nHost: {}.{}.{}.{}:{}\r\nAccept: */*\r\n\r\n",
// ip_address[0],
// ip_address[1],
// ip_address[2],
// ip_address[3],
// port
// ).ok().unwrap();
write!(
http_document,
"GET / HTTP/1.1\r\nHost: {}:{}\r\nAccept: */*\r\n\r\n",
hostname, port
)
.ok()
.unwrap();
if let Err(e) = TcpClient::build(&mut wifi).connect(
hostname,
port,
mode,
&mut delay,
&mut |tcp_client| {
hostname,
port
);
match tcp_client.send_data(&http_document) {
Ok(response) => {
defmt::info!("Response: {:?}", response)
}
Err(e) => {
defmt::error!("Response error: {:?}", e)
}
}
},
) {
defmt::error!(
"TCP connection to {:?}:{:?} failed: {:?}",
hostname,
port,
e
);
}
delay.delay_ms(100);
wifi.leave().ok();
} else if status == ConnectionStatus::Disconnected {
sleep = 20000; // No need to loop as often after disconnecting
}
}
Err(e) => {
defmt::error!("Failed to get connection result: {:?}", e);
}
}
}
What’s next?
Development of new features marches onward as we continually add new features and improve the ergonomics of the crate’s exposed API. We are in the process of improving its documentation and working to provide easy and fun ways to contribute to the project.
Checkout our v0.4.0 Milestone to get a detailed view of what’s coming down the pipeline in our next release.
Note that our ultimate goal is to support all NINA Firmware functionality.
Call to action
Please let us know what you think!
How can we improve the crate?
What new features should we prioritize that are important to your use case?
Please join us in this project and our community! You can find us in Slack or in GitHub Discussions.
How to get involved
Come help us further build this crate and other related Rust projects in a fun and relationally-safe environment focused on learning, supporting each other, and contributing to the Rust ecosystem.
We use GitHub Issues to track our roadmap and all suggested improvements or defects that come up. Please feel welcomed and encouraged to open a new issue or to pick one up and open a PR! We are passionate about supporting users and contributors alike. Lastly, we’re happy to talk through any issue you might be interested in contributing to, providing you confidence to provide meaningful contributions.
Please check out our home base on GitHub at Rust Never Sleeps for more details on how to get involved in the community.
1 The Rust Never Sleeps open source community is proudly hosted by Jim Hodapp Coaching, Inc.