From ee5576f0f738f031b7fe8265acc35ad5027627cb Mon Sep 17 00:00:00 2001 From: Martin Hierholzer <martin.hierholzer@desy.de> Date: Fri, 22 Apr 2022 11:21:20 +0200 Subject: [PATCH] do not send out identical time stamps on the same property (#67) Identical time stamps are considered to have identical data when DOOCS checks for inconsistencies on silent ZeroMQ connections. If on the same property new data is set without changing the VersionNumber, the timestamp will now be altered by 1 microsecond. This is more like a temporary work around. A feature request to DOOCS should be made to introduce a distinction between a "server timestamp" and a "source timestamp" like it is realised in OPC UA. Also a potential better solution to the other part of the problem inside ApplicationCore is described here: https://redmine.msktools.desy.de/issues/9723 --- include/DoocsProcessArray.h | 24 +++++++++++++----------- include/DoocsProcessScalar.h | 20 +++++++++++--------- src/DoocsIfff.cc | 6 ++++++ src/DoocsSpectrum.cc | 20 ++++++++++++-------- 4 files changed, 42 insertions(+), 28 deletions(-) diff --git a/include/DoocsProcessArray.h b/include/DoocsProcessArray.h index 97d57a7..b73c4d0 100644 --- a/include/DoocsProcessArray.h +++ b/include/DoocsProcessArray.h @@ -155,23 +155,25 @@ namespace ChimeraTK { this->fill_array(dataPtr, processVector.size()); modified = true; - // Convert time stamp from version number in Unix time (seconds and microseconds). - // Note that epoch of std::chrono::system_time might be different from Unix time, and Unix time omits leap seconds - // and hence is not the duration since the epoch! We have to convert to time_t and then find out the microseconds. - auto timestamp = _processArray->getVersionNumber().getTime(); - auto seconds = std::chrono::system_clock::to_time_t(timestamp); - auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>( - timestamp - std::chrono::system_clock::from_time_t(seconds)) - .count(); - this->set_tmstmp(seconds, microseconds); + // Convert time stamp from version number to DOOCS timestamp + doocs::Timestamp timestamp(_processArray->getVersionNumber().getTime()); + + // Make sure we never send out two absolute identical time stamps. If we would do so, the "watchdog" which + // corrects inconsistencies in ZeroMQ subscriptions between sender and subcriber cannot detect the inconsistency. + if(this->get_timestamp() == timestamp) { + timestamp += std::chrono::microseconds(1); + } + + this->set_timestamp(timestamp); if(_macroPulseNumberSource) this->set_mpnum(_macroPulseNumberSource->accessData(0)); // send data via ZeroMQ if enabled and if DOOCS initialisation is complete if(publishZMQ && ChimeraTK::DoocsAdapter::isInitialised) { dmsg_info info; memset(&info, 0, sizeof(info)); - info.sec = seconds; - info.usec = microseconds; + auto sinceEpoch = timestamp.get_seconds_and_microseconds_since_epoch(); + info.sec = sinceEpoch.seconds; + info.usec = sinceEpoch.microseconds; if(_macroPulseNumberSource != nullptr) { info.ident = _macroPulseNumberSource->accessData(0); } diff --git a/include/DoocsProcessScalar.h b/include/DoocsProcessScalar.h index bbfadeb..a79f813 100644 --- a/include/DoocsProcessScalar.h +++ b/include/DoocsProcessScalar.h @@ -61,13 +61,14 @@ namespace ChimeraTK { this->d_error(no_error); } - // Convert time stamp from version number in Unix time (seconds and microseconds). - // Note that epoch of std::chrono::system_time might be different from Unix time, and Unix time omits leap seconds - // and hence is not the duration since the epoch! We have to convert to time_t and then find out the microseconds. + // Convert time stamp from version number to DOOCS timestamp doocs::Timestamp timestamp(_processScalar->getVersionNumber().getTime()); - auto sinceEpoch = timestamp.get_seconds_and_microseconds_since_epoch(); - auto seconds = sinceEpoch.seconds; - auto microseconds = sinceEpoch.microseconds; + + // Make sure we never send out two absolute identical time stamps. If we would do so, the "watchdog" which + // corrects inconsistencies in ZeroMQ subscriptions between sender and subcriber cannot detect the inconsistency. + if(this->get_timestamp() == timestamp) { + timestamp += std::chrono::microseconds(1); + } // update global time stamp of DOOCS, but only if our time stamp is newer if(get_global_timestamp() < timestamp) { @@ -94,15 +95,16 @@ namespace ChimeraTK { // We must set the timestamp again so it is correctly attached to the variable. set_and_archive does not to it. // This must happen after set_and_archive, otherwise the global time stamp is taken. - this->set_tmstmp(seconds, microseconds); + this->set_timestamp(timestamp); if(_macroPulseNumberSource) this->set_mpnum(_macroPulseNumberSource->accessData(0)); // send data via ZeroMQ if enabled and if DOOCS initialisation is complete if(_publishZMQ && ChimeraTK::DoocsAdapter::isInitialised) { dmsg_info info; memset(&info, 0, sizeof(info)); - info.sec = seconds; - info.usec = microseconds; + auto sinceEpoch = timestamp.get_seconds_and_microseconds_since_epoch(); + info.sec = sinceEpoch.seconds; + info.usec = sinceEpoch.microseconds; if(_macroPulseNumberSource != nullptr) { info.ident = _macroPulseNumberSource->accessData(0); } diff --git a/src/DoocsIfff.cc b/src/DoocsIfff.cc index 2feec99..fd28697 100644 --- a/src/DoocsIfff.cc +++ b/src/DoocsIfff.cc @@ -87,6 +87,12 @@ namespace ChimeraTK { doocs::Timestamp timestamp(_i1Value->getVersionNumber().getTime()); + // Make sure we never send out two absolute identical time stamps. If we would do so, the "watchdog" which + // corrects inconsistencies in ZeroMQ subscriptions between sender and subcriber cannot detect the inconsistency. + if(this->get_timestamp() == timestamp) { + timestamp += std::chrono::microseconds(1); + } + // update global time stamp of DOOCS, but only if our time stamp is newer if(get_global_timestamp() < timestamp) { set_global_timestamp(timestamp); diff --git a/src/DoocsSpectrum.cc b/src/DoocsSpectrum.cc index f7b4219..b0181ff 100644 --- a/src/DoocsSpectrum.cc +++ b/src/DoocsSpectrum.cc @@ -148,14 +148,18 @@ namespace ChimeraTK { } _doocsSuccessfullyUpdated = true; - // Convert time stamp from version number in Unix time (seconds and microseconds). - // Note that epoch of std::chrono::system_time might be different from Unix time, and Unix time omits leap seconds - // and hence is not the duration since the epoch! We have to convert to time_t and then find out the microseconds. - auto timestamp = _processArray->getVersionNumber().getTime(); - auto seconds = std::chrono::system_clock::to_time_t(timestamp); - auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>( - timestamp - std::chrono::system_clock::from_time_t(seconds)) - .count(); + // Convert time stamp from version number to DOOCS timestamp + doocs::Timestamp timestamp(_processArray->getVersionNumber().getTime()); + + // Make sure we never send out two absolute identical time stamps. If we would do so, the "watchdog" which + // corrects inconsistencies in ZeroMQ subscriptions between sender and subcriber cannot detect the inconsistency. + if(this->get_timestamp() == timestamp) { + timestamp += std::chrono::microseconds(1); + } + + auto sinceEpoch = timestamp.get_seconds_and_microseconds_since_epoch(); + auto seconds = sinceEpoch.seconds; + auto microseconds = sinceEpoch.microseconds; // set macro pulse number, buffer number and time stamp size_t ibuf = 0; -- GitLab