autd3_driver/firmware/driver/
strategy.rs

1use std::time::{Duration, Instant};
2
3use autd3_core::sleep::Sleep;
4
5/// A trait for timer strategies.
6pub trait TimerStrategy<S: Sleep> {
7    /// Returns the initial instant.
8    fn initial(&self) -> Instant;
9    /// Sleep until the specified time.
10    /// The first call receives the return value of [`TimerStrategy::initial`] as `old`, and subsequent calls receive the previous return value.
11    fn sleep(&self, old: Instant, interval: Duration) -> Instant;
12}
13
14/// [`FixedSchedule`] prioritize average behavior for the transmission timing. That is, not the interval from the previous transmission, but ensuring that T/interval transmissions are performed in a sufficiently long time T.
15/// For example, if the interval is 1ms and it takes 1.5ms to transmit due to some reason, the next transmission will be performed not 1ms later but 0.5ms later.
16pub struct FixedSchedule<S>(pub S);
17
18impl<S: Sleep> TimerStrategy<S> for FixedSchedule<S> {
19    fn initial(&self) -> Instant {
20        Instant::now()
21    }
22
23    fn sleep(&self, old: Instant, interval: Duration) -> Instant {
24        let new = old + interval;
25        self.0.sleep(new.saturating_duration_since(Instant::now()));
26        new
27    }
28}
29
30impl Default for FixedSchedule<autd3_core::sleep::SpinSleeper> {
31    fn default() -> Self {
32        Self(autd3_core::sleep::SpinSleeper::default())
33    }
34}
35
36/// [`FixedDelay`] prioritize the delay from the previous transmission. That is, it sleeps for the specified interval regardless of the time taken for the previous transmission.
37pub struct FixedDelay<S>(pub S);
38
39impl<S: Sleep> TimerStrategy<S> for FixedDelay<S> {
40    fn initial(&self) -> Instant {
41        Instant::now()
42    }
43
44    fn sleep(&self, old: Instant, interval: Duration) -> Instant {
45        self.0.sleep(interval);
46        old
47    }
48}
49
50// GRCOV_EXCL_START
51impl<S: Sleep> TimerStrategy<S> for Box<dyn TimerStrategy<S>> {
52    fn initial(&self) -> Instant {
53        self.as_ref().initial()
54    }
55
56    fn sleep(&self, old: Instant, interval: Duration) -> Instant {
57        self.as_ref().sleep(old, interval)
58    }
59}
60// GRCOV_EXCL_STOP
61
62#[cfg(test)]
63mod tests {
64    use std::{cell::RefCell, rc::Rc};
65
66    use derive_more::Debug;
67
68    use super::*;
69
70    #[derive(Debug)]
71    struct DebugSleep {
72        sleep: Rc<RefCell<Vec<Duration>>>,
73    }
74
75    impl Sleep for DebugSleep {
76        fn sleep(&self, duration: Duration) {
77            self.sleep.borrow_mut().push(duration);
78        }
79    }
80
81    #[test]
82    fn fixed_schedule_test() {
83        let sleep = Rc::new(RefCell::new(Vec::new()));
84
85        let strategy = FixedSchedule(DebugSleep { sleep });
86
87        let start = strategy.initial();
88        let interval = Duration::from_millis(1);
89
90        let next = strategy.sleep(start, interval);
91        assert_eq!(next, start + interval);
92
93        let next = strategy.sleep(next, interval);
94        assert_eq!(next, start + interval * 2);
95    }
96
97    #[test]
98    fn fixed_delay_test() {
99        let sleep = Rc::new(RefCell::new(Vec::new()));
100
101        let strategy = FixedDelay(DebugSleep {
102            sleep: sleep.clone(),
103        });
104
105        let start = strategy.initial();
106        let interval = Duration::from_millis(1);
107
108        let next = strategy.sleep(start, interval);
109        assert_eq!(next, start);
110
111        let next = strategy.sleep(start, interval);
112        assert_eq!(next, start);
113
114        assert_eq!(*sleep.borrow(), vec![interval, interval]);
115    }
116}