cortex-m-async 0.1.0

Cortex-M helpers for async IO abstractions.
use core::{
    cell::RefCell,
    future::Future,
    pin::Pin,
    task::{
        Context,
        Poll,
        Waker,
    },
};

use cortex_m::interrupt::{
    self,
    Mutex,
};

struct FlagInner {
    waker: Option<Waker>,
    woken: bool,
}

pub struct Flag {
    inner: Mutex<RefCell<FlagInner>>,
}

impl Flag {
    pub const fn new() -> Flag {
        Flag {
            inner: Mutex::new(RefCell::new(FlagInner {
                waker: None,
                woken: false,
            })),
        }
    }

    fn modify<R>(&self, f: impl FnOnce(&mut FlagInner) -> R) -> R {
        interrupt::free(move |cs| {
            let mut lock = self.inner.borrow(cs).borrow_mut();
            f(&mut *lock)
        })
    }

    /// Check and clear the interrupt flag
    ///
    /// Registers the waker to be called when the flag is set if the flag wasn't
    /// set when this is called.
    pub fn check(&self, waker: &Waker) -> bool {
        self.modify(|inner| {
            let woken = inner.woken;
            inner.woken = false;
            if !woken {
                inner.waker = Some(waker.clone());
            }
            woken
        })
    }

    /// Remove the waker, call wake, and set the interrupt flag
    pub fn wake(&self) {
        self.modify(|timer_waker| {
            timer_waker.woken = true;
            if let Some(waker) = timer_waker.waker.take() {
                waker.wake();
            }
        })
    }

    /// Wait for the flag to be set
    pub fn wait(&self) -> FlagWait<'_> {
        FlagWait { inner: self }
    }
}

/// Future returned from [Flag::wait]
pub struct FlagWait<'f> {
    inner: &'f Flag,
}

impl<'f> Future for FlagWait<'f> {
    type Output = ();
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
        if self.inner.check(cx.waker()) {
            Poll::Ready(())
        } else {
            Poll::Pending
        }
    }
}