|
| 1 | +//! Time types similar to `std::time` types. |
| 2 | +//! |
| 3 | +//! However, the rust-embedded world tends to use `fugit` for time. This has a Duration and |
| 4 | +//! Instant type, but they are parameterized by the slice used, and try hard to do the conversion |
| 5 | +//! at compile time. |
| 6 | +//! |
| 7 | +//! std has two time types, a Duration which represents an elapsed amount of time, and Instant, |
| 8 | +//! which represents a specific instance in time. |
| 9 | +//! |
| 10 | +//! Zephyr typically coordinates time in terms of a system tick interval, which comes from |
| 11 | +//! `sys_clock_hw_cycles_per_sec()`. |
| 12 | +//! |
| 13 | +//! The Rust/std semantics require Instant to be monotonically increasing. |
| 14 | +//! |
| 15 | +//! Zephyr's `sys/time_units.h` header contains numerous optimized macros for manipulating time in |
| 16 | +//! these units, specifically for converting between human time units and ticks, trying to avoid |
| 17 | +//! division, especially division by non-constants. |
| 18 | +
|
| 19 | +use zephyr_sys::k_timeout_t; |
| 20 | + |
| 21 | +// The system ticks, is mostly a constant, but there are some boards that use a dynamic tick |
| 22 | +// frequency, and thus need to read this at runtime. |
| 23 | +#[cfg(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME)] |
| 24 | +compile_error!("Rust does not (yet) support dynamic frequency timer"); |
| 25 | + |
| 26 | +// Given the above not defined, the system time base comes from a kconfig. |
| 27 | +/// The system time base. The system clock has this many ticks per second. |
| 28 | +pub const SYS_FREQUENCY: u32 = crate::kconfig::CONFIG_SYS_CLOCK_TICKS_PER_SEC as u32; |
| 29 | + |
| 30 | +/// Zephyr can be configured for either 64-bit or 32-bit time values. Use the appropriate type |
| 31 | +/// internally to match. This should end up the same size as `k_ticks_t`, but unsigned instead of |
| 32 | +/// signed. |
| 33 | +#[cfg(CONFIG_TIMEOUT_64BIT)] |
| 34 | +pub type Tick = u64; |
| 35 | +#[cfg(not(CONFIG_TIMEOUT_64BIT))] |
| 36 | +pub type Tick = u32; |
| 37 | + |
| 38 | +/// Duration appropraite for Zephyr calls that expect `k_timeout_t`. The result will be a time |
| 39 | +/// interval from "now" (when the call is made). |
| 40 | +pub type Duration = fugit::Duration<Tick, 1, SYS_FREQUENCY>; |
| 41 | + |
| 42 | +/// An Instant appropriate for Zephyr calls that expect a `k_timeout_t`. The result will be an |
| 43 | +/// absolute time in terms of system ticks. |
| 44 | +#[cfg(CONFIG_TIMEOUT_64BIT)] |
| 45 | +pub type Instant = fugit::Instant<Tick, 1, SYS_FREQUENCY>; |
| 46 | + |
| 47 | +// The zephry k_timeout_t represents several different types of intervals, based on the range of |
| 48 | +// the value. It is a signed number of the same size as the Tick here, which effectively means it |
| 49 | +// is one bit less. |
| 50 | +// |
| 51 | +// 0: K_NO_WAIT: indicates the operation should not wait. |
| 52 | +// 1 .. Max: indicates a duration in ticks of a delay from "now". |
| 53 | +// -1: K_FOREVER: a time that never expires. |
| 54 | +// MIN .. -2: A wait for an absolute amount of ticks from the start of the system. |
| 55 | +// |
| 56 | +// The absolute time offset is only implemented when time is a 64 bit value. This also means that |
| 57 | +// "Instant" isn't available when time is defined as a 32-bit value. |
| 58 | + |
| 59 | +// Wrapper around the timeout type, so we can implement From/Info. |
| 60 | +pub struct Timeout(pub k_timeout_t); |
| 61 | + |
| 62 | +// From allows methods to take a time of various types and convert it into a Zephyr timeout. |
| 63 | +impl From<Duration> for Timeout { |
| 64 | + fn from(value: Duration) -> Timeout { |
| 65 | + Timeout(k_timeout_t { ticks: value.ticks() as i64 }) |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +#[cfg(CONFIG_TIMEOUT_64BIT)] |
| 70 | +impl From<Instant> for Timeout { |
| 71 | + fn from(value: Instant) -> Timeout { |
| 72 | + Timeout(k_timeout_t { ticks: -1 - 1 - (value.ticks() as i64) }) |
| 73 | + } |
| 74 | +} |
| 75 | + |
| 76 | +/// A sleep that waits forever. This is its own type, that is `Into<Timeout>` and can be used |
| 77 | +/// anywhere a timeout is needed. |
| 78 | +pub struct Forever; |
| 79 | + |
| 80 | +impl From<Forever> for Timeout { |
| 81 | + fn from(_value: Forever) -> Timeout { |
| 82 | + Timeout(crate::sys::K_FOREVER) |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +/// A sleep that doesn't ever wait. This is its own type, that is `Info<Timeout>` and can be used |
| 87 | +/// anywhere a timeout is needed. |
| 88 | +pub struct NoWait; |
| 89 | + |
| 90 | +impl From<NoWait> for Timeout { |
| 91 | + fn from(_valued: NoWait) -> Timeout { |
| 92 | + Timeout(crate::sys::K_NO_WAIT) |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +/// Put the current thread to sleep, for the given duration. Uses `k_sleep` for the actual sleep. |
| 97 | +/// Returns a duration roughly representing the remaining amount of time if the sleep was woken. |
| 98 | +pub fn sleep<T>(timeout: T) -> Duration |
| 99 | + where T: Into<Timeout>, |
| 100 | +{ |
| 101 | + let timeout: Timeout = timeout.into(); |
| 102 | + let rest = unsafe { crate::raw::k_sleep(timeout.0) }; |
| 103 | + Duration::millis(rest as Tick) |
| 104 | +} |
0 commit comments