From 7ebc147f5154b5489daadfc5d3bf90bc1cf17b7e Mon Sep 17 00:00:00 2001 From: Empire Phoenix Date: Sun, 28 Sep 2025 13:42:30 +0200 Subject: [PATCH] v3 wip --- .../inspectionProfiles/Project_Default.xml | 1 + rust/Cargo.toml | 22 +- rust/scratch/v3_hal.rs | 434 ------------------ rust/src/fat_error.rs | 6 + rust/src/hal/esp.rs | 71 ++- rust/src/hal/initial_hal.rs | 4 +- rust/src/hal/mod.rs | 30 +- rust/src/hal/v3_hal.rs | 429 +++++++++++++++++ rust/src/hal/v4_hal.rs | 72 ++- rust/src/main.rs | 5 +- rust/src/sipo.rs | 20 +- rust/src/webserver/mod.rs | 32 +- 12 files changed, 590 insertions(+), 536 deletions(-) delete mode 100644 rust/scratch/v3_hal.rs create mode 100644 rust/src/hal/v3_hal.rs diff --git a/rust/.idea/inspectionProfiles/Project_Default.xml b/rust/.idea/inspectionProfiles/Project_Default.xml index 3fe75f2..656b6be 100644 --- a/rust/.idea/inspectionProfiles/Project_Default.xml +++ b/rust/.idea/inspectionProfiles/Project_Default.xml @@ -7,5 +7,6 @@ + \ No newline at end of file diff --git a/rust/Cargo.toml b/rust/Cargo.toml index ae96c6a..8a67bd1 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -26,19 +26,29 @@ command = [ "partitions.csv" ] +#this strips the bootloader, we need that tho +#strip = true +[profile.dev] lto = "fat" -strip = true debug = false overflow-checks = true panic = "abort" incremental = true opt-level = "z" +[profile.release] +lto = "fat" +#debug = false +overflow-checks = true +panic = "abort" +incremental = false +opt-level = "z" [package.metadata.espflash] partition_table = "partitions.csv" + [dependencies] #ESP stuff esp-bootloader-esp-idf = { version = "0.2.0", features = ["esp32c6"] } @@ -106,7 +116,6 @@ smoltcp = { version = "0.12.0", default-features = false, features = [ ] } #static_cell = "2.1.1" embedded-hal = "1.0.0" -heapless = { version = "0.8", features = ["serde"] } embedded-hal-bus = { version = "0.3.0" } #Hardware additional driver @@ -148,8 +157,15 @@ bincode = { version = "2.0.1", default-features = false, features = ["derive"] } sntpc = { version = "0.6.0", default-features = false, features = ["log", "embassy-socket", "embassy-socket-ipv6"] } option-lock = { version = "0.3.1", default-features = false } +#stay in sync with mcutie version here! +heapless = { version = "0.7.17", features = ["serde"] } +mcutie = { version = "0.3.0", default-features = false } + + + [patch.crates-io] +mcutie = { git = 'https://github.com/empirephoenix/mcutie.git' } #bq34z100 = { path = "../../bq34z100_rust" } [build-dependencies] -vergen = { version = "8.2.6", features = ["build", "git", "gitcl"] } +vergen = { version = "8.2.6", features = ["build", "git", "gitcl"] } \ No newline at end of file diff --git a/rust/scratch/v3_hal.rs b/rust/scratch/v3_hal.rs deleted file mode 100644 index 1508407..0000000 --- a/rust/scratch/v3_hal.rs +++ /dev/null @@ -1,434 +0,0 @@ -use crate::hal::rtc::RTCModuleInteraction; -use crate::hal::water::TankSensor; -use crate::hal::{ - deep_sleep, BoardInteraction, FreePeripherals, Sensor, PLANT_COUNT, -}; -use crate::log::{log, LogMessage}; -use crate::{ - config::PlantControllerConfig, - hal::{battery::BatteryInteraction, esp::Esp}, -}; -use anyhow::{bail, Ok, Result}; -use embedded_hal::digital::OutputPin; -use measurements::{Current, Voltage}; -use plant_ctrl2::sipo::ShiftRegister40; -use core::result::Result::Ok as OkStd; -use alloc::string::ToString; -use alloc::boxed::Box; -use esp_hall::gpio::Pull; - -const PUMP8_BIT: usize = 0; -const PUMP1_BIT: usize = 1; -const PUMP2_BIT: usize = 2; -const PUMP3_BIT: usize = 3; -const PUMP4_BIT: usize = 4; -const PUMP5_BIT: usize = 5; -const PUMP6_BIT: usize = 6; -const PUMP7_BIT: usize = 7; -const MS_0: usize = 8; -const MS_4: usize = 9; -const MS_2: usize = 10; -const MS_3: usize = 11; -const MS_1: usize = 13; -const SENSOR_ON: usize = 12; - -const SENSOR_A_1: u8 = 7; -const SENSOR_A_2: u8 = 6; -const SENSOR_A_3: u8 = 5; -const SENSOR_A_4: u8 = 4; -const SENSOR_A_5: u8 = 3; -const SENSOR_A_6: u8 = 2; -const SENSOR_A_7: u8 = 1; -const SENSOR_A_8: u8 = 0; - -const SENSOR_B_1: u8 = 8; -const SENSOR_B_2: u8 = 9; -const SENSOR_B_3: u8 = 10; -const SENSOR_B_4: u8 = 11; -const SENSOR_B_5: u8 = 12; -const SENSOR_B_6: u8 = 13; -const SENSOR_B_7: u8 = 14; -const SENSOR_B_8: u8 = 15; - -const CHARGING: usize = 14; -const AWAKE: usize = 15; - -const FAULT_3: usize = 16; -const FAULT_8: usize = 17; -const FAULT_7: usize = 18; -const FAULT_6: usize = 19; -const FAULT_5: usize = 20; -const FAULT_4: usize = 21; -const FAULT_1: usize = 22; -const FAULT_2: usize = 23; - -const REPEAT_MOIST_MEASURE: usize = 1; - - -pub struct V3<'a> { - config: PlantControllerConfig, - battery_monitor: Box, - rtc_module: Box, - esp: Esp<'a>, - 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_sensor: TankSensor<'a>, - 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>, - general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, - signal_counter: PcntDriver<'a>, -} - -pub(crate) fn create_v3( - peripherals: FreePeripherals, - esp: Esp<'static>, - config: PlantControllerConfig, - battery_monitor: Box, - rtc_module: Box, -) -> Result + Send>> { - log::info!("Start v3"); - let mut clock = PinDriver::input_output(peripherals.gpio15.downgrade())?; - clock.set_pull(Pull::Floating)?; - let mut latch = PinDriver::input_output(peripherals.gpio3.downgrade())?; - latch.set_pull(Pull::Floating)?; - let mut data = PinDriver::input_output(peripherals.gpio23.downgrade())?; - data.set_pull(Pull::Floating)?; - let shift_register = ShiftRegister40::new(clock, latch, data); - //disable all - for mut pin in shift_register.decompose() { - pin.set_low()?; - } - - let awake = &mut shift_register.decompose()[AWAKE]; - awake.set_high()?; - - let charging = &mut shift_register.decompose()[CHARGING]; - charging.set_high()?; - - let ms0 = &mut shift_register.decompose()[MS_0]; - ms0.set_low()?; - let ms1 = &mut shift_register.decompose()[MS_1]; - ms1.set_low()?; - let ms2 = &mut shift_register.decompose()[MS_2]; - ms2.set_low()?; - let ms3 = &mut shift_register.decompose()[MS_3]; - ms3.set_low()?; - - let ms4 = &mut shift_register.decompose()[MS_4]; - ms4.set_high()?; - - let one_wire_pin = peripherals.gpio18.downgrade(); - let tank_power_pin = peripherals.gpio11.downgrade(); - - let flow_sensor_pin = peripherals.gpio4.downgrade(); - - let tank_sensor = TankSensor::create( - one_wire_pin, - peripherals.adc1, - peripherals.gpio5, - tank_power_pin, - flow_sensor_pin, - peripherals.pcnt1, - )?; - - let mut signal_counter = PcntDriver::new( - peripherals.pcnt0, - Some(peripherals.gpio22), - Option::::None, - Option::::None, - Option::::None, - )?; - - signal_counter.channel_config( - PcntChannel::Channel0, - PinIndex::Pin0, - PinIndex::Pin1, - &PcntChannelConfig { - lctrl_mode: PcntControlMode::Keep, - hctrl_mode: PcntControlMode::Keep, - pos_mode: PcntCountMode::Increment, - neg_mode: PcntCountMode::Hold, - counter_h_lim: i16::MAX, - counter_l_lim: 0, - }, - )?; - - 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)?; - - let mut main_pump = PinDriver::input_output(peripherals.gpio2.downgrade())?; - main_pump.set_pull(Pull::Floating)?; - main_pump.set_low()?; - - let mut general_fault = PinDriver::input_output(peripherals.gpio6.downgrade())?; - general_fault.set_pull(Pull::Floating)?; - general_fault.set_low()?; - - 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(Box::new(V3 { - config, - battery_monitor, - rtc_module, - esp, - shift_register, - _shift_register_enable_invert: shift_register_enable_invert, - tank_sensor, - solar_is_day, - light, - main_pump, - general_fault, - signal_counter, - })) -} - -impl<'a> BoardInteraction<'a> for V3<'a> { - fn get_tank_sensor(&mut self) -> Option<&mut TankSensor<'a>> { - Some(&mut self.tank_sensor) - } - - fn get_esp(&mut self) -> &mut Esp<'a> { - &mut self.esp - } - - fn get_config(&mut self) -> &PlantControllerConfig { - &self.config - } - - fn get_battery_monitor(&mut self) -> &mut Box { - &mut self.battery_monitor - } - - fn get_rtc_module(&mut self) -> &mut Box { - &mut self.rtc_module - } - 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 is_day(&self) -> bool { - self.solar_is_day.get_level().into() - } - - fn light(&mut self, enable: bool) -> Result<()> { - unsafe { gpio_hold_dis(self.light.pin()) }; - self.light.set_state(enable.into())?; - unsafe { gpio_hold_en(self.light.pin()) }; - Ok(()) - } - fn pump(&mut self, plant: usize, enable: bool) -> Result<()> { - if enable { - self.main_pump.set_high()?; - } - - let index = match plant { - 0 => PUMP1_BIT, - 1 => PUMP2_BIT, - 2 => PUMP3_BIT, - 3 => PUMP4_BIT, - 4 => PUMP5_BIT, - 5 => PUMP6_BIT, - 6 => PUMP7_BIT, - 7 => PUMP8_BIT, - _ => bail!("Invalid pump {plant}",), - }; - self.shift_register.decompose()[index].set_state(enable.into())?; - - if !enable { - self.main_pump.set_low()?; - } - Ok(()) - } - - fn pump_current(&mut self, _plant: usize) -> Result { - bail!("Not implemented in v3") - } - - fn fault(&mut self, plant: usize, enable: bool) -> Result<()> { - let index = match plant { - 0 => FAULT_1, - 1 => FAULT_2, - 2 => FAULT_3, - 3 => FAULT_4, - 4 => FAULT_5, - 5 => FAULT_6, - 6 => FAULT_7, - 7 => FAULT_8, - _ => panic!("Invalid plant id {}", plant), - }; - self.shift_register.decompose()[index].set_state(enable.into())?; - Ok(()) - } - - fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result { - let mut results = [0_f32; REPEAT_MOIST_MEASURE]; - for repeat in 0..REPEAT_MOIST_MEASURE { - self.signal_counter.counter_pause()?; - self.signal_counter.counter_clear()?; - //Disable all - self.shift_register.decompose()[MS_4].set_high()?; - - let sensor_channel = match sensor { - Sensor::A => match plant { - 0 => SENSOR_A_1, - 1 => SENSOR_A_2, - 2 => SENSOR_A_3, - 3 => SENSOR_A_4, - 4 => SENSOR_A_5, - 5 => SENSOR_A_6, - 6 => SENSOR_A_7, - 7 => SENSOR_A_8, - _ => bail!("Invalid plant id {}", plant), - }, - Sensor::B => match plant { - 0 => SENSOR_B_1, - 1 => SENSOR_B_2, - 2 => SENSOR_B_3, - 3 => SENSOR_B_4, - 4 => SENSOR_B_5, - 5 => SENSOR_B_6, - 6 => SENSOR_B_7, - 7 => SENSOR_B_8, - _ => bail!("Invalid plant id {}", plant), - }, - }; - - let is_bit_set = |b: u8| -> bool { sensor_channel & (1 << b) != 0 }; - let pin_0 = &mut self.shift_register.decompose()[MS_0]; - let pin_1 = &mut self.shift_register.decompose()[MS_1]; - let pin_2 = &mut self.shift_register.decompose()[MS_2]; - let pin_3 = &mut self.shift_register.decompose()[MS_3]; - if is_bit_set(0) { - pin_0.set_high()?; - } else { - pin_0.set_low()?; - } - if is_bit_set(1) { - pin_1.set_high()?; - } else { - pin_1.set_low()?; - } - if is_bit_set(2) { - pin_2.set_high()?; - } else { - pin_2.set_low()?; - } - if is_bit_set(3) { - pin_3.set_high()?; - } else { - pin_3.set_low()?; - } - - self.shift_register.decompose()[MS_4].set_low()?; - self.shift_register.decompose()[SENSOR_ON].set_high()?; - - let measurement = 100; //how long to measure and then extrapolate to hz - let factor = 1000f32 / measurement as f32; //scale raw cound by this number to get hz - - //give some time to stabilize - self.esp.delay.delay_ms(10); - self.signal_counter.counter_resume()?; - self.esp.delay.delay_ms(measurement); - self.signal_counter.counter_pause()?; - self.shift_register.decompose()[MS_4].set_high()?; - self.shift_register.decompose()[SENSOR_ON].set_low()?; - self.esp.delay.delay_ms(10); - let unscaled = self.signal_counter.get_counter_value()? as i32; - let hz = unscaled as f32 * factor; - log( - LogMessage::RawMeasure, - unscaled as u32, - hz as u32, - &plant.to_string(), - &format!("{sensor:?}"), - ); - results[repeat] = hz; - } - results.sort_by(|a, b| a.partial_cmp(b).unwrap()); // floats don't seem to implement total_ord - - let mid = results.len() / 2; - let median = results[mid]; - Ok(median) - } - - fn general_fault(&mut self, enable: bool) { - unsafe { gpio_hold_dis(self.general_fault.pin()) }; - self.general_fault.set_state(enable.into()).unwrap(); - unsafe { gpio_hold_en(self.general_fault.pin()) }; - } - - fn test(&mut self) -> Result<()> { - self.general_fault(true); - self.esp.delay.delay_ms(100); - self.general_fault(false); - self.esp.delay.delay_ms(100); - self.light(true)?; - self.esp.delay.delay_ms(500); - self.light(false)?; - self.esp.delay.delay_ms(500); - for i in 0..PLANT_COUNT { - self.fault(i, true)?; - self.esp.delay.delay_ms(500); - self.fault(i, false)?; - self.esp.delay.delay_ms(500); - } - for i in 0..PLANT_COUNT { - self.pump(i, true)?; - self.esp.delay.delay_ms(100); - self.pump(i, false)?; - self.esp.delay.delay_ms(100); - } - for plant in 0..PLANT_COUNT { - let a = self.measure_moisture_hz(plant, Sensor::A); - let b = self.measure_moisture_hz(plant, Sensor::B); - let aa = match a { - OkStd(a) => a as u32, - Err(_) => u32::MAX, - }; - let bb = match b { - OkStd(b) => b as u32, - Err(_) => u32::MAX, - }; - log(LogMessage::TestSensor, aa, bb, &plant.to_string(), ""); - } - self.esp.delay.delay_ms(10); - Ok(()) - } - - fn set_config(&mut self, config: PlantControllerConfig) -> Result<()> { - self.config = config; - self.esp.save_config(&self.config)?; - anyhow::Ok(()) - } - - fn get_mptt_voltage(&mut self) -> Result { - //assuming module to work, these are the hardware set values - if self.is_day() { - Ok(Voltage::from_volts(15_f64)) - } else { - Ok(Voltage::from_volts(0_f64)) - } - } - - fn get_mptt_current(&mut self) -> Result { - bail!("Board does not have current sensor") - } -} diff --git a/rust/src/fat_error.rs b/rust/src/fat_error.rs index 5f1a5da..7512076 100644 --- a/rust/src/fat_error.rs +++ b/rust/src/fat_error.rs @@ -257,3 +257,9 @@ impl From>> for Fat } } } + +impl From for FatError { + fn from(value: Infallible) -> Self { + panic!("Infallible error: {:?}", value) + } +} diff --git a/rust/src/hal/esp.rs b/rust/src/hal/esp.rs index c3c106b..3b99fa5 100644 --- a/rust/src/hal/esp.rs +++ b/rust/src/hal/esp.rs @@ -28,7 +28,10 @@ use esp_bootloader_esp_idf::ota::{Ota, OtaImageState}; use esp_bootloader_esp_idf::partitions::FlashRegion; use esp_hal::gpio::{Input, InputConfig, Pull, RtcPinWithResistors}; use esp_hal::rng::Rng; -use esp_hal::rtc_cntl::{sleep::{TimerWakeupSource, WakeupLevel}, Rtc}; +use esp_hal::rtc_cntl::{ + sleep::{TimerWakeupSource, WakeupLevel}, + Rtc, +}; use esp_hal::system::software_reset; use esp_println::println; use esp_storage::FlashStorage; @@ -78,7 +81,7 @@ pub struct FileSystemSizeInfo { pub struct MqttClient<'a> { dummy: PhantomData<&'a ()>, //mqtt_client: EspMqttClient<'a>, - base_topic: heapless::String<64>, + base_topic: String, } #[derive(Copy, Clone, Default)] @@ -86,6 +89,22 @@ struct Timestamp { stamp: DateTime, } +// Minimal esp-idf equivalent for gpio_hold on esp32c6 via ROM functions +extern "C" { + fn gpio_pad_hold(gpio_num: u32); + fn gpio_pad_unhold(gpio_num: u32); +} + +#[inline(always)] +pub fn hold_enable(gpio_num: u8) { + unsafe { gpio_pad_hold(gpio_num as u32) } +} + +#[inline(always)] +pub fn hold_disable(gpio_num: u8) { + unsafe { gpio_pad_unhold(gpio_num as u32) } +} + impl NtpTimestampGenerator for Timestamp { fn init(&mut self) { self.stamp = DateTime::default(); @@ -495,12 +514,19 @@ impl Esp<'_> { } _ => {} } - if { let guard = TIME_ACCESS.get().await.lock().await; guard.current_time_us() } > timeout { + if { + let guard = TIME_ACCESS.get().await.lock().await; + guard.current_time_us() + } > timeout + { bail!("Timeout waiting for wifi sta ready") } Timer::after(Duration::from_millis(500)).await; } - let timeout = { let guard = TIME_ACCESS.get().await.lock().await; guard.current_time_us() } + max_wait as u64 * 1000; + let timeout = { + let guard = TIME_ACCESS.get().await.lock().await; + guard.current_time_us() + } + max_wait as u64 * 1000; loop { let state = esp_wifi::wifi::sta_state(); match state { @@ -509,21 +535,39 @@ impl Esp<'_> { } _ => {} } - if { let guard = TIME_ACCESS.get().await.lock().await; guard.current_time_us() } > timeout { + if { + let guard = TIME_ACCESS.get().await.lock().await; + guard.current_time_us() + } > timeout + { bail!("Timeout waiting for wifi sta connected") } Timer::after(Duration::from_millis(500)).await; } - let timeout = { let guard = TIME_ACCESS.get().await.lock().await; guard.current_time_us() } + max_wait as u64 * 1000; + let timeout = { + let guard = TIME_ACCESS.get().await.lock().await; + guard.current_time_us() + } + max_wait as u64 * 1000; while !stack.is_link_up() { - if { let guard = TIME_ACCESS.get().await.lock().await; guard.current_time_us() } > timeout { + if { + let guard = TIME_ACCESS.get().await.lock().await; + guard.current_time_us() + } > timeout + { bail!("Timeout waiting for wifi link up") } Timer::after(Duration::from_millis(500)).await; } - let timeout = { let guard = TIME_ACCESS.get().await.lock().await; guard.current_time_us() } + max_wait as u64 * 1000; + let timeout = { + let guard = TIME_ACCESS.get().await.lock().await; + guard.current_time_us() + } + max_wait as u64 * 1000; while !stack.is_config_up() { - if { let guard = TIME_ACCESS.get().await.lock().await; guard.current_time_us() } > timeout { + if { + let guard = TIME_ACCESS.get().await.lock().await; + guard.current_time_us() + } > timeout + { bail!("Timeout waiting for wifi config up") } Timer::after(Duration::from_millis(100)).await @@ -531,7 +575,11 @@ impl Esp<'_> { Ok(stack.clone()) } - pub fn deep_sleep(&mut self, duration_in_ms: u64, mut rtc: MutexGuard) -> ! { + pub fn deep_sleep( + &mut self, + duration_in_ms: u64, + mut rtc: MutexGuard, + ) -> ! { // Configure and enter deep sleep using esp-hal. Also keep prior behavior where // duration_in_ms == 0 triggers an immediate reset. @@ -549,7 +597,8 @@ impl Esp<'_> { } else { ///let timer = TimerWakeupSource::new(core::time::Duration::from_millis(duration_in_ms)); let timer = TimerWakeupSource::new(core::time::Duration::from_millis(5000)); - let mut wake_pins: [(&mut dyn RtcPinWithResistors, WakeupLevel); 1] = [(&mut self.wake_gpio1, WakeupLevel::Low)]; + let mut wake_pins: [(&mut dyn RtcPinWithResistors, WakeupLevel); 1] = + [(&mut self.wake_gpio1, WakeupLevel::Low)]; let ext1 = esp_hal::rtc_cntl::sleep::Ext1WakeupSource::new(&mut wake_pins); rtc.sleep_deep(&[&timer, &ext1]); } diff --git a/rust/src/hal/initial_hal.rs b/rust/src/hal/initial_hal.rs index 6ecf8a8..6cec44b 100644 --- a/rust/src/hal/initial_hal.rs +++ b/rust/src/hal/initial_hal.rs @@ -1,9 +1,9 @@ use crate::alloc::boxed::Box; +use crate::fat_error::{FatError, FatResult}; use crate::hal::esp::Esp; use crate::hal::rtc::{BackupHeader, RTCModuleInteraction}; use crate::hal::water::TankSensor; use crate::hal::{BoardInteraction, FreePeripherals, Sensor, TIME_ACCESS}; -use crate::fat_error::{FatError, FatResult}; use crate::{ bail, config::PlantControllerConfig, @@ -90,7 +90,7 @@ impl<'a> BoardInteraction<'a> for Initial<'a> { &mut self.rtc } - fn set_charge_indicator(&mut self, _charging: bool) -> Result<(), FatError> { + async fn set_charge_indicator(&mut self, _charging: bool) -> Result<(), FatError> { bail!("Please configure board revision") } diff --git a/rust/src/hal/mod.rs b/rust/src/hal/mod.rs index 65ed891..ee11ee1 100644 --- a/rust/src/hal/mod.rs +++ b/rust/src/hal/mod.rs @@ -3,6 +3,7 @@ pub mod esp; mod initial_hal; mod little_fs2storage_adapter; pub(crate) mod rtc; +mod v3_hal; mod v4_hal; mod v4_sensor; mod water; @@ -79,11 +80,11 @@ use esp_hal::clock::CpuClock; use esp_hal::gpio::{Input, InputConfig, Pull}; use measurements::{Current, Voltage}; +use crate::fat_error::{FatError, FatResult}; use crate::hal::battery::{print_battery_bq34z100, BQ34Z100G1}; use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem; use crate::hal::water::TankSensor; use crate::log::LOG_ACCESS; -use crate::fat_error::FatError; use embassy_sync::mutex::Mutex; use embassy_sync::once_lock::OnceLock; use esp_alloc as _; @@ -134,7 +135,7 @@ pub trait BoardInteraction<'a> { fn get_config(&mut self) -> &PlantControllerConfig; fn get_battery_monitor(&mut self) -> &mut Box; fn get_rtc_module(&mut self) -> &mut Box; - fn set_charge_indicator(&mut self, charging: bool) -> Result<(), FatError>; + async fn set_charge_indicator(&mut self, charging: bool) -> Result<(), FatError>; async fn deep_sleep(&mut self, duration_in_ms: u64) -> !; fn is_day(&self) -> bool; @@ -230,9 +231,11 @@ impl PlantHal { esp_alloc::heap_allocator!(#[link_section = ".dram2_uninit"] size: 64000); let rtc: Rtc = Rtc::new(peripherals.LPWR); - TIME_ACCESS.init(Mutex::new(rtc)).map_err(|_| FatError::String { - error: "Init error rct".to_string(), - })?; + TIME_ACCESS + .init(Mutex::new(rtc)) + .map_err(|_| FatError::String { + error: "Init error rct".to_string(), + })?; let systimer = SystemTimer::new(peripherals.SYSTIMER); @@ -387,8 +390,8 @@ impl PlantHal { fs, rng, controller: Arc::new(Mutex::new(controller)), - interface_sta : Some(sta), - interface_ap : Some(ap), + interface_sta: Some(sta), + interface_ap: Some(ap), boot_button, wake_gpio1, mqtt_client: None, @@ -424,7 +427,6 @@ impl PlantHal { //TODO still required? or via button ignore? to_config_mode = true; to_config_mode = true; "core usb uart" - } SocResetReason::CoreUsbJtag => "core usb jtag", SocResetReason::Cpu0JtagCpu => "cpu0 jtag cpu", @@ -539,9 +541,9 @@ impl PlantHal { BoardVersion::INITIAL => { initial_hal::create_initial_board(free_pins, config, esp)? } - // BoardVersion::V3 => { - // v3_hal::create_v3(free_pins, esp, config, battery_interaction, rtc_module)? - // } + BoardVersion::V3 => { + v3_hal::create_v3(free_pins, esp, config, battery_interaction, rtc_module)? + } BoardVersion::V4 => { v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module) .await? @@ -584,9 +586,9 @@ pub async fn esp_time() -> DateTime { DateTime::from_timestamp_micros(guard.current_time_us() as i64).unwrap() } -pub async fn esp_set_time(time: DateTime) { +pub async fn esp_set_time(time: DateTime) -> FatResult<()> { { - let mut guard = TIME_ACCESS.get().await.lock().await; + let guard = TIME_ACCESS.get().await.lock().await; guard.set_current_time_us(time.timestamp_micros() as u64); } BOARD_ACCESS @@ -597,5 +599,5 @@ pub async fn esp_set_time(time: DateTime) { .board_hal .get_rtc_module() .set_rtc_time(&time.to_utc()) - .await; + .await } diff --git a/rust/src/hal/v3_hal.rs b/rust/src/hal/v3_hal.rs new file mode 100644 index 0000000..7045523 --- /dev/null +++ b/rust/src/hal/v3_hal.rs @@ -0,0 +1,429 @@ +use crate::bail; +use crate::fat_error::FatError; +use crate::hal::esp::{hold_disable, hold_enable}; +use crate::hal::rtc::RTCModuleInteraction; +use crate::hal::water::TankSensor; +use crate::hal::{BoardInteraction, FreePeripherals, Sensor, PLANT_COUNT, TIME_ACCESS}; +use crate::log::{LogMessage, LOG_ACCESS}; +use crate::sipo::ShiftRegister40; +use crate::{ + config::PlantControllerConfig, + hal::{battery::BatteryInteraction, esp::Esp}, +}; +use alloc::boxed::Box; +use alloc::format; +use alloc::string::ToString; +use async_trait::async_trait; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex::CriticalSectionMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::Timer; +use embedded_hal::digital::OutputPin as _; +use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull}; +use measurements::{Current, Voltage}; + +const PUMP8_BIT: usize = 0; +const PUMP1_BIT: usize = 1; +const PUMP2_BIT: usize = 2; +const PUMP3_BIT: usize = 3; +const PUMP4_BIT: usize = 4; +const PUMP5_BIT: usize = 5; +const PUMP6_BIT: usize = 6; +const PUMP7_BIT: usize = 7; +const MS_0: usize = 8; +const MS_4: usize = 9; +const MS_2: usize = 10; +const MS_3: usize = 11; +const MS_1: usize = 13; +const SENSOR_ON: usize = 12; + +const SENSOR_A_1: u8 = 7; +const SENSOR_A_2: u8 = 6; +const SENSOR_A_3: u8 = 5; +const SENSOR_A_4: u8 = 4; +const SENSOR_A_5: u8 = 3; +const SENSOR_A_6: u8 = 2; +const SENSOR_A_7: u8 = 1; +const SENSOR_A_8: u8 = 0; + +const SENSOR_B_1: u8 = 8; +const SENSOR_B_2: u8 = 9; +const SENSOR_B_3: u8 = 10; +const SENSOR_B_4: u8 = 11; +const SENSOR_B_5: u8 = 12; +const SENSOR_B_6: u8 = 13; +const SENSOR_B_7: u8 = 14; +const SENSOR_B_8: u8 = 15; + +const CHARGING: usize = 14; +const AWAKE: usize = 15; + +const FAULT_3: usize = 16; +const FAULT_8: usize = 17; +const FAULT_7: usize = 18; +const FAULT_6: usize = 19; +const FAULT_5: usize = 20; +const FAULT_4: usize = 21; +const FAULT_1: usize = 22; +const FAULT_2: usize = 23; + +const REPEAT_MOIST_MEASURE: usize = 1; + +pub struct V3<'a> { + config: PlantControllerConfig, + battery_monitor: Box, + rtc_module: Box, + esp: Esp<'a>, + shift_register: + Mutex, Output<'a>, Output<'a>>>, + _shift_register_enable_invert: Output<'a>, + tank_sensor: TankSensor<'a>, + solar_is_day: Input<'a>, + light: Output<'a>, + main_pump: Output<'a>, + general_fault: Output<'a>, +} + +pub(crate) fn create_v3( + peripherals: FreePeripherals<'static>, + esp: Esp<'static>, + config: PlantControllerConfig, + battery_monitor: Box, + rtc_module: Box, +) -> Result + Send + 'static>, FatError> { + log::info!("Start v3"); + let clock = Output::new(peripherals.gpio15, Level::Low, OutputConfig::default()); + let latch = Output::new(peripherals.gpio3, Level::Low, OutputConfig::default()); + let data = Output::new(peripherals.gpio23, Level::Low, OutputConfig::default()); + let shift_register = ShiftRegister40::new(clock, latch, data); + //disable all + for mut pin in shift_register.decompose() { + let _ = pin.set_low(); + } + + // Set always-on status bits + let _ = shift_register.decompose()[AWAKE].set_high(); + let _ = shift_register.decompose()[CHARGING].set_high(); + + // Multiplexer defaults: ms0..ms3 low, ms4 high (disabled) + let _ = shift_register.decompose()[MS_0].set_low(); + let _ = shift_register.decompose()[MS_1].set_low(); + let _ = shift_register.decompose()[MS_2].set_low(); + let _ = shift_register.decompose()[MS_3].set_low(); + let _ = shift_register.decompose()[MS_4].set_high(); + + let one_wire_pin = Flex::new(peripherals.gpio18); + let tank_power_pin = Output::new(peripherals.gpio11, Level::Low, OutputConfig::default()); + + let flow_sensor_pin = Input::new( + peripherals.gpio4, + InputConfig::default().with_pull(Pull::Up), + ); + + let tank_sensor = TankSensor::create( + one_wire_pin, + peripherals.adc1, + peripherals.gpio5, + tank_power_pin, + flow_sensor_pin, + peripherals.pcnt1, + )?; + + let solar_is_day = Input::new(peripherals.gpio7, InputConfig::default()); + let light = Output::new(peripherals.gpio10, Level::Low, OutputConfig::default()); + let mut main_pump = Output::new(peripherals.gpio2, Level::Low, OutputConfig::default()); + main_pump.set_low(); + let mut general_fault = Output::new(peripherals.gpio6, Level::Low, OutputConfig::default()); + general_fault.set_low(); + + let mut shift_register_enable_invert = + Output::new(peripherals.gpio21, Level::Low, OutputConfig::default()); + shift_register_enable_invert.set_low(); + + Ok(Box::new(V3 { + config, + battery_monitor, + rtc_module, + esp, + shift_register: Mutex::new(shift_register), + _shift_register_enable_invert: shift_register_enable_invert, + tank_sensor, + solar_is_day, + light, + main_pump, + general_fault, + })) +} + +#[async_trait] +impl<'a> BoardInteraction<'a> for V3<'a> { + fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> { + Ok(&mut self.tank_sensor) + } + + fn get_esp(&mut self) -> &mut Esp<'a> { + &mut self.esp + } + + fn get_config(&mut self) -> &PlantControllerConfig { + &self.config + } + + fn get_battery_monitor(&mut self) -> &mut Box { + &mut self.battery_monitor + } + + fn get_rtc_module(&mut self) -> &mut Box { + &mut self.rtc_module + } + async fn set_charge_indicator(&mut self, charging: bool) -> Result<(), FatError> { + let shift_register = self.shift_register.lock().await; + if charging { + let _ = shift_register.decompose()[CHARGING].set_high(); + } else { + let _ = shift_register.decompose()[CHARGING].set_low(); + } + Ok(()) + } + + async fn deep_sleep(&mut self, duration_in_ms: u64) -> ! { + let _ = self.shift_register.lock().await.decompose()[AWAKE].set_low(); + let guard = TIME_ACCESS.get().await.lock().await; + self.esp.deep_sleep(duration_in_ms, guard) + } + + fn is_day(&self) -> bool { + self.solar_is_day.is_high() + } + + async fn light(&mut self, enable: bool) -> Result<(), FatError> { + hold_disable(10); + if enable { + self.light.set_high(); + } else { + self.light.set_low(); + } + hold_enable(10); + Ok(()) + } + async fn pump(&mut self, plant: usize, enable: bool) -> Result<(), FatError> { + if enable { + self.main_pump.set_high(); + } + + let index = match plant { + 0 => PUMP1_BIT, + 1 => PUMP2_BIT, + 2 => PUMP3_BIT, + 3 => PUMP4_BIT, + 4 => PUMP5_BIT, + 5 => PUMP6_BIT, + 6 => PUMP7_BIT, + 7 => PUMP8_BIT, + _ => bail!("Invalid pump {plant}"), + }; + let shift_register = self.shift_register.lock().await; + if enable { + let _ = shift_register.decompose()[index].set_high(); + } else { + let _ = shift_register.decompose()[index].set_low(); + } + + if !enable { + self.main_pump.set_low(); + } + Ok(()) + } + + async fn pump_current(&mut self, _plant: usize) -> Result { + bail!("Not implemented in v3") + } + + async fn fault(&mut self, plant: usize, enable: bool) -> Result<(), FatError> { + let index = match plant { + 0 => FAULT_1, + 1 => FAULT_2, + 2 => FAULT_3, + 3 => FAULT_4, + 4 => FAULT_5, + 5 => FAULT_6, + 6 => FAULT_7, + 7 => FAULT_8, + _ => panic!("Invalid plant id {}", plant), + }; + let shift_register = self.shift_register.lock().await; + if enable { + let _ = shift_register.decompose()[index].set_high(); + } else { + let _ = shift_register.decompose()[index].set_low(); + } + Ok(()) + } + + async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result { + let mut results = [0_f32; REPEAT_MOIST_MEASURE]; + for repeat in 0..REPEAT_MOIST_MEASURE { + //self.signal_counter.counter_pause()?; + //self.signal_counter.counter_clear()?; + //Disable all + { + let mut shift_register = self.shift_register.lock().await; + shift_register.decompose()[MS_4].set_high()?; + } + + let sensor_channel = match sensor { + Sensor::A => match plant { + 0 => SENSOR_A_1, + 1 => SENSOR_A_2, + 2 => SENSOR_A_3, + 3 => SENSOR_A_4, + 4 => SENSOR_A_5, + 5 => SENSOR_A_6, + 6 => SENSOR_A_7, + 7 => SENSOR_A_8, + _ => bail!("Invalid plant id {}", plant), + }, + Sensor::B => match plant { + 0 => SENSOR_B_1, + 1 => SENSOR_B_2, + 2 => SENSOR_B_3, + 3 => SENSOR_B_4, + 4 => SENSOR_B_5, + 5 => SENSOR_B_6, + 6 => SENSOR_B_7, + 7 => SENSOR_B_8, + _ => bail!("Invalid plant id {}", plant), + }, + }; + + let is_bit_set = |b: u8| -> bool { sensor_channel & (1 << b) != 0 }; + { + let mut shift_register = self.shift_register.lock().await; + let pin_0 = &mut shift_register.decompose()[MS_0]; + let pin_1 = &mut shift_register.decompose()[MS_1]; + let pin_2 = &mut shift_register.decompose()[MS_2]; + let pin_3 = &mut shift_register.decompose()[MS_3]; + if is_bit_set(0) { + pin_0.set_high()?; + } else { + pin_0.set_low()?; + } + if is_bit_set(1) { + pin_1.set_high()?; + } else { + pin_1.set_low()?; + } + if is_bit_set(2) { + pin_2.set_high()?; + } else { + pin_2.set_low()?; + } + if is_bit_set(3) { + pin_3.set_high()?; + } else { + pin_3.set_low()?; + } + + shift_register.decompose()[MS_4].set_low()?; + shift_register.decompose()[SENSOR_ON].set_high()?; + } + let measurement = 100; //how long to measure and then extrapolate to hz + let factor = 1000f32 / measurement as f32; //scale raw cound by this number to get hz + + //give some time to stabilize + Timer::after_millis(10).await; + //self.signal_counter.counter_resume()?; + Timer::after_millis(measurement).await; + //self.signal_counter.counter_pause()?; + { + let mut shift_register = self.shift_register.lock().await; + shift_register.decompose()[MS_4].set_high()?; + shift_register.decompose()[SENSOR_ON].set_low()?; + } + Timer::after_millis(10).await; + let unscaled = 1337; //self.signal_counter.get_counter_value()? as i32; + let hz = unscaled as f32 * factor; + LOG_ACCESS + .lock() + .await + .log( + LogMessage::RawMeasure, + unscaled as u32, + hz as u32, + &plant.to_string(), + &format!("{sensor:?}"), + ) + .await; + results[repeat] = hz; + } + results.sort_by(|a, b| a.partial_cmp(b).unwrap()); // floats don't seem to implement total_ord + + let mid = results.len() / 2; + let median = results[mid]; + Ok(median) + } + + async fn general_fault(&mut self, enable: bool) { + hold_disable(6); + if enable { + self.general_fault.set_high(); + } else { + self.general_fault.set_low(); + } + hold_enable(6); + } + + async fn test(&mut self) -> Result<(), FatError> { + self.general_fault(true).await; + Timer::after_millis(100).await; + self.general_fault(false).await; + Timer::after_millis(100).await; + self.light(true).await?; + Timer::after_millis(500).await; + + self.light(false).await?; + Timer::after_millis(500).await; + for i in 0..PLANT_COUNT { + self.fault(i, true).await?; + Timer::after_millis(500).await; + self.fault(i, false).await?; + Timer::after_millis(500).await; + } + for i in 0..PLANT_COUNT { + self.pump(i, true).await?; + Timer::after_millis(100).await; + self.pump(i, false).await?; + Timer::after_millis(100).await; + } + for plant in 0..PLANT_COUNT { + let a = self.measure_moisture_hz(plant, Sensor::A).await; + let b = self.measure_moisture_hz(plant, Sensor::B).await; + let aa = match a { + Ok(a) => a as u32, + Err(_) => u32::MAX, + }; + let bb = match b { + Ok(b) => b as u32, + Err(_) => u32::MAX, + }; + LOG_ACCESS + .lock() + .await + .log(LogMessage::TestSensor, aa, bb, &plant.to_string(), "") + .await; + } + Timer::after_millis(10).await; + Ok(()) + } + + fn set_config(&mut self, config: PlantControllerConfig) { + self.config = config; + } + + async fn get_mptt_voltage(&mut self) -> Result { + bail!("Not implemented in v3") + } + async fn get_mptt_current(&mut self) -> Result { + bail!("Not implemented in v3") + } +} diff --git a/rust/src/hal/v4_hal.rs b/rust/src/hal/v4_hal.rs index 005da27..02533d9 100644 --- a/rust/src/hal/v4_hal.rs +++ b/rust/src/hal/v4_hal.rs @@ -1,6 +1,6 @@ use crate::config::PlantControllerConfig; use crate::hal::battery::BatteryInteraction; -use crate::hal::esp::Esp; +use crate::hal::esp::{hold_disable, hold_enable, Esp}; use crate::hal::rtc::RTCModuleInteraction; use crate::hal::water::TankSensor; use crate::hal::{BoardInteraction, FreePeripherals, Sensor, I2C_DRIVER, PLANT_COUNT, TIME_ACCESS}; @@ -14,8 +14,9 @@ use esp_hal::analog::adc::{Adc, AdcConfig, Attenuation}; use esp_hal::{twai, Blocking}; //use embedded_hal_bus::i2c::MutexDevice; use crate::bail; -use crate::hal::v4_sensor::{SensorImpl, SensorInteraction}; use crate::fat_error::{FatError, FatResult}; +use crate::hal::v4_sensor::{SensorImpl, SensorInteraction}; +use crate::log::{LogMessage, LOG_ACCESS}; use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull}; use esp_hal::i2c::master::I2c; use esp_hal::pcnt::Pcnt; @@ -28,23 +29,6 @@ use ina219::SyncIna219; use measurements::Resistance; use measurements::{Current, Voltage}; use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface}; -use crate::log::{LogMessage, LOG_ACCESS}; - -// Minimal esp-idf equivalent for gpio_hold on esp32c6 via ROM functions -extern "C" { - fn gpio_pad_hold(gpio_num: u32); - fn gpio_pad_unhold(gpio_num: u32); -} - -#[inline(always)] -fn hold_enable(gpio_num: u8) { - unsafe { gpio_pad_hold(gpio_num as u32) } -} - -#[inline(always)] -fn hold_disable(gpio_num: u8) { - unsafe { gpio_pad_unhold(gpio_num as u32) } -} const MPPT_CURRENT_SHUNT_OHMS: f64 = 0.05_f64; const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K; @@ -356,7 +340,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> { &mut self.rtc_module } - fn set_charge_indicator(&mut self, charging: bool) -> Result<(), FatError> { + async fn set_charge_indicator(&mut self, charging: bool) -> Result<(), FatError> { self.charger.set_charge_indicator(charging) } @@ -435,11 +419,11 @@ impl<'a> BoardInteraction<'a> for V4<'a> { } async fn test(&mut self) -> Result<(), FatError> { - self.general_fault(true).await; + self.general_fault(true).await; Timer::after_millis(100).await; - self.general_fault(false).await; + self.general_fault(false).await; Timer::after_millis(500).await; - self.light(true).await?; + self.light(true).await?; Timer::after_millis(500).await; self.light(false).await?; Timer::after_millis(500).await; @@ -449,25 +433,29 @@ impl<'a> BoardInteraction<'a> for V4<'a> { self.fault(i, false).await?; Timer::after_millis(500).await; } - for i in 0..PLANT_COUNT { - self.pump(i, true).await?; - Timer::after_millis(100).await; - self.pump(i, false).await?; - Timer::after_millis(100).await; - } - for plant in 0..PLANT_COUNT { - let a = self.measure_moisture_hz(plant, Sensor::A).await; - let b = self.measure_moisture_hz(plant, Sensor::B).await; - let aa = match a { - Ok(a) => a as u32, - Err(_) => u32::MAX, - }; - let bb = match b { - Ok(b) => b as u32, - Err(_) => u32::MAX, - }; - LOG_ACCESS.lock().await.log(LogMessage::TestSensor, aa, bb, &plant.to_string(), "").await; - } + for i in 0..PLANT_COUNT { + self.pump(i, true).await?; + Timer::after_millis(100).await; + self.pump(i, false).await?; + Timer::after_millis(100).await; + } + for plant in 0..PLANT_COUNT { + let a = self.measure_moisture_hz(plant, Sensor::A).await; + let b = self.measure_moisture_hz(plant, Sensor::B).await; + let aa = match a { + Ok(a) => a as u32, + Err(_) => u32::MAX, + }; + let bb = match b { + Ok(b) => b as u32, + Err(_) => u32::MAX, + }; + LOG_ACCESS + .lock() + .await + .log(LogMessage::TestSensor, aa, bb, &plant.to_string(), "") + .await; + } Timer::after_millis(10).await; Ok(()) } diff --git a/rust/src/main.rs b/rust/src/main.rs index 4c1cc4c..f0492d6 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -44,7 +44,6 @@ use log::LogMessage; use option_lock::OptionLock; use plant_state::PlantState; use serde::{Deserialize, Serialize}; -use smoltcp::socket::udp::PacketMetadata; #[no_mangle] extern "C" fn custom_halt() -> ! { @@ -248,7 +247,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> { try_connect_wifi_sntp_mqtt(&mut board, &mut stack).await } else { info!("No wifi configured"); - //the current sensors require this amount to stabilize, in case of wifi this is already handles for sure; + //the current sensors require this amount to stabilize, in case of wifi this is already handled due to connect timings; Timer::after_millis(100).await; NetworkMode::OFFLINE }; @@ -411,7 +410,6 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> { PlantState::read_hardware_state(7, &mut board).await, ]; - //publish_plant_states(&timezone_time.clone(), &plantstate).await; // let pump_required = plantstate @@ -500,7 +498,6 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> { .await .unwrap_or(BatteryState::Unknown); - info!("Battery state is {:?}", battery_state); let mut light_state = LightState { enabled: board.board_hal.get_config().night_lamp.enabled, diff --git a/rust/src/sipo.rs b/rust/src/sipo.rs index 7784b5b..f051ee2 100644 --- a/rust/src/sipo.rs +++ b/rust/src/sipo.rs @@ -7,7 +7,7 @@ use core::mem::{self, MaybeUninit}; use core::result::{Result, Result::Ok}; use embedded_hal::digital::OutputPin; -trait ShiftRegisterInternal { +trait ShiftRegisterInternal: Send { fn update(&self, index: usize, command: bool) -> Result<(), ()>; } @@ -47,9 +47,9 @@ macro_rules! ShiftRegisterBuilder { /// Serial-in parallel-out shift register pub struct $name where - Pin1: OutputPin, - Pin2: OutputPin, - Pin3: OutputPin, + Pin1: OutputPin + Send, + Pin2: OutputPin + Send, + Pin3: OutputPin + Send, { clock: RefCell, latch: RefCell, @@ -59,9 +59,9 @@ macro_rules! ShiftRegisterBuilder { impl ShiftRegisterInternal for $name where - Pin1: OutputPin, - Pin2: OutputPin, - Pin3: OutputPin, + Pin1: OutputPin + Send, + Pin2: OutputPin + Send, + Pin3: OutputPin + Send, { /// Sets the value of the shift register output at `index` to value `command` fn update(&self, index: usize, command: bool) -> Result<(), ()> { @@ -86,9 +86,9 @@ macro_rules! ShiftRegisterBuilder { impl $name where - Pin1: OutputPin, - Pin2: OutputPin, - Pin3: OutputPin, + Pin1: OutputPin + Send, + Pin2: OutputPin + Send, + Pin3: OutputPin + Send, { /// Creates a new SIPO shift register from clock, latch, and data output pins pub fn new(clock: Pin1, latch: Pin2, data: Pin3) -> Self { diff --git a/rust/src/webserver/mod.rs b/rust/src/webserver/mod.rs index a7cf81c..0baa0de 100644 --- a/rust/src/webserver/mod.rs +++ b/rust/src/webserver/mod.rs @@ -1,11 +1,11 @@ //offer ota and config mode use crate::config::PlantControllerConfig; +use crate::fat_error::{FatError, FatResult}; use crate::hal::rtc::X25; use crate::hal::{esp_set_time, esp_time}; use crate::log::LOG_ACCESS; use crate::tank::determine_tank_state; -use crate::fat_error::{FatError, FatResult}; use crate::{bail, do_secure_pump, get_version, log::LogMessage, BOARD_ACCESS}; use alloc::borrow::ToOwned; use alloc::format; @@ -13,12 +13,12 @@ use alloc::string::{String, ToString}; use alloc::sync::Arc; use alloc::vec::Vec; use chrono::DateTime; +use chrono_tz::Tz; use core::fmt::{Debug, Display}; use core::net::{IpAddr, Ipv4Addr, SocketAddr}; use core::result::Result::Ok; use core::str::{from_utf8, FromStr}; use core::sync::atomic::{AtomicBool, Ordering}; -use chrono_tz::Tz; use edge_http::io::server::{Connection, Handler, Server}; use edge_http::Method; use edge_nal::TcpBind; @@ -409,7 +409,7 @@ impl Handler for HttpHandler { async fn get_timezones( request: &mut Connection<'_, T, N>, -) -> FatResult> +) -> FatResult> where T: Read + Write, { @@ -421,18 +421,18 @@ where async fn board_test( request: &mut Connection<'_, T, N>, -) -> FatResult> +) -> FatResult> where T: Read + Write, - { - let mut board = BOARD_ACCESS.get().await.lock().await; - board.board_hal.test().await?; - Ok(None) - } +{ + let mut board = BOARD_ACCESS.get().await.lock().await; + board.board_hal.test().await?; + Ok(None) +} async fn pump_test( request: &mut Connection<'_, T, N>, -) -> FatResult> +) -> FatResult> where T: Read + Write, { @@ -454,11 +454,11 @@ async fn night_lamp_test( where T: Read + Write, { - let actual_data = read_up_to_bytes_from_request(request, None).await?; - let light_command: NightLampCommand = serde_json::from_slice(&actual_data)?; - let mut board = BOARD_ACCESS.get().await.lock().await; - board.board_hal.light(light_command.active).await?; - Ok(None) + let actual_data = read_up_to_bytes_from_request(request, None).await?; + let light_command: NightLampCommand = serde_json::from_slice(&actual_data)?; + let mut board = BOARD_ACCESS.get().await.lock().await; + board.board_hal.light(light_command.active).await?; + Ok(None) } async fn get_backup_config( @@ -645,7 +645,7 @@ where let actual_data = read_up_to_bytes_from_request(request, None).await?; let time: SetTime = serde_json::from_slice(&actual_data)?; let parsed = DateTime::parse_from_rfc3339(time.time).unwrap(); - esp_set_time(parsed).await; + esp_set_time(parsed).await?; Ok(None) }