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}