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