4 #define BOOST_TEST_DYN_LINK
5 #define BOOST_TEST_MODULE SubdeviceBackendUnifiedTest
6 #include <boost/test/unit_test.hpp>
7 using namespace boost::unit_test_framework;
15 #include <boost/thread/barrier.hpp>
19 BOOST_AUTO_TEST_SUITE(DoubleBufferingBackendUnifiedTestSuite)
29 using ExceptionDummy::ExceptionDummy;
31 static boost::shared_ptr<DeviceBackend>
createInstance(std::string, std::map<std::string, std::string> parameters) {
32 return returnInstance<DummyForDoubleBuffering>(
33 parameters.at(
"map"), convertPathRelativeToDmapToAbs(parameters.at(
"map")));
43 void read(uint64_t bar, uint64_t address, int32_t* data,
size_t sizeInBytes)
override {
48 for(
unsigned i = 0; i < 2; i++) {
49 if(blockNextRead[i]) {
50 blockedInRead[i].wait();
51 unblockRead[i].wait();
52 blockNextRead[i] =
false;
62 static thread_local
bool blockNextRead[2];
65 std::array<boost::barrier, 2> blockedInRead{boost::barrier{2}, boost::barrier{2}};
67 std::array<boost::barrier, 2> unblockRead{boost::barrier{2}, boost::barrier{2}};
73 static std::string rawDeviceCdd(
"(DummyForDoubleBuffering?map=doubleBuffer.map)");
74 std::string
lmap =
"(logicalNameMap?map=doubleBuffer.xlmap&target=" + rawDeviceCdd +
")";
75 static auto backdoor =
76 boost::dynamic_pointer_cast<ExceptionDummy>(BackendFactory::getInstance().createBackend(rawDeviceCdd));
80 template<
typename Register>
93 .disableAsyncReadInconsistency()
94 .disableTestWriteNeverLosesData()
95 .disableSwitchReadOnly()
96 .disableSwitchWriteOnly()
97 .disableTestRawTransfer();
99 template<
typename UserType>
101 auto values = this->getRemoteValue<typename Register::minimumUserType>();
102 for(
size_t i = 0; i < this->nChannels(); ++i)
103 for(
size_t j = 0; j < this->nElementsPerChannel(); ++j) {
104 values[i][j] += this->increment * (i + j + 1);
109 template<
typename UserType>
119 auto currentBufferNumber = backdoor->getRegisterAccessor<uint32_t>(
"APP.0.WORD_DUB_BUF_CURR", 0, 0, {});
120 auto buffer0 = backdoor->getRegisterAccessor<
typename Register::minimumUserType>(
121 "APP/0/DAQ0_BUF0", this->nElementsPerChannel(), 0, {});
122 auto buffer1 = backdoor->getRegisterAccessor<
typename Register::minimumUserType>(
123 "APP/0/DAQ0_BUF1", this->nElementsPerChannel(), 0, {});
125 bool deviceWasOpened =
false;
126 if(!backdoor->isOpen()) {
128 deviceWasOpened =
true;
131 boost::shared_ptr<NDRegisterAccessor<typename Register::minimumUserType>> currentBuffer;
133 currentBufferNumber->read();
135 if(currentBufferNumber->accessData(0) == 1) {
136 currentBuffer = buffer0;
139 currentBuffer = buffer1;
141 currentBuffer->read();
142 std::vector<std::vector<UserType>> v;
143 for(
size_t i = 0; i < this->nChannels(); ++i) {
144 v.push_back(std::vector<UserType>());
145 for(
size_t j = 0; j < this->nElementsPerChannel(); ++j) {
146 v[i].push_back(currentBuffer->accessData(j));
150 if(deviceWasOpened) {
158 auto currentBufferNumber = backdoor->getRegisterAccessor<uint32_t>(
"APP.0.WORD_DUB_BUF_CURR", 0, 0, {});
159 auto buffer0 = backdoor->getRegisterAccessor<
typename Register::minimumUserType>(
160 "APP/0/DAQ0_BUF0", this->nElementsPerChannel(), 0, {});
161 auto buffer1 = backdoor->getRegisterAccessor<
typename Register::minimumUserType>(
162 "APP/0/DAQ0_BUF1", this->nElementsPerChannel(), 0, {});
163 boost::shared_ptr<NDRegisterAccessor<typename Register::minimumUserType>> currentBuffer;
165 bool deviceWasOpened =
false;
166 if(!backdoor->isOpen()) {
168 deviceWasOpened =
true;
171 currentBufferNumber->accessData(0) = _currentBufferNumber;
172 currentBufferNumber->write();
173 _currentBufferNumber = _currentBufferNumber ? 0 : 1;
175 auto values = this->generateValue<typename Register::minimumUserType>();
177 if(currentBufferNumber->accessData(0) == 1) {
178 currentBuffer = buffer0;
181 currentBuffer = buffer1;
183 for(
size_t i = 0; i < this->nChannels(); ++i) {
184 for(
size_t j = 0; j < this->nElementsPerChannel(); ++j) {
185 currentBuffer->accessData(i, j) = values[i][j];
188 currentBuffer->write();
190 if(deviceWasOpened) {
196 if(caseNumber == 0) {
197 backdoor->throwExceptionRead = enable;
198 backdoor->throwExceptionOpen = enable;
206 std::string
path() {
return "/doubleBuffer"; }
209 int32_t increment = 3;
217 template<
typename Register>
232 doubleBufDummy = boost::dynamic_pointer_cast<DummyForDoubleBuffering>(backdoor);
233 assert(doubleBufDummy);
234 doubleBufferingEnabled = backdoor->getRegisterAccessor<uint32_t>(
"APP/0/WORD_DUB_BUF_ENA", 0, 0, {});
235 doubleBufferingEnabled->accessData(0) = 1;
236 doubleBufferingEnabled->write();
244 auto accessor = d.getOneDRegisterAccessor<uint32_t>(
"/doubleBuffer");
249 doubleBufDummy->blockNextRead[0] =
true;
254 doubleBufDummy->blockedInRead[0].wait();
258 doubleBufferingEnabled->readLatest();
259 BOOST_CHECK(!doubleBufferingEnabled->accessData(0));
261 doubleBufDummy->unblockRead[0].wait();
265 doubleBufferingEnabled->readLatest();
266 BOOST_CHECK(doubleBufferingEnabled->accessData(0));
285 std::thread readerA([&] {
286 auto accessor = d.getOneDRegisterAccessor<uint32_t>(
"/doubleBuffer");
288 doubleBufDummy->blockNextRead[0] =
true;
291 std::thread readerB([&] {
292 auto accessor = d.getOneDRegisterAccessor<uint32_t>(
"/doubleBuffer");
294 doubleBufDummy->blockedInRead[0].wait();
296 doubleBufDummy->blockNextRead[1] =
true;
299 doubleBufDummy->blockedInRead[1].wait();
300 doubleBufDummy->unblockRead[0].wait();
304 doubleBufferingEnabled->readLatest();
305 BOOST_CHECK(!doubleBufferingEnabled->accessData(0));
307 doubleBufDummy->unblockRead[1].wait();
310 doubleBufferingEnabled->readLatest();
311 BOOST_CHECK(doubleBufferingEnabled->accessData(0));
318 template<
class Derived>
320 const std::string rawDeviceCdd =
"(dummy?map=doubleBuffer.map)";
321 const std::string
lmap =
"(logicalNameMap?map=doubleBuffer.xlmap&target=" + this->rawDeviceCdd +
")";
325 boost::shared_ptr<NDRegisterAccessor<float>> buf0,
buf1;
327 std::string enableDoubleBufferingReg, currentBufferNumberReg, firstBufferReg,
secondBufferReg;
332 ConfigParams c =
static_cast<Derived*
>(
this)->getCf();
335 backdoor = BackendFactory::getInstance().createBackend(this->rawDeviceCdd);
336 doubleBufferingEnabled = backdoor->getRegisterAccessor<uint32_t>(c.enableDoubleBufferingReg, 1, c.daqNumber, {});
337 doubleBufferingEnabled->accessData(0) = 1;
338 doubleBufferingEnabled->write();
340 writingBufferNum = backdoor->getRegisterAccessor<uint32_t>(c.currentBufferNumberReg, 1, c.daqNumber, {});
341 buf0 = backdoor->getRegisterAccessor<
float>(c.firstBufferReg, 0, 0, {});
342 buf1 = backdoor->getRegisterAccessor<
float>(c.secondBufferReg, 0, 0, {});
349 writingBufferNum->accessData(0) = 1;
350 writingBufferNum->write();
352 float modulation = 4.2;
353 unsigned channel = 3;
354 buf0->accessData(channel, 0) = modulation;
355 buf1->accessData(channel, 0) = 2 * modulation;
359 boost::barrier waitForBufferSwapStart{2}, waitForBufferSwapDone{2};
360 std::thread readerA([&] {
362 accessorA.readLatest();
364 BOOST_CHECK_CLOSE(accessorA[0], modulation, 1e-4);
365 waitForBufferSwapStart.wait();
366 waitForBufferSwapDone.wait();
367 accessorA.readLatest();
368 BOOST_CHECK_CLOSE(accessorA[0], 2 * modulation, 1e-4);
371 waitForBufferSwapStart.wait();
372 writingBufferNum->accessData(0) = 0;
373 writingBufferNum->write();
374 waitForBufferSwapDone.wait();
385 writingBufferNum->accessData(0) = 1;
386 writingBufferNum->write();
388 float modulation = 4.2;
389 float correction = 10.1;
390 buf0->accessData(3, 0) = modulation;
391 buf1->accessData(3, 0) = 2 * modulation;
392 buf0->accessData(1, 0) = correction;
393 buf1->accessData(1, 0) = 2 * correction;
397 boost::barrier waitForBufferSwap{3};
400 bool readerA_ok1, readerA_ok2, readerB_ok1, readerB_ok2;
402 std::thread readerA([&] {
404 accessorA.readLatest();
405 readerA_ok1 = abs(accessorA[0] - modulation) < 1e-4;
406 waitForBufferSwap.wait();
407 waitForBufferSwap.wait();
408 accessorA.readLatest();
409 readerA_ok2 = abs(accessorA[0] - 2 * modulation) < 1e-4;
411 std::thread readerB([&] {
414 readerB_ok1 = abs(accessorB[0] - correction) < 1e-4;
415 waitForBufferSwap.wait();
416 waitForBufferSwap.wait();
418 readerB_ok2 = abs(accessorB[0] - 2 * correction) < 1e-4;
421 waitForBufferSwap.wait();
422 writingBufferNum->accessData(0) = 0;
423 writingBufferNum->write();
424 waitForBufferSwap.wait();
428 BOOST_CHECK(readerA_ok1);
429 BOOST_CHECK(readerA_ok2);
430 BOOST_CHECK(readerB_ok1);
431 BOOST_CHECK(readerB_ok2);
440 BOOST_CHECK_CLOSE(accessorA[0], 2 * modulation, 1e-4);
441 BOOST_CHECK_CLOSE(accessorB[0], 2 * correction, 1e-4);
443 writingBufferNum->accessData(0) = 1;
444 writingBufferNum->write();
446 BOOST_CHECK_CLOSE(accessorA[0], modulation, 1e-4);
447 BOOST_CHECK_CLOSE(accessorB[0], correction, 1e-4);
454 c.enableDoubleBufferingReg =
"DAQ0/WORD_DUB_BUF_ENA";
455 c.currentBufferNumberReg =
"DAQ0/WORD_DUB_BUF_CURR/DUMMY_WRITEABLE";
456 c.firstBufferReg =
"APP0/DAQ0_BUF0";
457 c.secondBufferReg =
"APP0/DAQ0_BUF1";
465 c.enableDoubleBufferingReg =
"DAQ2/WORD_DUB_BUF_ENA";
466 c.currentBufferNumberReg =
"DAQ2/WORD_DUB_BUF_CURR/DUMMY_WRITEABLE";
467 c.firstBufferReg =
"APP2/DAQ2_BUF0";
468 c.secondBufferReg =
"APP2/DAQ2_BUF1";
476 simpleCheckExtractedChannels(
"modulationA");
477 checkExtractedChannels(
"modulationA",
"correctionA");
482 simpleCheckExtractedChannels(
"modulationC");
483 checkExtractedChannels(
"modulationC",
"correctionC");
488 BOOST_AUTO_TEST_SUITE_END()