diff --git a/include/DoocsIfff.h b/include/DoocsIfff.h index 338a5309267309c0b488e2c1adee70c7495909ab..c97227add6ec017821804726de5cdf8a2f5bc7de 100644 --- a/include/DoocsIfff.h +++ b/include/DoocsIfff.h @@ -29,17 +29,23 @@ namespace ChimeraTK { void set(EqAdr* eqAdr, EqData* data1, EqData* data2, EqFct* eqFct) override; void auto_init(void) override; - + + void setMacroPulseNumberSource(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<int64_t>> macroPulseNumberSource); + DataConsistencyGroup _consistencyGroup; + protected: void updateAppToDoocs(TransferElementID& elementId); void sendToApplication(); + void registerVariable(const ChimeraTK::TransferElementAbstractor& var); - DataConsistencyGroup _consistencyGroup; boost::shared_ptr<NDRegisterAccessor<int>> _i1Value; boost::shared_ptr<NDRegisterAccessor<float>> _f1Value; boost::shared_ptr<NDRegisterAccessor<float>> _f2Value; boost::shared_ptr<NDRegisterAccessor<float>> _f3Value; + DoocsUpdater& _updater; + EqFct* _eqFct; bool isWriteable; + boost::shared_ptr<ChimeraTK::NDRegisterAccessor<int64_t>> _macroPulseNumberSource; }; } // namespace ChimeraTK diff --git a/src/DoocsIfff.cc b/src/DoocsIfff.cc index 853d1bca480ef9e6104862501002e9a752dd98fc..bef704117effdfe9dbb0b2293b95e4758bb27cfa 100644 --- a/src/DoocsIfff.cc +++ b/src/DoocsIfff.cc @@ -2,6 +2,8 @@ #include "DoocsUpdater.h" #include <ChimeraTK/OneDRegisterAccessor.h> +#include <ChimeraTK/ScalarRegisterAccessor.h> +#include <doocs/EventId.h> namespace ChimeraTK { DoocsIfff::DoocsIfff(EqFct* eqFct, std::string const& doocsPropertyName, @@ -9,13 +11,17 @@ namespace ChimeraTK { boost::shared_ptr<NDRegisterAccessor<float>> const& f1Value, boost::shared_ptr<NDRegisterAccessor<float>> const& f2Value, boost::shared_ptr<NDRegisterAccessor<float>> const& f3Value, DoocsUpdater& updater) - : D_ifff(eqFct, doocsPropertyName), _i1Value(i1Value), _f1Value(f1Value), _f2Value(f2Value), _f3Value(f3Value) { + : D_ifff(eqFct, doocsPropertyName), _i1Value(i1Value), _f1Value(f1Value), _f2Value(f2Value), _f3Value(f3Value), + _updater(updater), _eqFct(eqFct) { auto registerSource = [&](const ChimeraTK::TransferElementAbstractor& var) { if(var.isReadable()) { updater.addVariable(var, eqFct, std::bind(&DoocsIfff::updateAppToDoocs, this, var.getId())); _consistencyGroup.add(var); } }; + + // FIXME: What if not all 4 are readable? is it still valid to add + // all to a consistency group then? registerSource(OneDRegisterAccessor<int>(_i1Value)); registerSource(OneDRegisterAccessor<float>(_f1Value)); registerSource(OneDRegisterAccessor<float>(_f2Value)); @@ -29,40 +35,51 @@ namespace ChimeraTK { } void DoocsIfff::updateAppToDoocs(TransferElementID& elementId) { - if(_consistencyGroup.update(elementId)) { - if(_i1Value->dataValidity() != ChimeraTK::DataValidity::ok || - _f1Value->dataValidity() != ChimeraTK::DataValidity::ok || - _f2Value->dataValidity() != ChimeraTK::DataValidity::ok || - _f3Value->dataValidity() != ChimeraTK::DataValidity::ok) { - this->d_error(stale_data); - } - else { - this->d_error(no_error); - } + if(!_consistencyGroup.update(elementId)) { + return; + } - IFFF ifff; - ifff.i1_data = _i1Value->accessData(0); - ifff.f1_data = _f1Value->accessData(0); - ifff.f2_data = _f2Value->accessData(0); - ifff.f3_data = _f3Value->accessData(0); - - // we must not call set_and_archive if there is no history (otherwise it - // will be activated), but we have to if it is there. -> Abstraction, - // please! - if(this->get_histPointer()) { - // Set eventId - //doocs::EventId eventId; - //if(_macroPulseNumberSource) eventId = doocs::EventId(_macroPulseNumberSource->accessData(0)); - - /*FIXME: The archiver also has a status code. Set it correctly.*/ - /*FIXME: This set_and_archive does not support the timestamp yet (only sec and msec, and I guess m is milli?)*/ - /*FIXME: This set_and_archive does not support eventIDs yet */ - this->set_and_archive(&ifff, ArchiveStatus::sts_ok, 0 /*sec*/, 0 /*msec*/); - } - else { - this->set_value(&ifff); - } + if(_i1Value->dataValidity() != ChimeraTK::DataValidity::ok || + _f1Value->dataValidity() != ChimeraTK::DataValidity::ok || + _f2Value->dataValidity() != ChimeraTK::DataValidity::ok || + _f3Value->dataValidity() != ChimeraTK::DataValidity::ok) { + this->d_error(stale_data); + } + else { + this->d_error(no_error); + } + + IFFF ifff; + ifff.i1_data = _i1Value->accessData(0); + ifff.f1_data = _f1Value->accessData(0); + ifff.f2_data = _f2Value->accessData(0); + ifff.f3_data = _f3Value->accessData(0); + + doocs::Timestamp timestamp(_i1Value->getVersionNumber().getTime()); + auto sinceEpoch = timestamp.get_seconds_and_microseconds_since_epoch(); + auto seconds = sinceEpoch.seconds; + auto microseconds = sinceEpoch.microseconds; + // update global time stamp of DOOCS, but only if our time stamp is newer + if(get_global_timestamp() < timestamp) { + set_global_timestamp(timestamp); } + + if(this->get_histPointer()) { + /* + doocs::EventId eventId = + (_macroPulseNumberSource) ? doocs::EventId(_macroPulseNumberSource->accessData(0)) : doocs::EventId(0); + */ + /*FIXME: The archiver also has a status code. Set it correctly.*/ + /*FIXME: This set_and_archive does not support the timestamp yet (only sec and msec, and I guess m is milli?)*/ + /*FIXME: This set_and_archive does not support eventIDs yet */ + this->set_and_archive(&ifff, ArchiveStatus::sts_ok, 0, 0 /*msec*/); + } + else { + this->set_value(&ifff); + } + + this->set_tmstmp(seconds, microseconds); + if(_macroPulseNumberSource) this->set_mpnum(_macroPulseNumberSource->accessData(0)); } void DoocsIfff::set(EqAdr* eqAdr, EqData* data1, EqData* data2, EqFct* eqFct) { @@ -93,4 +110,26 @@ namespace ChimeraTK { _f3Value->write(v); } + void DoocsIfff::setMacroPulseNumberSource( + boost::shared_ptr<ChimeraTK::NDRegisterAccessor<int64_t>> macroPulseNumberSource) { + // FIXME: Assuming macroPulseNumberSource is relavent only when all 4 + // components are readable; correct behavior later if this assumption + // does not hold. + bool isIfffReadable = + (_i1Value->isReadable() && _f1Value->isReadable() && _f2Value->isReadable() && _f3Value->isReadable()); + if(not isIfffReadable) { + return; + } + _macroPulseNumberSource = macroPulseNumberSource; + if(_consistencyGroup.getMatchingMode() != DataConsistencyGroup::MatchingMode::none) { + registerVariable(ChimeraTK::ScalarRegisterAccessor<int64_t>(_macroPulseNumberSource)); + } + } + + void DoocsIfff::registerVariable(const ChimeraTK::TransferElementAbstractor& var) { + if(var.isReadable()) { + _updater.addVariable(var, _eqFct, std::bind(&DoocsIfff::updateAppToDoocs, this, var.getId())); + _consistencyGroup.add(var); + } + } } // namespace ChimeraTK diff --git a/src/DoocsPVFactory.cc b/src/DoocsPVFactory.cc index 1fb5f7685ff1d78a72c0e470e49710fb350791f1..5b35a4f45d86ce612f68911b66516b58b2cebfe7 100644 --- a/src/DoocsPVFactory.cc +++ b/src/DoocsPVFactory.cc @@ -271,6 +271,26 @@ namespace ChimeraTK { getDecorator<float>(f2ProcessVariable, DecoratorType::C_style_conversion), getDecorator<float>(f3ProcessVariable, DecoratorType::C_style_conversion), _updater)); + // set specified data_matching mode + boost::dynamic_pointer_cast<DoocsIfff>(doocsPV)->_consistencyGroup.setMatchingMode(ifffDescription.dataMatching); + + // set macro pulse number source, if configured + if(ifffDescription.macroPulseNumberSource.size() > 0) { + auto mpnSource = _controlSystemPVManager->getProcessVariable(ifffDescription.macroPulseNumberSource); + auto mpnDecorated = getDecorator<int64_t>(mpnSource, DecoratorType::C_style_conversion); + if(mpnDecorated->getNumberOfSamples() != 1) { + throw ChimeraTK::logic_error("The property '" + mpnDecorated->getName() + + "' is used as a macro pulse number source, but it has an array " + "length of " + + std::to_string(mpnDecorated->getNumberOfSamples()) + ". Length must be exactly 1"); + } + if(!mpnDecorated->isReadable()) { + throw ChimeraTK::logic_error("The property '" + mpnDecorated->getName() + + "' is used as a macro pulse number source, but it is not readable."); + } + boost::dynamic_pointer_cast<DoocsIfff>(doocsPV)->setMacroPulseNumberSource(mpnDecorated); + } + return doocsPV; }