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