From 3be585ecbf29059c1020583efdce5c3d464fa503 Mon Sep 17 00:00:00 2001 From: Empire Phoenix Date: Tue, 5 May 2026 00:49:38 +0200 Subject: [PATCH] Refactor flow meter handling with interrupt-based logic and global state - Added `flow_interrupt_handler` for efficient interrupt processing. - Replaced per-instance `flow_counter` with global atomic and mutex-based state (`FLOW_OVERFLOW_COUNTER`, `FLOW_UNIT`). - Updated flow meter functions to leverage the new architecture for better modularity and thread safety. - Switched debugging output from `println!` to `log` for improved logging consistency. --- Software/MainBoard/rust/src/hal/mod.rs | 3 +- Software/MainBoard/rust/src/hal/water.rs | 88 +++++++++++++++++++----- 2 files changed, 72 insertions(+), 19 deletions(-) diff --git a/Software/MainBoard/rust/src/hal/mod.rs b/Software/MainBoard/rust/src/hal/mod.rs index e64d2b9..405b9a8 100644 --- a/Software/MainBoard/rust/src/hal/mod.rs +++ b/Software/MainBoard/rust/src/hal/mod.rs @@ -290,7 +290,8 @@ impl PlantHal { error: format!("Could not init wifi: {:?}", e), })?; - let pcnt_module = Pcnt::new(peripherals.PCNT); + let mut pcnt_module = Pcnt::new(peripherals.PCNT); + pcnt_module.set_interrupt_handler(water::flow_interrupt_handler); let free_pins = FreePeripherals { gpio0: peripherals.GPIO0, diff --git a/Software/MainBoard/rust/src/hal/water.rs b/Software/MainBoard/rust/src/hal/water.rs index 5f3b457..8e02489 100644 --- a/Software/MainBoard/rust/src/hal/water.rs +++ b/Software/MainBoard/rust/src/hal/water.rs @@ -1,6 +1,8 @@ use crate::bail; use crate::fat_error::FatError; use crate::hal::{ADC1, TANK_MULTI_SAMPLE}; +use core::cell::RefCell; +use embassy_sync::blocking_mutex::CriticalSectionMutex; use embassy_time::Timer; use esp_hal::analog::adc::{Adc, AdcCalLine, AdcConfig, AdcPin, Attenuation}; use esp_hal::delay::Delay; @@ -10,17 +12,21 @@ use esp_hal::pcnt::channel::EdgeMode::{Hold, Increment}; use esp_hal::pcnt::unit::Unit; use esp_hal::peripherals::GPIO5; use esp_hal::Async; -use esp_println::println; +use log::info; use onewire::{ds18b20, Device, DeviceSearch, OneWire, DS18B20}; +use portable_atomic::{AtomicUsize, Ordering}; unsafe impl Send for TankSensor<'_> {} +static FLOW_OVERFLOW_COUNTER: AtomicUsize = AtomicUsize::new(0); +static FLOW_UNIT: CriticalSectionMutex>>> = + CriticalSectionMutex::new(RefCell::new(None)); + pub struct TankSensor<'a> { one_wire_bus: OneWire>, tank_channel: Adc<'a, ADC1<'a>, Async>, tank_power: Output<'a>, tank_pin: AdcPin, ADC1<'a>, AdcCalLine>>, - flow_counter: Unit<'a, 1>, } impl<'a> TankSensor<'a> { @@ -30,7 +36,7 @@ impl<'a> TankSensor<'a> { gpio5: GPIO5<'a>, tank_power: Output<'a>, flow_sensor: Input, - pcnt1: Unit<'a, 1>, + pcnt1: Unit<'static, 1>, ) -> Result, FatError> { one_wire_pin.apply_output_config( &OutputConfig::default() @@ -55,33 +61,64 @@ impl<'a> TankSensor<'a> { ch0.set_edge_signal(flow_sensor.peripheral_input()); ch0.set_input_mode(Hold, Increment); ch0.set_ctrl_mode(Keep, Keep); + pcnt1.listen(); + FLOW_UNIT.lock(|refcell| { + refcell.borrow_mut().replace(pcnt1); + }); + Ok(TankSensor { one_wire_bus, tank_channel, tank_power, tank_pin, - flow_counter: pcnt1, }) } pub fn reset_flow_meter(&mut self) { - self.flow_counter.pause(); - self.flow_counter.clear(); + FLOW_OVERFLOW_COUNTER.store(0, Ordering::SeqCst); + FLOW_UNIT.lock(|refcell| { + if let Some(unit) = refcell.borrow_mut().as_mut() { + unit.pause(); + unit.clear(); + } + }); } pub fn start_flow_meter(&mut self) { - self.flow_counter.resume(); + FLOW_UNIT.lock(|refcell| { + if let Some(unit) = refcell.borrow_mut().as_mut() { + unit.resume(); + } + }); } pub fn get_flow_meter_value(&mut self) -> i16 { - self.flow_counter.value() + FLOW_UNIT.lock(|refcell| { + refcell.borrow_mut().as_mut().map_or(0, |unit| unit.value()) + }) } pub fn stop_flow_meter(&mut self) -> i16 { - self.flow_counter.pause(); - self.get_flow_meter_value() + FLOW_UNIT.lock(|refcell| { + let mut borrowed = refcell.borrow_mut(); + if let Some(unit) = borrowed.as_mut() { + let val = unit.value(); + unit.pause(); + val + } else { + 0 + } + }) + } + + pub fn get_full_flow_count(&self) -> u32 { + let current = FLOW_UNIT.lock(|refcell| { + refcell.borrow().as_ref().map_or(0, |unit| unit.value() as u32) + }); + let overflowed = FLOW_OVERFLOW_COUNTER.load(Ordering::SeqCst) as u32; + overflowed * (i16::MAX.wrapping_add(1) as u32) + current } pub async fn water_temperature_c(&mut self) -> Result { @@ -90,9 +127,9 @@ impl<'a> TankSensor<'a> { let mut delay = Delay::new(); let presence = self.one_wire_bus.reset(&mut delay)?; - println!("OneWire: reset presence pulse = {}", presence); + info!("OneWire: reset presence pulse = {}", presence); if !presence { - println!("OneWire: no device responded to reset — check pull-up resistor and wiring"); + info!("OneWire: no device responded to reset — check pull-up resistor and wiring"); } let mut search = DeviceSearch::new(); @@ -100,7 +137,7 @@ impl<'a> TankSensor<'a> { let mut devices_found = 0u8; while let Some(device) = self.one_wire_bus.search_next(&mut search, &mut delay)? { devices_found += 1; - println!( + info!( "OneWire: found device #{} family=0x{:02X} addr={:02X?}", devices_found, device.address[0], device.address ); @@ -108,16 +145,16 @@ impl<'a> TankSensor<'a> { water_temp_sensor = Some(device); break; } else { - println!("OneWire: skipping device — not a DS18B20 (family 0x{:02X} != 0x{:02X})", device.address[0], ds18b20::FAMILY_CODE); + info!("OneWire: skipping device — not a DS18B20 (family 0x{:02X} != 0x{:02X})", device.address[0], ds18b20::FAMILY_CODE); } } if devices_found == 0 { - println!("OneWire: search found zero devices on the bus"); + info!("OneWire: search found zero devices on the bus"); } match water_temp_sensor { Some(device) => { - println!("Found one wire device: {:?}", device); + info!("Found one wire device: {:?}", device); let mut water_temp_sensor = DS18B20::new(device)?; let water_temp: Result = loop { @@ -126,11 +163,11 @@ impl<'a> TankSensor<'a> { .await; match &temp { Ok(res) => { - println!("Water temp is {}", res); + info!("Water temp is {}", res); break temp; } Err(err) => { - println!("Could not get water temp {} attempt {}", err, attempt) + info!("Could not get water temp {} attempt {}", err, attempt) } } if attempt == 5 { @@ -178,3 +215,18 @@ impl<'a> TankSensor<'a> { Ok(median_mv / 1000.0) } } + +#[esp_hal::handler] +pub fn flow_interrupt_handler() { + FLOW_UNIT.lock(|refcell| { + if let Some(unit) = refcell.borrow_mut().as_mut() { + if unit.interrupt_is_set() { + let events = unit.events(); + if events.high_limit { + FLOW_OVERFLOW_COUNTER.fetch_add(1, Ordering::SeqCst); + } + unit.reset_interrupt(); + } + } + }); +}