use super::timer::{self, InstanceX};
pub use super::timer::{Ch1, Ch2, ChExt};
use crate::ext::{CptcrW, MasterExt, TimExt};
use core::marker::PhantomData;
pub struct Dma;
pub struct NoDma;
pub type HrCaptCh1<TIM, PSCL> = HrCapt<TIM, PSCL, Ch1, NoDma>;
pub type HrCaptCh2<TIM, PSCL> = HrCapt<TIM, PSCL, Ch2, NoDma>;
pub struct HrCapt<TIM, PSCL, CH, DMA> {
_x: PhantomData<(TIM, PSCL, CH, DMA)>,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, Debug)]
pub enum CountingDirection {
Up = 0,
#[cfg(feature = "hrtim_v2")]
Down = 1,
}
pub trait CaptureEvent<TIM, PSCL> {
const BITS: u32;
}
pub trait HrCapture {
fn get(&mut self) -> Option<(u16, CountingDirection)> {
if self.is_pending() {
let value = self.get_last();
self.clear_interrupt();
Some(value)
} else {
None
}
}
fn get_signed(&mut self, period: u16) -> Option<i32> {
if self.is_pending() {
let value = self.get_last_signed(period);
self.clear_interrupt();
Some(value)
} else {
None
}
}
fn get_last(&self) -> (u16, CountingDirection);
fn get_last_signed(&self, #[allow(unused_variables)] period: u16) -> i32 {
let (value, dir) = self.get_last();
match dir {
CountingDirection::Up => i32::from(value),
#[cfg(feature = "hrtim_v2")]
CountingDirection::Down => i32::from(value) - i32::from(period),
}
}
fn clear_interrupt(&mut self);
fn is_pending(&self) -> bool;
}
pub fn dma_value_to_dir_and_value(x: u32) -> (u16, CountingDirection) {
let value = (x & 0xFFFF) as u16;
#[cfg(feature = "hrtim_v2")]
match x & (1 << 16) != 0 {
true => (value, CountingDirection::Down),
false => (value, CountingDirection::Up),
}
#[cfg(any(feature = "hrtim_v1", feature = "hrtim_v1_1"))]
(value, CountingDirection::Up)
}
pub fn dma_value_to_signed(x: u32, #[allow(unused_variables)] period: u16) -> i32 {
let (value, dir) = dma_value_to_dir_and_value(x);
match dir {
CountingDirection::Up => i32::from(value),
#[cfg(feature = "hrtim_v2")]
CountingDirection::Down => i32::from(value) - i32::from(period),
}
}
impl<TIM: InstanceX, CH: ChExt, PSCL> HrCapt<TIM, PSCL, CH, NoDma> {
pub fn add_event<E: CaptureEvent<TIM, PSCL>>(&mut self, _event: &E) {
let tim = unsafe { &*TIM::ptr() };
unsafe {
tim.cptcr(CH::CH).modify(|r, w| w.bits(r.bits() | E::BITS));
}
}
pub fn remove_event<E: CaptureEvent<TIM, PSCL>>(&mut self, _event: &E) {
let tim = unsafe { &*TIM::ptr() };
unsafe {
tim.cptcr(CH::CH).modify(|r, w| w.bits(r.bits() & !E::BITS));
}
}
pub fn trigger_now(&mut self) {
let tim = unsafe { &*TIM::ptr() };
tim.cptcr(CH::CH).modify(|_, w| w.set_swcpt());
}
pub fn enable_interrupt(&mut self, enable: bool, _hr_control: &mut super::HrPwmControl) {
let tim = unsafe { &*TIM::ptr() };
tim.dier().modify(|_r, w| w.cptie(CH::CH as _).bit(enable));
}
pub fn enable_dma(self, _ch: timer::DmaChannel<TIM>) -> HrCapt<TIM, PSCL, CH, Dma> {
let tim = unsafe { &*TIM::ptr() };
tim.dier().modify(|_r, w| w.cptde(CH::CH as _).set_bit());
HrCapt { _x: PhantomData }
}
}
impl<TIM: InstanceX, CH: ChExt, PSCL, DMA> HrCapture for HrCapt<TIM, PSCL, CH, DMA> {
fn get_last(&self) -> (u16, CountingDirection) {
let tim = unsafe { &*TIM::ptr() };
let data = tim.cptr(CH::CH).read();
#[cfg(feature = "hrtim_v2")]
let dir = match data.dir().bit() {
true => CountingDirection::Down,
false => CountingDirection::Up,
};
#[cfg(any(feature = "hrtim_v1", feature = "hrtim_v1_1"))]
let dir = CountingDirection::Up;
let value = data.cpt().bits();
(value, dir)
}
fn clear_interrupt(&mut self) {
let tim = unsafe { &*TIM::ptr() };
tim.icr().write(|w| w.cptc(CH::CH as _).clear());
}
fn is_pending(&self) -> bool {
let tim = unsafe { &*TIM::ptr() };
tim.isr().read().cpt(CH::CH as _).bit()
}
}