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.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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<RefCell<Option<Unit<'static, 1>>>> =
|
||||
CriticalSectionMutex::new(RefCell::new(None));
|
||||
|
||||
pub struct TankSensor<'a> {
|
||||
one_wire_bus: OneWire<Flex<'a>>,
|
||||
tank_channel: Adc<'a, ADC1<'a>, Async>,
|
||||
tank_power: Output<'a>,
|
||||
tank_pin: AdcPin<GPIO5<'a>, ADC1<'a>, AdcCalLine<ADC1<'a>>>,
|
||||
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<TankSensor<'a>, 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<f32, FatError> {
|
||||
@@ -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<f32, FatError> = 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user