Skip to content

Commit

Permalink
initial commit for client ota
Browse files Browse the repository at this point in the history
  • Loading branch information
Funnyklown committed Jan 17, 2025
1 parent a05e974 commit d6a9e1c
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ base64 = { version = "0.22", default-features = false, features = ["std"] }
serde = { version = "1.0", default-features = false, features = ["derive"] }
serde_urlencoded = { version = "0.7", default-features = false }
lazy_static = { version = "1.5", default-features = false }
http = "1.2.0"
mime = "0.3.17"

[build-dependencies]
embuild = "0.33"
104 changes: 104 additions & 0 deletions src/ota/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,105 @@
// TODO
use core::mem::size_of;

use embedded_svc::http::Headers;
use http::header::ACCEPT;
use http::Uri;
use embedded_svc::ota::FirmwareInfo;
use embedded_svc::http::{client::Client, Method};
use esp_idf_svc::http::client::{Configuration, EspHttpConnection};
use esp_idf_svc::ota::EspOta;
use esp_idf_svc::sys::{EspError, ESP_ERR_IMAGE_INVALID, ESP_ERR_INVALID_RESPONSE};

/// Macro to quickly create EspError from an ESP_ERR_ constant.
#[macro_export]
macro_rules! esp_err {
($x:ident) => {
EspError::from_infallible::<$x>()
};
}

// Config to use once https is enabled
//
//use esp_idf_svc::sys::esp_crt_bundle_attach;
//
//...
//Configuration {
// buffer_size: Some(1024 * 4),
// use_global_ca_store: true,
// crt_bundle_attach: Some(esp_crt_bundle_attach),
// ..Default::default()
//}


const FIRMWARE_DOWNLOAD_CHUNK_SIZE: usize = 1024 * 20;
// Not expect firmware bigger than 2MB
const FIRMWARE_MAX_SIZE: usize = 1024 * 1024 * 2;
const FIRMWARE_MIN_SIZE: usize = size_of::<FirmwareInfo>() + 1024;

pub fn download_and_update_firmware(url: Uri) -> Result<(), EspError> {
let mut client = Client::wrap(EspHttpConnection::new(&Configuration {
buffer_size: Some(1024 * 4),
..Default::default()
})?);
let headers = [(ACCEPT.as_str(), mime::APPLICATION_OCTET_STREAM.as_ref())];
let surl = url.to_string();
let request = client
.request(Method::Get, &surl, &headers)
.map_err(|e| e.0)?;
let mut response = request.submit().map_err(|e| e.0)?;
if response.status() != 200 {
log::info!("Bad HTTP response: {}", response.status());
return Err(esp_err!(ESP_ERR_INVALID_RESPONSE));
}
let file_size = response.content_len().unwrap_or(0) as usize;
if file_size <= FIRMWARE_MIN_SIZE {
log::info!(
"File size is {file_size}, too small to be a firmware! No need to proceed further."
);
return Err(esp_err!(ESP_ERR_IMAGE_INVALID));
}
if file_size > FIRMWARE_MAX_SIZE {
log::info!("File is too big ({file_size} bytes).");
return Err(esp_err!(ESP_ERR_IMAGE_INVALID));
}
let mut ota = EspOta::new()?;
let mut work = ota.initiate_update()?;
let mut buff = vec![0; FIRMWARE_DOWNLOAD_CHUNK_SIZE];
let mut total_read_len: usize = 0;
let mut got_info = false;
let dl_result = loop {
let n = response.read(&mut buff).unwrap_or_default();
total_read_len += n;
if !got_info {
match get_firmware_info(&buff[..n]) {
Ok(info) => log::info!("Firmware to be downloaded: {info:?}"),
Err(e) => {
log::error!("Failed to get firmware info from downloaded bytes!");
break Err(e);
}
};
got_info = true;
}
if n > 0 {
if let Err(e) = work.write(&buff[..n]) {
log::error!("Failed to write to OTA. {e}");
break Err(e);
}
}
if total_read_len >= file_size {
break Ok(());
}
};
if dl_result.is_err() {
return work.abort();
}
if total_read_len < file_size {
log::error!("Supposed to download {file_size} bytes, but we could only get {total_read_len}. May be network error?");
return work.abort();
}
work.complete()
}

fn get_firmware_info(buff: &[u8]) -> Result<(), EspError>{
todo!()
}

0 comments on commit d6a9e1c

Please sign in to comment.