embedded_async_timer/
lib.rs

1//! Async timers for embedded devices in Rust.
2//!
3//! This crate provides an interface and a generic implemention of a timer that can handle multiple
4//! concurrent deadlines using the Future architecture provided by Rust. This crate also provides
5//! two reference implementations for this interface for the STM32F103 and STM32L476.
6//!
7//! Using implementations for the `Timer` trait, you can instance an `AsyncTimer` that provides methods
8//! to concurrently wait on a specific deadline or duration with a `Future`-compatible interface.
9//! Using this crate you can implement device drivers that require delays. Using HAL crates that are
10//! compatible with `embedded-async-timer` you can develop firmware that directly require delays or use
11//! these aforementioned drivers.
12//! For HAL RTC implementations with alarms it should be trivial to adapt them to implement the `Timer` trait.
13//! View the STM32F103 example in the `impls` module for inspiration.
14//!
15//! **Note:** until `const_generics` lands the capacity for AsyncTimer is hard-coded.
16//!
17//! **Note:** the current design assumes a `bare_metal`-like single core architecture that supports
18//! `interrupt::free`-like blocks. In the future I would like to rewrite everything to no longer require this.
19//!
20//! **Note:** the priority queue used in this implementation is very likely to not be the most efficient choice of data structure.
21//! I intend to experiment with various setups to make an informed performance consideration based on real
22//! measurements given a small amount of concurrent timers.
23//!
24//! **State:** this crate has been tested with trivial examples on two embedded devices, but has not yet
25//! been applied in production. It is beyond a simple proof of concept though. Our intention to provide a
26//! basis for an async ecosystem. The quality might also be insufficient to run on production.
27//! Also the current state of async-await might be such that it is practically unusable for memory constrained embedded devices.
28//! We encourage developing async HAL drivers using this crate though.
29//!
30//! # Example
31//! ```rust
32//! async {
33//!     let timer = AsyncTimer::new(rtc);
34//!     timer.wait(Duration::from_millis(500).into()).await;
35//!
36//!     let mut interval = Interval::new(Duration::from_secs(1).into(), &timer);
37//!
38//!     loop {
39//!         interval.wait(&timer).await;
40//!         println!("ping");
41//!     }
42//! }
43//! ```
44
45#![no_std]
46
47pub mod impls;
48mod util;
49
50use core::sync::atomic::{AtomicBool, Ordering};
51use core::{
52    future::Future,
53    pin::Pin,
54    sync::atomic,
55    task::{Context, Poll, Waker},
56};
57
58use bare_metal::CriticalSection;
59
60use crate::util::mutmutex::MutMutex;
61use crate::util::priorityqueue::{Index, PriorityQueue};
62
63/// The amount of deadlines that can be scheduled for any given Timer.
64///
65/// Can be parameterized once the unstable `const_generics` features is stabilized.
66pub const CAPACITY: usize = 32;
67
68/// Too many timers were scheduled before finishing them.
69#[derive(Debug)]
70pub struct CapacityError;
71
72struct Handle<TIME: Ord> {
73    deadline: TIME,
74    awoken: AtomicBool,
75    waker: Option<Waker>,
76}
77
78impl<TIME: Ord> Handle<TIME> {
79    /// Awaken the handle, regardless of time.
80    ///
81    /// Will return whether it was awoken for the first time.
82    fn awaken(&self) -> bool {
83        let result = self.awoken.compare_and_swap(false, true, Ordering::SeqCst);
84
85        // Notify the waker, every time this function is called.
86        // Notifying the waker extra times cannot hurt.
87        if let Some(waker) = &self.waker {
88            waker.wake_by_ref();
89        }
90
91        result
92    }
93}
94
95impl<TIME: Ord> PartialEq for Handle<TIME> {
96    fn eq(&self, other: &Self) -> bool {
97        self.deadline.eq(&other.deadline)
98    }
99}
100impl<TIME: Ord> PartialOrd for Handle<TIME> {
101    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
102        self.deadline.partial_cmp(&other.deadline)
103    }
104}
105
106/// A clock device that supports throwing alarm interrupts at given instant.
107///
108/// This trait assumes that the clock is not (re)set after initial configuration.
109pub trait Timer {
110    /// A length of time.
111    ///
112    /// You will probably want to make this type as close to your Instant type as possible,
113    /// with a focus on making addition and storage efficient.
114    type Duration: Clone;
115    /// A moment in time.
116    ///
117    /// You will probably make this type as close to the internal representation of an instant
118    /// as used by your RTC peripheral.
119    type Instant: Clone + Ord + core::ops::AddAssign<Self::Duration>;
120
121    /// A minimal time increment, i.e. the time it takes to execute a handful of instructions.
122    ///
123    /// Used when scheduling the next deadline, but in the meantime the deadline has passed.
124    const DELTA: Self::Duration;
125
126    /// Initialize the clock and start counting.
127    ///
128    /// You will need to run this sometime after initializing the static memory in which the timer lives,
129    /// such that the interrupt handler can access the timer.
130    fn reset(&mut self);
131    /// Execute the function in an interrupt free critical section.
132    ///
133    /// Probably you want to directly feed through `cortex_m::interrupt::free` or similar.
134    fn interrupt_free<F: FnOnce(&CriticalSection) -> R, R>(f: F) -> R;
135    /// Yield the current time.
136    fn now(&self) -> Self::Instant;
137    /// Disarm the set alarm.
138    fn disarm(&mut self);
139    /// Set the alarm for a given time.
140    fn arm(&mut self, deadline: &Self::Instant);
141}
142
143/// Convenience function to easily express a time in the future.
144#[inline(always)]
145fn future<D, I: Clone + core::ops::AddAssign<D>>(mut i: I, d: D) -> I {
146    i += d;
147    i
148}
149
150/// A Future waiting for a deadline.
151///
152/// **Note** This future is instantiated by Timer.
153pub struct Delay<'a, T: Timer> {
154    index: Index,
155    timer: &'a AsyncTimer<T>,
156}
157
158impl<'a, T: Timer> Future for Delay<'a, T> {
159    type Output = ();
160
161    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
162        T::interrupt_free(|cs| {
163            let inner = unsafe { self.timer.0.borrow_mut(cs) };
164            let handle = inner.handles.get_mut(self.index).unwrap(); // Unwrap: only we get to clean up the handle. Logic error otherwise.
165            let waker = &mut handle.waker;
166
167            if handle.awoken.load(Ordering::SeqCst) {
168                if waker.is_none() {
169                    // Uninstall the waker.
170                    drop(waker.take());
171                }
172
173                // The handle will be removed at Drop.
174
175                Poll::Ready(())
176            } else {
177                // Always replace the waker, regardless whether it was set or not.
178                waker.replace(cx.waker().clone());
179
180                // Drop the mutex.
181                drop(inner);
182
183                // Ensure that the waker and dropping was actually done.
184                atomic::compiler_fence(Ordering::Release);
185
186                // Arm alarm with earliest (possibly newer) deadline.
187                self.timer.wake_and_arm(cs);
188
189                Poll::Pending
190            }
191        })
192    }
193}
194
195impl<'a, T: Timer> Drop for Delay<'a, T> {
196    fn drop(&mut self) {
197        T::interrupt_free(|cs| {
198            let inner = unsafe { self.timer.0.borrow_mut(cs) };
199            inner.handles.remove(self.index).unwrap(); // Unwrap: should not yet be cleaned up. Logic error otherwise.
200        });
201    }
202}
203
204/// Inner of Timer that might not be Sync.
205struct AsyncTimerInner<T: Timer> {
206    handles: PriorityQueue<Handle<T::Instant>>,
207    timer: T,
208}
209
210/// A wrapped timer that can asynchronously wake up for concurrent deadlines.
211///
212/// The capacity of this timer is determined by the internal PriorityQueue.
213pub struct AsyncTimer<T: Timer>(MutMutex<AsyncTimerInner<T>>);
214
215impl<T: Timer> AsyncTimer<T> {
216    pub fn new(timer: T) -> Self {
217        Self(MutMutex::new(AsyncTimerInner {
218            handles: PriorityQueue::new(),
219            timer,
220        }))
221    }
222
223    pub fn reset(&self) {
224        T::interrupt_free(|cs| {
225            let inner = unsafe { self.0.borrow_mut(cs) };
226            inner.timer.reset()
227        })
228    }
229
230    pub fn now(&self) -> T::Instant {
231        T::interrupt_free(|cs| {
232            let inner = unsafe { self.0.borrow_mut(cs) };
233            inner.timer.now()
234        })
235    }
236
237    pub unsafe fn get_inner<U>(&self, f: impl FnOnce(&mut T) -> U) -> U {
238        T::interrupt_free(|cs| f(&mut self.0.borrow_mut(cs).timer))
239    }
240
241    /// Wake up any tasks that can be awoken, and arm the inner RTC with the earliest deadline.
242    fn wake_and_arm(&self, cs: &CriticalSection) {
243        let inner = unsafe { self.0.borrow_mut(cs) };
244        let time = inner.timer.now();
245        let earliest = inner.handles.iter().try_fold((), |_, (_index, handle)| {
246            if handle.deadline <= time {
247                handle.awaken();
248                Ok(())
249            } else {
250                Err(&handle.deadline)
251            }
252        });
253
254        match earliest {
255            Ok(()) => {
256                inner.timer.disarm(); // All deadlines have been processed
257            }
258            Err(earliest) => {
259                let min_next = future(inner.timer.now(), T::DELTA);
260                if min_next < *earliest {
261                    inner.timer.arm(earliest);
262                } else {
263                    // We were too slow to re-arm the RTC before the next deadline,
264                    // hence schedule for the next time increment.
265                    inner.timer.arm(&min_next);
266                }
267            }
268        }
269    }
270
271    /// Awaken all timers for which the deadline has passed compared to the time.
272    ///
273    /// Will re-arm the inner RTC with the earliest deadline, if there is one.
274    ///
275    /// **Note:** call this in the appropriate interrupt handler.
276    #[inline(always)]
277    pub fn awaken(&self) {
278        T::interrupt_free(|cs| {
279            self.wake_and_arm(cs);
280        });
281    }
282
283    /// Wait at least for a specific duration.
284    #[inline(always)]
285    pub fn wait<'a>(&'a self, dur: T::Duration) -> Result<Delay<'a, T>, CapacityError> {
286        self.wait_until_always(future(self.now(), dur))
287    }
288
289    /// Wait until some time after a specific deadline.
290    ///
291    /// Will immediately return (and never yield) if the deadline has already passed.
292    #[inline(always)]
293    pub async fn wait_until<'a>(&'a self, deadline: T::Instant) -> Result<(), CapacityError> {
294        if deadline <= self.now() {
295            return Ok(());
296        }
297
298        Ok(self.wait_until_always(deadline)?.await)
299    }
300
301    /// Wait until some time after a specific deadline.
302    ///
303    /// Will at least yield once, even if the deadline has already passed.
304    #[inline(always)]
305    pub fn wait_until_always<'a>(
306        &'a self,
307        deadline: T::Instant,
308    ) -> Result<Delay<'a, T>, CapacityError> {
309        // Reading time is a read-only operation, and guaranteed to be consistent,
310        // Because the time is not reset after initialisation.
311        let handle = Handle {
312            deadline,
313            awoken: AtomicBool::new(false),
314            waker: None,
315        };
316
317        let index = T::interrupt_free(|cs| {
318            let inner = unsafe { self.0.borrow_mut(cs) };
319            inner.handles.insert(handle)
320        })?;
321
322        Ok(Delay { index, timer: self })
323    }
324}
325
326/// A repeating delay with a fixed start and fixed segment duration.
327pub struct Interval<CLOCK: Timer> {
328    last: CLOCK::Instant,
329    duration: CLOCK::Duration,
330}
331
332impl<CLOCK: Timer> Interval<CLOCK> {
333    /// Create a new interval starting **now**.
334    ///
335    /// Awaiting this new Interval will yield for the first time after `now + duration`.
336    pub fn new(duration: CLOCK::Duration, timer: &AsyncTimer<CLOCK>) -> Self {
337        Self {
338            last: timer.now(),
339            duration,
340        }
341    }
342
343    /// Await until some time after the end of the next interval segment.
344    ///
345    /// **Note**: if an interval segment has already completely passed it will return immediately without yielding.
346    pub fn wait<'a>(&mut self, timer: &'a AsyncTimer<CLOCK>) -> impl Future + 'a {
347        self.last += self.duration.clone();
348        timer.wait_until(self.last.clone())
349    }
350}