embedded_time/
lib.rs

1//! `embedded-time` provides a comprehensive library of [`Duration`] and [`Rate`] types as well as
2//! a [`Clock`] abstraction for hardware timers/clocks and the associated [`Instant`] type for
3//! in embedded systems.
4//!
5//! Additionally, an implementation of software timers is provided that work seemlessly with all
6//! the types in this crate.
7//!
8//! ```rust
9//! use embedded_time::{duration::*, rate::*};
10//! # use core::convert::TryInto;
11//!
12//! let micros = 200_000_u32.microseconds();                // 200_000 μs
13//! let millis: Milliseconds = micros.into();               // 200 ms
14//! let frequency: Result<Hertz,_> = millis.to_rate();      // 5 Hz
15//!
16//! assert_eq!(frequency, Ok(5_u32.Hz()));
17//! ```
18//!
19//! # Motivation
20//!
21//! The handling of time on embedded systems is generally much different than that of OSs. For
22//! instance, on an OS, the time is measured against an arbitrary epoch. Embedded systems generally
23//! don't know (nor do they care) what the *real* time is, but rather how much time has passed since
24//! the system has started.
25//!
26//! ## Drawbacks of the standard library types
27//!
28//! ### Duration
29//!
30//! - The storage is `u64` seconds and `u32` nanoseconds.
31//! - This is huge overkill and adds needless complexity beyond what is required (or desired) for
32//!   embedded systems.
33//! - Any read (with the exception of seconds and nanoseconds) requires arithmetic to convert to the
34//!   requested units
35//! - This is much slower than this project's implementation of what is analogous to a tagged union
36//!   of time units.
37//!
38//! ### Instant
39//!
40//! - The `Instant` type requires `std`.
41//!
42//! ## Drawbacks of the [`time`](https://crates.io/crates/time) crate
43//!
44//! The `time` crate is a remarkable library but isn't geared for embedded systems (although it does
45//! support a subset of features in `no_std` contexts). It suffers from some of the same drawbacks
46//! as the core::Duration type (namely the storage format) and the `Instant` struct dependency on
47//! `std`. It also adds a lot of functionally that would seldom be useful in an embedded context.
48//! For instance it has a comprehensive date/time formatting, timezone, and calendar support.
49//!
50//! ## Background
51//!
52//! ### What is an Instant?
53//!
54//! In the Rust ecosystem, it appears to be idiomatic to call a `now()` associated function from an
55//! Instant type. There is generally no concept of a "Clock". I believe that using the `Instant` in
56//! this way is a violation of the *separation of concerns* principle. What is an `Instant`? Is it a
57//! time-keeping entity from which you read the current instant in time, or is it that instant in
58//! time itself. In this case, it's both.
59//!
60//! As an alternative, the current instant in time is read from a **Clock**. The `Instant` read from
61//! the `Clock` has the same precision and width (inner type) as the `Clock`. Requesting the
62//! difference between two `Instant`s gives a `Duration` which can have different precision and/or
63//! width.
64//!
65//! # Overview
66//!
67//! The approach taken is similar to the C++ `chrono` library. [`Duration`]s and [`Rate`]s are
68//! fixed-point values as in they are comprised of _integer_ and _scaling factor_ values.
69//! The _scaling factor_ is a `const` [`Fraction`](fraction::Fraction). One benefit of this
70//! structure is that it avoids unnecessary arithmetic. For example, if the [`Duration`] type is
71//! [`Milliseconds`], a call to the [`Duration::integer()`] method simply returns the _integer_
72//! part directly which in this case is the number of milliseconds represented by the [`Duration`].
73//! Conversion arithmetic is only performed when explicitly converting between time units (eg.
74//! [`Milliseconds`] --> [`Seconds`]).
75//!
76//! In addition, a wide range of rate-type types are available including [`Hertz`],
77//! [`BitsPerSecond`], [`KibibytesPerSecond`], [`Baud`], etc.
78//!
79//! A [`Duration`] type can be converted to a [`Rate`] type and vica-versa.
80//!
81//! [`Seconds`]: duration::units::Seconds
82//! [`Milliseconds`]: duration::units::Milliseconds
83//! [`Clock`]: clock::Clock
84//! [`Instant`]: instant::Instant
85//! [`Rate`]: rate::Rate
86//! [`Hertz`]: rate::units::Hertz
87//! [`BitsPerSecond`]: rate::units::BitsPerSecond
88//! [`KibibytesPerSecond`]: rate::units::KibibytesPerSecond
89//! [`Baud`]: rate::units::Baud
90//! [`Duration`]: duration::Duration
91//! [`Duration::integer()`]: duration/trait.Duration.html#tymethod.integer
92//!
93//! ## Definitions
94//!
95//! **Clock**: Any entity that periodically counts (ie an external or peripheral hardware
96//! timer/counter). Generally, this needs to be monotonic. A wrapping clock is considered monotonic
97//! in this context as long as it fulfills the other requirements.
98//!
99//! **Wrapping Clock**: A clock that when at its maximum value, the next count is the minimum
100//! value.
101//!
102//! **Timer**: An entity that counts toward an expiration.
103//!
104//! **Instant**: A specific instant in time ("time-point") read from a clock.
105//!
106//! **Duration**: The difference of two instants. The time that has elapsed since an instant. A
107//! span of time.
108//!
109//! **Rate**: A measure of events per time such as frequency, data-rate, etc.
110//!
111//! # Imports
112//!
113//! The suggested use statements are as follows depending on what is needed:
114//!
115//! ```rust
116//! use embedded_time::duration::*;    // imports all duration-related types and traits
117//! use embedded_time::rate::*;        // imports all rate-related types and traits
118//! use embedded_time::clock;
119//! use embedded_time::Instant;
120//! use embedded_time::Timer;
121//! ```
122//!
123//! # Duration Types
124//!
125//! | Units        | Extension    |
126//! | :----------- | :----------- |
127//! | Hours        | hours        |
128//! | Minutes      | minutes      |
129//! | Seconds      | seconds      |
130//! | Milliseconds | milliseconds |
131//! | Microseconds | microseconds |
132//! | Nanoseconds  | nanoseconds  |
133//!
134//! - Conversion from `Rate` types
135//! ```rust
136//! use embedded_time::{duration::*, rate::*};
137//!
138//! # assert!(
139//! Microseconds(500_u32).to_rate() == Ok(Kilohertz(2_u32))
140//! # );
141//! ```
142//!
143//! - Conversion to/from `Generic` `Duration` type
144//!
145//! ```rust
146//! use embedded_time::{duration::*};
147//! # use core::convert::TryFrom;
148//!
149//! # assert!(
150//! Seconds(2_u64).to_generic(Fraction::new(1, 2_000)) == Ok(Generic::new(4_000_u32, Fraction::new(1, 2_000)))
151//! # );
152//! # assert!(
153//! Seconds::<u64>::try_from(Generic::new(2_000_u32, Fraction::new(1, 1_000))) == Ok(Seconds(2_u64))
154//! # );
155//! ```
156//!
157//! ## `core` Compatibility
158//!
159//! - Conversion to/from `core::time::Duration`
160//!
161//! ### Benchmark Comparisons to `core` duration type
162//!
163//! #### Construct and Read Milliseconds
164//!
165//! ```rust
166//! use embedded_time::duration::*;
167//!
168//! # let ms = 100;
169//! let duration = Milliseconds::<u64>(ms); // 8 bytes
170//! let count = duration.integer();
171//! ```
172//!
173//! _(the size of `embedded-time` duration types is only the size of the inner type)_
174//!
175//! ```rust
176//! use std::time::Duration;
177//!
178//! # let ms = 100;
179//! let core_duration = Duration::from_millis(ms); // 12 bytes
180//! let count = core_duration.as_millis();
181//! ```
182//!
183//! _(the size of `core` duration type is 12 B)_
184//!
185//! ![](resources/duration_violin_v0.7.0.svg)
186//!
187//! # Rate Types
188//!
189//! ## Frequency
190//! | Units             | Extension |
191//! | :---------------- | :-------- |
192//! | Mebihertz         | MiHz      |
193//! | Megahertz         | MHz       |
194//! | Kibihertz         | KiHz      |
195//! | Kilohertz         | kHz       |
196//! | Hertz             | Hz        |
197//!
198//! ## Data Rate
199//! | Units             | Extension |
200//! | :---------------- | :-------- |
201//! | MebibytePerSecond | MiBps     |
202//! | MegabytePerSecond | MBps      |
203//! | KibibytePerSecond | KiBps     |
204//! | KiloBytePerSecond | KBps      |
205//! | BytePerSecond     | Bps       |
206//! |                   |           |
207//! | MebibitPerSecond  | Mibps     |
208//! | MegabitPerSecond  | Mbps      |
209//! | KibibitPerSecond  | Kibps     |
210//! | KilobitPerSecond  | kbps      |
211//! | BitPerSecond      | bps       |
212//!
213//! ## Symbol Rate
214//! | Units             | Extension |
215//! | :---------------- | :-------- |
216//! | Mebibaud          | MiBd      |
217//! | Megabaud          | MBd       |
218//! | Kibibaud          | KiBd      |
219//! | Kilobaud          | kBd       |
220//! | Baud              | Bd        |
221//!
222//! - Conversion from/to all other rate types within the same class (frequency, data rate, etc.) and
223//!   _base_ (mega, mebi, kilo, kibi). For example, MiBps (mebibytes per second) --> Kibps (kibibits
224//!   per second) and MBps (megabytes per second) --> kbps (kilobits per second).
225//!
226//! - Conversion from `Duration` types
227//!
228//! ```rust
229//! use embedded_time::{duration::*, rate::*};
230//! # use core::convert::TryFrom;
231//!
232//! # assert!(
233//! Kilohertz(500_u32).to_duration() == Ok(Microseconds(2_u32))
234//! # );
235//! ```
236//!
237//! - Conversion to/from `Generic` `Rate` type
238//!
239//! ```rust
240//! use embedded_time::rate::*;
241//! # use core::convert::TryFrom;
242//!
243//! # assert!(
244//! Hertz(2_u64).to_generic(Fraction::new(1,2_000)) == Ok(Generic::new(4_000_u32, Fraction::new(1,2_000)))
245//! # );
246//! # assert!(
247//! Hertz::<u64>::try_from(Generic::new(2_000_u32, Fraction::new(1,1_000))) == Ok(Hertz(2_u64))
248//! # );
249//! ```
250//!
251//! # Hardware Abstraction
252//!
253//! - `Clock` trait allowing abstraction of hardware timers/clocks for timekeeping.
254//!
255//! # Timers
256//!
257//! - Software timers spawned from a `Clock` impl object.
258//! - One-shot or periodic/continuous
259//! - Blocking delay
260//! - Poll for expiration
261//! - Read elapsed/remaining duration
262//!
263//! # Reliability and Usability
264//!
265//! - Extensive tests
266//! - Thorough documentation with examples
267//! - Example for the nRF52_DK board
268//!
269//! # Notes
270//!
271//! Some parts of this crate were derived from various sources:
272//! - [`RTIC`](https://github.com/rtic-rs/cortex-m-rtic)
273//! - [`time`](https://docs.rs/time/latest/time) (Specifically the [`time::NumbericalDuration`](https://docs.rs/time/latest/time/trait.NumericalDuration.html)
274//!   implementations for primitive integers)
275#![doc(html_root_url = "https://docs.rs/embedded-time/0.12.1")]
276#![deny(unsafe_code)]
277#![cfg_attr(not(test), no_std)]
278#![warn(missing_docs)]
279#![deny(broken_intra_doc_links)]
280
281pub mod clock;
282pub mod duration;
283pub mod fixed_point;
284pub mod fraction;
285mod instant;
286pub mod rate;
287mod time_int;
288pub mod timer;
289
290pub use clock::Clock;
291pub use instant::Instant;
292pub use time_int::TimeInt;
293pub use timer::Timer;
294
295/// Crate errors
296#[non_exhaustive]
297#[derive(Debug, Eq, PartialEq, Hash)]
298pub enum TimeError {
299    /// Exact cause of failure is unknown
300    Unspecified,
301    /// Attempted type conversion failed
302    ConversionFailure,
303    /// Result is outside of those valid for this type
304    Overflow,
305    /// Attempted to divide by zero
306    DivByZero,
307    /// Resulting [`Duration`](duration/trait.Duration.html) is negative (not allowed)
308    NegDuration,
309    /// [`Clock`]-implementation-specific error
310    Clock(clock::Error),
311}
312
313impl From<clock::Error> for TimeError {
314    fn from(clock_error: clock::Error) -> Self {
315        TimeError::Clock(clock_error)
316    }
317}
318
319impl Default for TimeError {
320    fn default() -> Self {
321        Self::Unspecified
322    }
323}
324
325/// Conversion errors
326#[non_exhaustive]
327#[derive(Debug, Eq, PartialEq, Hash)]
328pub enum ConversionError {
329    /// Exact cause of failure is unknown
330    Unspecified,
331    /// Attempted type conversion failed
332    ConversionFailure,
333    /// Result is outside of those valid for this type
334    Overflow,
335    /// Attempted to divide by zero
336    DivByZero,
337    /// Resulting [`Duration`](duration/trait.Duration.html) is negative (not allowed)
338    NegDuration,
339}
340
341impl From<ConversionError> for TimeError {
342    fn from(error: ConversionError) -> Self {
343        match error {
344            ConversionError::Unspecified => TimeError::Unspecified,
345            ConversionError::ConversionFailure => TimeError::ConversionFailure,
346            ConversionError::Overflow => TimeError::Overflow,
347            ConversionError::DivByZero => TimeError::DivByZero,
348            ConversionError::NegDuration => TimeError::NegDuration,
349        }
350    }
351}
352
353impl Default for ConversionError {
354    fn default() -> Self {
355        Self::Unspecified
356    }
357}
358
359#[cfg(test)]
360mod tests {}