stm32_eth/ptp/
subseconds.rs1pub const NANOS_PER_SECOND: u32 = 1_000_000_000;
3
4pub const SUBSECONDS_PER_SECOND: u32 = 0x7FFF_FFFF;
6
7pub const SUBSECONDS_TO_SECONDS: f32 = 1.0 / (SUBSECONDS_PER_SECOND as f32);
9
10const NS_PER_S: u64 = NANOS_PER_SECOND as u64;
11const SUBS_PER_S: u64 = SUBSECONDS_PER_SECOND as u64;
12
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
16pub struct Subseconds(u32);
17
18impl Subseconds {
19 pub const MAX_VALUE: u32 = SUBSECONDS_PER_SECOND;
21
22 pub const MAX: Self = Self(SUBSECONDS_PER_SECOND);
24
25 pub const ZERO: Self = Self(0);
27
28 pub const fn new(value: u32) -> Option<Self> {
38 if value > SUBSECONDS_PER_SECOND as u32 {
39 None
40 } else {
41 Some(Self(value))
42 }
43 }
44
45 pub(crate) const fn new_unchecked(value: u32) -> Self {
54 Self(value)
55 }
56
57 pub const fn new_from_nanos(nanos: u32) -> Option<Self> {
62 if nanos >= NANOS_PER_SECOND as u32 {
63 return None;
64 }
65
66 let subseconds = ((nanos as u64 * SUBS_PER_S) + (NS_PER_S / 2)) / NS_PER_S;
67
68 Some(Subseconds::new_unchecked(subseconds as u32))
69 }
70
71 pub const fn nanos(&self) -> u32 {
73 let nanos = ((self.0 as u64 * NS_PER_S) + (SUBS_PER_S / 2)) / SUBS_PER_S;
74
75 nanos as u32
76 }
77
78 pub const fn raw(&self) -> u32 {
80 self.0
81 }
82
83 pub(crate) const fn hertz(&self) -> u32 {
85 SUBSECONDS_PER_SECOND as u32 / self.0
86 }
87
88 pub(crate) const fn nearest_increment(input_clk_hz: u32) -> Subseconds {
89 let hclk_half_subs = (SUBSECONDS_PER_SECOND as u32 + (input_clk_hz / 2)) / input_clk_hz;
90
91 Self::new_unchecked(hclk_half_subs)
92 }
93}
94
95impl core::ops::Add<Subseconds> for Subseconds {
96 type Output = Self;
97
98 fn add(self, rhs: Subseconds) -> Self::Output {
99 Self(self.0.wrapping_add(rhs.0) % (SUBSECONDS_PER_SECOND + 1))
100 }
101}
102
103impl core::ops::AddAssign<Subseconds> for Subseconds {
104 fn add_assign(&mut self, rhs: Subseconds) {
105 *self = *self + rhs;
106 }
107}
108
109impl core::ops::Sub<Subseconds> for Subseconds {
110 type Output = Self;
111
112 fn sub(self, rhs: Subseconds) -> Self::Output {
113 Self(self.0.wrapping_sub(rhs.0) % (SUBSECONDS_PER_SECOND + 1))
114 }
115}
116
117impl core::ops::SubAssign<Subseconds> for Subseconds {
118 fn sub_assign(&mut self, rhs: Subseconds) {
119 *self = *self - rhs;
120 }
121}
122
123#[cfg(all(test, not(target_os = "none")))]
124mod test {
125
126 use super::*;
127
128 #[test]
131 fn correct_subsecond_increment() {
132 for i in (25_000..180_000).map(|v| v * 1_000) {
133 let subs = Subseconds::nearest_increment(i).raw();
134 assert!(subs > 0 && subs <= 255);
135 }
136 }
137
138 #[test]
139 fn from_nanos() {
140 for i in [0, 1, 2, 3, NANOS_PER_SECOND - 1] {
141 let subseconds = Subseconds::new_from_nanos(i).unwrap();
142 assert!(subseconds.raw() < SUBSECONDS_PER_SECOND);
143 }
144
145 assert!(Subseconds::new_from_nanos(NANOS_PER_SECOND).is_none());
146 assert!(Subseconds::new_from_nanos(u32::MAX).is_none());
147 }
148
149 #[test]
150 fn subsecond_math() {
151 let one = Subseconds::new(1).unwrap();
152 let two = Subseconds::new(2).unwrap();
153 let three = Subseconds::new(3).unwrap();
154 let max = Subseconds::new(SUBSECONDS_PER_SECOND).unwrap();
155 let zero = Subseconds::new(0).unwrap();
156
157 assert_eq!(one + two, three);
158 assert_eq!(two - one, one);
159
160 assert_eq!(one - max + max, one);
161 assert_eq!(one - two, max);
162 assert_eq!(one + max, zero);
163 assert_eq!(two + max, one);
164 }
165}