embedded-svc 0.24.0

A set of traits for services higher level than embedded-hal and typically found in embedded microcontrollers with WiFi or BLE support.
Documentation
use core::future::Future;
use core::mem;
use core::pin::Pin;
use core::result::Result;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::task::{Context, Poll};
use core::time::Duration;

extern crate alloc;
use alloc::sync::Arc;

use futures::task::AtomicWaker;

#[cfg(all(feature = "nightly", feature = "experimental"))]
pub use async_traits_impl::*;

struct TimerSignal {
    waker: AtomicWaker,
    ticks: AtomicUsize,
}

impl TimerSignal {
    const fn new() -> Self {
        Self {
            waker: AtomicWaker::new(),
            ticks: AtomicUsize::new(0),
        }
    }

    fn reset(&self) {
        self.ticks.store(0, Ordering::SeqCst);
        self.waker.take();
    }

    fn tick(&self) {
        self.ticks.fetch_add(1, Ordering::SeqCst);
        self.waker.wake();
    }

    fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<usize> {
        self.waker.register(cx.waker());

        let data = self.ticks.swap(0, Ordering::SeqCst);

        if data > 0 {
            Poll::Ready(data)
        } else {
            Poll::Pending
        }
    }
}

pub struct AsyncTimer<T> {
    timer: T,
    signal: Arc<TimerSignal>,
    duration: Option<Duration>,
}

impl<T> AsyncTimer<T>
where
    T: crate::timer::OnceTimer + Send + 'static,
{
    pub fn after(&mut self, duration: Duration) -> Result<TimerFuture<'_, T>, T::Error> {
        self.timer.cancel()?;

        self.signal.reset();
        self.duration = None;

        Ok(TimerFuture(self, Some(duration)))
    }

    pub fn every(&mut self, duration: Duration) -> Result<&'_ mut Self, T::Error> {
        self.timer.cancel()?;

        self.signal.reset();
        self.duration = Some(duration);

        Ok(self)
    }

    pub fn tick(&mut self) -> TimerFuture<'_, T> {
        self.signal.reset();

        TimerFuture(self, self.duration)
    }
}

pub struct TimerFuture<'a, T>(&'a mut AsyncTimer<T>, Option<Duration>)
where
    T: crate::timer::Timer;

impl<'a, T> Drop for TimerFuture<'a, T>
where
    T: crate::timer::Timer,
{
    fn drop(&mut self) {
        self.0.timer.cancel().unwrap();
    }
}

impl<'a, T> Future for TimerFuture<'a, T>
where
    T: crate::timer::OnceTimer + 'static,
{
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if let Some(duration) = mem::replace(&mut self.1, None) {
            self.0.timer.after(duration).unwrap();
        }

        if self.0.signal.poll_wait(cx).is_ready() {
            Poll::Ready(())
        } else {
            Poll::Pending
        }
    }
}

pub struct AsyncTimerService<T>(T);

impl<T> AsyncTimerService<T> {
    pub const fn new(timer_service: T) -> Self {
        Self(timer_service)
    }
}

impl<T> Clone for AsyncTimerService<T>
where
    T: Clone,
{
    fn clone(&self) -> Self {
        Self(self.0.clone())
    }
}

impl<T> AsyncTimerService<T>
where
    T: crate::timer::TimerService,
    T::Timer: Send,
{
    pub fn timer(&mut self) -> Result<AsyncTimer<T::Timer>, T::Error> {
        let signal = Arc::new(TimerSignal::new());

        let timer = {
            let signal = Arc::downgrade(&signal);

            self.0.timer(move || {
                if let Some(signal) = signal.upgrade() {
                    signal.tick();
                }
            })?
        };

        Ok(AsyncTimer {
            timer,
            signal,
            duration: None,
        })
    }
}

#[cfg(all(feature = "nightly", feature = "experimental"))]
mod async_traits_impl {
    use core::result::Result;
    use core::time::Duration;

    extern crate alloc;

    use crate::timer::asynch::{Clock, ErrorType, OnceTimer, PeriodicTimer, TimerService};
    use crate::utils::asyncify::AsyncWrapper;

    use super::{AsyncTimer, AsyncTimerService, TimerFuture};

    impl<T> ErrorType for AsyncTimer<T>
    where
        T: ErrorType,
    {
        type Error = T::Error;
    }

    impl<T> OnceTimer for AsyncTimer<T>
    where
        T: crate::timer::OnceTimer + Send + 'static,
    {
        type AfterFuture<'a> = TimerFuture<'a, T>;

        fn after(&mut self, duration: Duration) -> Result<Self::AfterFuture<'_>, Self::Error> {
            AsyncTimer::after(self, duration)
        }
    }

    impl<T> PeriodicTimer for AsyncTimer<T>
    where
        T: crate::timer::OnceTimer + Send + 'static,
    {
        type Clock<'a> = &'a mut Self;

        fn every(&mut self, duration: Duration) -> Result<Self::Clock<'_>, Self::Error> {
            AsyncTimer::every(self, duration)
        }
    }

    impl<'a, T> Clock for &'a mut AsyncTimer<T>
    where
        T: crate::timer::OnceTimer + Send + 'static,
    {
        type TickFuture<'b>
        = TimerFuture<'b, T> where 'a: 'b;

        fn tick(&mut self) -> Self::TickFuture<'_> {
            AsyncTimer::tick(self)
        }
    }

    impl<T> AsyncWrapper<T> for AsyncTimerService<T> {
        fn new(timer_service: T) -> Self {
            AsyncTimerService::new(timer_service)
        }
    }

    impl<T> ErrorType for AsyncTimerService<T>
    where
        T: ErrorType,
    {
        type Error = T::Error;
    }

    impl<T> TimerService for AsyncTimerService<T>
    where
        T: crate::timer::TimerService,
        T::Timer: Send,
    {
        type Timer = AsyncTimer<T::Timer>;

        fn timer(&mut self) -> Result<Self::Timer, Self::Error> {
            AsyncTimerService::timer(self)
        }
    }
}