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);
ScalarAccessor<UserType>& operator=(ScalarAccessor<UserType>&& other);
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);
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=;
};
/********************************************************************************************************************/
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/********************************************************************************************************************/
/* Implementations below this point */
/********************************************************************************************************************/
/********************************************************************************************************************/
template<typename UserType>
ScalarAccessor<UserType>::ScalarAccessor(ScalarAccessor<UserType>&& other) {
InversionOfControlAccessor<ScalarAccessor<UserType>>::replace(std::move(other));
}
/********************************************************************************************************************/
template<typename UserType>
ScalarAccessor<UserType>& ScalarAccessor<UserType>::operator=(ScalarAccessor<UserType>&& other) {
// 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();
}
/********************************************************************************************************************/
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
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
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) {}
/********************************************************************************************************************/
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
} /* namespace ChimeraTK */