timeout_trait/
tick_impl.rs1use super::prelude::*;
2use core::marker::PhantomData;
3
4#[derive(Default)]
5pub struct TickTimeoutNs<T> {
6 _t: PhantomData<T>,
7}
8
9impl<T> TickTimeoutNs<T>
10where
11 T: TickInstant,
12{
13 pub const fn new() -> Self {
14 Self { _t: PhantomData }
15 }
16}
17
18impl<T> TimeoutNs for TickTimeoutNs<T>
19where
20 T: TickInstant,
21{
22 type TimeoutState = TickTimeoutState<T>;
23
24 #[inline]
25 fn start_ns(&self, timeout: u32) -> Self::TimeoutState {
26 TickTimeoutState::<T>::new_ns(timeout)
27 }
28
29 #[inline]
30 fn start_us(&self, timeout: u32) -> Self::TimeoutState {
31 TickTimeoutState::<T>::new_us(timeout)
32 }
33
34 #[inline]
35 fn start_ms(&self, timeout: u32) -> Self::TimeoutState {
36 TickTimeoutState::<T>::new_ms(timeout)
37 }
38}
39
40pub struct TickTimeoutState<T: TickInstant> {
41 tick: T,
42 timeout_tick: u32,
43 elapsed_tick: u32,
44 round: u32,
45 elapsed_round: u32,
46}
47
48impl<T> TickTimeoutState<T>
49where
50 T: TickInstant,
51{
52 pub fn new_ns(timeout: u32) -> Self {
53 let ns = timeout as u64;
54 let timeout_tick = (ns * T::frequency().to_kHz() as u64).div_ceil(1_000_000);
55 Self::new(timeout_tick)
56 }
57
58 pub fn new_us(timeout: u32) -> Self {
59 let us = timeout as u64;
60 let timeout_tick = (us * T::frequency().to_kHz() as u64).div_ceil(1_000);
61 Self::new(timeout_tick)
62 }
63
64 pub fn new_ms(timeout: u32) -> Self {
65 let ms = timeout as u64;
66 let frequency = T::frequency().to_kHz() as u64;
67 let timeout_tick = ms * frequency;
68 Self::new(timeout_tick)
69 }
70
71 fn new(mut timeout_tick: u64) -> Self {
72 let mut round = 1;
73 while timeout_tick > (u32::MAX >> 1) as u64 {
74 if (timeout_tick | 1) == 1 {
75 timeout_tick += 0b10;
76 }
77 timeout_tick >>= 1;
78 round <<= 1;
79 }
80
81 Self {
82 tick: T::now(),
83 timeout_tick: timeout_tick as u32,
84 elapsed_tick: 0,
85 round,
86 elapsed_round: 0,
87 }
88 }
89}
90
91impl<T> TimeoutState for TickTimeoutState<T>
92where
93 T: TickInstant,
94{
95 #[inline]
97 fn timeout(&mut self) -> bool {
98 let now = T::now();
99 self.elapsed_tick = self.elapsed_tick.saturating_add(now.tick_since(self.tick));
100 self.tick = now;
101
102 if self.elapsed_tick >= self.timeout_tick {
103 self.elapsed_tick -= self.timeout_tick;
104 self.elapsed_round += 1;
105 if self.elapsed_round >= self.round {
106 self.elapsed_round -= self.round;
107 return true;
108 }
109 }
110 false
111 }
112
113 #[inline(always)]
114 fn restart(&mut self) {
115 self.tick = T::now();
116 self.elapsed_tick = 0;
117 self.elapsed_round = 0;
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use core::cell::Cell;
125 use fugit::{ExtU32, KilohertzU32, NanosDurationU32, RateExtU32};
126
127 static TICK_SOURCE: critical_section::Mutex<Cell<u32>> =
128 critical_section::Mutex::new(Cell::new(0));
129
130 #[derive(Clone, Copy)]
131 pub struct MockInstant {
132 tick: u32,
133 }
134
135 impl MockInstant {
136 fn add_time(t: NanosDurationU32) {
137 let tick = t.to_nanos();
138 critical_section::with(|cs| {
139 let v = TICK_SOURCE.borrow(cs).get().wrapping_add(tick);
140 TICK_SOURCE.borrow(cs).set(v);
141 })
142 }
143 }
144
145 impl TickInstant for MockInstant {
146 fn frequency() -> KilohertzU32 {
147 1000.MHz()
148 }
149
150 fn now() -> Self {
151 critical_section::with(|cs| Self {
152 tick: TICK_SOURCE.borrow(cs).get(),
153 })
154 }
155
156 fn tick_since(self, earlier: Self) -> u32 {
157 self.tick.wrapping_sub(earlier.tick)
158 }
159 }
160
161 #[test]
162 fn tick_timeout() {
163 let now = MockInstant::now();
164 assert_eq!(now.tick_elapsed(), 0);
165 MockInstant::add_time(10.nanos());
166 assert_eq!(now.tick_elapsed(), 10);
167 MockInstant::add_time(1.millis());
168 assert_eq!(now.tick_elapsed(), 1_000_010);
169 MockInstant::add_time(10.micros());
170 let now2 = MockInstant::now();
171 assert_eq!(now2.tick_since(now), 1_010_010);
172 MockInstant::add_time(10.micros());
173 let now3 = MockInstant::now();
174 assert_eq!(now3.tick_since(now2), 10_000);
175
176 let mut t = TickTimeoutNs::<MockInstant>::new().start_ns(100);
177 assert!(!t.timeout());
178 MockInstant::add_time(10.nanos());
179 assert!(!t.timeout());
180 MockInstant::add_time(90.nanos());
181 assert!(t.timeout());
182 assert!(!t.timeout());
183 MockInstant::add_time(100.nanos());
184 assert!(t.timeout());
185
186 MockInstant::add_time(90.nanos());
187 assert!(!t.timeout());
188 t.restart();
189 MockInstant::add_time(90.nanos());
190 assert!(!t.timeout());
191 MockInstant::add_time(10.nanos());
192 assert!(t.timeout());
193
194 let mut t = TickTimeoutNs::<MockInstant>::new().start_us(100);
195 assert!(!t.timeout());
196 MockInstant::add_time(10.micros());
197 assert!(!t.timeout());
198 MockInstant::add_time(90.micros());
199 assert!(t.timeout());
200 assert!(!t.timeout());
201 MockInstant::add_time(100.micros());
202 assert!(t.timeout());
203
204 MockInstant::add_time(90.micros());
205 assert!(!t.timeout());
206 t.restart();
207 MockInstant::add_time(90.micros());
208 assert!(!t.timeout());
209 MockInstant::add_time(10.micros());
210 assert!(t.timeout());
211
212 let mut t = TickTimeoutNs::<MockInstant>::new().start_ms(100);
213 assert!(!t.timeout());
214 MockInstant::add_time(10.millis());
215 assert!(!t.timeout());
216 MockInstant::add_time(90.millis());
217 assert!(t.timeout());
218 assert!(!t.timeout());
219 MockInstant::add_time(100.millis());
220 assert!(t.timeout());
221
222 MockInstant::add_time(90.millis());
223 assert!(!t.timeout());
224 t.restart();
225 MockInstant::add_time(90.millis());
226 assert!(!t.timeout());
227 MockInstant::add_time(10.millis());
228 assert!(t.timeout());
229
230 let mut count = 0;
231 let t = TickTimeoutNs::<MockInstant>::new();
232 assert!(t.ns_with(100, || {
233 MockInstant::add_time(10.nanos());
234 count += 1;
235 true
236 }));
237 assert_eq!(count, 10);
238
239 let t = TickTimeoutState::<MockInstant>::new_us(40_000_000);
240 assert_eq!(t.round, 32);
241 assert_eq!(t.timeout_tick, 1_250_000_000);
242
243 let mut t = TickTimeoutState::<MockInstant>::new_ms(40_000);
244 assert_eq!(t.round, 32);
245 assert_eq!(t.timeout_tick, 1_250_000_000);
246
247 assert!(!t.timeout());
248
249 for _ in 0..40 {
250 MockInstant::add_time(999.millis());
251 assert!(!t.timeout());
252 }
253 assert_eq!(t.elapsed_round, 31);
254 assert!(t.elapsed_tick > 0);
255 MockInstant::add_time(100.millis());
256 assert!(t.timeout());
257 assert_eq!(t.elapsed_round, 0);
258 assert!(!t.timeout());
259
260 for _ in 0..39 {
261 MockInstant::add_time(999.millis());
262 assert!(!t.timeout());
263 }
264 t.restart();
265 for _ in 0..40 {
266 MockInstant::add_time(999.millis());
267 assert!(!t.timeout());
268 }
269 MockInstant::add_time(100.millis());
270 assert!(t.timeout());
271 }
272}
273
274#[cfg(test)]
275mod tests_fugit {
276 use core::ops::Div;
277 use fugit::{
278 ExtU32, ExtU32Ceil, KilohertzU32, MicrosDurationU32, MillisDurationU32, RateExtU32,
279 };
280
281 #[test]
282 fn duration_tick() {
283 assert_eq!(1 / 1000, 0);
284 assert_eq!(1_u32.div(1000), 0);
285 assert_eq!(1_u32.div_ceil(1000), 1);
286
287 let dur: MicrosDurationU32 = 1.micros();
288 assert_eq!(dur.ticks(), 1);
289
290 let dur: MicrosDurationU32 = 1.millis();
291 assert_eq!(dur.ticks(), 1000);
292 assert_eq!(dur.to_millis(), 1);
293
294 let dur: MillisDurationU32 = 1.millis();
295 assert_eq!(dur.ticks(), 1);
296 assert_eq!(dur.to_micros(), 1000);
297
298 let dur: MillisDurationU32 = 1.micros();
299 assert_eq!(dur.ticks(), 0);
300
301 let dur: MillisDurationU32 = 1.micros_at_least();
302 assert_eq!(dur.ticks(), 1);
303
304 let dur: MicrosDurationU32 = 1.micros();
305 assert_eq!(dur.to_millis(), 0);
306 let dur: MillisDurationU32 = dur.ticks().micros_at_least();
307 assert_eq!(dur.ticks(), 1);
308 }
309
310 #[test]
311 fn rate_tick() {
312 let r: KilohertzU32 = 1.MHz();
313 assert_eq!(r.raw(), 1_000);
314 let f: u32 = r.to_Hz();
315 assert_eq!(f, 1_000_000);
316 }
317}