Skip to content
Snippets Groups Projects
TestDecoratorRegisterAccessor.h 5.5 KiB
Newer Older
/*
 * 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>

  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);
        throw std::logic_error("Write operation called on read-only variable.");
        if(!firstReadTransfer) {
          application_lock.unlock();
        }
        else {
          firstReadTransfer = false;
        }
        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;
      }

        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.");
        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 */