9#include <ChimeraTK/AccessMode.h>
10#include <ChimeraTK/async/DataConsistencyKey.h>
11#include <ChimeraTK/Exception.h>
12#include <ChimeraTK/FixedPointConverter.h>
13#include <ChimeraTK/MappedImage.h>
14#include <ChimeraTK/NDRegisterAccessor.h>
15#include <ChimeraTK/RegisterPath.h>
17#include <doocs/EqCall.h>
73 template<
typename UserType>
98 if(!
_backend->isOpen())
throw ChimeraTK::logic_error(
"Read operation not allowed while device is closed.");
99 if(!
isReadable())
throw ChimeraTK::logic_error(
"Try to read from write-only register \"" +
_path +
"\".");
103 if(!
_backend->isOpen())
throw ChimeraTK::logic_error(
"Write operation not allowed while device is closed.");
104 if(!
isWriteable())
throw ChimeraTK::logic_error(
"Try to write read-only register \"" +
_path +
"\".");
108 if(!hasNewData)
return;
117 TransferElement::setDataValidity(
dst.error() == 0 ? DataValidity::ok : DataValidity::faulty);
126 if(
dst.get_event_id() == doocs::EventId()) {
128 TransferElement::_versionNumber = {};
142 auto newVersionNumber =
143 _backend->_dataConsistencyRealm->getVersion(async::DataConsistencyKey(
dst.get_event_id().to_int()));
146 auto startVersion =
_backend->getStartVersion();
147 if(newVersionNumber < startVersion) {
148 newVersionNumber = startVersion;
155 if(newVersionNumber < TransferElement::_versionNumber) {
160 TransferElement::_versionNumber = newVersionNumber;
170 using TransferElement::_readQueue;
172 bool mayReplaceOther(
const boost::shared_ptr<TransferElement const>& other)
const override {
173 auto rhsCasted = boost::dynamic_pointer_cast<const DoocsBackendRegisterAccessor<UserType>>(other);
174 if(!rhsCasted)
return false;
175 if(rhsCasted.get() ==
this)
return false;
176 if(
_path != rhsCasted->_path)
return false;
177 if(
nElements != rhsCasted->nElements)
return false;
183 return {boost::enable_shared_from_this<TransferElement>::shared_from_this()};
191 if(this->getAccessModeFlags().has(AccessMode::wait_for_new_data)) {
198 const std::string& registerPathName,
size_t numberOfWords,
size_t wordOffsetInRegister, AccessModeFlags flags);
221 template<
typename UserType>
223 size_t actualLength = 0;
229 if(_backend->isOpen()) {
231 rc = eq.get(&ea, &tmp, &dst);
234 if(rc == eq_errors::ill_property || rc == eq_errors::ill_location || rc == eq_errors::ill_address) {
236 throw ChimeraTK::logic_error(
"Property does not exist: " + _path);
245 actualLength = dst.array_length();
246 if(actualLength == 0 && dst.length() == 1) {
250 if(actualLength == 0) actualLength = dst.length();
253 if(typeId == DATA_IMAGE) {
255 actualLength +=
sizeof(ChimeraTK::ImgHeader);
260 if(typeId == DATA_TEXT || typeId == DATA_STRING) {
264 if(actualLength > 1) {
272 nElements = actualLength;
274 if(nElements + elementOffset > actualLength) {
276 if(typeId != DATA_IMAGE) {
277 throw ChimeraTK::logic_error(
"Requested number of words exceeds the length of the DOOCS property!");
280 if(nElements == actualLength && elementOffset == 0) {
288 NDRegisterAccessor<UserType>::buffer_2D.resize(1);
289 NDRegisterAccessor<UserType>::buffer_2D[0].resize(nElements);
292 src.set_type(typeId);
293 if(typeId == DATA_IMAGE) {
295 src.length(actualLength -
sizeof(ChimeraTK::ImgHeader));
297 else if(typeId != DATA_IIII) {
298 src.length(actualLength);
310 template<
typename UserType>
312 const std::string& path,
const std::string& registerPathName,
size_t numberOfWords,
size_t wordOffsetInRegister,
313 AccessModeFlags flags)
314 : NDRegisterAccessor<UserType>(path, flags), _isReadable(true), _isWriteable(true) {
323 flags.checkForUnknownFlags({AccessMode::wait_for_new_data});
329 auto info = backend->getBackendRegisterCatalogue().getBackendRegister(registerPathName);
332 if(flags.has(AccessMode::wait_for_new_data)) {
333 if(!info.getSupportedAccessModes().has(AccessMode::wait_for_new_data)) {
334 throw ChimeraTK::logic_error(
"invalid access mode for this register");
340 _readQueue =
notifications.then<
void>([
this](doocs::EqData& data) { this->
dst = data; }, std::launch::deferred);
353 template<
typename UserType>
355 assert(shutdownCalled);
360 template<
typename UserType>
362 if(!_backend->isFunctional()) {
363 throw ChimeraTK::runtime_error(std::string(
"Exception reported by another accessor."));
368 boost::this_thread::interruption_point();
372 int rc = eq.get(&ea, &tmp, &dst);
376 _backend->informRuntimeError(_path);
377 throw ChimeraTK::runtime_error(std::string(
"Cannot read from DOOCS property: ") + dst.get_string());
383 template<
typename UserType>
385 if(!_backend->isFunctional()) {
386 throw ChimeraTK::runtime_error(std::string(
"Exception reported by another accessor."));
390 int rc = eq.set(&ea, &src, &dst);
393 _backend->informRuntimeError(_path);
394 if(dst.error() == eq_errors::read_only) {
395 this->_isWriteable =
false;
397 throw ChimeraTK::runtime_error(std::string(
"Cannot write to DOOCS property: ") + dst.get_string());
static bool isCommunicationError(int doocs_error)
static ZMQSubscriptionManager & getInstance()
void unsubscribe(const std::string &path, DoocsBackendRegisterAccessorBase *accessor)
Unregister accessor subscription.
void subscribe(const std::string &path, DoocsBackendRegisterAccessorBase *accessor)
Register accessor subscription.
This is the untemplated base class which unifies all data members not depending on the UserType.
boost::shared_ptr< DoocsBackend > _backend
Pointer to the backend.
bool isArray
flag if the DOOCS data type is an array or not
bool isActiveZMQ
flag whether it should receive updates from the ZeroMQ subscription.
size_t nElements
number of elements
doocs::EqData src
DOOCS data structures.
size_t elementOffset
element offset specified by the user
cppext::future_queue< doocs::EqData > notifications
future_queue used to notify the TransferFuture about completed transfers
doocs::EqCall eq
DOOCS rpc call object.
doocs::EqAdr ea
DOOCS address structure.
bool useZMQ
flag if a ZeroMQ subscribtion is used for reading data (c.f. AccessMode::wait_for_new_data)
bool shutdownCalled
Flag whether shutdown() has been called or not.
doocs::EventId _lastEventId
first valid eventId
std::string _path
register path
bool isPartial
flag if the accessor should affect only a part of the property (in case of an array)
void shutdown()
All implementations must call this function in their destructor.
bool isReadOnly() const override
void replaceTransferElement(boost::shared_ptr< TransferElement >) override
bool mayReplaceOther(const boost::shared_ptr< TransferElement const > &other) const override
void doPostRead(TransferType, bool hasNewData) override
void doPreWrite(TransferType, VersionNumber) override
void interrupt() override
bool doWriteTransfer(VersionNumber) override
void write_internal()
internal write from doocs::EqData src
DoocsBackendRegisterAccessor(boost::shared_ptr< DoocsBackend > backend, const std::string &path, const std::string ®isterPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
bool isReadable() const override
~DoocsBackendRegisterAccessor() override
std::list< boost::shared_ptr< ChimeraTK::TransferElement > > getInternalElements() override
std::vector< boost::shared_ptr< TransferElement > > getHardwareAccessingElements() override
void doReadTransferSynchronously() override
void initialise(const DoocsBackendRegisterInfo &info)
Perform initialisation (i.e.
void doPreRead(TransferType) override
bool isWriteable() const override
unsigned int getNumberOfElements() const override