From c429c829b46ac02198a770c958873023efaae20e Mon Sep 17 00:00:00 2001 From: ju6ge Date: Thu, 19 Jun 2025 13:57:36 +0200 Subject: [PATCH] start splitting board hal enum into structs --- rust/src/hal/mod.rs | 712 +++++++++++++++++++++++++++++++++----------- 1 file changed, 538 insertions(+), 174 deletions(-) diff --git a/rust/src/hal/mod.rs b/rust/src/hal/mod.rs index d1ec766..8377e06 100644 --- a/rust/src/hal/mod.rs +++ b/rust/src/hal/mod.rs @@ -1,7 +1,7 @@ -mod esp; pub(crate) mod battery; +mod esp; -use bq34z100::{Bq34z100g1Driver}; +use bq34z100::Bq34z100g1Driver; use crate::log::LogMessage; use ds323x::{DateTimeAccess, Ds323x}; @@ -28,7 +28,7 @@ use esp_idf_sys::{ use once_cell::sync::Lazy; use plant_ctrl2::sipo::ShiftRegister40; -use anyhow::{anyhow}; +use anyhow::anyhow; use anyhow::{bail, Ok, Result}; use serde::{Deserialize, Serialize}; @@ -45,8 +45,15 @@ use crate::hal::BoardHal::{Initial, V3, V4}; use crate::log::log; use embedded_hal::digital::OutputPin; use esp_idf_hal::delay::Delay; -use esp_idf_hal::gpio::{AnyInputPin, Gpio0, Gpio1, Gpio10, Gpio11, Gpio12, Gpio13, Gpio14, Gpio15, Gpio16, Gpio17, Gpio18, Gpio19, Gpio2, Gpio20, Gpio21, Gpio22, Gpio23, Gpio24, Gpio25, Gpio26, Gpio27, Gpio28, Gpio29, Gpio3, Gpio30, Gpio4, Gpio5, Gpio6, Gpio7, Gpio8, IOPin, InputOutput, Level, Output, PinDriver, Pull}; -use esp_idf_hal::pcnt::{PcntChannel, PcntChannelConfig, PcntControlMode, PcntCountMode, PcntDriver, PinIndex, PCNT0}; +use esp_idf_hal::gpio::{ + AnyInputPin, Gpio0, Gpio1, Gpio10, Gpio11, Gpio12, Gpio13, Gpio14, Gpio15, Gpio16, Gpio17, + Gpio18, Gpio19, Gpio2, Gpio20, Gpio21, Gpio22, Gpio23, Gpio24, Gpio25, Gpio26, Gpio27, Gpio28, + Gpio29, Gpio3, Gpio30, Gpio4, Gpio5, Gpio6, Gpio7, Gpio8, IOPin, InputOutput, Level, Output, + PinDriver, Pull, +}; +use esp_idf_hal::pcnt::{ + PcntChannel, PcntChannelConfig, PcntControlMode, PcntCountMode, PcntDriver, PinIndex, PCNT0, +}; use esp_idf_hal::prelude::Peripherals; use esp_idf_hal::reset::ResetReason; use esp_idf_svc::sntp::{self, SyncStatus}; @@ -67,7 +74,6 @@ pub static I2C_DRIVER: Lazy>> = Lazy::new(PlantHal::cre struct V3Constants; impl V3Constants { - const PUMP8_BIT: usize = 0; const PUMP1_BIT: usize = 1; const PUMP2_BIT: usize = 2; @@ -102,9 +108,6 @@ impl V3Constants { const SENSOR_B_8: u8 = 15; } - - - const CHARGING: usize = 14; const AWAKE: usize = 15; @@ -117,10 +120,35 @@ const FAULT_4: usize = 21; const FAULT_1: usize = 22; const FAULT_2: usize = 23; - - const X25: crc::Crc = crc::Crc::::new(&crc::CRC_16_IBM_SDLC); +fn deep_sleep(duration_in_ms: u64) -> ! { + unsafe { + //if we don't do this here, we might just revert newly flashed firmware + mark_app_valid(); + //allow early wakeup by pressing the boot button + if duration_in_ms == 0 { + esp_restart(); + } else { + //configure gpio 1 to wakeup on low, reused boot button for this + esp_sleep_enable_ext1_wakeup( + 0b10u64, + esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ANY_LOW, + ); + esp_deep_sleep(duration_in_ms); + } + }; +} + +fn get_restart_to_conf() -> bool { + unsafe { RESTART_TO_CONF } +} +fn set_restart_to_conf(to_conf: bool) { + unsafe { + RESTART_TO_CONF = to_conf; + } +} + #[link_section = ".rtc.data"] static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT]; #[link_section = ".rtc.data"] @@ -139,71 +167,433 @@ pub enum Sensor { pub struct PlantHal {} - - -pub struct HAL<'a>{ +pub struct HAL<'a> { pub config: PlantControllerConfig, - pub board_hal: BoardHal<'a>, + pub board_hal: Box, pub esp: ESP<'a>, - pub battery_monitor: BatteryMonitor<'a> + pub battery_monitor: BatteryMonitor<'a>, } +pub struct Initial { + general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, +} +impl BoardInteraction for Initial { + fn set_charge_indicator(&mut self, charging: bool) -> Result<()> { + bail!("Please configure board revision") + } -pub enum BoardHal<'a>{ - Initial { - general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput> - }, - V3 { - shift_register: ShiftRegister40< - PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - >, - shift_register_enable_invert: - PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Output>, - tank_channel: AdcChannelDriver<'a, Gpio5, AdcDriver<'a, esp_idf_hal::adc::ADC1>>, - solar_is_day: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Input>, - light: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - main_pump: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - tank_power: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - signal_counter: PcntDriver<'a>, - one_wire_bus: OneWire>, - rtc: - Ds323x>>, ds323x::ic::DS3231>, - eeprom: Eeprom24x< - MutexDevice<'a, I2cDriver<'a>>, - eeprom24x::page_size::B32, - eeprom24x::addr_size::TwoBytes, - eeprom24x::unique_serial::No, - >, - }, - V4 { - tank_channel: AdcChannelDriver<'a, Gpio5, AdcDriver<'a, esp_idf_hal::adc::ADC1>>, - solar_is_day: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Input>, - signal_counter: PcntDriver<'a>, - charge_indicator: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - awake: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, Output>, - light: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - tank_power: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - one_wire_bus: OneWire>, - rtc: - Ds323x>>, ds323x::ic::DS3231>, - eeprom: Eeprom24x< - MutexDevice<'a, I2cDriver<'a>>, - eeprom24x::page_size::B32, - eeprom24x::addr_size::TwoBytes, - eeprom24x::unique_serial::No, - >, - general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - pump_expander: Pca9535Immediate>>, - sensor_expander: Pca9535Immediate>>, + fn deep_sleep(&mut self, duration_in_ms: u64) -> ! { + deep_sleep(duration_in_ms) + } + + fn get_backup_info(&mut self) -> Result { + bail!("Please configure board revision") + } + + fn get_backup_config(&mut self) -> Result> { + bail!("Please configure board revision") + } + + fn backup_config(&mut self, bytes: &[u8]) -> Result<()> { + bail!("Please configure board revision") + } + + fn is_day(&self) -> bool { + bail!("Please configure board revision") + } + + fn water_temperature_c(&mut self) -> Result { + bail!("Please configure board revision") + } + + fn tank_sensor_voltage(&mut self) -> Result { + bail!("Please configure board revision") + } + + fn set_low_voltage_in_cycle(&mut self) { + bail!("Please configure board revision") + } + + fn clear_low_voltage_in_cycle(&mut self) { + bail!("Please configure board revision") + } + + fn light(&mut self, enable: bool) -> Result<()> { + bail!("Please configure board revision") + } + + fn pump(&mut self, plant: usize, enable: bool) -> Result<()> { + bail!("Please configure board revision") + } + + fn last_pump_time(&self, plant: usize) -> Option> { + bail!("Please configure board revision") + } + + fn store_last_pump_time(&mut self, plant: usize, time: DateTime) { + bail!("Please configure board revision") + } + + fn store_consecutive_pump_count(&mut self, plant: usize, count: u32) { + bail!("Please configure board revision") + } + + fn consecutive_pump_count(&mut self, plant: usize) -> u32 { + bail!("Please configure board revision") + } + + fn fault(&mut self, plant: usize, enable: bool) -> Result<()> { + bail!("Please configure board revision") + } + + fn low_voltage_in_cycle(&mut self) -> bool { + bail!("Please configure board revision") + } + + fn any_pump(&mut self, enable: bool) -> Result<()> { + bail!("Please configure board revision") + } + + fn time(&mut self) -> Result> { + bail!("Please configure board revision") + } + + fn sntp(&mut self, max_wait_ms: u32) -> Result> { + bail!("Please configure board revision") + } + + fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result { + bail!("Please configure board revision") + } + + fn general_fault(&mut self, enable: bool) { + let _ = self.general_fault.set_state(enable.into()); + } + + fn mode_override_pressed(&mut self) -> bool { + bail!("Please configure board revision") + } + + fn factory_reset(&mut self) -> Result<()> { + bail!("Please configure board revision") + } + + fn get_rtc_time(&mut self) -> Result> { + bail!("Please configure board revision") + } + + fn set_rtc_time(&mut self, time: &DateTime) -> Result<()> { + bail!("Please configure board revision") + } + + fn wifi_scan(&mut self) -> Result> { + bail!("Please configure board revision") + } + + fn test_pump(&mut self, plant: usize) -> Result<()> { + bail!("Please configure board revision") + } + + fn test(&mut self) -> Result<()> { + bail!("Please configure board revision") + } + + fn get_restart_to_conf(&mut self) -> bool { + get_restart_to_conf() + } + + fn set_restart_to_conf(&mut self, to_conf: bool) { + set_restart_to_conf(to_conf); } } +pub struct V3 { + shift_register: ShiftRegister40< + PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + >, + shift_register_enable_invert: + PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Output>, + tank_channel: AdcChannelDriver<'a, Gpio5, AdcDriver<'a, esp_idf_hal::adc::ADC1>>, + solar_is_day: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Input>, + light: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + main_pump: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + tank_power: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + signal_counter: PcntDriver<'a>, + one_wire_bus: OneWire>, + rtc: + Ds323x>>, ds323x::ic::DS3231>, + eeprom: Eeprom24x< + MutexDevice<'a, I2cDriver<'a>>, + eeprom24x::page_size::B32, + eeprom24x::addr_size::TwoBytes, + eeprom24x::unique_serial::No, + >, +} +impl BoardInteraction for V3 { + fn set_charge_indicator(&mut self, charging: bool) -> Result<()> { + Ok(self.shift_register.decompose()[CHARGING].set_state(charging.into())?) + } + fn deep_sleep(&mut self, duration_in_ms: u64) -> ! { + let _ = self.shift_register.decompose()[AWAKE].set_low(); + deep_sleep(duration_in_ms) + } + + fn get_backup_info(&mut self) -> Result { + let store = bincode::serialize(&BackupHeader::default())?.len(); + let mut header_page_buffer = vec![0_u8; store]; + + self.eeprom + .read_data(0, &mut header_page_buffer) + .map_err(|err| bail!("Error reading eeprom header {:?}", err))?; + + println!("Raw header is {:?} with size {}", header_page_buffer, store); + let header: BackupHeader = bincode::deserialize(&header_page_buffer)?; + Ok(header) + } + + fn get_backup_config(&mut self) -> Result> { + let store = bincode::serialize(&BackupHeader::default())?.len(); + let mut header_page_buffer = vec![0_u8; store]; + + self.eeprom + .read_data(0, &mut header_page_buffer) + .map_err(|err| bail!("Error reading eeprom header {:?}", err))?; + + let header: BackupHeader = bincode::deserialize(&header_page_buffer)?; + + //skip page 0, used by the header + let data_start_address = eeprom.page_size() as u32; + let mut data_buffer = vec![0_u8; header.size]; + self.eeprom + .read_data(data_start_address, &mut data_buffer) + .map_err(|err| bail!("Error reading eeprom data {:?}", err))?; + + let checksum = X25.checksum(&data_buffer); + if checksum != header.crc16 { + bail!( + "Invalid checksum, got {} but expected {}", + checksum, + header.crc16 + ); + } + + Ok(data_buffer) + } + + fn backup_config(&mut self, bytes: &[u8]) -> Result<()> { + let time = self.get_rtc_time()?.timestamp_millis(); + + let delay = Delay::new_default(); + + let checksum = X25.checksum(bytes); + let page_size = eeprom.page_size(); + + let header = BackupHeader { + crc16: checksum, + timestamp: time, + size: bytes.len(), + }; + + let encoded = bincode::serialize(&header)?; + if encoded.len() > page_size { + bail!( + "Size limit reached header is {}, but firest page is only {}", + encoded.len(), + page_size + ) + } + let as_u8: &[u8] = &encoded; + + match self.eeprom.write_page(0, as_u8) { + OkStd(_) => {} + Err(err) => bail!("Error writing eeprom {:?}", err), + }; + delay.delay_ms(5); + + let to_write = bytes.chunks(page_size); + + let mut lastiter = 0; + let mut current_page = 1; + for chunk in to_write { + let address = current_page * page_size as u32; + self.eeprom + .write_page(address, chunk) + .map_err(|err| bail!("Error writing eeprom {:?}", err))?; + current_page += 1; + + let iter = (current_page % 8) as usize; + if iter != lastiter { + for i in 0..PLANT_COUNT { + let _ = self.fault(i, iter == i); + } + lastiter = iter; + } + + delay.delay_ms(5); + } + Ok(()) + } + + fn is_day(&self) -> bool { + self.solar_is_day.get_level().into() + } + + fn water_temperature_c(&mut self) -> Result { + self.one_wire_bus + .reset(&mut self.esp.delay) + .map_err(|err| -> anyhow::Error { anyhow!("Missing attribute: {:?}", err) })?; + let first = one_wire_bus.devices(false, &mut self.esp.delay).next(); + if first.is_none() { + bail!("Not found any one wire Ds18b20"); + } + let device_address = first + .unwrap() + .map_err(|err| -> anyhow::Error { anyhow!("Missing attribute: {:?}", err) })?; + + let water_temp_sensor = Ds18b20::new::(device_address) + .map_err(|err| -> anyhow::Error { anyhow!("Missing attribute: {:?}", err) })?; + + water_temp_sensor + .start_temp_measurement(one_wire_bus, &mut self.esp.delay) + .map_err(|err| -> anyhow::Error { anyhow!("Missing attribute: {:?}", err) })?; + ds18b20::Resolution::Bits12.delay_for_measurement_time(&mut self.esp.delay); + let sensor_data = water_temp_sensor + .read_data(one_wire_bus, &mut self.esp.delay) + .map_err(|err| -> anyhow::Error { anyhow!("Missing attribute: {:?}", err) })?; + if sensor_data.temperature == 85_f32 { + bail!("Ds18b20 dummy temperature returned"); + } + Ok(sensor_data.temperature / 10_f32) + } + + fn tank_sensor_voltage(&mut self) -> Result { + todo!() + } + + fn set_low_voltage_in_cycle(&mut self) { + todo!() + } + + fn clear_low_voltage_in_cycle(&mut self) { + todo!() + } + + fn light(&mut self, enable: bool) -> Result<()> { + todo!() + } + + fn pump(&mut self, plant: usize, enable: bool) -> Result<()> { + todo!() + } + + fn last_pump_time(&self, plant: usize) -> Option> { + todo!() + } + + fn store_last_pump_time(&mut self, plant: usize, time: DateTime) { + todo!() + } + + fn store_consecutive_pump_count(&mut self, plant: usize, count: u32) { + todo!() + } + + fn consecutive_pump_count(&mut self, plant: usize) -> u32 { + todo!() + } + + fn fault(&mut self, plant: usize, enable: bool) -> Result<()> { + todo!() + } + + fn low_voltage_in_cycle(&mut self) -> bool { + todo!() + } + + fn any_pump(&mut self, enable: bool) -> Result<()> { + todo!() + } + + fn time(&mut self) -> Result> { + todo!() + } + + fn sntp(&mut self, max_wait_ms: u32) -> Result> { + todo!() + } + + fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result { + todo!() + } + + fn general_fault(&mut self, enable: bool) { + todo!() + } + + fn mode_override_pressed(&mut self) -> bool { + todo!() + } + + fn factory_reset(&mut self) -> Result<()> { + todo!() + } + + fn get_rtc_time(&mut self) -> Result> { + todo!() + } + + fn set_rtc_time(&mut self, time: &DateTime) -> Result<()> { + todo!() + } + + fn wifi_scan(&mut self) -> Result> { + todo!() + } + + fn test_pump(&mut self, plant: usize) -> Result<()> { + todo!() + } + + fn test(&mut self) -> Result<()> { + todo!() + } + + fn get_restart_to_conf(&mut self) -> bool { + todo!() + } + + fn set_restart_to_conf(&mut self, to_conf: bool) { + todo!() + } +} + +pub struct V4 { + tank_channel: AdcChannelDriver<'a, Gpio5, AdcDriver<'a, esp_idf_hal::adc::ADC1>>, + solar_is_day: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Input>, + signal_counter: PcntDriver<'a>, + charge_indicator: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + awake: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, Output>, + light: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + tank_power: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + one_wire_bus: OneWire>, + rtc: + Ds323x>>, ds323x::ic::DS3231>, + eeprom: Eeprom24x< + MutexDevice<'a, I2cDriver<'a>>, + eeprom24x::page_size::B32, + eeprom24x::addr_size::TwoBytes, + eeprom24x::unique_serial::No, + >, + general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, + pump_expander: Pca9535Immediate>>, + sensor_expander: Pca9535Immediate>>, +} #[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct BackupHeader { @@ -212,6 +602,16 @@ pub struct BackupHeader { pub size: usize, } +impl Default for BackupHeader { + fn default() -> Self { + Self { + timestamp: Default::default(), + crc16: Default::default(), + size: Default::default(), + } + } +} + impl BoardInteraction for HAL<'_> { fn set_charge_indicator(&mut self, charging: bool) { match &mut self.board_hal { @@ -220,12 +620,12 @@ impl BoardInteraction for HAL<'_> { .set_state(charging.into()) .unwrap(); } - V4 { charge_indicator , ..} => { + V4 { + charge_indicator, .. + } => { charge_indicator.set_state(charging.into()).unwrap(); - }, - Initial { .. } => { - } + Initial { .. } => {} } } fn deep_sleep(&mut self, duration_in_ms: u64) -> ! { @@ -233,12 +633,10 @@ impl BoardInteraction for HAL<'_> { V3 { shift_register, .. } => { shift_register.decompose()[AWAKE].set_low().unwrap(); } - V4 { awake, .. } => { + V4 { awake, .. } => { awake.set_low().unwrap(); - }, - Initial { .. } => { - } + Initial { .. } => {} } unsafe { @@ -259,8 +657,8 @@ impl BoardInteraction for HAL<'_> { } fn get_backup_info(&mut self) -> Result { let eeprom = match &mut self.board_hal { - V3 { eeprom, .. } => {eeprom} - V4 { eeprom, .. } => {eeprom }, + V3 { eeprom, .. } => eeprom, + V4 { eeprom, .. } => eeprom, &mut Initial { .. } => { bail!("Board not configured yet") } @@ -283,8 +681,8 @@ impl BoardInteraction for HAL<'_> { } fn get_backup_config(&mut self) -> Result> { let eeprom = match &mut self.board_hal { - V3 { eeprom, .. } => {eeprom} - V4 { eeprom, .. } => {eeprom } + V3 { eeprom, .. } => eeprom, + V4 { eeprom, .. } => eeprom, &mut Initial { .. } => { bail!("Board not configured yet") } @@ -326,10 +724,8 @@ impl BoardInteraction for HAL<'_> { fn backup_config(&mut self, bytes: &[u8]) -> Result<()> { let time = self.get_rtc_time()?.timestamp_millis(); let eeprom = match &mut self.board_hal { - V3 { eeprom, .. } => { - eeprom - } - V4 { eeprom, .. } => { eeprom }, + V3 { eeprom, .. } => eeprom, + V4 { eeprom, .. } => eeprom, &mut Initial { .. } => { bail!("Board not configured yet") } @@ -369,10 +765,8 @@ impl BoardInteraction for HAL<'_> { for chunk in to_write { let address = current_page * page_size as u32; let eeprom = match &mut self.board_hal { - V3 { eeprom, .. } => { - eeprom - } - V4 { eeprom, .. } => { eeprom } + V3 { eeprom, .. } => eeprom, + V4 { eeprom, .. } => eeprom, &mut Initial { .. } => { bail!("Board not configured yet") } @@ -396,13 +790,11 @@ impl BoardInteraction for HAL<'_> { } Ok(()) } - fn is_day(& self) -> bool { - match & self.board_hal { - V3 { solar_is_day, .. } => {solar_is_day.get_level().into()} - V4 { solar_is_day, .. } => {solar_is_day.get_level().into() } - Initial { .. } => { - false - } + fn is_day(&self) -> bool { + match &self.board_hal { + V3 { solar_is_day, .. } => solar_is_day.get_level().into(), + V4 { solar_is_day, .. } => solar_is_day.get_level().into(), + Initial { .. } => false, } } //should be multsampled @@ -444,14 +836,21 @@ impl BoardInteraction for HAL<'_> { /// return median tank sensor value in milli volt fn tank_sensor_voltage(&mut self) -> Result { let (tank_power, tank_channel) = match &mut self.board_hal { - V3 { tank_power, tank_channel, .. } => {(tank_power,tank_channel)} - V4 { tank_power, tank_channel, .. } => {(tank_power,tank_channel) } + V3 { + tank_power, + tank_channel, + .. + } => (tank_power, tank_channel), + V4 { + tank_power, + tank_channel, + .. + } => (tank_power, tank_channel), &mut Initial { .. } => { bail!("Board not configured yet") } }; - tank_power.set_high()?; //let stabilize self.esp.delay.delay_ms(100); @@ -508,13 +907,13 @@ impl BoardInteraction for HAL<'_> { //currently infallible error, keep for future as result anyway shift_register.decompose()[index].set_state(enable.into())?; } - V4 { pump_expander, .. } => { + V4 { pump_expander, .. } => { if enable { pump_expander.pin_set_high(GPIOBank::Bank0, plant.try_into()?)?; } else { pump_expander.pin_set_low(GPIOBank::Bank0, plant.try_into()?)?; } - }, + } &mut Initial { .. } => { bail!("Board not configured yet") } @@ -539,7 +938,7 @@ impl BoardInteraction for HAL<'_> { fn consecutive_pump_count(&mut self, plant: usize) -> u32 { unsafe { CONSECUTIVE_WATERING_PLANT[plant] } } - fn fault(&mut self, plant: usize, enable: bool) -> Result<()>{ + fn fault(&mut self, plant: usize, enable: bool) -> Result<()> { match &mut self.board_hal { V3 { shift_register, .. } => { let index = match plant { @@ -553,8 +952,7 @@ impl BoardInteraction for HAL<'_> { 7 => FAULT_8, _ => panic!("Invalid plant id {}", plant), }; - shift_register.decompose()[index] - .set_state(enable.into())?; + shift_register.decompose()[index].set_state(enable.into())?; } V4 { pump_expander, .. } => { if enable { @@ -562,7 +960,6 @@ impl BoardInteraction for HAL<'_> { } else { pump_expander.pin_set_low(GPIOBank::Bank1, plant.try_into()?)?; } - } &mut Initial { .. } => { bail!("Board not configured yet") @@ -586,7 +983,6 @@ impl BoardInteraction for HAL<'_> { } } Ok(()) - } fn time(&mut self) -> Result> { let time = EspSystemTime {}.now().as_millis(); @@ -611,7 +1007,11 @@ impl BoardInteraction for HAL<'_> { } fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result { match &mut self.board_hal { - V3{ signal_counter, shift_register, .. } => { + V3 { + signal_counter, + shift_register, + .. + } => { let mut results = [0_f32; REPEAT_MOIST_MEASURE]; for repeat in 0..REPEAT_MOIST_MEASURE { signal_counter.counter_pause()?; @@ -644,7 +1044,6 @@ impl BoardInteraction for HAL<'_> { }, }; - let is_bit_set = |b: u8| -> bool { sensor_channel & (1 << b) != 0 }; let pin_0 = &mut shift_register.decompose()[V3Constants::MS_0]; let pin_1 = &mut shift_register.decompose()[V3Constants::MS_1]; @@ -702,14 +1101,17 @@ impl BoardInteraction for HAL<'_> { let mid = results.len() / 2; let median = results[mid]; Ok(median) - }, - V4 {sensor_expander, signal_counter, ..} => { + } + V4 { + sensor_expander, + signal_counter, + .. + } => { let mut results = [0_f32; REPEAT_MOIST_MEASURE]; for repeat in 0..REPEAT_MOIST_MEASURE { signal_counter.counter_pause()?; signal_counter.counter_clear()?; - const MS0: u8 = 1_u8; const MS1: u8 = 0_u8; const MS2: u8 = 3_u8; @@ -720,16 +1122,10 @@ impl BoardInteraction for HAL<'_> { sensor_expander.pin_set_high(GPIOBank::Bank0, MS4)?; let sensor_channel = match sensor { - Sensor::A =>{ - plant as u32 - }, - Sensor::B => { - (15 - plant) as u32 - }, + Sensor::A => plant as u32, + Sensor::B => (15 - plant) as u32, }; - - let is_bit_set = |b: u8| -> bool { sensor_channel & (1 << b) != 0 }; if is_bit_set(0) { sensor_expander.pin_set_high(GPIOBank::Bank0, MS0)?; @@ -792,13 +1188,12 @@ impl BoardInteraction for HAL<'_> { bail!("Not implemented for this board") } } - } fn general_fault(&mut self, enable: bool) { let general_fault = match &mut self.board_hal { - V3 { general_fault, .. } => {general_fault} - V4 { general_fault, .. } => {general_fault}, - Initial { general_fault, .. } => {general_fault} + V3 { general_fault, .. } => general_fault, + V4 { general_fault, .. } => general_fault, + Initial { general_fault, .. } => general_fault, }; unsafe { gpio_hold_dis(general_fault.pin()) }; general_fault.set_state(enable.into()).unwrap(); @@ -819,8 +1214,8 @@ impl BoardInteraction for HAL<'_> { } fn get_rtc_time(&mut self) -> Result> { let rtc = match &mut self.board_hal { - V3 { rtc, .. } => {rtc} - V4 { rtc, .. } => {rtc}, + V3 { rtc, .. } => rtc, + V4 { rtc, .. } => rtc, Initial { .. } => { bail!("Board not configured yet") } @@ -834,8 +1229,8 @@ impl BoardInteraction for HAL<'_> { } fn set_rtc_time(&mut self, time: &DateTime) -> Result<()> { let rtc = match &mut self.board_hal { - V3 { rtc, .. } => {rtc} - V4 { rtc, .. } => {rtc} + V3 { rtc, .. } => rtc, + V4 { rtc, .. } => rtc, Initial { .. } => { bail!("Board not configured yet") } @@ -908,21 +1303,10 @@ impl BoardInteraction for HAL<'_> { Delay::new_default().delay_ms(10); Ok(()) } - - fn get_restart_to_conf(&mut self) -> bool { - unsafe { RESTART_TO_CONF } - } - fn set_restart_to_conf(&mut self, to_conf: bool) { - unsafe { - RESTART_TO_CONF = to_conf; - } - } } - - pub trait BoardInteraction { - fn set_charge_indicator(&mut self, charging: bool); + fn set_charge_indicator(&mut self, charging: bool) -> Result<()>; fn deep_sleep(&mut self, duration_in_ms: u64) -> !; fn get_backup_info(&mut self) -> Result; fn get_backup_config(&mut self) -> Result>; @@ -956,11 +1340,8 @@ pub trait BoardInteraction { fn test(&mut self) -> Result<()>; fn get_restart_to_conf(&mut self) -> bool; fn set_restart_to_conf(&mut self, to_conf: bool); - } - - pub struct FreePeripherals { pub gpio0: Gpio0, pub gpio1: Gpio1, @@ -996,7 +1377,6 @@ pub struct FreePeripherals { pub adc1: ADC1, } - impl PlantHal { fn create_i2c() -> Mutex> { let peripherals = unsafe { Peripherals::new() }; @@ -1014,14 +1394,12 @@ impl PlantHal { Mutex::new(I2cDriver::new(i2c, sda, scl, &config).unwrap()) } - - pub fn create() -> Result>> { + pub fn create() -> Result>> { let peripherals = Peripherals::take()?; let sys_loop = EspSystemEventLoop::take()?; let nvs = EspDefaultNvsPartition::take()?; let wifi_driver = EspWifi::new(peripherals.modem, sys_loop, Some(nvs))?; - let mut boot_button = PinDriver::input(peripherals.pins.gpio9.downgrade())?; boot_button.set_pull(Pull::Floating)?; @@ -1062,10 +1440,9 @@ impl PlantHal { mqtt_client: None, wifi_driver, boot_button, - delay: Delay::new(1000) + delay: Delay::new(1000), }; - //init,reset rtc memory depending on cause let mut init_rtc_store: bool = false; let mut to_config_mode: bool = false; @@ -1104,9 +1481,10 @@ impl PlantHal { let config = esp.get_config(); let hal = match config { Result::Ok(config) => { - let board_hal : BoardHal = match config.hardware.board { + let board_hal: BoardHal = match config.hardware.board { BoardVersion::INITIAL => { - let mut general_fault = PinDriver::input_output(free_pins.gpio6.downgrade())?; + let mut general_fault = + PinDriver::input_output(free_pins.gpio6.downgrade())?; general_fault.set_pull(Pull::Floating)?; general_fault.set_low()?; @@ -1114,13 +1492,14 @@ impl PlantHal { general_fault.set_high()? } - Initial { general_fault}}, - BoardVersion::V3 => {PlantHal::create_v3(free_pins)?}, - BoardVersion::V4 => {PlantHal::create_v4(free_pins)?} + Initial { general_fault } + } + BoardVersion::V3 => PlantHal::create_v3(free_pins)?, + BoardVersion::V4 => PlantHal::create_v4(free_pins)?, }; - let battery_monitor : BatteryMonitor = match config.hardware.battery { - BatteryBoardVersion::Disabled => { BatteryMonitor::Disabled {}} + let battery_monitor: BatteryMonitor = match config.hardware.battery { + BatteryBoardVersion::Disabled => BatteryMonitor::Disabled {}, BatteryBoardVersion::BQ34Z100G1 => { let mut battery_driver = Bq34z100g1Driver { i2c: MutexDevice::new(&I2C_DRIVER), @@ -1142,17 +1521,14 @@ impl PlantHal { } BatteryMonitor::BQ34Z100G1 { battery_driver } } - BatteryBoardVersion::WchI2cSlave => { - BatteryMonitor::WchI2cSlave {} - } + BatteryBoardVersion::WchI2cSlave => BatteryMonitor::WchI2cSlave {}, }; - - HAL{ + HAL { config, board_hal, esp, - battery_monitor + battery_monitor, } } Err(err) => { @@ -1168,9 +1544,9 @@ impl PlantHal { general_fault.set_pull(Pull::Floating)?; general_fault.set_low()?; - HAL{ + HAL { config: Default::default(), - board_hal: Initial { general_fault}, + board_hal: Initial { general_fault }, esp, battery_monitor: BatteryMonitor::Disabled {}, } @@ -1205,7 +1581,6 @@ impl PlantHal { let one_wire_bus = OneWire::new(one_wire_pin) .map_err(|err| -> anyhow::Error { anyhow!("Missing attribute: {:?}", err) })?; - let rtc_time = rtc.datetime(); match rtc_time { OkStd(tt) => { @@ -1224,7 +1599,6 @@ impl PlantHal { } } - let mut signal_counter = PcntDriver::new( peripherals.pcnt0, Some(peripherals.gpio22), @@ -1269,11 +1643,10 @@ impl PlantHal { charge_indicator.set_pull(Pull::Floating)?; charge_indicator.set_low()?; - let mut pump_expander = Pca9535Immediate::new(MutexDevice::new(&I2C_DRIVER), 32); //todo error handing if init error - for pin in 0..8{ + for pin in 0..8 { 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); @@ -1281,7 +1654,7 @@ impl PlantHal { } let mut sensor_expander = Pca9535Immediate::new(MutexDevice::new(&I2C_DRIVER), 34); - for pin in 0..8{ + for pin in 0..8 { let _ = sensor_expander.pin_into_output(GPIOBank::Bank0, pin); let _ = sensor_expander.pin_into_output(GPIOBank::Bank1, pin); let _ = sensor_expander.pin_set_low(GPIOBank::Bank0, pin); @@ -1301,7 +1674,7 @@ impl PlantHal { general_fault, pump_expander, sensor_expander, - charge_indicator + charge_indicator, }) } @@ -1338,7 +1711,6 @@ impl PlantHal { println!("Init battery driver"); - println!("Init rtc driver"); let mut rtc = Ds323x::new_ds3231(MutexDevice::new(&I2C_DRIVER)); @@ -1371,7 +1743,6 @@ impl PlantHal { } } - let mut signal_counter = PcntDriver::new( peripherals.pcnt0, Some(peripherals.gpio22), @@ -1394,8 +1765,6 @@ impl PlantHal { }, )?; - - let adc_config = AdcChannelConfig { attenuation: attenuation::DB_11, resolution: Resolution::Resolution12Bit, @@ -1408,8 +1777,6 @@ impl PlantHal { let mut solar_is_day = PinDriver::input(peripherals.gpio7.downgrade())?; solar_is_day.set_pull(Pull::Floating)?; - - let mut light = PinDriver::input_output(peripherals.gpio10.downgrade())?; light.set_pull(Pull::Floating)?; @@ -1425,15 +1792,12 @@ impl PlantHal { let one_wire_bus = OneWire::new(one_wire_pin) .map_err(|err| -> anyhow::Error { anyhow!("Missing attribute: {:?}", err) })?; - let mut shift_register_enable_invert = PinDriver::output(peripherals.gpio21.downgrade())?; - unsafe { gpio_hold_dis(shift_register_enable_invert.pin()) }; shift_register_enable_invert.set_low()?; unsafe { gpio_hold_en(shift_register_enable_invert.pin()) }; - Ok(BoardHal::V3 { shift_register, shift_register_enable_invert,