LCOV - code coverage report
Current view: top level - zephyr/sys - timeutil.h Hit Total Coverage
Test: new.info Lines: 20 21 95.2 %
Date: 2024-12-22 00:14:23

          Line data    Source code
       1           1 : /*
       2             :  * Copyright (c) 2019 Peter Bigot Consulting, LLC
       3             :  *
       4             :  * SPDX-License-Identifier: Apache-2.0
       5             :  */
       6             : 
       7             : /**
       8             :  * @file
       9             :  * @brief Utilities supporting operation on time data structures.
      10             :  *
      11             :  * POSIX defines gmtime() to convert from time_t to struct tm, but all
      12             :  * inverse transformations are non-standard or require access to time
      13             :  * zone information.  timeutil_timegm() implements the functionality
      14             :  * of the GNU extension timegm() function, but changes the error value
      15             :  * as @c EOVERFLOW is not a standard C error identifier.
      16             :  *
      17             :  * timeutil_timegm64() is provided to support full precision
      18             :  * conversion on platforms where @c time_t is limited to 32 bits.
      19             :  */
      20             : 
      21             : #ifndef ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_
      22             : #define ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_
      23             : 
      24             : #include <time.h>
      25             : 
      26             : #include <zephyr/types.h>
      27             : 
      28             : #ifdef __cplusplus
      29             : extern "C" {
      30             : #endif
      31             : 
      32             : /**
      33             :  * @defgroup timeutil_apis Time Utility APIs
      34             :  * @ingroup utilities
      35             :  * @defgroup timeutil_repr_apis Time Representation APIs
      36             :  * @ingroup timeutil_apis
      37             :  * @{
      38             :  */
      39             : 
      40             : /* Base Year value use in calculations in "timeutil_timegm64" API */
      41           0 : #define TIME_UTILS_BASE_YEAR 1900
      42             : 
      43             : /**
      44             :  * @brief Convert broken-down time to a POSIX epoch offset in seconds.
      45             :  *
      46             :  * @param tm pointer to broken down time.
      47             :  *
      48             :  * @return the corresponding time in the POSIX epoch time scale.
      49             :  *
      50             :  * @see http://man7.org/linux/man-pages/man3/timegm.3.html
      51             :  */
      52           1 : int64_t timeutil_timegm64(const struct tm *tm);
      53             : 
      54             : /**
      55             :  * @brief Convert broken-down time to a POSIX epoch offset in seconds.
      56             :  *
      57             :  * @param tm pointer to broken down time.
      58             :  *
      59             :  * @return the corresponding time in the POSIX epoch time scale.  If
      60             :  * the time cannot be represented then @c (time_t)-1 is returned and
      61             :  * @c errno is set to @c ERANGE`.
      62             :  *
      63             :  * @see http://man7.org/linux/man-pages/man3/timegm.3.html
      64             :  */
      65           1 : time_t timeutil_timegm(const struct tm *tm);
      66             : 
      67             : /**
      68             :  * @}
      69             :  * @defgroup timeutil_sync_apis Time Synchronization APIs
      70             :  * @ingroup timeutil_apis
      71             :  * @{
      72             :  */
      73             : 
      74             : /**
      75             :  * @brief Immutable state for synchronizing two clocks.
      76             :  *
      77             :  * Values required to convert durations between two time scales.
      78             :  *
      79             :  * @note The accuracy of the translation and calculated skew between sources
      80             :  * depends on the resolution of these frequencies.  A reference frequency with
      81             :  * microsecond or nanosecond resolution would produce the most accurate
      82             :  * tracking when the local reference is the Zephyr tick counter.  A reference
      83             :  * source like an RTC chip with 1 Hz resolution requires a much larger
      84             :  * interval between sampled instants to detect relative clock drift.
      85             :  */
      86           1 : struct timeutil_sync_config {
      87             :         /** The nominal instance counter rate in Hz.
      88             :          *
      89             :          * This value is assumed to be precise, but may drift depending on
      90             :          * the reference clock source.
      91             :          *
      92             :          * The value must be positive.
      93             :          */
      94           1 :         uint32_t ref_Hz;
      95             : 
      96             :         /** The nominal local counter rate in Hz.
      97             :          *
      98             :          * This value is assumed to be inaccurate but reasonably stable.  For
      99             :          * a local clock driven by a crystal oscillator an error of 25 ppm is
     100             :          * common; for an RC oscillator larger errors should be expected.  The
     101             :          * timeutil_sync infrastructure can calculate the skew between the
     102             :          * local and reference clocks and apply it when converting between
     103             :          * time scales.
     104             :          *
     105             :          * The value must be positive.
     106             :          */
     107           1 :         uint32_t local_Hz;
     108             : };
     109             : 
     110             : /**
     111             :  * @brief Representation of an instant in two time scales.
     112             :  *
     113             :  * Capturing the same instant in two time scales provides a
     114             :  * registration point that can be used to convert between those time
     115             :  * scales.
     116             :  */
     117           1 : struct timeutil_sync_instant {
     118             :         /** An instant in the reference time scale.
     119             :          *
     120             :          * This must never be zero in an initialized timeutil_sync_instant
     121             :          * object.
     122             :          */
     123           1 :         uint64_t ref;
     124             : 
     125             :         /** The corresponding instance in the local time scale.
     126             :          *
     127             :          * This may be zero in a valid timeutil_sync_instant object.
     128             :          */
     129           1 :         uint64_t local;
     130             : };
     131             : 
     132             : /**
     133             :  * @brief State required to convert instants between time scales.
     134             :  *
     135             :  * This state in conjunction with functions that manipulate it capture
     136             :  * the offset information necessary to convert between two timescales
     137             :  * along with information that corrects for skew due to inaccuracies
     138             :  * in clock rates.
     139             :  *
     140             :  * State objects should be zero-initialized before use.
     141             :  */
     142           1 : struct timeutil_sync_state {
     143             :         /** Pointer to reference and local rate information. */
     144           1 :         const struct timeutil_sync_config *cfg;
     145             : 
     146             :         /** The base instant in both time scales. */
     147           1 :         struct timeutil_sync_instant base;
     148             : 
     149             :         /** The most recent instant in both time scales.
     150             :          *
     151             :          * This is captured here to provide data for skew calculation.
     152             :          */
     153           1 :         struct timeutil_sync_instant latest;
     154             : 
     155             :         /** The scale factor used to correct for clock skew.
     156             :          *
     157             :          * The nominal rate for the local counter is assumed to be
     158             :          * inaccurate but stable, i.e. it will generally be some
     159             :          * parts-per-million faster or slower than specified.
     160             :          *
     161             :          * A duration in observed local clock ticks must be multiplied by
     162             :          * this value to produce a duration in ticks of a clock operating at
     163             :          * the nominal local rate.
     164             :          *
     165             :          * A zero value indicates that the skew has not been initialized.
     166             :          * If the value is zero when #base is initialized the skew will be
     167             :          * set to 1.  Otherwise the skew is assigned through
     168             :          * timeutil_sync_state_set_skew().
     169             :          */
     170           1 :         float skew;
     171             : };
     172             : 
     173             : /**
     174             :  * @brief Record a new instant in the time synchronization state.
     175             :  *
     176             :  * Note that this updates only the latest persisted instant.  The skew
     177             :  * is not adjusted automatically.
     178             :  *
     179             :  * @param tsp pointer to a timeutil_sync_state object.
     180             :  *
     181             :  * @param inst the new instant to be recorded.  This becomes the base
     182             :  * instant if there is no base instant, otherwise the value must be
     183             :  * strictly after the base instant in both the reference and local
     184             :  * time scales.
     185             :  *
     186             :  * @retval 0 if installation succeeded in providing a new base
     187             :  * @retval 1 if installation provided a new latest instant
     188             :  * @retval -EINVAL if the new instant is not compatible with the base instant
     189             :  */
     190           1 : int timeutil_sync_state_update(struct timeutil_sync_state *tsp,
     191             :                                const struct timeutil_sync_instant *inst);
     192             : 
     193             : /**
     194             :  * @brief Update the state with a new skew and possibly base value.
     195             :  *
     196             :  * Set the skew from a value retrieved from persistent storage, or
     197             :  * calculated based on recent skew estimations including from
     198             :  * timeutil_sync_estimate_skew().
     199             :  *
     200             :  * Optionally update the base timestamp.  If the base is replaced the
     201             :  * latest instant will be cleared until timeutil_sync_state_update() is
     202             :  * invoked.
     203             :  *
     204             :  * @param tsp pointer to a time synchronization state.
     205             :  *
     206             :  * @param skew the skew to be used.  The value must be positive and
     207             :  * shouldn't be too far away from 1.
     208             :  *
     209             :  * @param base optional new base to be set.  If provided this becomes
     210             :  * the base timestamp that will be used along with skew to convert
     211             :  * between reference and local timescale instants.  Setting the base
     212             :  * clears the captured latest value.
     213             :  *
     214             :  * @return 0 if skew was updated
     215             :  * @return -EINVAL if skew was not valid
     216             :  */
     217           1 : int timeutil_sync_state_set_skew(struct timeutil_sync_state *tsp, float skew,
     218             :                                  const struct timeutil_sync_instant *base);
     219             : 
     220             : /**
     221             :  * @brief Estimate the skew based on current state.
     222             :  *
     223             :  * Using the base and latest syncpoints from the state determine the
     224             :  * skew of the local clock relative to the reference clock.  See
     225             :  * timeutil_sync_state::skew.
     226             :  *
     227             :  * @param tsp pointer to a time synchronization state.  The base and latest
     228             :  * syncpoints must be present and the latest syncpoint must be after
     229             :  * the base point in the local time scale.
     230             :  *
     231             :  * @return the estimated skew, or zero if skew could not be estimated.
     232             :  */
     233           1 : float timeutil_sync_estimate_skew(const struct timeutil_sync_state *tsp);
     234             : 
     235             : /**
     236             :  * @brief Interpolate a reference timescale instant from a local
     237             :  * instant.
     238             :  *
     239             :  * @param tsp pointer to a time synchronization state.  This must have a base
     240             :  * and a skew installed.
     241             :  *
     242             :  * @param local an instant measured in the local timescale.  This may
     243             :  * be before or after the base instant.
     244             :  *
     245             :  * @param refp where the corresponding instant in the reference
     246             :  * timescale should be stored.  A negative interpolated reference time
     247             :  * produces an error.  If interpolation fails the referenced object is
     248             :  * not modified.
     249             :  *
     250             :  * @retval 0 if interpolated using a skew of 1
     251             :  * @retval 1 if interpolated using a skew not equal to 1
     252             :  * @retval -EINVAL
     253             :  *   * the times synchronization state is not adequately initialized
     254             :  *   * @p refp is null
     255             :  * @retval -ERANGE the interpolated reference time would be negative
     256             :  */
     257           1 : int timeutil_sync_ref_from_local(const struct timeutil_sync_state *tsp,
     258             :                                  uint64_t local, uint64_t *refp);
     259             : 
     260             : /**
     261             :  * @brief Interpolate a local timescale instant from a reference
     262             :  * instant.
     263             :  *
     264             :  * @param tsp pointer to a time synchronization state.  This must have a base
     265             :  * and a skew installed.
     266             :  *
     267             :  * @param ref an instant measured in the reference timescale.  This
     268             :  * may be before or after the base instant.
     269             :  *
     270             :  * @param localp where the corresponding instant in the local
     271             :  * timescale should be stored.  An interpolated value before local
     272             :  * time 0 is provided without error.  If interpolation fails the
     273             :  * referenced object is not modified.
     274             :  *
     275             :  * @retval 0 if successful with a skew of 1
     276             :  * @retval 1 if successful with a skew not equal to 1
     277             :  * @retval -EINVAL
     278             :  *   * the time synchronization state is not adequately initialized
     279             :  *   * @p refp is null
     280             :  */
     281           1 : int timeutil_sync_local_from_ref(const struct timeutil_sync_state *tsp,
     282             :                                  uint64_t ref, int64_t *localp);
     283             : 
     284             : /**
     285             :  * @brief Convert from a skew to an error in parts-per-billion.
     286             :  *
     287             :  * A skew of 1.0 has zero error.  A skew less than 1 has a positive
     288             :  * error (clock is faster than it should be).  A skew greater than one
     289             :  * has a negative error (clock is slower than it should be).
     290             :  *
     291             :  * Note that due to the limited precision of @c float compared with @c
     292             :  * double the smallest error that can be represented is about 120 ppb.
     293             :  * A "precise" time source may have error on the order of 2000 ppb.
     294             :  *
     295             :  * A skew greater than 3.14748 may underflow the 32-bit
     296             :  * representation; this represents a clock running at less than 1/3
     297             :  * its nominal rate.
     298             :  *
     299             :  * @return skew error represented as parts-per-billion, or INT32_MIN
     300             :  * if the skew cannot be represented in the return type.
     301             :  */
     302           1 : int32_t timeutil_sync_skew_to_ppb(float skew);
     303             : 
     304             : #ifdef __cplusplus
     305             : }
     306             : #endif
     307             : 
     308             : /**
     309             :  * @}
     310             :  */
     311             : 
     312             : #endif /* ZEPHYR_INCLUDE_SYS_TIMEUTIL_H_ */

Generated by: LCOV version 1.14