use core::marker::PhantomData;
use esp_sync::RawMutex;
use crate::{pcnt::channel::Channel, peripherals::PCNT, system::GenericPeripheralGuard};
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidFilterThreshold;
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidLowLimit;
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidHighLimit;
#[derive(Copy, Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ZeroMode {
#[default]
PosZero = 0,
NegZero = 1,
Negative = 2,
Positive = 3,
}
impl From<u8> for ZeroMode {
fn from(value: u8) -> Self {
match value {
0 => Self::PosZero,
1 => Self::NegZero,
2 => Self::Negative,
3 => Self::Positive,
_ => unreachable!(), }
}
}
#[derive(Copy, Clone, Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Events {
pub low_limit: bool,
pub high_limit: bool,
pub threshold0: bool,
pub threshold1: bool,
pub zero: bool,
}
#[non_exhaustive]
pub struct Unit<'d, const NUM: usize> {
pub counter: Counter<'d, NUM>,
pub channel0: Channel<'d, NUM, 0>,
pub channel1: Channel<'d, NUM, 1>,
}
static MUTEX: RawMutex = RawMutex::new();
impl<const NUM: usize> Unit<'_, NUM> {
pub(super) fn new() -> Self {
Self {
counter: Counter::new(),
channel0: Channel::new(),
channel1: Channel::new(),
}
}
pub fn set_low_limit(&self, value: Option<i16>) -> Result<(), InvalidLowLimit> {
let pcnt = PCNT::regs();
let unit = pcnt.unit(NUM);
if let Some(value) = value {
if !value.is_negative() {
return Err(InvalidLowLimit);
} else {
unit.conf2()
.modify(|_, w| unsafe { w.cnt_l_lim().bits(value as u16) });
unit.conf0().modify(|_, w| w.thr_l_lim_en().set_bit());
}
} else {
unit.conf0().modify(|_, w| w.thr_l_lim_en().clear_bit());
}
Ok(())
}
pub fn set_high_limit(&self, value: Option<i16>) -> Result<(), InvalidHighLimit> {
let pcnt = PCNT::regs();
let unit = pcnt.unit(NUM);
if let Some(value) = value {
if !value.is_positive() {
return Err(InvalidHighLimit);
} else {
unit.conf2()
.modify(|_, w| unsafe { w.cnt_h_lim().bits(value as u16) });
unit.conf0().modify(|_, w| w.thr_h_lim_en().set_bit());
}
} else {
unit.conf0().modify(|_, w| w.thr_h_lim_en().clear_bit());
}
Ok(())
}
pub fn set_threshold0(&self, value: Option<i16>) {
let pcnt = PCNT::regs();
let unit = pcnt.unit(NUM);
if let Some(value) = value {
unit.conf1()
.modify(|_, w| unsafe { w.cnt_thres0().bits(value as u16) });
unit.conf0().modify(|_, w| w.thr_thres0_en().set_bit());
} else {
unit.conf0().modify(|_, w| w.thr_thres0_en().clear_bit());
}
}
pub fn set_threshold1(&self, value: Option<i16>) {
let pcnt = PCNT::regs();
let unit = pcnt.unit(NUM);
if let Some(value) = value {
unit.conf1()
.modify(|_, w| unsafe { w.cnt_thres1().bits(value as u16) });
unit.conf0().modify(|_, w| w.thr_thres1_en().set_bit());
} else {
unit.conf0().modify(|_, w| w.thr_thres1_en().clear_bit());
}
}
pub fn set_filter(&self, threshold: Option<u16>) -> Result<(), InvalidFilterThreshold> {
let pcnt = PCNT::regs();
let unit = pcnt.unit(NUM);
match threshold {
None => {
unit.conf0().modify(|_, w| w.filter_en().clear_bit());
}
Some(threshold) => {
if threshold > 1023 {
return Err(InvalidFilterThreshold);
}
unit.conf0().modify(|_, w| unsafe {
w.filter_thres().bits(threshold);
w.filter_en().set_bit()
});
}
}
Ok(())
}
pub fn clear(&self) {
MUTEX.lock(|| {
let bits = PCNT::regs().ctrl().read().bits();
PCNT::regs().ctrl().write(|w| {
unsafe { w.bits(bits) };
w.cnt_rst_u(NUM as u8).set_bit()
});
PCNT::regs().ctrl().write(|w| {
unsafe { w.bits(bits) };
w.cnt_rst_u(NUM as u8).clear_bit()
});
});
}
pub fn pause(&self) {
MUTEX.lock(|| {
PCNT::regs()
.ctrl()
.modify(|_, w| w.cnt_pause_u(NUM as u8).set_bit());
});
}
pub fn resume(&self) {
MUTEX.lock(|| {
PCNT::regs()
.ctrl()
.modify(|_, w| w.cnt_pause_u(NUM as u8).clear_bit());
});
}
pub fn events(&self) -> Events {
let status = PCNT::regs().u_status(NUM).read();
Events {
low_limit: status.l_lim().bit(),
high_limit: status.h_lim().bit(),
threshold0: status.thres0().bit(),
threshold1: status.thres1().bit(),
zero: status.zero().bit(),
}
}
pub fn zero_mode(&self) -> ZeroMode {
PCNT::regs().u_status(NUM).read().zero_mode().bits().into()
}
pub fn listen(&self) {
MUTEX.lock(|| {
PCNT::regs()
.int_ena()
.modify(|_, w| w.cnt_thr_event_u(NUM as u8).set_bit());
});
}
pub fn unlisten(&self) {
MUTEX.lock(|| {
PCNT::regs()
.int_ena()
.modify(|_, w| w.cnt_thr_event_u(NUM as u8).clear_bit());
});
}
pub fn interrupt_is_set(&self) -> bool {
PCNT::regs()
.int_raw()
.read()
.cnt_thr_event_u(NUM as u8)
.bit()
}
pub fn reset_interrupt(&self) {
PCNT::regs()
.int_clr()
.write(|w| w.cnt_thr_event_u(NUM as u8).set_bit());
}
pub fn value(&self) -> i16 {
self.counter.get()
}
}
impl<const NUM: usize> Drop for Unit<'_, NUM> {
fn drop(&mut self) {
}
}
unsafe impl<const NUM: usize> Send for Unit<'_, NUM> {}
#[derive(Clone)]
pub struct Counter<'d, const NUM: usize> {
_phantom: PhantomData<&'d ()>,
_guard: GenericPeripheralGuard<{ crate::system::Peripheral::Pcnt as u8 }>,
}
impl<const NUM: usize> Counter<'_, NUM> {
fn new() -> Self {
let guard = GenericPeripheralGuard::new();
Self {
_phantom: PhantomData,
_guard: guard,
}
}
pub fn get(&self) -> i16 {
let pcnt = PCNT::regs();
pcnt.u_cnt(NUM).read().cnt().bits() as i16
}
}