mirror of
https://github.com/stakwork/sphinx-key.git
synced 2026-01-31 13:24:54 +01:00
factory: init, writes upgrades from sd card to flash and sets up ESP to boot newly written app
This commit is contained in:
@@ -8,6 +8,7 @@ members = [
|
||||
|
||||
exclude = [
|
||||
"broker",
|
||||
"factory",
|
||||
"persister",
|
||||
"sphinx-key",
|
||||
]
|
||||
|
||||
34
factory/.cargo/config.toml
Normal file
34
factory/.cargo/config.toml
Normal file
@@ -0,0 +1,34 @@
|
||||
[build]
|
||||
# Uncomment the relevant target for your chip here (ESP32, ESP32-S2, ESP32-S3 or ESP32-C3)
|
||||
#target = "xtensa-esp32-espidf"
|
||||
#target = "xtensa-esp32s2-espidf"
|
||||
#target = "xtensa-esp32s3-espidf"
|
||||
target = "riscv32imc-esp-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"
|
||||
|
||||
# Future - necessary for the experimental "native build" of esp-idf-sys with ESP32C3
|
||||
# See also https://github.com/ivmarkov/embuild/issues/16
|
||||
rustflags = ["-C", "default-linker-libraries"]
|
||||
|
||||
[unstable]
|
||||
|
||||
build-std = ["std", "panic_abort"]
|
||||
build-std-features = ["panic_immediate_abort"] # Required for older ESP-IDF versions without a realpath implementation
|
||||
|
||||
[env]
|
||||
# Note: these variables are not used when using pio builder
|
||||
# Enables the esp-idf-sys "native" build feature (`cargo build --features native`) to build against ESP-IDF stable (v4.4)
|
||||
ESP_IDF_VERSION = { value = "release/v4.4" }
|
||||
# Enables the esp-idf-sys "native" build feature (`cargo build --features native`) to build against ESP-IDF master (mainline)
|
||||
#ESP_IDF_VERSION = { value = "master" }
|
||||
26
factory/Cargo.toml
Normal file
26
factory/Cargo.toml
Normal file
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "sphinx-key-factory"
|
||||
version = "0.1.0"
|
||||
authors = ["decentclock <decentclock.5uh2k@slmail.me>"]
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
pio = ["esp-idf-sys/pio"]
|
||||
|
||||
[dependencies]
|
||||
esp-idf-sys = { version = "0.31.8", features = ["binstart"] }
|
||||
esp-idf-svc = { version = "0.42.3", features = ["experimental", "alloc"] }
|
||||
esp-idf-hal = "0.38.1"
|
||||
embedded-hal = "0.2.7"
|
||||
embedded-svc = "0.22.1"
|
||||
anyhow = { version = "1.0.65", features = ["backtrace"] }
|
||||
rand = "0.8.5"
|
||||
log = "0.4.17"
|
||||
bitflags = "1.3.2"
|
||||
|
||||
[build-dependencies]
|
||||
embuild = "0.29"
|
||||
anyhow = "1"
|
||||
|
||||
[package.metadata.espflash]
|
||||
partition_table = "table.csv"
|
||||
14
factory/README.md
Normal file
14
factory/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Sphinx Key Factory App
|
||||
|
||||
The main function of this app is to write any `update.bin` files from the sd card to the flash of the ESP, and configure the ESP so that on the next boot, it boots the freshly written app.
|
||||
|
||||
## Background Reading
|
||||
|
||||
- Partition Tables: https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-guides/partition-tables.html
|
||||
- Over-the-Air Updates: https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/system/ota.html
|
||||
|
||||
## Flashing factory and sphinx-key
|
||||
|
||||
- First flash the factory app here using the usual `espflash` command, but add the `--partition-table` flag and point it to `table.csv` here. See `espflash -h` for more info.
|
||||
- Then use `esptool.py` to flash the sphinx-key binary at offset `0xc0000`.
|
||||
- Finally use this command to tell the ESP to boot the sphinx-key binary first ( there is no update to write to the ESP yet, so we don't boot the factory app ): `otatool.py switch_ota_partition --slot 0`
|
||||
5
factory/build.rs
Normal file
5
factory/build.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// Necessary because of this issue: https://github.com/rust-lang/cargo/issues/9641
|
||||
fn main() -> anyhow::Result<()> {
|
||||
embuild::build::CfgArgs::output_propagated("ESP_IDF")?;
|
||||
embuild::build::LinkArgs::output_propagated("ESP_IDF")
|
||||
}
|
||||
2
factory/rust-toolchain.toml
Normal file
2
factory/rust-toolchain.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
11
factory/sdkconfig.defaults
Normal file
11
factory/sdkconfig.defaults
Normal file
@@ -0,0 +1,11 @@
|
||||
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=64000
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
|
||||
# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
|
||||
# This allows to use 1 ms granuality for thread sleeps (10 ms by default).
|
||||
#CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
# Workaround for https://github.com/espressif/esp-idf/issues/7631
|
||||
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n
|
||||
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n
|
||||
34
factory/src/main.rs
Normal file
34
factory/src/main.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
mod ota;
|
||||
mod sdcard;
|
||||
use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
|
||||
use log::{error, info, warn};
|
||||
use ota::{run_sdcard_ota_update, set_boot_main_app, UPDATE_BIN_PATH};
|
||||
use std::path::Path;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
// Temporary. Will disappear once ESP-IDF 4.4 is released, but for now it is necessary to call this function once,
|
||||
// or else some patches to the runtime implemented by esp-idf-sys might not link properly.
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
esp_idf_sys::link_patches();
|
||||
|
||||
thread::sleep(Duration::from_secs(10));
|
||||
info!("Hello, world! Mounting sd card...");
|
||||
sdcard::mount_sd_card();
|
||||
info!("SD card mounted! Checking for update...");
|
||||
if let Ok(true) = Path::new(UPDATE_BIN_PATH).try_exists() {
|
||||
info!("Found update.bin file! Launching the update process...");
|
||||
while let Err(e) = run_sdcard_ota_update() {
|
||||
error!("OTA update failed: {}", e.to_string());
|
||||
error!("Trying again...");
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
}
|
||||
info!("OTA update complete!");
|
||||
} else {
|
||||
warn!("Update file not found! Setting up main app boot...");
|
||||
set_boot_main_app();
|
||||
}
|
||||
info!("Restarting ESP, booting the main app...");
|
||||
unsafe { esp_idf_sys::esp_restart() };
|
||||
}
|
||||
51
factory/src/ota.rs
Normal file
51
factory/src/ota.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use anyhow::Result;
|
||||
use embedded_svc::io::Write;
|
||||
use embedded_svc::ota::Ota;
|
||||
use embedded_svc::ota::OtaUpdate;
|
||||
use esp_idf_svc::ota::EspOta;
|
||||
use esp_idf_sys::{esp, esp_ota_get_next_update_partition, esp_ota_set_boot_partition};
|
||||
use log::info;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::io::Read;
|
||||
use std::ptr;
|
||||
|
||||
pub const UPDATE_BIN_PATH: &str = "/sdcard/update.bin";
|
||||
const BUFFER_LEN: usize = 1024;
|
||||
|
||||
pub fn run_sdcard_ota_update() -> Result<()> {
|
||||
let f = File::open(UPDATE_BIN_PATH)?;
|
||||
let mut reader = BufReader::with_capacity(BUFFER_LEN, f);
|
||||
|
||||
let mut ota = EspOta::new()?;
|
||||
let mut ota = ota.initiate_update()?;
|
||||
|
||||
let mut buf = [0_u8; BUFFER_LEN];
|
||||
let mut read_tot: usize = 0;
|
||||
let mut write_tot: usize = 0;
|
||||
let mut i = 0;
|
||||
loop {
|
||||
let r = reader.read(&mut buf)?;
|
||||
if r == 0 {
|
||||
break;
|
||||
}
|
||||
let w = ota.write(&buf[..r])?;
|
||||
read_tot += r;
|
||||
write_tot += w;
|
||||
i += 1;
|
||||
if i % 20 == 0 {
|
||||
info!("Cumulative bytes read: {}", read_tot);
|
||||
info!("Cumulative bytes written: {}", write_tot);
|
||||
}
|
||||
}
|
||||
info!("TOTAL read: {}", read_tot);
|
||||
info!("TOTAL write: {}", write_tot);
|
||||
ota.complete()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_boot_main_app() {
|
||||
let partition = unsafe { esp_ota_get_next_update_partition(ptr::null()) };
|
||||
esp!(unsafe { esp_ota_set_boot_partition(partition) })
|
||||
.expect("Couldn't set next boot partition...");
|
||||
}
|
||||
138
factory/src/sdcard.rs
Normal file
138
factory/src/sdcard.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
use bitflags::bitflags;
|
||||
use esp_idf_sys::c_types::c_char;
|
||||
use esp_idf_sys::{
|
||||
esp, esp_vfs_fat_sdmmc_mount_config_t, esp_vfs_fat_sdspi_mount, gpio_num_t, sdmmc_card_t,
|
||||
sdmmc_host_t, sdspi_device_config_t, spi_bus_config_t, spi_bus_initialize, spi_host_device_t,
|
||||
spi_host_device_t_SPI2_HOST,
|
||||
};
|
||||
use std::ptr;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
const C_MOUNT_POINT: &'static [u8] = b"/sdcard\0";
|
||||
|
||||
const SPI_HOST_SLOT: spi_host_device_t = spi_host_device_t_SPI2_HOST;
|
||||
const SPI_GPIO_MOSI: gpio_num_t = 7;
|
||||
const SPI_GPIO_CLK: gpio_num_t = 6;
|
||||
const SPI_GPIO_MISO: gpio_num_t = 2;
|
||||
const SPI_GPIO_CS: gpio_num_t = 10;
|
||||
|
||||
bitflags! {
|
||||
struct SDMMCHostFlag: u32 {
|
||||
/// host supports 1-line SD and MMC protocol
|
||||
const BIT1 = 1 << 0;
|
||||
/// host supports 4-line SD and MMC protocol
|
||||
const BIT4 = 1 << 1;
|
||||
/// host supports 8-line MMC protocol
|
||||
const BIT8 = 1 << 2;
|
||||
/// host supports SPI protocol
|
||||
const SPI = 1 << 3;
|
||||
/// host supports DDR mode for SD/MMC
|
||||
const DDR = 1 << 4;
|
||||
/// host `deinit` function called with the slot argument
|
||||
const DEINIT_ARG = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum SDMMCFreq {
|
||||
/// SD/MMC Default speed (limited by clock divider)
|
||||
Default = 20000,
|
||||
/// SD High speed (limited by clock divider)
|
||||
HighSPeed = 40000,
|
||||
/// SD/MMC probing speed
|
||||
Probing = 400,
|
||||
/// MMC 52MHz speed
|
||||
_52M = 52000,
|
||||
/// MMC 26MHz speed
|
||||
_26M = 26000,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn mount_sd_card() {
|
||||
while let Err(e) = setup() {
|
||||
println!("Failed to mount sd card. Make sure it is connected, trying again...");
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
}
|
||||
}
|
||||
|
||||
fn setup() -> anyhow::Result<()> {
|
||||
let mount_config = esp_vfs_fat_sdmmc_mount_config_t {
|
||||
format_if_mount_failed: false,
|
||||
max_files: 5,
|
||||
allocation_unit_size: 16 * 1024,
|
||||
};
|
||||
|
||||
let mut card: *mut sdmmc_card_t = ptr::null_mut();
|
||||
|
||||
let bus_cfg = spi_bus_config_t {
|
||||
__bindgen_anon_1: esp_idf_sys::spi_bus_config_t__bindgen_ty_1 {
|
||||
mosi_io_num: SPI_GPIO_MOSI,
|
||||
},
|
||||
__bindgen_anon_2: esp_idf_sys::spi_bus_config_t__bindgen_ty_2 {
|
||||
miso_io_num: SPI_GPIO_MISO,
|
||||
},
|
||||
sclk_io_num: SPI_GPIO_CLK,
|
||||
__bindgen_anon_3: esp_idf_sys::spi_bus_config_t__bindgen_ty_3 { quadwp_io_num: -1 },
|
||||
__bindgen_anon_4: esp_idf_sys::spi_bus_config_t__bindgen_ty_4 { quadhd_io_num: -1 },
|
||||
data4_io_num: -1,
|
||||
data5_io_num: -1,
|
||||
data6_io_num: -1,
|
||||
data7_io_num: -1,
|
||||
max_transfer_sz: 4000,
|
||||
flags: 0,
|
||||
intr_flags: 0,
|
||||
};
|
||||
|
||||
if let Err(error) = esp!(unsafe {
|
||||
spi_bus_initialize(
|
||||
SPI_HOST_SLOT as u32,
|
||||
&bus_cfg,
|
||||
esp_idf_sys::spi_common_dma_t_SPI_DMA_CH_AUTO,
|
||||
)
|
||||
}) {
|
||||
if error.code() != 259 {
|
||||
return Err(anyhow::Error::new(error));
|
||||
}
|
||||
}
|
||||
|
||||
println!("Initialized SPI BUS!");
|
||||
|
||||
let slot_config = sdspi_device_config_t {
|
||||
host_id: SPI_HOST_SLOT,
|
||||
gpio_cs: SPI_GPIO_CS,
|
||||
gpio_cd: -1,
|
||||
gpio_wp: -1,
|
||||
gpio_int: -1,
|
||||
};
|
||||
|
||||
let host = sdmmc_host_t {
|
||||
flags: (SDMMCHostFlag::SPI | SDMMCHostFlag::DEINIT_ARG).bits, //SDMMC_HOST_FLAG_SPI | SDMMC_HOST_FLAG_DEINIT_ARG,
|
||||
slot: SPI_HOST_SLOT as i32,
|
||||
max_freq_khz: SDMMCFreq::Default as i32, //SDMMC_FREQ_DEFAULT,
|
||||
io_voltage: 3.3f32,
|
||||
init: Some(esp_idf_sys::sdspi_host_init),
|
||||
set_bus_width: None,
|
||||
get_bus_width: None,
|
||||
set_bus_ddr_mode: None,
|
||||
set_card_clk: Some(esp_idf_sys::sdspi_host_set_card_clk),
|
||||
do_transaction: Some(esp_idf_sys::sdspi_host_do_transaction),
|
||||
__bindgen_anon_1: esp_idf_sys::sdmmc_host_t__bindgen_ty_1 {
|
||||
deinit_p: Some(esp_idf_sys::sdspi_host_remove_device),
|
||||
},
|
||||
io_int_enable: Some(esp_idf_sys::sdspi_host_io_int_enable),
|
||||
io_int_wait: Some(esp_idf_sys::sdspi_host_io_int_wait),
|
||||
command_timeout_ms: 0,
|
||||
};
|
||||
|
||||
esp!(unsafe {
|
||||
esp_vfs_fat_sdspi_mount(
|
||||
C_MOUNT_POINT.as_ptr() as *const c_char,
|
||||
&host,
|
||||
&slot_config,
|
||||
&mount_config,
|
||||
&mut card as *mut *mut sdmmc_card_t,
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
7
factory/table.csv
Normal file
7
factory/table.csv
Normal file
@@ -0,0 +1,7 @@
|
||||
# ESP-IDF Partition Table
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x4000,
|
||||
otadata, data, ota, 0xd000, 0x2000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1200K,
|
||||
ota_0, app, ota_0, 0x140000, 2800K,
|
||||
|
Reference in New Issue
Block a user