9#include <ChimeraTK/SystemTags.h>
10#include <ChimeraTK/TransferElement.h>
18 template<
typename UserType>
20 boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor,
const VariableNetworkNode& networkNode,
21 boost::shared_ptr<RecoveryHelper> recoveryHelper)
22 :
ChimeraTK::NDRegisterAccessorDecorator<UserType>(accessor), _recoveryHelper(std::move(recoveryHelper)),
23 _direction(networkNode.getDirection()) {
34 deviceManager->_writeRegisterPaths.emplace_back(registerName);
47 registerName, nElements, 0, {});
53 if(networkNode.
getTags().contains(ChimeraTK::SystemTags::reverseRecovery)) {
60 if(!std::is_same<UserType, ChimeraTK::Void>::value) {
65 deviceManager->_readRegisterPaths.emplace_back(registerName);
69 deviceManager->_readRegisterPaths.emplace_back(registerName);
72 throw ChimeraTK::logic_error(
"Invalid variable direction in " + networkNode.
getRegisterName());
78 template<
typename UserType>
80 auto deviceManager = _deviceManager.lock();
90 _inhibitWriteTransfer =
false;
91 _hasThrownLogicError =
false;
92 _dataLostInPreviousWrite =
false;
93 auto recoverylock{deviceManager->getRecoverySharedLock()};
95 if(_recoveryAccessor !=
nullptr) {
96 if(!_recoveryHelper->wasWritten && (_recoveryHelper->writeOrder != 0)) {
97 _dataLostInPreviousWrite =
true;
101 for(
unsigned int ch = 0; ch < _recoveryAccessor->getNumberOfChannels(); ++ch) {
102 _recoveryAccessor->accessChannel(ch) = buffer_2D[ch];
104 _recoveryHelper->versionNumber = versionNumber;
105 _recoveryHelper->writeOrder = deviceManager->writeOrder();
106 _recoveryHelper->wasWritten =
false;
109 _hasThrownLogicError =
true;
110 throw ChimeraTK::logic_error(
111 "ChimeraTK::ExceptionhandlingDecorator: Calling write() on a non-writeable accessor is not supported ");
114 boost::shared_lock<boost::shared_mutex> errorLock(deviceManager->_errorMutex);
115 if(deviceManager->_deviceHasError) {
116 _inhibitWriteTransfer =
true;
120 ++deviceManager->_synchronousTransferCounter;
126 ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPreWrite(type, versionNumber);
131 template<
typename UserType>
133 auto deviceManager = _deviceManager.lock();
135 if(_hasThrownLogicError) {
140 if(!_inhibitWriteTransfer) {
141 --deviceManager->_synchronousTransferCounter;
143 ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostWrite(type, versionNumber);
145 auto recoverylock{deviceManager->getRecoverySharedLock()};
148 _recoveryHelper->wasWritten =
true;
151 catch(ChimeraTK::runtime_error& e) {
152 auto description = std::string(e.what()) +
" (seen by '" + _target->getName() +
"')";
155 this->_exceptionBackend->setException(description);
157 deviceManager->reportException(description);
160 assert(_activeException ==
nullptr);
165 template<
typename UserType>
167 auto deviceManager = _deviceManager.lock();
170 if(!_hasThrownToInhibitTransfer) {
172 if(!TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) {
173 --deviceManager->_synchronousTransferCounter;
175 _target->setActiveException(this->_activeException);
176 _target->postRead(type, hasNewData);
182 _hasReportedException =
false;
185 catch(ChimeraTK::runtime_error& e) {
186 auto description = std::string(e.what()) +
" (seen by '" + _target->getName() +
"')";
189 this->_exceptionBackend->setException(description);
191 deviceManager->reportException(description);
192 _hasReportedException =
true;
196 _activeException =
nullptr;
199 if(_hasReportedException || _hasThrownToInhibitTransfer) {
200 _dataValidity = DataValidity::faulty;
204 if(deviceManager->getExceptionVersionNumber() > _versionNumber) {
205 _versionNumber = deviceManager->getExceptionVersionNumber();
209 _dataValidity = _target->dataValidity();
213 if(_target->getVersionNumber() > _versionNumber) {
214 _versionNumber = _target->getVersionNumber();
220 for(
size_t i = 0; i < buffer_2D.size(); ++i) {
221 buffer_2D[i].swap(this->_target->accessChannel(
static_cast<unsigned int>(i)));
224 assert(_activeException ==
nullptr);
229 template<
typename UserType>
231 auto deviceManager = _deviceManager.lock();
233 _hasThrownToInhibitTransfer =
false;
235 if(TransferElement::_versionNumber == VersionNumber(
nullptr) && !_skipInitialValueWait) {
236 deviceManager->waitForInitialValues();
240 if(!TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) {
241 boost::shared_lock<boost::shared_mutex> errorLock(deviceManager->_errorMutex);
242 if(deviceManager->_deviceHasError) {
243 _hasThrownToInhibitTransfer =
true;
244 throw ChimeraTK::runtime_error(
"ExceptionHandlingDecorator has thrown to skip read transfer");
248 ++deviceManager->_synchronousTransferCounter;
251 ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPreRead(type);
256 template<
typename UserType>
258 return genericWriteWrapper([&] {
return _target->writeTransferDestructively(versionNumber); });
263 template<
typename UserType>
265 return genericWriteWrapper([&] {
return _target->writeTransferDestructively(versionNumber); });
270 template<
typename UserType>
271 template<
typename Callable>
273 if(_inhibitWriteTransfer) {
274 return _dataLostInPreviousWrite;
276 bool transferReportsPreviousDataLost =
false;
278 transferReportsPreviousDataLost = writeFunction();
280 catch(ChimeraTK::runtime_error&) {
281 _activeException = std::current_exception();
283 return (transferReportsPreviousDataLost || _dataLostInPreviousWrite);
std::map< std::string, boost::shared_ptr< DeviceManager > > _deviceManagerMap
Map of DeviceManagers.
static Application & getInstance()
Obtain instance of the application.
Decorator of the NDRegisterAccessor which facilitates tests of the application.
boost::weak_ptr< DeviceManager > _deviceManager
ExceptionHandlingDecorator(boost::shared_ptr< ChimeraTK::NDRegisterAccessor< UserType > > accessor, const VariableNetworkNode &networkNode, boost::shared_ptr< RecoveryHelper > recoveryHelper)
Decorate the accessors which is handed in the constructor.
boost::shared_ptr< RecoveryHelper > _recoveryHelper
bool _skipInitialValueWait
void doPostRead(TransferType type, bool hasNewData) override
void doPreWrite(TransferType type, VersionNumber versionNumber) override
bool genericWriteWrapper(Callable writeFunction)
VariableDirection _direction
void doPostWrite(TransferType type, VersionNumber versionNumber) override
bool doWriteTransferDestructively(VersionNumber versionNumber) override
bool doWriteTransfer(VersionNumber versionNumber) override
void doPreRead(TransferType type) override
boost::shared_ptr< NDRegisterAccessor< UserType > > _recoveryAccessor
Class describing a node of a variable network.
const std::string & getRegisterName() const
const std::unordered_set< std::string > & getTags() const
size_t getNumberOfElements() const
const std::string & getDeviceAlias() const
InvalidityTracer application module.
constexpr char noInitialValueReadTag[]
System tag to mark an accessor which should be excluded from the initial value read during applicatio...
INSTANTIATE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(DebugPrintAccessorDecorator)
enum ChimeraTK::VariableDirection::@0 dir
Enum to define directions of variables.
bool withReturn
Presence of return channel.