adjust rust code to new config file, fix bq34z100 flasher

This commit is contained in:
Empire Phoenix 2024-12-16 02:15:03 +01:00
parent c89a617d9d
commit 74f9c17461
4 changed files with 267 additions and 220 deletions

View File

@ -1,68 +1,77 @@
use std::{array::from_fn, str::FromStr};
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use crate::PLANT_COUNT;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct Config {
pub struct NetworkConfig {
pub ap_ssid: heapless::String<32>,
pub ssid: Option<heapless::String<32>>,
pub password: Option<heapless::String<64>>,
pub mqtt_url: Option<heapless::String<128>>,
pub base_topic: Option<heapless::String<64>>,
pub max_consecutive_pump_count: u8,
}
impl Default for NetworkConfig {
fn default() -> Self {
Self {
ap_ssid: heapless::String::from_str("PlantCtrl Init").unwrap(),
ssid: None,
password: None,
mqtt_url: None,
base_topic: None,
}
}
}
pub tank_allow_pumping_if_sensor_error: bool,
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct NightLampConfig {
pub night_lamp_hour_start: u8,
pub night_lamp_hour_end: u8,
pub night_lamp_only_when_dark: bool,
}
impl Default for NightLampConfig {
fn default() -> Self {
Self {
night_lamp_hour_start: 19,
night_lamp_hour_end: 2,
night_lamp_only_when_dark: true,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct TankConfig {
pub tank_sensor_enabled: bool,
pub tank_allow_pumping_if_sensor_error: bool,
pub tank_useable_ml: u32,
pub tank_warn_percent: u8,
pub tank_empty_percent: u8,
pub tank_full_percent: u8,
pub night_lamp_hour_start: u8,
pub night_lamp_hour_end: u8,
pub night_lamp_only_when_dark: bool,
pub plants: [Plant; PLANT_COUNT],
}
impl Default for Config {
impl Default for TankConfig {
fn default() -> Self {
Self {
ap_ssid: heapless::String::from_str("Plantctrl").unwrap(),
ssid: None,
password: None,
base_topic: Some(heapless::String::from_str("plant/one").unwrap()),
mqtt_url: Some(heapless::String::from_str("mqtt://192.168.1.1:1883").unwrap()),
tank_sensor_enabled: false,
tank_allow_pumping_if_sensor_error: true,
tank_sensor_enabled: true,
tank_warn_percent: 50,
night_lamp_hour_start: 21,
night_lamp_hour_end: 2,
night_lamp_only_when_dark: true,
plants: from_fn(|_i| Plant::default()),
max_consecutive_pump_count: 15,
tank_useable_ml: 5000,
tank_empty_percent: 0_u8,
tank_full_percent: 100_u8,
tank_useable_ml: 50000,
tank_warn_percent: 40,
tank_empty_percent: 5,
tank_full_percent: 95,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum Mode {
OFF,
TargetMoisture,
TimerOnly,
TimerAndDeadzone,
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
pub struct PlantControllerConfig {
pub network: NetworkConfig,
pub tank: TankConfig,
pub night_lamp: NightLampConfig,
pub plants: [PlantConfig; PLANT_COUNT],
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct Plant {
pub struct PlantConfig {
pub mode: Mode,
pub target_moisture: u8,
pub pump_time_s: u16,
@ -70,17 +79,27 @@ pub struct Plant {
pub pump_hour_start: u8,
pub pump_hour_end: u8,
pub sensor_b: bool,
pub max_consecutive_pump_count: u8,
}
impl Default for Plant {
impl Default for PlantConfig {
fn default() -> Self {
Self {
target_moisture: 40,
pump_time_s: 60,
pump_cooldown_min: 60,
pump_hour_start: 8,
pump_hour_end: 20,
mode: Mode::OFF,
target_moisture: 40,
pump_time_s: 30,
pump_cooldown_min: 60,
pump_hour_start: 9,
pump_hour_end: 20,
sensor_b: false,
max_consecutive_pump_count: 10,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum Mode {
OFF,
TargetMoisture,
TimerOnly,
TimerAndDeadzone,
}

View File

@ -22,7 +22,7 @@ use plant_hal::{PlantCtrlBoard, PlantHal, PLANT_COUNT};
use serde::{Deserialize, Serialize};
use crate::{
config::Config,
config::PlantControllerConfig,
espota::{mark_app_valid, rollback_and_reboot},
webserver::webserver::httpd,
};
@ -250,7 +250,7 @@ fn safe_main() -> anyhow::Result<()> {
}
}
let config: Config;
let config: PlantControllerConfig;
match board.get_config() {
Ok(valid) => {
config = valid;
@ -271,8 +271,12 @@ fn safe_main() -> anyhow::Result<()> {
let mut sntp = false;
println!("attempting to connect wifi");
let mut ip_address: Option<String> = None;
if config.ssid.is_some() {
match board.wifi(config.ssid.clone().unwrap(), config.password.clone(), 10000) {
if config.network.ssid.is_some() {
match board.wifi(
config.network.ssid.clone().unwrap(),
config.network.password.clone(),
10000,
) {
Ok(ip_info) => {
ip_address = Some(ip_info.ip.to_string());
wifi = true;
@ -412,16 +416,16 @@ fn safe_main() -> anyhow::Result<()> {
let mut did_pump = false;
match plant_to_pump {
Some(plant) => {
let plant_config = &config.plants[plant];
let state = &mut plantstate[plant];
state.consecutive_pump_count = board.consecutive_pump_count(plant) + 1;
board.store_consecutive_pump_count(plant, state.consecutive_pump_count);
if state.consecutive_pump_count > config.max_consecutive_pump_count.into() {
if state.consecutive_pump_count > plant_config.max_consecutive_pump_count.into() {
state.not_effective = true;
board.fault(plant, true);
}
let plant_config = &config.plants[plant];
println!(
"Trying to pump for {}s with pump {} now",
plant_config.pump_time_s, plant
@ -454,8 +458,8 @@ fn safe_main() -> anyhow::Result<()> {
light_state.is_day = is_day;
light_state.out_of_work_hour = !in_time_range(
&timezone_time,
config.night_lamp_hour_start,
config.night_lamp_hour_end,
config.night_lamp.night_lamp_hour_start,
config.night_lamp.night_lamp_hour_end,
);
let state_of_charge = board.state_charge_percent().unwrap_or(0);
@ -467,7 +471,7 @@ fn safe_main() -> anyhow::Result<()> {
light_state.battery_low = board.low_voltage_in_cycle();
if !light_state.out_of_work_hour {
if config.night_lamp_only_when_dark {
if config.night_lamp.night_lamp_only_when_dark {
if !light_state.is_day {
if light_state.battery_low {
board.light(false).unwrap();
@ -537,7 +541,7 @@ fn safe_main() -> anyhow::Result<()> {
fn publish_battery_state(
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
config: &Config,
config: &PlantControllerConfig,
) {
let bat = BatteryState {
voltage_milli_volt: &to_string(&board.voltage_milli_volt()),
@ -560,9 +564,9 @@ fn publish_battery_state(
fn determine_tank_state(
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
config: &Config,
config: &PlantControllerConfig,
) -> TankState {
if config.tank_sensor_enabled {
if config.tank.tank_sensor_enabled {
let mut rv: TankState = TankState {
..Default::default()
};
@ -572,30 +576,30 @@ fn determine_tank_state(
rv.raw = raw;
return map_range(
(
config.tank_empty_percent as f32,
config.tank_full_percent as f32,
config.tank.tank_empty_percent as f32,
config.tank.tank_full_percent as f32,
),
raw as f32,
);
})
.and_then(|percent| {
rv.left_ml = ((percent * config.tank_useable_ml as f32) / 100_f32) as u32;
rv.left_ml = ((percent * config.tank.tank_useable_ml as f32) / 100_f32) as u32;
println!(
"Tank sensor returned mv {} as {}% leaving {} ml useable",
rv.raw, percent as u8, rv.left_ml
);
if config.tank_warn_percent > percent as u8 {
if config.tank.tank_warn_percent > percent as u8 {
board.general_fault(true);
println!(
"Low water, current percent is {}, minimum warn level is {}",
percent as u8, config.tank_warn_percent
percent as u8, config.tank.tank_warn_percent
);
rv.warn_level = true;
}
if config.tank_empty_percent < percent as u8 {
if config.tank.tank_empty_percent < percent as u8 {
println!(
"Enough water, current percent is {}, minimum empty level is {}",
percent as u8, config.tank_empty_percent
percent as u8, config.tank.tank_empty_percent
);
rv.enough_water = true;
}
@ -624,7 +628,7 @@ fn determine_state_target_moisture_for_plant(
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
plant: usize,
state: &mut PlantState,
config: &Config,
config: &PlantControllerConfig,
tank_state: &TankState,
cur: DateTime<Tz>,
) {
@ -671,7 +675,7 @@ fn determine_state_target_moisture_for_plant(
if a_low || b_low {
state.dry = true;
if tank_state.sensor_error && !config.tank_allow_pumping_if_sensor_error {
if tank_state.sensor_error && !config.tank.tank_allow_pumping_if_sensor_error {
//ignore is ok
} else if !tank_state.enough_water {
state.no_water = true;
@ -714,7 +718,7 @@ fn determine_state_timer_only_for_plant(
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
plant: usize,
state: &mut PlantState,
config: &Config,
config: &PlantControllerConfig,
tank_state: &TankState,
cur: DateTime<Tz>,
) {
@ -730,7 +734,7 @@ fn determine_state_timer_only_for_plant(
state.next_pump = Some(europe_time);
state.cooldown = true;
} else {
if tank_state.sensor_error && !config.tank_allow_pumping_if_sensor_error {
if tank_state.sensor_error && !config.tank.tank_allow_pumping_if_sensor_error {
state.do_water = true;
} else if !tank_state.enough_water {
state.no_water = true;
@ -752,7 +756,7 @@ fn determine_state_timer_and_deadzone_for_plant(
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
plant: usize,
state: &mut PlantState,
config: &Config,
config: &PlantControllerConfig,
tank_state: &TankState,
cur: DateTime<Tz>,
) {
@ -776,7 +780,7 @@ fn determine_state_timer_and_deadzone_for_plant(
state.out_of_work_hour = true;
}
if !state.cooldown && !state.out_of_work_hour {
if tank_state.sensor_error && !config.tank_allow_pumping_if_sensor_error {
if tank_state.sensor_error && !config.tank.tank_allow_pumping_if_sensor_error {
state.do_water = true;
} else if !tank_state.enough_water {
state.no_water = true;
@ -799,7 +803,7 @@ fn determine_next_plant(
cur: DateTime<Tz>,
tank_state: &TankState,
water_frozen: bool,
config: &Config,
config: &PlantControllerConfig,
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
) -> Option<usize> {
for plant in 0..PLANT_COUNT {
@ -850,7 +854,7 @@ fn determine_next_plant(
fn update_plant_state(
plantstate: &mut [PlantState; PLANT_COUNT],
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
config: &Config,
config: &PlantControllerConfig,
) {
for plant in 0..PLANT_COUNT {
let state = &plantstate[plant];

View File

@ -2,7 +2,6 @@ use bq34z100::{Bq34Z100Error, Bq34z100g1, Bq34z100g1Driver};
use ds323x::{DateTimeAccess, Ds323x};
use eeprom24x::page_size::No;
use eeprom24x::{Eeprom24x, SlaveAddr};
use embedded_hal_bus::i2c::MutexDevice;
use embedded_svc::wifi::{
@ -14,7 +13,6 @@ use esp_idf_hal::adc::{attenuation, Resolution};
use esp_idf_hal::i2c::{APBTickType, I2cConfig, I2cDriver, I2cError};
use esp_idf_hal::units::FromValueType;
use esp_idf_svc::eventloop::EspSystemEventLoop;
use esp_idf_svc::io::vfs;
use esp_idf_svc::ipv4::IpInfo;
use esp_idf_svc::mqtt::client::QoS::AtLeastOnce;
use esp_idf_svc::mqtt::client::QoS::ExactlyOnce;
@ -30,8 +28,7 @@ use anyhow::{anyhow, Context};
use anyhow::{bail, Ok, Result};
use serde::Serialize;
use std::ffi::CString;
use std::fs::{self, DirEntry, File};
use std::io::{Read, Write};
use std::fs::{self, File};
use std::path::Path;
use chrono::{DateTime, Utc};
@ -52,10 +49,10 @@ use esp_idf_hal::prelude::Peripherals;
use esp_idf_hal::reset::ResetReason;
use esp_idf_svc::sntp::{self, SyncStatus};
use esp_idf_svc::systime::EspSystemTime;
use esp_idf_sys::{esp, esp_spiffs_check, f_opendir, gpio_hold_dis, gpio_hold_en, vTaskDelay, EspError};
use esp_idf_sys::{esp, esp_spiffs_check, gpio_hold_dis, gpio_hold_en, vTaskDelay, EspError};
use one_wire_bus::OneWire;
use crate::config::{self, Config};
use crate::config::{self, PlantControllerConfig};
use crate::{plant_hal, STAY_ALIVE};
//Only support for 8 right now!
@ -173,7 +170,7 @@ pub struct PlantCtrlBoard<'a> {
#[derive(Serialize, Debug)]
pub struct FileInfo {
filename: String,
size:usize
size: usize,
}
#[derive(Serialize, Debug)]
@ -193,13 +190,11 @@ impl PlantCtrlBoard<'_> {
};
let mut file_system_corrupt = match error {
OkStd(_) => {
None
},
OkStd(_) => None,
Err(err) => {
println!("Corrupt spiffs {err:?}");
Some(format!("{err:?}"))
},
}
};
let mut iter_error = None;
@ -216,37 +211,41 @@ impl PlantCtrlBoard<'_> {
OkStd(file) => {
let f = FileInfo {
filename: file.file_name().into_string().unwrap(),
size: file.metadata().and_then(|it| core::result::Result::Ok(it.len())).unwrap_or_default() as usize
size: file
.metadata()
.and_then(|it| core::result::Result::Ok(it.len()))
.unwrap_or_default()
as usize,
};
println!("fileinfo {f:?}");
result.push(f);
},
}
Err(err) => {
iter_error = Some(format!("{err:?}"));
break;
},
}
}
},
}
}
Err(err) => {
file_system_corrupt = Some(format!("{err:?}"));
},
}
}
return FileList {
file_system_corrupt,
files: result,
iter_error
iter_error,
};
}
pub fn delete_file(&self, filename: &str) -> Result<()> {
let filepath = Path::new(BASE_PATH).join(Path::new(filename));
match (fs::remove_file(filepath)){
match fs::remove_file(filepath) {
OkStd(_) => Ok(()),
Err(err) => {
bail!(format!("{err:?}"))
},
}
}
}
@ -256,7 +255,7 @@ impl PlantCtrlBoard<'_> {
File::create(filepath)?
} else {
File::open(filepath)?
})
});
}
pub fn is_day(&self) -> bool {
@ -495,7 +494,10 @@ impl PlantCtrlBoard<'_> {
delay.delay_ms(10);
let unscaled = self.signal_counter.get_counter_value()? as i32;
let hz = (unscaled as f32 * factor) as i32;
println!("raw measure unscaled {} hz {}, plant {} sensor {:?}",unscaled, hz, plant, sensor);
println!(
"raw measure unscaled {} hz {}, plant {} sensor {:?}",
unscaled, hz, plant, sensor
);
results[repeat] = hz;
//println!("Measuring {:?} @ {} with {}", sensor, plant, hz);
}
@ -661,13 +663,13 @@ impl PlantCtrlBoard<'_> {
}
}
pub fn get_config(&mut self) -> Result<config::Config> {
pub fn get_config(&mut self) -> Result<config::PlantControllerConfig> {
let cfg = File::open(CONFIG_FILE)?;
let config: Config = serde_json::from_reader(cfg)?;
let config: PlantControllerConfig = serde_json::from_reader(cfg)?;
Ok(config)
}
pub fn set_config(&mut self, config: &Config) -> Result<()> {
pub fn set_config(&mut self, config: &PlantControllerConfig) -> Result<()> {
let mut cfg = File::create(CONFIG_FILE)?;
serde_json::to_writer(&mut cfg, &config)?;
println!("Wrote config config {:?}", config);
@ -735,9 +737,17 @@ impl PlantCtrlBoard<'_> {
config.exists()
}
pub fn mqtt(&mut self, config: &Config) -> Result<()> {
let base_topic = config.base_topic.as_ref().context("missing base topic")?;
let mqtt_url = config.mqtt_url.as_ref().context("missing mqtt url")?;
pub fn mqtt(&mut self, config: &PlantControllerConfig) -> Result<()> {
let base_topic = config
.network
.base_topic
.as_ref()
.context("missing base topic")?;
let mqtt_url = config
.network
.mqtt_url
.as_ref()
.context("missing mqtt url")?;
let last_will_topic = format!("{}/state", base_topic);
let mqtt_client_config = MqttClientConfiguration {
@ -865,7 +875,12 @@ impl PlantCtrlBoard<'_> {
bail!("Mqtt did not fire connection callback in time");
}
pub fn mqtt_publish(&mut self, config: &Config, subtopic: &str, message: &[u8]) -> Result<()> {
pub fn mqtt_publish(
&mut self,
config: &PlantControllerConfig,
subtopic: &str,
message: &[u8],
) -> Result<()> {
if self.mqtt_client.is_none() {
return Ok(());
}
@ -880,7 +895,7 @@ impl PlantCtrlBoard<'_> {
let client = self.mqtt_client.as_mut().unwrap();
let mut full_topic: heapless::String<256> = heapless::String::new();
if full_topic
.push_str(&config.base_topic.as_ref().unwrap())
.push_str(&config.network.base_topic.as_ref().unwrap())
.is_err()
{
println!("Some error assembling full_topic 1");

View File

@ -1,20 +1,23 @@
//offer ota and config mode
use std::{
collections::VecDeque, fs, io::{BufRead, Read, Write}, str::from_utf8, sync::{atomic::AtomicBool, Arc}
io::{BufRead, BufReader, Read, Write},
str::from_utf8,
sync::{atomic::AtomicBool, Arc},
};
use crate::{espota::OtaUpdate, map_range_moisture, plant_hal::FileInfo, BOARD_ACCESS};
use anyhow::bail;
use chrono::DateTime;
use url::Url;
use core::result::Result::Ok;
use embedded_svc::http::Method;
use esp_idf_hal::delay::Delay;
use esp_idf_svc::{http::server::{Configuration, EspHttpConnection, EspHttpServer, Request}};
use esp_idf_svc::http::server::{Configuration, EspHttpConnection, EspHttpServer, Request};
use heapless::String;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::config::Config;
use crate::config::PlantControllerConfig;
#[derive(Serialize, Debug)]
struct SSIDList<'a> {
@ -87,8 +90,8 @@ fn get_data(
match a_pct {
Ok(result) => {
a.push(result);
},
Err(err) => {
}
Err(_) => {
a.push(200);
}
}
@ -97,19 +100,18 @@ fn get_data(
match b_pct {
Ok(result) => {
b.push(result);
},
Err(err) => {
}
Err(_) => {
b.push(200);
}
}
}
let data = LoadData {
rtc: rtc.as_str(),
native: native.as_str(),
moisture_a: a,
moisture_b: b
moisture_b: b,
};
let json = serde_json::to_string(&data)?;
@ -122,7 +124,7 @@ fn get_config(
let mut board = BOARD_ACCESS.lock().unwrap();
let json = match board.get_config() {
Ok(config) => serde_json::to_string(&config)?,
Err(_) => serde_json::to_string(&Config::default())?,
Err(_) => serde_json::to_string(&PlantControllerConfig::default())?,
};
anyhow::Ok(Some(json))
}
@ -134,7 +136,7 @@ fn set_config(
let read = request.read(&mut buf)?;
let actual_data = &buf[0..read];
println!("Raw data {}", from_utf8(actual_data).unwrap());
let config: Config = serde_json::from_slice(actual_data)?;
let config: PlantControllerConfig = serde_json::from_slice(actual_data)?;
let mut board = BOARD_ACCESS.lock().unwrap();
board.set_config(&config)?;
anyhow::Ok(Some("saved".to_owned()))
@ -215,6 +217,45 @@ fn ota(
finalizer.restart();
}
fn flash_bq(filename: &str, dryrun: bool) -> anyhow::Result<()> {
let mut board = BOARD_ACCESS.lock().unwrap();
let mut toggle = true;
let delay = Delay::new(1);
let file_handle = board.get_file_handle(filename, false)?;
let mut reader = BufReader::with_capacity(512, file_handle).lines();
let mut line = 0;
loop {
board.general_fault(toggle);
toggle = !toggle;
delay.delay_us(2);
line += 1;
match reader.next() {
Some(next) => {
let input = next?;
println!("flashing bq34z100 dryrun:{dryrun} line {line} payload: {input}");
match board.flash_bq34_z100(&input, dryrun) {
Ok(_) => {
println!("ok")
}
Err(err) => {
bail!(
"Error flashing bq34z100 in dryrun: {dryrun} line: {line} error: {err}"
)
}
}
}
None => break,
}
}
println!("Finished flashing file {line} lines processed");
board.general_fault(false);
return anyhow::Ok(());
}
fn query_param(uri: &str, param_name: &str) -> Option<std::string::String> {
println!("{uri} get {param_name}");
let parsed = Url::parse(&format!("http://127.0.0.1/{uri}")).unwrap();
@ -222,10 +263,8 @@ fn query_param(uri:&str, param_name:&str) -> Option<std::string::String>{
match value {
Some(found) => {
return Some(found.1.into_owned());
},
None => {
return None
},
}
None => return None,
}
}
@ -291,10 +330,12 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
server
.fn_handler("/file", Method::Get, move |request| {
let filename = query_param(request.uri(), "filename").unwrap();
let file_handle = BOARD_ACCESS.lock().unwrap().get_file_handle(&filename, false);
let file_handle = BOARD_ACCESS
.lock()
.unwrap()
.get_file_handle(&filename, false);
match file_handle {
Ok(mut file_handle) => {
let headers = [("Access-Control-Allow-Origin", "*")];
let mut response = request.into_response(200, None, &headers)?;
const BUFFER_SIZE: usize = 512;
@ -303,7 +344,10 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
loop {
let read = file_handle.read(&mut buffer)?;
total_read += read;
println!("sending {read} bytes of {total_read} for file {}", &filename);
println!(
"sending {read} bytes of {total_read} for file {}",
&filename
);
let to_write = &buffer[0..read];
response.write(to_write)?;
println!("wrote {read} bytes of {total_read} for file {filename}");
@ -313,8 +357,7 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
}
drop(file_handle);
response.flush()?;
},
}
Err(err) => {
//todo set headers here for filename to be error
let error_text = err.to_string();
@ -328,7 +371,10 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
server
.fn_handler("/file", Method::Post, move |mut request| {
let filename = query_param(request.uri(), "filename").unwrap();
let file_handle = BOARD_ACCESS.lock().unwrap().get_file_handle(&filename,true);
let file_handle = BOARD_ACCESS
.lock()
.unwrap()
.get_file_handle(&filename, true);
match file_handle {
Ok(mut file_handle) => {
const BUFFER_SIZE: usize = 512;
@ -346,7 +392,7 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
}
}
cors_response(request, 200, &format!("saved {total_read} bytes"))?;
},
}
Err(err) => {
//todo set headers here for filename to be error
let error_text = err.to_string();
@ -367,80 +413,41 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
Ok(_) => {
let info = format!("Deleted file {copy}");
cors_response(request, 200, &info)?;
},
}
Err(err) => {
let info = format!("Could not delete file {copy} {err:?}");
cors_response(request, 400, &info)?;
},
}
}
anyhow::Ok(())
})
.unwrap();
server
.fn_handler("/flashbattery", Method::Post, move |mut request| {
let mut board = BOARD_ACCESS.lock().unwrap();
let mut buffer: [u8; 128] = [0; 128];
let mut line_buffer: VecDeque<u8> = VecDeque::new();
let is_dry_run = !request.uri().ends_with("?flash=true");
let mut total_read: usize = 0;
let mut toggle = true;
let delay = Delay::new(1);
todo!("Write to storage before attempting to flash!");
loop {
delay.delay_us(2);
let read = request.read(&mut buffer).unwrap();
total_read += read;
if read == 0 {
if line_buffer.len() > 0 {
println!("No further body but no endline");
let mut line = std::string::String::new();
line_buffer.read_to_string(&mut line).unwrap();
let msg = format!("Finished reading, but there is still some leftover in buffer and no full line {line}<br>");
println!("{}", msg);
let mut response = request.into_status_response(400_u16).unwrap();
response.write(msg.as_bytes()).unwrap();
response.flush().unwrap();
return anyhow::Ok(())
.fn_handler("/flashbattery", Method::Post, move |request| {
let filename = query_param(request.uri(),"filename").unwrap();
let dryrun = true;
match flash_bq(&filename, false) {
Ok(_) => {
if !dryrun {
match flash_bq(&filename, true) {
Ok(_) => {
cors_response(request, 200, "Sucessfully flashed bq34z100")?;
},
Err(err) => {
let info = format!("Could not flash bq34z100, could be bricked now! {filename} {err:?}");
cors_response(request, 500, &info)?;
},
}
break;
} else {
cors_response(request, 200, "Sucessfully processed bq34z100")?;
}
let to_write = &buffer[0..read];
line_buffer.write_all(to_write).unwrap();
board.general_fault(toggle);
toggle = !toggle;
loop {
let has_line = line_buffer.contains(&b'\n');
if !has_line {
break;
}
let mut line = std::string::String::new();
line_buffer.read_line(&mut line)?;
let line2 = &line[0..line.len()-1];
println!("Processing dry:{} line {}", is_dry_run, line2);
let validate = board.flash_bq34_z100(&line2, is_dry_run);
delay.delay_us(2);
if validate.is_err() {
let mut response = request.into_status_response(400_u16).unwrap();
let err = validate.unwrap_err();
let err_str = err.to_string();
let err_msg = err_str.as_bytes();
println!("Error writing {}", err_str);
response
.write(err_msg)
.unwrap();
return anyhow::Ok(())
}
}
}
let mut response = request.into_status_response(200_u16).unwrap();
let msg = format!("Finished writing {total_read} bytes<br>");
response.write(msg.as_bytes()).unwrap();
board.general_fault(false);
},
Err(err) => {
let info = format!("Could not process firmware file for, bq34z100, refusing to flash! {filename} {err:?}");
cors_response(request, 500, &info)?;
},
};
anyhow::Ok(())
})
.unwrap();
@ -448,7 +455,7 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
server
.fn_handler("/", Method::Get, move |request| {
let mut response = request.into_ok_response()?;
response.write(include_bytes!("index.html"))?;let mut buf = [0_u8; 3072];
response.write(include_bytes!("index.html"))?;
anyhow::Ok(())
})
.unwrap();
@ -458,7 +465,6 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
.into_ok_response()?
.write(include_bytes!("favicon.ico"))?;
anyhow::Ok(())
})
.unwrap();
server
@ -467,13 +473,16 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
.into_ok_response()?
.write(include_bytes!("bundle.js"))?;
anyhow::Ok(())
})
.unwrap();
server
}
fn cors_response(request: Request<&mut EspHttpConnection>, status: u16, body: &str) -> Result<(), anyhow::Error>{
fn cors_response(
request: Request<&mut EspHttpConnection>,
status: u16,
body: &str,
) -> Result<(), anyhow::Error> {
let headers = [("Access-Control-Allow-Origin", "*")];
let mut response = request.into_response(status, None, &headers)?;
response.write(body.as_bytes())?;