mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 20:30:29 +00:00
Update documentation and changelogs
This commit is contained in:
parent
e861344b17
commit
0492dba536
@ -1,4 +1,4 @@
|
|||||||
# Changelog for embassy-time-queue-driver
|
# Changelog for embassy-time-driver
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
- The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed.
|
- The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed.
|
||||||
|
- `schedule_wake` has been added to the `Driver` trait.
|
||||||
|
|
||||||
## 0.1.0 - 2024-01-11
|
## 0.1.0 - 2024-01-11
|
||||||
|
|
||||||
|
@ -17,25 +17,7 @@
|
|||||||
//! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by
|
//! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by
|
||||||
//! enabling a feature on `embassy-time`.
|
//! enabling a feature on `embassy-time`.
|
||||||
//!
|
//!
|
||||||
//! # Linkage details
|
//! ### Example
|
||||||
//!
|
|
||||||
//! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions.
|
|
||||||
//!
|
|
||||||
//! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it.
|
|
||||||
//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the
|
|
||||||
//! calls from the `embassy` crate to call into the driver crate.
|
|
||||||
//!
|
|
||||||
//! If there is none or multiple drivers in the crate tree, linking will fail.
|
|
||||||
//!
|
|
||||||
//! This method has a few key advantages for something as foundational as timekeeping:
|
|
||||||
//!
|
|
||||||
//! - The time driver is available everywhere easily, without having to thread the implementation
|
|
||||||
//! through generic parameters. This is especially helpful for libraries.
|
|
||||||
//! - It means comparing `Instant`s will always make sense: if there were multiple drivers
|
|
||||||
//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
|
|
||||||
//! would yield incorrect results.
|
|
||||||
//!
|
|
||||||
//! # Example
|
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! use core::task::Waker;
|
//! use core::task::Waker;
|
||||||
@ -56,6 +38,65 @@
|
|||||||
//!
|
//!
|
||||||
//! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
|
//! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Implementing the timer queue
|
||||||
|
//!
|
||||||
|
//! The simplest (but suboptimal) way to implement a timer queue is to define a single queue in the
|
||||||
|
//! time driver. Declare a field protected by an appropriate mutex (e.g. `critical_section::Mutex`).
|
||||||
|
//!
|
||||||
|
//! Then, you'll need to adapt the `schedule_wake` method to use this queue.
|
||||||
|
//!
|
||||||
|
//! ```ignore
|
||||||
|
//! use core::cell::RefCell;
|
||||||
|
//! use core::task::Waker;
|
||||||
|
//!
|
||||||
|
//! use embassy_time_queue_driver::Queue;
|
||||||
|
//! use embassy_time_driver::Driver;
|
||||||
|
//!
|
||||||
|
//! struct MyDriver {
|
||||||
|
//! timer_queue: critical_section::Mutex<RefCell<Queue>>,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! impl MyDriver {
|
||||||
|
//! fn set_alarm(&self, cs: &CriticalSection, at: u64) -> bool {
|
||||||
|
//! todo!()
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! impl Driver for MyDriver {
|
||||||
|
//! // fn now(&self) -> u64 { ... }
|
||||||
|
//!
|
||||||
|
//! fn schedule_wake(&self, at: u64, waker: &Waker) {
|
||||||
|
//! critical_section::with(|cs| {
|
||||||
|
//! let mut queue = self.queue.borrow(cs).borrow_mut();
|
||||||
|
//! if queue.schedule_wake(at, waker) {
|
||||||
|
//! let mut next = queue.next_expiration(self.now());
|
||||||
|
//! while !self.set_alarm(cs, next) {
|
||||||
|
//! next = queue.next_expiration(self.now());
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! });
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Linkage details
|
||||||
|
//!
|
||||||
|
//! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions.
|
||||||
|
//!
|
||||||
|
//! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it.
|
||||||
|
//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the
|
||||||
|
//! calls from the `embassy` crate to call into the driver crate.
|
||||||
|
//!
|
||||||
|
//! If there is none or multiple drivers in the crate tree, linking will fail.
|
||||||
|
//!
|
||||||
|
//! This method has a few key advantages for something as foundational as timekeeping:
|
||||||
|
//!
|
||||||
|
//! - The time driver is available everywhere easily, without having to thread the implementation
|
||||||
|
//! through generic parameters. This is especially helpful for libraries.
|
||||||
|
//! - It means comparing `Instant`s will always make sense: if there were multiple drivers
|
||||||
|
//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
|
||||||
|
//! would yield incorrect results.
|
||||||
|
|
||||||
//! ## Feature flags
|
//! ## Feature flags
|
||||||
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
|
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
|
||||||
|
@ -7,9 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
- Added `integrated-timers` and `generic-queue-N` features
|
- Added `generic-queue-N` features.
|
||||||
- Added `queue_generic` module which contains `Queue` (configured via the `generic-queue-N` features) and `ConstGenericQueue<SIZE>`.
|
- Added `embassy_time_queue_driver::Queue` struct which uses integrated or a generic storage (configured using `generic-queue-N`).
|
||||||
- Added `GenericTimerQueue` and `GlobalTimerQueue` structs that can be used to implement timer queues.
|
|
||||||
|
|
||||||
## 0.1.0 - 2024-01-11
|
## 0.1.0 - 2024-01-11
|
||||||
|
|
||||||
|
@ -2,52 +2,13 @@
|
|||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
//! ## Implementing a timer queue
|
//! This crate is an implementation detail of `embassy-time-driver`.
|
||||||
//!
|
//!
|
||||||
//! - Define a struct `MyTimerQueue`
|
//! As a HAL user, you should only depend on this crate if your application does not use
|
||||||
//! - Implement [`TimerQueue`] for it
|
//! `embassy-executor` and your HAL does not configure a generic queue by itself.
|
||||||
//! - Register it as the global timer queue with [`timer_queue_impl`].
|
|
||||||
//! - Ensure that you process the timer queue when `schedule_wake` is due. This usually involves
|
|
||||||
//! waking expired tasks, finding the next expiration time and setting an alarm.
|
|
||||||
//!
|
//!
|
||||||
//! If a single global timer queue is sufficient for you, you can use the
|
//! As a HAL implementer, you need to depend on this crate if you want to implement a time driver,
|
||||||
//! [`GlobalTimerQueue`] type, which is a wrapper around a global timer queue
|
//! but how you should do so is documented in [`embassy_time_driver`].
|
||||||
//! protected by a critical section.
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! use embassy_time_queue_driver::GlobalTimerQueue;
|
|
||||||
//! embassy_time_queue_driver::timer_queue_impl!(
|
|
||||||
//! static TIMER_QUEUE_DRIVER: GlobalTimerQueue
|
|
||||||
//! = GlobalTimerQueue::new(|next_expiration| todo!("Set an alarm"))
|
|
||||||
//! );
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! You can also use the `queue_generic` or the `queue_integrated` modules to implement your own
|
|
||||||
//! timer queue. These modules contain queue implementations which you can wrap and tailor to
|
|
||||||
//! your needs.
|
|
||||||
//!
|
|
||||||
//! If you are providing an embassy-executor implementation besides a timer queue, you can choose to
|
|
||||||
//! expose the `integrated-timers` feature in your implementation. This feature stores timer items
|
|
||||||
//! in the tasks themselves, so you don't need a fixed-size queue or dynamic memory allocation.
|
|
||||||
//!
|
|
||||||
//! ## Example
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! use core::task::Waker;
|
|
||||||
//!
|
|
||||||
//! use embassy_time::Instant;
|
|
||||||
//! use embassy_time::queue::TimerQueue;
|
|
||||||
//!
|
|
||||||
//! struct MyTimerQueue{}; // not public!
|
|
||||||
//!
|
|
||||||
//! impl TimerQueue for MyTimerQueue {
|
|
||||||
//! fn schedule_wake(&'static self, at: u64, waker: &Waker) {
|
|
||||||
//! todo!()
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{});
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
use core::task::Waker;
|
use core::task::Waker;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user