embedded_charts/
time.rs

1//! Time abstraction layer for animation systems.
2//!
3//! This module provides a time abstraction that works in both std and no_std environments.
4//! It allows the animation system to work with different timer sources while maintaining
5//! a consistent API.
6
7/// Time value in milliseconds.
8pub type Milliseconds = u32;
9
10/// Time value in microseconds.
11pub type Microseconds = u64;
12
13/// Trait for providing time information to the animation system.
14///
15/// This trait abstracts time operations to support both std and no_std environments.
16/// Implementations can use system clocks, hardware timers, or external time sources.
17pub trait TimeProvider {
18    /// Get the current time in milliseconds since some reference point.
19    ///
20    /// The reference point doesn't matter as long as it's consistent.
21    /// This is typically used for calculating elapsed time between calls.
22    fn current_time_ms(&self) -> Milliseconds;
23
24    /// Get the current time in microseconds since some reference point.
25    ///
26    /// This provides higher precision timing for fine-grained animations.
27    /// The reference point should be the same as `current_time_ms()`.
28    fn current_time_us(&self) -> Microseconds;
29
30    /// Calculate elapsed time in milliseconds since the last call.
31    ///
32    /// This is a convenience method that handles the delta calculation.
33    /// The implementation should track the last time internally.
34    fn elapsed_ms(&mut self) -> Milliseconds {
35        let current = self.current_time_ms();
36        let last = self.last_time_ms();
37        self.update_last_time_ms(current);
38        current.saturating_sub(last)
39    }
40
41    /// Calculate elapsed time in microseconds since the last call.
42    ///
43    /// This is a convenience method that handles the delta calculation.
44    /// The implementation should track the last time internally.
45    fn elapsed_us(&mut self) -> Microseconds {
46        let current = self.current_time_us();
47        let last = self.last_time_us();
48        self.update_last_time_us(current);
49        current.saturating_sub(last)
50    }
51
52    /// Get the last recorded time in milliseconds.
53    ///
54    /// This is used internally by `elapsed_ms()`.
55    fn last_time_ms(&self) -> Milliseconds;
56
57    /// Get the last recorded time in microseconds.
58    ///
59    /// This is used internally by `elapsed_us()`.
60    fn last_time_us(&self) -> Microseconds;
61
62    /// Update the last recorded time in milliseconds.
63    ///
64    /// This is used internally by `elapsed_ms()`.
65    fn update_last_time_ms(&mut self, time: Milliseconds);
66
67    /// Update the last recorded time in microseconds.
68    ///
69    /// This is used internally by `elapsed_us()`.
70    fn update_last_time_us(&mut self, time: Microseconds);
71
72    /// Reset the time provider to start fresh timing.
73    ///
74    /// This resets any internal state and starts timing from the current moment.
75    fn reset(&mut self) {
76        let current_ms = self.current_time_ms();
77        let current_us = self.current_time_us();
78        self.update_last_time_ms(current_ms);
79        self.update_last_time_us(current_us);
80    }
81}
82
83/// A monotonic time provider for no_std environments.
84///
85/// This implementation uses a user-provided timer function to get the current time.
86/// It's designed to work with hardware timers or other monotonic time sources.
87#[derive(Debug)]
88pub struct MonotonicTimeProvider<F>
89where
90    F: Fn() -> Microseconds,
91{
92    /// Function to get current time in microseconds.
93    timer_fn: F,
94    /// Last recorded time in milliseconds.
95    last_ms: Milliseconds,
96    /// Last recorded time in microseconds.
97    last_us: Microseconds,
98}
99
100impl<F> MonotonicTimeProvider<F>
101where
102    F: Fn() -> Microseconds,
103{
104    /// Create a new monotonic time provider with the given timer function.
105    ///
106    /// The timer function should return the current time in microseconds
107    /// from a monotonic source (e.g., hardware timer, system tick counter).
108    ///
109    /// # Example
110    ///
111    /// ```rust,no_run
112    /// use embedded_charts::time::MonotonicTimeProvider;
113    ///
114    /// // Example with a hypothetical hardware timer
115    /// fn hardware_timer_get_us() -> u64 {
116    ///     // Mock implementation - in real use, this would read from hardware
117    ///     1000
118    /// }
119    ///
120    /// let timer = MonotonicTimeProvider::new(|| {
121    ///     // Get microseconds from hardware timer
122    ///     hardware_timer_get_us()
123    /// });
124    /// ```
125    pub fn new(timer_fn: F) -> Self {
126        let current_us = timer_fn();
127        Self {
128            timer_fn,
129            last_ms: (current_us / 1000) as Milliseconds,
130            last_us: current_us,
131        }
132    }
133
134    /// Create a new monotonic time provider with a tick-based timer.
135    ///
136    /// This is useful when you have a timer that increments at a known frequency.
137    ///
138    /// # Arguments
139    ///
140    /// * `get_ticks` - Function that returns the current tick count
141    /// * `ticks_per_second` - Number of ticks per second (timer frequency)
142    ///
143    /// # Example
144    ///
145    /// ```rust,no_run
146    /// use embedded_charts::time::{MonotonicTimeProvider, Microseconds};
147    ///
148    /// // Mock hardware timer function
149    /// fn hardware_timer_get_ticks() -> u64 {
150    ///     // Mock implementation - in real use, this would read from hardware
151    ///     1000
152    /// }
153    ///
154    /// // Example with a 1MHz timer (1,000,000 ticks per second)
155    /// // let get_ticks = || hardware_timer_get_ticks();
156    /// // let timer = MonotonicTimeProvider::from_ticks(get_ticks, 1_000_000);
157    ///
158    /// // Use the timer to get current time
159    /// // let current_time = timer.now();
160    /// ```
161    pub fn from_ticks<G>(
162        get_ticks: G,
163        ticks_per_second: u32,
164    ) -> MonotonicTimeProvider<impl Fn() -> Microseconds>
165    where
166        G: Fn() -> u64,
167    {
168        let timer_fn = move || {
169            let ticks = get_ticks();
170            // Convert ticks to microseconds
171            (ticks * 1_000_000) / ticks_per_second as u64
172        };
173
174        let current_us = timer_fn();
175        MonotonicTimeProvider {
176            timer_fn,
177            last_ms: (current_us / 1000) as Milliseconds,
178            last_us: current_us,
179        }
180    }
181}
182
183impl<F> TimeProvider for MonotonicTimeProvider<F>
184where
185    F: Fn() -> Microseconds,
186{
187    fn current_time_ms(&self) -> Milliseconds {
188        ((self.timer_fn)() / 1000) as Milliseconds
189    }
190
191    fn current_time_us(&self) -> Microseconds {
192        (self.timer_fn)()
193    }
194
195    fn last_time_ms(&self) -> Milliseconds {
196        self.last_ms
197    }
198
199    fn last_time_us(&self) -> Microseconds {
200        self.last_us
201    }
202
203    fn update_last_time_ms(&mut self, time: Milliseconds) {
204        self.last_ms = time;
205    }
206
207    fn update_last_time_us(&mut self, time: Microseconds) {
208        self.last_us = time;
209    }
210}
211
212/// A simple time provider for testing and simulation.
213///
214/// This provider allows manual control of time, useful for testing animations
215/// or when you want to control timing externally.
216#[derive(Debug, Clone)]
217pub struct ManualTimeProvider {
218    /// Current time in microseconds.
219    current_us: Microseconds,
220    /// Last recorded time in milliseconds.
221    last_ms: Milliseconds,
222    /// Last recorded time in microseconds.
223    last_us: Microseconds,
224}
225
226impl ManualTimeProvider {
227    /// Create a new manual time provider starting at time zero.
228    pub fn new() -> Self {
229        Self {
230            current_us: 0,
231            last_ms: 0,
232            last_us: 0,
233        }
234    }
235
236    /// Create a new manual time provider starting at the specified time.
237    pub fn with_start_time(start_us: Microseconds) -> Self {
238        Self {
239            current_us: start_us,
240            last_ms: (start_us / 1000) as Milliseconds,
241            last_us: start_us,
242        }
243    }
244
245    /// Advance time by the specified number of milliseconds.
246    pub fn advance_ms(&mut self, delta_ms: Milliseconds) {
247        self.current_us += (delta_ms as Microseconds) * 1000;
248    }
249
250    /// Advance time by the specified number of microseconds.
251    pub fn advance_us(&mut self, delta_us: Microseconds) {
252        self.current_us += delta_us;
253    }
254
255    /// Set the current time to the specified value in microseconds.
256    pub fn set_time_us(&mut self, time_us: Microseconds) {
257        self.current_us = time_us;
258    }
259
260    /// Set the current time to the specified value in milliseconds.
261    pub fn set_time_ms(&mut self, time_ms: Milliseconds) {
262        self.current_us = (time_ms as Microseconds) * 1000;
263    }
264}
265
266impl Default for ManualTimeProvider {
267    fn default() -> Self {
268        Self::new()
269    }
270}
271
272impl TimeProvider for ManualTimeProvider {
273    fn current_time_ms(&self) -> Milliseconds {
274        (self.current_us / 1000) as Milliseconds
275    }
276
277    fn current_time_us(&self) -> Microseconds {
278        self.current_us
279    }
280
281    fn last_time_ms(&self) -> Milliseconds {
282        self.last_ms
283    }
284
285    fn last_time_us(&self) -> Microseconds {
286        self.last_us
287    }
288
289    fn update_last_time_ms(&mut self, time: Milliseconds) {
290        self.last_ms = time;
291    }
292
293    fn update_last_time_us(&mut self, time: Microseconds) {
294        self.last_us = time;
295    }
296}
297
298/// Standard library time provider using `std::time::Instant`.
299///
300/// This provider uses the system's monotonic clock and is only available
301/// when the `std` feature is enabled.
302#[cfg(feature = "std")]
303#[derive(Debug)]
304pub struct StdTimeProvider {
305    /// Reference point for time calculations.
306    start_time: std::time::Instant,
307    /// Last recorded time in milliseconds.
308    last_ms: Milliseconds,
309    /// Last recorded time in microseconds.
310    last_us: Microseconds,
311}
312
313#[cfg(feature = "std")]
314impl StdTimeProvider {
315    /// Create a new standard library time provider.
316    pub fn new() -> Self {
317        let now = std::time::Instant::now();
318        Self {
319            start_time: now,
320            last_ms: 0,
321            last_us: 0,
322        }
323    }
324}
325
326#[cfg(feature = "std")]
327impl Default for StdTimeProvider {
328    fn default() -> Self {
329        Self::new()
330    }
331}
332
333#[cfg(feature = "std")]
334impl TimeProvider for StdTimeProvider {
335    fn current_time_ms(&self) -> Milliseconds {
336        self.start_time.elapsed().as_millis() as Milliseconds
337    }
338
339    fn current_time_us(&self) -> Microseconds {
340        self.start_time.elapsed().as_micros() as Microseconds
341    }
342
343    fn last_time_ms(&self) -> Milliseconds {
344        self.last_ms
345    }
346
347    fn last_time_us(&self) -> Microseconds {
348        self.last_us
349    }
350
351    fn update_last_time_ms(&mut self, time: Milliseconds) {
352        self.last_ms = time;
353    }
354
355    fn update_last_time_us(&mut self, time: Microseconds) {
356        self.last_us = time;
357    }
358}
359
360#[cfg(test)]
361mod tests {
362    use super::*;
363
364    #[test]
365    fn test_manual_time_provider() {
366        let mut provider = ManualTimeProvider::new();
367
368        assert_eq!(provider.current_time_ms(), 0);
369        assert_eq!(provider.current_time_us(), 0);
370
371        provider.advance_ms(100);
372        assert_eq!(provider.current_time_ms(), 100);
373        assert_eq!(provider.current_time_us(), 100_000);
374
375        provider.advance_us(500);
376        assert_eq!(provider.current_time_ms(), 100);
377        assert_eq!(provider.current_time_us(), 100_500);
378    }
379
380    #[test]
381    fn test_manual_time_provider_elapsed() {
382        let mut provider = ManualTimeProvider::new();
383
384        // First call should return 0 (no time has passed)
385        assert_eq!(provider.elapsed_ms(), 0);
386
387        provider.advance_ms(50);
388        assert_eq!(provider.elapsed_ms(), 50);
389
390        provider.advance_ms(25);
391        assert_eq!(provider.elapsed_ms(), 25);
392    }
393
394    #[test]
395    fn test_monotonic_time_provider() {
396        use core::cell::RefCell;
397
398        let counter = RefCell::new(0u64);
399        let timer_fn = || {
400            let mut c = counter.borrow_mut();
401            *c += 1000; // Advance by 1ms each call
402            *c
403        };
404
405        let provider = MonotonicTimeProvider::new(timer_fn);
406
407        let first_time = provider.current_time_us();
408        let second_time = provider.current_time_us();
409
410        assert!(second_time > first_time);
411        assert_eq!(second_time - first_time, 1000); // 1ms difference
412    }
413
414    // #[test]
415    // fn test_monotonic_time_provider_from_ticks() {
416    //     // TODO: Fix type inference issues with closure types
417    //     // This test is temporarily disabled due to complex type inference
418    // }
419
420    #[cfg(feature = "std")]
421    #[test]
422    fn test_std_time_provider() {
423        let provider = StdTimeProvider::new();
424
425        let first_time = provider.current_time_ms();
426        std::thread::sleep(std::time::Duration::from_millis(10));
427        let second_time = provider.current_time_ms();
428
429        assert!(second_time >= first_time + 10);
430    }
431
432    #[test]
433    fn test_time_provider_reset() {
434        let mut provider = ManualTimeProvider::new();
435
436        provider.advance_ms(100);
437        let _ = provider.elapsed_ms(); // This should be 100
438
439        provider.advance_ms(50);
440        provider.reset();
441
442        provider.advance_ms(25);
443        let elapsed = provider.elapsed_ms();
444
445        assert_eq!(elapsed, 25); // Should only count from reset point
446    }
447}