embedded-timers 0.4.0

Softwaretimers and -delays (ms/us) based on a Clock implementation
Documentation
// Copyright Open Logistics Foundation
//
// Licensed under the Open Logistics Foundation License 1.3.
// For details on the licensing terms, see the LICENSE file.
// SPDX-License-Identifier: OLFL-1.3

//! This crate provides a common base for monotonically nondecreasing clocks in `no_std`
//! environments. It defines the [`Clock`](clock::Clock) and [`Instant`](instant::Instant) traits
//! as interface and implements timers and delays based on these traits.
//!
//! By using the `Clock` trait as dependency, device drivers and applications can be developed in
//! a platform-independent way. Therefore, this crate serves the same purpose for clocks as the
//! [`embedded-hal`](https://docs.rs/embedded-hal/latest/embedded_hal/) or
//! [`embedded-nal`](https://docs.rs/embedded-nal/latest/embedded_nal/) crates for peripheral or
//! network abstraction, respectively.
//!
//! This crate is _only_ concerned with monotonically nondecreasing clocks, i.e. clocks which serve
//! the same purpose as the
//! [`std::time::Instant`](https://doc.rust-lang.org/stable/std/time/struct.Instant.html) type.
//! These can be used for measuring durations between instants, creating timers/timeouts or just
//! wait/delay program execution. Anything else which might be part of a time library is a
//! _non-goal_ of this crate: This crate is not concerned with system time or wall clock time
//! which might jump when the clock is synchronized. Furthermore, this crate does not cover time
//! zone handling or calendars.
//!
//! # Design Decisions
//!
//! To create a common interface for handling clocks in `no_std` environments, this crate aims to
//! make decisions which are acceptable for many use cases and many users. In this regard, it tries
//! to be as straightforward (boring) as possible and to avoid too opinionated or debatable
//! decisions. For example:
//! - Use whatever is already defined in `core`. Specifically, the
//!   [`core::time::Duration`](https://doc.rust-lang.org/stable/core/time/struct.Duration.html) type
//!   is used for durations although its 12 byte memory layout seems like overkill for many embedded
//!   applications. But it covers all use cases from high-precision to multi-year timing and it is
//!   already agreed upon in the community.
//! - The `Clock` and `Instant` traits are inspired by `std::time::Instant` which should be
//!   familiar for Rust developers. But different from `std::time::Instant`, no assumption of a
//!   globally available clock is made. Therefore, the functionality is split in two different
//!   traits.
//!
//! # Usage
//!
//! Most users (application, library or device driver developers) will depend on the `Clock` trait.
//! Then, the clock can be used for timers or delays without being concerned with the underlying
//! `Instant` type:
//!
//! ```
//! fn application(clock: &impl embedded_timers::clock::Clock) {
//!     // Get the current instant, the instant type is inferred from the generic Clock
//!     let earlier = clock.now();
//!     let later = clock.now();
//!     // The instant type is guaranteed to support calculations due to the Instant trait
//!     let time_passed: core::time::Duration = later - earlier;
//!
//!     // Timers and delays can easily be written manually
//!     let deadline = clock.now() + core::time::Duration::from_secs(1); // 1 second timer/delay
//!     loop {
//!         // By comparing clock.now() with the deadline, we determine if the timer has expired.
//!         // When doing nothing in the loop, this is a simple busy wait delay.
//!         if clock.now() > deadline {
//!             break;
//!         }
//!     }
//!
//!     // Alternatively, the provided helper types for timer and delay can be used
//!     let mut timer = embedded_timers::timer::Timer::new(clock);
//!     timer.try_start(core::time::Duration::from_secs(1)).unwrap();
//!     let is_expired = timer.is_expired().unwrap();
//! }
//! ```
//!
//! On the platform level, the `Clock` trait has to be implemented for a clock type. The associated
//! `Instant` type needs to implement the `Instant` trait. If the `std` feature is enabled,
//! `std::time::Instant` implements the `Instant` trait and can be used for a very simple clock:
//!
//! ```
//! struct StdClock;
//!
//! impl embedded_timers::clock::Clock for StdClock {
//!     type Instant = std::time::Instant;
//!     fn now(&self) -> Self::Instant {
//!         std::time::Instant::now()
//!     }
//! }
//! ```
//!
//! In an actual `no_std` environment, a clock needs to be implemented manually. For the associated
//! `Instant` type, it may use one of the types defined in the [`instant`] module. It needs to take
//! care of setting up an appropriate tick interrupt handler and to synchronize accesses to the
//! tick variable. This may look somewhat like:
//! ```
//! // Global tick counter variable which is incremented in the tick interrupt handler. By using an
//! // atomic variable, we can do this without unsafe code. Note that using a 32 bit counter for
//! // milliseconds will wrap around after around 50 days so this might not be feasible in a real
//! // scenario.
//! static TICKS: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
//!
//! // This tick interrupt handler is assumed to be called once per millisecond
//! fn tick_handler() {
//!     TICKS.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
//! }
//!
//! struct MilliSecondClock32;
//!
//! impl embedded_timers::clock::Clock for MilliSecondClock32 {
//!     type Instant = embedded_timers::instant::Instant32<1000>;
//!     fn now(&self) -> Self::Instant {
//!         let ticks = TICKS.load(core::sync::atomic::Ordering::Relaxed);
//!         embedded_timers::instant::Instant32::<1000>::new(ticks)
//!     }
//! }
//! ```
//!
//! ## Delay
//!
//! From the clock, a delay can be created. This will perform a busy waiting delay.
//!
//! ```rust,no_run
//! use embedded_timers::clock::Clock;
//! use embedded_hal::delay::DelayNs;
//! #[derive(Debug)]
//! pub struct MilliSecondClock;
//! # impl embedded_timers::clock::Clock for MilliSecondClock {
//! #     type Instant = std::time::Instant;
//! #     fn now(&self) -> Self::Instant {
//! #         std::time::Instant::now()
//! #     }
//! # }
//!
//! let clock = MilliSecondClock;
//! let mut delay = embedded_timers::delay::Delay::new(&clock);
//!
//! loop {
//!     println!("This shows every second");
//!     delay.delay_ms(1000_u32);
//! }
//! ```
//!
//! ## Timer
//!
//! The crate provides a convenient timer interface with functionality to check if the timer
//! `is_running` or `is_expired` and how much `duration_left`.
//!
//! ```rust,no_run
//! use embedded_timers::clock::Clock;
//! use embedded_timers::timer::Timer;
//! #[derive(Debug)]
//! pub struct MilliSecondClock;
//! # impl embedded_timers::clock::Clock for MilliSecondClock {
//! #     type Instant = std::time::Instant;
//! #     fn now(&self) -> Self::Instant {
//! #         std::time::Instant::now()
//! #     }
//! # }
//!
//! let clock = MilliSecondClock;
//! let mut timer = embedded_timers::timer::Timer::new(&clock);
//!
//! timer.start(core::time::Duration::from_secs(1));
//!
//! loop {
//!     if let Ok(expired) = timer.is_expired() {
//!         if expired {
//!             println!("This shows every second");
//!             timer.start(core::time::Duration::from_secs(1));
//!         }
//!     }
//! }
//! ```
//!
//! The `embedded_timers::Timer` also implements a non-blocking _count-down_
//! which utilizes [nb](https://docs.rs/nb/latest/nb/).
//!
//! ```rust,no_run
//! use embedded_timers::clock::Clock;
//! use embedded_timers::timer::Timer;
//! use embedded_hal::delay::DelayNs;
//! #[derive(Debug)]
//! pub struct MilliSecondClock;
//! # impl embedded_timers::clock::Clock for MilliSecondClock {
//! #     type Instant = std::time::Instant;
//! #     fn now(&self) -> Self::Instant {
//! #         std::time::Instant::now()
//! #     }
//! # }
//!
//! let clock = MilliSecondClock;
//! let mut timer = embedded_timers::timer::Timer::new(&clock);
//! let mut delay = embedded_timers::delay::Delay::new(&clock);
//!
//! timer.start(core::time::Duration::from_secs(1));
//!
//! loop {
//!     match timer.wait() {
//!         Err(nb::Error::WouldBlock) => {
//!             println!("Timer still running");
//!             delay.delay_ms(50_u32);
//!         }
//!         Err(_) => panic!("TIMER ERROR"),
//!         Ok(_) => {
//!             println!("This shows after one second");
//!             timer.start(core::time::Duration::from_secs(1));
//!         }
//!     }
//! }
//! ```
//!
//! # License
//!
//! Open Logistics Foundation License\
//! Version 1.3, January 2023
//!
//! See the LICENSE file in the top-level directory.
//!
//! # Contact
//!
//! Fraunhofer IML Embedded Rust Group - <embedded-rust@iml.fraunhofer.de>

#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
#![warn(missing_docs)]

/// Defines the [`Clock`](clock::Clock) trait for clocks which are expected to be always running
/// and never fail
pub mod clock;

pub mod instant;

/// Timer implementation based on Clocks
pub mod timer;

/// Delays based on Clocks
pub mod delay;