ota is back

This commit is contained in:
2025-10-01 21:56:16 +02:00
parent 9c6dcc465e
commit 27b18df78e
4 changed files with 117 additions and 15 deletions

View File

@@ -20,8 +20,9 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::mutex::{Mutex, MutexGuard}; use embassy_sync::mutex::{Mutex, MutexGuard};
use embassy_sync::once_lock::OnceLock; use embassy_sync::once_lock::OnceLock;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use embedded_storage::nor_flash::ReadNorFlash; use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
use esp_bootloader_esp_idf::ota::{Ota, OtaImageState}; use esp_bootloader_esp_idf::ota::{Ota, OtaImageState};
use esp_bootloader_esp_idf::ota::OtaImageState::Valid;
use esp_bootloader_esp_idf::partitions::FlashRegion; use esp_bootloader_esp_idf::partitions::FlashRegion;
use esp_hal::gpio::{Input, RtcPinWithResistors}; use esp_hal::gpio::{Input, RtcPinWithResistors};
use esp_hal::rng::Rng; use esp_hal::rng::Rng;
@@ -29,6 +30,7 @@ use esp_hal::rtc_cntl::{
sleep::{TimerWakeupSource, WakeupLevel}, sleep::{TimerWakeupSource, WakeupLevel},
Rtc, Rtc,
}; };
use esp_hal::sha::Digest;
use esp_hal::system::software_reset; use esp_hal::system::software_reset;
use esp_println::println; use esp_println::println;
use esp_storage::FlashStorage; use esp_storage::FlashStorage;
@@ -127,7 +129,7 @@ pub struct Esp<'a> {
pub wake_gpio1: esp_hal::peripherals::GPIO1<'static>, pub wake_gpio1: esp_hal::peripherals::GPIO1<'static>,
pub ota: Ota<'static, FlashStorage>, pub ota: Ota<'static, FlashStorage>,
pub ota_next: &'static mut FlashRegion<'static, FlashStorage>, pub ota_next: &'static mut FlashRegion<'static, FlashStorage>
} }
// SAFETY: On this target we never move Esp across OS threads; the firmware runs single-core // SAFETY: On this target we never move Esp across OS threads; the firmware runs single-core
@@ -234,6 +236,28 @@ impl Esp<'_> {
} }
} }
pub(crate) async fn write_ota(
&mut self,
offset: u32,
buf: &[u8],
) -> Result<(), FatError> {
self.ota_next.write(offset, buf)?;
Ok(())
}
pub(crate) async fn finalize_ota(
&mut self,
) -> Result<(), FatError> {
let current_state = self.ota.current_ota_state()?;
let current_slot = self.ota.current_slot()?;
if current_state == OtaImageState::PendingVerify {
self.ota.set_current_ota_state(Valid)?;
}
self.ota.set_current_slot(current_slot.next())?;
self.set_restart_to_conf(true);
Ok(())
}
// let current = ota.current_slot()?; // let current = ota.current_slot()?;
// println!( // println!(
// "current image state {:?} (only relevant if the bootloader was built with auto-rollback support)", // "current image state {:?} (only relevant if the bootloader was built with auto-rollback support)",

View File

@@ -70,14 +70,12 @@ use eeprom24x::{Eeprom24x, SlaveAddr, Storage};
use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::CriticalSectionMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex;
use esp_bootloader_esp_idf::partitions::{ use esp_bootloader_esp_idf::partitions::{AppPartitionSubType, DataPartitionSubType, Error, FlashRegion, PartitionEntry};
AppPartitionSubType, DataPartitionSubType, FlashRegion, PartitionEntry,
};
use esp_hal::clock::CpuClock; use esp_hal::clock::CpuClock;
use esp_hal::gpio::{Input, InputConfig, Pull}; use esp_hal::gpio::{Input, InputConfig, Pull};
use measurements::{Current, Voltage}; use measurements::{Current, Voltage};
use crate::fat_error::{FatError, FatResult}; use crate::fat_error::{ContextExt, FatError, FatResult};
use crate::hal::battery::{print_battery_bq34z100, BQ34Z100G1}; use crate::hal::battery::{print_battery_bq34z100, BQ34Z100G1};
use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem; use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem;
use crate::hal::water::TankSensor; use crate::hal::water::TankSensor;
@@ -87,6 +85,7 @@ use embassy_sync::once_lock::OnceLock;
use esp_alloc as _; use esp_alloc as _;
use esp_backtrace as _; use esp_backtrace as _;
use esp_bootloader_esp_idf::ota::Slot; use esp_bootloader_esp_idf::ota::Slot;
use esp_bootloader_esp_idf::ota::Slot::{Slot0, Slot1};
use esp_hal::delay::Delay; use esp_hal::delay::Delay;
use esp_hal::i2c::master::{BusTimeout, Config, I2c}; use esp_hal::i2c::master::{BusTimeout, Config, I2c};
use esp_hal::pcnt::unit::Unit; use esp_hal::pcnt::unit::Unit;
@@ -323,23 +322,23 @@ impl PlantHal {
let mut ota = esp_bootloader_esp_idf::ota::Ota::new(ota_data)?; let mut ota = esp_bootloader_esp_idf::ota::Ota::new(ota_data)?;
let ota_partition = match ota.current_slot()? { let next_slot = ota.current_slot()?.next();
let ota_next = match next_slot {
Slot::None => { Slot::None => {
panic!("No OTA slot active?"); panic!("No OTA slot active?");
} }
Slot::Slot0 => pt Slot::Slot0 => pt
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App( .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
AppPartitionSubType::Ota0, AppPartitionSubType::Ota0,
))? ))?.context("Partition table invalid no ota0")?,
.expect("No OTA slot0 found"),
Slot::Slot1 => pt Slot::Slot1 => pt
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App( .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
AppPartitionSubType::Ota1, AppPartitionSubType::Ota1,
))? ))?.context("Partition table invalid no ota1")?
.expect("No OTA slot1 found"), ,
}; };
let ota_next = mk_static!(PartitionEntry, ota_partition); let ota_next = mk_static!(PartitionEntry, ota_next);
let storage_ota = mk_static!(FlashStorage, FlashStorage::new()); let storage_ota = mk_static!(FlashStorage, FlashStorage::new());
let ota_next = mk_static!( let ota_next = mk_static!(
FlashRegion<FlashStorage>, FlashRegion<FlashStorage>,
@@ -388,7 +387,7 @@ impl PlantHal {
boot_button, boot_button,
wake_gpio1, wake_gpio1,
ota, ota,
ota_next, ota_next
}; };
//init,reset rtc memory depending on cause //init,reset rtc memory depending on cause
@@ -589,4 +588,4 @@ pub async fn esp_set_time(time: DateTime<FixedOffset>) -> FatResult<()> {
.get_rtc_module() .get_rtc_module()
.set_rtc_time(&time.to_utc()) .set_rtc_time(&time.to_utc())
.await .await
} }

