pigweed / third_party / github / zephyrproject-rtos / zephyr / aaaed300713d241bb222feb769b43eb32c446b33 / . / include / zephyr / sys / timeutil.h

/* | |

* Copyright (c) 2019 Peter Bigot Consulting, LLC | |

* | |

* SPDX-License-Identifier: Apache-2.0 | |

*/ | |

/** | |

* @file | |

* @brief Utilities supporting operation on time data structures. | |

* | |

* POSIX defines gmtime() to convert from time_t to struct tm, but all | |

* inverse transformations are non-standard or require access to time | |

* zone information. timeutil_timegm() implements the functionality | |

* of the GNU extension timegm() function, but changes the error value | |

* as @c EOVERFLOW is not a standard C error identifier. | |

* | |

* timeutil_timegm64() is provided to support full precision | |

* conversion on platforms where @c time_t is limited to 32 bits. | |

*/ | |

#ifndef ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_ | |

#define ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_ | |

#include <time.h> | |

#include <zephyr/types.h> | |

#ifdef __cplusplus | |

extern "C" { | |

#endif | |

/** | |

* @defgroup timeutil_apis Time Utility APIs | |

* @defgroup timeutil_repr_apis Time Representation APIs | |

* @ingroup timeutil_apis | |

* @{ | |

*/ | |

/** | |

* @brief Convert broken-down time to a POSIX epoch offset in seconds. | |

* | |

* @param tm pointer to broken down time. | |

* | |

* @return the corresponding time in the POSIX epoch time scale. | |

* | |

* @see http://man7.org/linux/man-pages/man3/timegm.3.html | |

*/ | |

int64_t timeutil_timegm64(const struct tm *tm); | |

/** | |

* @brief Convert broken-down time to a POSIX epoch offset in seconds. | |

* | |

* @param tm pointer to broken down time. | |

* | |

* @return the corresponding time in the POSIX epoch time scale. If | |

* the time cannot be represented then @c (time_t)-1 is returned and | |

* @c errno is set to @c ERANGE`. | |

* | |

* @see http://man7.org/linux/man-pages/man3/timegm.3.html | |

*/ | |

time_t timeutil_timegm(const struct tm *tm); | |

/** | |

* @} | |

* @defgroup timeutil_sync_apis Time Synchronization APIs | |

* @ingroup timeutil_apis | |

* @{ | |

*/ | |

/** | |

* @brief Immutable state for synchronizing two clocks. | |

* | |

* Values required to convert durations between two time scales. | |

* | |

* @note The accuracy of the translation and calculated skew between sources | |

* depends on the resolution of these frequencies. A reference frequency with | |

* microsecond or nanosecond resolution would produce the most accurate | |

* tracking when the local reference is the Zephyr tick counter. A reference | |

* source like an RTC chip with 1 Hz resolution requires a much larger | |

* interval between sampled instants to detect relative clock drift. | |

*/ | |

struct timeutil_sync_config { | |

/** The nominal instance counter rate in Hz. | |

* | |

* This value is assumed to be precise, but may drift depending on | |

* the reference clock source. | |

* | |

* The value must be positive. | |

*/ | |

uint32_t ref_Hz; | |

/** The nominal local counter rate in Hz. | |

* | |

* This value is assumed to be inaccurate but reasonably stable. For | |

* a local clock driven by a crystal oscillator an error of 25 ppm is | |

* common; for an RC oscillator larger errors should be expected. The | |

* timeutil_sync infrastructure can calculate the skew between the | |

* local and reference clocks and apply it when converting between | |

* time scales. | |

* | |

* The value must be positive. | |

*/ | |

uint32_t local_Hz; | |

}; | |

/** | |

* @brief Representation of an instant in two time scales. | |

* | |

* Capturing the same instant in two time scales provides a | |

* registration point that can be used to convert between those time | |

* scales. | |

*/ | |

struct timeutil_sync_instant { | |

/** An instant in the reference time scale. | |

* | |

* This must never be zero in an initialized timeutil_sync_instant | |

* object. | |

*/ | |

uint64_t ref; | |

/** The corresponding instance in the local time scale. | |

* | |

* This may be zero in a valid timeutil_sync_instant object. | |

*/ | |

uint64_t local; | |

}; | |

/** | |

* @brief State required to convert instants between time scales. | |

* | |

* This state in conjunction with functions that manipulate it capture | |

* the offset information necessary to convert between two timescales | |

* along with information that corrects for skew due to inaccuracies | |

* in clock rates. | |

* | |

* State objects should be zero-initialized before use. | |

*/ | |

struct timeutil_sync_state { | |

/** Pointer to reference and local rate information. */ | |

const struct timeutil_sync_config *cfg; | |

/** The base instant in both time scales. */ | |

struct timeutil_sync_instant base; | |

/** The most recent instant in both time scales. | |

* | |

* This is captured here to provide data for skew calculation. | |

*/ | |

struct timeutil_sync_instant latest; | |

/** The scale factor used to correct for clock skew. | |

* | |

* The nominal rate for the local counter is assumed to be | |

* inaccurate but stable, i.e. it will generally be some | |

* parts-per-million faster or slower than specified. | |

* | |

* A duration in observed local clock ticks must be multiplied by | |

* this value to produce a duration in ticks of a clock operating at | |

* the nominal local rate. | |

* | |

* A zero value indicates that the skew has not been initialized. | |

* If the value is zero when #base is initialized the skew will be | |

* set to 1. Otherwise the skew is assigned through | |

* timeutil_sync_state_set_skew(). | |

*/ | |

float skew; | |

}; | |

/** | |

* @brief Record a new instant in the time synchronization state. | |

* | |

* Note that this updates only the latest persisted instant. The skew | |

* is not adjusted automatically. | |

* | |

* @param tsp pointer to a timeutil_sync_state object. | |

* | |

* @param inst the new instant to be recorded. This becomes the base | |

* instant if there is no base instant, otherwise the value must be | |

* strictly after the base instant in both the reference and local | |

* time scales. | |

* | |

* @retval 0 if installation succeeded in providing a new base | |

* @retval 1 if installation provided a new latest instant | |

* @retval -EINVAL if the new instant is not compatible with the base instant | |

*/ | |

int timeutil_sync_state_update(struct timeutil_sync_state *tsp, | |

const struct timeutil_sync_instant *inst); | |

/** | |

* @brief Update the state with a new skew and possibly base value. | |

* | |

* Set the skew from a value retrieved from persistent storage, or | |

* calculated based on recent skew estimations including from | |

* timeutil_sync_estimate_skew(). | |

* | |

* Optionally update the base timestamp. If the base is replaced the | |

* latest instant will be cleared until timeutil_sync_state_update() is | |

* invoked. | |

* | |

* @param tsp pointer to a time synchronization state. | |

* | |

* @param skew the skew to be used. The value must be positive and | |

* shouldn't be too far away from 1. | |

* | |

* @param base optional new base to be set. If provided this becomes | |

* the base timestamp that will be used along with skew to convert | |

* between reference and local timescale instants. Setting the base | |

* clears the captured latest value. | |

* | |

* @return 0 if skew was updated | |

* @return -EINVAL if skew was not valid | |

*/ | |

int timeutil_sync_state_set_skew(struct timeutil_sync_state *tsp, float skew, | |

const struct timeutil_sync_instant *base); | |

/** | |

* @brief Estimate the skew based on current state. | |

* | |

* Using the base and latest syncpoints from the state determine the | |

* skew of the local clock relative to the reference clock. See | |

* timeutil_sync_state::skew. | |

* | |

* @param tsp pointer to a time synchronization state. The base and latest | |

* syncpoints must be present and the latest syncpoint must be after | |

* the base point in the local time scale. | |

* | |

* @return the estimated skew, or zero if skew could not be estimated. | |

*/ | |

float timeutil_sync_estimate_skew(const struct timeutil_sync_state *tsp); | |

/** | |

* @brief Interpolate a reference timescale instant from a local | |

* instant. | |

* | |

* @param tsp pointer to a time synchronization state. This must have a base | |

* and a skew installed. | |

* | |

* @param local an instant measured in the local timescale. This may | |

* be before or after the base instant. | |

* | |

* @param refp where the corresponding instant in the reference | |

* timescale should be stored. A negative interpolated reference time | |

* produces an error. If interpolation fails the referenced object is | |

* not modified. | |

* | |

* @retval 0 if interpolated using a skew of 1 | |

* @retval 1 if interpolated using a skew not equal to 1 | |

* @retval -EINVAL | |

* * the times synchronization state is not adequately initialized | |

* * @p refp is null | |

* @retval -ERANGE the interpolated reference time would be negative | |

*/ | |

int timeutil_sync_ref_from_local(const struct timeutil_sync_state *tsp, | |

uint64_t local, uint64_t *refp); | |

/** | |

* @brief Interpolate a local timescale instant from a reference | |

* instant. | |

* | |

* @param tsp pointer to a time synchronization state. This must have a base | |

* and a skew installed. | |

* | |

* @param ref an instant measured in the reference timescale. This | |

* may be before or after the base instant. | |

* | |

* @param localp where the corresponding instant in the local | |

* timescale should be stored. An interpolated value before local | |

* time 0 is provided without error. If interpolation fails the | |

* referenced object is not modified. | |

* | |

* @retval 0 if successful with a skew of 1 | |

* @retval 1 if successful with a skew not equal to 1 | |

* @retval -EINVAL | |

* * the time synchronization state is not adequately initialized | |

* * @p refp is null | |

*/ | |

int timeutil_sync_local_from_ref(const struct timeutil_sync_state *tsp, | |

uint64_t ref, int64_t *localp); | |

/** | |

* @brief Convert from a skew to an error in parts-per-billion. | |

* | |

* A skew of 1.0 has zero error. A skew less than 1 has a positive | |

* error (clock is faster than it should be). A skew greater than one | |

* has a negative error (clock is slower than it should be). | |

* | |

* Note that due to the limited precision of @c float compared with @c | |

* double the smallest error that can be represented is about 120 ppb. | |

* A "precise" time source may have error on the order of 2000 ppb. | |

* | |

* A skew greater than 3.14748 may underflow the 32-bit | |

* representation; this represents a clock running at less than 1/3 | |

* its nominal rate. | |

* | |

* @return skew error represented as parts-per-billion, or INT32_MIN | |

* if the skew cannot be represented in the return type. | |

*/ | |

int32_t timeutil_sync_skew_to_ppb(float skew); | |

#ifdef __cplusplus | |

} | |

#endif | |

/** | |

* @} | |

*/ | |

#endif /* ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_ */ |