#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ClockdriftLevel {
None,
Probable,
Verified,
}
#[derive(Debug)]
pub(crate) struct ClockdriftDetector {
delay_history: [i32; 3],
level: ClockdriftLevel,
stability_counter: usize,
}
impl ClockdriftDetector {
pub(crate) fn new() -> Self {
Self {
delay_history: [0; 3],
level: ClockdriftLevel::None,
stability_counter: 0,
}
}
pub(crate) fn update(&mut self, delay_estimate: i32) {
if delay_estimate == self.delay_history[0] {
self.stability_counter += 1;
if self.stability_counter > 7500 {
self.level = ClockdriftLevel::None;
}
return;
}
self.stability_counter = 0;
let d1 = self.delay_history[0] - delay_estimate;
let d2 = self.delay_history[1] - delay_estimate;
let d3 = self.delay_history[2] - delay_estimate;
let probable_drift_up = (d1 == -1 && d2 == -2) || (d1 == -2 && d2 == -1);
let drift_up = probable_drift_up && d3 == -3;
let probable_drift_down = (d1 == 1 && d2 == 2) || (d1 == 2 && d2 == 1);
let drift_down = probable_drift_down && d3 == 3;
if drift_up || drift_down {
self.level = ClockdriftLevel::Verified;
} else if (probable_drift_up || probable_drift_down) && self.level == ClockdriftLevel::None
{
self.level = ClockdriftLevel::Probable;
}
self.delay_history[2] = self.delay_history[1];
self.delay_history[1] = self.delay_history[0];
self.delay_history[0] = delay_estimate;
}
pub(crate) fn clockdrift_level(&self) -> ClockdriftLevel {
self.level
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clockdrift_detector() {
let mut c = ClockdriftDetector::new();
assert_eq!(c.clockdrift_level(), ClockdriftLevel::None);
for _ in 0..100 {
c.update(1000);
}
assert_eq!(c.clockdrift_level(), ClockdriftLevel::None);
for _ in 0..100 {
c.update(1001);
}
assert_eq!(c.clockdrift_level(), ClockdriftLevel::None);
for _ in 0..100 {
c.update(1002);
}
assert_eq!(c.clockdrift_level(), ClockdriftLevel::Probable);
for _ in 0..100 {
c.update(1003);
}
assert_eq!(c.clockdrift_level(), ClockdriftLevel::Verified);
for _ in 0..10000 {
c.update(1003);
}
assert_eq!(c.clockdrift_level(), ClockdriftLevel::None);
for _ in 0..100 {
c.update(1001);
}
for _ in 0..100 {
c.update(999);
}
assert_eq!(c.clockdrift_level(), ClockdriftLevel::Probable);
for _ in 0..100 {
c.update(1000);
}
for _ in 0..100 {
c.update(998);
}
assert_eq!(c.clockdrift_level(), ClockdriftLevel::Verified);
}
}