/* * (c) Copyright, Real-Time Innovations, 2005-2024. * All rights reserved. * * No duplications, whole or partial, manual or electronic, may be made * without express written permission. Any such copies, or * revisions thereof, must display this notice unaltered. * This code contains trade secrets of Real-Time Innovations, Inc. */ #ifndef osapi_ntptime_h #define osapi_ntptime_h #include "osapi/osapi_type.h" #include "osapi/osapi_dll.h" #if defined(RTI_VXWORKS) #include "osapi/osapi_vxVersions.h" #if VXWORKS_VERSION_6_3_OR_BETTER #include #endif #elif defined(RTI_WIN32) #include #elif defined(RTI_UNIX) || defined(RTI_LYNX) || defined(RTI_QNX) \ || defined(RTI_INTIME) #if defined(RTI_LYNX) && !defined(RTI_LYNXOS_SE) && !defined(RTI_LYNX500) #include #else #include #endif #elif defined(RTI_INTY) #include #endif #ifdef RTI_64BIT_TIME_T #define RTI_TIME_T time_t #else #define RTI_TIME_T RTI_INT64 #endif #ifdef __cplusplus extern "C" { #endif /** @internal \file * \brief NTP time API */ /** @internal \defgroup RTINtpTimeClass RTINtpTime * \ingroup RTIOsapiModule * * @brief NTP Time representation. * * Expresses time in NTP format. The second field is simply an integer * expressing seconds. The fraction field expresses 1/2^32 of a second. * We strongly urge customers to use our provided macros to convert this * format to and from human readable form. * * When working with RTINtpTime there isn't a concrete INFINITY value defined. * For all practical purposes, we consider the maximum value, and every other * value above this maximum as INFINITY. To check for INFINITY, use the * RTINtpTime_isInfinite macro. Never check for a specific value. * * \b Example: * * The following is a simple example on how to prepare a RTINtpTime structure * to be 1.5 seconds. * * \verbatim * RTINtpTime ntpTime; * * RTINtpTime_packFromMillisec(ntpTime, 1, 500); * \endverbatim * * @see RTINtpTime_packFromMillisec RTINtpTime_packFromMicrosec * @see RTINtpTime_packFromNanosec * @see RtiNtpTimeUnpackFromMillisec RtiNtpTimeUnpackFromMicrosec * @see RtiNtpTimeUnpackFromNanosec */ typedef struct RTINtpTime { /** @internal Seconds.**/ RTI_INT64 sec; /** @internal fraction of a second in 1/2^32 form.*/ RTI_UINT32 frac; } RTINtpTime; /** @internal \ingroup RTINtpTimeClass * \brief The size of a serialized RTINtpTime. */ #define RTI_OSAPI_NTPTIME_SERIALIZED_SIZE \ (sizeof(RTI_INT64) + sizeof(RTI_UINT32)) /** @internal \ingroup RTINtpTimeClass Represents infinite time value. Handy for specifying no timeout or sleeping forever. */ #define RTI_NTP_TIME_INFINITE ((RTINtpTime *) NULL) /** @internal \ingroup RTINtpTimeClass @brief Zero time. This global variable is for convenience. This allows users to check and see if a RTITime variable is negative or positive by comparing against this. @see RtiTimeCompare */ #define RTI_NTP_TIME_ZERO \ { \ 0, 0 \ } /** @internal \ingroup RTINtpTimeClass Represents maximum timevalue that can be represented using the NTP time format. For all practical purposes, can be considered equivalent to infinity. */ #define RTI_NTP_TIME_MAX \ { \ RTI_NTP_TIME_SEC_MAX, RTI_NTP_TIME_FRAC_MAX \ } /** @internal \ingroup RTINtpTimeClass The maximum number of seconds, 4294967295, that can be represented using NTP time. This value is the maximum range of an unsigned 32-bit. */ #define RTI_NTP_TIME_SEC_MAX 0x00000000FFFFFFFFLL /** @internal * \ingroup RTINtpTimeClass * The minimum number of seconds that can be represented using NTP time. * This value, 0xFFFFFFFF00000001 represent the -4294967295 in two's complement. */ #define RTI_NTP_TIME_SEC_MIN ((RTI_INT64) 0xFFFFFFFF00000001) /** @internal \ingroup RTINtpTimeClass The largest possible value of the fraction field in NTP time. */ #define RTI_NTP_TIME_FRAC_MAX ((RTI_UINT32) 0xffffffff) /** @internal \ingroup RTINtpTimeClass The AUTO value semantic depends on the usage. */ #define RTI_NTP_TIME_AUTO \ { \ RTI_NTP_TIME_SEC_AUTO, RTI_NTP_TIME_FRAC_AUTO \ } /** @internal \ingroup RTINtpTimeClass The number of seconds corresponding to RTI_NTP_TIME_AUTO. */ #define RTI_NTP_TIME_SEC_AUTO ((RTI_INT64) 0xffffffffffffffff) /** @internal \ingroup RTINtpTimeClass The fraction of seconds corresponding to RTI_NTP_TIME_AUTO. */ #define RTI_NTP_TIME_FRAC_AUTO 0U /** @internal \ingroup RTINtpTimeClass The number of seconds corresponding to RTI_NTP_TIME_INVALID. */ #define RTI_NTP_TIME_SEC_INVALID ((RTI_INT64) 0xffffffffffffffff) /** @internal \ingroup RTINtpTimeClass The fraction of seconds corresponding to RTI_NTP_TIME_INVALID. */ #define RTI_NTP_TIME_FRAC_INVALID RTI_NTP_TIME_FRAC_MAX /** @internal * \ingroup RTINtpTimeClass * * @brief Invalid time. * * Represents an invalid timevalue that can be represented using the NTP time * format. */ #define RTI_NTP_TIME_INVALID \ { \ RTI_NTP_TIME_SEC_INVALID, RTI_NTP_TIME_FRAC_INVALID \ } /** @internal * @brief This define represents the maximum size of a string containing an * NTP Time. So since the NTP Time structure contains an RTI_INT64, and a * RTI_UINT32 attribute, the value result of the following: * - RTI_INT64: 1 - 19 bytes * - RTI_UINT32: 1 - 9 bytes * - 4 extra characters: '{' + ',' + '}'' + '\0' * 19 + 9 + 4 = 32 */ #define RTI_NTP_TIME_STRING_LEN (32) /** @internal \ingroup RTINtpTimeClass * @brief Set RTINtpTime time to zero. * * @param time (RTINtpTime*) Pointer to RTINtpTime struct that needs to be * set to zero. */ extern RTIOsapiDllExport void RTINtpTime_setZero(struct RTINtpTime *time); /** @internal \ingroup RTINtpTimeClass * @brief Set RTINtpTime time to maximum value. * * @param time (RTINtpTime*) Pointer to RTINtpTime struct that needs to be * set to its maximum possible value. * * The maximum possible value equals: * * (time).sec = RTI_NTP_TIME_SEC_MAX * (time).frac = RTI_NTP_TIME_FRAC_MAX */ extern RTIOsapiDllExport void RTINtpTime_setMax(struct RTINtpTime *time); /** @internal * \ingroup RTINtpTimeClass * * @brief convert to double * * "t" cannot exceed the maximum value supported by an unsigned 32 bit integer * 4294967295. If the value exceeded the limit it will be capped to the maximum. */ extern RTIOsapiDllExport void RTINtpTime_toDouble( const struct RTINtpTime *t, RTI_DOUBLE64 *value); /** @internal * \ingroup RTINtpTimeClass * * @brief convert to RTI_UINT64 * * This functions convert t into an RTIRtpsTime to not overflow. */ extern RTIOsapiDllExport void RTINtpTime_toUInt64( const struct RTINtpTime *t, RTI_UINT64 *value); /** @internal * \ingroup RTINtpTimeClass * * @brief convert to RTINtpTime from an RTI_UINT64 * * This functions first convert value into an RTIRtpsTime and then into an * RTINtpTime. */ extern RTIOsapiDllExport void RTINtpTime_fromUInt64( struct RTINtpTime *t, RTI_UINT64 value); /** @internal \ingroup RTINtpTimeClass * @brief Copy an RTINtpTime struct. * * @param out. The destination of the copy. * @param in. The source of the copy. */ extern RTIOsapiDllExport void RTINtpTime_copy( struct RTINtpTime *out, const struct RTINtpTime *in); /** @internal \ingroup RTINtpTimeClass * * @brief Macro to convert from sec and milli-seconds to RTINtpTime format. * * @param time (RTINtpTime) contains the answer. * @param s (long long) Second to convert. * @param msec (millisecond) fraction portion (less than 1000). * * \verbatim * RTINtpTime time; * RTI_INT64 sec; * RTI_INT32 msec; * sec = 10; * msec = 577; * * RTINtpTime_packFromMillisec(time, sec, msec); * \endverbatim * * After the above call is made, the variable time will contain the equivalent * time stamp in RTINtpTime representation. * * This macro assumes that msec<1000. It is the callers responsibility * to ensure this. This is done for performance reasons, the extra check slows * the execution a factor of 5! If msec may be greater than 1000, you can invoke * the macro as follows: * \verbatim * RTINtpTime_packFromMillisec(time, sec + msec/1000, msec%1000); * \endverbatim * * This macro only evaluates its arguments once, so it is safe to invoke it * with an argument that has side effects, that is. if you write: * \verbatim * RTI_UINT32 count = 10; * RTINtpTime_packFromMillisec(time, sec, count++) * \endverbatim * After the macro count is guaranteed to be 11. * * The accuracy of this conversion over the whole range of millisecond values * is 0.013 milli-seconds. * * This is a fairly efficient macro. On a 400MHz Pentium-II linux box * the execute time is about 0.06 usec. * * \verbatim * 2^22*time.frac = ms + ms/2^6 + ms/2^7 + ms/2^11 + ms/2^14 + 1.3e-5 * = ms + ms*393/2^14; * time.frac = (ms<<22) + (ms<<16) + (ms<<15) + (ms<<11) + (ms<<8) * = (ms<<22) + ((ms*393)<<8) * \endverbatim * * @see RTINtpTime RTINtpTime_unpackToMillisec */ extern RTIOsapiDllExport void RTINtpTime_packFromMillisec( struct RTINtpTime time, long long s, RTI_UINT32 msec); /** @internal \ingroup RTINtpTimeClass * * @brief Macro to convert from RTINtpTime to sec and milli-seconds. * * @param s (long long) Holds the seconds answer. * @param msec (integer) Holds the millisecond answer. * @param time (RTINtpTime) The time to convert to seconds and milliseconds. * * This macro does not check for overflow, so for a near infinite time value, * the conversion result may end up being negative. It is the responsibility * of the user to avoid passing these large time values. * * Use as indicated by the following code: * \verbatim} * RTINtpTime time; * RTI_INT64 sec; * RTI_INT32 msec; * * time.sec = 10; * time.frac = 577; * * RTINtpTime_unpackToMillisec(sec, msec, time); * \endverbatim * * After the above call is made, the variables "sec" and "msec" will * contain the equivalent time stamp. * * The accuracy of this conversion is approx. 0.5 milli-seconds. * * This is a fairly efficient macro. On a 400MHz Pentium-II linux box * the execute time is about 0.08 usec * * \verbatim * ms/2^22 = frac*1000/1024 = frac*(1 - 24/1024) = frac*(1 - 3/2^7) = * frac*(1 - 1/2^6 - 1/2^7) * \endverbatim * * @see RTINtpTime RTINtpTime_packFromMillisec * @todo arguments don't make sense because this is implemented as a macro */ extern RTIOsapiDllExport void RTINtpTime_unpackToMillisec( long long s, unsigned msec, struct RTINtpTime time); /** @internal \ingroup RTINtpTimeClass * * @brief Macro to convert from sec and micro-seconds to RTINtpTime format. * * @param time (RTINtpTime) to contain the answer. * @param s (long long) second of the time to covert. * @param usec (integer) microsecond fraction to convert from. * * This macro does not check for overflow, so for a near infinite time value, * the conversion result may end up being negative. It is the responsibility * of the user to avoid passing these large time values. * * Use as indicated by the following code: * \verbatim * RTINtpTime ntp; * RTI_INT64 sec; * RTI_INT32 usec; * sec = 10; * usec = 577; * * RTINtpTime_packFromMicrosec(ntp, sec, usec); * \endverbatim * * After the above call is made, the variable ntp will contain the equivalent * time stamp in RTINtpTime representation. * * This macro assumes that msec<1000000. It is the callers responsibility * to ensure this. This is done for performance reasons, the extra check * slows the execution a factor of 5! If msec may be greater than 1000000, * you can invoke the macro as follows: * \verbatim * RTINtpTime_packFromMicrosec(ntp, sec + usec/1000000, usec%1000000); * \endverbatim * * This macro only evaluates its arguments once, so it is safe to invoke it * with an argument that has side effects, that is. if you write: * \verbatim * RTI_UINT32 count = 10; * RTINtpTime_packFromMicrosec(ntp, sec, count++) * \endverbatim * * After the macro count is guaranteed to be 11. * * The accuracy of this conversion over the whole range of microsecond values * is 0.0028 micro-seconds. * * This is a fairly efficient macro. On a 400MHz Pentium-II linux box * the execute time is about 0.08 usec * * \verbatim * 2^12 * ntp.frac = us + us/2^5 + us/2^6 + us/2^10 + us/2^11 * + us/2^13 + us/2^14 + us/2^15 + us/2^16 * + us/2^18 + us/2^19 + us/2^20 + us/2^21 * + us/2^23 + 3e-9 * = us + us*99/2^11 + us*15/2^16 + us*61/2^23 * ntp.frac = (us<<12) + (us<<7) + (us<<6) + (us<<2) + (us<<1) * + (us>>1) + (us>>2) + (us>>3) + (us>>4) * + (us>>6) + (us>>7) + (us>>8) + (us>>9) + * (us>>11) = (us<<12) + ((us*99)<<1)+ ((us*15)>>4)+ ((us*61)>>11) \endverbatim */ extern RTIOsapiDllExport void RTINtpTime_packFromMicrosec( struct RTINtpTime time, long long s, RTI_UINT32 usec); /** @internal \ingroup RTINtpTimeClass * * @brief Macro to convert from RTINtpTime to sec and micro-seconds. * * @param s (long long) Holds the second portion. * @param usec (integer) holds the microsecond fraction. * @param time (RTINtpTime) to be converted. * * This macro does not check for overflow, so for a near infinite time value, * the conversion result may end up being negative. It is the responsibility * of the user to avoid passing these large time values. * * Use as indicated by the following code: * \verbatim * RTINtpTime ntp; * RTI_INT64 sec; * RTI_INT32 usec; * * ntp.sec = 10; * ntp.frac = 577; * * RTINtpTime_unpackToMicrosec(sec, usec, ntp); * \endverbatim * * After the above call is made, the variables "sec" and "usec" will * contain the equivalent time stamp. * * The accuracy of this conversion is approx 0.5 nano-seconds. * * This is a fairly efficient macro. On a 400MHz Pentium-II linux box * the execute time is about 0.12 usec * * \verbatim * us = frac*1000000/2^20 = frac*( 1 - 48576/2^20 ) * = frac*(1 - 47/2^10 - 7/2^14) * = frac - ((47*frac)>>10) - ((7*frac)>>14) * = frac - (frac>>5)-(frac>>7)-(frac>>8)-(frac>>9)-(frac>>10) * - (frac>>12)-(frac>>13)-(frac>>14) * \endverbatim * @todo arguments don't make sense because this is implemented as a macro */ extern RTIOsapiDllExport void RTINtpTime_unpackToMicrosec( long long s, unsigned usec, struct RTINtpTime time); /** @internal \ingroup RTINtpTimeClass * * @brief Macro to convert from sec and nano-seconds to RTINtpTime format. * * @param time (RTINtpTime) Holds the answer. * @param s (long long) Seconds to convert from. * @param nsec (integer) nanosecond fraction to convert from. * * Use as indicated by the following code: * \verbatim * RTINtpTime time; * RTI_INT64 sec; * RTI_INT32 nsec; * sec = 10; * nsec = 577; * * RTINtpTime_packFromNanosec(time, sec, msec); * \endverbatim * * After the above call is made, the variable time will contain the equivalent * time stamp in RTINtpTime representation. * * This macro assumes that nsec<1000000000. It is the callers responsibility * to ensure this. This is done for performance reasons. If nsec may be greater * or equal to 1000000000, you can invoke the macro as follows: * \verbatim} * RTINtpTime_packFromNanosec(time, sec + nsec/1000000000, nsec%1000000000); * \endverbatim * * This macro only evaluates its arguments once, so it is safe to invoke it * with an argument that has side effects, that is. if you write: * \verbatim * RTI_UINT32 count = 10; * RTINtpTime_packFromNanosec(time, sec, count++) * \endverbatim * After the macro count is guaranteed to be 11. * * The accuracy of this conversion over the whole range of nanosecond values * is 0.25 nano-second, */ extern RTIOsapiDllExport void RTINtpTime_packFromNanosec( struct RTINtpTime time, long long s, RTI_UINT32 nsec); /** @internal \ingroup RTINtpTimeClass * * @brief Macro to convert from RTINtpTime to sec and nano-seconds. * * @param s (long long) Second of the time to covert * @param usec (integer) Microsecond fraction to convert. * @param time (RTINtpTime) to convert from. * * Use as indicated by the following code: * \verbatim * RTINtpTime time; * RTI_INT64 sec; * RTI_INT32 nsec; * time.sec = 10; * time.frac = 577; * * RTINtpTime_unpackToNanosec(sec, nsec, time); * \endverbatim * After the above call is made, the variables "sec" and "nsec" will * contain the equivalent time stamp. * * The accuracy of this conversion is approx. 1 nsec. * * @todo arguments don't make sense because this is implemented as a macro */ extern RTIOsapiDllExport void RTINtpTime_unpackToNanosec( long long s, unsigned nsec, struct RTINtpTime time); /** @internal \ingroup RTINtpTimeClass * * @brief Macro to convert numerator/denom_per_sec into the ntp time. * * @param time RTINtpTime to contain the result. The existing * content of time does not affect the result, as it should not. * * @param numerator May be larger than denominator. Since this is a macro * and numerator is evaluated multiple times, you shouldn't specify things * like (i++). * * @param denominator_per_sec Denominator. * Physically, this means ticks per sec. Since this is a macro and * denominator is evaluated multiple times, you shouldn't specify things * like (i++). */ extern RTIOsapiDllExport void RTINtpTime_packFromFraction( struct RTINtpTime time, RTI_UINT32 numerator, RTI_UINT32 denominator_per_sec); /** @internal \ingroup RTINtpTimeClass * * @brief Transforms from RTINtpTime to any integral fraction of second without * using floating point operations. * * @param numerator RTI_UINT32 where to put the result of the conversion. * * @param denominator_per_sec the number of units of the fraction contained in * a second. Should be 1000 to convert to millisec, or 60 if using default * Vx clock rate, or whatever. * * @param time RTINtpTime to unpack * * The algorithm is based on the observation that the time.frac looked * as a sequence of bits: b[1], b[2], b[3], ... represents the * following expansion * * time_in_sec = b[1]*1/2 + b[1]*1/4 +...+ b[2]*1/8 * = Sum{i=1..32} b[i]*1/2^i * * So given that what we want to obtain is the time in units of which * there are denominator_per_sec units in a second, the arithmetic is: * * time_in_units = denominator_per_sec*time_in_sec * = denominator_per_sec*time.sec+denominator_per_sec*time.frac * * And denominator_per_sec*time.frac = * Sum{i=1..32} b[i]*(denominator_per_sec/2^i) * the key here is that b[i] is easily computed as (1<<31)>>(i-1) * and (denominator_per_sec/2^i) is easily computed as denominator_per_sec>>i * * Note that each time we compute (denominator_per_sec/2^i) to add it we may * be off by one unit. Therefore at the end of the computation we may * be off by log2(denominator_per_sec) units which means we should in fact * perform each step with an accuracy of log2(2*denominator_per_sec) * greater. In other words, we should use units a factor * log2(2*denominator_per_sec) greater than the ones we require at the end * of the conversion. * * The other key observation is that the computation can end as soon * as (denominator_per_sec<>i becomes * zero because that means that what is left has a significance of * less than one unit>>RTI_NTP_TIME_PRECISION_BITS_DEFAULT. This will give a * conversion that is strictly * smaller than the NTP timestamp. For example, for millisecond * conversion log2(1000) = 10 so we will do 10 operations so we need a * precision 1/20 or 5 bits (4 bits gives 1/16, 5 gives 1/32). * * The final operation: * (precision_units + (1<> * RTI_NTP_TIME_PRECISION_BITS_DEFAULT; * makes sure that the integer division by * 2^(RTI_NTP_TIME_PRECISION_BITS_DEFAULT) is * rounded off to the closest number. * * @todo arguments don't make sense because this is implemented as a macro */ extern RTIOsapiDllExport void RTINtpTime_unpackToFraction( unsigned numerator, unsigned denominator_per_sec, struct RTINtpTime time); /* \ingroup RTINtpTimeClass * @todo arguments don't make sense because this is implemented as a macro */ extern RTIOsapiDllExport void RTINtpTime_unpackToFractionPrecise( unsigned numerator, unsigned denominator_per_sec, struct RTINtpTime time, unsigned precisionBits); /** @internal \ingroup RTINtpTimeClass * * @brief Function to convert from sec (expressed as a double) to RTINtpTime * format. * * @param time (RTINtpTime) to contain the answer. * @param num (double) seconds to convert, e.g. 3.14 * * After the above call is made, the variable time will contain the equivalent * timestamp in RTINtpTime representation. * * Note: this is not implemented in a header file because math.h's log may * collide with the log defined in another RTI header file. */ extern RTIOsapiDllExport void RTINtpTime_packFromDouble( struct RTINtpTime *time, double num); /** @internal \ingroup RTINtpTimeClass * * @brief Compare two RTINtpTimes. * * @param time1 RTINtpTime, NOT NULL. * @param time2 RTINtpTime, NOT NULL. * * @return If time1 > time2 then return 1. If time1 < time2 then return -1. * If time1 == time2 then return 0. */ extern RTIOsapiDllExport int RTINtpTime_compare( const struct RTINtpTime time1, const struct RTINtpTime time2); /** @internal \ingroup RTINtpTimeClass * * @brief Get the min of two RTINtpTimes. */ extern RTIOsapiDllExport void RTINtpTime_min( struct RTINtpTime answer, const struct RTINtpTime time1, const struct RTINtpTime time2); /** @internal \ingroup RTINtpTimeClass * * @brief Get the max of two RTINtpTimes. */ extern RTIOsapiDllExport void RTINtpTime_max( struct RTINtpTime answer, const struct RTINtpTime time1, const struct RTINtpTime time2); /** @internal \ingroup RTINtpTimeClass * * @brief answer = t1 + t2. * * This macro does not check for overflow (faster). * * @param answer RTINtpTime * @param t1 RTINtpTime * @param t2 RTINtpTime */ extern RTIOsapiDllExport void RTINtpTime_add( struct RTINtpTime answer, struct RTINtpTime t1, struct RTINtpTime t2); /** @internal \ingroup RTINtpTimeClass * * @brief answer = t1 - t2. * * @param answer RTINtpTime * @param t1 RTINtpTime * @param t2 RTINtpTime */ extern RTIOsapiDllExport void RTINtpTime_subtract( struct RTINtpTime answer, struct RTINtpTime t1, struct RTINtpTime t2); /** @internal \ingroup RTINtpTimeClass * * @brief answer = time << shift. * * To use this macro for multiplying by a num, shift can be calculated * as log10(num)/log10(2). * * This macro only support shifting 32 bits. * * @param answer RTINtpTime * @param time RTINtpTime * @param shift int Cannot exceeds 32 bits. */ extern RTIOsapiDllExport void RTINtpTime_shiftLeft( struct RTINtpTime answer, struct RTINtpTime time, int shift); /** @internal \ingroup RTINtpTimeClass * * @brief answer = time >> shift. * * To use this macro for dividing by a num, shift can be calculated * as log10(num)/log10(2). * * This macro only support shifting 32 bits. * * @param answer RTINtpTime * @param time RTINtpTime * @param shift int Cannot exceeds 32 bits. */ extern RTIOsapiDllExport void RTINtpTime_shiftRight( struct RTINtpTime answer, struct RTINtpTime time, int shift); /** @internal \ingroup RTINtpTimeClass * * @brief answer = time * (percentScaler / 100). * * Scales time by a percentage-factor. * * This operation assumes that seconds cannot be greater than * RTI_NTP_TIME_SEC_MAX. * * @param answer RTINtpTime * @param time RTINtpTime * @param percentScaler RTI_INT32 */ extern RTIOsapiDllExport void RTINtpTime_scale( struct RTINtpTime *answer, struct RTINtpTime *time, RTI_INT32 percentScaler); /** @internal \ingroup RTINtpTimeClass * * @brief answer = time / divisor. * * Divides time by an integral divisor. Answer resolution limited to 16.16 * * This operation assumes that seconds cannot be greater than * RTI_NTP_TIME_SEC_MAX. * * @param answer RTINtpTime * @param time RTINtpTime * @param divisor RTI_INT64 */ extern RTIOsapiDllExport void RTINtpTime_divide( struct RTINtpTime *answer, struct RTINtpTime *time, RTI_INT64 divisor); /** @internal \ingroup * * @brief answer += time. * * This macro does not check for overflow. * * @param answer RTINtpTime * @param time RTINtpTime */ extern RTIOsapiDllExport void RTINtpTime_increment( struct RTINtpTime answer, struct RTINtpTime time); /** @internal \ingroup RTINtpTimeClass * * @brief Decrement one RTINtpTime value by another RTINtpTime value. * * Precondition: * Postcondition: answer -= time. * * @param answer RTINtpTime * @param time RTINtpTime */ extern RTIOsapiDllExport void RTINtpTime_decrement( struct RTINtpTime answer, struct RTINtpTime time); /** @internal \ingroup RTINtpTimeClass * * @brief time = time + 1 fraction (~200 picoseconds). * * This macro does not check for overflow, so time cannot be infinite. * * @param time * @return NO RETURN VALUE => do NOT evaluate this expression; simply call it. */ extern RTIOsapiDllExport void RTINtpTime_incrementInfinitesimally( struct RTINtpTime time); /** @internal * \ingroup RTINtpTimeClass * * NULL RTINtpTime pointer is considered infinity. This is consistent * with the concept of infinite time on UNIX. * * In addition, if the seconds field equals, or is above RTI_NTP_TIME_SEC_MAX, * the time value is also considered infinite. * * @param time Pointer to RTINtpTime. * * @return RTI_TRUE if time is infinite, RTI_FALSE otherwise. */ extern RTIOsapiDllExport RTIBool RTINtpTime_isInfinite(const struct RTINtpTime *time); /** @internal \ingroup RTINtpTimeClass * * @param time Pointer to RTINtpTime. * @return RTI_TRUE if time is AUTO, RTI_FALSE otherwise. */ extern RTIOsapiDllExport RTIBool RTINtpTime_isAuto(const struct RTINtpTime *time); /** @internal * \ingroup RTINtpTimeClass * * Checks if the time structure represents an invalid time. * * @param time Pointer to RTINtpTime. * * @return RTI_TRUE if time is invalid, RTI_FALSE otherwise. */ extern RTIOsapiDllExport RTIBool RTINtpTime_isInvalid(const struct RTINtpTime *time); /** @internal \ingroup RTINtpTimeClass * * Checks if the time structure represents zero time. Zero time may be useful * when getting the sign of the time quantity. * @param time Pointer to RTINtpTime. Must not be NULL. * @return positive if greater, 0 if equal, negative if less */ extern RTIOsapiDllExport int RTINtpTime_compareToZero( const struct RTINtpTime *time); /** @internal \ingroup RTINtpTimeClass * * Converts the RTINtpTime structure "time" into a string format * * @param time In. The RTINtpTime structure to convert into a string. * @param str In. The string within which to store the result. The buffer should * be sized to RTI_NTP_TIME_STRING_LEN. * * @returns The string. */ extern RTIOsapiDllExport char *RTINtpTime_toString( const struct RTINtpTime *time, char *str); /** @internal * \ingroup RTINtpTimeClass * * Converts the RTINtpTime structure "time" into a timeval format * * @param time In. The RTINtpTime structure to convert into a timeval. * @param timeval Out. The timeval within which to store the result. */ extern RTIOsapiDllExport void RTINtpTime_toTimeval( const struct RTINtpTime *time, struct timeval *timeval); /** @internal * \ingroup RTINtpTimeClass * * Converts the RTINtpTime structure "time" into a calendar time format * * @param time In. The RTINtpTime structure to convert into a calendar time. * @param calendarTime Out. The calendar time within which to store the result. * @param roundUp In. Whether to round up the time to the closest second. If set * to RTI_TRUE, the calendar time will be rounded up to the next seconds once * the fractional part of the RTINtpTime represents a value greater than 500000 * microseconds. It should only be set if the caller is not going to use the * microseconds. If the calendar time is going to be compared with another * calendar time, the value used should be the same for both calendar times. */ extern RTIOsapiDllExport void RTINtpTime_toCalendarTime( const struct RTINtpTime *time, RTI_TIME_T *calendarTime, RTIBool roundUp); /** @internal * \ingroup RTINtpTimeClass * * Converts the RTINtpTime structure "time" into a timespec format * * @param time In. The RTINtpTime structure to convert into a timespec. * @param calendarTime Out. The timespec within which to store the result. */ extern RTIOsapiDllExport void RTINtpTime_toTimespec( const struct RTINtpTime *time, struct timespec *calendarTime); /** @internal \ingroup RTINtpTimeClass * * Copies the RTINtpTime structure "time" into a buffer * * @param time In. The RTINtpTime structure to copy into a buffer. * @param buffer Out. The buffer where the RTINtpTime structure is going to be * copied. The size of the buffer should be at least * RTI_OSAPI_NTPTIME_SERIALIZED_SIZE. */ extern RTIOsapiDllExport void RTINtpTime_toBuffer( const struct RTINtpTime *time, char *buffer); #ifdef __cplusplus } /* extern "C" */ #endif #include "osapi/osapi_ntptime_impl.h" #endif /* osapi_ntptime_h */