From 50b2e994ca624769b301bb265e7ff964c56d5339 Mon Sep 17 00:00:00 2001 From: Empire Date: Thu, 14 Aug 2025 22:10:53 +0200 Subject: [PATCH] can prepare stuff --- rust/Cargo.toml | 1 + rust/src/hal/initial_hal.rs | 1 + rust/src/hal/mod.rs | 6 +- rust/src/hal/v3_hal.rs | 6 +- rust/src/hal/v4_hal.rs | 192 +++++++++++++++--------------------- rust/src/hal/v4_sensor.rs | 115 +++++++++++++++++++++ 6 files changed, 204 insertions(+), 117 deletions(-) create mode 100644 rust/src/hal/v4_sensor.rs diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 579a276..80488db 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -86,6 +86,7 @@ pca9535 = { version = "2.0.0", features = ["std"] } ina219 = { version = "0.2.0", features = ["std"] } embedded-storage = "=0.3.1" ekv = "1.0.0" +embedded-can = "0.4.1" [patch.crates-io] diff --git a/rust/src/hal/initial_hal.rs b/rust/src/hal/initial_hal.rs index 06e757e..09edb52 100644 --- a/rust/src/hal/initial_hal.rs +++ b/rust/src/hal/initial_hal.rs @@ -51,6 +51,7 @@ pub(crate) fn create_initial_board( config: PlantControllerConfig, esp: Esp<'static>, ) -> Result + Send>> { + println!("Start initial"); let mut general_fault = PinDriver::input_output(free_pins.gpio6.downgrade())?; general_fault.set_pull(Pull::Floating)?; general_fault.set_low()?; diff --git a/rust/src/hal/mod.rs b/rust/src/hal/mod.rs index d722e81..7bfe321 100644 --- a/rust/src/hal/mod.rs +++ b/rust/src/hal/mod.rs @@ -5,6 +5,7 @@ mod rtc; mod v3_hal; mod v4_hal; mod water; +mod v4_sensor; use crate::hal::rtc::{DS3231Module, RTCModuleInteraction}; use crate::hal::water::TankSensor; @@ -47,11 +48,12 @@ use once_cell::sync::Lazy; use std::result::Result::Ok as OkStd; use std::sync::Mutex; use std::time::Duration; +use esp_idf_hal::can::CAN; use esp_idf_hal::pcnt::PCNT1; //Only support for 8 right now! pub const PLANT_COUNT: usize = 8; -const REPEAT_MOIST_MEASURE: usize = 1; + const TANK_MULTI_SAMPLE: usize = 11; @@ -157,6 +159,7 @@ pub struct FreePeripherals { pub pcnt0: PCNT0, pub pcnt1: PCNT1, pub adc1: ADC1, + pub can: CAN, } impl PlantHal { @@ -186,6 +189,7 @@ impl PlantHal { boot_button.set_pull(Pull::Floating)?; let free_pins = FreePeripherals { + can: peripherals.can, adc1: peripherals.adc1, pcnt0: peripherals.pcnt0, pcnt1: peripherals.pcnt1, diff --git a/rust/src/hal/v3_hal.rs b/rust/src/hal/v3_hal.rs index 312f1e9..75fbb45 100644 --- a/rust/src/hal/v3_hal.rs +++ b/rust/src/hal/v3_hal.rs @@ -1,7 +1,7 @@ use crate::hal::rtc::RTCModuleInteraction; use crate::hal::water::TankSensor; use crate::hal::{ - deep_sleep, BoardInteraction, FreePeripherals, Sensor, PLANT_COUNT, REPEAT_MOIST_MEASURE, + deep_sleep, BoardInteraction, FreePeripherals, Sensor, PLANT_COUNT, }; use crate::log::{log, LogMessage}; use crate::{ @@ -64,6 +64,9 @@ 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, @@ -91,6 +94,7 @@ pub(crate) fn create_v3( battery_monitor: Box, rtc_module: Box, ) -> Result + Send>> { + println!("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())?; diff --git a/rust/src/hal/v4_hal.rs b/rust/src/hal/v4_hal.rs index 18e8bc9..11222f8 100644 --- a/rust/src/hal/v4_hal.rs +++ b/rust/src/hal/v4_hal.rs @@ -2,18 +2,18 @@ use crate::config::PlantControllerConfig; use crate::hal::battery::BatteryInteraction; use crate::hal::esp::Esp; use crate::hal::rtc::RTCModuleInteraction; +use crate::hal::v4_sensor::SensorImpl; +use crate::hal::v4_sensor::SensorInteraction; use crate::hal::water::TankSensor; use crate::hal::{ - deep_sleep, BoardInteraction, FreePeripherals, Sensor, I2C_DRIVER, PLANT_COUNT, - REPEAT_MOIST_MEASURE, + deep_sleep, BoardInteraction, FreePeripherals, Sensor, I2C_DRIVER, PLANT_COUNT }; use crate::log::{log, LogMessage}; use anyhow::bail; use embedded_hal::digital::OutputPin; use embedded_hal_bus::i2c::MutexDevice; -use esp_idf_hal::delay::Delay; use esp_idf_hal::gpio::{AnyInputPin, IOPin, InputOutput, Output, PinDriver, Pull}; -use esp_idf_hal::i2c::I2cDriver; +use esp_idf_hal::i2c::{I2cDriver, I2cError}; use esp_idf_hal::pcnt::{ PcntChannel, PcntChannelConfig, PcntControlMode, PcntCountMode, PcntDriver, PinIndex, }; @@ -23,15 +23,13 @@ use ina219::calibration::UnCalibrated; use ina219::configuration::{Configuration, OperatingMode}; use ina219::SyncIna219; use measurements::{Current, Resistance, Voltage}; -use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface}; +use pca9535::{ExpanderError, GPIOBank, Pca9535Immediate, StandardExpanderInterface}; use std::result::Result::Ok as OkStd; - -const MS0: u8 = 1_u8; -const MS1: u8 = 0_u8; -const MS2: u8 = 3_u8; -const MS3: u8 = 4_u8; -const MS4: u8 = 2_u8; -const SENSOR_ON: u8 = 5_u8; +use embedded_can::nb::Can; +use embedded_can::Frame; +use embedded_can::StandardId; +use esp_idf_hal::prelude::*; +use esp_idf_hal::can; pub enum Charger<'a> { SolarMpptV1 { @@ -119,13 +117,13 @@ pub struct V4<'a> { rtc_module: Box, battery_monitor: Box, config: PlantControllerConfig, - signal_counter: PcntDriver<'a>, + awake: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, Output>, light: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, pump_expander: Pca9535Immediate>>, pump_ina: Option>, UnCalibrated>>, - sensor_expander: Pca9535Immediate>>, + sensor: SensorImpl<'a>, extra1: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, Output>, extra2: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, Output>, } @@ -137,6 +135,7 @@ pub(crate) fn create_v4( battery_monitor: Box, rtc_module: Box, ) -> anyhow::Result + Send + 'static>> { + println!("Start v4"); let mut awake = PinDriver::output(peripherals.gpio21.downgrade())?; awake.set_high()?; @@ -163,27 +162,68 @@ pub(crate) fn create_v4( peripherals.pcnt1 )?; - let mut signal_counter = PcntDriver::new( - peripherals.pcnt0, - Some(peripherals.gpio22), - Option::::None, - Option::::None, - Option::::None, - )?; + let mut sensor_expander = Pca9535Immediate::new(MutexDevice::new(&I2C_DRIVER), 34); + let sensor = match sensor_expander.pin_into_output(GPIOBank::Bank0, 0) { + Ok(_) => { + println!("SensorExpander answered"); + //pulse counter version + 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, + }, + )?; + + 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); + let _ = sensor_expander.pin_set_low(GPIOBank::Bank1, pin); + } + + SensorImpl::PulseCounter { + signal_counter, + sensor_expander, + } + } + Err(_) => { + println!("Can bus mode "); + let timing = can::config::Timing::B25K; + let config = can::config::Config::new().timing(timing); + let mut can = can::CanDriver::new(peripherals.can, peripherals.gpio0, peripherals.gpio2, &config).unwrap(); + + + let frame = StandardId::new(0x042).unwrap(); + let tx_frame = Frame::new(frame, &[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); + can.transmit(&tx_frame, 1000).unwrap(); + + if let Ok(rx_frame) = can.receive(1000) { + println!("rx {:}:", rx_frame); + } + //can bus version + SensorImpl::CanBus { + can + } + } + }; + + - 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)?; @@ -203,13 +243,7 @@ pub(crate) fn create_v4( let _ = pump_expander.pin_set_low(GPIOBank::Bank1, pin); } - let mut sensor_expander = Pca9535Immediate::new(MutexDevice::new(&I2C_DRIVER), 34); - 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); - let _ = sensor_expander.pin_set_low(GPIOBank::Bank1, pin); - } + let mppt_ina = SyncIna219::new( MutexDevice::new(&I2C_DRIVER), @@ -252,17 +286,16 @@ pub(crate) fn create_v4( esp, awake, tank_sensor, - signal_counter, light, general_fault, pump_ina, pump_expander, - sensor_expander, config, battery_monitor, charger, extra1, extra2, + sensor, }; Ok(Box::new(v)) } @@ -350,78 +383,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> { } fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> anyhow::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.sensor_expander.pin_set_high(GPIOBank::Bank0, MS4)?; - - let sensor_channel = match sensor { - 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) { - self.sensor_expander.pin_set_high(GPIOBank::Bank0, MS0)?; - } else { - self.sensor_expander.pin_set_low(GPIOBank::Bank0, MS0)?; - } - if is_bit_set(1) { - self.sensor_expander.pin_set_high(GPIOBank::Bank0, MS1)?; - } else { - self.sensor_expander.pin_set_low(GPIOBank::Bank0, MS1)?; - } - if is_bit_set(2) { - self.sensor_expander.pin_set_high(GPIOBank::Bank0, MS2)?; - } else { - self.sensor_expander.pin_set_low(GPIOBank::Bank0, MS2)?; - } - if is_bit_set(3) { - self.sensor_expander.pin_set_high(GPIOBank::Bank0, MS3)?; - } else { - self.sensor_expander.pin_set_low(GPIOBank::Bank0, MS3)?; - } - - self.sensor_expander.pin_set_low(GPIOBank::Bank0, MS4)?; - self.sensor_expander - .pin_set_high(GPIOBank::Bank0, SENSOR_ON)?; - - let delay = Delay::new_default(); - let measurement = 100; // TODO what is this scaling factor? what is its purpose? - let factor = 1000f32 / measurement as f32; - - //give some time to stabilize - delay.delay_ms(10); - self.signal_counter.counter_resume()?; - delay.delay_ms(measurement); - self.signal_counter.counter_pause()?; - self.sensor_expander.pin_set_high(GPIOBank::Bank0, MS4)?; - self.sensor_expander - .pin_set_low(GPIOBank::Bank0, SENSOR_ON)?; - self.sensor_expander.pin_set_low(GPIOBank::Bank0, MS0)?; - self.sensor_expander.pin_set_low(GPIOBank::Bank0, MS1)?; - self.sensor_expander.pin_set_low(GPIOBank::Bank0, MS2)?; - self.sensor_expander.pin_set_low(GPIOBank::Bank0, MS3)?; - 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]; - anyhow::Ok(median) + self.sensor.measure_moisture_hz(plant, sensor) } fn general_fault(&mut self, enable: bool) { diff --git a/rust/src/hal/v4_sensor.rs b/rust/src/hal/v4_sensor.rs new file mode 100644 index 0000000..3fcfcf2 --- /dev/null +++ b/rust/src/hal/v4_sensor.rs @@ -0,0 +1,115 @@ +use embedded_hal_bus::i2c::MutexDevice; +use esp_idf_hal::can::CanDriver; +use esp_idf_hal::delay::Delay; +use esp_idf_hal::i2c::I2cDriver; +use esp_idf_hal::pcnt::PcntDriver; +use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface}; +use crate::hal::Sensor; +use crate::log::{log, LogMessage}; + +const REPEAT_MOIST_MEASURE: usize = 10; + +pub trait SensorInteraction { + fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> anyhow::Result; +} + +const MS0: u8 = 1_u8; +const MS1: u8 = 0_u8; +const MS2: u8 = 3_u8; +const MS3: u8 = 4_u8; +const MS4: u8 = 2_u8; +const SENSOR_ON: u8 = 5_u8; + +pub enum SensorImpl<'a> { + PulseCounter{ + signal_counter: PcntDriver<'a>, + sensor_expander: Pca9535Immediate>>, + }, + CanBus{ + can: CanDriver<'a> + } +} + +impl SensorInteraction for SensorImpl<'_> { + fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> anyhow::Result { + match self { + SensorImpl::PulseCounter { signal_counter, sensor_expander, .. } => { + let mut results = [0_f32; REPEAT_MOIST_MEASURE]; + for repeat in 0..REPEAT_MOIST_MEASURE { + signal_counter.counter_pause()?; + signal_counter.counter_clear()?; + + //Disable all + sensor_expander.pin_set_high(GPIOBank::Bank0, MS4)?; + + let sensor_channel = match sensor { + 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)?; + } else { + sensor_expander.pin_set_low(GPIOBank::Bank0, MS0)?; + } + if is_bit_set(1) { + sensor_expander.pin_set_high(GPIOBank::Bank0, MS1)?; + } else { + sensor_expander.pin_set_low(GPIOBank::Bank0, MS1)?; + } + if is_bit_set(2) { + sensor_expander.pin_set_high(GPIOBank::Bank0, MS2)?; + } else { + sensor_expander.pin_set_low(GPIOBank::Bank0, MS2)?; + } + if is_bit_set(3) { + sensor_expander.pin_set_high(GPIOBank::Bank0, MS3)?; + } else { + sensor_expander.pin_set_low(GPIOBank::Bank0, MS3)?; + } + + sensor_expander.pin_set_low(GPIOBank::Bank0, MS4)?; + sensor_expander + .pin_set_high(GPIOBank::Bank0, SENSOR_ON)?; + + let delay = Delay::new_default(); + let measurement = 100; // TODO what is this scaling factor? what is its purpose? + let factor = 1000f32 / measurement as f32; + + //give some time to stabilize + delay.delay_ms(10); + signal_counter.counter_resume()?; + delay.delay_ms(measurement); + signal_counter.counter_pause()?; + sensor_expander.pin_set_high(GPIOBank::Bank0, MS4)?; + sensor_expander + .pin_set_low(GPIOBank::Bank0, SENSOR_ON)?; + sensor_expander.pin_set_low(GPIOBank::Bank0, MS0)?; + sensor_expander.pin_set_low(GPIOBank::Bank0, MS1)?; + sensor_expander.pin_set_low(GPIOBank::Bank0, MS2)?; + sensor_expander.pin_set_low(GPIOBank::Bank0, MS3)?; + delay.delay_ms(10); + let unscaled = 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]; + anyhow::Ok(median) + } + SensorImpl::CanBus { .. } => { + todo!() + } + } + } +}