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}