Skip to main content

thread_delay/
lib.rs

1//! This crate provides a blocking implementation of DelayNs from
2//! [`embedded_hal`] that can be used on Linux systems using the
3//! Linux standard library. It is intended to be a drop-in replacement
4//! for application using libraries that were written for embedded
5//! devices but have access to the standard library, such as a single 
6//! board computer (SBC) running Linux.
7//! 
8//! The Delay implementation is like the one from [`linux_embedded_hal`] but
9//! provides all the `delay_*` functions defined by the trait.
10//! 
11//! The functions are:
12//! 
13//! 1. `delay_ns` for nanosecond delays
14//! 2. `delay_us` for microsecond delays
15//! 3. `delay_ms` for milliseconds delays
16//! 
17//! ## Example
18//!
19//! This example is an application running on a Raspberry Pi Zero 2 W
20//! that takes readings from a `bme280` atmospheric sensor.
21//! 
22//! ```rust,ignore
23//! use thread_delay::Delay;
24//!
25//! use bme280::i2c::BME280;
26//! use rppal::i2c::I2c;
27//! use std::time::Instant;
28//!  
29//! enum LoopState {
30//!     Waiting,
31//!     Measureing,
32//! }
33//!
34//! fn main() -> ! {
35//!     let i2c = I2c::with_bus(1).expect("failed to find i2c bus 1");
36//!     assert!(i2c.bus() == 1_u8);
37//!
38//!     let mut delay = Delay {};
39//!
40//!     let mut bme280 = BME280::new_primary(i2c);
41//!
42//!     bme280.init(&mut delay).expect("failed to initialize bme280 sensor");
43//!
44//!     let mut state = LoopState::Waiting;
45//!
46//!     let delay_millis: u128 = 1_000;
47//!
48//!     let mut last_update = Instant::now();
49//!
50//!     loop {
51//!         let elapsed = last_update.elapsed();
52//!
53//!         match state {
54//!             LoopState::Waiting => {
55//!                 if elapsed.as_millis() >= delay_millis {
56//!                     state = LoopState::Measureing
57//!                 }
58//!             }
59//!
60//!             LoopState::Measureing => {
61//!                 let measurements = bme280
62//!                     .measure(&mut delay)
63//!                     .expect("failed to read measurements from bme280");
64//!
65//!                 println!("Temp:     |{:-10.3} C |", measurements.temperature);
66//!                 println!("Humidity: |{:-10.3} % |", measurements.humidity);
67//!                 println!("Pressure: |{:-10.3} Pa|", measurements.pressure);
68//!                 println!("-----");
69//!
70//!                 last_update = Instant::now();
71//!                 state = LoopState::Waiting;
72//!             }
73//!         }
74//!     }
75//! }
76//! ```
77use std::{thread::sleep, time::Duration};
78
79use embedded_hal::delay::DelayNs;
80
81#[allow(unused)]
82/// Empty struct that implements the `DelayNs` trait using `std::thread::sleep`
83pub struct ThreadDelay;
84
85#[allow(unused)]
86/// A convienvce alias for keeping the `Delay` struct name
87pub type Delay = ThreadDelay;
88
89/// `DelayNs` trait from [`embedded_hal`] implemented using sleep.
90/// The thread may sleep longer than the duration specified due to
91/// scheduling specifics or platform-dependent functionality.
92/// It will never sleep less.
93/// 
94/// This function is blocking, and should not be used in async functions.
95impl DelayNs for ThreadDelay {
96    /// Pauses execution for at minimum `ns` nanoseconds.
97    fn delay_ns(&mut self, ns: u32) {
98        sleep(Duration::from_nanos(ns as u64));
99    }
100
101    /// Pauses execution for at minimum `us` microseconds.
102    fn delay_us(&mut self, us: u32) {
103        sleep(Duration::from_micros(us as u64));
104    }
105
106    /// Pauses execution for at minimum `ms` milliseconds.
107    fn delay_ms(&mut self, ms: u32) {
108        sleep(Duration::from_millis(ms as u64));
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use std::time::Instant;
115
116    use super::*;
117
118    #[test]
119    fn test_delay_ms() {
120        let millis = [500_u32, 127, 0, 1];
121        let mut delay = Delay {};
122
123        for milli in millis {
124            let start = Instant::now();
125            delay.delay_ms(milli);
126            let elapsed = start.elapsed();
127            assert!(elapsed.as_millis() >= milli as u128);
128        }
129    }
130
131    #[test]
132    fn test_delay_ns() {
133        let nanos = [500_u32, 127, 0, 454];
134        let mut delay = Delay {};
135
136        for nano in nanos {
137            let start = Instant::now();
138            delay.delay_ns(nano);
139            assert!(start.elapsed().as_nanos() >= nano as u128);
140        }
141    }
142
143    #[test]
144    fn test_delay_us() {
145        let micros = [250_u32, 128, 324, 98123];
146        let mut delay = Delay {};
147
148        for micro in micros {
149            let start = Instant::now();
150            delay.delay_us(micro);
151            assert!(start.elapsed().as_micros() >= micro as u128);
152        }
153    }
154}