add pump expander
This commit is contained in:
@@ -24,6 +24,8 @@ CHRONO_TZ_TIMEZONE_FILTER = "UTC|America/New_York|America/Chicago|America/Los_An
|
||||
CARGO_WORKSPACE_DIR = { value = "", relative = true }
|
||||
ESP_LOG = "info"
|
||||
|
||||
|
||||
|
||||
[unstable]
|
||||
build-std = ["alloc", "core"]
|
||||
|
||||
|
@@ -72,7 +72,8 @@ esp-println = { version = "0.15.0", features = ["esp32c6", "log-04"] }
|
||||
# for more networking protocol support see https://crates.io/crates/edge-net
|
||||
embassy-executor = { version = "0.7.0", features = [
|
||||
"log",
|
||||
"task-arena-size-98304"
|
||||
"task-arena-size-64",
|
||||
"nightly"
|
||||
] }
|
||||
embassy-time = { version = "0.5.0", features = ["log"], default-features = false }
|
||||
esp-hal-embassy = { version = "0.9.0", features = ["esp32c6", "log-04"] }
|
||||
|
@@ -10,6 +10,7 @@ use esp_hal::i2c::master::ConfigError;
|
||||
use esp_wifi::wifi::WifiError;
|
||||
use littlefs2_core::PathError;
|
||||
use onewire::Error;
|
||||
use pca9535::ExpanderError;
|
||||
|
||||
//All error superconstruct
|
||||
#[derive(Debug)]
|
||||
@@ -54,6 +55,9 @@ pub enum FatError {
|
||||
Eeprom24x {
|
||||
error: String,
|
||||
},
|
||||
ExpanderError {
|
||||
error: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub type FatResult<T> = Result<T, FatError>;
|
||||
@@ -81,6 +85,7 @@ impl fmt::Display for FatError {
|
||||
FatError::I2CConfigError { error } => write!(f, "I2CConfigError {:?}", error),
|
||||
FatError::DS323 { error } => write!(f, "DS323 {:?}", error),
|
||||
FatError::Eeprom24x { error } => write!(f, "Eeprom24x {:?}", error),
|
||||
FatError::ExpanderError { error } => write!(f, "ExpanderError {:?}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,7 +183,7 @@ impl From<Utf8Error> for FatError {
|
||||
impl<E: core::fmt::Debug> From<edge_http::io::Error<E>> for FatError {
|
||||
fn from(value: edge_http::io::Error<E>) -> Self {
|
||||
FatError::String {
|
||||
error: format!("HttpIoError {:?}", value),
|
||||
error: format!("{:?}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +191,7 @@ impl<E: core::fmt::Debug> From<edge_http::io::Error<E>> for FatError {
|
||||
impl<E: core::fmt::Debug> From<ds323x::Error<E>> for FatError {
|
||||
fn from(value: ds323x::Error<E>) -> Self {
|
||||
FatError::DS323 {
|
||||
error: format!("Ds323xError {:?}", value),
|
||||
error: format!("{:?}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,7 +199,15 @@ impl<E: core::fmt::Debug> From<ds323x::Error<E>> for FatError {
|
||||
impl<E: core::fmt::Debug> From<eeprom24x::Error<E>> for FatError {
|
||||
fn from(value: eeprom24x::Error<E>) -> Self {
|
||||
FatError::Eeprom24x {
|
||||
error: format!("Eeprom24xError {:?}", value),
|
||||
error: format!("{:?}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: core::fmt::Debug> From<ExpanderError<I2cDeviceError<E>>> for FatError {
|
||||
fn from(value: ExpanderError<I2cDeviceError<E>>) -> Self {
|
||||
FatError::ExpanderError {
|
||||
error: format!("{:?}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,7 +215,7 @@ impl<E: core::fmt::Debug> From<eeprom24x::Error<E>> for FatError {
|
||||
impl From<bincode::error::DecodeError> for FatError {
|
||||
fn from(value: bincode::error::DecodeError) -> Self {
|
||||
FatError::Eeprom24x {
|
||||
error: format!("Eeprom24xError {:?}", value),
|
||||
error: format!("{:?}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,7 +223,7 @@ impl From<bincode::error::DecodeError> for FatError {
|
||||
impl From<bincode::error::EncodeError> for FatError {
|
||||
fn from(value: bincode::error::EncodeError) -> Self {
|
||||
FatError::Eeprom24x {
|
||||
error: format!("Eeprom24xError {:?}", value),
|
||||
error: format!("{:?}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -104,7 +104,7 @@ pub static TIME_ACCESS: OnceLock<Rtc> = OnceLock::new();
|
||||
pub const PLANT_COUNT: usize = 8;
|
||||
|
||||
const TANK_MULTI_SAMPLE: usize = 11;
|
||||
static I2C_DRIVER: OnceLock<
|
||||
pub static I2C_DRIVER: OnceLock<
|
||||
embassy_sync::blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<I2c<Blocking>>>,
|
||||
> = OnceLock::new();
|
||||
|
||||
@@ -144,13 +144,13 @@ pub trait BoardInteraction<'a> {
|
||||
async fn get_mptt_current(&mut self) -> Result<Current, FatError>;
|
||||
|
||||
async fn progress(&mut self, counter: u32) {
|
||||
let even = counter % 2 == 0;
|
||||
let current = counter / (PLANT_COUNT as u32);
|
||||
for led in 0..PLANT_COUNT {
|
||||
if let Err(err) = self.fault(led, current == led as u32).await {
|
||||
warn!("Fault on plant {}: {:?}", led, err);
|
||||
}
|
||||
}
|
||||
let even = counter % 2 == 0;
|
||||
let _ = self.general_fault(even.into()).await;
|
||||
}
|
||||
}
|
||||
@@ -529,7 +529,8 @@ impl PlantHal {
|
||||
// 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)?
|
||||
v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module)
|
||||
.await?
|
||||
}
|
||||
_ => {
|
||||
todo!()
|
||||
|
@@ -3,14 +3,21 @@ use crate::hal::battery::BatteryInteraction;
|
||||
use crate::hal::esp::Esp;
|
||||
use crate::hal::rtc::RTCModuleInteraction;
|
||||
use crate::hal::water::TankSensor;
|
||||
use crate::hal::{BoardInteraction, FreePeripherals, Sensor};
|
||||
use crate::hal::{BoardInteraction, FreePeripherals, Sensor, I2C_DRIVER};
|
||||
use alloc::boxed::Box;
|
||||
use async_trait::async_trait;
|
||||
use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use esp_hal::Blocking;
|
||||
//use embedded_hal_bus::i2c::MutexDevice;
|
||||
use crate::bail;
|
||||
use crate::FatError::FatError;
|
||||
use crate::FatError::{FatError, FatResult};
|
||||
use esp_hal::gpio::{Flex, Level, Output, OutputConfig};
|
||||
use esp_hal::i2c::master::I2c;
|
||||
use ina219::address::{Address, Pin};
|
||||
use ina219::SyncIna219;
|
||||
use measurements::{Current, Voltage};
|
||||
use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface};
|
||||
// pub enum Charger<'a> {
|
||||
// SolarMpptV1 {
|
||||
// mppt_ina: SyncIna219<MutexDevice<'a, I2cDriver<'a>>, UnCalibrated>,
|
||||
@@ -101,7 +108,7 @@ pub struct V4<'a> {
|
||||
awake: Output<'a>,
|
||||
light: Output<'a>,
|
||||
general_fault: Output<'a>,
|
||||
//pump_expander: Pca9535Immediate<MutexDevice<'a, I2cDriver<'a>>>,
|
||||
pump_expander: Pca9535Immediate<I2cDevice<'a, CriticalSectionRawMutex, I2c<'static, Blocking>>>,
|
||||
//pump_ina: Option<SyncIna219<MutexDevice<'a, I2cDriver<'a>>, UnCalibrated>>,
|
||||
//sensor: SensorImpl<'a>,
|
||||
extra1: Output<'a>,
|
||||
@@ -112,7 +119,7 @@ struct InputOutput<'a> {
|
||||
pin: Flex<'a>,
|
||||
}
|
||||
|
||||
pub(crate) fn create_v4(
|
||||
pub(crate) async fn create_v4(
|
||||
peripherals: FreePeripherals<'static>,
|
||||
esp: Esp<'static>,
|
||||
config: PlantControllerConfig,
|
||||
@@ -209,19 +216,18 @@ pub(crate) fn create_v4(
|
||||
let mut light = Output::new(peripherals.gpio10, Level::Low, Default::default());
|
||||
let mut charge_indicator = Output::new(peripherals.gpio3, Level::Low, Default::default());
|
||||
|
||||
// let mut pump_expander = Pca9535Immediate::new(MutexDevice::new(&I2C_DRIVER), 32);
|
||||
// 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);
|
||||
// let _ = pump_expander.pin_set_low(GPIOBank::Bank1, pin);
|
||||
// }
|
||||
//
|
||||
// let mppt_ina = SyncIna219::new(
|
||||
// MutexDevice::new(&I2C_DRIVER),
|
||||
// Address::from_pins(Pin::Vcc, Pin::Gnd),
|
||||
// );
|
||||
//
|
||||
let pump_device = I2cDevice::new(I2C_DRIVER.get().await);
|
||||
let mut pump_expander = Pca9535Immediate::new(pump_device, 32);
|
||||
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);
|
||||
let _ = pump_expander.pin_set_low(GPIOBank::Bank1, pin);
|
||||
}
|
||||
|
||||
let mppt_current = I2cDevice::new(I2C_DRIVER.get().await);
|
||||
let mppt_ina = SyncIna219::new(mppt_current, Address::from_pins(Pin::Vcc, Pin::Gnd));
|
||||
|
||||
// let charger = match mppt_ina {
|
||||
// Ok(mut mppt_ina) => {
|
||||
// mppt_ina.set_configuration(Configuration {
|
||||
@@ -261,7 +267,7 @@ pub(crate) fn create_v4(
|
||||
light,
|
||||
general_fault,
|
||||
//pump_ina,
|
||||
//pump_expander,
|
||||
pump_expander,
|
||||
config,
|
||||
battery_monitor,
|
||||
//charger,
|
||||
@@ -318,16 +324,15 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
||||
// anyhow::Ok(())
|
||||
}
|
||||
|
||||
async fn pump(&mut self, plant: usize, enable: bool) -> Result<(), FatError> {
|
||||
bail!("not implemented");
|
||||
// if enable {
|
||||
// self.pump_expander
|
||||
// .pin_set_high(GPIOBank::Bank0, plant.try_into()?)?;
|
||||
// } else {
|
||||
// self.pump_expander
|
||||
// .pin_set_low(GPIOBank::Bank0, plant.try_into()?)?;
|
||||
// }
|
||||
// anyhow::Ok(())
|
||||
async fn pump(&mut self, plant: usize, enable: bool) -> FatResult<()> {
|
||||
if enable {
|
||||
self.pump_expander
|
||||
.pin_set_high(GPIOBank::Bank0, plant as u8)?;
|
||||
} else {
|
||||
self.pump_expander
|
||||
.pin_set_low(GPIOBank::Bank0, plant as u8)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn pump_current(&mut self, _plant: usize) -> Result<Current, FatError> {
|
||||
@@ -349,16 +354,15 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
||||
// }
|
||||
}
|
||||
|
||||
async fn fault(&mut self, plant: usize, enable: bool) -> Result<(), FatError> {
|
||||
bail!("not implemented");
|
||||
// if enable {
|
||||
// self.pump_expander
|
||||
// .pin_set_high(GPIOBank::Bank1, plant.try_into()?)?
|
||||
// } else {
|
||||
// self.pump_expander
|
||||
// .pin_set_low(GPIOBank::Bank1, plant.try_into()?)?
|
||||
// }
|
||||
// anyhow::Ok(())
|
||||
async fn fault(&mut self, plant: usize, enable: bool) -> FatResult<()> {
|
||||
if enable {
|
||||
self.pump_expander
|
||||
.pin_set_high(GPIOBank::Bank1, plant as u8)?;
|
||||
} else {
|
||||
self.pump_expander
|
||||
.pin_set_low(GPIOBank::Bank1, plant as u8)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result<f32, FatError> {
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#![no_main]
|
||||
#![feature(never_type)]
|
||||
#![feature(string_from_utf8_lossy_owned)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![deny(
|
||||
clippy::mem_forget,
|
||||
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
|
||||
|
@@ -276,6 +276,7 @@ impl Handler for HttpHandler {
|
||||
let mut chunk = 0;
|
||||
loop {
|
||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||
board.board_hal.progress(chunk as u32).await;
|
||||
let read_chunk = board
|
||||
.board_hal
|
||||
.get_esp()
|
||||
@@ -308,6 +309,7 @@ impl Handler for HttpHandler {
|
||||
}
|
||||
|
||||
let mut offset = 0_usize;
|
||||
let mut chunk = 0;
|
||||
loop {
|
||||
let mut buf = [0_u8; 1024];
|
||||
let to_write = conn.read(&mut buf).await?;
|
||||
@@ -316,13 +318,15 @@ impl Handler for HttpHandler {
|
||||
break;
|
||||
} else {
|
||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||
board.board_hal.progress(chunk as u32).await;
|
||||
board
|
||||
.board_hal
|
||||
.get_esp()
|
||||
.write_file(filename.to_owned(), offset as u32, &buf[0..to_write])
|
||||
.await?;
|
||||
}
|
||||
offset = offset + to_write
|
||||
offset = offset + to_write;
|
||||
chunk = chunk + 1;
|
||||
}
|
||||
|
||||
Some(200)
|
||||
@@ -437,80 +441,67 @@ async fn get_backup_config<T, const N: usize>(
|
||||
where
|
||||
T: Read + Write,
|
||||
{
|
||||
// First pass: verify checksum without sending data
|
||||
let mut checksum = X25.digest();
|
||||
let mut chunk = 0_usize;
|
||||
loop {
|
||||
info!("Chunk {}", chunk);
|
||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||
board.board_hal.progress(chunk as u32).await;
|
||||
let read_chunk = board
|
||||
let (buf, len, expected_crc) = board
|
||||
.board_hal
|
||||
.get_rtc_module()
|
||||
.get_backup_config(chunk)
|
||||
.await?;
|
||||
let length = read_chunk.1;
|
||||
info!("Length {}", length);
|
||||
if length == 0 {
|
||||
let check = checksum.finalize();
|
||||
if check != read_chunk.2 {
|
||||
if check != read_chunk.2 {
|
||||
|
||||
// Update checksum with the actual data bytes of this chunk
|
||||
checksum.update(&buf[..len]);
|
||||
|
||||
let is_last = len == 0 || len < buf.len();
|
||||
if is_last {
|
||||
let actual_crc = checksum.finalize();
|
||||
if actual_crc != expected_crc {
|
||||
conn.initiate_response(
|
||||
409,
|
||||
Some(
|
||||
format!("Checksum mismatch expected {} got {}", read_chunk.2, check)
|
||||
format!(
|
||||
"Checksum mismatch expected {} got {}",
|
||||
expected_crc, actual_crc
|
||||
)
|
||||
.as_str(),
|
||||
),
|
||||
&[],
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
info!("file request for backup finished");
|
||||
break;
|
||||
}
|
||||
let data = &read_chunk.0[0..length];
|
||||
checksum.update(&data);
|
||||
if length < read_chunk.0.len() {
|
||||
let check = checksum.finalize();
|
||||
if check != read_chunk.2 {
|
||||
conn.initiate_response(
|
||||
409,
|
||||
Some(
|
||||
format!("Checksum mismatch expected {} got {}", read_chunk.2, check)
|
||||
.as_str(),
|
||||
),
|
||||
&[],
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
info!("file request for backup finished");
|
||||
break;
|
||||
}
|
||||
chunk = chunk + 1;
|
||||
chunk += 1;
|
||||
}
|
||||
|
||||
// Second pass: stream data
|
||||
conn.initiate_response(200, Some("OK"), &[]).await?;
|
||||
|
||||
let mut chunk = 0;
|
||||
let mut chunk = 0_usize;
|
||||
loop {
|
||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||
board.board_hal.progress(chunk as u32).await;
|
||||
let read_chunk = board
|
||||
let (buf, len, _expected_crc) = board
|
||||
.board_hal
|
||||
.get_rtc_module()
|
||||
.get_backup_config(chunk)
|
||||
.await?;
|
||||
let length = read_chunk.1;
|
||||
if length == 0 {
|
||||
info!("file request for backup finished");
|
||||
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
let data = &read_chunk.0[0..length];
|
||||
conn.write_all(data).await?;
|
||||
if length < read_chunk.0.len() {
|
||||
info!("file request for backup finished");
|
||||
|
||||
conn.write_all(&buf[..len]).await?;
|
||||
|
||||
if len < buf.len() {
|
||||
break;
|
||||
}
|
||||
chunk = chunk + 1;
|
||||
chunk += 1;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -756,18 +747,18 @@ async fn get_time<T, const N: usize>(
|
||||
_request: &mut Connection<'_, T, N>,
|
||||
) -> FatResult<Option<String>> {
|
||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||
//TODO do not fail if rtc module is missing
|
||||
|
||||
let native = esp_time().await.to_rfc3339();
|
||||
let rtc = "todo";
|
||||
// board
|
||||
// .board_hal
|
||||
// .get_rtc_module()
|
||||
// .get_rtc_time()
|
||||
// .await?
|
||||
// .to_rfc3339();
|
||||
|
||||
let rtc = match board.board_hal.get_rtc_module().get_rtc_time().await {
|
||||
Ok(time) => time.to_rfc3339(),
|
||||
Err(err) => {
|
||||
format!("Error getting time: {}", err)
|
||||
}
|
||||
};
|
||||
|
||||
let data = LoadData {
|
||||
rtc,
|
||||
rtc: rtc.as_str(),
|
||||
native: native.as_str(),
|
||||
};
|
||||
let json = serde_json::to_string(&data)?;
|
||||
@@ -872,32 +863,6 @@ pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
|
||||
// cors_response(request, 200, "")
|
||||
// })
|
||||
// .unwrap();
|
||||
// server
|
||||
// .fn_handler("/get_config", Method::Get, move |request| {
|
||||
// handle_error_to500(request, get_config)
|
||||
// })
|
||||
// .unwrap();
|
||||
// server
|
||||
// .fn_handler("/get_backup_config", Method::Get, move |request| {
|
||||
// handle_error_to500(request, get_backup_config)
|
||||
// })
|
||||
// .unwrap();
|
||||
//
|
||||
// server
|
||||
// .fn_handler("/backup_config", Method::Post, move |request| {
|
||||
// handle_error_to500(request, backup_config)
|
||||
// })
|
||||
// .unwrap();
|
||||
// server
|
||||
// .fn_handler("/backup_info", Method::Get, move |request| {
|
||||
// handle_error_to500(request, backup_info)
|
||||
// })
|
||||
// .unwrap();
|
||||
// server
|
||||
// .fn_handler("/files", Method::Get, move |request| {
|
||||
// handle_error_to500(request, list_files)
|
||||
// })
|
||||
// .unwrap();
|
||||
// let reboot_now_for_reboot = reboot_now.clone();
|
||||
// server
|
||||
// .fn_handler("/reboot", Method::Post, move |_| {
|
||||
|
Reference in New Issue
Block a user