Skip to main content

statime_base/
clock.rs

1use crate::{Duration, Timestamp};
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6/// Errors than can occur when interacting with a clock
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ClockError {
9    /// Insufficient permissions to perform the requested operation
10    PermissionDenied,
11    /// The underlying clock device is no longer available
12    NoDevice,
13    /// The requested operation is not supported by the clock or OS
14    NotSupported,
15    /// One of the provided values is invalid
16    InvalidValue,
17    /// An unknown error occured when interacting with the clock
18    Unknown,
19}
20
21impl core::fmt::Display for ClockError {
22    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
23        match self {
24            ClockError::PermissionDenied => {
25                f.write_str("Insufficient permissions to perform the requested operation.")
26            }
27            ClockError::NoDevice => {
28                f.write_str("The underlying clock device is no longer available")
29            }
30            ClockError::NotSupported => {
31                f.write_str("The requested operation is not supported by the clock or OS.")
32            }
33            ClockError::InvalidValue => f.write_str("One of the provided values is invalid."),
34            ClockError::Unknown => {
35                f.write_str("An unknown error occured when interacting with the clock.")
36            }
37        }
38    }
39}
40
41impl core::error::Error for ClockError {}
42
43/// Interface for a controllable clock
44/// This needs to be a trait as a single system can have multiple clocks
45/// which need different implementation for steering and/or now.
46pub trait Clock<Timescale>: Clone + Send + 'static {
47    /// Get current time
48    ///
49    /// # Errors
50    /// Should return an error if the clock is unable to provide a timestamp.
51    fn now(&self) -> Result<Timestamp<Timescale>, ClockError>;
52
53    /// Change the frequency of the clock, returning the time
54    /// at which the change was applied. The frequency is
55    /// in seconds per second deviation.
56    ///
57    /// # Errors
58    /// Should return an error if the clock is unable to be steered by the requested amount.
59    fn set_frequency(&self, freq: f64) -> Result<Timestamp<Timescale>, ClockError>;
60
61    /// Get the frequency of the clock, in seconds per second deviation
62    ///
63    /// # Errors
64    /// Should return an error if the clock is unable to provide its current steering frequency.
65    fn get_frequency(&self) -> Result<f64, ClockError>;
66
67    /// Maximum frequency offset the clock is capable of, in seconds per second deviation.
68    ///
69    /// # Errors
70    /// Should return an error if the maximum frequency offset could not be determined.
71    fn max_frequency(&self) -> Result<f64, ClockError>;
72
73    /// Change the current time of the clock by offset. Returns
74    /// the time at which the change was applied.
75    ///
76    /// # Errors
77    /// Should return an error if the clock cannot be stepped by the amount requested.
78    fn step_clock(&self, offset: Duration) -> Result<Timestamp<Timescale>, ClockError>;
79
80    /// Provide the system with our current best estimates for
81    /// the statistical error of the clock (`est_error`), and
82    /// the maximum deviation due to frequency error and
83    /// distance to the root clock.
84    ///
85    /// # Errors
86    /// Should return an error if the error estimate update cannot be applied to the clock.
87    fn error_estimate_update(
88        &self,
89        est_error: Duration,
90        max_error: Duration,
91    ) -> Result<(), ClockError>;
92
93    /// Change the indicators for upcoming leap seconds. Application should happen at the end of the UTC month.
94    ///
95    /// # Errors
96    /// Should return an error if the status update cannot be applied to the clock.
97    fn leap_update(&self, leap_status: LeapStatus) -> Result<(), ClockError>;
98
99    /// Change the synchronization indicator.
100    ///
101    /// # Errors
102    /// should return an error if the synchronization indicator cannot be updated
103    fn synchronization_update(&self, synchronized: bool) -> Result<(), ClockError>;
104}
105
106/// Information on what the next leap second is going to be.
107#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109pub enum LeapStatus {
110    /// There is no leap second at the end of the month.
111    #[default]
112    None,
113    /// A second needs to be removed from the last minute of the month.
114    Leap59,
115    /// A second needs to be inserted into the last minute of the month.
116    Leap61,
117}