Merge pull request #112 from torfmaster/feature/async-timer
Add parallel timer
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1f666c..17c8d81 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@
- `syscalls::allow_ptr` becomes `syscalls::raw::allow`
- Targets without support for atomics can be built
- Most API functions, including `main()`, return a `Result<T, TockError>`
+- The timer now supports to be used simultaneously. To make this safe, `TimerDriver` is now a singleton.
## a8bb4fa9be504517d5533511fd8e607ea61f1750 (0.1.0)
diff --git a/examples/adc.rs b/examples/adc.rs
index c4aafb2..2ed3b88 100644
--- a/examples/adc.rs
+++ b/examples/adc.rs
@@ -9,6 +9,10 @@
#[libtock::main]
async fn main() -> TockResult<()> {
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
+
let mut console = Console::new();
let mut with_callback = adc::with_callback(|channel: usize, value: usize| {
writeln!(console, "channel: {}, value: {}", channel, value).unwrap();
@@ -18,6 +22,6 @@
loop {
adc.sample(0)?;
- timer::sleep(Duration::from_ms(2000)).await?;
+ timer_driver.sleep(Duration::from_ms(2000)).await?;
}
}
diff --git a/examples/async.rs b/examples/async.rs
deleted file mode 100644
index fa661dd..0000000
--- a/examples/async.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-#![no_std]
-
-use futures::future;
-use libtock::buttons;
-use libtock::buttons::ButtonState;
-use libtock::futures as libtock_futures;
-use libtock::led;
-use libtock::result::TockResult;
-use libtock::timer;
-use libtock::timer::Duration;
-
-#[libtock::main]
-async fn main() -> TockResult<()> {
- future::try_join(blink_periodically(), blink_on_button_press()).await?;
- Ok(())
-}
-
-async fn blink_periodically() -> TockResult<()> {
- let led = led::get(0).unwrap();
- loop {
- timer::sleep(Duration::from_ms(250)).await?;
- led.on()?;
- timer::sleep(Duration::from_ms(250)).await?;
- led.off()?;
- }
-}
-
-async fn blink_on_button_press() -> TockResult<()> {
- let mut with_callback = buttons::with_callback(|_, _| {});
- let mut buttons = with_callback.init()?;
- let mut button = buttons.iter_mut().next().unwrap();
- let button = button.enable()?;
- let led = led::get(1).unwrap();
-
- loop {
- libtock_futures::wait_until(|| button.read().ok() == Some(ButtonState::Released)).await;
- libtock_futures::wait_until(|| button.read().ok() == Some(ButtonState::Pressed)).await;
- led.on()?;
- libtock_futures::wait_until(|| button.read().ok() == Some(ButtonState::Released)).await;
- libtock_futures::wait_until(|| button.read().ok() == Some(ButtonState::Pressed)).await;
- led.off()?;
- }
-}
diff --git a/examples/blink.rs b/examples/blink.rs
index aa75f36..f37fd12 100644
--- a/examples/blink.rs
+++ b/examples/blink.rs
@@ -8,6 +8,9 @@
#[libtock::main]
async fn main() -> TockResult<()> {
let num_leds = led::count()?;
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
// Blink the LEDs in a binary count pattern and scale
// to the number of LEDs on the board.
@@ -23,6 +26,6 @@
count = count.wrapping_add(1);
// This delay uses an underlying timer in the kernel.
- timer::sleep(Duration::from_ms(250)).await?;
+ timer_driver.sleep(Duration::from_ms(250)).await?;
}
}
diff --git a/examples/blink_random.rs b/examples/blink_random.rs
index 2298958..6b964a2 100644
--- a/examples/blink_random.rs
+++ b/examples/blink_random.rs
@@ -8,7 +8,11 @@
#[libtock::main]
async fn main() -> TockResult<()> {
- let num_leds = led::count().ok().unwrap();
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
+
+ let num_leds = led::count()?;
// blink_nibble assumes 4 leds.
assert_eq!(num_leds, 4);
@@ -18,9 +22,9 @@
for &x in buf.iter() {
blink_nibble(x)?;
- timer::sleep(Duration::from_ms(100)).await?;
+ timer_driver.sleep(Duration::from_ms(100)).await?;
blink_nibble(x >> 4)?;
- timer::sleep(Duration::from_ms(100)).await?;
+ timer_driver.sleep(Duration::from_ms(100)).await?;
}
}
}
diff --git a/examples/button_read.rs b/examples/button_read.rs
index 12648c1..74d1479 100644
--- a/examples/button_read.rs
+++ b/examples/button_read.rs
@@ -16,11 +16,16 @@
let mut button = buttons.iter_mut().next().unwrap();
let button = button.enable()?;
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
+
loop {
match button.read()? {
ButtonState::Pressed => writeln!(console, "pressed"),
ButtonState::Released => writeln!(console, "released"),
}?;
- timer::sleep(Duration::from_ms(500)).await?;
+
+ timer_driver.sleep(Duration::from_ms(500)).await?;
}
}
diff --git a/examples/gpio.rs b/examples/gpio.rs
index c0169e5..e472f2a 100644
--- a/examples/gpio.rs
+++ b/examples/gpio.rs
@@ -10,11 +10,14 @@
async fn main() -> TockResult<()> {
let pin = GpioPinUnitialized::new(0);
let pin = pin.open_for_write()?;
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
loop {
pin.set_high()?;
- timer::sleep(Duration::from_ms(500)).await?;
+ timer_driver.sleep(Duration::from_ms(500)).await?;
pin.set_low()?;
- timer::sleep(Duration::from_ms(500)).await?;
+ timer_driver.sleep(Duration::from_ms(500)).await?;
}
}
diff --git a/examples/gpio_read.rs b/examples/gpio_read.rs
index 5125042..cb3dc22 100644
--- a/examples/gpio_read.rs
+++ b/examples/gpio_read.rs
@@ -14,6 +14,9 @@
let mut console = Console::new();
let pin = GpioPinUnitialized::new(0);
let pin = pin.open_for_read(None, InputMode::PullDown)?;
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
loop {
if pin.read() {
@@ -21,6 +24,6 @@
} else {
writeln!(console, "false")?;
}
- timer::sleep(Duration::from_ms(500)).await?;
+ timer_driver.sleep(Duration::from_ms(500)).await?;
}
}
diff --git a/examples/hardware_test.rs b/examples/hardware_test.rs
index 87a6081..8a4689b 100644
--- a/examples/hardware_test.rs
+++ b/examples/hardware_test.rs
@@ -34,7 +34,7 @@
#[libtock::main]
async fn main() -> TockResult<()> {
let mut console = Console::new();
- write!(console, "[test-results]\n").unwrap();
+ write!(console, "[test-results]\n")?;
test_heap(&mut console);
test_formatting(&mut console);
@@ -42,11 +42,9 @@
test_gpio(&mut console);
- test_trait_objects(&mut console);
+ test_trait_objects(&mut console)?;
- test_callbacks_and_wait_forever(&mut console).await;
-
- Ok(())
+ test_callbacks_and_wait_forever(&mut console).await
}
fn test_heap(console: &mut Console) {
@@ -63,16 +61,13 @@
/// Output order should be:
/// trait_obj_value_usize = 1
/// trait_obj_value_string = string
-fn test_trait_objects(console: &mut Console) {
+fn test_trait_objects(console: &mut Console) -> TockResult<()> {
let pin_in = GpioPinUnitialized::new(0);
- let pin_in = pin_in
- .open_for_read(None, InputMode::PullDown)
- .ok()
- .unwrap();
+ let pin_in = pin_in.open_for_read(None, InputMode::PullDown)?;
let pin_out = GpioPinUnitialized::new(1);
- let pin_out = pin_out.open_for_write().ok().unwrap();
- pin_out.set_high().ok().unwrap();
+ let pin_out = pin_out.open_for_write()?;
+ pin_out.set_high()?;
let string = String::from("string");
@@ -90,6 +85,7 @@
x.do_something_with_a_console(console);
y.do_something_with_a_console(console);
+ Ok(())
}
fn test_static_mut(console: &mut Console) {
@@ -113,15 +109,15 @@
write!(console, "gpio_works = {}\n", pin_in.read()).unwrap();
}
-async fn test_callbacks_and_wait_forever(console: &mut Console) {
+async fn test_callbacks_and_wait_forever(console: &mut Console) -> TockResult<()> {
let mut with_callback = timer::with_callback(|_, _| {
write!(console, "callbacks_work = true\n").unwrap();
write!(console, "all_tests_run = true").unwrap();
});
- let mut timer = with_callback.init().ok().unwrap();
+ let mut timer = with_callback.init()?;
- timer.set_alarm(Duration::from_ms(500)).ok().unwrap();
+ timer.set_alarm(Duration::from_ms(500))?;
future::pending().await
}
diff --git a/examples/hello.rs b/examples/hello.rs
index fe42f6e..989a572 100644
--- a/examples/hello.rs
+++ b/examples/hello.rs
@@ -9,10 +9,13 @@
#[libtock::main]
async fn main() -> TockResult<()> {
let mut console = Console::new();
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
for i in 0.. {
writeln!(console, "Hello world! {}", i)?;
- timer::sleep(Duration::from_ms(500)).await?;
+ timer_driver.sleep(Duration::from_ms(500)).await?;
}
Ok(())
diff --git a/examples/sensors.rs b/examples/sensors.rs
index 4e1748a..1dd373b 100644
--- a/examples/sensors.rs
+++ b/examples/sensors.rs
@@ -14,11 +14,15 @@
let mut temperature = TemperatureSensor;
let mut light = AmbientLightSensor;
let mut ninedof = unsafe { Ninedof::new() };
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
+
loop {
writeln!(console, "Humidity: {}\n", humidity.read()?)?;
writeln!(console, "Temperature: {}\n", temperature.read()?)?;
writeln!(console, "Light: {}\n", light.read()?)?;
writeln!(console, "Accel: {}\n", ninedof.read_acceleration()?)?;
- timer::sleep(Duration::from_ms(500)).await?;
+ timer_driver.sleep(Duration::from_ms(500)).await?;
}
}
diff --git a/examples/seven_segment.rs b/examples/seven_segment.rs
index 9e73a80..cf884e4 100644
--- a/examples/seven_segment.rs
+++ b/examples/seven_segment.rs
@@ -31,10 +31,14 @@
GpioPinUnitialized::new(2).open_for_write()?,
);
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
+
let mut i = 0;
loop {
i = (i + 1) % 11;
shift_register.write_bits(&number_to_bits(i))?;
- timer::sleep(Duration::from_ms(200)).await?;
+ timer_driver.sleep(Duration::from_ms(200)).await?;
}
}
diff --git a/examples/simple_ble.rs b/examples/simple_ble.rs
index b3dce9b..a4bee5a 100644
--- a/examples/simple_ble.rs
+++ b/examples/simple_ble.rs
@@ -43,10 +43,14 @@
let _handle = BleAdvertisingDriver::initialize(100, &gap_payload, &mut buffer);
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
+
loop {
led.on()?;
- timer::sleep(Duration::from_ms(500)).await?;
+ timer_driver.sleep(Duration::from_ms(500)).await?;
led.off()?;
- timer::sleep(Duration::from_ms(500)).await?;
+ timer_driver.sleep(Duration::from_ms(500)).await?;
}
}
diff --git a/examples/timer_parallel.rs b/examples/timer_parallel.rs
new file mode 100644
index 0000000..c19e583
--- /dev/null
+++ b/examples/timer_parallel.rs
@@ -0,0 +1,34 @@
+#![no_std]
+
+use futures::future;
+use libtock::led;
+use libtock::result::TockResult;
+use libtock::timer;
+use libtock::timer::Duration;
+use libtock::timer::ParallelSleepDriver;
+
+async fn blink<'a>(
+ timer_driver: &'a ParallelSleepDriver<'a>,
+ duration: Duration<usize>,
+ led_number: usize,
+) -> TockResult<()> {
+ loop {
+ led::get(led_number).unwrap().toggle()?;
+
+ timer_driver.sleep(duration).await?;
+ }
+}
+
+#[libtock::main]
+async fn main() -> TockResult<()> {
+ let context = timer::DriverContext::create()?;
+ let mut driver = context.create_timer_driver()?;
+ let timer_driver = driver.activate()?;
+
+ let fut_1 = blink(&timer_driver, Duration::from_ms(500), 0);
+ let fut_2 = blink(&timer_driver, Duration::from_ms(333), 1);
+ let fut_3 = blink(&timer_driver, Duration::from_ms(250), 2);
+
+ future::try_join3(fut_1, fut_2, fut_3).await?;
+ Ok(())
+}
diff --git a/src/lang_items.rs b/src/lang_items.rs
index 1447929..197de47 100644
--- a/src/lang_items.rs
+++ b/src/lang_items.rs
@@ -47,15 +47,22 @@
// Flash all LEDs (if available).
executor::block_on(async {
+ let context = timer::DriverContext::create().ok();
+ let mut driver = context.as_ref().map(|c| c.create_timer_driver_unsafe());
+ let timer_driver = driver.as_mut().and_then(|d| d.activate().ok());
loop {
for led in led::all() {
let _ = led.on();
}
- let _ = timer::sleep(Duration::from_ms(100)).await;
+ if let Some(ref timer_driver) = timer_driver {
+ let _ = timer_driver.sleep(Duration::from_ms(100)).await;
+ }
for led in led::all() {
let _ = led.off();
}
- let _ = timer::sleep(Duration::from_ms(100)).await;
+ if let Some(ref timer_driver) = timer_driver {
+ let _ = timer_driver.sleep(Duration::from_ms(100)).await;
+ }
}
});
// Never type is not supported for T in Future
@@ -65,12 +72,22 @@
#[alloc_error_handler]
unsafe fn cycle_leds(_: Layout) -> ! {
executor::block_on(async {
+ let context = timer::DriverContext::create().ok();
+ let mut driver = context.as_ref().map(|c| c.create_timer_driver_unsafe());
+ let timer_driver = driver.as_mut().and_then(|d| d.activate().ok());
loop {
for led in led::all() {
let _ = led.on();
- let _ = timer::sleep(Duration::from_ms(100)).await;
+ }
+ if let Some(ref timer_driver) = timer_driver {
+ let _ = timer_driver.sleep(Duration::from_ms(100)).await;
+ }
+ for led in led::all() {
let _ = led.off();
}
+ if let Some(ref timer_driver) = timer_driver {
+ let _ = timer_driver.sleep(Duration::from_ms(100)).await;
+ }
}
});
// Never type is not supported for T in Future
diff --git a/src/result.rs b/src/result.rs
index 9b26c31..4eaec21 100644
--- a/src/result.rs
+++ b/src/result.rs
@@ -69,6 +69,7 @@
pub enum OtherError {
TimerDriverDurationOutOfRange,
TimerDriverErroneousClockFrequency,
+ DriverAlreadyTaken,
}
impl From<OtherError> for TockError {
diff --git a/src/timer.rs b/src/timer.rs
index 08c6fa6..9a43027 100644
--- a/src/timer.rs
+++ b/src/timer.rs
@@ -1,8 +1,12 @@
+//! Async timer driver. Can be used for (non-busy) sleeping.
+
use crate::callback::CallbackSubscription;
use crate::callback::SubscribableCallback;
use crate::futures;
use crate::result::OtherError;
+use crate::result::TockError;
use crate::result::TockResult;
+use crate::result::EALREADY;
use crate::syscalls;
use core::cell::Cell;
use core::isize;
@@ -22,17 +26,6 @@
pub const SUBSCRIBE_CALLBACK: usize = 0;
}
-pub async fn sleep(duration: Duration<isize>) -> TockResult<()> {
- let expired = Cell::new(false);
- let mut with_callback = with_callback(|_, _| expired.set(true));
-
- let mut timer = with_callback.init()?;
- timer.set_alarm(duration)?;
-
- futures::wait_until(|| expired.get()).await;
- Ok(())
-}
-
pub fn with_callback<CB>(callback: CB) -> WithCallback<CB> {
WithCallback {
callback,
@@ -288,3 +281,498 @@
self.ms += duration.ms();
}
}
+
+static mut TIMER_DRIVER_AVAILABLE: bool = true;
+
+#[derive(Copy, Clone, Default, PartialEq, Eq)]
+struct ActiveTimer {
+ instant: u32,
+ set_at: u32,
+}
+
+/// Context for the time driver.
+/// You can create a context as follows:
+/// ```no_run
+/// # use libtock::timer::DriverContext;
+/// # use libtock::result::TockResult;
+/// # #[libtock::main]
+/// # async fn main() -> TockResult<()> {
+/// let context = DriverContext::create();
+/// # Ok(())
+/// # }
+/// ```
+pub struct DriverContext {
+ active_timer: Cell<Option<ActiveTimer>>,
+ current_time: Cell<usize>,
+}
+
+impl DriverContext {
+ /// Create a driver context
+ pub fn create() -> TockResult<Self> {
+ let num_ticks = get_current_ticks()?;
+ Ok(DriverContext {
+ active_timer: Default::default(),
+ current_time: Cell::new(num_ticks),
+ })
+ }
+ /// Create a driver timer from a context. As the driver is a singleton
+ /// from the app perspective this function will return None
+ /// if called more than once.
+ pub fn create_timer_driver<'a>(&'a self) -> TockResult<TimerDriver<'a>> {
+ if unsafe { TIMER_DRIVER_AVAILABLE } {
+ unsafe {
+ TIMER_DRIVER_AVAILABLE = false;
+ }
+ Ok(TimerDriver {
+ callback: Callback {
+ now: &self.current_time,
+ },
+ context: &self,
+ })
+ } else {
+ Err(TockError::Other(OtherError::DriverAlreadyTaken))
+ }
+ }
+
+ pub unsafe fn create_timer_driver_unsafe<'a>(&'a self) -> TimerDriver<'a> {
+ TimerDriver {
+ callback: Callback {
+ now: &self.current_time,
+ },
+ context: &self,
+ }
+ }
+}
+
+/// Timer driver instance. You can create a TimerDriver from a DriverContext as follows:
+/// ```no_run
+/// # use libtock::timer::DriverContext;
+/// # use libtock::result::TockResult;
+/// # #[libtock::main]
+/// # async fn main() -> TockResult<()> {
+/// let context = DriverContext::create()?;
+/// context.create_timer_driver().expect("The timer driver is a singleton and can only created once.");
+/// # Ok(())
+/// # }
+/// ```
+pub struct TimerDriver<'a> {
+ callback: Callback<'a>,
+ context: &'a DriverContext,
+}
+
+struct Callback<'a> {
+ now: &'a Cell<usize>,
+}
+
+impl<'a> SubscribableCallback for Callback<'a> {
+ fn call_rust(&mut self, now: usize, _: usize, _: usize) {
+ self.now.set(now);
+ }
+}
+
+/// Activated time driver. Updates current time in the context and manages
+/// active alarms.
+/// Example usage (sleep for 1 second):
+/// ```no_run
+/// # use libtock::timer::DriverContext;
+/// # use libtock::result::TockResult;
+/// # use libtock::timer::Duration;
+/// # #[libtock::main]
+/// # async fn main() -> TockResult<()> {
+/// let context = DriverContext::create()?;
+/// let mut driver = context.create_timer_driver().unwrap();
+/// let timer_driver = driver.activate()?;
+/// timer_driver.sleep(Duration::from_ms(1000)).await?;
+/// # Ok(())
+/// # }
+/// ```
+pub struct ParallelSleepDriver<'a> {
+ _callback_subscription: CallbackSubscription<'a>,
+ context: &'a DriverContext,
+}
+
+impl<'a> TimerDriver<'a> {
+ /// Activate the timer driver, will return a ParallelSleepDriver which
+ /// can used to sleep.
+ pub fn activate(&'a mut self) -> TockResult<ParallelSleepDriver<'a>> {
+ let subscription = syscalls::subscribe(
+ DRIVER_NUMBER,
+ subscribe_nr::SUBSCRIBE_CALLBACK,
+ &mut self.callback,
+ )?;
+ let driver = ParallelSleepDriver {
+ _callback_subscription: subscription,
+ context: &self.context,
+ };
+ Ok(driver)
+ }
+}
+
+impl<'a> ParallelSleepDriver<'a> {
+ /// Sleep for the given duration
+ pub async fn sleep(&self, duration: Duration<usize>) -> TockResult<()> {
+ let now = get_current_ticks()?;
+ self.context.current_time.set(now);
+ let freq = get_clock_frequency()?;
+ let alarm_instant = Self::compute_alarm_instant(duration.ms, now, freq)?;
+ let this_alarm = ActiveTimer {
+ instant: alarm_instant as u32,
+ set_at: now as u32,
+ };
+
+ let suspended_timer: Cell<Option<ActiveTimer>> = Cell::new(None);
+
+ futures::wait_until(|| {
+ self.activate_current_timer(this_alarm, &suspended_timer)
+ .unwrap_or(false)
+ })
+ .await;
+
+ Ok(())
+ }
+
+ fn activate_timer(&self, timer: &ActiveTimer) -> TockResult<()> {
+ set_alarm_at(timer.instant as usize)?;
+ let now = get_current_ticks()?;
+ if !is_over(*timer, now as u32) {
+ self.context.active_timer.set(Some(*timer));
+ } else {
+ self.wakeup_soon()?;
+ }
+ Ok(())
+ }
+
+ fn wakeup_soon(&self) -> TockResult<()> {
+ self.context.active_timer.set(None);
+
+ for i in 0.. {
+ let now = get_current_ticks()?;
+
+ let next_timer = ActiveTimer {
+ instant: now as u32 + i,
+ set_at: now as u32,
+ };
+ set_alarm_at(next_timer.instant as usize)?;
+ let now = get_current_ticks()?;
+ if !is_over(next_timer, now as u32) {
+ break;
+ } else {
+ match stop_alarm_at(next_timer.instant as usize) {
+ Ok(_) => (),
+ Err(_) => (),
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn compute_alarm_instant(
+ duration_ms: usize,
+ num_ticks: usize,
+ freq: usize,
+ ) -> TockResult<usize> {
+ let ticks = match duration_ms.checked_mul(freq) {
+ Some(x) => x / 1000,
+ None => {
+ // Divide the largest of the two operands by 1000, to improve precision of the
+ // result.
+ if duration_ms > freq {
+ match (duration_ms / 1000).checked_mul(freq) {
+ Some(y) => y,
+ None => {
+ return Err(TockError::Other(OtherError::TimerDriverDurationOutOfRange))
+ }
+ }
+ } else {
+ match (freq / 1000).checked_mul(duration_ms) {
+ Some(y) => y,
+ None => {
+ return Err(TockError::Other(OtherError::TimerDriverDurationOutOfRange))
+ }
+ }
+ }
+ }
+ };
+ let alarm_instant = num_ticks + ticks;
+ Ok(alarm_instant)
+ }
+
+ fn activate_current_timer(
+ &self,
+ this_alarm: ActiveTimer,
+ suspended_timer: &Cell<Option<ActiveTimer>>,
+ ) -> TockResult<bool> {
+ let now = get_current_ticks()?;
+
+ if let Some(active) = self.context.active_timer.get() {
+ if left_is_later(active, this_alarm) {
+ suspended_timer.set(Some(active));
+ self.activate_timer(&this_alarm)?;
+ }
+ } else {
+ self.activate_timer(&this_alarm)?;
+ }
+ if is_over(this_alarm, now as u32) {
+ if let Some(paused) = suspended_timer.get() {
+ self.activate_timer(&paused)?;
+ } else {
+ self.context.active_timer.set(None);
+ }
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
+}
+
+fn get_current_ticks() -> TockResult<usize> {
+ syscalls::command(DRIVER_NUMBER, command_nr::GET_CLOCK_VALUE, 0, 0).map_err(|err| err.into())
+}
+fn set_alarm_at(instant: usize) -> TockResult<()> {
+ syscalls::command(DRIVER_NUMBER, command_nr::SET_ALARM, instant, 0)
+ .map(|_| ())
+ .map_err(|err| err.into())
+}
+
+fn stop_alarm_at(instant: usize) -> TockResult<()> {
+ match syscalls::command(DRIVER_NUMBER, command_nr::STOP_ALARM, instant, 0) {
+ Ok(_) => Ok(()),
+ Err(error) => match error.return_code {
+ EALREADY => Ok(()),
+ _ => Err(TockError::Command(error)),
+ },
+ }
+}
+
+fn get_clock_frequency() -> TockResult<usize> {
+ syscalls::command(DRIVER_NUMBER, command_nr::GET_CLOCK_FREQUENCY, 0, 0)
+ .map_err(|err| err.into())
+}
+
+fn is_over(timer: ActiveTimer, now: u32) -> bool {
+ now.wrapping_sub(timer.set_at) >= timer.instant.wrapping_sub(timer.set_at)
+}
+
+fn left_is_later(alarm_1: ActiveTimer, alarm_2: ActiveTimer) -> bool {
+ if alarm_1.set_at <= alarm_1.instant && alarm_2.set_at <= alarm_2.instant {
+ return alarm_1.instant > alarm_2.instant;
+ }
+ if alarm_1.set_at <= alarm_1.instant && alarm_2.set_at >= alarm_2.instant {
+ return false;
+ }
+ if alarm_1.set_at >= alarm_1.instant && alarm_2.set_at <= alarm_2.instant {
+ return true;
+ }
+ if alarm_1.set_at >= alarm_1.instant && alarm_2.set_at >= alarm_2.instant {
+ return alarm_1.instant > alarm_2.instant;
+ }
+ false
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ #[test]
+ pub fn duration_bigger_than_frequency() {
+ let x = ParallelSleepDriver::compute_alarm_instant(10000, 0, 1000)
+ .ok()
+ .unwrap();
+ assert_eq!(x, 10000);
+ }
+
+ #[test]
+ pub fn frequency_bigger_than_duration() {
+ let x = ParallelSleepDriver::compute_alarm_instant(1000, 0, 10000)
+ .ok()
+ .unwrap();
+ assert_eq!(x, 10000);
+ }
+
+ #[test]
+ pub fn fails_if_duration_is_too_large() {
+ let x =
+ ParallelSleepDriver::compute_alarm_instant(core::usize::MAX, 0, core::usize::MAX - 1);
+ assert!(x.is_err());
+ }
+
+ #[test]
+ pub fn fails_if_frequency_is_too_large() {
+ let x =
+ ParallelSleepDriver::compute_alarm_instant(core::usize::MAX - 1, 0, core::usize::MAX);
+ assert!(x.is_err());
+ }
+
+ #[test]
+ pub fn alarm_before_systick_wrap_expired() {
+ assert_eq!(
+ super::is_over(
+ super::ActiveTimer {
+ instant: 2u32,
+ set_at: 1u32
+ },
+ 3u32
+ ),
+ true
+ );
+ }
+
+ #[test]
+ pub fn alarm_before_systick_wrap_not_expired() {
+ assert_eq!(
+ super::is_over(
+ super::ActiveTimer {
+ instant: 3u32,
+ set_at: 1u32
+ },
+ 2u32
+ ),
+ false
+ );
+ }
+
+ #[test]
+ pub fn alarm_after_systick_wrap_expired() {
+ assert_eq!(
+ super::is_over(
+ super::ActiveTimer {
+ instant: 1u32,
+ set_at: 3u32
+ },
+ 2u32
+ ),
+ true
+ );
+ }
+
+ #[test]
+ pub fn alarm_after_systick_wrap_time_before_systick_wrap_not_expired() {
+ assert_eq!(
+ super::is_over(
+ super::ActiveTimer {
+ instant: 1u32,
+ set_at: 3u32
+ },
+ 4u32
+ ),
+ false
+ );
+ }
+
+ #[test]
+ pub fn alarm_after_systick_wrap_time_after_systick_wrap_not_expired() {
+ assert_eq!(
+ super::is_over(
+ super::ActiveTimer {
+ instant: 1u32,
+ set_at: 3u32
+ },
+ 0u32
+ ),
+ false
+ );
+ }
+
+ #[test]
+ pub fn left_later_than_the_other_both_not_wrapped() {
+ let later = super::ActiveTimer {
+ instant: 3u32,
+ set_at: 1u32,
+ };
+ let earlier = super::ActiveTimer {
+ instant: 2u32,
+ set_at: 1u32,
+ };
+ assert_eq!(super::left_is_later(later, earlier), true);
+ }
+
+ #[test]
+ pub fn right_later_than_the_other_both_not_wrapped() {
+ let later = super::ActiveTimer {
+ instant: 2u32,
+ set_at: 1u32,
+ };
+ let earlier = super::ActiveTimer {
+ instant: 3u32,
+ set_at: 1u32,
+ };
+ assert_eq!(super::left_is_later(later, earlier), false);
+ }
+
+ #[test]
+ pub fn left_later_left_wrapped() {
+ let later = super::ActiveTimer {
+ instant: 1u32,
+ set_at: 3u32,
+ };
+ let earlier = super::ActiveTimer {
+ instant: 2u32,
+ set_at: 1u32,
+ };
+ assert_eq!(super::left_is_later(later, earlier), true);
+ }
+
+ #[test]
+ pub fn right_later_right_wrapped() {
+ let later = super::ActiveTimer {
+ instant: 3u32,
+ set_at: 1u32,
+ };
+ let earlier = super::ActiveTimer {
+ instant: 1u32,
+ set_at: 3u32,
+ };
+ assert_eq!(super::left_is_later(later, earlier), false);
+ }
+
+ #[test]
+ pub fn left_later_both_wrapped() {
+ let later = super::ActiveTimer {
+ instant: 2u32,
+ set_at: 3u32,
+ };
+ let earlier = super::ActiveTimer {
+ instant: 1u32,
+ set_at: 3u32,
+ };
+ assert_eq!(super::left_is_later(later, earlier), true);
+ }
+
+ #[test]
+ pub fn right_later_both_wrapped() {
+ let later = super::ActiveTimer {
+ instant: 1u32,
+ set_at: 3u32,
+ };
+ let earlier = super::ActiveTimer {
+ instant: 2u32,
+ set_at: 3u32,
+ };
+ assert_eq!(super::left_is_later(later, earlier), false);
+ }
+
+ #[test]
+ pub fn inequality_is_strict() {
+ let later = super::ActiveTimer {
+ instant: 2u32,
+ set_at: 1u32,
+ };
+ let earlier = super::ActiveTimer {
+ instant: 2u32,
+ set_at: 1u32,
+ };
+ assert_eq!(super::left_is_later(later, earlier), false);
+ }
+
+ #[test]
+ pub fn inequality_is_strict_wrapped() {
+ let later = super::ActiveTimer {
+ instant: 1u32,
+ set_at: 2u32,
+ };
+ let earlier = super::ActiveTimer {
+ instant: 1u32,
+ set_at: 2u32,
+ };
+ assert_eq!(super::left_is_later(later, earlier), false);
+ }
+}