can prepare stuff

This commit is contained in:
Empire 2025-08-14 22:10:53 +02:00
parent 7a7f000743
commit 50b2e994ca
6 changed files with 204 additions and 117 deletions

View File

@ -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]

View File

@ -51,6 +51,7 @@ pub(crate) fn create_initial_board(
config: PlantControllerConfig,
esp: Esp<'static>,
) -> Result<Box<dyn BoardInteraction<'static> + 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()?;

View File

@ -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,

View File

@ -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<dyn BatteryInteraction + Send>,
@ -91,6 +94,7 @@ pub(crate) fn create_v3(
battery_monitor: Box<dyn BatteryInteraction + Send>,
rtc_module: Box<dyn RTCModuleInteraction + Send>,
) -> Result<Box<dyn BoardInteraction<'static> + 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())?;

View File

@ -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<dyn RTCModuleInteraction + Send>,
battery_monitor: Box<dyn BatteryInteraction + Send>,
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<MutexDevice<'a, I2cDriver<'a>>>,
pump_ina: Option<SyncIna219<MutexDevice<'a, I2cDriver<'a>>, UnCalibrated>>,
sensor_expander: Pca9535Immediate<MutexDevice<'a, I2cDriver<'a>>>,
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<dyn BatteryInteraction + Send>,
rtc_module: Box<dyn RTCModuleInteraction + Send>,
) -> anyhow::Result<Box<dyn BoardInteraction<'static> + 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::<AnyInputPin>::None,
Option::<AnyInputPin>::None,
Option::<AnyInputPin>::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::<AnyInputPin>::None,
Option::<AnyInputPin>::None,
Option::<AnyInputPin>::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<f32> {
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) {

115
rust/src/hal/v4_sensor.rs Normal file
View File

@ -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<f32>;
}
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<MutexDevice<'a, I2cDriver<'a>>>,
},
CanBus{
can: CanDriver<'a>
}
}
impl SensorInteraction for SensorImpl<'_> {
fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> anyhow::Result<f32> {
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!()
}
}
}
}