Newer
Older
Martin Christoph Hierholzer
committed
/*
* 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>
Martin Christoph Hierholzer
committed
#include "Application.h"
Martin Christoph Hierholzer
committed
namespace ChimeraTK {
Martin Christoph Hierholzer
committed
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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;
};
/*******************************************************************************************************************/
Martin Christoph Hierholzer
committed
/** 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);
Martin Christoph Hierholzer
committed
assert(_accessor->isReadOnly());
application_lock = std::unique_lock<std::mutex>(Application::getInstance().testableMode_mutex, std::defer_lock);
Martin Christoph Hierholzer
committed
}
void write() override {
Martin Christoph Hierholzer
committed
throw std::logic_error("Write operation called on read-only variable.");
Martin Christoph Hierholzer
committed
}
void doReadTransfer() override {
Martin Christoph Hierholzer
committed
if(!firstReadTransfer) {
application_lock.unlock();
}
else {
firstReadTransfer = false;
}
Martin Christoph Hierholzer
committed
_accessor->doReadTransfer();
Martin Christoph Hierholzer
committed
application_lock.lock();
++Application::getInstance().testableMode_counter;
Martin Christoph Hierholzer
committed
}
bool doReadTransferNonBlocking() override {
return _accessor->doReadTransferNonBlocking();
}
Martin Christoph Hierholzer
committed
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;
}
Martin Christoph Hierholzer
committed
void postRead() override {
Martin Christoph Hierholzer
committed
if(!TransferElement::hasActiveFuture) _accessor->postRead();
Martin Christoph Hierholzer
committed
for(size_t i=0; i<_accessor->getNumberOfChannels(); ++i) buffer_2D[i].swap(_accessor->accessChannel(i));
}
void preWrite() override {
Martin Christoph Hierholzer
committed
throw std::logic_error("Write operation called on read-only variable.");
Martin Christoph Hierholzer
committed
}
void postWrite() override {
Martin Christoph Hierholzer
committed
throw std::logic_error("Write operation called on read-only variable.");
Martin Christoph Hierholzer
committed
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
}
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;
Martin Christoph Hierholzer
committed
/** 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;
Martin Christoph Hierholzer
committed
};
} /* namespace ChimeraTK */
#endif /* CHIMERATK_TEST_DECORATOR_REGISTER_ACCCESSOR */