View File

@@ -6,6 +6,7 @@ mod get_json;
mod get_log; mod get_log;
mod get_static; mod get_static;
mod post_json; mod post_json;
mod ota;
use crate::fat_error::{FatError, FatResult}; use crate::fat_error::{FatError, FatResult};
use crate::webserver::backup_manager::{backup_config, backup_info, get_backup_config}; use crate::webserver::backup_manager::{backup_config, backup_info, get_backup_config};
@@ -36,7 +37,7 @@ use embassy_net::Stack;
use embassy_time::Instant; use embassy_time::Instant;
use embedded_io_async::{Read, Write}; use embedded_io_async::{Read, Write};
use log::info; use log::info;
use crate::webserver::ota::ota_operations;
// fn ota( // fn ota(
// request: &mut Request<&mut EspHttpConnection>, // request: &mut Request<&mut EspHttpConnection>,
// ) -> Result<Option<std::string::String>, anyhow::Error> { // ) -> Result<Option<std::string::String>, anyhow::Error> {
@@ -107,6 +108,8 @@ impl Handler for HTTPRequestRouter {
let prefix = "/file?filename="; let prefix = "/file?filename=";
let status = if path.starts_with(prefix) { let status = if path.starts_with(prefix) {
file_operations(conn, method, &path, &prefix).await? file_operations(conn, method, &path, &prefix).await?
} else if path == "/ota" {
ota_operations(conn,method).await?
} else { } else {
match method { match method {
Method::Get => match path { Method::Get => match path {

76
rust/src/webserver/ota.rs Normal file
View File

@@ -0,0 +1,76 @@
use alloc::borrow::ToOwned;
use alloc::format;
use edge_http::io::server::Connection;
use edge_http::Method;
use embedded_io_async::{Read, Write};
use log::info;
use crate::BOARD_ACCESS;
use crate::fat_error::FatError;
pub(crate) async fn ota_operations<T, const N: usize>(
conn: &mut Connection<'_, T, { N }>,
method: Method
) -> Result<Option<u32>, FatError>
where
T: Read + Write,
{
Ok(match method {
Method::Options => {
conn.initiate_response(
200,
Some("OK"),
&[
("Access-Control-Allow-Origin", "*"),
("Access-Control-Allow-Headers", "*"),
("Access-Control-Allow-Methods", "*"),
],
)
.await?;
Some(200)
}
Method::Post => {
let mut offset = 0_usize;
let mut chunk = 0;
loop {
let mut buf = [0_u8; 1024];
let to_write = conn.read(&mut buf).await?;
if to_write == 0 {
info!("file request for ota finished");
let mut board = BOARD_ACCESS.get().await.lock().await;
board.board_hal.get_esp().finalize_ota().await?;
break;
} else {
let mut board = BOARD_ACCESS.get().await.lock().await;
board.board_hal.progress(chunk as u32).await;
board
.board_hal
.get_esp()
.write_ota(offset as u32, &buf[0..to_write])
.await?;
}
offset = offset + to_write;
chunk = chunk + 1;
}
BOARD_ACCESS
.get()
.await
.lock()
.await
.board_hal
.clear_progress()
.await;
conn.initiate_response(
200,
Some("OK"),
&[
("Access-Control-Allow-Origin", "*"),
("Access-Control-Allow-Headers", "*"),
("Access-Control-Allow-Methods", "*"),
],
)
.await?;
Some(200)
}
_ => None,
})
}