aboutsummaryrefslogtreecommitdiff
path: root/embassy-time-driver/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-time-driver/src')
-rw-r--r--embassy-time-driver/src/lib.rs79
1 files changed, 60 insertions, 19 deletions
diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs
index 090969d8c..57a9f7587 100644
--- a/embassy-time-driver/src/lib.rs
+++ b/embassy-time-driver/src/lib.rs
@@ -17,25 +17,7 @@
17//! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by 17//! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by
18//! enabling a feature on `embassy-time`. 18//! enabling a feature on `embassy-time`.
19//! 19//!
20//! # Linkage details 20//! ### Example
21//!
22//! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions.
23//!
24//! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it.
25//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the
26//! calls from the `embassy` crate to call into the driver crate.
27//!
28//! If there is none or multiple drivers in the crate tree, linking will fail.
29//!
30//! This method has a few key advantages for something as foundational as timekeeping:
31//!
32//! - The time driver is available everywhere easily, without having to thread the implementation
33//! through generic parameters. This is especially helpful for libraries.
34//! - It means comparing `Instant`s will always make sense: if there were multiple drivers
35//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
36//! would yield incorrect results.
37//!
38//! # Example
39//! 21//!
40//! ``` 22//! ```
41//! use core::task::Waker; 23//! use core::task::Waker;
@@ -56,6 +38,65 @@
56//! 38//!
57//! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); 39//! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
58//! ``` 40//! ```
41//!
42//! ## Implementing the timer queue
43//!
44//! The simplest (but suboptimal) way to implement a timer queue is to define a single queue in the
45//! time driver. Declare a field protected by an appropriate mutex (e.g. `critical_section::Mutex`).
46//!
47//! Then, you'll need to adapt the `schedule_wake` method to use this queue.
48//!
49//! ```ignore
50//! use core::cell::RefCell;
51//! use core::task::Waker;
52//!
53//! use embassy_time_queue_driver::Queue;
54//! use embassy_time_driver::Driver;
55//!
56//! struct MyDriver {
57//! timer_queue: critical_section::Mutex<RefCell<Queue>>,
58//! }
59//!
60//! impl MyDriver {
61//! fn set_alarm(&self, cs: &CriticalSection, at: u64) -> bool {
62//! todo!()
63//! }
64//! }
65//!
66//! impl Driver for MyDriver {
67//! // fn now(&self) -> u64 { ... }
68//!
69//! fn schedule_wake(&self, at: u64, waker: &Waker) {
70//! critical_section::with(|cs| {
71//! let mut queue = self.queue.borrow(cs).borrow_mut();
72//! if queue.schedule_wake(at, waker) {
73//! let mut next = queue.next_expiration(self.now());
74//! while !self.set_alarm(cs, next) {
75//! next = queue.next_expiration(self.now());
76//! }
77//! }
78//! });
79//! }
80//! }
81//! ```
82//!
83//! # Linkage details
84//!
85//! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions.
86//!
87//! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it.
88//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the
89//! calls from the `embassy` crate to call into the driver crate.
90//!
91//! If there is none or multiple drivers in the crate tree, linking will fail.
92//!
93//! This method has a few key advantages for something as foundational as timekeeping:
94//!
95//! - The time driver is available everywhere easily, without having to thread the implementation
96//! through generic parameters. This is especially helpful for libraries.
97//! - It means comparing `Instant`s will always make sense: if there were multiple drivers
98//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
99//! would yield incorrect results.
59 100
60//! ## Feature flags 101//! ## Feature flags
61#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] 102#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]