aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDániel Buga <[email protected]>2024-12-15 19:24:49 +0100
committerDániel Buga <[email protected]>2024-12-15 19:24:49 +0100
commit0492dba5368e7cb22ede2d41d26d4d0431ba2252 (patch)
tree735ad32cd3f40acbc57248373ab2622c8a9a03e3
parente861344b179b3e955ac47f1985b7f97fdfb93892 (diff)
Update documentation and changelogs
-rw-r--r--embassy-time-driver/CHANGELOG.md3
-rw-r--r--embassy-time-driver/src/lib.rs79
-rw-r--r--embassy-time-queue-driver/CHANGELOG.md5
-rw-r--r--embassy-time-queue-driver/src/lib.rs49
4 files changed, 69 insertions, 67 deletions
diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md
index ebc37b6f4..2af1dc736 100644
--- a/embassy-time-driver/CHANGELOG.md
+++ b/embassy-time-driver/CHANGELOG.md
@@ -1,4 +1,4 @@
1# Changelog for embassy-time-queue-driver 1# Changelog for embassy-time-driver
2 2
3All notable changes to this project will be documented in this file. 3All notable changes to this project will be documented in this file.
4 4
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8## Unreleased 8## Unreleased
9 9
10- The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed. 10- The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed.
11- `schedule_wake` has been added to the `Driver` trait.
11 12
12## 0.1.0 - 2024-01-11 13## 0.1.0 - 2024-01-11
13 14
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>"#)]
diff --git a/embassy-time-queue-driver/CHANGELOG.md b/embassy-time-queue-driver/CHANGELOG.md
index 3b2aa8695..a99f250ed 100644
--- a/embassy-time-queue-driver/CHANGELOG.md
+++ b/embassy-time-queue-driver/CHANGELOG.md
@@ -7,9 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10- Added `integrated-timers` and `generic-queue-N` features 10- Added `generic-queue-N` features.
11- Added `queue_generic` module which contains `Queue` (configured via the `generic-queue-N` features) and `ConstGenericQueue<SIZE>`. 11- Added `embassy_time_queue_driver::Queue` struct which uses integrated or a generic storage (configured using `generic-queue-N`).
12- Added `GenericTimerQueue` and `GlobalTimerQueue` structs that can be used to implement timer queues.
13 12
14## 0.1.0 - 2024-01-11 13## 0.1.0 - 2024-01-11
15 14
diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs
index 46dd646ca..d8b01df3b 100644
--- a/embassy-time-queue-driver/src/lib.rs
+++ b/embassy-time-queue-driver/src/lib.rs
@@ -2,52 +2,13 @@
2#![doc = include_str!("../README.md")] 2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)] 3#![warn(missing_docs)]
4 4
5//! ## Implementing a timer queue 5//! This crate is an implementation detail of `embassy-time-driver`.
6//! 6//!
7//! - Define a struct `MyTimerQueue` 7//! As a HAL user, you should only depend on this crate if your application does not use
8//! - Implement [`TimerQueue`] for it 8//! `embassy-executor` and your HAL does not configure a generic queue by itself.
9//! - Register it as the global timer queue with [`timer_queue_impl`].
10//! - Ensure that you process the timer queue when `schedule_wake` is due. This usually involves
11//! waking expired tasks, finding the next expiration time and setting an alarm.
12//! 9//!
13//! If a single global timer queue is sufficient for you, you can use the 10//! As a HAL implementer, you need to depend on this crate if you want to implement a time driver,
14//! [`GlobalTimerQueue`] type, which is a wrapper around a global timer queue 11//! but how you should do so is documented in [`embassy_time_driver`].
15//! protected by a critical section.
16//!
17//! ```
18//! use embassy_time_queue_driver::GlobalTimerQueue;
19//! embassy_time_queue_driver::timer_queue_impl!(
20//! static TIMER_QUEUE_DRIVER: GlobalTimerQueue
21//! = GlobalTimerQueue::new(|next_expiration| todo!("Set an alarm"))
22//! );
23//! ```
24//!
25//! You can also use the `queue_generic` or the `queue_integrated` modules to implement your own
26//! timer queue. These modules contain queue implementations which you can wrap and tailor to
27//! your needs.
28//!
29//! If you are providing an embassy-executor implementation besides a timer queue, you can choose to
30//! expose the `integrated-timers` feature in your implementation. This feature stores timer items
31//! in the tasks themselves, so you don't need a fixed-size queue or dynamic memory allocation.
32//!
33//! ## Example
34//!
35//! ```
36//! use core::task::Waker;
37//!
38//! use embassy_time::Instant;
39//! use embassy_time::queue::TimerQueue;
40//!
41//! struct MyTimerQueue{}; // not public!
42//!
43//! impl TimerQueue for MyTimerQueue {
44//! fn schedule_wake(&'static self, at: u64, waker: &Waker) {
45//! todo!()
46//! }
47//! }
48//!
49//! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{});
50//! ```
51 12
52use core::task::Waker; 13use core::task::Waker;
53 14