use core::future::Future;
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::pin::Pin;
use core::task::{Context, Poll};
use super::low_level::{
CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource as Ts,
};
use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin};
pub use super::{Ch1, Ch2};
use crate::Peri;
use crate::gpio::{AfType, Flex, Pull};
use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::pac::timer::vals::Etp;
use crate::time::Hertz;
use crate::timer::TimerChannel;
pub enum Ext {}
#[derive(Clone, Copy)]
pub enum ExternalTriggerPolarity {
Rising,
Falling,
}
impl From<ExternalTriggerPolarity> for Etp {
fn from(mode: ExternalTriggerPolarity) -> Self {
match mode {
ExternalTriggerPolarity::Rising => 0.into(),
ExternalTriggerPolarity::Falling => 1.into(),
}
}
}
pub struct TriggerPin<'d, T, C> {
#[allow(unused)]
pin: Flex<'d>,
phantom: PhantomData<(T, C)>,
}
trait SealedTriggerSource {}
#[expect(private_bounds)]
pub trait TriggerSource: SealedTriggerSource {}
impl TriggerSource for Ch1 {}
impl TriggerSource for Ch2 {}
impl TriggerSource for Ext {}
impl SealedTriggerSource for Ch1 {}
impl SealedTriggerSource for Ch2 {}
impl SealedTriggerSource for Ext {}
impl<'d, T: GeneralInstance4Channel, C: TriggerSource + TimerChannel> TriggerPin<'d, T, C> {
pub fn new<#[cfg(afio)] A>(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>, pull: Pull) -> Self {
TriggerPin {
pin: new_pin!(pin, AfType::input(pull)).unwrap(),
phantom: PhantomData,
}
}
}
impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, Ext> {
pub fn new_external<#[cfg(afio)] A>(pin: Peri<'d, if_afio!(impl ExternalTriggerPin<T, A>)>, pull: Pull) -> Self {
TriggerPin {
pin: new_pin!(pin, AfType::input(pull)).unwrap(),
phantom: PhantomData,
}
}
}
pub struct OnePulse<'d, T: GeneralInstance4Channel> {
inner: Timer<'d, T>,
_pin: Flex<'d>,
}
impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
#[allow(unused)]
pub fn new_ch1_edge_detect(
tim: Peri<'d, T>,
pin: TriggerPin<'d, T, Ch1>,
_irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
freq: Hertz,
pulse_end: u32,
counting_mode: CountingMode,
) -> Self {
let mut this = Self {
inner: Timer::new(tim),
_pin: pin.pin,
};
this.inner.set_trigger_source(Ts::TI1F_ED);
this.inner
.set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
this.inner
.set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER);
this.new_inner(freq, pulse_end, counting_mode);
this
}
pub fn new_ch1(
tim: Peri<'d, T>,
_pin: TriggerPin<'d, T, Ch1>,
_irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
freq: Hertz,
pulse_end: u32,
counting_mode: CountingMode,
capture_mode: InputCaptureMode,
) -> Self {
let mut this = Self {
inner: Timer::new(tim),
_pin: _pin.pin,
};
this.inner.set_trigger_source(Ts::TI1FP1);
this.inner
.set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
this.inner
.set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER);
this.inner.set_input_capture_mode(Channel::Ch1, capture_mode);
this.new_inner(freq, pulse_end, counting_mode);
this
}
pub fn new_ch2(
tim: Peri<'d, T>,
_pin: TriggerPin<'d, T, Ch2>,
_irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
freq: Hertz,
pulse_end: u32,
counting_mode: CountingMode,
capture_mode: InputCaptureMode,
) -> Self {
let mut this = Self {
inner: Timer::new(tim),
_pin: _pin.pin,
};
this.inner.set_trigger_source(Ts::TI2FP2);
this.inner
.set_input_ti_selection(Channel::Ch2, InputTISelection::Normal);
this.inner
.set_input_capture_filter(Channel::Ch2, FilterValue::NO_FILTER);
this.inner.set_input_capture_mode(Channel::Ch2, capture_mode);
this.new_inner(freq, pulse_end, counting_mode);
this
}
pub fn new_ext(
tim: Peri<'d, T>,
_pin: TriggerPin<'d, T, Ext>,
_irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
freq: Hertz,
pulse_end: u32,
counting_mode: CountingMode,
polarity: ExternalTriggerPolarity,
) -> Self {
let mut this = Self {
inner: Timer::new(tim),
_pin: _pin.pin,
};
this.inner.regs_gp16().smcr().modify(|r| {
r.set_etp(polarity.into());
r.set_etps(0.into());
r.set_etf(FilterValue::NO_FILTER);
});
this.inner.set_trigger_source(Ts::ETRF);
this.new_inner(freq, pulse_end, counting_mode);
this
}
fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) {
self.inner.set_counting_mode(counting_mode);
self.inner.set_tick_freq(freq);
self.inner.set_max_compare_value(unwrap!(pulse_end.try_into()));
self.inner.regs_core().cr1().modify(|r| r.set_opm(true));
self.inner.enable_outputs();
self.inner.set_slave_mode(SlaveMode::TRIGGER_MODE);
T::CaptureCompareInterrupt::unpend();
unsafe { T::CaptureCompareInterrupt::enable() };
}
pub fn pulse_end(&self) -> u32 {
let max: u32 = self.inner.get_max_compare_value().into();
assert!(max < u32::MAX);
max + 1
}
pub fn set_pulse_end(&mut self, ticks: u32) {
self.inner.set_max_compare_value(unwrap!(ticks.try_into()))
}
#[cfg(not(stm32l0))]
pub fn set_reset_on_trigger(&mut self, reset: bool) {
let slave_mode = if reset {
SlaveMode::COMBINED_RESET_TRIGGER
} else {
SlaveMode::TRIGGER_MODE
};
self.inner.set_slave_mode(slave_mode);
}
pub fn channel(&mut self, channel: Channel) -> OnePulseChannel<'_, T> {
OnePulseChannel {
inner: unsafe { self.inner.clone_unchecked() },
channel,
}
}
pub fn ch1(&mut self) -> OnePulseChannel<'_, T> {
self.channel(Channel::Ch1)
}
pub fn ch2(&mut self) -> OnePulseChannel<'_, T> {
self.channel(Channel::Ch2)
}
pub fn ch3(&mut self) -> OnePulseChannel<'_, T> {
self.channel(Channel::Ch3)
}
pub fn ch4(&mut self) -> OnePulseChannel<'_, T> {
self.channel(Channel::Ch4)
}
pub fn split(self) -> OnePulseChannels<'static, T>
where
'd: 'static,
{
let timer = ManuallyDrop::new(self.inner);
let ch = |channel| OnePulseChannel {
inner: unsafe { timer.clone_unchecked() },
channel,
};
OnePulseChannels {
ch1: ch(Channel::Ch1),
ch2: ch(Channel::Ch2),
ch3: ch(Channel::Ch3),
ch4: ch(Channel::Ch4),
}
}
}
pub struct OnePulseChannels<'d, T: GeneralInstance4Channel> {
pub ch1: OnePulseChannel<'d, T>,
pub ch2: OnePulseChannel<'d, T>,
pub ch3: OnePulseChannel<'d, T>,
pub ch4: OnePulseChannel<'d, T>,
}
pub struct OnePulseChannel<'d, T: GeneralInstance4Channel> {
inner: ManuallyDrop<Timer<'d, T>>,
channel: Channel,
}
impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> {
pub fn pulse_end(&self) -> u32 {
let max: u32 = self.inner.get_max_compare_value().into();
assert!(max < u32::MAX);
max + 1
}
pub fn pulse_width(&mut self) -> u32 {
self.pulse_end().saturating_sub(self.pulse_delay())
}
pub fn pulse_delay(&mut self) -> u32 {
self.inner.get_compare_value(self.channel).into()
}
pub fn set_pulse_delay(&mut self, delay: u32) {
assert!(delay <= self.pulse_end());
self.inner.set_compare_value(self.channel, unwrap!(delay.try_into()));
}
pub fn set_pulse_width(&mut self, width: u32) {
assert!(width <= self.pulse_end());
self.set_pulse_delay(self.pulse_end() - width);
}
pub async fn wait_for_pulse_start(&mut self) {
self.inner.enable_input_interrupt(self.channel, true);
OnePulseFuture::<T> {
channel: self.channel,
phantom: PhantomData,
}
.await
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct OnePulseFuture<T: GeneralInstance4Channel> {
channel: Channel,
phantom: PhantomData<T>,
}
impl<'d, T: GeneralInstance4Channel> Drop for OnePulseFuture<T> {
fn drop(&mut self) {
critical_section::with(|_| {
let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
regs.dier().modify(|w| w.set_ccie(self.channel.index(), false));
});
}
}
impl<'d, T: GeneralInstance4Channel> Future for OnePulseFuture<T> {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
T::state().cc_waker[self.channel.index()].register(cx.waker());
let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
let dier = regs.dier().read();
if !dier.ccie(self.channel.index()) {
Poll::Ready(())
} else {
Poll::Pending
}
}
}