factory: no std

This commit is contained in:
irriden
2023-10-21 01:28:28 +00:00
parent 0c0b59789b
commit 9773e4bec2
18 changed files with 1735 additions and 308 deletions

29
factory/src/colors.rs Normal file
View File

@@ -0,0 +1,29 @@
pub(crate) struct RGB {
pub(crate) r: u8,
pub(crate) g: u8,
pub(crate) b: u8,
}
pub(crate) const BLUE: RGB = RGB {
r: 00,
g: 00,
b: 255,
};
pub(crate) const GREEN: RGB = RGB {
r: 00,
g: 255,
b: 00,
};
pub(crate) const ORANGE: RGB = RGB {
r: 255,
g: 55,
b: 00,
};
pub(crate) const WHITE: RGB = RGB {
r: 255,
g: 255,
b: 255,
};

View File

@@ -1,47 +1,54 @@
use esp_idf_hal::delay::Ets;
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::rmt::config::TransmitConfig;
use esp_idf_hal::rmt::*;
use std::time::Duration;
use crate::{colors::*, FactoryError};
use core::time::Duration;
use esp_idf_svc::hal::{
delay::FreeRtos,
gpio::Gpio0,
rmt::{config::TransmitConfig, FixedLengthSignal, PinState, Pulse, TxRmtDriver, CHANNEL0},
sys::EspError,
};
pub fn set_ota_led() -> anyhow::Result<()> {
let peripherals = Peripherals::take().unwrap();
let led = peripherals.pins.gpio0;
let channel = peripherals.rmt.channel0;
pub(crate) struct Peripherals {
pub led: Gpio0,
pub channel: CHANNEL0,
}
pub(crate) fn setup(peripherals: Peripherals) -> Result<TxRmtDriver<'static>, FactoryError> {
let led = peripherals.led;
let channel = peripherals.channel;
let config = TransmitConfig::new().clock_divider(1);
let mut tx = TxRmtDriver::new(channel, led, &config).unwrap();
let tx = TxRmtDriver::new(channel, led, &config).map_err(|e| FactoryError::EspError(e))?;
Ok(tx)
}
neopixel(
RGB {
r: 255,
g: 55,
b: 00,
},
&mut tx,
)?;
pub(crate) fn setup_complete(led_tx: &mut TxRmtDriver) -> Result<(), FactoryError> {
neopixel(BLUE, led_tx).map_err(|e| FactoryError::EspError(e))?;
FreeRtos::delay_ms(10);
Ok(())
}
struct RGB {
r: u8,
g: u8,
b: u8,
pub(crate) fn update_launch(led_tx: &mut TxRmtDriver) -> Result<(), FactoryError> {
neopixel(ORANGE, led_tx).map_err(|e| FactoryError::EspError(e))?;
FreeRtos::delay_ms(10);
Ok(())
}
pub(crate) fn update_complete(led_tx: &mut TxRmtDriver) -> Result<(), FactoryError> {
neopixel(GREEN, led_tx).map_err(|e| FactoryError::EspError(e))?;
FreeRtos::delay_ms(10);
Ok(())
}
pub(crate) fn main_app_launch(led_tx: &mut TxRmtDriver) -> Result<(), FactoryError> {
neopixel(WHITE, led_tx).map_err(|e| FactoryError::EspError(e))?;
FreeRtos::delay_ms(10);
Ok(())
}
fn ns(nanos: u64) -> Duration {
Duration::from_nanos(nanos)
}
fn rotate_rgb(rgb: u32) -> u32 {
let b_mask: u32 = 0xff;
let blue = (rgb & b_mask) << 16;
blue | (rgb >> 8)
}
fn neopixel(rgb: RGB, tx: &mut TxRmtDriver) -> anyhow::Result<()> {
fn neopixel(rgb: RGB, tx: &mut TxRmtDriver) -> Result<(), EspError> {
// e.g. rgb: (1,2,4)
// G R B
// 7 0 7 0 7 0

View File

@@ -1,37 +1,68 @@
#![no_std]
#![no_main]
mod colors;
mod led;
mod ota;
mod sdcard;
use crate::led::set_ota_led;
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();
use embedded_sdmmc::{Error, SdCardError};
use esp_idf_svc::{
hal::{delay::FreeRtos, prelude::Peripherals},
sys::EspError,
};
use esp_println::println;
thread::sleep(Duration::from_secs(10));
set_ota_led();
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() };
#[derive(Debug)]
pub(crate) enum FactoryError {
SdCardError(Error<SdCardError>),
OtaError(EspError),
EspError(EspError),
}
#[no_mangle]
fn main() -> Result<(), FactoryError> {
esp_idf_svc::sys::link_patches();
println!("Launcher started");
let (sd_card_peripherals, led_peripherals) = assign_peripherals()?;
println!("Assigned peripherals");
let mut manager = sdcard::setup(sd_card_peripherals)?;
println!("Setup sdcard");
let mut led_tx = led::setup(led_peripherals)?;
println!("Setup led");
led::setup_complete(&mut led_tx)?; // BLUE
println!("Setup complete");
FreeRtos::delay_ms(5000u32);
if ota::update_present(&mut manager)? {
led::update_launch(&mut led_tx)?; // ORANGE
println!("Update present, proceeding with update");
ota::write_update(&mut manager)?;
led::update_complete(&mut led_tx)?; // GREEN
println!("Update finished, restarting the chip");
} else {
println!("No update present, setting boot to main app");
ota::set_boot_main_app()?;
led::main_app_launch(&mut led_tx)?; // WHITE
println!("Boot set to main app");
}
println!("Restarting esp");
FreeRtos::delay_ms(5000u32);
unsafe { esp_idf_svc::sys::esp_restart() };
}
fn assign_peripherals() -> Result<(sdcard::Peripherals, led::Peripherals), FactoryError> {
// this function here must be called only once
let peripherals = Peripherals::take().map_err(|e| FactoryError::EspError(e))?;
let sd_card_peripherals = sdcard::Peripherals {
spi: peripherals.spi2,
sck: peripherals.pins.gpio6,
mosi: peripherals.pins.gpio7,
miso: peripherals.pins.gpio2,
cs: peripherals.pins.gpio10,
};
let led_peripherals = led::Peripherals {
led: peripherals.pins.gpio0,
channel: peripherals.rmt.channel0,
};
Ok((sd_card_peripherals, led_peripherals))
}

View File

@@ -1,51 +1,69 @@
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;
use crate::sdcard::Manager;
use crate::FactoryError;
use core::ptr;
use embedded_sdmmc::{Error::FileNotFound, Mode, VolumeIdx};
use esp_idf_svc::{
ota::EspOta,
sys::{esp, esp_ota_get_next_update_partition, esp_ota_set_boot_partition},
};
pub const UPDATE_BIN_PATH: &str = "/sdcard/update.bin";
const FILE: &str = "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);
pub(crate) fn update_present(volume_mgr: &mut Manager) -> Result<bool, FactoryError> {
let volume0 = volume_mgr
.get_volume(VolumeIdx(0))
.map_err(|e| FactoryError::SdCardError(e))?;
let root_dir = volume_mgr
.open_root_dir(&volume0)
.map_err(|e| FactoryError::SdCardError(e))?;
let ret = match volume_mgr.find_directory_entry(&volume0, &root_dir, FILE) {
Ok(_) => Ok(true),
Err(FileNotFound) => Ok(false),
Err(e) => Err(FactoryError::SdCardError(e)),
};
volume_mgr.close_dir(&volume0, root_dir);
ret
}
let mut ota = EspOta::new()?;
let mut ota = ota.initiate_update()?;
pub(crate) fn write_update(volume_mgr: &mut Manager) -> Result<(), FactoryError> {
let mut volume0 = volume_mgr
.get_volume(VolumeIdx(0))
.map_err(|e| FactoryError::SdCardError(e))?;
let root_dir = volume_mgr
.open_root_dir(&volume0)
.map_err(|e| FactoryError::SdCardError(e))?;
let mut my_file = volume_mgr
.open_file_in_dir(&mut volume0, &root_dir, FILE, Mode::ReadOnly)
.map_err(|e| FactoryError::SdCardError(e))?;
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);
}
let mut ota = EspOta::new().map_err(|e| FactoryError::OtaError(e))?;
let mut ota = ota
.initiate_update()
.map_err(|e| FactoryError::OtaError(e))?;
let mut buffer = [0u8; BUFFER_LEN];
while !my_file.eof() {
let r = volume_mgr
.read(&volume0, &mut my_file, &mut buffer)
.map_err(|e| FactoryError::SdCardError(e))?;
ota.write(&buffer[..r])
.map_err(|e| FactoryError::OtaError(e))?;
}
info!("TOTAL read: {}", read_tot);
info!("TOTAL write: {}", write_tot);
ota.complete()?;
ota.complete().map_err(|e| FactoryError::OtaError(e))?;
volume_mgr
.close_file(&volume0, my_file)
.map_err(|e| FactoryError::SdCardError(e))?;
volume_mgr.close_dir(&volume0, root_dir);
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...");
pub(crate) fn set_boot_main_app() -> Result<(), FactoryError> {
esp!(unsafe {
let partition = esp_ota_get_next_update_partition(ptr::null());
esp_ota_set_boot_partition(partition)
})
.map_err(|e| FactoryError::OtaError(e))
}

View File

@@ -1,139 +1,59 @@
use bitflags::bitflags;
use core::ffi::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 crate::FactoryError;
use embedded_sdmmc::{SdCard, TimeSource, Timestamp, VolumeManager};
use esp_idf_svc::hal::{
delay::Ets,
gpio::{Gpio10, Gpio2, Gpio6, Gpio7, Output, PinDriver},
spi::{
config::{DriverConfig, Duplex},
SpiConfig, SpiDeviceDriver, SpiDriver, SPI2,
},
units::FromValueType,
};
use std::ptr;
use std::thread;
use std::time::Duration;
const C_MOUNT_POINT: &'static [u8] = b"/sdcard\0";
pub(crate) type Manager<'a> = VolumeManager<
SdCard<SpiDeviceDriver<'a, SpiDriver<'a>>, PinDriver<'a, Gpio10, Output>, Ets>,
SdMmcClock,
>;
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;
}
pub(crate) struct Peripherals {
pub spi: SPI2,
pub sck: Gpio6,
pub mosi: Gpio7,
pub miso: Gpio2,
pub cs: Gpio10,
}
#[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,
}
pub(crate) struct SdMmcClock;
#[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,
disk_status_check_enable: false,
};
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));
impl TimeSource for SdMmcClock {
fn get_timestamp(&self) -> Timestamp {
Timestamp {
year_since_1970: 0,
zero_indexed_month: 0,
zero_indexed_day: 0,
hours: 0,
minutes: 0,
seconds: 0,
}
}
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(())
}
pub(crate) fn setup(peripherals: Peripherals) -> Result<Manager<'static>, FactoryError> {
let driver = SpiDriver::new(
peripherals.spi,
peripherals.sck,
peripherals.mosi,
Some(peripherals.miso),
&DriverConfig::default(),
)
.map_err(|e| FactoryError::EspError(e))?;
let mut spi_config = SpiConfig::new();
spi_config.duplex = Duplex::Full;
spi_config = spi_config.baudrate(24.MHz().into());
let spi = SpiDeviceDriver::new(driver, Option::<Gpio10>::None, &spi_config)
.map_err(|e| FactoryError::EspError(e))?;
let sdmmc_cs = PinDriver::output(peripherals.cs).map_err(|e| FactoryError::EspError(e))?;
let sdcard = SdCard::new(spi, sdmmc_cs, Ets {});
let volume_mgr = VolumeManager::new(sdcard, SdMmcClock {});
Ok(volume_mgr)
}