Skip to content

Commit 9e6f0ec

Browse files
bors[bot]dbrgn
andauthored
Merge #36
36: Add timer::CountDown implementation r=posborne a=dbrgn Based on the [implementation by @MathiasKoch](https://github.com/BlackbirdHQ/ublox-cellular-rs/blob/master/examples/common/timer.rs). Co-authored-by: Danilo Bargen <[email protected]>
2 parents 734f41e + 373cf8e commit 9e6f0ec

File tree

3 files changed

+94
-3
lines changed

3 files changed

+94
-3
lines changed

Cargo.toml

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ gpio-cdev = { version = "0.2", optional = true }
2020
sysfs_gpio = { version = "0.5", optional = true }
2121

2222
i2cdev = "0.4.3"
23-
spidev = "0.4"
24-
serial-unix = "0.4.0"
25-
serial-core = "0.4.0"
2623
nb = "0.1.1"
24+
serial-core = "0.4.0"
25+
serial-unix = "0.4.0"
26+
spidev = "0.4"
27+
void = "1"
2728

2829
[dev-dependencies]
2930
openpty = "0.1.0"

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ use i2cdev::linux::LinuxI2CMessage;
4040
use spidev::SpidevTransfer;
4141

4242
mod serial;
43+
mod timer;
4344

4445
pub use serial::Serial;
46+
pub use timer::SysTimer;
4547

4648
#[cfg(feature = "gpio_sysfs")]
4749
/// Sysfs Pin wrapper module

src/timer.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//! Timers.
2+
3+
use std::time::{Duration, Instant};
4+
5+
use hal::timer::{CountDown, Periodic};
6+
7+
/// A periodic timer based on [`std::time::Instant`][instant], which is a
8+
/// monotonically nondecreasing clock.
9+
///
10+
/// [instant]: https://doc.rust-lang.org/std/time/struct.Instant.html
11+
pub struct SysTimer {
12+
start: Instant,
13+
duration: Duration,
14+
}
15+
16+
impl SysTimer {
17+
/// Create a new timer instance.
18+
///
19+
/// The `duration` will be initialized to 0, so make sure to call `start`
20+
/// with your desired timer duration before calling `wait`.
21+
pub fn new() -> SysTimer {
22+
SysTimer {
23+
start: Instant::now(),
24+
duration: Duration::from_millis(0),
25+
}
26+
}
27+
}
28+
29+
impl CountDown for SysTimer {
30+
type Time = Duration;
31+
32+
fn start<T>(&mut self, count: T)
33+
where
34+
T: Into<Self::Time>,
35+
{
36+
self.start = Instant::now();
37+
self.duration = count.into();
38+
}
39+
40+
fn wait(&mut self) -> nb::Result<(), void::Void> {
41+
if (Instant::now() - self.start) >= self.duration {
42+
// Restart the timer to fulfill the contract by `Periodic`
43+
self.start = Instant::now();
44+
Ok(())
45+
} else {
46+
Err(nb::Error::WouldBlock)
47+
}
48+
}
49+
}
50+
51+
impl Periodic for SysTimer {}
52+
53+
#[cfg(test)]
54+
mod tests {
55+
use super::*;
56+
57+
/// Ensure that a 100 ms delay takes at least 100 ms,
58+
/// but not longer than 500 ms.
59+
#[test]
60+
fn test_delay() {
61+
let mut timer = SysTimer::new();
62+
let before = Instant::now();
63+
timer.start(Duration::from_millis(100));
64+
nb::block!(timer.wait()).unwrap();
65+
let after = Instant::now();
66+
let duration_ms = (after - before).as_millis();
67+
assert!(duration_ms >= 100);
68+
assert!(duration_ms < 500);
69+
}
70+
71+
/// Ensure that the timer is periodic.
72+
#[test]
73+
fn test_periodic() {
74+
let mut timer = SysTimer::new();
75+
let before = Instant::now();
76+
timer.start(Duration::from_millis(100));
77+
nb::block!(timer.wait()).unwrap();
78+
let after1 = Instant::now();
79+
let duration_ms_1 = (after1 - before).as_millis();
80+
assert!(duration_ms_1 >= 100);
81+
assert!(duration_ms_1 < 500);
82+
nb::block!(timer.wait()).unwrap();
83+
let after2 = Instant::now();
84+
let duration_ms_2 = (after2 - after1).as_millis();
85+
assert!(duration_ms_2 >= 100);
86+
assert!(duration_ms_2 < 500);
87+
}
88+
}

0 commit comments

Comments
 (0)