use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin;
use core::task::{Context, Poll};
use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin};
pub use super::{Ch1, Ch2, Ch3, Ch4};
use crate::gpio::{AfType, Flex, Pull};
use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::time::Hertz;
use crate::timer::TimerChannel;
use crate::{Peri, dma};
pub struct CapturePin<'d, T, C, #[cfg(afio)] A> {
#[allow(unused)]
pin: Flex<'d>,
phantom: PhantomData<if_afio!((T, C, A))>,
}
impl<'d, T: GeneralInstance4Channel, C: TimerChannel, #[cfg(afio)] A> if_afio!(CapturePin<'d, T, C, A>) {
pub fn new(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>, pull: Pull) -> Self {
set_as_af!(pin, AfType::input(pull));
CapturePin {
pin: Flex::new(pin),
phantom: PhantomData,
}
}
}
pub struct InputCapture<'d, T: GeneralInstance4Channel> {
inner: Timer<'d, T>,
_ch1: Option<Flex<'d>>,
_ch2: Option<Flex<'d>>,
_ch3: Option<Flex<'d>>,
_ch4: Option<Flex<'d>>,
}
impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
#[allow(unused)]
pub fn new<#[cfg(afio)] A>(
tim: Peri<'d, T>,
ch1: Option<if_afio!(CapturePin<'d, T, Ch1, A>)>,
ch2: Option<if_afio!(CapturePin<'d, T, Ch2, A>)>,
ch3: Option<if_afio!(CapturePin<'d, T, Ch3, A>)>,
ch4: Option<if_afio!(CapturePin<'d, T, Ch4, A>)>,
_irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
freq: Hertz,
counting_mode: CountingMode,
) -> Self {
Self::new_inner(
tim,
ch1.map(|pin| pin.pin),
ch2.map(|pin| pin.pin),
ch3.map(|pin| pin.pin),
ch4.map(|pin| pin.pin),
freq,
counting_mode,
)
}
fn new_inner(
tim: Peri<'d, T>,
_ch1: Option<Flex<'d>>,
_ch2: Option<Flex<'d>>,
_ch3: Option<Flex<'d>>,
_ch4: Option<Flex<'d>>,
freq: Hertz,
counting_mode: CountingMode,
) -> Self {
let mut this = Self {
inner: Timer::new(tim),
_ch1,
_ch2,
_ch3,
_ch4,
};
this.inner.set_counting_mode(counting_mode);
this.inner.set_tick_freq(freq);
this.inner.enable_outputs(); this.inner.generate_update_event();
this.inner.start();
T::CaptureCompareInterrupt::unpend();
unsafe { T::CaptureCompareInterrupt::enable() };
this
}
pub fn enable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, true);
}
pub fn disable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, false);
}
pub fn is_enabled(&self, channel: Channel) -> bool {
self.inner.get_channel_enable_state(channel)
}
pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
self.inner.set_input_capture_mode(channel, mode);
}
pub fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
self.inner.set_input_ti_selection(channel, tisel)
}
pub fn get_capture_value(&self, channel: Channel) -> T::Word {
self.inner.get_capture_value(channel)
}
pub fn get_input_interrupt(&self, channel: Channel) -> bool {
self.inner.get_input_interrupt(channel)
}
fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture<T> {
self.inner.set_input_ti_selection(channel, tisel);
self.inner.set_input_capture_filter(channel, FilterValue::NO_FILTER);
self.inner.set_input_capture_mode(channel, mode);
self.inner.set_input_capture_prescaler(channel, 0);
self.inner.enable_channel(channel, true);
self.inner.enable_input_interrupt(channel, true);
InputCaptureFuture {
channel,
phantom: PhantomData,
}
}
pub async fn wait_for_rising_edge(&mut self, channel: Channel) -> T::Word {
self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Normal)
.await
}
pub async fn wait_for_falling_edge(&mut self, channel: Channel) -> T::Word {
self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Normal)
.await
}
pub async fn wait_for_any_edge(&mut self, channel: Channel) -> T::Word {
self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Normal)
.await
}
pub async fn wait_for_rising_edge_alternate(&mut self, channel: Channel) -> T::Word {
self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Alternate)
.await
}
pub async fn wait_for_falling_edge_alternate(&mut self, channel: Channel) -> T::Word {
self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Alternate)
.await
}
pub async fn wait_for_any_edge_alternate(&mut self, channel: Channel) -> T::Word {
self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Alternate)
.await
}
pub async fn receive_waveform<M, D: super::Dma<T, M>>(
&mut self,
dma: Peri<'_, D>,
irq: impl crate::interrupt::typelevel::Binding<D::Interrupt, crate::dma::InterruptHandler<D>>,
buf: &mut [u16],
) where
M: TimerChannel,
{
#[allow(clippy::let_unit_value)] let req = dma.request();
let original_enable_state = self.is_enabled(M::CHANNEL);
let original_cc_dma_enable_state = self.inner.get_cc_dma_enable_state(M::CHANNEL);
self.inner.set_input_ti_selection(M::CHANNEL, InputTISelection::Normal);
self.inner
.set_input_capture_mode(M::CHANNEL, InputCaptureMode::BothEdges);
if !original_cc_dma_enable_state {
self.inner.set_cc_dma_enable_state(M::CHANNEL, true);
}
if !original_enable_state {
self.enable(M::CHANNEL);
}
unsafe {
let mut dma_channel = dma::Channel::new(dma, irq);
dma_channel
.read(
req,
self.inner.regs_gp16().ccr(M::CHANNEL.index()).as_ptr() as *mut u16,
buf,
dma::TransferOptions::default(),
)
.await
};
if !original_enable_state {
self.disable(M::CHANNEL);
}
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct InputCaptureFuture<T: GeneralInstance4Channel> {
channel: Channel,
phantom: PhantomData<T>,
}
impl<T: GeneralInstance4Channel> Drop for InputCaptureFuture<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<T: GeneralInstance4Channel> Future for InputCaptureFuture<T> {
type Output = T::Word;
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()) {
let val = unwrap!(regs.ccr(self.channel.index()).read().ccr().try_into());
Poll::Ready(val)
} else {
Poll::Pending
}
}
}