Skip to main content

cu29_clock/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3extern crate alloc;
4#[cfg(test)]
5extern crate approx;
6
7mod calibration;
8#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
9#[cfg_attr(all(target_os = "none", target_arch = "arm"), path = "cortexm.rs")]
10#[cfg_attr(target_arch = "riscv64", path = "riscv64.rs")]
11#[cfg_attr(
12    all(feature = "std", target_arch = "wasm32", target_os = "unknown"),
13    path = "wasm.rs"
14)]
15#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
16#[cfg_attr(
17    not(any(
18        target_arch = "x86_64",
19        target_arch = "aarch64",
20        all(target_os = "none", target_arch = "arm"),
21        target_arch = "riscv64",
22        all(feature = "std", target_arch = "wasm32", target_os = "unknown")
23    )),
24    path = "fallback.rs"
25)]
26mod raw_counter;
27
28pub use raw_counter::*;
29
30#[cfg(feature = "reflect")]
31use bevy_reflect::Reflect;
32use bincode::BorrowDecode;
33use bincode::de::BorrowDecoder;
34use bincode::de::Decoder;
35use bincode::enc::Encoder;
36use bincode::error::{DecodeError, EncodeError};
37use bincode::{Decode, Encode};
38use core::ops::{Add, Sub};
39use serde::{Deserialize, Serialize};
40
41// We use this to be able to support embedded 32bit platforms
42use portable_atomic::{AtomicU64, Ordering};
43
44use alloc::format;
45use alloc::sync::Arc;
46use alloc::vec::Vec;
47use core::fmt::{Display, Formatter};
48use core::ops::{AddAssign, Div, Mul, SubAssign};
49
50/// High-precision instant in time, represented as nanoseconds since an arbitrary epoch
51#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
52pub struct CuInstant(u64);
53
54pub type Instant = CuInstant; // Backward compatibility
55
56impl CuInstant {
57    pub fn now() -> Self {
58        CuInstant(calibration::counter_to_nanos(read_raw_counter))
59    }
60
61    pub fn as_nanos(&self) -> u64 {
62        self.0
63    }
64}
65
66impl Sub for CuInstant {
67    type Output = CuDuration;
68
69    fn sub(self, other: CuInstant) -> CuDuration {
70        CuDuration(self.0.saturating_sub(other.0))
71    }
72}
73
74impl Sub<CuDuration> for CuInstant {
75    type Output = CuInstant;
76
77    fn sub(self, duration: CuDuration) -> CuInstant {
78        CuInstant(self.0.saturating_sub(duration.as_nanos()))
79    }
80}
81
82impl Add<CuDuration> for CuInstant {
83    type Output = CuInstant;
84
85    fn add(self, duration: CuDuration) -> CuInstant {
86        CuInstant(self.0.saturating_add(duration.as_nanos()))
87    }
88}
89
90/// For Robot times, the underlying type is a u64 representing nanoseconds.
91/// It is always positive to simplify the reasoning on the user side.
92#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
93#[cfg_attr(feature = "reflect", derive(Reflect))]
94pub struct CuDuration(pub u64);
95
96impl CuDuration {
97    // Lowest value a CuDuration can have.
98    pub const MIN: CuDuration = CuDuration(0u64);
99    // Highest value a CuDuration can have reserving the max value for None.
100    pub const MAX: CuDuration = CuDuration(NONE_VALUE - 1);
101
102    pub fn max(self, other: CuDuration) -> CuDuration {
103        let Self(lhs) = self;
104        let Self(rhs) = other;
105        CuDuration(lhs.max(rhs))
106    }
107
108    pub fn min(self, other: CuDuration) -> CuDuration {
109        let Self(lhs) = self;
110        let Self(rhs) = other;
111        CuDuration(lhs.min(rhs))
112    }
113
114    pub fn as_nanos(&self) -> u64 {
115        let Self(nanos) = self;
116        *nanos
117    }
118
119    pub fn as_micros(&self) -> u64 {
120        let Self(nanos) = self;
121        nanos / 1_000
122    }
123
124    pub fn as_millis(&self) -> u64 {
125        let Self(nanos) = self;
126        nanos / 1_000_000
127    }
128
129    pub fn as_secs(&self) -> u64 {
130        let Self(nanos) = self;
131        nanos / 1_000_000_000
132    }
133
134    pub fn from_nanos(nanos: u64) -> Self {
135        CuDuration(nanos)
136    }
137
138    pub fn from_micros(micros: u64) -> Self {
139        CuDuration(micros * 1_000)
140    }
141
142    pub fn from_millis(millis: u64) -> Self {
143        CuDuration(millis * 1_000_000)
144    }
145
146    pub fn from_secs(secs: u64) -> Self {
147        CuDuration(secs * 1_000_000_000)
148    }
149}
150
151/// Saturating subtraction for time and duration types.
152pub trait SaturatingSub {
153    fn saturating_sub(self, other: Self) -> Self;
154}
155
156impl SaturatingSub for CuDuration {
157    fn saturating_sub(self, other: Self) -> Self {
158        let Self(lhs) = self;
159        let Self(rhs) = other;
160        CuDuration(lhs.saturating_sub(rhs))
161    }
162}
163
164/// bridge the API with standard Durations.
165#[cfg(feature = "std")]
166impl From<std::time::Duration> for CuDuration {
167    fn from(duration: std::time::Duration) -> Self {
168        CuDuration(duration.as_nanos() as u64)
169    }
170}
171
172#[cfg(not(feature = "std"))]
173impl From<core::time::Duration> for CuDuration {
174    fn from(duration: core::time::Duration) -> Self {
175        CuDuration(duration.as_nanos() as u64)
176    }
177}
178
179#[cfg(feature = "std")]
180impl From<CuDuration> for std::time::Duration {
181    fn from(val: CuDuration) -> Self {
182        let CuDuration(nanos) = val;
183        std::time::Duration::from_nanos(nanos)
184    }
185}
186
187impl From<u64> for CuDuration {
188    fn from(duration: u64) -> Self {
189        CuDuration(duration)
190    }
191}
192
193impl From<CuDuration> for u64 {
194    fn from(val: CuDuration) -> Self {
195        let CuDuration(nanos) = val;
196        nanos
197    }
198}
199
200impl Sub for CuDuration {
201    type Output = Self;
202
203    fn sub(self, rhs: Self) -> Self::Output {
204        let CuDuration(lhs) = self;
205        let CuDuration(rhs) = rhs;
206        CuDuration(lhs - rhs)
207    }
208}
209
210impl Add for CuDuration {
211    type Output = Self;
212
213    fn add(self, rhs: Self) -> Self::Output {
214        let CuDuration(lhs) = self;
215        let CuDuration(rhs) = rhs;
216        CuDuration(lhs + rhs)
217    }
218}
219
220impl AddAssign for CuDuration {
221    fn add_assign(&mut self, rhs: Self) {
222        let CuDuration(lhs) = self;
223        let CuDuration(rhs) = rhs;
224        *lhs += rhs;
225    }
226}
227
228impl SubAssign for CuDuration {
229    fn sub_assign(&mut self, rhs: Self) {
230        let CuDuration(lhs) = self;
231        let CuDuration(rhs) = rhs;
232        *lhs -= rhs;
233    }
234}
235
236// a way to divide a duration by a scalar.
237// useful to compute averages for example.
238impl<T> Div<T> for CuDuration
239where
240    T: Into<u64>,
241{
242    type Output = Self;
243    fn div(self, rhs: T) -> Self {
244        let CuDuration(lhs) = self;
245        CuDuration(lhs / rhs.into())
246    }
247}
248
249// a way to multiply a duration by a scalar.
250// useful to compute offsets for example.
251// CuDuration * scalar
252impl<T> Mul<T> for CuDuration
253where
254    T: Into<u64>,
255{
256    type Output = CuDuration;
257
258    fn mul(self, rhs: T) -> CuDuration {
259        let CuDuration(lhs) = self;
260        CuDuration(lhs * rhs.into())
261    }
262}
263
264// u64 * CuDuration
265impl Mul<CuDuration> for u64 {
266    type Output = CuDuration;
267
268    fn mul(self, rhs: CuDuration) -> CuDuration {
269        let CuDuration(nanos) = rhs;
270        CuDuration(self * nanos)
271    }
272}
273
274// u32 * CuDuration
275impl Mul<CuDuration> for u32 {
276    type Output = CuDuration;
277
278    fn mul(self, rhs: CuDuration) -> CuDuration {
279        let CuDuration(nanos) = rhs;
280        CuDuration(self as u64 * nanos)
281    }
282}
283
284// i32 * CuDuration
285impl Mul<CuDuration> for i32 {
286    type Output = CuDuration;
287
288    fn mul(self, rhs: CuDuration) -> CuDuration {
289        let CuDuration(nanos) = rhs;
290        CuDuration(self as u64 * nanos)
291    }
292}
293
294impl Encode for CuDuration {
295    fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
296        let CuDuration(nanos) = self;
297        nanos.encode(encoder)
298    }
299}
300
301impl<Context> Decode<Context> for CuDuration {
302    fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
303        Ok(CuDuration(u64::decode(decoder)?))
304    }
305}
306
307impl<'de, Context> BorrowDecode<'de, Context> for CuDuration {
308    fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
309        Ok(CuDuration(u64::decode(decoder)?))
310    }
311}
312
313impl Display for CuDuration {
314    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
315        let Self(nanos) = *self;
316        if nanos >= 86_400_000_000_000 {
317            write!(f, "{:.3} d", nanos as f64 / 86_400_000_000_000.0)
318        } else if nanos >= 3_600_000_000_000 {
319            write!(f, "{:.3} h", nanos as f64 / 3_600_000_000_000.0)
320        } else if nanos >= 60_000_000_000 {
321            write!(f, "{:.3} m", nanos as f64 / 60_000_000_000.0)
322        } else if nanos >= 1_000_000_000 {
323            write!(f, "{:.3} s", nanos as f64 / 1_000_000_000.0)
324        } else if nanos >= 1_000_000 {
325            write!(f, "{:.3} ms", nanos as f64 / 1_000_000.0)
326        } else if nanos >= 1_000 {
327            write!(f, "{:.3} µs", nanos as f64 / 1_000.0)
328        } else {
329            write!(f, "{nanos} ns")
330        }
331    }
332}
333
334/// A robot time is a monotonic timestamp in nanoseconds from the robot clock epoch.
335#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
336#[cfg_attr(feature = "reflect", derive(Reflect))]
337#[repr(transparent)]
338pub struct CuTime(pub u64);
339
340impl CuTime {
341    pub const MIN: CuTime = CuTime(0u64);
342    pub const MAX: CuTime = CuTime(NONE_VALUE - 1);
343
344    pub fn max(self, other: CuTime) -> CuTime {
345        let Self(lhs) = self;
346        let Self(rhs) = other;
347        CuTime(lhs.max(rhs))
348    }
349
350    pub fn min(self, other: CuTime) -> CuTime {
351        let Self(lhs) = self;
352        let Self(rhs) = other;
353        CuTime(lhs.min(rhs))
354    }
355
356    pub fn as_nanos(&self) -> u64 {
357        let Self(nanos) = self;
358        *nanos
359    }
360
361    pub fn as_micros(&self) -> u64 {
362        self.as_nanos() / 1_000
363    }
364
365    pub fn as_millis(&self) -> u64 {
366        self.as_nanos() / 1_000_000
367    }
368
369    pub fn as_secs(&self) -> u64 {
370        self.as_nanos() / 1_000_000_000
371    }
372
373    pub fn from_nanos(nanos: u64) -> Self {
374        CuTime(nanos)
375    }
376
377    pub fn from_micros(micros: u64) -> Self {
378        CuTime::from(CuDuration::from_micros(micros))
379    }
380
381    pub fn from_millis(millis: u64) -> Self {
382        CuTime::from(CuDuration::from_millis(millis))
383    }
384
385    pub fn from_secs(secs: u64) -> Self {
386        CuTime::from(CuDuration::from_secs(secs))
387    }
388}
389
390impl SaturatingSub for CuTime {
391    fn saturating_sub(self, other: Self) -> Self {
392        let Self(lhs) = self;
393        let Self(rhs) = other;
394        CuTime(lhs.saturating_sub(rhs))
395    }
396}
397
398#[cfg(feature = "std")]
399impl From<std::time::Duration> for CuTime {
400    fn from(duration: std::time::Duration) -> Self {
401        CuTime::from(CuDuration::from(duration))
402    }
403}
404
405#[cfg(not(feature = "std"))]
406impl From<core::time::Duration> for CuTime {
407    fn from(duration: core::time::Duration) -> Self {
408        CuTime::from(CuDuration::from(duration))
409    }
410}
411
412#[cfg(feature = "std")]
413impl From<CuTime> for std::time::Duration {
414    fn from(val: CuTime) -> Self {
415        std::time::Duration::from_nanos(val.as_nanos())
416    }
417}
418
419impl From<u64> for CuTime {
420    fn from(time: u64) -> Self {
421        CuTime(time)
422    }
423}
424
425impl From<CuTime> for u64 {
426    fn from(val: CuTime) -> Self {
427        let CuTime(nanos) = val;
428        nanos
429    }
430}
431
432impl From<CuDuration> for CuTime {
433    fn from(duration: CuDuration) -> Self {
434        CuTime(duration.as_nanos())
435    }
436}
437
438impl From<CuTime> for CuDuration {
439    fn from(time: CuTime) -> Self {
440        CuDuration(time.as_nanos())
441    }
442}
443
444impl Add for CuTime {
445    type Output = Self;
446
447    fn add(self, rhs: Self) -> Self::Output {
448        CuTime(self.as_nanos().saturating_add(rhs.as_nanos()))
449    }
450}
451
452impl Add<CuDuration> for CuTime {
453    type Output = Self;
454
455    fn add(self, rhs: CuDuration) -> Self::Output {
456        CuTime(self.as_nanos().saturating_add(rhs.as_nanos()))
457    }
458}
459
460impl AddAssign<CuDuration> for CuTime {
461    fn add_assign(&mut self, rhs: CuDuration) {
462        *self = *self + rhs;
463    }
464}
465
466impl AddAssign for CuTime {
467    fn add_assign(&mut self, rhs: Self) {
468        *self = *self + rhs;
469    }
470}
471
472impl Sub<CuDuration> for CuTime {
473    type Output = Self;
474
475    fn sub(self, rhs: CuDuration) -> Self::Output {
476        CuTime(self.as_nanos().saturating_sub(rhs.as_nanos()))
477    }
478}
479
480impl SubAssign<CuDuration> for CuTime {
481    fn sub_assign(&mut self, rhs: CuDuration) {
482        *self = *self - rhs;
483    }
484}
485
486impl SubAssign for CuTime {
487    fn sub_assign(&mut self, rhs: Self) {
488        *self = CuTime(self.as_nanos().saturating_sub(rhs.as_nanos()));
489    }
490}
491
492impl Sub for CuTime {
493    type Output = CuDuration;
494
495    fn sub(self, rhs: Self) -> Self::Output {
496        CuDuration(self.as_nanos().saturating_sub(rhs.as_nanos()))
497    }
498}
499
500impl<T> Div<T> for CuTime
501where
502    T: Into<u64>,
503{
504    type Output = Self;
505
506    fn div(self, rhs: T) -> Self::Output {
507        CuTime(self.as_nanos() / rhs.into())
508    }
509}
510
511impl<T> Mul<T> for CuTime
512where
513    T: Into<u64>,
514{
515    type Output = Self;
516
517    fn mul(self, rhs: T) -> Self::Output {
518        CuTime(self.as_nanos() * rhs.into())
519    }
520}
521
522impl Mul<CuTime> for u64 {
523    type Output = CuTime;
524
525    fn mul(self, rhs: CuTime) -> Self::Output {
526        CuTime(self * rhs.as_nanos())
527    }
528}
529
530impl Mul<CuTime> for u32 {
531    type Output = CuTime;
532
533    fn mul(self, rhs: CuTime) -> Self::Output {
534        CuTime(self as u64 * rhs.as_nanos())
535    }
536}
537
538impl Mul<CuTime> for i32 {
539    type Output = CuTime;
540
541    fn mul(self, rhs: CuTime) -> Self::Output {
542        CuTime(self as u64 * rhs.as_nanos())
543    }
544}
545
546impl Encode for CuTime {
547    fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
548        self.as_nanos().encode(encoder)
549    }
550}
551
552impl<Context> Decode<Context> for CuTime {
553    fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
554        Ok(CuTime(u64::decode(decoder)?))
555    }
556}
557
558impl<'de, Context> BorrowDecode<'de, Context> for CuTime {
559    fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
560        Ok(CuTime(u64::decode(decoder)?))
561    }
562}
563
564impl Display for CuTime {
565    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
566        CuDuration(self.as_nanos()).fmt(f)
567    }
568}
569
570/// A busy looping function based on this clock for a duration.
571/// Mainly useful for embedded to spinlocking.
572#[inline(always)]
573pub fn busy_wait_for(duration: CuDuration) {
574    busy_wait_until(CuInstant::now() + duration);
575}
576
577/// A busy looping function based on this until a specific time.
578/// Mainly useful for embedded to spinlocking.
579#[inline(always)]
580pub fn busy_wait_until(time: CuInstant) {
581    while CuInstant::now() < time {
582        core::hint::spin_loop();
583    }
584}
585
586/// Homebrewed `Option<CuDuration>` to avoid using 128bits just to represent an Option.
587#[derive(Copy, Clone, Debug, PartialEq, Encode, Decode, Serialize, Deserialize)]
588#[cfg_attr(feature = "reflect", derive(Reflect))]
589pub struct OptionCuTime(CuTime);
590
591const NONE_VALUE: u64 = 0xFFFFFFFFFFFFFFFF;
592
593impl OptionCuTime {
594    pub const NONE_SENTINEL_NANOS: u64 = NONE_VALUE;
595
596    #[inline]
597    pub fn is_none(&self) -> bool {
598        let Self(CuTime(nanos)) = self;
599        *nanos == NONE_VALUE
600    }
601
602    #[inline]
603    pub const fn none() -> Self {
604        OptionCuTime(CuTime(NONE_VALUE))
605    }
606
607    #[inline]
608    pub fn unwrap(self) -> CuTime {
609        if self.is_none() {
610            panic!("called `OptionCuTime::unwrap()` on a `None` value");
611        }
612        self.0
613    }
614}
615
616impl Display for OptionCuTime {
617    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
618        if self.is_none() {
619            write!(f, "None")
620        } else {
621            write!(f, "{}", self.0)
622        }
623    }
624}
625
626impl Default for OptionCuTime {
627    fn default() -> Self {
628        Self::none()
629    }
630}
631
632impl From<Option<CuTime>> for OptionCuTime {
633    #[inline]
634    fn from(duration: Option<CuTime>) -> Self {
635        match duration {
636            Some(duration) => OptionCuTime(duration),
637            None => OptionCuTime(CuTime(NONE_VALUE)),
638        }
639    }
640}
641
642impl From<OptionCuTime> for Option<CuTime> {
643    #[inline]
644    fn from(val: OptionCuTime) -> Self {
645        let OptionCuTime(CuTime(nanos)) = val;
646        if nanos == NONE_VALUE {
647            None
648        } else {
649            Some(CuTime(nanos))
650        }
651    }
652}
653
654impl From<CuTime> for OptionCuTime {
655    #[inline]
656    fn from(val: CuTime) -> Self {
657        Some(val).into()
658    }
659}
660
661#[derive(Debug, Clone, Copy, PartialEq, Eq)]
662pub enum ClockDebugScalarKind {
663    Time,
664    OptionalTime,
665    Duration,
666}
667
668#[derive(Debug, Clone, Copy, PartialEq, Eq)]
669pub struct ClockDebugScalarRegistration {
670    pub type_path: &'static str,
671    pub field_type: &'static str,
672    pub kind: ClockDebugScalarKind,
673}
674
675pub fn debug_scalar_registrations() -> Vec<ClockDebugScalarRegistration> {
676    alloc::vec![
677        ClockDebugScalarRegistration {
678            type_path: core::any::type_name::<CuDuration>(),
679            field_type: "integer",
680            kind: ClockDebugScalarKind::Duration,
681        },
682        ClockDebugScalarRegistration {
683            type_path: core::any::type_name::<CuTime>(),
684            field_type: "integer",
685            kind: ClockDebugScalarKind::Time,
686        },
687        ClockDebugScalarRegistration {
688            type_path: core::any::type_name::<OptionCuTime>(),
689            field_type: "integer",
690            kind: ClockDebugScalarKind::OptionalTime,
691        },
692    ]
693}
694
695/// Represents a time range.
696#[derive(Copy, Clone, Debug, Encode, Decode, Serialize, Deserialize, PartialEq)]
697#[cfg_attr(feature = "reflect", derive(Reflect))]
698pub struct CuTimeRange {
699    pub start: CuTime,
700    pub end: CuTime,
701}
702
703/// Builds a time range from a slice of CuTime.
704/// This is an O(n) operation.
705impl From<&[CuTime]> for CuTimeRange {
706    fn from(slice: &[CuTime]) -> Self {
707        CuTimeRange {
708            start: *slice.iter().min().expect("Empty slice"),
709            end: *slice.iter().max().expect("Empty slice"),
710        }
711    }
712}
713
714/// Represents a time range with possible undefined start or end or both.
715#[derive(Default, Copy, Clone, Debug, Encode, Decode, Serialize, Deserialize)]
716#[cfg_attr(feature = "reflect", derive(Reflect))]
717pub struct PartialCuTimeRange {
718    pub start: OptionCuTime,
719    pub end: OptionCuTime,
720}
721
722impl Display for PartialCuTimeRange {
723    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
724        let start = if self.start.is_none() {
725            "…"
726        } else {
727            &format!("{}", self.start)
728        };
729        let end = if self.end.is_none() {
730            "…"
731        } else {
732            &format!("{}", self.end)
733        };
734        write!(f, "[{start} – {end}]")
735    }
736}
737
738/// The time of validity of a message can be more than one time but can be a time range of Tovs.
739/// For example a sub scan for a lidar, a set of images etc... can have a range of validity.
740#[derive(Default, Clone, Debug, PartialEq, Encode, Decode, Serialize, Deserialize, Copy)]
741#[cfg_attr(feature = "reflect", derive(Reflect))]
742pub enum Tov {
743    #[default]
744    None,
745    Time(CuTime),
746    Range(CuTimeRange),
747}
748
749impl Display for Tov {
750    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
751        match self {
752            Tov::None => write!(f, "None"),
753            Tov::Time(t) => write!(f, "{t}"),
754            Tov::Range(r) => write!(f, "[{} – {}]", r.start, r.end),
755        }
756    }
757}
758
759impl From<Option<CuDuration>> for Tov {
760    fn from(duration: Option<CuDuration>) -> Self {
761        duration.map(CuTime::from).map_or(Tov::None, Tov::Time)
762    }
763}
764
765impl From<Option<CuTime>> for Tov {
766    fn from(time: Option<CuTime>) -> Self {
767        time.map_or(Tov::None, Tov::Time)
768    }
769}
770
771impl From<CuDuration> for Tov {
772    fn from(duration: CuDuration) -> Self {
773        Tov::Time(duration.into())
774    }
775}
776
777impl From<CuTime> for Tov {
778    fn from(time: CuTime) -> Self {
779        Tov::Time(time)
780    }
781}
782
783/// Internal clock implementation that provides high-precision timing
784#[derive(Clone, Debug)]
785struct InternalClock {
786    // For real clocks, this stores the initialization time
787    // For mock clocks, this references the mock state
788    mock_state: Option<Arc<AtomicU64>>,
789}
790
791// Implements the std version of the RTC clock
792#[cfg(all(
793    feature = "std",
794    not(all(target_arch = "wasm32", target_os = "unknown"))
795))]
796#[inline(always)]
797fn read_rtc_ns() -> u64 {
798    std::time::SystemTime::now()
799        .duration_since(std::time::UNIX_EPOCH)
800        .unwrap()
801        .as_nanos() as u64
802}
803
804#[cfg(all(feature = "std", target_arch = "wasm32", target_os = "unknown"))]
805#[inline(always)]
806fn read_rtc_ns() -> u64 {
807    read_raw_counter()
808}
809
810#[cfg(all(
811    feature = "std",
812    not(all(target_arch = "wasm32", target_os = "unknown"))
813))]
814#[inline(always)]
815fn sleep_ns(ns: u64) {
816    std::thread::sleep(std::time::Duration::from_nanos(ns));
817}
818
819#[cfg(all(feature = "std", target_arch = "wasm32", target_os = "unknown"))]
820#[inline(always)]
821fn sleep_ns(ns: u64) {
822    let start = read_raw_counter();
823    while read_raw_counter().saturating_sub(start) < ns {
824        core::hint::spin_loop();
825    }
826}
827
828impl InternalClock {
829    fn new(
830        read_rtc_ns: impl Fn() -> u64 + Send + Sync + 'static,
831        sleep_ns: impl Fn(u64) + Send + Sync + 'static,
832    ) -> Self {
833        initialize();
834
835        // Initialize the frequency calibration
836        calibration::calibrate(read_raw_counter, read_rtc_ns, sleep_ns);
837        InternalClock { mock_state: None }
838    }
839
840    fn mock() -> (Self, Arc<AtomicU64>) {
841        let mock_state = Arc::new(AtomicU64::new(0));
842        let clock = InternalClock {
843            mock_state: Some(Arc::clone(&mock_state)),
844        };
845        (clock, mock_state)
846    }
847
848    fn now(&self) -> CuInstant {
849        if let Some(ref mock_state) = self.mock_state {
850            CuInstant(mock_state.load(Ordering::Relaxed))
851        } else {
852            CuInstant::now()
853        }
854    }
855
856    fn recent(&self) -> CuInstant {
857        // For simplicity, we use the same implementation as now()
858        // In a more sophisticated implementation, this could use a cached value
859        self.now()
860    }
861}
862
863/// A running Robot clock.
864/// The clock is a monotonic clock that starts at an arbitrary reference time.
865/// It is clone resilient, ie a clone will be the same clock, even when mocked.
866#[derive(Clone, Debug)]
867pub struct RobotClock {
868    inner: InternalClock,
869    ref_time: CuInstant,
870}
871
872/// A mock clock that can be controlled by the user.
873#[derive(Debug, Clone)]
874pub struct RobotClockMock(Arc<AtomicU64>);
875
876impl RobotClockMock {
877    pub fn increment(&self, amount: CuDuration) {
878        let Self(mock_state) = self;
879        mock_state.fetch_add(amount.as_nanos(), Ordering::Relaxed);
880    }
881
882    /// Decrements the time by the given amount.
883    /// Be careful this breaks the monotonicity of the clock.
884    pub fn decrement(&self, amount: CuDuration) {
885        let Self(mock_state) = self;
886        mock_state.fetch_sub(amount.as_nanos(), Ordering::Relaxed);
887    }
888
889    /// Gets the current value of time.
890    pub fn value(&self) -> u64 {
891        let Self(mock_state) = self;
892        mock_state.load(Ordering::Relaxed)
893    }
894
895    /// A convenient way to get the current time from the mocking side.
896    pub fn now(&self) -> CuTime {
897        let Self(mock_state) = self;
898        CuTime(mock_state.load(Ordering::Relaxed))
899    }
900
901    /// Sets the absolute value of the time.
902    pub fn set_value(&self, value: u64) {
903        let Self(mock_state) = self;
904        mock_state.store(value, Ordering::Relaxed);
905    }
906}
907
908impl RobotClock {
909    /// Creates a RobotClock using now as its reference time.
910    /// It will start at 0ns incrementing monotonically.
911    /// This uses the std System Time as a reference clock.
912    #[cfg(feature = "std")]
913    pub fn new() -> Self {
914        let clock = InternalClock::new(read_rtc_ns, sleep_ns);
915        let ref_time = clock.now();
916        RobotClock {
917            inner: clock,
918            ref_time,
919        }
920    }
921
922    /// Builds a RobotClock using a reference RTC clock to calibrate with.
923    /// This is mandatory to use with the no-std platforms as we have no idea where to find a reference clock.
924    pub fn new_with_rtc(
925        read_rtc_ns: impl Fn() -> u64 + Send + Sync + 'static,
926        sleep_ns: impl Fn(u64) + Send + Sync + 'static,
927    ) -> Self {
928        let clock = InternalClock::new(read_rtc_ns, sleep_ns);
929        let ref_time = clock.now();
930        RobotClock {
931            inner: clock,
932            ref_time,
933        }
934    }
935
936    /// Builds a monotonic clock starting at the given reference time.
937    #[cfg(feature = "std")]
938    pub fn from_ref_time(ref_time_ns: u64) -> Self {
939        let clock = InternalClock::new(read_rtc_ns, sleep_ns);
940        let ref_time = clock.now() - CuDuration(ref_time_ns);
941        RobotClock {
942            inner: clock,
943            ref_time,
944        }
945    }
946
947    /// Overrides the RTC with a custom implementation, should be the same as the new_with_rtc.
948    pub fn from_ref_time_with_rtc(
949        read_rtc_ns: fn() -> u64,
950        sleep_ns: fn(u64),
951        ref_time_ns: u64,
952    ) -> Self {
953        let clock = InternalClock::new(read_rtc_ns, sleep_ns);
954        let ref_time = clock.now() - CuDuration(ref_time_ns);
955        RobotClock {
956            inner: clock,
957            ref_time,
958        }
959    }
960
961    /// Build a fake clock with a reference time of 0.
962    /// The RobotMock interface enables you to control all the clones of the clock given.
963    pub fn mock() -> (Self, RobotClockMock) {
964        let (clock, mock_state) = InternalClock::mock();
965        let ref_time = clock.now();
966        (
967            RobotClock {
968                inner: clock,
969                ref_time,
970            },
971            RobotClockMock(mock_state),
972        )
973    }
974
975    /// Now returns the time that passed since the reference time, usually the start time.
976    /// It is a monotonically increasing value.
977    #[inline]
978    pub fn now(&self) -> CuTime {
979        CuTime::from_nanos((self.inner.now() - self.ref_time).as_nanos())
980    }
981
982    /// A less precise but quicker time
983    #[inline]
984    pub fn recent(&self) -> CuTime {
985        CuTime::from_nanos((self.inner.recent() - self.ref_time).as_nanos())
986    }
987}
988
989/// We cannot build a default RobotClock on no-std because we don't know how to find a reference clock.
990/// Use RobotClock::new_with_rtc instead on no-std.
991#[cfg(feature = "std")]
992impl Default for RobotClock {
993    fn default() -> Self {
994        Self::new()
995    }
996}
997
998/// A trait to provide a clock to the runtime.
999pub trait ClockProvider {
1000    fn get_clock(&self) -> RobotClock;
1001}
1002
1003#[cfg(test)]
1004mod tests {
1005    use super::*;
1006    use approx::assert_relative_eq;
1007
1008    #[test]
1009    fn test_cuduration_comparison_operators() {
1010        let a = CuDuration(100);
1011        let b = CuDuration(200);
1012
1013        assert!(a < b);
1014        assert!(b > a);
1015        assert_ne!(a, b);
1016        assert_eq!(a, CuDuration(100));
1017    }
1018
1019    #[test]
1020    fn test_cuduration_arithmetic_operations() {
1021        let a = CuDuration(100);
1022        let b = CuDuration(50);
1023
1024        assert_eq!(a + b, CuDuration(150));
1025        assert_eq!(a - b, CuDuration(50));
1026        assert_eq!(a * 2u32, CuDuration(200));
1027        assert_eq!(a / 2u32, CuDuration(50));
1028    }
1029
1030    #[test]
1031    fn test_robot_clock_monotonic() {
1032        let clock = RobotClock::new();
1033        let t1 = clock.now();
1034        let t2 = clock.now();
1035        assert!(t2 >= t1);
1036    }
1037
1038    #[test]
1039    fn test_robot_clock_mock() {
1040        let (clock, mock) = RobotClock::mock();
1041        let t1 = clock.now();
1042        mock.increment(CuDuration::from_millis(100));
1043        let t2 = clock.now();
1044        assert!(t2 > t1);
1045        assert_eq!(t2 - t1, CuDuration(100_000_000)); // 100ms in nanoseconds
1046    }
1047
1048    #[test]
1049    fn test_robot_clock_clone_consistency() {
1050        let (clock1, mock) = RobotClock::mock();
1051        let clock2 = clock1.clone();
1052
1053        mock.set_value(1_000_000_000); // 1 second
1054        assert_eq!(clock1.now(), clock2.now());
1055    }
1056
1057    #[test]
1058    fn test_from_ref_time() {
1059        let tolerance_ms = 10f64;
1060        let clock = RobotClock::from_ref_time(1_000_000_000);
1061        assert_relative_eq!(
1062            clock.now().as_millis() as f64,
1063            CuDuration::from_secs(1).as_millis() as f64,
1064            epsilon = tolerance_ms
1065        );
1066    }
1067
1068    #[test]
1069    fn longest_duration() {
1070        let maxcu = CuDuration(u64::MAX);
1071        assert_eq!(maxcu.as_nanos(), u64::MAX);
1072        let s = maxcu.as_secs();
1073        let y = s / 60 / 60 / 24 / 365;
1074        assert!(y >= 584); // 584 years of robot uptime, we should be good.
1075    }
1076
1077    #[test]
1078    fn test_some_time_arithmetics() {
1079        let a: CuDuration = 10.into();
1080        let b: CuDuration = 20.into();
1081        let c = a + b;
1082        assert_eq!(c.0, 30);
1083        let d = b - a;
1084        assert_eq!(d.0, 10);
1085    }
1086
1087    #[test]
1088    fn test_build_range_from_slice() {
1089        let range = CuTimeRange::from(&[20.into(), 10.into(), 30.into()][..]);
1090        assert_eq!(range.start, 10.into());
1091        assert_eq!(range.end, 30.into());
1092    }
1093
1094    #[test]
1095    fn test_time_range_operations() {
1096        // Test creating a time range and checking its properties
1097        let start = CuTime::from(100u64);
1098        let end = CuTime::from(200u64);
1099        let range = CuTimeRange { start, end };
1100
1101        assert_eq!(range.start, start);
1102        assert_eq!(range.end, end);
1103
1104        // Test creating from a slice
1105        let times = [
1106            CuTime::from(150u64),
1107            CuTime::from(120u64),
1108            CuTime::from(180u64),
1109        ];
1110        let range_from_slice = CuTimeRange::from(&times[..]);
1111
1112        // Range should capture min and max values
1113        assert_eq!(range_from_slice.start, CuTime::from(120u64));
1114        assert_eq!(range_from_slice.end, CuTime::from(180u64));
1115    }
1116
1117    #[test]
1118    fn test_partial_time_range() {
1119        // Test creating a partial time range with defined start/end
1120        let start = CuTime::from(100u64);
1121        let end = CuTime::from(200u64);
1122
1123        let partial_range = PartialCuTimeRange {
1124            start: OptionCuTime::from(start),
1125            end: OptionCuTime::from(end),
1126        };
1127
1128        // Test converting to Option
1129        let opt_start: Option<CuTime> = partial_range.start.into();
1130        let opt_end: Option<CuTime> = partial_range.end.into();
1131
1132        assert_eq!(opt_start, Some(start));
1133        assert_eq!(opt_end, Some(end));
1134
1135        // Test partial range with undefined values
1136        let partial_undefined = PartialCuTimeRange::default();
1137        assert!(partial_undefined.start.is_none());
1138        assert!(partial_undefined.end.is_none());
1139    }
1140
1141    #[test]
1142    fn test_tov_conversions() {
1143        // Test different Time of Validity (Tov) variants
1144        let time = CuTime::from(100u64);
1145
1146        // Test conversion from CuTime
1147        let tov_time: Tov = time.into();
1148        assert!(matches!(tov_time, Tov::Time(_)));
1149
1150        if let Tov::Time(t) = tov_time {
1151            assert_eq!(t, time);
1152        }
1153
1154        // Test conversion from Option<CuTime>
1155        let some_time = Some(time);
1156        let tov_some: Tov = some_time.into();
1157        assert!(matches!(tov_some, Tov::Time(_)));
1158
1159        let none_time: Option<CuDuration> = None;
1160        let tov_none: Tov = none_time.into();
1161        assert!(matches!(tov_none, Tov::None));
1162
1163        // Test range
1164        let start = CuTime::from(100u64);
1165        let end = CuTime::from(200u64);
1166        let range = CuTimeRange { start, end };
1167        let tov_range = Tov::Range(range);
1168
1169        assert!(matches!(tov_range, Tov::Range(_)));
1170    }
1171
1172    #[cfg(feature = "std")]
1173    #[test]
1174    fn test_cuduration_display() {
1175        // Test the display implementation for different magnitudes
1176        let nano = CuDuration(42);
1177        assert_eq!(nano.to_string(), "42 ns");
1178
1179        let micro = CuDuration(42_000);
1180        assert_eq!(micro.to_string(), "42.000 µs");
1181
1182        let milli = CuDuration(42_000_000);
1183        assert_eq!(milli.to_string(), "42.000 ms");
1184
1185        let sec = CuDuration(1_500_000_000);
1186        assert_eq!(sec.to_string(), "1.500 s");
1187
1188        let min = CuDuration(90_000_000_000);
1189        assert_eq!(min.to_string(), "1.500 m");
1190
1191        let hour = CuDuration(3_600_000_000_000);
1192        assert_eq!(hour.to_string(), "1.000 h");
1193
1194        let day = CuDuration(86_400_000_000_000);
1195        assert_eq!(day.to_string(), "1.000 d");
1196    }
1197
1198    #[test]
1199    fn test_robot_clock_precision() {
1200        // Test that RobotClock::now() and RobotClock::recent() return different values
1201        // and that recent() is always <= now()
1202        let clock = RobotClock::new();
1203
1204        // We can't guarantee the exact values, but we can check relationships
1205        let recent = clock.recent();
1206        let now = clock.now();
1207
1208        // recent() should be less than or equal to now()
1209        assert!(recent <= now);
1210
1211        // Test precision of from_ref_time
1212        let ref_time_ns = 1_000_000_000; // 1 second
1213        let clock = RobotClock::from_ref_time(ref_time_ns);
1214
1215        // Clock should start at approximately ref_time_ns
1216        let now = clock.now();
1217        let now_ns: u64 = now.into();
1218
1219        // Allow reasonable tolerance for clock initialization time
1220        let tolerance_ns = 50_000_000; // 50ms tolerance
1221        assert!(now_ns >= ref_time_ns);
1222        assert!(now_ns < ref_time_ns + tolerance_ns);
1223    }
1224
1225    #[test]
1226    fn test_mock_clock_advanced_operations() {
1227        // Test more complex operations with the mock clock
1228        let (clock, mock) = RobotClock::mock();
1229
1230        // Test initial state
1231        assert_eq!(clock.now(), CuTime::from(0));
1232
1233        // Test increment
1234        mock.increment(CuDuration::from_secs(10));
1235        assert_eq!(
1236            clock.now(),
1237            CuTime::from_nanos(CuDuration::from_secs(10).as_nanos())
1238        );
1239
1240        // Test decrement (unusual but supported)
1241        mock.decrement(CuDuration::from_secs(5));
1242        assert_eq!(
1243            clock.now(),
1244            CuTime::from_nanos(CuDuration::from_secs(5).as_nanos())
1245        );
1246
1247        // Test setting absolute value
1248        mock.set_value(30_000_000_000); // 30 seconds in ns
1249        assert_eq!(
1250            clock.now(),
1251            CuTime::from_nanos(CuDuration::from_secs(30).as_nanos())
1252        );
1253
1254        // Test that getting the time from the mock directly works
1255        assert_eq!(
1256            mock.now(),
1257            CuTime::from_nanos(CuDuration::from_secs(30).as_nanos())
1258        );
1259        assert_eq!(mock.value(), 30_000_000_000);
1260    }
1261
1262    #[test]
1263    fn test_cuduration_min_max() {
1264        // Test MIN and MAX constants
1265        assert_eq!(CuDuration::MIN, CuDuration(0));
1266
1267        // Test min/max methods
1268        let a = CuDuration(100);
1269        let b = CuDuration(200);
1270
1271        assert_eq!(a.min(b), a);
1272        assert_eq!(a.max(b), b);
1273        assert_eq!(b.min(a), a);
1274        assert_eq!(b.max(a), b);
1275
1276        // Edge cases
1277        assert_eq!(a.min(a), a);
1278        assert_eq!(a.max(a), a);
1279
1280        // Test with MIN/MAX constants
1281        assert_eq!(a.min(CuDuration::MIN), CuDuration::MIN);
1282        assert_eq!(a.max(CuDuration::MAX), CuDuration::MAX);
1283    }
1284
1285    #[test]
1286    fn test_clock_provider_trait() {
1287        // Test implementing the ClockProvider trait
1288        struct TestClockProvider {
1289            clock: RobotClock,
1290        }
1291
1292        impl ClockProvider for TestClockProvider {
1293            fn get_clock(&self) -> RobotClock {
1294                self.clock.clone()
1295            }
1296        }
1297
1298        // Create a provider with a mock clock
1299        let (clock, mock) = RobotClock::mock();
1300        let provider = TestClockProvider { clock };
1301
1302        // Test that provider returns a clock synchronized with the original
1303        let provider_clock = provider.get_clock();
1304        assert_eq!(provider_clock.now(), CuTime::from(0));
1305
1306        // Advance the mock clock and check that the provider's clock also advances
1307        mock.increment(CuDuration::from_secs(5));
1308        assert_eq!(
1309            provider_clock.now(),
1310            CuTime::from_nanos(CuDuration::from_secs(5).as_nanos())
1311        );
1312    }
1313}