diff --git a/Software/MainBoard/rust/src/hal/battery.rs b/Software/MainBoard/rust/src/hal/battery.rs index a387ac0..8de40c4 100644 --- a/Software/MainBoard/rust/src/hal/battery.rs +++ b/Software/MainBoard/rust/src/hal/battery.rs @@ -1,11 +1,13 @@ -use crate::hal::Box; use crate::fat_error::{FatError, FatResult}; +use crate::hal::Box; use async_trait::async_trait; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use esp_hal::i2c::master::I2c; use esp_hal::Blocking; -use lib_bms_protocol::{BatteryState as bstate, BmsReadable, Config, FirmwareVersion, ProtocolVersion}; +use lib_bms_protocol::{ + BatteryState as bstate, BmsReadable, Config, FirmwareVersion, ProtocolVersion, +}; use serde::Serialize; #[async_trait(?Send)] @@ -59,18 +61,17 @@ impl BatteryInteraction for NoBatteryMonitor { pub struct WchI2cSlave {} pub struct WCHI2CSlave<'a> { - pub(crate) i2c: I2cDevice<'a, CriticalSectionRawMutex, I2c<'a, Blocking>> + pub(crate) i2c: I2cDevice<'a, CriticalSectionRawMutex, I2c<'a, Blocking>>, } #[async_trait(?Send)] impl BatteryInteraction for WCHI2CSlave<'_> { - - async fn get_state(&mut self) -> FatResult { let state = bstate::read_from_i2c(&mut self.i2c)?; let config = Config::read_from_i2c(&mut self.i2c)?; - let state_of_charge = (state.remaining_capacity_mah * 100 / state.lifetime_capacity_mah) as u8; + let state_of_charge = + (state.remaining_capacity_mah * 100 / state.lifetime_capacity_mah) as u8; let state_of_health = state.lifetime_capacity_mah / config.capacity_mah * 100; Ok(BatteryState::Info(BatteryInfo { @@ -95,4 +96,4 @@ impl BatteryInteraction for WCHI2CSlave<'_> { async fn reset(&mut self) -> FatResult<()> { todo!() } -} \ No newline at end of file +} diff --git a/Software/MainBoard/rust/src/hal/v4_hal.rs b/Software/MainBoard/rust/src/hal/v4_hal.rs index 89b8c70..99bfc82 100644 --- a/Software/MainBoard/rust/src/hal/v4_hal.rs +++ b/Software/MainBoard/rust/src/hal/v4_hal.rs @@ -186,6 +186,8 @@ pub(crate) async fn create_v4( let pump_device = I2cDevice::new(I2C_DRIVER.get().await); let mut pump_expander = Pca9535Immediate::new(pump_device, 32); for pin in 0..8 { + let _ = pump_expander.pin_set_low(GPIOBank::Bank0, pin); + let _ = pump_expander.pin_set_low(GPIOBank::Bank1, pin); let _ = pump_expander.pin_into_output(GPIOBank::Bank0, pin); let _ = pump_expander.pin_into_output(GPIOBank::Bank1, pin); let _ = pump_expander.pin_set_low(GPIOBank::Bank0, pin); diff --git a/Software/MainBoard/rust/src/main.rs b/Software/MainBoard/rust/src/main.rs index 1891ea5..0fbe2ab 100644 --- a/Software/MainBoard/rust/src/main.rs +++ b/Software/MainBoard/rust/src/main.rs @@ -39,7 +39,7 @@ use embassy_net::Stack; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::{Mutex, MutexGuard}; use embassy_sync::once_lock::OnceLock; -use embassy_time::{Duration, Timer, WithTimeout}; +use embassy_time::{Duration, Instant, Timer, WithTimeout}; use esp_hal::rom::ets_delay_us; use esp_hal::system::software_reset; use esp_hal_ota::OtaImgState; @@ -642,17 +642,24 @@ pub async fn do_secure_pump( plant_config: &PlantConfig, dry_run: bool, ) -> FatResult { - let mut current_collector = vec![0_u16; plant_config.pump_time_s.into()]; - let mut flow_collector = vec![0_i16; plant_config.pump_time_s.into()]; + const STARTUP_IGNORE_MS: u32 = 500; + const STARTUP_ABORT_CURRENT_MA: u16 = 1500; + + let steps_in_50ms = plant_config.pump_time_s as usize * 20; + + let mut current_collector = vec![0_u16; steps_in_50ms]; + let mut flow_collector = vec![0_i16; steps_in_50ms]; let mut error = false; let mut first_error = true; - let mut pump_time_s = 0; + let mut pump_time_ms: u32 = 0; + if !dry_run { board.board_hal.get_tank_sensor()?.reset_flow_meter(); board.board_hal.get_tank_sensor()?.start_flow_meter(); board.board_hal.pump(plant_id, true).await?; - Timer::after_millis(10).await; - for step in 0..plant_config.pump_time_s as usize { + + for step in 0..steps_in_50ms { + let step_start = Instant::now(); let flow_value = board.board_hal.get_tank_sensor()?.get_flow_meter_value(); flow_collector[step] = flow_value; let flow_value_ml = flow_value as f32 * board.board_hal.get_config().tank.ml_per_pulse; @@ -672,7 +679,20 @@ pub async fn do_secure_pump( let current_ma = current.as_milliamperes() as u16; current_collector[step] = current_ma; let high_current = current_ma > plant_config.max_pump_current_ma; - if high_current && first_error { + if pump_time_ms < STARTUP_IGNORE_MS + && high_current + && current_ma > STARTUP_ABORT_CURRENT_MA + { + log( + LogMessage::PumpOverCurrent, + plant_id as u32 + 1, + current_ma as u32, + plant_config.max_pump_current_ma.to_string().as_str(), + step.to_string().as_str(), + ) + .await; + error = true; + } else if high_current && first_error { log( LogMessage::PumpOverCurrent, plant_id as u32 + 1, @@ -722,12 +742,27 @@ pub async fn do_secure_pump( error = true; break; } else { - //e.g., v3 without a sensor ends here, do not spam + error!("Error getting pump current: {err}"); } } } - Timer::after_millis(1000).await; - pump_time_s += 1; + + // Keep the loop period as close to 50ms (including sensor read + processing time) as possible. + // Always sleep at least 1ms to avoid a fully busy loop when we overrun. + let elapsed = step_start.elapsed(); + let target = Duration::from_millis(50); + let sleep_time = match target.checked_sub(elapsed) { + Some(remaining) => { + if remaining < Duration::from_millis(1) { + Duration::from_millis(1) + } else { + remaining + } + } + None => Duration::from_millis(1), + }; + Timer::after(sleep_time).await; + pump_time_ms += 50; } } board.board_hal.get_tank_sensor()?.stop_flow_meter(); @@ -741,7 +776,7 @@ pub async fn do_secure_pump( min_current_ma: current_collector[0], flow_value_ml, flow_value_count: final_flow_value, - pump_time_s, + pump_time_s: (pump_time_ms / 1000) as u16, error, }) } diff --git a/Software/MainBoard/rust/src/webserver/mod.rs b/Software/MainBoard/rust/src/webserver/mod.rs index fc57366..052b39b 100644 --- a/Software/MainBoard/rust/src/webserver/mod.rs +++ b/Software/MainBoard/rust/src/webserver/mod.rs @@ -18,7 +18,10 @@ use crate::webserver::get_json::{ use crate::webserver::get_log::get_log; use crate::webserver::get_static::{serve_bundle, serve_favicon, serve_index}; use crate::webserver::ota::ota_operations; -use crate::webserver::post_json::{board_test, can_power, detect_sensors, night_lamp_test, pump_test, set_config, wifi_scan, write_time}; +use crate::webserver::post_json::{ + board_test, can_power, detect_sensors, night_lamp_test, pump_test, set_config, wifi_scan, + write_time, +}; use crate::{bail, BOARD_ACCESS}; use alloc::borrow::ToOwned; use alloc::string::{String, ToString};