/* * TestDecoratorRegisterAccessor.h * * Created on: Feb 17, 2017 * Author: Martin Hierholzer */ #ifndef CHIMERATK_TEST_DECORATOR_REGISTER_ACCCESSOR #define CHIMERATK_TEST_DECORATOR_REGISTER_ACCCESSOR #include <mtca4u/NDRegisterAccessor.h> #include "Application.h" namespace ChimeraTK { template<typename UserType> class TestDecoratorRegisterAccessor; /** Altered version of the TransferFuture since we need to deal with the lock in the wait() function. */ template<typename UserType> class TestDecoratorTransferFuture : public TransferFuture { public: TestDecoratorTransferFuture() : _originalFuture{nullptr} {} TestDecoratorTransferFuture(TransferFuture &originalFuture, boost::shared_ptr<TestDecoratorRegisterAccessor<UserType>> accessor) : _originalFuture(&originalFuture), _accessor(accessor) { TransferFuture::_theFuture = _originalFuture->getBoostFuture(); TransferFuture::_transferElement = &(_originalFuture->getTransferElement()); } void wait() override { if(!_accessor->firstReadTransfer) { _accessor->application_lock.unlock(); } else { _accessor->firstReadTransfer = false; } _originalFuture->wait(); _accessor->postRead(); _accessor->hasActiveFuture = false; _accessor->application_lock.lock(); ++Application::getInstance().testableMode_counter; } protected: TransferFuture *_originalFuture; boost::shared_ptr<TestDecoratorRegisterAccessor<UserType>> _accessor; }; /*******************************************************************************************************************/ /** Decorator of the NDRegisterAccessor which facilitates tests of the application */ template<typename UserType> class TestDecoratorRegisterAccessor : public mtca4u::NDRegisterAccessor<UserType> { public: TestDecoratorRegisterAccessor(boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>> accessor) : mtca4u::NDRegisterAccessor<UserType>(accessor->getName(), accessor->getUnit(), accessor->getDescription()), _accessor(accessor) { buffer_2D.resize(_accessor->getNumberOfChannels()); for(size_t i=0; i<_accessor->getNumberOfChannels(); ++i) buffer_2D[i] = _accessor->accessChannel(i); assert(_accessor->isReadOnly()); application_lock = std::unique_lock<std::mutex>(Application::getInstance().testableMode_mutex, std::defer_lock); } void write() override { throw std::logic_error("Write operation called on read-only variable."); } void doReadTransfer() override { if(!firstReadTransfer) { application_lock.unlock(); } else { firstReadTransfer = false; } _accessor->doReadTransfer(); application_lock.lock(); ++Application::getInstance().testableMode_counter; } bool doReadTransferNonBlocking() override { return _accessor->doReadTransferNonBlocking(); } TransferFuture& readAsync() override { auto &future = _accessor->readAsync(); auto sharedThis = boost::static_pointer_cast<TestDecoratorRegisterAccessor<UserType>>(this->shared_from_this()); TransferElement::hasActiveFuture = true; activeTestDecoratorFuture = TestDecoratorTransferFuture<UserType>(future, sharedThis); return activeTestDecoratorFuture; } void postRead() override { if(!TransferElement::hasActiveFuture) _accessor->postRead(); for(size_t i=0; i<_accessor->getNumberOfChannels(); ++i) buffer_2D[i].swap(_accessor->accessChannel(i)); } void preWrite() override { throw std::logic_error("Write operation called on read-only variable."); } void postWrite() override { throw std::logic_error("Write operation called on read-only variable."); } bool isSameRegister(const boost::shared_ptr<mtca4u::TransferElement const> &other) const override { return _accessor->isSameRegister(other); } bool isReadOnly() const override { return _accessor->isReadOnly(); } bool isReadable() const override { return _accessor->isReadable(); } bool isWriteable() const override { return _accessor->isWriteable(); } std::vector< boost::shared_ptr<mtca4u::TransferElement> > getHardwareAccessingElements() override { return _accessor->getHardwareAccessingElements(); } void replaceTransferElement(boost::shared_ptr<mtca4u::TransferElement> newElement) override { _accessor->replaceTransferElement(newElement); } void setPersistentDataStorage(boost::shared_ptr<ChimeraTK::PersistentDataStorage> storage) override { _accessor->setPersistentDataStorage(storage); } protected: using mtca4u::NDRegisterAccessor<UserType>::buffer_2D; boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>> _accessor; /** Lock used to lock the testableMode_mutex of the application */ std::unique_lock<std::mutex> application_lock; /** Flag whether the call to doReadTransfer() is the first call after construction or not */ bool firstReadTransfer{true}; friend class TestDecoratorTransferFuture<UserType>; TestDecoratorTransferFuture<UserType> activeTestDecoratorFuture; }; } /* namespace ChimeraTK */ #endif /* CHIMERATK_TEST_DECORATOR_REGISTER_ACCCESSOR */