#![cfg_attr(
not(feature = "esp32"),
doc = "See the [timg] and [systimer] modules for more information."
)]
#![cfg_attr(feature = "esp32", doc = "See the [timg] module for more information.")]
#![doc = crate::before_snippet!()]
#![doc = crate::before_snippet!()]
use core::{
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};
use crate::{
asynch::AtomicWaker,
interrupt::{InterruptConfigurable, InterruptHandler},
peripheral::{Peripheral, PeripheralRef},
peripherals::Interrupt,
system::Cpu,
time::{Duration, Instant},
Async,
Blocking,
DriverMode,
};
#[cfg(systimer)]
pub mod systimer;
#[cfg(any(timg0, timg1))]
pub mod timg;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
TimerActive,
TimerInactive,
AlarmInactive,
InvalidTimeout,
}
pub trait Timer: Into<AnyTimer> + 'static + crate::private::Sealed {
#[doc(hidden)]
fn start(&self);
#[doc(hidden)]
fn stop(&self);
#[doc(hidden)]
fn reset(&self);
#[doc(hidden)]
fn is_running(&self) -> bool;
#[doc(hidden)]
fn now(&self) -> Instant;
#[doc(hidden)]
fn load_value(&self, value: Duration) -> Result<(), Error>;
#[doc(hidden)]
fn enable_auto_reload(&self, auto_reload: bool);
#[doc(hidden)]
fn enable_interrupt(&self, state: bool);
fn clear_interrupt(&self);
fn is_interrupt_set(&self) -> bool;
#[doc(hidden)]
fn async_interrupt_handler(&self) -> InterruptHandler;
fn peripheral_interrupt(&self) -> Interrupt;
#[doc(hidden)]
fn set_interrupt_handler(&self, handler: InterruptHandler);
#[doc(hidden)]
fn waker(&self) -> &AtomicWaker;
}
pub struct OneShotTimer<'d, Dm: DriverMode> {
inner: PeripheralRef<'d, AnyTimer>,
_ph: PhantomData<Dm>,
}
impl<'d> OneShotTimer<'d, Blocking> {
pub fn new(inner: impl Peripheral<P = impl Timer> + 'd) -> OneShotTimer<'d, Blocking> {
crate::into_mapped_ref!(inner);
Self {
inner,
_ph: PhantomData,
}
}
}
impl<'d> OneShotTimer<'d, Blocking> {
pub fn into_async(self) -> OneShotTimer<'d, Async> {
let handler = self.inner.async_interrupt_handler();
self.inner.set_interrupt_handler(handler);
OneShotTimer {
inner: self.inner,
_ph: PhantomData,
}
}
}
impl OneShotTimer<'_, Async> {
pub fn into_blocking(self) -> Self {
crate::interrupt::disable(Cpu::current(), self.inner.peripheral_interrupt());
Self {
inner: self.inner,
_ph: PhantomData,
}
}
pub async fn delay_nanos_async(&mut self, ns: u32) {
self.delay_async(Duration::from_micros(ns.div_ceil(1000) as u64))
.await
}
pub async fn delay_millis_async(&mut self, ms: u32) {
self.delay_async(Duration::from_millis(ms as u64)).await;
}
pub async fn delay_micros_async(&mut self, us: u32) {
self.delay_async(Duration::from_micros(us as u64)).await;
}
async fn delay_async(&mut self, us: Duration) {
unwrap!(self.schedule(us));
WaitFuture::new(self.inner.reborrow()).await;
self.stop();
self.clear_interrupt();
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct WaitFuture<'d> {
timer: PeripheralRef<'d, AnyTimer>,
}
impl<'d> WaitFuture<'d> {
fn new(timer: impl Peripheral<P = AnyTimer> + 'd) -> Self {
crate::into_ref!(timer);
timer.enable_interrupt(true);
Self { timer }
}
fn is_done(&self) -> bool {
self.timer.is_interrupt_set()
}
}
impl core::future::Future for WaitFuture<'_> {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
self.timer.waker().register(ctx.waker());
if self.is_done() {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
impl Drop for WaitFuture<'_> {
fn drop(&mut self) {
self.timer.enable_interrupt(false);
}
}
impl<Dm> OneShotTimer<'_, Dm>
where
Dm: DriverMode,
{
pub fn delay_millis(&mut self, ms: u32) {
self.delay(Duration::from_millis(ms as u64));
}
pub fn delay_micros(&mut self, us: u32) {
self.delay(Duration::from_micros(us as u64));
}
pub fn delay_nanos(&mut self, ns: u32) {
self.delay(Duration::from_micros(ns.div_ceil(1000) as u64))
}
fn delay(&mut self, us: Duration) {
self.schedule(us).unwrap();
while !self.inner.is_interrupt_set() {
}
self.stop();
self.clear_interrupt();
}
pub fn schedule(&mut self, timeout: Duration) -> Result<(), Error> {
if self.inner.is_running() {
self.inner.stop();
}
self.inner.clear_interrupt();
self.inner.reset();
self.inner.enable_auto_reload(false);
self.inner.load_value(timeout)?;
self.inner.start();
Ok(())
}
pub fn stop(&mut self) {
self.inner.stop();
}
#[instability::unstable]
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.inner.set_interrupt_handler(handler);
}
pub fn enable_interrupt(&mut self, enable: bool) {
self.inner.enable_interrupt(enable);
}
pub fn clear_interrupt(&mut self) {
self.inner.clear_interrupt();
}
}
impl<Dm> crate::private::Sealed for OneShotTimer<'_, Dm> where Dm: DriverMode {}
impl<Dm> InterruptConfigurable for OneShotTimer<'_, Dm>
where
Dm: DriverMode,
{
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
OneShotTimer::set_interrupt_handler(self, handler);
}
}
impl embedded_hal::delay::DelayNs for OneShotTimer<'_, Blocking> {
fn delay_ns(&mut self, ns: u32) {
self.delay_nanos(ns);
}
}
impl embedded_hal_async::delay::DelayNs for OneShotTimer<'_, Async> {
async fn delay_ns(&mut self, ns: u32) {
self.delay_nanos_async(ns).await
}
}
pub struct PeriodicTimer<'d, Dm: DriverMode> {
inner: PeripheralRef<'d, AnyTimer>,
_ph: PhantomData<Dm>,
}
impl<'d> PeriodicTimer<'d, Blocking> {
pub fn new(inner: impl Peripheral<P = impl Timer> + 'd) -> PeriodicTimer<'d, Blocking> {
crate::into_mapped_ref!(inner);
Self {
inner,
_ph: PhantomData,
}
}
}
impl<Dm> PeriodicTimer<'_, Dm>
where
Dm: DriverMode,
{
pub fn start(&mut self, period: Duration) -> Result<(), Error> {
if self.inner.is_running() {
self.inner.stop();
}
self.inner.clear_interrupt();
self.inner.reset();
self.inner.enable_auto_reload(true);
self.inner.load_value(period)?;
self.inner.start();
Ok(())
}
pub fn wait(&mut self) {
while !self.inner.is_interrupt_set() {}
self.inner.clear_interrupt();
}
pub fn cancel(&mut self) -> Result<(), Error> {
if !self.inner.is_running() {
return Err(Error::TimerInactive);
}
self.inner.stop();
Ok(())
}
#[instability::unstable]
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.inner.set_interrupt_handler(handler);
}
pub fn enable_interrupt(&mut self, enable: bool) {
self.inner.enable_interrupt(enable);
}
pub fn clear_interrupt(&mut self) {
self.inner.clear_interrupt();
}
}
impl<Dm> crate::private::Sealed for PeriodicTimer<'_, Dm> where Dm: DriverMode {}
impl<Dm> InterruptConfigurable for PeriodicTimer<'_, Dm>
where
Dm: DriverMode,
{
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
PeriodicTimer::set_interrupt_handler(self, handler);
}
}
crate::any_peripheral! {
pub peripheral AnyTimer {
TimgTimer(timg::Timer),
#[cfg(systimer)]
SystimerAlarm(systimer::Alarm),
}
}
impl Timer for AnyTimer {
delegate::delegate! {
to match &self.0 {
AnyTimerInner::TimgTimer(inner) => inner,
#[cfg(systimer)]
AnyTimerInner::SystimerAlarm(inner) => inner,
} {
fn start(&self);
fn stop(&self);
fn reset(&self);
fn is_running(&self) -> bool;
fn now(&self) -> Instant;
fn load_value(&self, value: Duration) -> Result<(), Error>;
fn enable_auto_reload(&self, auto_reload: bool);
fn enable_interrupt(&self, state: bool);
fn clear_interrupt(&self);
fn is_interrupt_set(&self) -> bool;
fn async_interrupt_handler(&self) -> InterruptHandler;
fn peripheral_interrupt(&self) -> Interrupt;
fn set_interrupt_handler(&self, handler: InterruptHandler);
fn waker(&self) -> &AtomicWaker;
}
}
}