8#include <ChimeraTK/SystemTags.h>
9#include <ChimeraTK/TransferElement.h>
17 template<
typename UserType>
19 boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor,
const VariableNetworkNode& networkNode,
20 boost::shared_ptr<RecoveryHelper> recoveryHelper)
21 :
ChimeraTK::NDRegisterAccessorDecorator<UserType>(accessor), _recoveryHelper(std::move(recoveryHelper)),
22 _direction(networkNode.getDirection()) {
32 deviceManager->_writeRegisterPaths.emplace_back(registerName);
45 registerName, nElements, 0, {});
51 if(networkNode.
getTags().contains(ChimeraTK::SystemTags::reverseRecovery)) {
58 if(!std::is_same<UserType, ChimeraTK::Void>::value) {
63 deviceManager->_readRegisterPaths.emplace_back(registerName);
67 deviceManager->_readRegisterPaths.emplace_back(registerName);
70 throw ChimeraTK::logic_error(
"Invalid variable direction in " + networkNode.
getRegisterName());
76 template<
typename UserType>
78 auto deviceManager = _deviceManager.lock();
88 _inhibitWriteTransfer =
false;
89 _hasThrownLogicError =
false;
90 _dataLostInPreviousWrite =
false;
91 auto recoverylock{deviceManager->getRecoverySharedLock()};
93 if(_recoveryAccessor !=
nullptr) {
94 if(!_recoveryHelper->wasWritten && (_recoveryHelper->writeOrder != 0)) {
95 _dataLostInPreviousWrite =
true;
99 for(
unsigned int ch = 0; ch < _recoveryAccessor->getNumberOfChannels(); ++ch) {
100 _recoveryAccessor->accessChannel(ch) = buffer_2D[ch];
102 _recoveryHelper->versionNumber = versionNumber;
103 _recoveryHelper->writeOrder = deviceManager->writeOrder();
104 _recoveryHelper->wasWritten =
false;
107 _hasThrownLogicError =
true;
108 throw ChimeraTK::logic_error(
109 "ChimeraTK::ExceptionhandlingDecorator: Calling write() on a non-writeable accessor is not supported ");
112 boost::shared_lock<boost::shared_mutex> errorLock(deviceManager->_errorMutex);
113 if(deviceManager->_deviceHasError) {
114 _inhibitWriteTransfer =
true;
118 ++deviceManager->_synchronousTransferCounter;
124 ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPreWrite(type, versionNumber);
129 template<
typename UserType>
131 auto deviceManager = _deviceManager.lock();
133 if(_hasThrownLogicError) {
138 if(!_inhibitWriteTransfer) {
139 --deviceManager->_synchronousTransferCounter;
141 ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostWrite(type, versionNumber);
143 auto recoverylock{deviceManager->getRecoverySharedLock()};
146 _recoveryHelper->wasWritten =
true;
149 catch(ChimeraTK::runtime_error& e) {
150 auto description = std::string(e.what()) +
" (seen by '" + _target->getName() +
"')";
153 this->_exceptionBackend->setException(description);
155 deviceManager->reportException(description);
158 assert(_activeException ==
nullptr);
163 template<
typename UserType>
165 auto deviceManager = _deviceManager.lock();
168 if(!_hasThrownToInhibitTransfer) {
170 if(!TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) {
171 --deviceManager->_synchronousTransferCounter;
173 _target->setActiveException(this->_activeException);
174 _target->postRead(type, hasNewData);
180 _hasReportedException =
false;
183 catch(ChimeraTK::runtime_error& e) {
184 auto description = std::string(e.what()) +
" (seen by '" + _target->getName() +
"')";
187 this->_exceptionBackend->setException(description);
189 deviceManager->reportException(description);
190 _hasReportedException =
true;
194 _activeException =
nullptr;
197 if(_hasReportedException || _hasThrownToInhibitTransfer) {
198 _dataValidity = DataValidity::faulty;
202 if(deviceManager->getExceptionVersionNumber() > _versionNumber) {
203 _versionNumber = deviceManager->getExceptionVersionNumber();
207 _dataValidity = _target->dataValidity();
211 if(_target->getVersionNumber() > _versionNumber) {
212 _versionNumber = _target->getVersionNumber();
218 for(
size_t i = 0; i < buffer_2D.size(); ++i) {
219 buffer_2D[i].swap(this->_target->accessChannel(
static_cast<unsigned int>(i)));
222 assert(_activeException ==
nullptr);
227 template<
typename UserType>
229 auto deviceManager = _deviceManager.lock();
231 _hasThrownToInhibitTransfer =
false;
233 if(TransferElement::_versionNumber == VersionNumber(
nullptr)) {
234 deviceManager->waitForInitialValues();
238 if(!TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) {
239 boost::shared_lock<boost::shared_mutex> errorLock(deviceManager->_errorMutex);
240 if(deviceManager->_deviceHasError) {
241 _hasThrownToInhibitTransfer =
true;
242 throw ChimeraTK::runtime_error(
"ExceptionHandlingDecorator has thrown to skip read transfer");
246 ++deviceManager->_synchronousTransferCounter;
249 ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPreRead(type);
254 template<
typename UserType>
256 return genericWriteWrapper([&] {
return _target->writeTransferDestructively(versionNumber); });
261 template<
typename UserType>
263 return genericWriteWrapper([&] {
return _target->writeTransferDestructively(versionNumber); });
268 template<
typename UserType>
269 template<
typename Callable>
271 if(_inhibitWriteTransfer) {
272 return _dataLostInPreviousWrite;
274 bool transferReportsPreviousDataLost =
false;
276 transferReportsPreviousDataLost = writeFunction();
278 catch(ChimeraTK::runtime_error&) {
279 _activeException = std::current_exception();
281 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
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.
INSTANTIATE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(DebugPrintAccessorDecorator)
enum ChimeraTK::VariableDirection::@0 dir
Enum to define directions of variables.
bool withReturn
Presence of return channel.