sphinx-key: fetch ota update in the main thread

we previously spawned a separate led thread, which caused two problems
1) starved the main thread, preventing any progress on signing
a solution here could have been to sleep the ota fetch thread every so often
2) also increased memory usage
a solution here is much smaller buffer for ota thread

both of these solutions significantly hindered the speed of the ota update

i like much better keeping the ota fetch blocking in the main thread,
and giving it the appropriate resources to perform the ota fetch fast

this commit also only sends a new status into the led_tx-led_rx channel when
necessary - we previously sent new statuses into the channel even if the led
was already at that state
This commit is contained in:
irriden
2023-10-30 23:00:44 +00:00
parent dde34efbdc
commit 616acc868e
2 changed files with 33 additions and 39 deletions

View File

@@ -143,6 +143,7 @@ pub fn make_event_loop(
log::info!("=> starting the main signing loop...");
let flash_db = ctrlr.persister();
let mut expected_sequence = None;
let mut current_status = Status::ConnectingToMqtt;
while let Ok(event) = rx.recv() {
log::info!("new event loop!");
check_memory();
@@ -153,14 +154,14 @@ pub fn make_event_loop(
thread::sleep(std::time::Duration::from_secs(1));
// send the initial HELLO again
mqtt_pub(&mut mqtt, &client_id, topics::HELLO, &[]);
led_tx.send(Status::Connected).unwrap();
current_status = update_led(current_status, Status::Connected, &led_tx);
}
Event::Disconnected => {
led_tx.send(Status::ConnectingToMqtt).unwrap();
current_status = update_led(current_status, Status::ConnectingToMqtt, &led_tx);
log::info!("GOT A Event::Disconnected msg!");
}
Event::VlsMessage(msg_bytes) => {
led_tx.send(Status::Signing).unwrap();
current_status = update_led(current_status, Status::Signing, &led_tx);
let state1 = approver.control().get_state();
//log::info!("FULL MSG {:?}", &msg_bytes);
let _ret = match sphinx_signer::root::handle_with_lss(
@@ -246,18 +247,32 @@ pub fn make_event_loop(
Event::Control(ref msg_bytes) => {
log::info!("GOT A CONTROL MSG");
let cres = ctrlr.handle(msg_bytes);
if let Some(res) =
handle_control_response(&root_handler, &approver, cres, led_tx.clone())
{
let mut bb = ByteBuf::new();
serialize_controlresponse(&mut bb, &res).expect("failed serialize_lssresponse");
mqtt_pub(&mut mqtt, &client_id, topics::CONTROL_RES, bb.as_slice());
let res = handle_control_response(&root_handler, &approver, cres, led_tx.clone());
let mut bb = ByteBuf::new();
serialize_controlresponse(&mut bb, &res).expect("failed serialize_lssresponse");
mqtt_pub(&mut mqtt, &client_id, topics::CONTROL_RES, bb.as_slice());
if let ControlResponse::OtaConfirm(params) = res {
if let Err(e) = update_sphinx_key(params) {
log::error!("OTA update failed {:?}", e.to_string());
} else {
log::info!("OTA flow complete, restarting esp...");
unsafe { esp_idf_svc::sys::esp_restart() };
}
}
}
}
}
}
fn update_led(current: Status, new: Status, led_tx: &mpsc::Sender<Status>) -> Status {
if current != new {
led_tx.send(new).unwrap();
new
} else {
current
}
}
pub(crate) fn restart_esp_if_memory_low() {
unsafe {
let size = esp_idf_svc::sys::heap_caps_get_free_size(4);
@@ -289,7 +304,7 @@ fn handle_control_response(
approver: &SphinxApprover,
cres: anyhow::Result<(ControlMessage, ControlResponse)>,
led_tx: mpsc::Sender<Status>,
) -> Option<ControlResponse> {
) -> ControlResponse {
match cres {
Ok((control_msg, mut control_res)) => {
// the following msg types require other actions besides Flash persistence
@@ -325,30 +340,18 @@ fn handle_control_response(
control_res =
ControlResponse::Error(format!("OTA update cannot launch {:?}", e))
} else {
// A 10kB size stack was consistently overflowing when doing a factory reset
let builder = thread::Builder::new().stack_size(15000usize);
builder
.spawn(move || {
led_tx.send(Status::Ota).unwrap();
if let Err(e) = update_sphinx_key(params, led_tx) {
log::error!("OTA update failed {:?}", e.to_string());
} else {
log::info!("OTA flow complete, restarting esp...");
unsafe { esp_idf_svc::sys::esp_restart() };
}
})
.unwrap();
log::info!("OTA update launched...");
led_tx.send(Status::Ota).unwrap();
log::info!("Launching OTA update...");
}
}
_ => (),
};
Some(control_res)
control_res
}
Err(e) => {
let control_res = ControlResponse::Error(e.to_string());
log::warn!("error parsing ctrl msg {:?}", e);
Some(control_res)
control_res
}
}
}

View File

@@ -1,4 +1,3 @@
use crate::status::Status;
use anyhow::{anyhow, Result};
use esp_idf_svc::http::client::Configuration;
use esp_idf_svc::http::client::EspHttpConnection;
@@ -10,9 +9,8 @@ use sphinx_signer::sphinx_glyph::control::OtaParams;
use std::fs::{remove_file, File};
use std::io::BufWriter;
use std::io::Write;
use std::sync::mpsc;
const BUFFER_LEN: usize = 512;
const BUFFER_LEN: usize = 1024;
const UPDATE_BIN_PATH: &str = "/sdcard/update.bin";
fn factory_reset() -> Result<()> {
@@ -28,7 +26,7 @@ fn factory_reset() -> Result<()> {
}
}
fn get_update(params: OtaParams, led_tx: mpsc::Sender<Status>) -> Result<()> {
fn get_update(params: OtaParams) -> Result<()> {
let configuration = Configuration {
buffer_size: Some(BUFFER_LEN),
buffer_size_tx: Some(BUFFER_LEN / 3),
@@ -49,7 +47,6 @@ fn get_update(params: OtaParams, led_tx: mpsc::Sender<Status>) -> Result<()> {
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 {
@@ -58,21 +55,15 @@ fn get_update(params: OtaParams, led_tx: mpsc::Sender<Status>) -> Result<()> {
let w = writer.write(&buf[..r])?;
read_tot += r;
write_tot += w;
i += 1;
if i % 20 == 0 {
led_tx.send(Status::Ota).unwrap();
info!("Cumulative bytes read: {}", read_tot);
info!("Cumulative bytes written: {}", write_tot);
}
}
info!("TOTAL read: {}", read_tot);
info!("TOTAL written: {}", write_tot);
Ok(())
}
pub fn update_sphinx_key(params: OtaParams, led_tx: mpsc::Sender<Status>) -> Result<()> {
pub fn update_sphinx_key(params: OtaParams) -> Result<()> {
info!("Getting the update...");
get_update(params, led_tx)?;
get_update(params)?;
info!("Update written to sd card, performing factory reset");
factory_reset()?;
info!("Factory reset completed!");