sparreal_kernel/time/
timer.rs1use core::{
2 sync::atomic::{Ordering, fence},
3 time::Duration,
4};
5
6use super::queue;
7use alloc::boxed::Box;
8use rdrive::timer::*;
9
10const NANO_PER_SEC: u128 = 1_000_000_000;
11
12pub struct Timer {
13 timer: HardwareCPU,
14 q: queue::Queue,
15}
16
17unsafe impl Sync for Timer {}
18unsafe impl Send for Timer {}
19
20impl Timer {
21 pub fn new(timer: HardwareCPU) -> Self {
22 Self {
23 timer,
24 q: queue::Queue::new(),
25 }
26 }
27
28 pub fn enable(&mut self) {
29 let _ = self.timer.open();
30 }
31
32 pub fn since_boot(&self) -> Duration {
33 self.tick_to_duration(self.timer.current_ticks())
34 }
35
36 pub fn after(&mut self, duration: Duration, callback: impl Fn() + 'static) {
37 let ticks = self.duration_to_tick(duration);
38
39 let event = queue::Event {
40 interval: None,
41 at_tick: self.timer.current_ticks() + ticks,
42 callback: Box::new(callback),
43 called: false,
44 };
45
46 self.add_event(event);
47 }
48
49 pub fn every(&mut self, duration: Duration, callback: impl Fn() + 'static) {
50 let ticks = self.duration_to_tick(duration);
51
52 let event = queue::Event {
53 interval: Some(ticks),
54 at_tick: self.timer.current_ticks() + ticks,
55 callback: Box::new(callback),
56 called: false,
57 };
58
59 self.add_event(event);
60 }
61
62 fn add_event(&mut self, event: queue::Event) {
63 self.timer.set_irq_enable(false);
64 fence(Ordering::SeqCst);
65
66 let next_tick = self.q.add_and_next_tick(event);
67 let v = next_tick - self.timer.current_ticks();
68 self.timer.set_timeval(v);
69
70 fence(Ordering::SeqCst);
71 self.timer.set_irq_enable(true);
72 }
73
74 pub fn handle_irq(&mut self) {
75 while let Some(event) = self.q.pop(self.timer.current_ticks()) {
76 (event.callback)();
77 }
78
79 match self.q.next_tick() {
80 Some(next_tick) => {
81 self.timer.set_timeval(next_tick);
82 }
83 None => {
84 self.timer.set_irq_enable(false);
85 }
86 }
87 }
88
89 pub fn set_irq_enable(&mut self, enable: bool) {
90 self.timer.set_irq_enable(enable);
91 }
92
93 fn tick_to_duration(&self, tick: u64) -> Duration {
94 Duration::from_nanos((tick as u128 * NANO_PER_SEC / self.timer.tick_hz() as u128) as _)
95 }
96
97 fn duration_to_tick(&self, duration: Duration) -> u64 {
98 (duration.as_nanos() * self.timer.tick_hz() as u128 / NANO_PER_SEC) as _
99 }
100
101 pub fn irq(&self) -> IrqConfig {
102 self.timer.irq()
103 }
104}