1use crate::peripherals::Timer;
16use crate::soc::ws63::SYSTEM_CLOCK_HZ;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum TimerMode {
21 OneShot = 0,
23 Periodic = 1,
25}
26
27pub struct TimerDriver<'d> {
29 _timer: Timer<'d>,
30}
31
32impl<'d> TimerDriver<'d> {
33 pub fn new(timer: Timer<'d>) -> Self {
35 Self { _timer: timer }
36 }
37
38 fn regs(&self) -> &'static ws63_pac::timer::RegisterBlock {
39 unsafe { &*Timer::ptr() }
41 }
42
43 pub fn configure(&self, n: usize, mode: TimerMode, load_value: u32) {
45 let r = self.regs();
46 match n {
47 0 => r.timer0_load_count(0).write(|w| unsafe { w.bits(load_value) }),
48 1 => r.timer0_load_count(1).write(|w| unsafe { w.bits(load_value) }),
49 2 => r.timer0_load_count(2).write(|w| unsafe { w.bits(load_value) }),
50 _ => unreachable!(),
51 };
52 let ctl = ((mode as u32) & 0x3) << 1;
53 match n {
54 0 => r.timer0_control(0).write(|w| unsafe { w.bits(ctl) }),
55 1 => r.timer0_control(1).write(|w| unsafe { w.bits(ctl) }),
56 2 => r.timer0_control(2).write(|w| unsafe { w.bits(ctl) }),
57 _ => unreachable!(),
58 };
59 }
60
61 pub fn enable(&self, n: usize) {
63 let r = self.regs();
64 let prev = match n {
65 0 => r.timer0_control(0).read().bits(),
66 1 => r.timer0_control(1).read().bits(),
67 2 => r.timer0_control(2).read().bits(),
68 _ => unreachable!(),
69 };
70 match n {
71 0 => r.timer0_control(0).write(|w| unsafe { w.bits(prev | 1) }),
72 1 => r.timer0_control(1).write(|w| unsafe { w.bits(prev | 1) }),
73 2 => r.timer0_control(2).write(|w| unsafe { w.bits(prev | 1) }),
74 _ => unreachable!(),
75 };
76 }
77
78 pub fn disable(&self, n: usize) {
80 let r = self.regs();
81 let prev = match n {
82 0 => r.timer0_control(0).read().bits(),
83 1 => r.timer0_control(1).read().bits(),
84 2 => r.timer0_control(2).read().bits(),
85 _ => unreachable!(),
86 };
87 match n {
88 0 => r.timer0_control(0).write(|w| unsafe { w.bits(prev & !1) }),
89 1 => r.timer0_control(1).write(|w| unsafe { w.bits(prev & !1) }),
90 2 => r.timer0_control(2).write(|w| unsafe { w.bits(prev & !1) }),
91 _ => unreachable!(),
92 };
93 }
94
95 pub fn current_value(&self, n: usize) -> u32 {
97 let r = self.regs();
98 match n {
99 0 => r.timer0_current_value(0).read().bits(),
100 1 => r.timer0_current_value(1).read().bits(),
101 2 => r.timer0_current_value(2).read().bits(),
102 _ => unreachable!(),
103 }
104 }
105
106 pub fn interrupt_pending(&self, n: usize) -> bool {
108 let r = self.regs();
109 match n {
110 0 => r.timer0_raw_intr(0).read().bits() & 1 != 0,
111 1 => r.timer0_raw_intr(1).read().bits() & 1 != 0,
112 2 => r.timer0_raw_intr(2).read().bits() & 1 != 0,
113 _ => unreachable!(),
114 }
115 }
116
117 pub fn clear_interrupt(&self, n: usize) {
119 let r = self.regs();
120 match n {
121 0 => {
122 let _ = r.timer0_eoi(0).read().bits();
123 }
124 1 => {
125 let _ = r.timer0_eoi(1).read().bits();
126 }
127 2 => {
128 let _ = r.timer0_eoi(2).read().bits();
129 }
130 _ => unreachable!(),
131 }
132 }
133
134 pub fn oneshot(&self, channel: usize) -> OneShotTimer<'_> {
136 OneShotTimer { driver: self, channel }
137 }
138
139 pub fn periodic(&self, channel: usize) -> PeriodicTimer<'_> {
141 PeriodicTimer { driver: self, channel }
142 }
143}
144
145pub struct OneShotTimer<'a> {
151 driver: &'a TimerDriver<'a>,
152 channel: usize,
153}
154
155impl OneShotTimer<'_> {
156 pub fn start(&mut self, count: u32) {
160 self.driver.configure(self.channel, TimerMode::OneShot, count);
161 self.driver.enable(self.channel);
162 }
163
164 pub fn start_micros(&mut self, us: u32) {
169 let ticks64 = SYSTEM_CLOCK_HZ as u64 * us as u64 / 1_000_000;
170 let ticks = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
172 self.start(ticks);
173 }
174
175 pub fn start_millis(&mut self, ms: u32) {
180 let ticks64 = SYSTEM_CLOCK_HZ as u64 * ms as u64 / 1_000;
181 let ticks = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
182 self.start(ticks);
183 }
184
185 pub fn expired(&self) -> bool {
187 self.driver.interrupt_pending(self.channel)
188 }
189
190 pub fn wait(&self) {
192 while !self.expired() {}
193 self.driver.clear_interrupt(self.channel);
194 }
195
196 pub fn current(&self) -> u32 {
198 self.driver.current_value(self.channel)
199 }
200
201 pub fn stop(&self) {
203 self.driver.disable(self.channel);
204 }
205
206 pub fn clear(&self) {
208 self.driver.clear_interrupt(self.channel);
209 }
210}
211
212impl embedded_hal::delay::DelayNs for OneShotTimer<'_> {
213 fn delay_ns(&mut self, ns: u32) {
214 let ticks64 = (SYSTEM_CLOCK_HZ as u64 * ns as u64) / 1_000_000_000;
215 let ticks = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
216 if ticks > 0 {
217 self.start(ticks);
218 self.wait();
219 }
220 }
221
222 fn delay_us(&mut self, us: u32) {
223 self.start_micros(us);
224 self.wait();
225 }
226
227 fn delay_ms(&mut self, ms: u32) {
228 self.start_millis(ms);
229 self.wait();
230 }
231}
232
233pub struct PeriodicTimer<'a> {
239 driver: &'a TimerDriver<'a>,
240 channel: usize,
241}
242
243impl PeriodicTimer<'_> {
244 pub fn start(&mut self, period: u32) {
246 self.driver.configure(self.channel, TimerMode::Periodic, period);
247 self.driver.enable(self.channel);
248 }
249
250 pub fn start_micros(&mut self, us: u32) {
252 let ticks64 = SYSTEM_CLOCK_HZ as u64 * us as u64 / 1_000_000;
253 let ticks = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
254 self.start(ticks);
255 }
256
257 pub fn tick_elapsed(&self) -> bool {
259 self.driver.interrupt_pending(self.channel)
260 }
261
262 pub fn wait_tick(&self) {
264 while !self.tick_elapsed() {}
265 self.driver.clear_interrupt(self.channel);
266 }
267
268 pub fn stop(&self) {
270 self.driver.disable(self.channel);
271 }
272
273 pub fn current(&self) -> u32 {
275 self.driver.current_value(self.channel)
276 }
277
278 pub fn clear_tick(&self) {
280 self.driver.clear_interrupt(self.channel);
281 }
282}
283
284#[cfg(test)]
287mod tests {
288 use super::*;
289
290 #[test]
291 fn test_oneshot_overflows_u32_clamps() {
292 let ticks64: u64 = 240_000_000u64 * 20_000_000u64 / 1_000_000;
295 let ticks = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
296 assert_eq!(ticks, u32::MAX);
297 }
298
299 #[test]
300 fn test_oneshot_small_value_does_not_clamp() {
301 let ticks64: u64 = 240_000_000u64 * 100u64 / 1_000_000;
303 assert_eq!(ticks64, 24_000);
304 let ticks = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
305 assert_eq!(ticks, 24_000);
306 }
307
308 #[test]
309 fn test_oneshot_max_safe_value() {
310 let max_safe_us: u32 = u32::MAX / 240;
312 let ticks64: u64 = 240_000_000u64 * max_safe_us as u64 / 1_000_000;
313 assert!(ticks64 <= u32::MAX as u64);
314 let ticks = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
315 assert_eq!(ticks, ticks64 as u32);
316 }
317
318 #[test]
319 fn test_periodic_clamping_matches_oneshot() {
320 let us: u32 = 20_000_000; let oneshot_ticks64: u64 = 240_000_000u64 * us as u64 / 1_000_000;
323 let periodic_ticks64: u64 = crate::soc::ws63::SYSTEM_CLOCK_HZ as u64 * us as u64 / 1_000_000;
324 assert_eq!(oneshot_ticks64, periodic_ticks64); let oneshot = if oneshot_ticks64 > u32::MAX as u64 { u32::MAX } else { oneshot_ticks64 as u32 };
326 let periodic = if periodic_ticks64 > u32::MAX as u64 { u32::MAX } else { periodic_ticks64 as u32 };
327 assert_eq!(oneshot, periodic);
328 assert_eq!(oneshot, u32::MAX);
329 }
330}
331
332#[cfg(test)]
335mod proptests {
336 use proptest::prelude::*;
337
338 proptest! {
339 #[test]
341 fn timer_ticks_never_panics(us in any::<u32>()) {
342 let ticks64: u64 = 240_000_000u64 * us as u64 / 1_000_000;
343 let ticks = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
344 let _ = ticks;
345 }
346
347 #[test]
349 fn timer_clamping_idempotent(us in any::<u32>()) {
350 let ticks64: u64 = 240_000_000u64 * us as u64 / 1_000_000;
351 let first = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
352 let second = if first as u64 > u32::MAX as u64 { u32::MAX } else { first };
353 prop_assert_eq!(first, second);
354 }
355
356 fn timer_safe_range_not_clamped(us in 0u32..17_895_697u32) {
358 let ticks64: u64 = 240_000_000u64 * us as u64 / 1_000_000;
359 prop_assert!(ticks64 <= u32::MAX as u64, "safe us={} produced ticks64={} > u32::MAX", us, ticks64);
360 }
361
362 fn timer_overflow_always_clamps(us in 17_895_698u32..u32::MAX) {
364 let ticks64: u64 = 240_000_000u64 * us as u64 / 1_000_000;
365 prop_assert!(ticks64 > u32::MAX as u64);
366 let ticks = if ticks64 > u32::MAX as u64 { u32::MAX } else { ticks64 as u32 };
367 prop_assert_eq!(ticks, u32::MAX);
368 }
369
370 #[test]
372 fn timer_both_formulas_equivalent(us in any::<u32>()) {
373 let oneshot: u64 = 240_000_000u64 * us as u64 / 1_000_000;
374 let periodic: u64 = crate::soc::ws63::SYSTEM_CLOCK_HZ as u64 * us as u64 / 1_000_000;
375 prop_assert_eq!(oneshot, periodic);
376 }
377 }
378}