use embassy_time::{Duration, Ticker};
use esp_hal::gpio::{AnyPin, Input, InputConfig};
use crate::driver::pcnt::PcntDriver;
pub struct RpmConfig {
pub loop_time_ms: u64,
pub pole_pairs: f32,
pub pulley_ratio: f32,
}
pub struct RpmResources<'a> {
pub pcnt: esp_hal::peripherals::PCNT<'a>,
pub pin: AnyPin<'a>,
}
impl RpmResources<'static> {
pub fn into_driver(self) -> PcntDriver {
let input = Input::new(
self.pin,
InputConfig::default().with_pull(esp_hal::gpio::Pull::Down),
);
PcntDriver::new(self.pcnt, input)
}
}
pub fn read_rpm(pcnt: &mut PcntDriver, config: &RpmConfig) -> f32 {
let pulse_count = pcnt.get_and_reset();
pulse_count as f32
* 60. * (1. / config.pole_pairs / 2.) * (1000. / config.loop_time_ms as f32) * config.pulley_ratio
}
const NO_SIGNAL_INTERVALS: u32 = 30;
pub async fn rpm_loop(resources: RpmResources<'static>, config: RpmConfig, on_rpm: fn(f32)) {
let mut pcnt_driver = resources.into_driver();
let mut ticker = Ticker::every(Duration::from_millis(config.loop_time_ms));
let mut zero_intervals: u32 = 0;
loop {
let rpm = read_rpm(&mut pcnt_driver, &config);
if rpm > 0.0 {
zero_intervals = 0;
on_rpm(rpm);
} else {
let prev = zero_intervals;
zero_intervals = zero_intervals.saturating_add(1);
if prev == 0 {
on_rpm(0.0); } else if prev == NO_SIGNAL_INTERVALS {
on_rpm(f32::NAN); }
}
ticker.next().await;
}
}