Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ gpio-cdev = { version = "0.2", optional = true }
sysfs_gpio = { version = "0.5", optional = true }

i2cdev = "0.4.3"
spidev = "0.4"
serial-unix = "0.4.0"
serial-core = "0.4.0"
nb = "0.1.1"
serial-core = "0.4.0"
serial-unix = "0.4.0"
spidev = "0.4"
void = "1"

[dev-dependencies]
openpty = "0.1.0"
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ use i2cdev::linux::LinuxI2CMessage;
use spidev::SpidevTransfer;

mod serial;
mod timer;

pub use serial::Serial;
pub use timer::SysTimer;

#[cfg(feature = "gpio_sysfs")]
/// Sysfs Pin wrapper module
Expand Down
88 changes: 88 additions & 0 deletions src/timer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! Timers.

use std::time::{Duration, Instant};

use hal::timer::{CountDown, Periodic};

/// A periodic timer based on [`std::time::Instant`][instant], which is a
/// monotonically nondecreasing clock.
///
/// [instant]: https://doc.rust-lang.org/std/time/struct.Instant.html
pub struct SysTimer {
start: Instant,
duration: Duration,
}

impl SysTimer {
/// Create a new timer instance.
///
/// The `duration` will be initialized to 0, so make sure to call `start`
/// with your desired timer duration before calling `wait`.
pub fn new() -> SysTimer {
SysTimer {
start: Instant::now(),
duration: Duration::from_millis(0),
}
}
}

impl CountDown for SysTimer {
type Time = Duration;

fn start<T>(&mut self, count: T)
where
T: Into<Self::Time>,
{
self.start = Instant::now();
self.duration = count.into();
}

fn wait(&mut self) -> nb::Result<(), void::Void> {
if (Instant::now() - self.start) >= self.duration {
// Restart the timer to fulfill the contract by `Periodic`
self.start = Instant::now();
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}

impl Periodic for SysTimer {}

#[cfg(test)]
mod tests {
use super::*;

/// Ensure that a 100 ms delay takes at least 100 ms,
/// but not longer than 500 ms.
#[test]
fn test_delay() {
let mut timer = SysTimer::new();
let before = Instant::now();
timer.start(Duration::from_millis(100));
nb::block!(timer.wait()).unwrap();
let after = Instant::now();
let duration_ms = (after - before).as_millis();
assert!(duration_ms >= 100);
assert!(duration_ms < 500);
}

/// Ensure that the timer is periodic.
#[test]
fn test_periodic() {
let mut timer = SysTimer::new();
let before = Instant::now();
timer.start(Duration::from_millis(100));
nb::block!(timer.wait()).unwrap();
let after1 = Instant::now();
let duration_ms_1 = (after1 - before).as_millis();
assert!(duration_ms_1 >= 100);
assert!(duration_ms_1 < 500);
nb::block!(timer.wait()).unwrap();
let after2 = Instant::now();
let duration_ms_2 = (after2 - after1).as_millis();
assert!(duration_ms_2 >= 100);
assert!(duration_ms_2 < 500);
}
}