diff --git a/Software/MainBoard/rust/Cargo.toml b/Software/MainBoard/rust/Cargo.toml index 34e4b80..4fce08b 100644 --- a/Software/MainBoard/rust/Cargo.toml +++ b/Software/MainBoard/rust/Cargo.toml @@ -13,6 +13,10 @@ test = false bench = false doc = false +[features] +default = ["esp32c6"] +esp32c6 = [] + #this strips the bootloader, we need that tho #strip = true @@ -87,6 +91,8 @@ edge-nal = "0.5.0" edge-nal-embassy = "0.6.0" edge-http = { version = "0.6.1", features = ["log"] } +esp32c6 = { version = "0.22.0" } + # Hardware abstraction traits and HAL adapters embedded-hal = "1.0.0" embedded-storage = "0.3.1" @@ -95,7 +101,7 @@ embedded-can = "0.4.1" nb = "1.1.0" # Concrete hardware drivers and sensors/IO expanders -lib-bms-protocol = {git = "https://gitea.wlandt.de/judge/ch32-bms.git" , default-features = false } +lib-bms-protocol = { git = "https://gitea.wlandt.de/judge/ch32-bms.git", default-features = false } onewire = "0.4.0" ds323x = "0.7.0" eeprom24x = "0.7.2" diff --git a/Software/MainBoard/rust/src/fat_error.rs b/Software/MainBoard/rust/src/fat_error.rs index 5e6bbe0..604b3f0 100644 --- a/Software/MainBoard/rust/src/fat_error.rs +++ b/Software/MainBoard/rust/src/fat_error.rs @@ -52,6 +52,7 @@ pub enum FatError { SpawnError { error: SpawnError, }, + OTAError, PartitionError { error: esp_bootloader_esp_idf::partitions::Error, }, @@ -106,6 +107,9 @@ impl fmt::Display for FatError { } FatError::SNTPError { error } => write!(f, "SNTPError {error:?}"), FatError::BMSError { error } => write!(f, "BMSError, {error}"), + FatError::OTAError => { + write!(f, "OTA missing partition") + } } } } @@ -323,13 +327,12 @@ impl From for FatError { } } - -impl From for FatError{ +impl From for FatError { fn from(value: BmsProtocolError) -> Self { match value { - BmsProtocolError::I2cCommunicationError => { - FatError::String{error: "I2C communication error".to_string()} - } + BmsProtocolError::I2cCommunicationError => FatError::String { + error: "I2C communication error".to_string(), + }, } } -} \ No newline at end of file +} diff --git a/Software/MainBoard/rust/src/hal/esp.rs b/Software/MainBoard/rust/src/hal/esp.rs index 03e2fb6..3a69e66 100644 --- a/Software/MainBoard/rust/src/hal/esp.rs +++ b/Software/MainBoard/rust/src/hal/esp.rs @@ -21,11 +21,10 @@ 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 embedded_storage::nor_flash::{check_erase, NorFlash, ReadNorFlash}; +use embedded_storage::nor_flash::{check_erase, NorFlash, ReadNorFlash, RmwNorFlashStorage}; use esp_bootloader_esp_idf::ota::OtaImageState::Valid; use esp_bootloader_esp_idf::ota::{Ota, OtaImageState}; use esp_bootloader_esp_idf::partitions::{AppPartitionSubType, FlashRegion}; -use esp_hal::Blocking; use esp_hal::gpio::{Input, RtcPinWithResistors}; use esp_hal::rng::Rng; use esp_hal::rtc_cntl::{ @@ -34,6 +33,7 @@ use esp_hal::rtc_cntl::{ }; use esp_hal::system::software_reset; use esp_hal::uart::Uart; +use esp_hal::Blocking; use esp_println::println; use esp_radio::wifi::{ AccessPointConfig, AccessPointInfo, AuthMethod, ClientConfig, ModeConfig, ScanConfig, @@ -130,7 +130,7 @@ pub struct Esp<'a> { pub wake_gpio1: esp_hal::peripherals::GPIO1<'static>, pub uart0: Uart<'a, Blocking>, - pub ota: Ota<'static, MutexFlashStorage>, + pub ota: Ota<'static, RmwNorFlashStorage<'static, &'static mut MutexFlashStorage>>, pub ota_target: &'static mut FlashRegion<'static, MutexFlashStorage>, pub current: AppPartitionSubType, pub slot0_state: OtaImageState, @@ -155,7 +155,6 @@ macro_rules! mk_static { } impl Esp<'_> { - pub(crate) async fn read_serial_line(&mut self) -> FatResult> { let mut buf = [0u8; 1]; let mut line = String::new(); @@ -171,7 +170,7 @@ impl Esp<'_> { } line.push(c); } - Err(error ) => { + Err(error) => { if line.is_empty() { return Ok(None); } else { @@ -252,6 +251,7 @@ impl Esp<'_> { pub(crate) async fn write_ota(&mut self, offset: u32, buf: &[u8]) -> Result<(), FatError> { let _ = check_erase(self.ota_target, offset, offset + 4096); + info!("erasing and writing block 0x{offset:x}"); self.ota_target.erase(offset, offset + 4096)?; let mut temp = vec![0; buf.len()]; @@ -288,8 +288,6 @@ impl Esp<'_> { info!("switched state for new partition"); let state_new = self.ota.current_ota_state()?; info!("state on new partition now {state_new:?}"); - //determine nextslot crc - self.set_restart_to_conf(true); Ok(()) } @@ -597,10 +595,13 @@ impl Esp<'_> { // Mark the current OTA image as valid if we reached here while in pending verify. if let Ok(cur) = self.ota.current_ota_state() { if cur == OtaImageState::PendingVerify { + info!("Marking OTA image as valid"); self.ota .set_current_ota_state(Valid) .expect("Could not set image to valid"); } + } else { + info!("No OTA image to mark as valid"); } if duration_in_ms == 0 { diff --git a/Software/MainBoard/rust/src/hal/mod.rs b/Software/MainBoard/rust/src/hal/mod.rs index 034c018..b350fc6 100644 --- a/Software/MainBoard/rust/src/hal/mod.rs +++ b/Software/MainBoard/rust/src/hal/mod.rs @@ -1,5 +1,5 @@ +use esp_hal::uart::Config as UartConfig; use lib_bms_protocol::BmsReadable; -use esp_hal::uart::{Config as UartConfig}; pub(crate) mod battery; // mod can_api; // replaced by external canapi crate pub mod esp; @@ -9,7 +9,6 @@ mod shared_flash; mod v4_hal; mod water; -use lib_bms_protocol::ProtocolVersion; use crate::alloc::string::ToString; use crate::hal::rtc::{DS3231Module, RTCModuleInteraction}; use esp_hal::peripherals::Peripherals; @@ -36,6 +35,7 @@ use esp_hal::peripherals::GPIO6; use esp_hal::peripherals::GPIO7; use esp_hal::peripherals::GPIO8; use esp_hal::peripherals::TWAI0; +use lib_bms_protocol::ProtocolVersion; use crate::{ bail, @@ -66,19 +66,21 @@ use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex; use esp_bootloader_esp_idf::partitions::{ - AppPartitionSubType, DataPartitionSubType, FlashRegion, PartitionEntry, + AppPartitionSubType, DataPartitionSubType, FlashRegion, PartitionEntry, PartitionTable, + PartitionType, }; use esp_hal::clock::CpuClock; use esp_hal::gpio::{Input, InputConfig, Pull}; use measurements::{Current, Voltage}; use crate::fat_error::{ContextExt, FatError, FatResult}; -use crate::hal::battery::{WCHI2CSlave}; +use crate::hal::battery::WCHI2CSlave; use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem; use crate::hal::water::TankSensor; use crate::log::LOG_ACCESS; use embassy_sync::mutex::Mutex; use embassy_sync::once_lock::OnceLock; +use embedded_storage::nor_flash::RmwNorFlashStorage; use embedded_storage::ReadStorage; use esp_alloc as _; use esp_backtrace as _; @@ -93,8 +95,8 @@ use esp_hal::rtc_cntl::{Rtc, SocResetReason}; use esp_hal::system::reset_reason; use esp_hal::time::Rate; use esp_hal::timer::timg::TimerGroup; -use esp_hal::Blocking; use esp_hal::uart::Uart; +use esp_hal::Blocking; use esp_radio::{init, Controller}; use esp_storage::FlashStorage; use littlefs2::fs::{Allocation, Filesystem as lfs2Filesystem}; @@ -138,12 +140,6 @@ pub struct HAL<'a> { pub board_hal: Box + Send>, } -pub struct DetectionRequest { - pub sensorsa: [Sensor; PLANT_COUNT], - pub sensorsb: [Sensor; PLANT_COUNT], - -} - #[async_trait(?Send)] pub trait BoardInteraction<'a> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError>; @@ -169,7 +165,7 @@ pub trait BoardInteraction<'a> { async fn can_power(&mut self, state: bool) -> FatResult<()>; // Return JSON string with autodetected sensors per plant. Default: not supported. - async fn detect_sensors(&mut self, request: Detection) -> FatResult { + async fn detect_sensors(&mut self, _request: Detection) -> FatResult { bail!("Autodetection is only available on v4 HAL with CAN bus"); } @@ -333,31 +329,31 @@ impl PlantHal { ); let ota_data = mk_static!( - FlashRegion, - ota_data.as_embedded_storage(flash_storage_2) + FlashRegion>, + ota_data.as_embedded_storage(mk_static!( + RmwNorFlashStorage<&mut MutexFlashStorage>, + RmwNorFlashStorage::new(flash_storage_2, mk_static!([u8; 4096], [0_u8; 4096])) + )) ); let state_0 = ota_state(AppPartitionSubType::Ota0, ota_data); let state_1 = ota_state(AppPartitionSubType::Ota1, ota_data); let mut ota = Ota::new(ota_data, 2)?; - let running = get_current_slot_and_fix_ota_data(&mut ota, state_0, state_1)?; + let running = get_current_slot(&pt, &mut ota)?; let target = next_partition(running)?; info!("Currently running OTA slot: {running:?}"); + info!("Updates will be stored in OTA slot: {target:?}"); info!("Slot0 state: {state_0:?}"); info!("Slot1 state: {state_1:?}"); //get current_state and next_state here! let ota_target = match target { AppPartitionSubType::Ota0 => pt - .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App( - AppPartitionSubType::Ota0, - ))? + .find_partition(PartitionType::App(AppPartitionSubType::Ota0))? .context("Partition table invalid no ota0")?, AppPartitionSubType::Ota1 => pt - .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App( - AppPartitionSubType::Ota1, - ))? + .find_partition(PartitionType::App(AppPartitionSubType::Ota1))? .context("Partition table invalid no ota1")?, _ => { bail!("Invalid target partition"); @@ -401,8 +397,8 @@ impl PlantHal { lfs2Filesystem::mount(alloc, lfs2filesystem).expect("Could not mount lfs2 filesystem"), )); - let uart0 = Uart::new(peripherals.UART0, UartConfig::default()) - .map_err(|_| FatError::String { + let uart0 = + Uart::new(peripherals.UART0, UartConfig::default()).map_err(|_| FatError::String { error: "Uart creation failed".to_string(), })?; @@ -421,7 +417,7 @@ impl PlantHal { current: running, slot0_state: state_0, slot1_state: state_1, - uart0 + uart0, }; //init,reset rtc memory depending on cause @@ -551,9 +547,9 @@ impl PlantHal { // initial_hal::create_initial_board(free_pins, config, esp)? //} //BoardVersion::V4 => { - v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module) - .await?; - //} + v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module) + .await?; + //} //}; HAL { board_hal } @@ -571,9 +567,14 @@ impl PlantHal { ) .await; HAL { - board_hal: v4_hal::create_v4(free_pins, esp, PlantControllerConfig::default(), - Box::new(NoBatteryMonitor {}), rtc_module) - .await? + board_hal: v4_hal::create_v4( + free_pins, + esp, + PlantControllerConfig::default(), + Box::new(NoBatteryMonitor {}), + rtc_module, + ) + .await?, } } }; @@ -584,7 +585,7 @@ impl PlantHal { fn ota_state( slot: AppPartitionSubType, - ota_data: &mut FlashRegion, + ota_data: &mut FlashRegion>, ) -> OtaImageState { // Read and log OTA states for both slots before constructing Ota // Each OTA select entry is 32 bytes: [seq:4][label:20][state:4][crc:4] @@ -600,56 +601,40 @@ fn ota_state( OtaImageState::try_from(raw_state).unwrap_or(OtaImageState::Undefined) } -fn get_current_slot_and_fix_ota_data( - ota: &mut Ota, - state0: OtaImageState, - state1: OtaImageState, +fn get_current_slot( + pt: &PartitionTable, + ota: &mut Ota>, ) -> Result { - let state = ota.current_ota_state().unwrap_or_default(); - let swap = match state { - OtaImageState::Invalid => true, - OtaImageState::Aborted => true, - OtaImageState::Undefined => { - info!("Undefined image in current slot, bootloader wrong?"); - false + let booted = pt.booted_partition()?.ok_or(FatError::OTAError)?; + let booted_type = booted.partition_type(); + let booted_ota_type = match booted_type { + PartitionType::App(subtype) => subtype, + _ => { + bail!("Booted partition is not an app partition"); } - _ => false, }; - let current = ota.current_app_partition()?; - if swap { - let other = match current { - AppPartitionSubType::Ota0 => state1, - AppPartitionSubType::Ota1 => state0, - _ => OtaImageState::Invalid, - }; - match other { - OtaImageState::Invalid => { - bail!( - "cannot recover slot, as both slots in invalid state {:?} {:?} {:?}", - current, - state0, - state1 - ); - } - OtaImageState::Aborted => { - bail!( - "cannot recover slot, as both slots in invalid state {:?} {:?} {:?}", - current, - state0, - state1 - ); - } - _ => {} - } - info!("Current slot has state {state:?} other state has {other:?} swapping"); - let next = next_partition(current)?; - ota.set_current_app_partition(next)?; + let expected_partition = ota.current_app_partition()?; + if expected_partition == booted_ota_type { + info!("Booted partition matches expected partition"); + } else { + info!("Booted partition does not match expected partition, fixing ota entry"); + ota.set_current_app_partition(booted_ota_type)?; + } - //we actually booted other slot, than partition table assumes - return Ok(ota.current_app_partition()?); - }; - Ok(current) + let fixed = ota.current_app_partition()?; + let state = ota.current_ota_state(); + info!("Expected partition: {expected_partition:?}, current partition: {booted_ota_type:?}, state: {state:?}"); + + if fixed != booted_ota_type { + bail!( + "Could not fix ota entry, booted partition is still not correct: {:?} != {:?}", + booted_ota_type, + fixed + ); + } + + Ok(booted_ota_type) } pub fn next_partition(current: AppPartitionSubType) -> FatResult { @@ -699,4 +684,3 @@ pub struct DetectionSensorResult { sensor_a: bool, sensor_b: bool, } - diff --git a/Software/MainBoard/rust/src/hal/shared_flash.rs b/Software/MainBoard/rust/src/hal/shared_flash.rs index b206ea5..0bd37c8 100644 --- a/Software/MainBoard/rust/src/hal/shared_flash.rs +++ b/Software/MainBoard/rust/src/hal/shared_flash.rs @@ -5,6 +5,7 @@ use embassy_sync::blocking_mutex::CriticalSectionMutex; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; use embedded_storage::ReadStorage; use esp_storage::{FlashStorage, FlashStorageError}; +use log::info; #[derive(Clone)] pub struct MutexFlashStorage { @@ -52,6 +53,7 @@ impl NorFlash for MutexFlashStorage { const ERASE_SIZE: usize = 4096; fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + info!("Erasing flash from 0x{:x} to 0x{:x}", from, to); self.inner .lock(|f| NorFlash::erase(f.borrow_mut().deref_mut(), from, to)) } diff --git a/Software/MainBoard/rust/src/hal/v4_hal.rs b/Software/MainBoard/rust/src/hal/v4_hal.rs index fdd4556..8d924d7 100644 --- a/Software/MainBoard/rust/src/hal/v4_hal.rs +++ b/Software/MainBoard/rust/src/hal/v4_hal.rs @@ -11,7 +11,7 @@ use crate::hal::{ }; use crate::log::{LogMessage, LOG_ACCESS}; use alloc::boxed::Box; -use alloc::string::{ToString}; +use alloc::string::ToString; use async_trait::async_trait; use canapi::id::{classify, plant_id, MessageKind, IDENTIFY_CMD_OFFSET}; use canapi::SensorSlot; @@ -23,7 +23,6 @@ use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull} use esp_hal::i2c::master::I2c; use esp_hal::twai::{EspTwaiError, EspTwaiFrame, StandardId, Twai, TwaiConfiguration, TwaiMode}; use esp_hal::{twai, Async, Blocking}; -use esp_println::println; use ina219::address::{Address, Pin}; use ina219::calibration::UnCalibrated; use ina219::configuration::{Configuration, OperatingMode, Resolution}; @@ -133,10 +132,9 @@ pub struct V4<'a> { extra1: Output<'a>, extra2: Output<'a>, - twai_config: Option> + twai_config: Option>, } - pub(crate) async fn create_v4( peripherals: FreePeripherals<'static>, esp: Esp<'static>, @@ -263,12 +261,11 @@ pub(crate) async fn create_v4( extra1, extra2, can_power, - twai_config + twai_config, }; Ok(Box::new(v)) } - #[async_trait(?Send)] impl<'a> BoardInteraction<'a> for V4<'a> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> { @@ -377,69 +374,6 @@ impl<'a> BoardInteraction<'a> for V4<'a> { Ok(moistures) } - async fn detect_sensors(&mut self, request: Detection) -> FatResult { - self.can_power.set_high(); - let config = self.twai_config.take().expect("twai config not set"); - let mut twai = config.into_async().start(); - - Timer::after_millis(1000).await; - info!("Sending info messages now"); - // Send a few test messages per potential sensor node - for plant in 0..PLANT_COUNT { - for sensor in [Sensor::A, Sensor::B] { - let detect = if sensor == Sensor::A { - request.plant[plant].sensor_a - } else { - request.plant[plant].sensor_b - }; - if !detect { - continue; - } - let target = - StandardId::new(plant_id(IDENTIFY_CMD_OFFSET, sensor.into(), (plant +1) as u16)) - .context(">> Could not create address for sensor! (plant: {}) <<")?; - let can_buffer = [0_u8; 0]; - info!("Sending test message to plant {} sensor {sensor:?} with id {}", plant +1, target.as_raw()); - if let Some(frame) = EspTwaiFrame::new(target, &can_buffer) { - // Try a few times; we intentionally ignore rx here and rely on stub logic - let resu = twai - .transmit_async(&frame) - .with_timeout(Duration::from_millis(3000)) - .await; - match resu { - Ok(_) => { - } - Err(err) => { - info!( - "Error sending test message to plant {} sensor {sensor:?}: {err:?}", plant +1 - ); - } - } - } else { - info!("Error building CAN frame"); - } - } - } - - let mut moistures = Moistures::default(); - let _ = wait_for_can_measurements(&mut twai, &mut moistures) - .with_timeout(Duration::from_millis(3000)) - .await; - - - let config = twai.stop().into_blocking(); - self.twai_config.replace(config); - - self.can_power.set_low(); - - - let result = moistures.into(); - - info!("Autodetection result: {result:?}"); - Ok(result) - } - - async fn general_fault(&mut self, enable: bool) { hold_disable(23); self.general_fault.set_level(enable.into()); @@ -482,7 +416,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> { LOG_ACCESS .lock() .await - .log(LogMessage::TestSensor, a, b, &(plant+1).to_string(), "") + .log(LogMessage::TestSensor, a, b, &(plant + 1).to_string(), "") .await; } Timer::after_millis(10).await; @@ -509,8 +443,74 @@ impl<'a> BoardInteraction<'a> for V4<'a> { } Ok(()) } -} + async fn detect_sensors(&mut self, request: Detection) -> FatResult { + self.can_power.set_high(); + let config = self.twai_config.take().expect("twai config not set"); + let mut twai = config.into_async().start(); + + Timer::after_millis(1000).await; + info!("Sending info messages now"); + // Send a few test messages per potential sensor node + for plant in 0..PLANT_COUNT { + for sensor in [Sensor::A, Sensor::B] { + let detect = if sensor == Sensor::A { + request.plant[plant].sensor_a + } else { + request.plant[plant].sensor_b + }; + if !detect { + continue; + } + let target = StandardId::new(plant_id( + IDENTIFY_CMD_OFFSET, + sensor.into(), + (plant + 1) as u16, + )) + .context(">> Could not create address for sensor! (plant: {}) <<")?; + let can_buffer = [0_u8; 0]; + info!( + "Sending test message to plant {} sensor {sensor:?} with id {}", + plant + 1, + target.as_raw() + ); + if let Some(frame) = EspTwaiFrame::new(target, &can_buffer) { + // Try a few times; we intentionally ignore rx here and rely on stub logic + let resu = twai + .transmit_async(&frame) + .with_timeout(Duration::from_millis(3000)) + .await; + match resu { + Ok(_) => {} + Err(err) => { + info!( + "Error sending test message to plant {} sensor {sensor:?}: {err:?}", + plant + 1 + ); + } + } + } else { + info!("Error building CAN frame"); + } + } + } + + let mut moistures = Moistures::default(); + let _ = wait_for_can_measurements(&mut twai, &mut moistures) + .with_timeout(Duration::from_millis(3000)) + .await; + + let config = twai.stop().into_blocking(); + self.twai_config.replace(config); + + self.can_power.set_low(); + + let result = moistures.into(); + + info!("Autodetection result: {result:?}"); + Ok(result) + } +} async fn wait_for_can_measurements( as_async: &mut Twai<'_, Async>, @@ -538,10 +538,12 @@ async fn wait_for_can_measurements( let frequency = u32::from_be_bytes(bytes); match sensor { SensorSlot::A => { - moistures.sensor_a_hz[plant-1] = Some(frequency as f32); + moistures.sensor_a_hz[plant - 1] = + Some(frequency as f32); } SensorSlot::B => { - moistures.sensor_b_hz[plant-1] = Some(frequency as f32); + moistures.sensor_b_hz[plant - 1] = + Some(frequency as f32); } } } else { diff --git a/Software/MainBoard/rust/src/main.rs b/Software/MainBoard/rust/src/main.rs index a686c6e..8704770 100644 --- a/Software/MainBoard/rust/src/main.rs +++ b/Software/MainBoard/rust/src/main.rs @@ -29,8 +29,8 @@ use ::log::{error, info, warn}; use alloc::borrow::ToOwned; use alloc::string::{String, ToString}; use alloc::sync::Arc; -use alloc::{format, vec}; use alloc::vec::Vec; +use alloc::{format, vec}; use chrono::{DateTime, Datelike, Timelike, Utc}; use chrono_tz::Tz::{self, UTC}; use core::sync::atomic::{AtomicBool, Ordering}; @@ -501,16 +501,17 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> { info!("state of charg"); let is_day = board.board_hal.is_day(); - let battery_state = board.board_hal.get_battery_monitor().get_state().await.unwrap_or(BatteryState::Unknown); + let battery_state = board + .board_hal + .get_battery_monitor() + .get_state() + .await + .unwrap_or(BatteryState::Unknown); info!("Battery state is {battery_state:?}"); let state_of_charge = match &battery_state { - BatteryState::Unknown => { - 0 - } - BatteryState::Info(data) => { - data.state_of_charge - } + BatteryState::Unknown => 0, + BatteryState::Info(data) => data.state_of_charge, }; let mut light_state = LightState { @@ -529,22 +530,10 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> { board.board_hal.get_config().night_lamp.night_lamp_hour_end, ); - if state_of_charge - < board - .board_hal - .get_config() - .night_lamp - .low_soc_cutoff - { + if state_of_charge < board.board_hal.get_config().night_lamp.low_soc_cutoff { board.board_hal.get_esp().set_low_voltage_in_cycle(); info!("Set low voltage in cycle"); - } else if state_of_charge - > board - .board_hal - .get_config() - .night_lamp - .low_soc_restore - { + } else if state_of_charge > board.board_hal.get_config().night_lamp.low_soc_restore { board.board_hal.get_esp().clear_low_voltage_in_cycle(); info!("Clear low voltage in cycle"); } @@ -793,7 +782,7 @@ pub async fn do_secure_pump( async fn update_charge_indicator( board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>, -) -> FatResult<()>{ +) -> FatResult<()> { //FIXME add config and code to allow power supply mode, in this case this is a nop //we have mppt controller, ask it for charging current let current = board.board_hal.get_mptt_current().await?; @@ -801,10 +790,9 @@ async fn update_charge_indicator( .board_hal .set_charge_indicator(current.as_milliamperes() > 20_f64) .await?; - Ok(()) + Ok(()) } - async fn publish_tank_state( board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>, tank_state: &TankState, @@ -984,11 +972,7 @@ async fn publish_mppt_state( async fn publish_battery_state( board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>, ) -> () { - let state = board - .board_hal - .get_battery_monitor() - .get_state() - .await; + let state = board.board_hal.get_battery_monitor().get_state().await; let value = match state { Ok(state) => { let json = serde_json::to_string(&state).unwrap().to_owned(); @@ -1021,7 +1005,7 @@ async fn wait_infinity( loop { { let mut board = BOARD_ACCESS.get().await.lock().await; - match update_charge_indicator(&mut board).await{ + match update_charge_indicator(&mut board).await { Ok(_) => {} Err(error) => { if !suppress_further_mppt_error { @@ -1104,35 +1088,38 @@ async fn wait_infinity( } } -async fn handle_serial_config(board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'_>>, serial_config_receive: &AtomicBool, reboot_now: &AtomicBool) -> FatResult<()> { +async fn handle_serial_config( + board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'_>>, + serial_config_receive: &AtomicBool, + reboot_now: &AtomicBool, +) -> FatResult<()> { match board.board_hal.get_esp().read_serial_line().await { - Ok(serial_line) => { - match serial_line { - None => { + Ok(serial_line) => match serial_line { + None => Ok(()), + Some(line) => { + if serial_config_receive.load(Ordering::Relaxed) { + let ll = line.as_str(); + let config: PlantControllerConfig = serde_json::from_str(ll)?; + board + .board_hal + .get_esp() + .save_config(Vec::from(ll.as_bytes())) + .await?; + board.board_hal.set_config(config); + serial_config_receive.store(false, Ordering::Relaxed); + info!("Config received, rebooting"); + board.board_hal.get_esp().set_restart_to_conf(false); + reboot_now.store(true, Ordering::Relaxed); + Ok(()) + } else { + if line == "automation:streamconfig" { + serial_config_receive.store(true, Ordering::Relaxed); + info!("streamconfig:recieving"); + } Ok(()) } - Some(line) => { - if serial_config_receive.load(Ordering::Relaxed) { - let ll = line.as_str(); - let config: PlantControllerConfig = serde_json::from_str(ll)?; - board.board_hal.get_esp().save_config(Vec::from(ll.as_bytes())).await?; - board.board_hal.set_config(config); - serial_config_receive.store(false, Ordering::Relaxed); - info!("Config received, rebooting"); - board.board_hal.get_esp().set_restart_to_conf(false); - reboot_now.store(true, Ordering::Relaxed); - Ok(()) - } else { - if line == "automation:streamconfig" { - serial_config_receive.store(true, Ordering::Relaxed); - info!("streamconfig:recieving"); - } - Ok(()) - } - - } } - } + }, Err(_) => { error!("Error reading serial line"); Ok(()) @@ -1158,7 +1145,7 @@ async fn main(spawner: Spawner) -> ! { } } println!("Hal init done, starting logic"); - + panic!("test"); match safe_main(spawner).await { // this should not get triggered, safe_main should not return but go into deep sleep or reboot Ok(_) => { diff --git a/Software/MainBoard/rust/src/plant_state.rs b/Software/MainBoard/rust/src/plant_state.rs index 0e92eee..26f914b 100644 --- a/Software/MainBoard/rust/src/plant_state.rs +++ b/Software/MainBoard/rust/src/plant_state.rs @@ -16,7 +16,6 @@ pub enum MoistureSensorError { #[derive(Debug, PartialEq, Serialize)] pub enum MoistureSensorState { - Disabled, MoistureValue { raw_hz: f32, moisture_percent: f32 }, SensorError(MoistureSensorError), } @@ -117,12 +116,11 @@ impl PlantState { plant_id: usize, board: &mut HAL<'_>, ) -> Self { - let sensor_a = { //if board.board_hal.get_config().plants[plant_id].sensor_a { + let sensor_a = { + //if board.board_hal.get_config().plants[plant_id].sensor_a { let raw = moistures.sensor_a_hz[plant_id]; match raw { - None => { - MoistureSensorState::SensorError(MoistureSensorError::NoMessage) - } + None => MoistureSensorState::SensorError(MoistureSensorError::NoMessage), Some(raw) => { match map_range_moisture( raw, @@ -141,17 +139,15 @@ impl PlantState { } } } - }; // else { - // MoistureSensorState::Disabled - //}; + // MoistureSensorState::Disabled + //}; - let sensor_b = { //if board.board_hal.get_config().plants[plant_id].sensor_b { + let sensor_b = { + //if board.board_hal.get_config().plants[plant_id].sensor_b { let raw = moistures.sensor_b_hz[plant_id]; match raw { - None => { - MoistureSensorState::SensorError(MoistureSensorError::NoMessage) - } + None => MoistureSensorState::SensorError(MoistureSensorError::NoMessage), Some(raw) => { match map_range_moisture( raw, @@ -171,8 +167,8 @@ impl PlantState { } } }; // else { - // MoistureSensorState::Disabled - //}; + // MoistureSensorState::Disabled + //}; let previous_pump = board.board_hal.get_esp().last_pump_time(plant_id); let consecutive_pump_count = board.board_hal.get_esp().consecutive_pump_count(plant_id); diff --git a/Software/MainBoard/rust/src/webserver/get_json.rs b/Software/MainBoard/rust/src/webserver/get_json.rs index e801b35..107ee90 100644 --- a/Software/MainBoard/rust/src/webserver/get_json.rs +++ b/Software/MainBoard/rust/src/webserver/get_json.rs @@ -5,7 +5,7 @@ use crate::plant_state::{MoistureSensorState, PlantState}; use crate::tank::determine_tank_state; use crate::{get_version, BOARD_ACCESS}; use alloc::format; -use alloc::string::{String, ToString}; +use alloc::string::String; use alloc::vec::Vec; use chrono_tz::Tz; use core::str::FromStr; @@ -43,7 +43,6 @@ where plant_state.push(PlantState::read_hardware_state(moistures, i, &mut board).await); } let a = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_a { - MoistureSensorState::Disabled => "disabled".to_string(), MoistureSensorState::MoistureValue { raw_hz, moisture_percent, @@ -53,7 +52,6 @@ where MoistureSensorState::SensorError(err) => format!("{err:?}"), })); let b = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_b { - MoistureSensorState::Disabled => "disabled".to_string(), MoistureSensorState::MoistureValue { raw_hz, moisture_percent, @@ -128,11 +126,7 @@ pub(crate) async fn get_battery_state( _request: &mut Connection<'_, T, N>, ) -> FatResult> { let mut board = BOARD_ACCESS.get().await.lock().await; - let battery_state = board - .board_hal - .get_battery_monitor() - .get_state() - .await?; + let battery_state = board.board_hal.get_battery_monitor().get_state().await?; Ok(Some(serde_json::to_string(&battery_state)?)) } diff --git a/Software/MainBoard/rust/src/webserver/ota.rs b/Software/MainBoard/rust/src/webserver/ota.rs index c8195df..112e6e1 100644 --- a/Software/MainBoard/rust/src/webserver/ota.rs +++ b/Software/MainBoard/rust/src/webserver/ota.rs @@ -41,7 +41,6 @@ where let mut board = BOARD_ACCESS.get().await.lock().await; board.board_hal.progress(chunk as u32).await; // Erase next block if we are at a 4K boundary (including the first block at offset 0) - info!("erasing and writing block 0x{offset:x}"); board .board_hal .get_esp() diff --git a/Software/MainBoard/rust/src/webserver/post_json.rs b/Software/MainBoard/rust/src/webserver/post_json.rs index e49cac2..c92fa75 100644 --- a/Software/MainBoard/rust/src/webserver/post_json.rs +++ b/Software/MainBoard/rust/src/webserver/post_json.rs @@ -1,6 +1,6 @@ use crate::config::PlantControllerConfig; use crate::fat_error::FatResult; -use crate::hal::{esp_set_time, Detection, DetectionRequest}; +use crate::hal::{esp_set_time, Detection}; use crate::webserver::read_up_to_bytes_from_request; use crate::{do_secure_pump, BOARD_ACCESS}; use alloc::string::{String, ToString}; @@ -142,9 +142,6 @@ where board.board_hal.can_power(can_power_request.state).await?; let enable = can_power_request.state; - info!( - "set can power to {enable}" - ); + info!("set can power to {enable}"); Ok(None) } -