Newer
Older
// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
// SPDX-License-Identifier: LGPL-3.0-or-later
#pragma once
Martin Christoph Hierholzer
committed
#include "Application.h"
#include "InversionOfControlAccessor.h"
#include <ChimeraTK/ScalarRegisterAccessor.h>
Martin Christoph Hierholzer
committed
#include <boost/smart_ptr/shared_ptr.hpp>
Martin Christoph Hierholzer
committed
#include <boost/thread.hpp>
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
namespace ChimeraTK {
/********************************************************************************************************************/
/** Accessor for scalar variables (i.e. single values). Note for users: Use the
* convenience classes
* ScalarPollInput, ScalarPushInput, ScalarOutput instead of this class
* directly. */
template<typename UserType>
class ScalarAccessor : public ChimeraTK::ScalarRegisterAccessor<UserType>,
public InversionOfControlAccessor<ScalarAccessor<UserType>> {
public:
using InversionOfControlAccessor<ScalarAccessor<UserType>>::operator VariableNetworkNode;
void replace(const ChimeraTK::NDRegisterAccessorAbstractor<UserType>& newAccessor) = delete;
using InversionOfControlAccessor<ScalarAccessor<UserType>>::replace;
ScalarAccessor<UserType>& operator=(ScalarAccessor<UserType>& other) = delete;
using ChimeraTK::ScalarRegisterAccessor<UserType>::operator=;
/** Move constructor */
ScalarAccessor(ScalarAccessor<UserType>&& other) noexcept;
ScalarAccessor<UserType>& operator=(ScalarAccessor<UserType>&& other) noexcept;
bool write(ChimeraTK::VersionNumber versionNumber) = delete;
Martin Christoph Hierholzer
committed
bool writeDestructively(ChimeraTK::VersionNumber versionNumber) = delete;
void writeIfDifferent(UserType newValue, VersionNumber versionNumber, DataValidity validity) = delete;
void setAndWrite(UserType newValue, VersionNumber versionNumber) = delete;
bool write();
bool writeDestructively();
void writeIfDifferent(UserType newValue);
void setAndWrite(UserType newValue);
using value_type = UserType;
protected:
friend class InversionOfControlAccessor<ScalarAccessor<UserType>>;
ScalarAccessor(Module* owner, const std::string& name, VariableDirection direction, std::string unit,
UpdateMode mode, const std::string& description, const std::unordered_set<std::string>& tags = {});
/** Default constructor creates a dysfunctional accessor (to be assigned with
* a real accessor later) */
ScalarAccessor() = default;
};
/********************************************************************************************************************/
/** Convenience class for input scalar accessors with UpdateMode::push */
template<typename UserType>
struct ScalarPushInput : public ScalarAccessor<UserType> {
ScalarPushInput(Module* owner, const std::string& name, std::string unit, const std::string& description,
const std::unordered_set<std::string>& tags = {});
ScalarPushInput() : ScalarAccessor<UserType>() {}
using ScalarAccessor<UserType>::operator=;
};
/********************************************************************************************************************/
/** Convenience class for input scalar accessors with UpdateMode::poll */
template<typename UserType>
struct ScalarPollInput : public ScalarAccessor<UserType> {
ScalarPollInput(Module* owner, const std::string& name, std::string unit, const std::string& description,
const std::unordered_set<std::string>& tags = {});
ScalarPollInput() : ScalarAccessor<UserType>() {}
Martin Killenberg
committed
void read() { this->readLatest(); }
using ScalarAccessor<UserType>::operator=;
};
/********************************************************************************************************************/
/** Convenience class for output scalar accessors (always UpdateMode::push) */
template<typename UserType>
struct ScalarOutput : public ScalarAccessor<UserType> {
ScalarOutput(Module* owner, const std::string& name, std::string unit, const std::string& description,
const std::unordered_set<std::string>& tags = {});
ScalarOutput() : ScalarAccessor<UserType>() {}
using ScalarAccessor<UserType>::operator=;
};
/********************************************************************************************************************/
/** Convenience class for input scalar accessors with return channel ("write back") and UpdateMode::push. */
template<typename UserType>
struct ScalarPushInputWB : public ScalarAccessor<UserType> {
ScalarPushInputWB(Module* owner, const std::string& name, std::string unit, const std::string& description,
const std::unordered_set<std::string>& tags = {});
ScalarPushInputWB() : ScalarAccessor<UserType>() {}
using ScalarAccessor<UserType>::operator=;
};
/********************************************************************************************************************/
/** Convenience class for output scalar accessors with return channel ("read back") (always UpdateMode::push) */
template<typename UserType>
struct ScalarOutputPushRB : public ScalarAccessor<UserType> {
ScalarOutputPushRB(Module* owner, const std::string& name, std::string unit, const std::string& description,
const std::unordered_set<std::string>& tags = {});
ScalarOutputPushRB() : ScalarAccessor<UserType>() {}
using ScalarAccessor<UserType>::operator=;
};
/********************************************************************************************************************/
/** Convenience class for output scalar accessors with return channel ("read back") (always UpdateMode::push) */
template<typename UserType>
struct ScalarOutputReverseRecovery : public ScalarAccessor<UserType> {
ScalarOutputReverseRecovery(Module* owner, const std::string& name, std::string unit,
const std::string& description, const std::unordered_set<std::string>& tags = {});
ScalarOutputReverseRecovery() : ScalarAccessor<UserType>() {}
using ScalarAccessor<UserType>::operator=;
};
/********************************************************************************************************************/
/********************************************************************************************************************/
/* Implementations below this point */
/********************************************************************************************************************/
/********************************************************************************************************************/
template<typename UserType>
ScalarAccessor<UserType>::ScalarAccessor(ScalarAccessor<UserType>&& other) noexcept {
InversionOfControlAccessor<ScalarAccessor<UserType>>::replace(std::move(other));
}
/********************************************************************************************************************/
template<typename UserType>
ScalarAccessor<UserType>& ScalarAccessor<UserType>::operator=(ScalarAccessor<UserType>&& other) noexcept {
// Having a move-assignment operator is required to use the move-assignment
// operator of a module containing an accessor.
InversionOfControlAccessor<ScalarAccessor<UserType>>::replace(std::move(other));
return *this;
}
/********************************************************************************************************************/
template<typename UserType>
bool ScalarAccessor<UserType>::write() {
auto versionNumber = this->getOwner()->getCurrentVersionNumber();
bool dataLoss = ChimeraTK::ScalarRegisterAccessor<UserType>::write(versionNumber);
if(dataLoss) {
Application::incrementDataLossCounter(this->_node.getQualifiedName());
}
return dataLoss;
}
/********************************************************************************************************************/
template<typename UserType>
bool ScalarAccessor<UserType>::writeDestructively() {
auto versionNumber = this->getOwner()->getCurrentVersionNumber();
bool dataLoss = ChimeraTK::ScalarRegisterAccessor<UserType>::writeDestructively(versionNumber);
if(dataLoss) {
Application::incrementDataLossCounter(this->_node.getQualifiedName());
}
return dataLoss;
}
/********************************************************************************************************************/
template<typename UserType>
void ScalarAccessor<UserType>::writeIfDifferent(UserType newValue) {
// Need to get to the MetaDataPropagatingRegisterDecorator to obtain the last written data validity for this PV.
// The dynamic_cast is ok, since the MetaDataPropagatingRegisterDecorator is always the outermost accessor, cf.
// the data validity propagation specification, Section 2.5.1.
auto* targetMetaDataPropagatingDecorator =
dynamic_cast<MetaDataPropagatingRegisterDecorator<UserType>*>(this->get());
assert(targetMetaDataPropagatingDecorator != nullptr);
// In contrast to ScalarRegisterAccessor::writeIfDifferent(), we must not set the data validity on the target
// accessor, since that would be interpreted by the MetaDataPropagatingRegisterDecorator as an application-induced
// forced fault state. This would result in invalidity lock-ups if this happens in a circular network. Hence the
// comparison of the data validity must also be done against the validity of the decorator's target accessor which
// corresponds to the last written data validity for this PV.
if(this->get()->accessData(0, 0) != newValue || this->getVersionNumber() == VersionNumber(nullptr) ||
targetMetaDataPropagatingDecorator->getTargetValidity() != this->getOwner()->getDataValidity()) {
setAndWrite(newValue);
}
/********************************************************************************************************************/
template<typename UserType>
void ScalarAccessor<UserType>::setAndWrite(UserType newValue) {
operator=(newValue);
this->write();
}
/********************************************************************************************************************/
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
template<typename UserType>
ScalarAccessor<UserType>::ScalarAccessor(Module* owner, const std::string& name, VariableDirection direction,
std::string unit, UpdateMode mode, const std::string& description, const std::unordered_set<std::string>& tags)
: InversionOfControlAccessor<ScalarAccessor<UserType>>(
owner, name, direction, unit, 1, mode, description, &typeid(UserType), tags) {}
/********************************************************************************************************************/
/********************************************************************************************************************/
template<typename UserType>
ScalarPushInput<UserType>::ScalarPushInput(Module* owner, const std::string& name, std::string unit,
const std::string& description, const std::unordered_set<std::string>& tags)
: ScalarAccessor<UserType>(
owner, name, {VariableDirection::consuming, false}, unit, UpdateMode::push, description, tags) {}
/********************************************************************************************************************/
/********************************************************************************************************************/
template<typename UserType>
ScalarPollInput<UserType>::ScalarPollInput(Module* owner, const std::string& name, std::string unit,
const std::string& description, const std::unordered_set<std::string>& tags)
: ScalarAccessor<UserType>(
owner, name, {VariableDirection::consuming, false}, unit, UpdateMode::poll, description, tags) {}
/********************************************************************************************************************/
/********************************************************************************************************************/
template<typename UserType>
ScalarOutput<UserType>::ScalarOutput(Module* owner, const std::string& name, std::string unit,
const std::string& description, const std::unordered_set<std::string>& tags)
: ScalarAccessor<UserType>(
owner, name, {VariableDirection::feeding, false}, unit, UpdateMode::push, description, tags) {}
/********************************************************************************************************************/
/********************************************************************************************************************/
template<typename UserType>
ScalarPushInputWB<UserType>::ScalarPushInputWB(Module* owner, const std::string& name, std::string unit,
const std::string& description, const std::unordered_set<std::string>& tags)
: ScalarAccessor<UserType>(
owner, name, {VariableDirection::consuming, true}, unit, UpdateMode::push, description, tags) {}
/********************************************************************************************************************/
/********************************************************************************************************************/
template<typename UserType>
ScalarOutputPushRB<UserType>::ScalarOutputPushRB(Module* owner, const std::string& name, std::string unit,
const std::string& description, const std::unordered_set<std::string>& tags)
: ScalarAccessor<UserType>(
owner, name, {VariableDirection::feeding, true}, unit, UpdateMode::push, description, tags) {}
/********************************************************************************************************************/
/********************************************************************************************************************/
template<typename UserType>
ScalarOutputReverseRecovery<UserType>::ScalarOutputReverseRecovery(Module* owner, const std::string& name,
std::string unit, const std::string& description, const std::unordered_set<std::string>& tags)
: ScalarAccessor<UserType>(
owner, name, {VariableDirection::feeding, true}, unit, UpdateMode::push, description, tags) {
this->addTag(ChimeraTK::SystemTags::reverseRecovery);
}
/********************************************************************************************************************/
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
} /* namespace ChimeraTK */