epicsTime roundTimeDown(const epicsTime &time, double secs) { if (secs <= 0.0) return time; struct local_tm_nano_sec tm; unsigned long round, full_secs; if (secs < 1.0) { epicsTimeStamp stamp = (epicsTimeStamp)time; round =(unsigned long)(secs * NSEC); stamp.nsec = (stamp.nsec / round)*round; return epicsTime(stamp); } else if (secs < secsPerDay) { full_secs = (unsigned long)secs; epicsTimeStamp stamp = (epicsTimeStamp)time; // secs >= 1.0, so nanosecs are 0 round = stamp.secPastEpoch / full_secs; stamp.secPastEpoch = (epicsUInt32) (round*secs); stamp.nsec = 0; return epicsTime(stamp); } else if (secs < secsPerMonth) { full_secs = (unsigned long)secs; tm = (local_tm_nano_sec) time; round = full_secs/secsPerDay; tm.nSec = 0; tm.ansi_tm.tm_sec = 0; tm.ansi_tm.tm_min = 0; tm.ansi_tm.tm_hour = 0; tm.ansi_tm.tm_mday = (tm.ansi_tm.tm_mday / round) * round; } else if (secs < secsPerYear) { full_secs = (unsigned long)secs; tm = (local_tm_nano_sec) time; round = full_secs/secsPerMonth; tm.nSec = 0; tm.ansi_tm.tm_sec = 0; tm.ansi_tm.tm_min = 0; tm.ansi_tm.tm_hour = 0; tm.ansi_tm.tm_mday = 1; tm.ansi_tm.tm_mon = (tm.ansi_tm.tm_mon / round) * round; } else { tm = (local_tm_nano_sec) time; tm.nSec = 0; tm.ansi_tm.tm_sec = 0; tm.ansi_tm.tm_min = 0; tm.ansi_tm.tm_hour = 0; tm.ansi_tm.tm_mday = 1; tm.ansi_tm.tm_mon = 0; } // TODO: round weeks, fortnights? return epicsTime(tm); }
epicsShareFunc void epicsShareAPI epicsTimeAddSeconds (epicsTimeStamp *pDest, double seconds) { try { *pDest = epicsTime (*pDest) + seconds; } catch ( ... ) { *pDest = epicsTime (); } }
epicsShareFunc int epicsShareAPI epicsTimeNotEqual (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight) { try { return epicsTime (*pLeft) != epicsTime (*pRight); } catch ( ... ) { return 1; } }
epicsShareFunc int epicsShareAPI epicsTimeLessThanEqual (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight) { try { return epicsTime (*pLeft) <= epicsTime (*pRight); } catch ( ... ) { return 0; } }
epicsShareFunc int epicsShareAPI epicsTimeGreaterThan (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight) { try { return epicsTime (*pLeft) > epicsTime (*pRight); } catch ( ... ) { return 0; } }
epicsShareFunc double epicsShareAPI epicsTimeDiffInSeconds (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight) { try { return epicsTime (*pLeft) - epicsTime (*pRight); } catch (...) { return - DBL_MAX; } }
epicsTime::epicsTime (const gm_tm_nano_sec &tm) { int year = tm.ansi_tm.tm_year + 1900; int month = tm.ansi_tm.tm_mon; if (month > 11) { year += month / 12; month %= 12; } else if (month < 0) { int years_diff = (-month + 11) / 12; year -= years_diff; month += 12 * years_diff; } month++; int day = tm.ansi_tm.tm_mday; int day_of_year = days_from_1jan(year, month, day); int days_since_epoch = days_from_1970(year) + day_of_year; time_t_wrapper ansiTimeTicks; ansiTimeTicks.ts = ((days_since_epoch * 24 + tm.ansi_tm.tm_hour) * 60 + tm.ansi_tm.tm_min) * 60 + tm.ansi_tm.tm_sec; *this = epicsTime(ansiTimeTicks); this->addNanoSec(tm.nSec); }
// // epicsTime::operator + (const double &rhs) // // rhs has units seconds // epicsTime epicsTime::operator + (const double &rhs) const { unsigned long newSec, newNSec, secOffset, nSecOffset; double fnsec; if (rhs >= 0) { secOffset = static_cast <unsigned long> (rhs); fnsec = rhs - secOffset; nSecOffset = static_cast <unsigned long> ( (fnsec * nSecPerSec) + 0.5 ); newSec = this->secPastEpoch + secOffset; // overflow expected newNSec = this->nSec + nSecOffset; if (newNSec >= nSecPerSec) { newSec++; // overflow expected newNSec -= nSecPerSec; } } else { secOffset = static_cast <unsigned long> (-rhs); fnsec = rhs + secOffset; nSecOffset = static_cast <unsigned long> ( (-fnsec * nSecPerSec) + 0.5 ); newSec = this->secPastEpoch - secOffset; // underflow expected if (this->nSec>=nSecOffset) { newNSec = this->nSec - nSecOffset; } else { // borrow newSec--; // underflow expected newNSec = this->nSec + (nSecPerSec - nSecOffset); } } return epicsTime (newSec, newNSec); }
// // epicsTime (const struct timespec &ts) // epicsTime::epicsTime (const struct timespec &ts) { time_t_wrapper ansiTimeTicks; ansiTimeTicks.ts = ts.tv_sec; *this = epicsTime (ansiTimeTicks); this->addNanoSec (ts.tv_nsec); }
// // epicsTime (const local_tm_nano_sec &tm) // epicsTime::epicsTime (const local_tm_nano_sec &tm) { static const time_t mktimeFailure = static_cast <time_t> (-1); time_t_wrapper ansiTimeTicks; struct tm tmp = tm.ansi_tm; ansiTimeTicks.ts = mktime (&tmp); if (ansiTimeTicks.ts == mktimeFailure) { throwWithLocation ( formatProblemWithStructTM () ); } *this = epicsTime (ansiTimeTicks); unsigned long nSecAdj = tm.nSec % nSecPerSec; unsigned long secAdj = tm.nSec / nSecPerSec; *this = epicsTime ( this->secPastEpoch+secAdj, this->nSec+nSecAdj ); }
epicsTime epicsTime::getEvent (const epicsTimeEvent &event) { epicsTimeStamp current; int status = epicsTimeGetEvent (¤t, event); if (status) { throwWithLocation ( unableToFetchCurrentTime () ); } return epicsTime ( current ); }
epicsShareFunc void epicsShareAPI epicsTimeShow (const epicsTimeStamp *pTS, unsigned interestLevel) { try { epicsTime(*pTS).show (interestLevel); } catch ( ... ) { printf ( "Invalid epicsTimeStamp\n" ); } }
epicsShareFunc size_t epicsShareAPI epicsTimeToStrftime (char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp *pTS) { try { return epicsTime(*pTS).strftime (pBuff, bufLength, pFormat); } catch ( ... ) { return 0; } }
epicsShareFunc int epicsShareAPI epicsTimeToTimespec (struct timespec *pDest, const epicsTimeStamp *pSrc) { try { *pDest = epicsTime (*pSrc); } catch (...) { return epicsTimeERROR; } return epicsTimeOK; }
epicsShareFunc int epicsShareAPI epicsTimeFromTimeval (epicsTimeStamp *pDest, const struct timeval *pSrc) { try { *pDest = epicsTime (*pSrc); } catch (...) { return epicsTimeERROR; } return epicsTimeOK; }
// // ANSI C interface // // its too bad that these cant be implemented with inline functions // at least when running the GNU compiler // epicsShareFunc int epicsShareAPI epicsTimeToTime_t (time_t *pDest, const epicsTimeStamp *pSrc) { try { time_t_wrapper dst = epicsTime (*pSrc); *pDest = dst.ts; } catch (...) { return epicsTimeERROR; } return epicsTimeOK; }
void bhe::unregisterIIU ( epicsGuard < epicsMutex > & guard, tcpiiu & iiu ) { guard.assertIdenticalMutex ( this->mutex ); if ( this->pIIU == & iiu ) { this->pIIU = 0; this->timeStamp = epicsTime(); this->averagePeriod = - DBL_MAX; logBeacon ( "ui", this->averagePeriod, epicsTime::getCurrent () ); } }
static int osdTimeGetCurrent (epicsTimeStamp *pDest) { struct timeval tv; struct timezone tz; if (gettimeofday (&tv, &tz)) return epicsTimeERROR; *pDest = epicsTime(tv); return epicsTimeOK; }
static void format_time(const epicsTime &time, stdString &text) { if (only_millisecs) { epicsTimeStamp stamp = time; stamp.nsec = ((stamp.nsec + 500000) / 1000000) * 1000000; epicsTime2string(epicsTime(stamp), text); text = text.substr(0, 23); return; } epicsTime2string(time, text); }
epicsShareFunc int epicsShareAPI epicsTimeFromTime_t (epicsTimeStamp *pDest, time_t src) { try { time_t_wrapper dst; dst.ts = src; *pDest = epicsTime ( dst ); } catch (...) { return epicsTimeERROR; } return epicsTimeOK; }
epicsShareFunc int epicsShareAPI epicsTimeToGMTM (struct tm *pDest, unsigned long *pNSecDest, const epicsTimeStamp *pSrc) { try { gm_tm_nano_sec gmtmns = epicsTime (*pSrc); *pDest = gmtmns.ansi_tm; *pNSecDest = gmtmns.nSec; } catch (...) { return epicsTimeERROR; } return epicsTimeOK; }
epicsShareFunc int epicsShareAPI epicsTimeFromTM (epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc) { try { local_tm_nano_sec tmns; tmns.ansi_tm = *pSrc; tmns.nSec = nSecSrc; *pDest = epicsTime (tmns); } catch (...) { return epicsTimeERROR; } return epicsTimeOK; }
// // epicsTime (const local_tm_nano_sec &tm) // epicsTime::epicsTime (const local_tm_nano_sec &tm) { struct tm tmp = tm.ansi_tm; time_t_wrapper ansiTimeTicks = { mktime (&tmp) }; static const time_t mktimeError = static_cast <time_t> (-1); if (ansiTimeTicks.ts == mktimeError) { throwWithLocation ( formatProblemWithStructTM () ); } *this = epicsTime(ansiTimeTicks); this->addNanoSec(tm.nSec); }
bool cac::findOrCreateVirtCircuit ( epicsGuard < epicsMutex > & guard, const osiSockAddr & addr, unsigned priority, tcpiiu *& piiu, unsigned minorVersionNumber, SearchDestTCP * pSearchDest ) { guard.assertIdenticalMutex ( this->mutex ); bool newIIU = false; if ( piiu ) { if ( ! piiu->alive ( guard ) ) { return newIIU; } } else { try { autoPtrFreeList < tcpiiu, 32, epicsMutexNOOP > pnewiiu ( this->freeListVirtualCircuit, new ( this->freeListVirtualCircuit ) tcpiiu ( *this, this->mutex, this->cbMutex, this->notify, this->connTMO, this->timerQueue, addr, this->comBufMemMgr, minorVersionNumber, this->ipToAEngine, priority, pSearchDest ) ); bhe * pBHE = this->beaconTable.lookup ( addr.ia ); if ( ! pBHE ) { pBHE = new ( this->bheFreeList ) bhe ( this->mutex, epicsTime (), 0u, addr.ia ); if ( this->beaconTable.add ( *pBHE ) < 0 ) { return newIIU; } } this->serverTable.add ( *pnewiiu ); this->circuitList.add ( *pnewiiu ); this->iiuExistenceCount++; pBHE->registerIIU ( guard, *pnewiiu ); piiu = pnewiiu.release (); newIIU = true; } catch ( std :: exception & except ) { errlogPrintf ( "CAC: exception during virtual circuit creation \"%s\"\n", except.what () ); return newIIU; } catch ( ... ) { errlogPrintf ( "CAC: Nonstandard exception during virtual circuit creation\n" ); return newIIU; } } return newIIU; }
// // epicsTime (const struct timeval &ts) // epicsTime::epicsTime (const struct timeval &ts) { time_t_wrapper ansiTimeTicks; // On Posix systems timeval :: tv_sec is a time_t so this can be // a direct assignement. On other systems I dont know that we can // guarantee that time_t and timeval :: tv_sec will have the // same epoch or have the same scaling factor to discrete seconds. // For example, on windows time_t changed recently to a 64 bit // quantity but timeval is still a long. That can cause problems // on 32 bit systems. So technically, we should have an os // dependent conversion between time_t and timeval :: tv_sec? ansiTimeTicks.ts = ts.tv_sec; *this = epicsTime (ansiTimeTicks); this->addNanoSec (ts.tv_usec * nSecPerUSec); }
/* * update beacon period * * updates beacon period, and looks for beacon anomalies */ bool bhe::updatePeriod ( epicsGuard < epicsMutex > & guard, const epicsTime & programBeginTime, const epicsTime & currentTime, ca_uint32_t beaconNumber, unsigned protocolRevision ) { guard.assertIdenticalMutex ( this->mutex ); // // this block is enetered if the beacon was created as a side effect of // creating a connection and so we dont yet know the first beacon time // and sequence number // if ( this->timeStamp == epicsTime () ) { if ( CA_V410 ( protocolRevision ) ) { this->lastBeaconNumber = beaconNumber; } this->beaconAnomalyNotify ( guard ); /* * this is the 1st beacon seen - the beacon time stamp * was not initialized during BHE create because * a TCP/IP connection created the beacon. * (nothing to do but set the beacon time stamp and return) */ this->timeStamp = currentTime; logBeacon ( "fb", - DBL_MAX, currentTime ); return false; } // 1) detect beacon duplications due to redundant routes // 2) detect lost beacons due to input queue overrun or damage if ( CA_V410 ( protocolRevision ) ) { unsigned beaconSeqAdvance; if ( beaconNumber >= this->lastBeaconNumber ) { beaconSeqAdvance = beaconNumber - this->lastBeaconNumber; } else { beaconSeqAdvance = ( ca_uint32_max - this->lastBeaconNumber ) + beaconNumber; } this->lastBeaconNumber = beaconNumber; // throw out sequence numbers just prior to, or the same as, the last one received // (this situation is probably caused by a temporary duplicate route ) if ( beaconSeqAdvance == 0 || beaconSeqAdvance > ca_uint32_max - 256 ) { logBeaconDiscard ( beaconSeqAdvance, currentTime ); return false; } // throw out sequence numbers that jump forward by only a few numbers // (this situation is probably caused by a duplicate route // or a beacon due to input queue overun) if ( beaconSeqAdvance > 1 && beaconSeqAdvance < 4 ) { logBeaconDiscard ( beaconSeqAdvance, currentTime ); return false; } } // compute the beacon period (if we have seen at least two beacons) bool netChange = false; double currentPeriod = currentTime - this->timeStamp; if ( this->averagePeriod < 0.0 ) { double totalRunningTime; this->beaconAnomalyNotify ( guard ); /* * this is the 2nd beacon seen. We cant tell about * the change in period at this point so we just * initialize the average period and return. */ this->averagePeriod = currentPeriod; logBeacon ( "fp", currentPeriod, currentTime ); /* * ignore beacons seen for the first time shortly after * init, but do not ignore beacons arriving with a short * period because the IOC was rebooted soon after the * client starts up. */ totalRunningTime = this->timeStamp - programBeginTime; if ( currentPeriod <= totalRunningTime ) { netChange = true; } } else { /* * Is this an IOC seen because of a restored * network segment? * * It may be possible to get false triggers here * if the client is busy, but this does not cause * problems because the echo response will tell us * that the server is available */ if ( currentPeriod >= this->averagePeriod * 1.25 ) { /* * trigger on any missing beacon * if connected to this server */ this->beaconAnomalyNotify ( guard ); if ( currentPeriod >= this->averagePeriod * 3.25 ) { /* * trigger on any 3 contiguous missing beacons * if not connected to this server */ netChange = true; } logBeacon ( "bah", currentPeriod, currentTime ); } /* * Is this an IOC seen because of an IOC reboot * (beacon come at a higher rate just after the * IOC reboots). Lower tolarance here because we * dont have to worry about lost beacons. * * It may be possible to get false triggers here * if the client is busy, but this does not cause * problems because the echo response will tell us * that the server is available */ else if ( currentPeriod <= this->averagePeriod * 0.80 ) { this->beaconAnomalyNotify ( guard ); netChange = true; logBeacon ( "bal", currentPeriod, currentTime ); } else if ( this->pIIU ) { // update state of health for active virtual circuits // if the beacon looks ok this->pIIU->beaconArrivalNotify ( guard ); logBeacon ( "vb", currentPeriod, currentTime ); } // update a running average period this->averagePeriod = currentPeriod * 0.125 + this->averagePeriod * 0.875; } this->timeStamp = currentTime; return netChange; }
const RawValue::Data *OldDataReader::find( const stdString &channel_name, const epicsTime *start) { this->channel_name = channel_name; OldDirectoryFileIterator dfi = index.find(channel_name); if (!dfi.isValid()) { LOG_MSG ("OldDataReader: Cannot find '%s' in index\n", channel_name.c_str()); return 0; } if (start) { // look for time, start at end header = getHeader(index.getDirname(), dfi.entry.data.last_file, dfi.entry.data.last_offset); if (!header) { LOG_MSG("OldDataReader: No data for '%s'\n", channel_name.c_str()); return 0; } /// stdString txt; epicsTime2string(epicsTime(header->data.begin_time), txt); printf("header: %s\n", txt.c_str()); /// while (epicsTime(header->data.begin_time) > *start) { if (!header->read_prev()) { header = 0; LOG_MSG("OldDataReader: No data for '%s'\n", channel_name.c_str()); return 0; } epicsTime2string(epicsTime(header->data.begin_time), txt); printf("header: %s\n", txt.c_str()); } // Have header <= *start } else { // Start at first buffer header = getHeader(index.getDirname(), dfi.entry.data.first_file, dfi.entry.data.first_offset); if (!header) { LOG_MSG("OldDataReader: No data for '%s'\n", channel_name.c_str()); return 0; } } dbr_type = header->data.dbr_type; dbr_count = header->data.dbr_count; ctrl_info.read(header->datafile, header->data.ctrl_info_offset); raw_value_size = RawValue::getSize(dbr_type, dbr_count); data = RawValue::allocate(dbr_type, dbr_count, 1); val_idx = 0; type_changed = false; ctrl_info_changed = false; if (start) { // Binary search for best matching sample. size_t low = 0, high = header->data.num_samples - 1; FileOffset offset0 = header->offset + sizeof(DataHeader::DataHeaderData); FileOffset offset; epicsTime stamp; /// stdString start_txt; epicsTime2string(*start, start_txt); printf("Start: %s\n", start_txt.c_str()); /// while (true) { // Pick middle value, rounded up val_idx = low+high; if (val_idx & 1) ++val_idx; val_idx /= 2; offset = offset0 + val_idx * raw_value_size; RawValue::read(this->dbr_type, this->dbr_count, raw_value_size, data, header->datafile, offset); stamp = RawValue::getTime(data); /// stdString stamp_txt; epicsTime2string(stamp, stamp_txt); printf("Index %u: %s\n", (unsigned int)val_idx, stamp_txt.c_str()); /// if (high-low <= 1) { // The intervall can't shrink further, // idx = (low+high)/2 == high. // Which value's best? LOG_ASSERT(val_idx == high); if (stamp > *start) { val_idx = low; return next(); } // else: val_idx == high is good & already in data break; } if (stamp == *start) break; else if (stamp > *start) high = val_idx; else low = val_idx; } ++val_idx; return data; } else return next(); }
epicsTime DataWriter::getLastStamp() { if (header) return epicsTime(header->data.end_time); return nullTime; }
static void ntpshmupdate(void*, epicsUInt32 event) { if(event!=ntpShm.event) { incFail(); return; } epicsTimeStamp evrts; if(!ntpShm.evr->getTimeStamp(&evrts, 0)) // read current wall clock time { // no valid device time incFail(); return; } struct timeval cputs; if(gettimeofday(&cputs, 0)) { // no valid cpu time? incFail(); return; } struct timeval evrts_posix; evrts_posix.tv_sec = evrts.secPastEpoch + POSIX_TIME_AT_EPICS_EPOCH; evrts_posix.tv_usec = evrts.nsec / 1000; // correct for bias in truncation if(evrts.nsec % 1000 >= 500) { evrts_posix.tv_usec += 1; if(evrts_posix.tv_usec>=1000000) { evrts_posix.tv_sec += 1; evrts_posix.tv_usec = 0; } } // volatile operations aren't really enough, but will have to do. volatile shmSegment* seg=ntpShm.seg; seg->valid = 0; SYNC(); int c1 = seg->count++; seg->stampSec = evrts_posix.tv_sec; seg->stampUsec = evrts_posix.tv_usec; seg->rxSec = cputs.tv_sec; seg->rxUsec = cputs.tv_usec; int c2 = seg->count++; if(c1+1!=c2) { fprintf(stderr, "ntpshmupdate: possible collision with another writer!\n"); incFail(); return; } seg->valid = 1; SYNC(); epicsMutexMustLock(ntpShm.ntplock); ntpShm.lastValid = true; ntpShm.numOk++; ntpShm.lastStamp = evrts; ntpShm.lastRx = epicsTime(cputs); epicsMutexUnlock(ntpShm.ntplock); scanIoRequest(ntpShm.lastUpdate); if(!ntpShm.notify_1strx) { fprintf(stderr, "First update ready for NTPD\n"); ntpShm.notify_1strx = 1; } return; // normal exit }