From 7323486b9ed25376ebe1aa313440cbe336350f64 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Tue, 20 Jun 2000 21:12:45 +0000 Subject: [PATCH] back out to previous version --- src/libCom/osi/osiTime.cpp | 130 ++++++++++++++++++++++++++++++++++--- src/libCom/osi/osiTime.h | 41 ++++++++++++ 2 files changed, 162 insertions(+), 9 deletions(-) diff --git a/src/libCom/osi/osiTime.cpp b/src/libCom/osi/osiTime.cpp index 5b777d525..aae979552 100644 --- a/src/libCom/osi/osiTime.cpp +++ b/src/libCom/osi/osiTime.cpp @@ -50,9 +50,10 @@ const unsigned osiTime::nSecPerSec = 1000u*osiTime::uSecPerSec; const unsigned osiTime::nSecPerUSec = 1000u; const unsigned osiTime::secPerMin = 60u; -//Following is (SEC_IN_YEAR*20)+(5*SEC_IN_DAY) -// 5 is leap years from 1970 to 1990 -static const double posixEpochToEpicsEpoch = 631152000.0; +static const unsigned ntpEpochYear = 1900; +static const unsigned ntpEpocMonth = 0; // January +static const unsigned ntpEpocDayOfTheMonth = 1; // the 1st day of the month +static const double ULONG_MAX_PLUS_ONE = (static_cast(ULONG_MAX) + 1.0); // // force this module to include code that can convert @@ -67,6 +68,10 @@ 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 + // // forward declarations for utility routines // @@ -87,7 +92,12 @@ inline osiTime::osiTime (const unsigned long secIn, const unsigned long nSecIn) class osiTimeLoadTimeInit { public: osiTimeLoadTimeInit (); - double time_tSecPerTick; // seconds ( EPICS uses int sec) + + double epicsEpochOffset; // seconds +#ifdef NTP_SUPPORT + double ntpEpochOffset; // seconds +#endif + double time_tSecPerTick; // seconds (both NTP and EPICS use int sec) }; static const osiTimeLoadTimeInit lti; @@ -97,9 +107,63 @@ static const osiTimeLoadTimeInit lti; // osiTimeLoadTimeInit::osiTimeLoadTimeInit () { - time_t first = static_cast (0); - time_t last = static_cast (1); - this->time_tSecPerTick = difftime (last, first); + static const time_t ansiEpoch = 0; + double secWest; + + { + time_t current = time (NULL); + time_t error; + tm date; + + gmtime_r (¤t, &date); + error = mktime (&date); + assert (error!=(time_t)-1); + secWest = difftime (error, current); + } + + { + time_t first = static_cast (0); + time_t last = static_cast (1); + this->time_tSecPerTick = difftime (last, first); + } + + { + struct tm tmEpicsEpoch; + time_t epicsEpoch; + + tmEpicsEpoch.tm_sec = 0; + tmEpicsEpoch.tm_min = 0; + tmEpicsEpoch.tm_hour = 0; + tmEpicsEpoch.tm_mday = epicsEpocDayOfTheMonth; + tmEpicsEpoch.tm_mon = epicsEpocMonth; + tmEpicsEpoch.tm_year = epicsEpochYear-tmStructEpochYear; + tmEpicsEpoch.tm_isdst = -1; // dont know if its daylight savings time + + epicsEpoch = mktime (&tmEpicsEpoch); + assert (epicsEpoch!=(time_t)-1); + 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 } // @@ -124,7 +188,7 @@ osiTime::osiTime (const time_t_wrapper &ansiTimeTicks) // // map time_t, which ansi C defines as some arithmetic type, into type double // - sec = ansiTimeTicks.ts * lti.time_tSecPerTick - posixEpochToEpicsEpoch; + sec = ansiTimeTicks.ts * lti.time_tSecPerTick - lti.epicsEpochOffset; // // map into the the EPICS time stamp range (which allows rollover) @@ -151,7 +215,7 @@ osiTime::operator time_t_wrapper () const double tmp; time_t_wrapper wrap; - tmp = (this->secPastEpoch + posixEpochToEpicsEpoch) / lti.time_tSecPerTick; + tmp = (this->secPastEpoch + lti.epicsEpochOffset) / lti.time_tSecPerTick; tmp += (this->nSec / lti.time_tSecPerTick) / nSecPerSec; // @@ -179,6 +243,7 @@ osiTime::operator tm_nano_sec () const // succes? // localtime_r (&ansiTimeTicks.ts, &tm.ansi_tm); + tm.nSec = this->nSec; return tm; @@ -286,6 +351,53 @@ osiTime::osiTime (const aitTimeStamp &ts) *this = osiTime (this->secPastEpoch+secAdj, this->nSec+nSecAdj); } +// +// 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->secPastEpoch - offset; + } + else { + unsigned long offset = static_cast (-lti.ntpEpochOffset); + // overflow expected + ts.l_ui = this->secPastEpoch + 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->secPastEpoch = ts.l_ui + this->secPastEpoch + offset; + } + else { + unsigned long offset = static_cast (-lti.ntpEpochOffset); + // underflow expected + this->secPastEpoch = ts.l_ui + this->secPastEpoch - offset; + } + + this->nSec = static_cast ( ( ts.l_uf / ULONG_MAX_PLUS_ONE ) * nSecPerSec ); +} +#endif + // // size_t osiTime::strftime (char *pBuff, size_t bufLength, const char *pFormat) // diff --git a/src/libCom/osi/osiTime.h b/src/libCom/osi/osiTime.h index 9dfd186d5..ed434e52a 100644 --- a/src/libCom/osi/osiTime.h +++ b/src/libCom/osi/osiTime.h @@ -65,6 +65,33 @@ struct time_t_wrapper { time_t ts; }; +// +// This comment is from the NTP header files: +// +// 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 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// +struct ntpTimeStamp { + epicsUInt32 l_ui; /* sec past NTP epoch */ + epicsUInt32 l_uf; /* fractional seconds */ +}; + class osiTime; // @@ -146,6 +173,13 @@ public: 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 // @@ -329,6 +363,13 @@ inline osiTime::operator TS_STAMP () const return ts; } +#ifdef NTP_SUPPORT +inline osiTime osiTime::operator = (const ntpTimeStamp &rhs) +{ + *this = osiTime (rhs); + return *this; +} +#endif inline osiTime osiTime::operator = (const time_t_wrapper &rhs) {