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//! 
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 {}