1#![no_std]
5#![doc = include_str!("../README.md")]
6#![deny(clippy::undocumented_unsafe_blocks)]
7#![deny(unsafe_op_in_unsafe_fn)]
8#![cfg_attr(docsrs, feature(doc_cfg))]
9
10#[cfg(feature = "embedded-hal")]
11mod embedded_hal;
12pub mod memory_mapped;
16#[cfg(any(test, feature = "fakes", target_arch = "aarch64"))]
20pub mod sysreg;
21
22use core::{hint::spin_loop, time::Duration};
23
24pub trait TimerInterface {
26 fn enable(&mut self);
28
29 fn frequency(&self) -> u32;
31
32 fn timer_value(&self) -> u32;
34}
35
36pub struct Timer<T: TimerInterface> {
38 timer: T,
39}
40
41impl<T: TimerInterface> Timer<T> {
42 pub fn new(timer: T) -> Self {
44 Self { timer }
45 }
46
47 pub fn enable(&mut self) {
49 self.timer.enable();
50 }
51
52 pub fn wait(&self, duration: Duration) {
55 let ticks =
56 u128::from(self.timer.frequency()).saturating_mul(duration.as_micros()) / 1_000_000;
57 let increment = u32::try_from(ticks).unwrap_or(u32::MAX);
58
59 let start = self.timer.timer_value();
60
61 while start.wrapping_sub(self.timer.timer_value()) < increment {
63 spin_loop();
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use core::cell::Cell;
72
73 struct MockTimer<'a> {
74 frequency: u32,
75 timer_values: &'a [u32],
76 value_index: Cell<usize>,
77 }
78
79 impl<'a> MockTimer<'a> {
80 pub fn new(frequency: u32, timer_values: &'a [u32]) -> Self {
81 Self {
82 frequency,
83 timer_values,
84 value_index: Cell::new(0),
85 }
86 }
87 }
88
89 impl<'a> Drop for MockTimer<'a> {
90 fn drop(&mut self) {
91 assert!(
92 self.timer_values.len() == self.value_index.get(),
93 "Not all timer values have been used: {:?}",
94 &self.timer_values[self.value_index.get()..]
95 );
96 }
97 }
98
99 impl<'a> TimerInterface for MockTimer<'a> {
100 fn enable(&mut self) {}
101
102 fn frequency(&self) -> u32 {
103 self.frequency
104 }
105
106 fn timer_value(&self) -> u32 {
107 let index = self.value_index.get();
108 self.value_index.update(|i| i + 1);
109
110 self.timer_values[index]
111 }
112 }
113
114 #[test]
115 fn wait() {
116 let mock = MockTimer::new(1000, &[7000, 5000, 3000, 2000]);
117
118 let timer = Timer::new(mock);
119 timer.wait(Duration::from_secs(5));
120 }
121
122 #[test]
123 fn wait_overflow() {
124 let mock = MockTimer::new(1000, &[2000, 1000, 2001]);
125
126 let timer = Timer::new(mock);
127 timer.wait(Duration::from_secs(u64::MAX));
128 }
129}