esp-ota

This crate allows easy [OTA updates] for ESP32 chips using only safe Rust. The crate is completely transport agnostic, meaning it does not deal with how you transfer the new app image to the ESP.

Usage

This section will explain how to use esp-ota in an application to write a downloaded app image to the flash and boot from it.

Partition table

The chip must have at least two app, ota_X partitions, so it can boot from one and write the OTA update to the other one. And a data, ota partition to store information about which partition the bootloader should boot from.

Create a file called partitions.csv. You can read more about [ESP partition tables] on espressifs website. But here is a fairly default example that works on a 4M flash: ```csv

Name, Type, SubType, Offset, Size, Flags

nvs, data, nvs, 0x9000, 0x4000, otadata, data, ota, 0xd000, 0x2000, phyinit, data, phy, 0xf000, 0x1000, ota0, app, ota0, 0x10000, 0x180000, ota1, app, ota_1, 0x190000, 0x180000, ```

And tell espflash to use it in Cargo.toml. Read more in the [cargo espflash documentation]: toml [package.metadata.espflash] partition_table = "partitions.csv"

App image format

The app that you want to flash must have the correct format. It should not be the ELF executable produced by a regular cargo build in an ESP project, but rather the ESP32 specific [app image format].

One way to convert your programs into this format is with [esptool.py elf2image]: $ esptool.py --chip ESP32-C3 elf2image --output my-app.bin target/release/my-app

Code

To flash a new app to the next partition on the flash, include code similar to this:

```rust // This is a very unrealistic example. You usually don't store the new app in the // old app. Instead you obtain it by downloading it from somewhere or similar. const NEWAPP: &[u8] = includebytes!("../my-app.bin");

// Finds the next suitable OTA partition and erases it let mut ota = esp_ota::OtaUpdate::begin()?;

// Write the app to flash. Normally you would download // the app and call ota.write every time you have obtained // a part of the app image. This example is not realistic, // since it has the entire new app bundled. for appchunk in NEWAPP.chunks(4096) { ota.write(app_chunk)?; }

// Performs validation of the newly written app image and completes the OTA update. let completed_ota = ota.finalize()?;

// Sets the newly written to partition as the next partition to boot from. completedota.setasbootpartition()?; // Restarts the CPU, booting into the newly written app. completed_ota.restart(); ```

And if [the rollback feature] is enabled, you need to validate that the new app works as intended, or perform a rollback. Read more in the espressif documentation on [app rollback].

rust fn main() { if is_working_as_intended() { esp_ota::mark_app_valid(); } else { esp_ota::rollback_and_reboot().expect("Failed to roll back to working app"); } }