1use crate::dma::desc::Descriptor;
2
3use super::{Subseconds, NANOS_PER_SECOND};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub struct Timestamp(i64);
8
9#[cfg(feature = "defmt")]
10impl defmt::Format for Timestamp {
11 fn format(&self, fmt: defmt::Formatter) {
12 if self.is_positive() {
13 defmt::write!(fmt, "{}.{:09}", self.seconds(), self.nanos());
14 } else {
15 defmt::write!(fmt, "-{}.{:09}", self.seconds(), self.nanos());
16 }
17 }
18}
19
20impl Timestamp {
21 const SIGN_BIT: u32 = 0x8000_0000;
24
25 pub const fn new(negative: bool, seconds: u32, subseconds: Subseconds) -> Self {
27 Self::new_unchecked(negative, seconds, subseconds.raw())
28 }
29
30 pub const fn new_raw(value: i64) -> Self {
32 Self(value)
33 }
34
35 pub const fn raw(&self) -> i64 {
37 self.0
38 }
39
40 pub const fn is_negative(&self) -> bool {
42 self.0.is_negative()
43 }
44
45 pub const fn is_positive(&self) -> bool {
47 !self.is_negative()
48 }
49
50 pub(crate) const fn new_unchecked(negative: bool, seconds: u32, subseconds: u32) -> Self {
51 let seconds: i64 = (seconds as i64) << 31;
52 let subseconds: i64 = subseconds as i64;
53
54 let mut total = seconds + subseconds;
55
56 if negative {
57 total = -total;
58 };
59
60 Self(total)
61 }
62
63 pub const fn seconds(&self) -> u32 {
65 (self.0.abs() >> 31) as u32
66 }
67
68 pub const fn subseconds(&self) -> Subseconds {
70 Subseconds::new_unchecked(self.0.abs() as u32 & Subseconds::MAX_VALUE)
71 }
72
73 pub const fn subseconds_signed(&self) -> u32 {
78 let mut subseconds = self.subseconds().raw();
79
80 if self.0.is_negative() {
81 subseconds |= Self::SIGN_BIT;
82 }
83
84 subseconds
85 }
86
87 pub const fn nanos(&self) -> u32 {
89 self.subseconds().nanos()
90 }
91
92 pub const fn total_nanos(&self) -> i64 {
105 let nanos = self.seconds() as i64 * NANOS_PER_SECOND as i64 + self.nanos() as i64;
106
107 if self.is_positive() {
108 nanos
109 } else {
110 -nanos
111 }
112 }
113
114 pub const fn from_parts(high: u32, low: u32) -> Timestamp {
116 let negative = (low & Self::SIGN_BIT) == Self::SIGN_BIT;
117 let subseconds = low & !(Self::SIGN_BIT);
118
119 Timestamp::new_unchecked(negative, high, subseconds)
120 }
121
122 pub fn from_descriptor(desc: &Descriptor) -> Option<Self> {
124 #[cfg(not(feature = "stm32f1xx-hal"))]
125 {
126 let (high, low) = { (desc.read(7), desc.read(6)) };
127 Some(Self::from_parts(high, low))
128 }
129
130 #[cfg(feature = "stm32f1xx-hal")]
131 {
132 let (high, low) = { (desc.read(3), desc.read(2)) };
133
134 if high == 0xFFFF_FFFF && low == 0xFFFF_FFFF {
137 None
138 } else {
139 Some(Self::from_parts(high, low))
140 }
141 }
142 }
143}
144
145impl core::ops::Add<Timestamp> for Timestamp {
146 type Output = Self;
147
148 fn add(self, rhs: Timestamp) -> Self::Output {
149 Self(self.0 + rhs.0)
150 }
151}
152
153impl core::ops::AddAssign<Timestamp> for Timestamp {
154 fn add_assign(&mut self, rhs: Timestamp) {
155 self.0 += rhs.0;
156 }
157}
158
159impl core::ops::Sub<Timestamp> for Timestamp {
160 type Output = Self;
161
162 fn sub(self, rhs: Timestamp) -> Self::Output {
163 Self(self.0 - rhs.0)
164 }
165}
166
167impl core::ops::SubAssign<Timestamp> for Timestamp {
168 fn sub_assign(&mut self, rhs: Timestamp) {
169 self.0 -= rhs.0
170 }
171}
172
173#[cfg(all(test, not(target_os = "none")))]
174mod test {
175 use crate::ptp::SUBSECONDS_PER_SECOND;
176
177 use super::{Subseconds, Timestamp};
178
179 fn subs(val: u32) -> Subseconds {
180 Subseconds::new(val).unwrap()
181 }
182
183 #[test]
184 fn timestamp_add() {
185 let one = Timestamp::new(false, 1, subs(1));
186 let one_big = Timestamp::new(false, 1, subs(SUBSECONDS_PER_SECOND - 1));
187 let two = Timestamp::new(false, 2, subs(2));
188 let three = Timestamp::new(false, 3, subs(3));
189
190 let one_neg = Timestamp::new(true, 1, subs(1));
191 let one_big_neg = Timestamp::new(true, 1, subs(SUBSECONDS_PER_SECOND - 1));
192 let two_neg = Timestamp::new(true, 2, subs(2));
193 let three_neg = Timestamp::new(true, 3, subs(3));
194
195 let one_minus_two = Timestamp::new(true, 1, subs(1));
196 let one_big_plus_two = Timestamp::new(false, 4, subs(0));
197 let two_minus_one_big = Timestamp::new(false, 0, subs(4));
198 let one_big_neg_plus_two_neg = Timestamp::new(true, 4, subs(0));
199
200 assert_eq!(one + two, three);
202 assert_eq!(two + one, three);
203 assert_eq!(one_big + two, one_big_plus_two);
204 assert_eq!(two + one_big, one_big_plus_two);
205
206 assert_eq!(one + two_neg, one_minus_two);
208 assert_eq!(two + one_big_neg, two_minus_one_big);
209
210 assert_eq!(one_neg + two, one);
212 assert_eq!(two + one_neg, one);
213
214 assert_eq!(one_neg + two_neg, three_neg);
216 assert_eq!(two_neg + one_neg, three_neg);
217 assert_eq!(one_big_neg + two_neg, one_big_neg_plus_two_neg);
218 assert_eq!(two_neg + one_big_neg, one_big_neg_plus_two_neg);
219 }
220
221 #[test]
222 fn timestamp_sub() {
223 let one = Timestamp::new(false, 1, subs(1));
224 let one_big = Timestamp::new(false, 1, subs(SUBSECONDS_PER_SECOND - 1));
225 let two = Timestamp::new(false, 2, subs(2));
226 let three = Timestamp::new(false, 3, subs(3));
227
228 let one_neg = Timestamp::new(true, 1, subs(1));
229 let two_neg = Timestamp::new(true, 2, subs(2));
230 let three_neg = Timestamp::new(true, 3, subs(3));
231
232 let one_minus_two = Timestamp::new(true, 1, subs(1));
233 let one_minus_one_big = Timestamp::new(true, 0, subs(SUBSECONDS_PER_SECOND - 2));
234
235 assert_eq!(one - one_big, one_minus_one_big);
236
237 assert_eq!(two - one, one);
239 assert_eq!(one - two, one_minus_two);
240
241 assert_eq!(two - one_neg, three);
243 assert_eq!(one_neg - two, three_neg);
244
245 assert_eq!(one_neg - two, three_neg);
247 assert_eq!(two - one_neg, three);
248
249 assert_eq!(one_neg - two_neg, one);
251 assert_eq!(two_neg - one_neg, one_minus_two);
252 }
253}