From acc12432fb412949aee50c1b1d13903a15344f7a Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 23 May 2026 17:48:52 +0200 Subject: [PATCH 1/2] add default implementations delegating to `ticks` functionality --- src/lib.rs | 56 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fd00e54..c47174a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,10 @@ use core::{error::Error, fmt::Display}; +const MILLIS_PER_SEC: u64 = 1_000; +const MICROS_PER_SEC: u64 = 1_000_000; +const NANOS_PER_SEC: u64 = 1_000_000_000; + /// A timer that can be started from 0 and keeps track of the time until it overflows. /// /// This trait may be implemented directly on top of short running hardware timers @@ -28,13 +32,21 @@ pub trait Timer { fn elapsed_ticks(&self) -> Result; /// Return the number of elapsed nanoseconds, rounded down. - fn elapsed_nanos(&self) -> Result; + fn elapsed_nanos(&self) -> Result { + Ok((self.elapsed_ticks()? * NANOS_PER_SEC) / self.tickrate()) + } /// Return the number of elapsed microseconds, rounded down. - fn elapsed_micros(&self) -> Result; + fn elapsed_micros(&self) -> Result { + Ok((self.elapsed_ticks()? * MICROS_PER_SEC) / self.tickrate()) + } /// Return the number of elapsed milliseconds, rounded down. - fn elapsed_millis(&self) -> Result; + fn elapsed_millis(&self) -> Result { + Ok((self.elapsed_ticks()? * MILLIS_PER_SEC) / self.tickrate()) + } /// Return the number of elapsed seconds, rounded down. - fn elapsed_secs(&self) -> Result; + fn elapsed_secs(&self) -> Result { + Ok(self.elapsed_ticks()? / self.tickrate()) + } /// The (inclusive) maximum number of ticks that can happen before the overflow occurs /// if [start](Self::start) were called now. @@ -47,25 +59,33 @@ pub trait Timer { /// /// This value is not necessarily constant as implementations built on top of continuously running /// timers will have shrinking amount of time left. - fn max_nanos(&self) -> u64; + fn max_nanos(&self) -> u64 { + (self.max_ticks() * NANOS_PER_SEC) / self.tickrate() + } /// The (inclusive) maximum number of microseconds that can happen before the overflow occurs /// if [start](Self::start) were called now. /// /// This value is not necessarily constant as implementations built on top of continuously running /// timers will have shrinking amount of time left. - fn max_micros(&self) -> u64; + fn max_micros(&self) -> u64 { + (self.max_ticks() * MICROS_PER_SEC) / self.tickrate() + } /// The (inclusive) maximum number of milliseconds that can happen before the overflow occurs /// if [start](Self::start) were called now. /// /// This value is not necessarily constant as implementations built on top of continuously running /// timers will have shrinking amount of time left. - fn max_millis(&self) -> u64; + fn max_millis(&self) -> u64 { + (self.max_ticks() * MILLIS_PER_SEC) / self.tickrate() + } /// The (inclusive) maximum number of seconds that can happen before the overflow occurs /// if [start](Self::start) were called now. /// /// This value is not necessarily constant as implementations built on top of continuously running /// timers will have shrinking amount of time left. - fn max_secs(&self) -> u64; + fn max_secs(&self) -> u64 { + self.max_ticks() / self.tickrate() + } } /// An alarm that can be used to wait for a time to come. @@ -80,22 +100,34 @@ pub trait Alarm: Timer { /// If the alarm is already reached, the function exits immediately. /// /// The function returns an overflow error if the alarm value is higher than is supported by the implementation. - async fn wait_until_nanos(&mut self, value: u64) -> Result<(), OverflowError>; + fn wait_until_nanos(&mut self, value: u64) -> impl Future> { + let ticks = (value * self.tickrate()) / NANOS_PER_SEC; + self.wait_until_ticks(ticks) + } /// Wait until the timer reaches the alarm specified in microseconds since the timer has started. /// If the alarm is already reached, the function exits immediately. /// /// The function returns an overflow error if the alarm value is higher than is supported by the implementation. - async fn wait_until_micros(&mut self, value: u64) -> Result<(), OverflowError>; + fn wait_until_micros(&mut self, value: u64) -> impl Future> { + let ticks = (value * self.tickrate()) / MICROS_PER_SEC; + self.wait_until_ticks(ticks) + } /// Wait until the timer reaches the alarm specified in milliseconds since the timer has started. /// If the alarm is already reached, the function exits immediately. /// /// The function returns an overflow error if the alarm value is higher than is supported by the implementation. - async fn wait_until_millis(&mut self, value: u64) -> Result<(), OverflowError>; + fn wait_until_millis(&mut self, value: u64) -> impl Future> { + let ticks = (value * self.tickrate()) / MILLIS_PER_SEC; + self.wait_until_ticks(ticks) + } /// Wait until the timer reaches the alarm specified in seconds since the timer has started. /// If the alarm is already reached, the function exits immediately. /// /// The function returns an overflow error if the alarm value is higher than is supported by the implementation. - async fn wait_until_secs(&mut self, value: u64) -> Result<(), OverflowError>; + fn wait_until_secs(&mut self, value: u64) -> impl Future> { + let ticks = value * self.tickrate(); + self.wait_until_ticks(ticks) + } } /// The timer has overflowed From 0cbc546292c36db891a1ab766f8bda4814da3904 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 23 May 2026 18:23:18 +0200 Subject: [PATCH 2/2] Make `tickrate` return `NonZeroU64` Having a tickrate of zero seems nonsensical, and gives rise to some cases where division could lead to div-by-zero. --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c47174a..1c9b5c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ //! These traits are intended to be eventually included into embedded-hal & embedded-hal-async. //! As such these traits are work in progress and the crate may receive breaking changes. -use core::{error::Error, fmt::Display}; +use core::{error::Error, fmt::Display, num::NonZeroU64}; const MILLIS_PER_SEC: u64 = 1_000; const MICROS_PER_SEC: u64 = 1_000_000; @@ -27,7 +27,7 @@ pub trait Timer { fn start(&mut self); /// Get the amount of ticks per second. - fn tickrate(&self) -> u64; + fn tickrate(&self) -> NonZeroU64; /// Return the number of elapsed ticks. fn elapsed_ticks(&self) -> Result; @@ -101,7 +101,7 @@ pub trait Alarm: Timer { /// /// The function returns an overflow error if the alarm value is higher than is supported by the implementation. fn wait_until_nanos(&mut self, value: u64) -> impl Future> { - let ticks = (value * self.tickrate()) / NANOS_PER_SEC; + let ticks = (value * self.tickrate().get()) / NANOS_PER_SEC; self.wait_until_ticks(ticks) } /// Wait until the timer reaches the alarm specified in microseconds since the timer has started. @@ -109,7 +109,7 @@ pub trait Alarm: Timer { /// /// The function returns an overflow error if the alarm value is higher than is supported by the implementation. fn wait_until_micros(&mut self, value: u64) -> impl Future> { - let ticks = (value * self.tickrate()) / MICROS_PER_SEC; + let ticks = (value * self.tickrate().get()) / MICROS_PER_SEC; self.wait_until_ticks(ticks) } /// Wait until the timer reaches the alarm specified in milliseconds since the timer has started. @@ -117,7 +117,7 @@ pub trait Alarm: Timer { /// /// The function returns an overflow error if the alarm value is higher than is supported by the implementation. fn wait_until_millis(&mut self, value: u64) -> impl Future> { - let ticks = (value * self.tickrate()) / MILLIS_PER_SEC; + let ticks = (value * self.tickrate().get()) / MILLIS_PER_SEC; self.wait_until_ticks(ticks) } /// Wait until the timer reaches the alarm specified in seconds since the timer has started. @@ -125,7 +125,7 @@ pub trait Alarm: Timer { /// /// The function returns an overflow error if the alarm value is higher than is supported by the implementation. fn wait_until_secs(&mut self, value: u64) -> impl Future> { - let ticks = value * self.tickrate(); + let ticks = value * self.tickrate().get(); self.wait_until_ticks(ticks) } }