general overhaul of the osiTime class
This commit is contained in:
@@ -1,25 +1,78 @@
|
||||
//
|
||||
// osiTime.cc
|
||||
//
|
||||
// Author: Jeff Hill
|
||||
//
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#ifndef assert // allow other versions of assert
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <tsDefs.h>
|
||||
#include <osiTime.h>
|
||||
#include <envDefs.h>
|
||||
|
||||
|
||||
//
|
||||
// 1/1/90 20 yr (5 leap) of seconds
|
||||
// this is defined by POSIX 1003.1b (POSIX real time) compilant OS
|
||||
//
|
||||
const unsigned osiTime::epicsEpochSecPast1970 = 7305 * 86400;
|
||||
#ifndef CLOCK_REALTIME
|
||||
|
||||
const unsigned osiTime::mSecPerSec = 1000u;
|
||||
const unsigned osiTime::nSecPerSec = 1000000000u;
|
||||
const unsigned osiTime::nSecPerUSec = 1000u;
|
||||
const unsigned osiTime::secPerMin = 60u;
|
||||
//
|
||||
// this is part of the POSIX RT standard but some OS
|
||||
// still do not define this in time.h
|
||||
//
|
||||
struct timespec {
|
||||
time_t tv_sec; /* seconds since some epoch */
|
||||
long tv_nsec; /* nanoseconds within the second */
|
||||
};
|
||||
|
||||
struct tm *gmtime_r (const time_t *, struct tm *);
|
||||
struct tm *localtime_r (const time_t *, struct tm *);
|
||||
#endif
|
||||
|
||||
//
|
||||
// force this module to include code that can convert
|
||||
// to GDD's aitTimeStamp, but dont require that it must
|
||||
// link with gdd. Therefore, gdd.h is not included here.
|
||||
//
|
||||
class aitTimeStamp {
|
||||
public:
|
||||
unsigned long tv_sec;
|
||||
unsigned long tv_nsec;
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
//
|
||||
// osiTime (const unsigned long secIn, const unsigned long nSecIn)
|
||||
@@ -63,88 +116,182 @@ osiTime osiTime::getCurrent ()
|
||||
}
|
||||
|
||||
//
|
||||
// this is part of the POSIX RT standard but some OS
|
||||
// still do not define this so this code intentionally
|
||||
// does not include header files that do define this
|
||||
// loadTimeInit
|
||||
//
|
||||
struct timespec {
|
||||
unsigned long tv_sec; /* seconds */
|
||||
unsigned long tv_nsec; /* nanoseconds */
|
||||
class loadTimeInit {
|
||||
public:
|
||||
loadTimeInit ();
|
||||
|
||||
long epicsEpochOffset; // integer seconds
|
||||
long double time_tTicksPerSec;
|
||||
};
|
||||
|
||||
static const loadTimeInit lti;
|
||||
|
||||
//
|
||||
// loadTimeInit ()
|
||||
//
|
||||
loadTimeInit::loadTimeInit ()
|
||||
{
|
||||
long secWest;
|
||||
|
||||
{
|
||||
time_t current = time (NULL);
|
||||
time_t error;
|
||||
tm date;
|
||||
|
||||
gmtime_r (¤t, &date);
|
||||
error = mktime (&date);
|
||||
secWest = static_cast<long> (difftime (error, current));
|
||||
}
|
||||
|
||||
{
|
||||
time_t first = static_cast<time_t> (0);
|
||||
time_t last = static_cast<time_t> (1);
|
||||
this->time_tTicksPerSec = 1.0 / difftime (last, first);
|
||||
}
|
||||
|
||||
{
|
||||
struct tm tmEpicsEpoch;
|
||||
time_t epicsEpoch;
|
||||
time_t ansiEpoch = 0;
|
||||
|
||||
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);
|
||||
//
|
||||
// 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<long> (difftime (epicsEpoch, ansiEpoch));
|
||||
this->epicsEpochOffset -= secWest;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ansiSecToInternalSec ()
|
||||
//
|
||||
unsigned long osiTime::time_tToInternalSec (const time_t &ansiTimeTicks)
|
||||
{
|
||||
unsigned long sec;
|
||||
|
||||
sec = static_cast<unsigned long> (ansiTimeTicks / lti.time_tTicksPerSec);
|
||||
|
||||
// expect over / under flow
|
||||
if (lti.epicsEpochOffset>=0) {
|
||||
sec -= static_cast<unsigned long>(lti.epicsEpochOffset);
|
||||
}
|
||||
else {
|
||||
sec += static_cast<unsigned long>(-lti.epicsEpochOffset);
|
||||
}
|
||||
|
||||
return sec;
|
||||
}
|
||||
|
||||
//
|
||||
// operator time_t_wrapper ()
|
||||
//
|
||||
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<unsigned long>(lti.epicsEpochOffset);
|
||||
}
|
||||
else {
|
||||
newSec = this->sec + static_cast<unsigned long>(-lti.epicsEpochOffset);
|
||||
}
|
||||
tmp = newSec * lti.time_tTicksPerSec;
|
||||
tmp += (this->nSec * lti.time_tTicksPerSec) / nSecPerSec;
|
||||
wrap.ts = static_cast<time_t> (tmp);
|
||||
return wrap;
|
||||
}
|
||||
|
||||
//
|
||||
// convert to and from ANSI C struct tm (with nano seconds)
|
||||
//
|
||||
osiTime::operator tm_nano_sec () const
|
||||
{
|
||||
struct tm_nano_sec tm;
|
||||
time_t_wrapper ansiTimeTicks;
|
||||
|
||||
ansiTimeTicks = *this;
|
||||
|
||||
// from POSIX RT
|
||||
localtime_r (&ansiTimeTicks.ts, &tm.tm);
|
||||
|
||||
tm.nsec = this->nSec;
|
||||
|
||||
return tm;
|
||||
}
|
||||
|
||||
//
|
||||
// osiTime (const struct tm_nano_sec &tm)
|
||||
//
|
||||
osiTime::osiTime (const struct tm_nano_sec &tm)
|
||||
{
|
||||
time_t ansiTimeTicks;
|
||||
struct tm tmp = tm.tm;
|
||||
|
||||
ansiTimeTicks = mktime (&tmp);
|
||||
assert (ansiTimeTicks!=(time_t)-1);
|
||||
|
||||
this->sec = osiTime::time_tToInternalSec (ansiTimeTicks);
|
||||
this->nSec = tm.nsec;
|
||||
}
|
||||
|
||||
//
|
||||
// operator struct timespec ()
|
||||
//
|
||||
osiTime::operator struct timespec () const
|
||||
inline osiTime::operator struct timespec () const
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = this->sec + osiTime::epicsEpochSecPast1970;
|
||||
ts.tv_nsec = this->nSec;
|
||||
time_t_wrapper ansiTimeTicks;
|
||||
|
||||
ansiTimeTicks = *this;
|
||||
ts.tv_sec = ansiTimeTicks.ts;
|
||||
ts.tv_nsec = static_cast<long> (this->nSec);
|
||||
return ts;
|
||||
}
|
||||
|
||||
//
|
||||
// osiTime (const struct timespec &ts)
|
||||
//
|
||||
osiTime::osiTime (const struct timespec &ts)
|
||||
inline osiTime::osiTime (const struct timespec &ts)
|
||||
{
|
||||
if (ts.tv_sec >= osiTime::epicsEpochSecPast1970) {
|
||||
this->sec = ts.tv_sec - osiTime::epicsEpochSecPast1970;
|
||||
this->sec = osiTime::time_tToInternalSec (ts.tv_sec);
|
||||
assert (ts.tv_nsec>=0);
|
||||
unsigned long nSec = static_cast<unsigned long> (ts.tv_nsec);
|
||||
if (nSec<nSecPerSec) {
|
||||
this->nSec = nSec;
|
||||
}
|
||||
else {
|
||||
this->sec = 0;
|
||||
}
|
||||
|
||||
if (ts.tv_nsec<osiTime::nSecPerSec) {
|
||||
this->nSec = ts.tv_nsec;
|
||||
}
|
||||
else {
|
||||
this->sec += ts.tv_nsec / osiTime::nSecPerSec;
|
||||
this->nSec = ts.tv_nsec % osiTime::nSecPerSec;
|
||||
this->sec += nSec / nSecPerSec;
|
||||
this->nSec = nSec % nSecPerSec;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// operator = (const struct timespec &rhs)
|
||||
//
|
||||
osiTime osiTime::operator = (const struct timespec &rhs)
|
||||
{
|
||||
if (rhs.tv_sec >= osiTime::epicsEpochSecPast1970) {
|
||||
this->sec = rhs.tv_sec - osiTime::epicsEpochSecPast1970;
|
||||
}
|
||||
else {
|
||||
this->sec = 0;
|
||||
}
|
||||
|
||||
if (rhs.tv_nsec<osiTime::nSecPerSec) {
|
||||
this->nSec = rhs.tv_nsec;
|
||||
}
|
||||
else {
|
||||
this->sec += rhs.tv_nsec / osiTime::nSecPerSec;
|
||||
this->nSec = rhs.tv_nsec % osiTime::nSecPerSec;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// force this module to include code that can convert
|
||||
// to GDD's aitTimeStamp, but dont require that it must
|
||||
// link with gdd. Therefore, gdd.h is not included here.
|
||||
//
|
||||
class aitTimeStamp {
|
||||
public:
|
||||
unsigned long tv_sec;
|
||||
unsigned long tv_nsec;
|
||||
};
|
||||
|
||||
//
|
||||
// operator aitTimeStamp ()
|
||||
//
|
||||
osiTime::operator aitTimeStamp () const
|
||||
{
|
||||
aitTimeStamp ts;
|
||||
ts.tv_sec = this->sec + osiTime::epicsEpochSecPast1970;
|
||||
time_t_wrapper ansiTimeTicks;
|
||||
|
||||
ansiTimeTicks = *this;
|
||||
ts.tv_sec = ansiTimeTicks.ts;
|
||||
ts.tv_nsec = this->nSec;
|
||||
return ts;
|
||||
}
|
||||
@@ -154,43 +301,17 @@ osiTime::operator aitTimeStamp () const
|
||||
//
|
||||
osiTime::osiTime (const aitTimeStamp &ts)
|
||||
{
|
||||
if (ts.tv_sec >= osiTime::epicsEpochSecPast1970) {
|
||||
this->sec = ts.tv_sec - osiTime::epicsEpochSecPast1970;
|
||||
}
|
||||
else {
|
||||
this->sec = 0;
|
||||
}
|
||||
this->sec = osiTime::time_tToInternalSec (ts.tv_sec);
|
||||
|
||||
if (ts.tv_nsec<osiTime::nSecPerSec) {
|
||||
if (ts.tv_nsec<nSecPerSec) {
|
||||
this->nSec = ts.tv_nsec;
|
||||
}
|
||||
else {
|
||||
this->sec += ts.tv_nsec / osiTime::nSecPerSec;
|
||||
this->nSec = ts.tv_nsec % osiTime::nSecPerSec;
|
||||
this->sec += ts.tv_nsec / nSecPerSec;
|
||||
this->nSec = ts.tv_nsec % nSecPerSec;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// operator = (const aitTimeStamp &rhs)
|
||||
//
|
||||
osiTime osiTime::operator = (const aitTimeStamp &rhs)
|
||||
{
|
||||
if (rhs.tv_sec >= osiTime::epicsEpochSecPast1970) {
|
||||
this->sec = rhs.tv_sec - osiTime::epicsEpochSecPast1970;
|
||||
}
|
||||
else {
|
||||
this->sec = 0;
|
||||
}
|
||||
if (rhs.tv_nsec<osiTime::nSecPerSec) {
|
||||
this->nSec = rhs.tv_nsec;
|
||||
}
|
||||
else {
|
||||
this->sec += rhs.tv_nsec / osiTime::nSecPerSec;
|
||||
this->nSec = rhs.tv_nsec % osiTime::nSecPerSec;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// operator TS_STAMP ()
|
||||
//
|
||||
@@ -211,112 +332,138 @@ osiTime::osiTime (const struct TS_STAMP &ts)
|
||||
this->nSec = ts.nsec;
|
||||
}
|
||||
|
||||
//
|
||||
// operator = (const TS_STAMP &rhs)
|
||||
//
|
||||
osiTime osiTime::operator = (const struct TS_STAMP &rhs)
|
||||
{
|
||||
this->sec = rhs.secPastEpoch;
|
||||
this->nSec = rhs.nsec;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// osiTime::show (unsigned)
|
||||
//
|
||||
void osiTime::show (unsigned) const
|
||||
{
|
||||
//
|
||||
// lame way to print the time ...
|
||||
//
|
||||
printf ("osiTime: sec=%lu nSec=%lu\n",
|
||||
this->sec, this->nSec);
|
||||
int status;
|
||||
char bigBuffer[256];
|
||||
tm_nano_sec tmns = *this;
|
||||
|
||||
status = strftime (bigBuffer, sizeof(bigBuffer), "%c", &tmns.tm);
|
||||
if (status>0) {
|
||||
printf ("osiTime: %s %f\n", bigBuffer,
|
||||
static_cast <double> (tmns.nsec) / nSecPerSec);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// osiTime::operator + (const long double &rhs)
|
||||
//
|
||||
// rhs has units seconds
|
||||
//
|
||||
inline osiTime osiTime::operator + (const long double &rhs) const
|
||||
{
|
||||
unsigned long newSec, newNSec, secOffset, nSecOffset;
|
||||
long double fnsec;
|
||||
|
||||
if (rhs >= 0) {
|
||||
secOffset = static_cast <unsigned long> (rhs);
|
||||
fnsec = rhs - static_cast <long double> (secOffset);
|
||||
nSecOffset = static_cast <unsigned long> (fnsec * nSecPerSec);
|
||||
|
||||
newSec = this->sec + secOffset; // overflow expected
|
||||
newNSec = this->nSec + nSecOffset;
|
||||
if (newNSec >= nSecPerSec) {
|
||||
newSec++; // overflow expected
|
||||
newNSec -= nSecPerSec;
|
||||
}
|
||||
}
|
||||
else {
|
||||
secOffset = static_cast <unsigned long> (-rhs);
|
||||
fnsec = rhs + static_cast <long double> (secOffset);
|
||||
nSecOffset = static_cast <unsigned long> (-fnsec * nSecPerSec);
|
||||
|
||||
newSec = this->sec - secOffset; // underflow expected
|
||||
if (this->nSec>=nSecOffset) {
|
||||
newNSec = this->nSec - nSecOffset;
|
||||
}
|
||||
else {
|
||||
// borrow
|
||||
newSec--; // underflow expected
|
||||
newNSec = this->nSec + (nSecPerSec - nSecOffset);
|
||||
}
|
||||
}
|
||||
return osiTime (newSec, newNSec);
|
||||
}
|
||||
|
||||
//
|
||||
// operator -
|
||||
//
|
||||
// Since negative discontinuities in time are of particular
|
||||
// concern, the "A-B" operator has special code executed
|
||||
// as follows:
|
||||
// To make this code robust during timestamp rollover events
|
||||
// time stamp differences greater than one half full scale are
|
||||
// interpreted as rollover situations:
|
||||
//
|
||||
// when B is greater than A:
|
||||
// B-A > one half full scale => assume time stamp wrap around
|
||||
// B-A <= one half full scale => return a difference of zero
|
||||
// when RHS is greater than THIS:
|
||||
// RHS-THIS > one half full scale => return THIS + (ULONG_MAX-RHS)
|
||||
// RHS-THIS <= one half full scale => return -(RHS-THIS)
|
||||
//
|
||||
// when A is greater than or equal to B
|
||||
// A-B > one half full scale => return a difference of zero
|
||||
// A-B <= one half full scale => return A-B
|
||||
// when THIS is greater than or equal to RHS
|
||||
// THIS-RHS > one half full scale => return -(RHS + (ULONG_MAX-THIS))
|
||||
// THIS-RHS <= one half full scale => return THIS-RHS
|
||||
//
|
||||
osiTime osiTime::operator - (const osiTime &rhs) const
|
||||
long double osiTime::operator - (const osiTime &rhs) const
|
||||
{
|
||||
unsigned long nSecRes, secRes;
|
||||
long double nSecRes, secRes;
|
||||
|
||||
//
|
||||
// first compute the difference between the nano-seconds members
|
||||
//
|
||||
// nano sec member is not allowed to be greater that 1/2 full scale
|
||||
// so the unsigned to signed conversion is ok
|
||||
//
|
||||
if (this->nSec>=rhs.nSec) {
|
||||
nSecRes = this->nSec - rhs.nSec;
|
||||
}
|
||||
else {
|
||||
nSecRes = rhs.nSec - this->nSec;
|
||||
nSecRes = -nSecRes;
|
||||
}
|
||||
|
||||
//
|
||||
// next compute the difference between the seconds memebers
|
||||
// and invert the sign of the nano seconds result if there
|
||||
// is a range violation
|
||||
//
|
||||
if (this->sec<rhs.sec) {
|
||||
if (rhs.sec-this->sec < ULONG_MAX/2) {
|
||||
//
|
||||
// In this situation where the difference is less than
|
||||
// 69 years assume that someone adjusted the time
|
||||
// backwards slightly. This would happen if a high
|
||||
// resolution counter drift was realigned to some master
|
||||
// time source
|
||||
//
|
||||
return osiTime ();
|
||||
}
|
||||
else {
|
||||
secRes = rhs.sec - this->sec;
|
||||
if (secRes > ULONG_MAX/2) {
|
||||
//
|
||||
// In this situation where the difference is more than
|
||||
// 69 years assume that the seconds counter has rolled
|
||||
// 68 years assume that the seconds counter has rolled
|
||||
// over and compute the "wrap around" difference
|
||||
//
|
||||
secRes = 1 + this->sec + (ULONG_MAX - rhs.sec);
|
||||
secRes = 1 + (ULONG_MAX-secRes);
|
||||
nSecRes = -nSecRes;
|
||||
}
|
||||
else {
|
||||
secRes = -secRes;
|
||||
}
|
||||
}
|
||||
else {
|
||||
secRes = this->sec - rhs.sec;
|
||||
if (secRes > ULONG_MAX/2) {
|
||||
//
|
||||
// assume that someone adjusted the time
|
||||
// backwards slightly. This would happen if a high
|
||||
// resolution counter drift was realigned to some master
|
||||
// time source
|
||||
// In this situation where the difference is more than
|
||||
// 68 years assume that the seconds counter has rolled
|
||||
// over and compute the "wrap around" difference
|
||||
//
|
||||
return osiTime ();
|
||||
secRes = 1 + (ULONG_MAX-secRes);
|
||||
secRes = -secRes;
|
||||
nSecRes = -nSecRes;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->nSec>=rhs.nSec) {
|
||||
nSecRes = this->nSec - rhs.nSec;
|
||||
}
|
||||
else {
|
||||
|
||||
if (secRes>0) {
|
||||
//
|
||||
// Borrow
|
||||
//
|
||||
nSecRes = this->nSec + (osiTime::nSecPerSec - rhs.nSec);
|
||||
secRes--;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// In this situation where the difference is less than
|
||||
// 69 years assume that someone adjusted the time
|
||||
// backwards slightly. This would happen if the high
|
||||
// resolution counter drift was realigned to some master
|
||||
// time source
|
||||
//
|
||||
return osiTime ();
|
||||
}
|
||||
}
|
||||
return osiTime (secRes, nSecRes);
|
||||
return secRes + nSecRes/nSecPerSec;
|
||||
}
|
||||
|
||||
//
|
||||
// operator <=
|
||||
//
|
||||
int osiTime::operator <= (const osiTime &rhs) const
|
||||
bool osiTime::operator <= (const osiTime &rhs) const
|
||||
{
|
||||
int rc;
|
||||
bool rc;
|
||||
|
||||
if (this->sec<rhs.sec) {
|
||||
if (rhs.sec-this->sec < ULONG_MAX/2) {
|
||||
@@ -324,7 +471,7 @@ int osiTime::operator <= (const osiTime &rhs) const
|
||||
// In this situation where the difference is less than
|
||||
// 69 years compute the expected result
|
||||
//
|
||||
rc = 1;
|
||||
rc = true;
|
||||
}
|
||||
else {
|
||||
//
|
||||
@@ -332,7 +479,7 @@ int osiTime::operator <= (const osiTime &rhs) const
|
||||
// 69 years assume that the seconds counter has rolled
|
||||
// over and compute the "wrap around" result
|
||||
//
|
||||
rc = 0;
|
||||
rc = false;
|
||||
}
|
||||
}
|
||||
else if (this->sec>rhs.sec) {
|
||||
@@ -341,7 +488,7 @@ int osiTime::operator <= (const osiTime &rhs) const
|
||||
// In this situation where the difference is less than
|
||||
// 69 years compute the expected result
|
||||
//
|
||||
rc = 0;
|
||||
rc = false;
|
||||
}
|
||||
else {
|
||||
//
|
||||
@@ -349,15 +496,15 @@ int osiTime::operator <= (const osiTime &rhs) const
|
||||
// 69 years assume that the seconds counter has rolled
|
||||
// over and compute the "wrap around" result
|
||||
//
|
||||
rc = 1;
|
||||
rc = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this->nSec<=rhs.nSec) {
|
||||
rc = 1;
|
||||
rc = true;
|
||||
}
|
||||
else {
|
||||
rc = 0;
|
||||
rc = false;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -366,9 +513,9 @@ int osiTime::operator <= (const osiTime &rhs) const
|
||||
//
|
||||
// operator <
|
||||
//
|
||||
int osiTime::operator < (const osiTime &rhs) const
|
||||
bool osiTime::operator < (const osiTime &rhs) const
|
||||
{
|
||||
int rc;
|
||||
bool rc;
|
||||
|
||||
if (this->sec<rhs.sec) {
|
||||
if (rhs.sec-this->sec < ULONG_MAX/2) {
|
||||
@@ -376,7 +523,7 @@ int osiTime::operator < (const osiTime &rhs) const
|
||||
// In this situation where the difference is less than
|
||||
// 69 years compute the expected result
|
||||
//
|
||||
rc = 1;
|
||||
rc = true;
|
||||
}
|
||||
else {
|
||||
//
|
||||
@@ -384,7 +531,7 @@ int osiTime::operator < (const osiTime &rhs) const
|
||||
// 69 years assume that the seconds counter has rolled
|
||||
// over and compute the "wrap around" result
|
||||
//
|
||||
rc = 0;
|
||||
rc = false;
|
||||
}
|
||||
}
|
||||
else if (this->sec>rhs.sec) {
|
||||
@@ -393,7 +540,7 @@ int osiTime::operator < (const osiTime &rhs) const
|
||||
// In this situation where the difference is less than
|
||||
// 69 years compute the expected result
|
||||
//
|
||||
rc = 0;
|
||||
rc = false;
|
||||
}
|
||||
else {
|
||||
//
|
||||
@@ -401,16 +548,17 @@ int osiTime::operator < (const osiTime &rhs) const
|
||||
// 69 years assume that the seconds counter has rolled
|
||||
// over and compute the "wrap around" result
|
||||
//
|
||||
rc = 1;
|
||||
rc = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this->nSec<rhs.nSec) {
|
||||
rc = 1;
|
||||
rc = true;
|
||||
}
|
||||
else {
|
||||
rc = 0;
|
||||
rc = false;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,84 +27,56 @@
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
*
|
||||
* History
|
||||
* $Log$
|
||||
* Revision 1.10 1999/05/07 20:34:50 jhill
|
||||
* fixed operator return type
|
||||
*
|
||||
* Revision 1.9 1999/05/07 19:12:39 jhill
|
||||
* many improvements to osiTime
|
||||
*
|
||||
* Revision 1.8 1999/05/03 16:22:29 jhill
|
||||
* allow osiTime to convert toaitTimeStamp without binding to gdd
|
||||
*
|
||||
* Revision 1.7 1999/04/30 00:02:02 jhill
|
||||
* added getCurrentEPICS()
|
||||
*
|
||||
* Revision 1.6 1997/06/13 09:31:46 jhill
|
||||
* fixed warnings
|
||||
*
|
||||
* Revision 1.5 1997/04/10 19:45:41 jhill
|
||||
* API changes and include with not <>
|
||||
*
|
||||
* Revision 1.4 1996/11/02 02:06:00 jhill
|
||||
* const param => #define
|
||||
*
|
||||
* Revision 1.3 1996/09/04 21:53:36 jhill
|
||||
* allow use with goofy vxWorks 5.2 time spec - which has unsigned sec and
|
||||
* signed nsec
|
||||
*
|
||||
* Revision 1.2 1996/07/09 23:01:04 jhill
|
||||
* added new operators
|
||||
*
|
||||
* Revision 1.1 1996/06/26 22:14:11 jhill
|
||||
* added new src files
|
||||
*
|
||||
* Revision 1.2 1996/06/21 02:03:40 jhill
|
||||
* added stdio.h include
|
||||
*
|
||||
* Revision 1.1.1.1 1996/06/20 22:15:56 jhill
|
||||
* installed ca server templates
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef osiTimehInclude
|
||||
#define osiTimehInclude
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#ifndef assert // allows use of epicsAssert.h
|
||||
#include <assert.h>
|
||||
#endif
|
||||
//
|
||||
// ANSI C
|
||||
//
|
||||
#include <time.h>
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
struct timespec;
|
||||
struct TS_STAMP;
|
||||
class aitTimeStamp;
|
||||
struct TS_STAMP; // EPICS
|
||||
class aitTimeStamp; // GDD
|
||||
struct timespec; // POSIX real time
|
||||
|
||||
//
|
||||
// an extended ANSI C RTL "struct tm" which includes nano seconds.
|
||||
//
|
||||
struct tm_nano_sec {
|
||||
tm tm; // ANSI C time details
|
||||
unsigned long nsec; // nano seconds extension
|
||||
};
|
||||
|
||||
//
|
||||
// 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 {
|
||||
time_t ts;
|
||||
};
|
||||
|
||||
//
|
||||
// class osiTime
|
||||
//
|
||||
// NOTE: this is an unsigned data type. It is not possible
|
||||
// to store a negative time value using this class.
|
||||
// high resolution osiTime stamp
|
||||
//
|
||||
class epicsShareClass osiTime {
|
||||
public:
|
||||
|
||||
//
|
||||
// fetch the current time
|
||||
//
|
||||
// (always returns a time value that is greater than or equal
|
||||
// to all previous time values returned)
|
||||
//
|
||||
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 osiTime to realign the high
|
||||
// this routine will cause class "time" to realign the high
|
||||
// resolution result from getCurrent() with some master
|
||||
// time base.
|
||||
//
|
||||
@@ -117,24 +89,8 @@ public:
|
||||
//
|
||||
// create an osiTime for the EPICS epoch
|
||||
//
|
||||
osiTime () : sec(0u), nSec(0u) {}
|
||||
|
||||
//
|
||||
// create an osiTime from another osiTime
|
||||
//
|
||||
osiTime (const osiTime &t) : sec(t.sec), nSec(t.nSec) {}
|
||||
|
||||
//
|
||||
// create an osiTime from sec and fractional nano-seconds
|
||||
//
|
||||
osiTime (const unsigned long secIn, const unsigned long nSecIn);
|
||||
|
||||
//
|
||||
// convert to and from floating point
|
||||
//
|
||||
osiTime (double t);
|
||||
operator double() const;
|
||||
operator float() const;
|
||||
osiTime ();
|
||||
osiTime (const osiTime &t);
|
||||
|
||||
//
|
||||
// convert to and from EPICS TS_STAMP format
|
||||
@@ -144,11 +100,22 @@ public:
|
||||
osiTime operator = (const struct TS_STAMP &rhs);
|
||||
|
||||
//
|
||||
// convert to and from GDD's aitTimeStamp format
|
||||
// convert to and from ANSI C's "time_t"
|
||||
//
|
||||
operator aitTimeStamp () const;
|
||||
osiTime (const aitTimeStamp &ts);
|
||||
osiTime operator = (const aitTimeStamp &rhs);
|
||||
// "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 POSIX RT's "struct timespec"
|
||||
@@ -157,23 +124,31 @@ public:
|
||||
osiTime (const struct timespec &ts);
|
||||
osiTime operator = (const struct timespec &rhs);
|
||||
|
||||
//
|
||||
// convert to and from GDD's aitTimeStamp format
|
||||
//
|
||||
operator aitTimeStamp () const;
|
||||
osiTime (const aitTimeStamp &ts);
|
||||
osiTime operator = (const aitTimeStamp &rhs);
|
||||
|
||||
//
|
||||
// arithmetic operators
|
||||
//
|
||||
osiTime operator- (const osiTime &rhs) const;
|
||||
osiTime operator+ (const osiTime &rhs) const;
|
||||
osiTime operator+= (const osiTime &rhs);
|
||||
osiTime operator-= (const osiTime &rhs);
|
||||
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
|
||||
//
|
||||
int operator == (const osiTime &rhs) const;
|
||||
int operator != (const osiTime &rhs) const;
|
||||
int operator <= (const osiTime &rhs) const;
|
||||
int operator < (const osiTime &rhs) const;
|
||||
int operator >= (const osiTime &rhs) const;
|
||||
int operator > (const osiTime &rhs) const;
|
||||
bool operator == (const osiTime &rhs) const;
|
||||
bool operator != (const osiTime &rhs) const;
|
||||
bool operator <= (const osiTime &rhs) const;
|
||||
bool operator < (const osiTime &rhs) const;
|
||||
bool operator >= (const osiTime &rhs) const;
|
||||
bool operator > (const osiTime &rhs) const;
|
||||
|
||||
//
|
||||
// dump current state to standard out
|
||||
@@ -183,107 +158,79 @@ public:
|
||||
//
|
||||
// useful public constants
|
||||
//
|
||||
static const unsigned nSecPerSec;
|
||||
static const unsigned mSecPerSec;
|
||||
static const unsigned nSecPerUSec;
|
||||
static const unsigned secPerMin;
|
||||
|
||||
//
|
||||
// fetch value as an unsigned integer
|
||||
//
|
||||
unsigned long getSec() const;
|
||||
unsigned long getUSec() const;
|
||||
unsigned long getNSec() const;
|
||||
|
||||
//
|
||||
// non standard calls for the many different
|
||||
// time formats that exist
|
||||
//
|
||||
long getSecTruncToLong() const;
|
||||
long getUSecTruncToLong() const;
|
||||
long getNSecTruncToLong() const;
|
||||
static const unsigned mSecPerSec;
|
||||
static const unsigned uSecPerSec;
|
||||
static const unsigned nSecPerSec;
|
||||
static const unsigned nSecPerUSec;
|
||||
|
||||
private:
|
||||
unsigned long sec; /* seconds since O000 Jan 1, 1990 */
|
||||
unsigned long nSec; /* nanoseconds within second */
|
||||
|
||||
static const unsigned epicsEpochSecPast1970;
|
||||
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)
|
||||
//
|
||||
osiTime (unsigned long sec, unsigned long nSec);
|
||||
};
|
||||
|
||||
inline unsigned long osiTime::getSec() const
|
||||
/////////////////////////////////////
|
||||
//
|
||||
// time inline member functions
|
||||
//
|
||||
/////////////////////////////////////
|
||||
|
||||
inline osiTime::osiTime () : sec(0u), nSec(0u) {}
|
||||
|
||||
inline osiTime::osiTime (const osiTime &t) : sec(t.sec), nSec(t.nSec) {}
|
||||
|
||||
inline osiTime osiTime::operator - (const long double &rhs) const
|
||||
{
|
||||
return this->sec;
|
||||
return osiTime::operator + (-rhs);
|
||||
}
|
||||
|
||||
inline unsigned long osiTime::getUSec() const
|
||||
{
|
||||
return (this->nSec/nSecPerUSec);
|
||||
}
|
||||
|
||||
inline unsigned long osiTime::getNSec() const
|
||||
{
|
||||
return this->nSec;
|
||||
}
|
||||
|
||||
inline osiTime::osiTime (double t)
|
||||
inline osiTime osiTime::operator += (const long double &rhs)
|
||||
{
|
||||
assert (t>=0.0);
|
||||
this->sec = (unsigned long) t;
|
||||
this->nSec = (unsigned long) ((t-this->sec)*nSecPerSec);
|
||||
}
|
||||
|
||||
inline osiTime::operator double() const
|
||||
{
|
||||
return ((double)this->nSec)/nSecPerSec+this->sec;
|
||||
}
|
||||
|
||||
inline osiTime::operator float() const
|
||||
{
|
||||
return ((float)this->nSec)/nSecPerSec+this->sec;
|
||||
}
|
||||
|
||||
inline osiTime osiTime::operator + (const osiTime &rhs) const
|
||||
{
|
||||
return osiTime(this->sec + rhs.sec, this->nSec + rhs.nSec);
|
||||
}
|
||||
|
||||
inline osiTime osiTime::operator += (const osiTime &rhs)
|
||||
{
|
||||
*this = *this + rhs;
|
||||
*this = osiTime::operator + (rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline osiTime osiTime::operator -= (const osiTime &rhs)
|
||||
inline osiTime osiTime::operator -= (const long double &rhs)
|
||||
{
|
||||
*this = *this - rhs;
|
||||
*this = osiTime::operator + (-rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline int osiTime::operator == (const osiTime &rhs) const
|
||||
inline bool osiTime::operator == (const osiTime &rhs) const
|
||||
{
|
||||
if (this->sec == rhs.sec && this->nSec == rhs.nSec) {
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline int osiTime::operator != (const osiTime &rhs) const
|
||||
//
|
||||
// operator !=
|
||||
//
|
||||
inline bool osiTime::operator != (const osiTime &rhs) const
|
||||
{
|
||||
if (this->sec != rhs.sec || this->nSec != rhs.nSec) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return !osiTime::operator == (rhs);
|
||||
}
|
||||
|
||||
//
|
||||
// operator >= (const osiTime &lhs, const osiTime &rhs)
|
||||
//
|
||||
inline int osiTime::operator >= (const osiTime &rhs) const
|
||||
inline bool osiTime::operator >= (const osiTime &rhs) const
|
||||
{
|
||||
return !(*this < rhs);
|
||||
}
|
||||
@@ -291,26 +238,61 @@ inline int osiTime::operator >= (const osiTime &rhs) const
|
||||
//
|
||||
// operator > (const osiTime &lhs, const osiTime &rhs)
|
||||
//
|
||||
inline int osiTime::operator > (const osiTime &rhs) const
|
||||
inline bool osiTime::operator > (const osiTime &rhs) const
|
||||
{
|
||||
return !(*this <= rhs);
|
||||
}
|
||||
|
||||
inline long osiTime::getSecTruncToLong() const
|
||||
//
|
||||
// osiTime operator = (const struct tm_nano_sec &rhs)
|
||||
//
|
||||
inline osiTime osiTime::operator = (const struct tm_nano_sec &rhs)
|
||||
{
|
||||
assert (this->sec<=LONG_MAX);
|
||||
return (long) this->sec;
|
||||
return *this = osiTime (rhs);
|
||||
}
|
||||
|
||||
inline long osiTime::getUSecTruncToLong() const
|
||||
{
|
||||
return (long) (this->nSec/nSecPerUSec);
|
||||
//
|
||||
// operator = (const struct timespec &rhs)
|
||||
//
|
||||
inline osiTime osiTime::operator = (const struct timespec &rhs)
|
||||
{
|
||||
*this = osiTime (rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline long osiTime::getNSecTruncToLong() const
|
||||
{
|
||||
return (long) this->nSec;
|
||||
//
|
||||
// operator = (const aitTimeStamp &rhs)
|
||||
//
|
||||
inline osiTime osiTime::operator = (const aitTimeStamp &rhs)
|
||||
{
|
||||
*this = osiTime (rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // osiTimehInclude
|
||||
|
||||
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)
|
||||
{
|
||||
this->sec = osiTime::time_tToInternalSec (ansiTimeTicks.ts);
|
||||
this->nSec = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
Reference in New Issue
Block a user