From 8b7d1425e5983bf58e0a92a0e53b5dcfe2592068 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 14 Dec 1999 21:19:38 +0000 Subject: [PATCH] added C callable API --- src/libCom/osi/osiTime.cpp | 437 ++++++++++++++++++++++++++++++------- src/libCom/osi/osiTime.h | 363 +++++++++++++++++++----------- 2 files changed, 590 insertions(+), 210 deletions(-) diff --git a/src/libCom/osi/osiTime.cpp b/src/libCom/osi/osiTime.cpp index aba5b38e4..4a6b20af3 100644 --- a/src/libCom/osi/osiTime.cpp +++ b/src/libCom/osi/osiTime.cpp @@ -33,7 +33,6 @@ #define epicsExportSharedSymbols #include "epicsAssert.h" -#include "tsDefs.h" #include "envDefs.h" #include "osiTime.h" @@ -63,6 +62,18 @@ const unsigned osiTime::secPerMin = 60u; struct tm *gmtime_r (const time_t *, struct tm *); struct tm *localtime_r (const time_t *, struct tm *); #endif + +#if 0 +struct TS_STAMP { + epicsUInt32 secPastEpoch; /* seconds since 0000 Jan 1, 1990 */ + epicsUInt32 nsec; /* nanoseconds within second */ +}; +#endif + +static const unsigned ntpEpochYear = 1900; +static const unsigned ntpEpocMonth = 0; // January +static const unsigned ntpEpocDayOfTheMonth = 1; // the 1st day of the month +static const long double ULONG_MAX_PLUS_ONE = (static_cast(ULONG_MAX) + 1.0); // // force this module to include code that can convert @@ -76,6 +87,7 @@ public: }; static const unsigned tmStructEpochYear = 1900; + static const unsigned epicsEpochYear = 1990; static const unsigned epicsEpocMonth = 0; // January static const unsigned epicsEpocDayOfTheMonth = 1; // the 1st day of the month @@ -83,20 +95,10 @@ static const unsigned epicsEpocDayOfTheMonth = 1; // the 1st day of the month // // osiTime (const unsigned long secIn, const unsigned long nSecIn) // -osiTime::osiTime (const unsigned long secIn, const unsigned long nSecIn) +inline osiTime::osiTime (const unsigned long secIn, const unsigned long nSecIn) { - if (nSecInsec = secIn; - this->nSec = nSecIn; - } - else if (nSecIn<(nSecPerSec*2)){ - this->sec = secIn + 1u; - this->nSec = nSecIn-nSecPerSec; - } - else { - this->sec = nSecIn/nSecPerSec + secIn; - this->nSec = nSecIn%nSecPerSec; - } + this->sec = nSecIn/nSecPerSec + secIn; + this->nSec = nSecIn%nSecPerSec; } // @@ -128,8 +130,11 @@ class loadTimeInit { public: loadTimeInit (); - long epicsEpochOffset; // integer seconds - long double time_tTicksPerSec; + long double epicsEpochOffset; // seconds +#ifdef NTP_SUPPORT + long double ntpEpochOffset; // seconds +#endif + long double time_tSecPerTick; // seconds (both NTP and EPICS use int sec) }; static const loadTimeInit lti; @@ -139,7 +144,8 @@ static const loadTimeInit lti; // loadTimeInit::loadTimeInit () { - long secWest; + static const time_t ansiEpoch = 0; + long double secWest; { time_t current = time (NULL); @@ -148,19 +154,19 @@ loadTimeInit::loadTimeInit () gmtime_r (¤t, &date); error = mktime (&date); - secWest = static_cast (difftime (error, current)); + assert (error!=(time_t)-1); + secWest = difftime (error, current); } { time_t first = static_cast (0); time_t last = static_cast (1); - this->time_tTicksPerSec = 1.0 / difftime (last, first); + this->time_tSecPerTick = difftime (last, first); } { struct tm tmEpicsEpoch; time_t epicsEpoch; - time_t ansiEpoch = 0; tmEpicsEpoch.tm_sec = 0; tmEpicsEpoch.tm_min = 0; @@ -171,35 +177,88 @@ loadTimeInit::loadTimeInit () tmEpicsEpoch.tm_isdst = -1; // dont know if its daylight savings time epicsEpoch = mktime (&tmEpicsEpoch); - // - // when this happens we will need to write the code which - // subtract the tm structures ourselves - // assert (epicsEpoch!=(time_t)-1); - - this->epicsEpochOffset = static_cast (difftime (epicsEpoch, ansiEpoch)); - this->epicsEpochOffset -= secWest; + this->epicsEpochOffset = difftime (epicsEpoch, ansiEpoch) - secWest; } + +#ifdef NTP_SUPPORT + /* unfortunately, on NT mktime cant calculate a time_t for a date before 1970 */ + { + struct tm tmEpochNTP; + time_t ntpEpoch; + + tmEpochNTP.tm_sec = 0; + tmEpochNTP.tm_min = 0; + tmEpochNTP.tm_hour = 0; + tmEpochNTP.tm_mday = ntpEpocDayOfTheMonth; + tmEpochNTP.tm_mon = ntpEpocMonth; + tmEpochNTP.tm_year = ntpEpochYear-tmStructEpochYear; + tmEpochNTP.tm_isdst = -1; // dont know if its daylight savings time + + ntpEpoch = mktime (&tmEpochNTP); + assert (ntpEpoch!=(time_t)-1); + + this->ntpEpochOffset = static_cast (difftime (ansiEpoch, ntpEpoch) + this->epicsEpochOffset - secWest); + } +#endif } // -// ansiSecToInternalSec () +// osiTime::addNanoSec () // -unsigned long osiTime::time_tToInternalSec (const time_t &ansiTimeTicks) +// many of the UNIX timestamp formats have nano sec stored as a long +// +inline void osiTime::addNanoSec (long nSecAdj) { - unsigned long sec; + // + // for now assume that they dont allow negative nanoseconds + // on UNIX platforms (this could be a mistake) + // + if ( nSecAdj < 0 ) { + throw negNanoSecInTimeStampFromUNIX (); + } - sec = static_cast (ansiTimeTicks / lti.time_tTicksPerSec); + unsigned long offset = static_cast (nSecAdj); - // expect over / under flow - if (lti.epicsEpochOffset>=0) { - sec -= static_cast(lti.epicsEpochOffset); - } - else { - sec += static_cast(-lti.epicsEpochOffset); - } + if ( offset >= nSecPerSec ) { + throw nanoSecFieldIsTooLarge (); + } - return sec; + // + // no need to worry about overflow here because + // offset + this->nSec will be less than ULONG_MAX/2 + // + *this = osiTime (this->sec, this->nSec + offset); +} + +// +// osiTime (const time_t_wrapper &tv) +// +osiTime::osiTime (const time_t_wrapper &ansiTimeTicks) +{ + static long double uLongMax = static_cast(ULONG_MAX); + long double sec; + + // + // map time_t, which ansi C defines as some arithmetic type, into "long double" + // + sec = ansiTimeTicks.ts * lti.time_tSecPerTick - lti.epicsEpochOffset; + + // + // map into the the EPICS time stamp range (which allows rollover) + // + if (sec < 0.0) { + if (sec < -uLongMax) { + sec = sec + static_cast(-sec/uLongMax)*uLongMax; + } + sec += uLongMax; + } + else if (sec > uLongMax) { + sec = sec - static_cast(sec/uLongMax)*uLongMax; + } + + this->sec = static_cast (sec); + this->nSec = static_cast ( (sec-this->sec) * nSecPerSec ); } // @@ -208,19 +267,16 @@ unsigned long osiTime::time_tToInternalSec (const time_t &ansiTimeTicks) osiTime::operator time_t_wrapper () const { long double tmp; - unsigned long newSec; time_t_wrapper wrap; - // expect over/under flow and allow it to occur befor proceeding - if (lti.epicsEpochOffset>=0) { - newSec = this->sec + static_cast(lti.epicsEpochOffset); - } - else { - newSec = this->sec + static_cast(-lti.epicsEpochOffset); - } - tmp = newSec * lti.time_tTicksPerSec; - tmp += (this->nSec * lti.time_tTicksPerSec) / nSecPerSec; - wrap.ts = static_cast (tmp); + tmp = (this->sec + lti.epicsEpochOffset) / lti.time_tSecPerTick; + tmp += (this->nSec / lti.time_tSecPerTick) / nSecPerSec; + + // + // map "long double" into time_t which ansi C defines as some arithmetic type + // + wrap.ts = static_cast (tmp); + return wrap; } @@ -229,32 +285,43 @@ osiTime::operator time_t_wrapper () const // osiTime::operator tm_nano_sec () const { - struct tm_nano_sec tm; + tm_nano_sec tm; time_t_wrapper ansiTimeTicks; + struct tm *p; ansiTimeTicks = *this; - // from POSIX RT - localtime_r (&ansiTimeTicks.ts, &tm.ansi_tm); + // reentrant version of localtime() - from POSIX RT + // WRS prototype is incorrect ? + p = localtime_r (&ansiTimeTicks.ts, &tm.ansi_tm); + if (p != &tm.ansi_tm) { + throw internalFailure (); + } - tm.nsec = this->nSec; + tm.nSec = this->nSec; return tm; } // -// osiTime (const struct tm_nano_sec &tm) +// osiTime (const tm_nano_sec &tm) // -osiTime::osiTime (const struct tm_nano_sec &tm) +osiTime::osiTime (const tm_nano_sec &tm) { - time_t ansiTimeTicks; + time_t_wrapper ansiTimeTicks; struct tm tmp = tm.ansi_tm; - ansiTimeTicks = mktime (&tmp); - assert (ansiTimeTicks!=(time_t)-1); + ansiTimeTicks.ts = mktime (&tmp); + if (ansiTimeTicks.ts==(time_t)-1) { + throw formatProblemWithStructTM (); + } - this->sec = osiTime::time_tToInternalSec (ansiTimeTicks); - this->nSec = tm.nsec; + *this = osiTime (ansiTimeTicks); + + if (tm.nSec>=nSecPerSec) { + throw nanoSecFieldIsTooLarge (); + } + *this = osiTime (this->sec, this->nSec + tm.nSec); } // @@ -276,16 +343,37 @@ osiTime::operator struct timespec () const // osiTime::osiTime (const struct timespec &ts) { - this->sec = osiTime::time_tToInternalSec (ts.tv_sec); - assert (ts.tv_nsec>=0); - unsigned long nSecIn = static_cast (ts.tv_nsec); - if (nSecInnSec = nSecIn; - } - else { - this->sec += nSecIn / nSecPerSec; - this->nSec = nSecIn % nSecPerSec; - } + time_t_wrapper ansiTimeTicks; + + ansiTimeTicks.ts = ts.tv_sec; + *this = osiTime (ansiTimeTicks); + this->addNanoSec (ts.tv_nsec); +} + +// +// operator struct timeval () +// +osiTime::operator struct timeval () const +{ + struct timeval ts; + time_t_wrapper ansiTimeTicks; + + ansiTimeTicks = *this; + ts.tv_sec = ansiTimeTicks.ts; + ts.tv_usec = static_cast (this->nSec / nSecPerUSec); + return ts; +} + +// +// osiTime (const struct timeval &ts) +// +osiTime::osiTime (const struct timeval &ts) +{ + time_t_wrapper ansiTimeTicks; + + ansiTimeTicks.ts = ts.tv_sec; + *this = osiTime (ansiTimeTicks); + this->addNanoSec (ts.tv_usec * nSecPerUSec); } // @@ -307,15 +395,15 @@ osiTime::operator aitTimeStamp () const // osiTime::osiTime (const aitTimeStamp &ts) { - this->sec = osiTime::time_tToInternalSec (ts.tv_sec); + time_t_wrapper ansiTimeTicks; - if (ts.tv_nsecnSec = ts.tv_nsec; - } - else { - this->sec += ts.tv_nsec / nSecPerSec; - this->nSec = ts.tv_nsec % nSecPerSec; - } + ansiTimeTicks.ts = ts.tv_sec; + *this = osiTime (ansiTimeTicks); + + if ( ts.tv_nsec>=nSecPerSec ) { + throw nanoSecFieldIsTooLarge (); + } + *this = osiTime ( this->sec, this->nSec + ts.tv_nsec ); } // @@ -338,6 +426,53 @@ osiTime::osiTime (const struct TS_STAMP &ts) this->nSec = ts.nsec; } +// +// osiTime::ntpTimeStamp () +// +#ifdef NTP_SUPPORT +osiTime::operator ntpTimeStamp () const +{ + ntpTimeStamp ts; + + if (lti.ntpEpochOffset>=0) { + unsigned long offset = static_cast (lti.ntpEpochOffset); + // underflow expected + ts.l_ui = this->sec - offset; + } + else { + unsigned long offset = static_cast (-lti.ntpEpochOffset); + // overflow expected + ts.l_ui = this->sec + offset; + } + + ts.l_uf = static_cast ( ( this->nSec * ULONG_MAX_PLUS_ONE ) / nSecPerSec ); + + return ts; +} +#endif + +// +// osiTime::osiTime (const ntpTimeStamp &ts) +// +#ifdef NTP_SUPPORT +osiTime::osiTime (const ntpTimeStamp &ts) +{ + + if (lti.ntpEpochOffset>=0) { + unsigned long offset = static_cast (lti.ntpEpochOffset); + // overflow expected + this->sec = ts.l_ui + this->sec + offset; + } + else { + unsigned long offset = static_cast (-lti.ntpEpochOffset); + // underflow expected + this->sec = ts.l_ui + this->sec - offset; + } + + this->nSec = static_cast ( ( ts.l_uf / ULONG_MAX_PLUS_ONE ) * nSecPerSec ); +} +#endif + // // osiTime::show (unsigned) // @@ -349,8 +484,8 @@ void osiTime::show (unsigned) const status = strftime (bigBuffer, sizeof(bigBuffer), "%a %b %d %H:%M:%S %Y", &tmns.ansi_tm); if (status>0) { - printf ("osiTime: %s %f\n", bigBuffer, - static_cast (tmns.nsec) / nSecPerSec); + printf ("osiTime: %s %g\n", bigBuffer, + static_cast (tmns.nSec) / nSecPerSec); } } @@ -366,7 +501,7 @@ osiTime osiTime::operator + (const long double &rhs) const if (rhs >= 0) { secOffset = static_cast (rhs); - fnsec = rhs - static_cast (secOffset); + fnsec = rhs - secOffset; nSecOffset = static_cast (fnsec * nSecPerSec); newSec = this->sec + secOffset; // overflow expected @@ -378,7 +513,7 @@ osiTime osiTime::operator + (const long double &rhs) const } else { secOffset = static_cast (-rhs); - fnsec = rhs + static_cast (secOffset); + fnsec = rhs + secOffset; nSecOffset = static_cast (-fnsec * nSecPerSec); newSec = this->sec - secOffset; // underflow expected @@ -568,3 +703,139 @@ bool osiTime::operator < (const osiTime &rhs) const return rc; } +extern "C" { + /* + * ANSI C interface + * + * its too bad that these cant be implemented with inline functions + * at least when running the GNU compiler + */ + epicsShareFunc void osiTimeGetCurrent (osiTime *pDest) + { + *pDest = osiTime::getCurrent(); + } + epicsShareFunc void osiTimeSynchronize () + { + osiTime::synchronize (); + } + epicsShareFunc int osiTimeToTS_STAMP (TS_STAMP *pDest, const osiTime *pSrc) + { + try { + *pDest = *pSrc; + } + catch (...) { + return -1; + } + return 0; + } + epicsShareFunc int osiTimeFromTS_STAMP (osiTime *pDest, const TS_STAMP *pSrc) + { + try { + *pDest = *pSrc; + } + catch (...) { + return -1; + } + return 0; + } + epicsShareFunc int osiTimeToTime_t (time_t *pDest, const osiTime *pSrc) + { + try { + time_t_wrapper dst; + dst = *pSrc; + *pDest = dst.ts; + } + catch (...) { + return -1; + } + return 0; + } + epicsShareFunc int osiTimeFromTime_t (osiTime *pDest, time_t src) + { + try { + time_t_wrapper dst; + dst.ts = src; + *pDest = dst; + } + catch (...) { + return -1; + } + return 0; + } + epicsShareFunc int osiTimeToTM (tm_nano_sec *pDest, const osiTime *pSrc) + { + try { + *pDest = *pSrc; + } + catch (...) { + return -1; + } + return 0; + } + epicsShareFunc int osiTimeFromTM (osiTime *pDest, const tm_nano_sec *pSrc) + { + try { + *pDest = *pSrc; + } + catch (...) { + return -1; + } + return 0; + } + epicsShareFunc int osiTimeToTimespec (struct timespec *pDest, const osiTime *pSrc) + { + try { + *pDest = *pSrc; + } + catch (...) { + return -1; + } + return 0; + } + epicsShareFunc int osiTimeFromTimespec (osiTime *pDest, const struct timespec *pSrc) + { + try { + *pDest = *pSrc; + } + catch (...) { + return -1; + } + return 0; + } + epicsShareFunc long double osiTimeDiffInSeconds (const osiTime *pLeft, const osiTime *pRight) + { + return *pLeft - *pRight; + } + epicsShareFunc void osiTimeAddSeconds (osiTime *pDest, long double seconds) + { + *pDest += seconds; + } + epicsShareFunc int osiTimeEqual (const osiTime *pLeft, const osiTime *pRight) + { + return *pLeft == *pRight; + } + epicsShareFunc int osiTimeNotEqual (const osiTime *pLeft, const osiTime *pRight) + { + return *pLeft != *pRight; + } + epicsShareFunc int osiTimeLessThan (const osiTime *pLeft, const osiTime *pRight) + { + return *pLeft < *pRight; + } + epicsShareFunc int osiTimeLessThanEqual (const osiTime *pLeft, const osiTime *pRight) + { + return *pLeft <= *pRight; + } + epicsShareFunc int osiTimeGreaterThan (const osiTime *pLeft, const osiTime *pRight) + { + return *pLeft > *pRight; + } + epicsShareFunc int osiTimeGreaterThanEqual (const osiTime *pLeft, const osiTime *pRight) + { + return *pLeft >= *pRight; + } + epicsShareFunc void osiTimeShow (const osiTime *pTS, unsigned interestLevel) + { + pTS->show (interestLevel); + } +} diff --git a/src/libCom/osi/osiTime.h b/src/libCom/osi/osiTime.h index 575d4e38b..c772a025c 100644 --- a/src/libCom/osi/osiTime.h +++ b/src/libCom/osi/osiTime.h @@ -32,118 +32,179 @@ #ifndef osiTimehInclude #define osiTimehInclude -// -// ANSI C -// +/* + * ANSI C + */ #include #include "shareLib.h" -#include "tsDefs.h" +#include "epicsTypes.h" -struct TS_STAMP; // EPICS -class aitTimeStamp; // GDD -struct timespec; // POSIX real time +struct TS_STAMP; /* EPICS */ +struct timespec; /* POSIX real time */ +struct timeval; /* BSD */ +#ifdef __cplusplus +class aitTimeStamp; /* GDD */ +#endif -// -// an extended ANSI C RTL "struct tm" which includes nano seconds. -// -struct tm_nano_sec { - tm ansi_tm; // ANSI C time details - unsigned long nsec; // nano seconds extension -}; +/* + * an extended ANSI C RTL "struct tm" which includes nano seconds. + */ +typedef struct tm_nano_sec { + struct tm ansi_tm; /* ANSI C time details */ + unsigned long nSec; /* nano seconds extension */ +} tm_nano_sec; -// -// wrapping this in a struct allows conversion to and -// from ANSI time_t but does not allow unexpected -// conversions to occur -// -struct time_t_wrapper { +/* + * wrapping this in a struct allows conversion to and + * from ANSI time_t but does not allow unexpected + * conversions to occur + */ +typedef struct time_t_wrapper { time_t ts; -}; +} time_t_wrapper; -// -// class osiTime -// -// high resolution osiTime stamp -// -class epicsShareClass osiTime { -public: +/* + * NTP uses two fixed point formats. The first (l_fp) is the "long" + * format and is 64 bits long with the decimal between bits 31 and 32. + * This is used for time stamps in the NTP packet header (in network + * byte order) and for internal computations of offsets (in local host + * byte order). We use the same structure for both signed and unsigned + * values, which is a big hack but saves rewriting all the operators + * twice. Just to confuse this, we also sometimes just carry the + * fractional part in calculations, in both signed and unsigned forms. + * Anyway, an l_fp looks like: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Integral Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Fractional Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +typedef struct { + epicsUInt32 l_ui; /* sec past NTP epoch */ + epicsUInt32 l_uf; /* fractional seconds */ +}ntpTimeStamp; - // - // fetch the current time - // +/* + * The number of nanoseconds past 0000 Jan 1, 1990, GMT (or UTC, if you prefer). + */ +typedef struct TS_STAMP { + epicsUInt32 secPastEpoch; /* seconds since 0000 Jan 1, 1990 */ + epicsUInt32 nsec; /* nanoseconds within second */ +} TS_STAMP; + +/* + * type osiTime + * + * high resolution osiTime stamp class (struct) which can be used + * from both C++ and also from ANSI C + */ +typedef struct epicsShareClass osiTime +{ +#ifdef __cplusplus + + /* + * exceptions + */ + class unableToFetchCurrentTime {}; + class negNanoSecInTimeStampFromUNIX {}; + class nanoSecFieldIsTooLarge {}; + class formatProblemWithStructTM {}; + class internalFailure {}; + + /* + * fetch the current time + */ static osiTime getCurrent(); - // - // some systems have a high resolution time source which - // gradually drifts away from the master time base. Calling - // this routine will cause class "time" to realign the high - // resolution result from getCurrent() with some master - // time base. - // - // if this routine has not been called at least once so far - // by the current process then it is called the first time - // that getCurrent() is called - // + /* + * some systems have a high resolution time source which + * gradually drifts away from the master time base. Calling + * this routine will cause class "time" to realign the high + * resolution result from getCurrent() with some master + * time base. + * + * if this routine has not been called at least once so far + * by the current process then it is called the first time + * that getCurrent() is called + */ static void synchronize(); - // - // create an osiTime for the EPICS epoch - // + /* + * create an osiTime for the EPICS epoch + */ osiTime (); osiTime (const osiTime &t); - // - // convert to and from EPICS TS_STAMP format - // + /* + * convert to and from EPICS TS_STAMP format + */ operator struct TS_STAMP () const; osiTime (const struct TS_STAMP &ts); osiTime operator = (const struct TS_STAMP &rhs); - // - // convert to and from ANSI C's "time_t" - // - // "time_t" is wrapped in another structure to avoid - // unsuspected type conversions - // fetch value as an integer - // + /* + * convert to and from ANSI C's "time_t" + * + * "time_t" is wrapped in another structure to avoid + * unsuspected type conversions + * fetch value as an integer + */ operator time_t_wrapper () const; osiTime (const time_t_wrapper &tv); osiTime operator = (const time_t_wrapper &rhs); - // - // convert to and from ANSI C's "struct tm" (with nano seconds) - // - operator struct tm_nano_sec () const; - osiTime (const struct tm_nano_sec &ts); - osiTime operator = (const struct tm_nano_sec &rhs); + /* + * convert to and from ANSI C's "struct tm" (with nano seconds) + */ + operator tm_nano_sec () const; + osiTime (const tm_nano_sec &ts); + osiTime operator = (const tm_nano_sec &rhs); - // - // convert to and from POSIX RT's "struct timespec" - // + /* + * convert to and from POSIX RT's "struct timespec" + */ operator struct timespec () const; osiTime (const struct timespec &ts); osiTime operator = (const struct timespec &rhs); - // - // convert to and from GDD's aitTimeStamp format - // + /* + * convert to and from BSD's "struct timeval" + */ + operator struct timeval () const; + osiTime (const struct timeval &ts); + osiTime operator = (const struct timeval &rhs); + + /* + * convert to and from NTP timestamp format + */ + operator ntpTimeStamp () const; + osiTime (const ntpTimeStamp &ts); + osiTime operator = (const ntpTimeStamp &rhs); + + /* + * convert to and from GDD's aitTimeStamp format + */ operator aitTimeStamp () const; osiTime (const aitTimeStamp &ts); osiTime operator = (const aitTimeStamp &rhs); - // - // arithmetic operators - // + /* + * arithmetic operators + */ long double operator- (const osiTime &rhs) const; // returns seconds osiTime operator+ (const long double &rhs) const; // add rhs seconds osiTime operator- (const long double &rhs) const; // subtract rhs seconds osiTime operator+= (const long double &rhs); // add rhs seconds osiTime operator-= (const long double &rhs); // subtract rhs seconds - // - // comparison operators - // + /* + * comparison operators + */ bool operator == (const osiTime &rhs) const; bool operator != (const osiTime &rhs) const; bool operator <= (const osiTime &rhs) const; @@ -151,14 +212,14 @@ public: bool operator >= (const osiTime &rhs) const; bool operator > (const osiTime &rhs) const; - // - // dump current state to standard out - // + /* + * dump current state to standard out + */ void show (unsigned interestLevel) const; - // - // useful public constants - // + /* + * useful public constants + */ static const unsigned secPerMin; static const unsigned mSecPerSec; static const unsigned uSecPerSec; @@ -166,28 +227,98 @@ public: static const unsigned nSecPerUSec; private: - unsigned long sec; /* seconds since O000 Jan 1, 1990 */ - unsigned long nSec; /* nanoseconds within second */ static osiTime osdGetCurrent(); - static unsigned long time_tToInternalSec (const time_t &tv); - // - // private because: - // a) application does not break when EPICS epoch is changed - // b) no assumptions about internal storage or internal precision - // in the application - // c) it would be easy to forget which argument is nanoseconds - // and which argument is seconds (no help from compiler) - // + /* + * private because: + * a) application does not break when EPICS epoch is changed + * b) no assumptions about internal storage or internal precision + * in the application + * c) it would be easy to forget which argument is nanoseconds + * and which argument is seconds (no help from compiler) + */ osiTime (const unsigned long sec, const unsigned long nSec); -}; + void addNanoSec (long nanoSecAdjust); -///////////////////////////////////// -// -// time inline member functions -// -///////////////////////////////////// +#endif /* ifdef __cplusplus */ + + /* + * private - do not touch these from within C programs + */ + unsigned long sec; /* seconds since O000 Jan 1, 1990 */ + unsigned long nSec; /* nanoseconds within second */ +} osiTime; + +/* + * ANSI C interface to osiTime + * + * all conversion functions return -1 on failure and 0 on success + */ +#ifdef __cplusplus +extern "C" { +#endif + + /* + * fetch and synchronize the current time + */ + epicsShareFunc void osiTimeGetCurrent (osiTime *pDest); + epicsShareFunc void osiTimeSynchronize (); + + /* + * convert to and from EPICS TS_STAMP format + */ + epicsShareFunc int osiTimeToTS_STAMP (TS_STAMP *pDest, const osiTime *pSrc); + epicsShareFunc int osiTimeFromTS_STAMP (osiTime *pDest, const TS_STAMP *pSrc); + + /* + * convert to and from ANSI C's "time_t" + */ + epicsShareFunc int osiTimeToTime_t (time_t *pDest, const osiTime *pSrc); + epicsShareFunc int osiTimeFromTime_t (osiTime *pDest, time_t src); + + /* + * convert to and from ANSI C's "struct tm" (with nano seconds) + */ + epicsShareFunc int osiTimeToTM (tm_nano_sec *pDest, const osiTime *pSrc); + epicsShareFunc int osiTimeFromTM (osiTime *pDest, const tm_nano_sec *pSrc); + + /* + * convert to and from POSIX RT's "struct timespec" + */ + epicsShareFunc int osiTimeToTimespec (struct timespec *pDest, const osiTime *pSrc); + epicsShareFunc int osiTimeFromTimespec (osiTime *pDest, const struct timespec *pSrc); + + /* + * arithmetic operations + */ + epicsShareFunc long double osiTimeDiffInSeconds (const osiTime *pLeft, const osiTime *pRight); /* returns *pLeft - *pRight in seconds */ + epicsShareFunc void osiTimeAddSeconds (osiTime *pDest, long double secondsToAdd); /* adds seconds to *pLeft */ + + /* + * comparison operations + */ + epicsShareFunc int osiTimeEqual (const osiTime *pLeft, const osiTime *pRight); /* returns boolean result */ + epicsShareFunc int osiTimeNotEqual (const osiTime *pLeft, const osiTime *pRight); /* returns boolean result */ + epicsShareFunc int osiTimeLessThan (const osiTime *pLeft, const osiTime *pRight); /* returns boolean result (true if *pLeft < *pRight) */ + epicsShareFunc int osiTimeLessThanEqual (const osiTime *pLeft, const osiTime *pRight); /* returns boolean result (true if *pLeft <= *pRight) */ + epicsShareFunc int osiTimeGreaterThan (const osiTime *pLeft, const osiTime *pRight); /* returns boolean result (true if *pLeft > *pRight) */ + epicsShareFunc int osiTimeGreaterThanEqual (const osiTime *pLeft, const osiTime *pRight); /* returns boolean result (true if *pLeft >= *pRight) */ + + /* + * dump current state to standard out + */ + epicsShareFunc void osiTimeShow (const osiTime *, unsigned interestLevel); + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +/* + * type osiTime inline member functions + */ inline osiTime::osiTime () : sec(0u), nSec(0u) {} @@ -220,81 +351,59 @@ inline bool osiTime::operator == (const osiTime &rhs) const } } -// -// operator != -// inline bool osiTime::operator != (const osiTime &rhs) const { return !osiTime::operator == (rhs); } -// -// operator >= (const osiTime &lhs, const osiTime &rhs) -// inline bool osiTime::operator >= (const osiTime &rhs) const { return !(*this < rhs); } -// -// operator > (const osiTime &lhs, const osiTime &rhs) -// inline bool osiTime::operator > (const osiTime &rhs) const { return !(*this <= rhs); } -// -// osiTime operator = (const struct tm_nano_sec &rhs) -// -inline osiTime osiTime::operator = (const struct tm_nano_sec &rhs) +inline osiTime osiTime::operator = (const tm_nano_sec &rhs) { return *this = osiTime (rhs); } -// -// operator = (const struct timespec &rhs) -// inline osiTime osiTime::operator = (const struct timespec &rhs) { *this = osiTime (rhs); return *this; } -// -// operator = (const aitTimeStamp &rhs) -// inline osiTime osiTime::operator = (const aitTimeStamp &rhs) { *this = osiTime (rhs); return *this; } - inline osiTime osiTime::operator = (const struct TS_STAMP &rhs) { *this = osiTime (rhs); return *this; } -// -// osiTime (const time_t_wrapper &tv) -// -inline osiTime::osiTime (const time_t_wrapper &ansiTimeTicks) +#ifdef NTP_SUPPORT +inline osiTime osiTime::operator = (const ntpTimeStamp &rhs) { - this->sec = osiTime::time_tToInternalSec (ansiTimeTicks.ts); - this->nSec = 0; + *this = osiTime (rhs); + return *this; } +#endif -// -// osiTime operator = (const time_t_wrapper &rhs) -// operator >= (const osiTime &lhs, const osiTime &rhs) -// inline osiTime osiTime::operator = (const time_t_wrapper &rhs) { *this = osiTime (rhs); return *this; } -#endif // osiTimehInclude +#endif /* __cplusplus */ + +#endif /* osiTimehInclude */