Skip to main content

statime_wire/common/
clock_accuracy.rs

1use core::cmp::Ordering;
2
3#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5/// How accurate the underlying clock device is expected to be when not
6/// synchronized.
7pub enum ClockAccuracy {
8    /// Reserved
9    Reserved,
10    /// Accurate within 1 ps
11    PS1,
12    /// Accurate within 2.5 ps
13    PS2_5,
14    /// Accurate within 10 ps
15    PS10,
16    /// Accurate within 25 ps
17    PS25,
18    /// Accurate within 100 ps
19    PS100,
20    /// Accurate within 250 ps
21    PS250,
22    /// Accurate within 1 ns
23    NS1,
24    /// Accurate within 2.5 ns
25    NS2_5,
26    /// Accurate within 10 ns
27    NS10,
28    /// Accurate within 25 ns
29    NS25,
30    /// Accurate within 100 ns
31    NS100,
32    /// Accurate within 250 ns
33    NS250,
34    /// Accurate within 1 us
35    US1,
36    /// Accurate within 2.5 us
37    US2_5,
38    /// Accurate within 10 us
39    US10,
40    /// Accurate within 25 us
41    US25,
42    /// Accurate within 100 us
43    US100,
44    /// Accurate within 250 us
45    US250,
46    /// Accurate within 1 ms
47    MS1,
48    /// Accurate within 2.5 ms
49    MS2_5,
50    /// Accurate within 10 ms
51    MS10,
52    /// Accurate within 25 ms
53    MS25,
54    /// Accurate within 100 ms
55    MS100,
56    /// Accurate within 250 ms
57    MS250,
58    /// Accurate within 1 s
59    S1,
60    /// Accurate within 10 s
61    S10,
62    /// Accurate within >10 s
63    SGT10,
64    /// Specific to a profile
65    ProfileSpecific(u8),
66    /// Accuracy is unknown
67    #[default]
68    Unknown,
69}
70
71impl ClockAccuracy {
72    /// Convert the clock accuracy to its u8 primitive representation.
73    #[must_use]
74    pub fn to_primitive(self) -> u8 {
75        match self {
76            Self::Reserved => 0x00,
77            Self::PS1 => 0x17,
78            Self::PS2_5 => 0x18,
79            Self::PS10 => 0x19,
80            Self::PS25 => 0x1a,
81            Self::PS100 => 0x1b,
82            Self::PS250 => 0x1c,
83            Self::NS1 => 0x1d,
84            Self::NS2_5 => 0x1e,
85            Self::NS10 => 0x1f,
86            Self::NS25 => 0x20,
87            Self::NS100 => 0x21,
88            Self::NS250 => 0x22,
89            Self::US1 => 0x23,
90            Self::US2_5 => 0x24,
91            Self::US10 => 0x25,
92            Self::US25 => 0x26,
93            Self::US100 => 0x27,
94            Self::US250 => 0x28,
95            Self::MS1 => 0x29,
96            Self::MS2_5 => 0x2a,
97            Self::MS10 => 0x2b,
98            Self::MS25 => 0x2c,
99            Self::MS100 => 0x2d,
100            Self::MS250 => 0x2e,
101            Self::S1 => 0x2f,
102            Self::S10 => 0x30,
103            Self::SGT10 => 0x31,
104            Self::ProfileSpecific(value) => 0x80 + value,
105            Self::Unknown => 0xfe,
106        }
107    }
108
109    /// Convert a primitive representation of clock accuracy to `ClockAccuracy`.
110    #[must_use]
111    pub fn from_primitive(value: u8) -> Self {
112        match value {
113            0x00..=0x16 | 0x32..=0x7f | 0xff => Self::Reserved,
114            0x17 => Self::PS1,
115            0x18 => Self::PS2_5,
116            0x19 => Self::PS10,
117            0x1a => Self::PS25,
118            0x1b => Self::PS100,
119            0x1c => Self::PS250,
120            0x1d => Self::NS1,
121            0x1e => Self::NS2_5,
122            0x1f => Self::NS10,
123            0x20 => Self::NS25,
124            0x21 => Self::NS100,
125            0x22 => Self::NS250,
126            0x23 => Self::US1,
127            0x24 => Self::US2_5,
128            0x25 => Self::US10,
129            0x26 => Self::US25,
130            0x27 => Self::US100,
131            0x28 => Self::US250,
132            0x29 => Self::MS1,
133            0x2a => Self::MS2_5,
134            0x2b => Self::MS10,
135            0x2c => Self::MS25,
136            0x2d => Self::MS100,
137            0x2e => Self::MS250,
138            0x2f => Self::S1,
139            0x30 => Self::S10,
140            0x31 => Self::SGT10,
141            0x80..=0xfd => Self::ProfileSpecific(value - 0x80),
142            0xfe => ClockAccuracy::Unknown,
143        }
144    }
145}
146
147impl PartialOrd for ClockAccuracy {
148    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
149        Some(self.cmp(other))
150    }
151}
152
153impl Ord for ClockAccuracy {
154    fn cmp(&self, other: &Self) -> Ordering {
155        self.to_primitive().cmp(&other.to_primitive())
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162
163    #[test]
164    fn network_protocol_values() {
165        for i in 0..u8::MAX {
166            let protocol = ClockAccuracy::from_primitive(i);
167            if !matches!(protocol, ClockAccuracy::Reserved) {
168                assert_eq!(protocol.to_primitive(), i);
169            }
170        }
171
172        assert_eq!(ClockAccuracy::ProfileSpecific(5).to_primitive(), 0x85);
173    }
174
175    #[test]
176    fn ordering() {
177        // the inaccuracy of PS1 is less than of PS10
178        let a = ClockAccuracy::PS1;
179        let b = ClockAccuracy::PS10;
180
181        assert_eq!(a.cmp(&b), Ordering::Less);
182    }
183}