9#include <ChimeraTK/AccessMode.h>
10#include <ChimeraTK/async/DataConsistencyKey.h>
11#include <ChimeraTK/Exception.h>
12#include <ChimeraTK/MappedImage.h>
13#include <ChimeraTK/NDRegisterAccessor.h>
14#include <ChimeraTK/RegisterPath.h>
16#include <doocs/EqCall.h>
72 template<
typename UserType>
97 if(!
_backend->isOpen())
throw ChimeraTK::logic_error(
"Read operation not allowed while device is closed.");
98 if(!
isReadable())
throw ChimeraTK::logic_error(
"Try to read from write-only register \"" +
_path +
"\".");
102 if(!
_backend->isOpen())
throw ChimeraTK::logic_error(
"Write operation not allowed while device is closed.");
103 if(!
isWriteable())
throw ChimeraTK::logic_error(
"Try to write read-only register \"" +
_path +
"\".");
107 if(!hasNewData)
return;
116 TransferElement::setDataValidity(
dst.error() == 0 ? DataValidity::ok : DataValidity::faulty);
125 if(
dst.get_event_id() == doocs::EventId()) {
127 TransferElement::_versionNumber = {};
141 auto newVersionNumber =
142 _backend->_dataConsistencyRealm->getVersion(async::DataConsistencyKey(
dst.get_event_id().to_int()));
145 auto startVersion =
_backend->getStartVersion();
146 if(newVersionNumber < startVersion) {
147 newVersionNumber = startVersion;
154 if(newVersionNumber < TransferElement::_versionNumber) {
159 TransferElement::_versionNumber = newVersionNumber;
169 using TransferElement::_readQueue;
171 bool mayReplaceOther(
const boost::shared_ptr<TransferElement const>& other)
const override {
172 auto rhsCasted = boost::dynamic_pointer_cast<const DoocsBackendRegisterAccessor<UserType>>(other);
173 if(!rhsCasted)
return false;
174 if(rhsCasted.get() ==
this)
return false;
175 if(
_path != rhsCasted->_path)
return false;
176 if(
nElements != rhsCasted->nElements)
return false;
182 return {boost::enable_shared_from_this<TransferElement>::shared_from_this()};
190 if(this->getAccessModeFlags().has(AccessMode::wait_for_new_data)) {
197 const std::string& registerPathName,
size_t numberOfWords,
size_t wordOffsetInRegister, AccessModeFlags flags);
220 template<
typename UserType>
222 size_t actualLength = 0;
228 if(_backend->isOpen()) {
230 rc = eq.get(&ea, &tmp, &dst);
233 if(rc == eq_errors::ill_property || rc == eq_errors::ill_location || rc == eq_errors::ill_address) {
235 throw ChimeraTK::logic_error(
"Property does not exist: " + _path);
244 actualLength = dst.array_length();
245 if(actualLength == 0 && dst.length() == 1) {
249 if(actualLength == 0) actualLength = dst.length();
252 if(typeId == DATA_IMAGE) {
254 actualLength +=
sizeof(ChimeraTK::ImgHeader);
259 if(typeId == DATA_TEXT || typeId == DATA_STRING) {
263 if(actualLength > 1) {
271 nElements = actualLength;
273 if(nElements + elementOffset > actualLength) {
275 if(typeId != DATA_IMAGE) {
276 throw ChimeraTK::logic_error(
"Requested number of words exceeds the length of the DOOCS property!");
279 if(nElements == actualLength && elementOffset == 0) {
287 NDRegisterAccessor<UserType>::buffer_2D.resize(1);
288 NDRegisterAccessor<UserType>::buffer_2D[0].resize(nElements);
291 src.set_type(typeId);
292 if(typeId == DATA_IMAGE) {
294 src.length(actualLength -
sizeof(ChimeraTK::ImgHeader));
296 else if(typeId != DATA_IIII) {
297 src.length(actualLength);
309 template<
typename UserType>
311 const std::string& path,
const std::string& registerPathName,
size_t numberOfWords,
size_t wordOffsetInRegister,
312 AccessModeFlags flags)
313 : NDRegisterAccessor<UserType>(path, flags), _isReadable(true), _isWriteable(true) {
322 flags.checkForUnknownFlags({AccessMode::wait_for_new_data});
328 auto info = backend->getBackendRegisterCatalogue().getBackendRegister(registerPathName);
331 if(flags.has(AccessMode::wait_for_new_data)) {
332 if(!info.getSupportedAccessModes().has(AccessMode::wait_for_new_data)) {
333 throw ChimeraTK::logic_error(
"invalid access mode for this register");
339 _readQueue =
notifications.then<
void>([
this](doocs::EqData& data) { this->
dst = data; }, std::launch::deferred);
352 template<
typename UserType>
354 assert(shutdownCalled);
359 template<
typename UserType>
361 if(!_backend->isFunctional()) {
362 throw ChimeraTK::runtime_error(std::string(
"Exception reported by another accessor."));
367 boost::this_thread::interruption_point();
371 int rc = eq.get(&ea, &tmp, &dst);
374 if(rc == doocs::TransactionResult::transaction_error || rc == doocs::TransactionResult::transport_error) {
375 _backend->informRuntimeError(_path);
376 throw ChimeraTK::runtime_error(std::string(
"Cannot read from DOOCS property: ") + dst.get_string());
382 template<
typename UserType>
384 if(!_backend->isFunctional()) {
385 throw ChimeraTK::runtime_error(std::string(
"Exception reported by another accessor."));
389 int rc = eq.set(&ea, &src, &dst);
391 if(rc == doocs::TransactionResult::transaction_error || rc == doocs::TransactionResult::transport_error ||
392 (dst.error() == eq_errors::read_only)) {
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 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