statime/
overlay_clock.rs

1use crate::{
2    time::{Duration, Time},
3    Clock,
4};
5
6/// An overlay over other, read-only clock, frequency-locked to it.
7/// In other words, a virtual clock which can be tuned in software without
8/// affecting the underlying system or hardware clock.
9#[derive(Debug)]
10pub struct OverlayClock<C: Clock> {
11    roclock: C,
12    last_sync: Time,
13    shift: Duration,
14    freq_scale_ppm_diff: f64,
15}
16
17impl<C: Clock> OverlayClock<C> {
18    /// Creates new OverlayClock based on given clock
19    pub fn new(underlying_clock: C) -> Self {
20        let now = underlying_clock.now();
21        Self {
22            roclock: underlying_clock,
23            last_sync: now,
24            shift: Duration::from_fixed_nanos(0),
25            freq_scale_ppm_diff: 0.0,
26        }
27    }
28
29    /// Converts (shifts and scales) `Time` in underlying clock's timescale to
30    /// overlay clock timescale
31    pub fn time_from_underlying(&self, roclock_time: Time) -> Time {
32        let elapsed = roclock_time - self.last_sync;
33        let corr = elapsed * self.freq_scale_ppm_diff / 1_000_000;
34
35        roclock_time + self.shift + corr
36        // equals self.last_sync + self.shift + elapsed + corr
37    }
38
39    /// Returns reference to underlying clock
40    pub fn underlying(&self) -> &C {
41        &self.roclock
42    }
43}
44
45impl<C: Clock> Clock for OverlayClock<C> {
46    type Error = C::Error;
47    fn now(&self) -> Time {
48        self.time_from_underlying(self.roclock.now())
49    }
50    fn set_frequency(&mut self, ppm: f64) -> Result<Time, Self::Error> {
51        // save current shift:
52        let now_roclock = self.roclock.now();
53        let now_local = self.time_from_underlying(now_roclock);
54        self.shift = now_local - now_roclock;
55        self.last_sync = now_roclock;
56
57        self.freq_scale_ppm_diff = ppm;
58        debug_assert_eq!(self.time_from_underlying(self.last_sync), now_local);
59        Ok(now_local)
60    }
61    fn step_clock(&mut self, offset: Duration) -> Result<Time, Self::Error> {
62        self.last_sync = self.roclock.now();
63        let multiplier = 1_000_000f64 + self.freq_scale_ppm_diff;
64        let reciprocal = 1_000_000f64 / multiplier;
65        self.shift += offset * reciprocal;
66        Ok(self.time_from_underlying(self.last_sync))
67    }
68    fn set_properties(
69        &mut self,
70        _time_properties_ds: &crate::config::TimePropertiesDS,
71    ) -> Result<(), Self::Error> {
72        // we can ignore the properies - they are just metadata
73        Ok(())
74    }
75}