ChimeraTK-DeviceAccess 03.27.00
Loading...
Searching...
No Matches
testNumericAddressedBackendRegisterAccessor.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4#define BOOST_TEST_DYN_LINK
5// Define a name for the test module.
6#define BOOST_TEST_MODULE NumericAddressedBackendRegisterAccessorTest
7// Only after defining the name include the unit test header.
8#include <boost/test/unit_test.hpp>
9using namespace boost::unit_test_framework;
10
11#include "accessPrivateData.h"
12#include "BackendFactory.h"
13#include "Device.h"
14#include "DummyBackend.h"
16#include "TransferGroup.h"
17
18namespace ChimeraTK {
19 using namespace ChimeraTK;
20}
21using namespace ChimeraTK;
22
23// we need to access some private data of the low level transfer element
24// FIXME: redesign test so this is not necessary!
30
36
37// Create a test suite which holds all your tests.
38BOOST_AUTO_TEST_SUITE(NumericAddressedBackendRegisterAccessorTestSuite)
39
40/**********************************************************************************************************************/
41
42// Test the creation by using all possible options in Device
43BOOST_AUTO_TEST_CASE(testCreation) {
44 // it is always a 1D-type register (for scalar it's just 1x1)
47 device.open("DUMMYD1");
48
49 // we only check the size. That writing/reading from the offsets is ok is
50 // checked elsewere
51 // FIXME: Should it be moved here? seems really scattered around at the
52 // moment.
53
54 // the full register
55 auto accessor1 = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA");
56 BOOST_CHECK(accessor1.getNElements() == 10);
57 // just a part
58 auto accessor2 = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 5);
59 BOOST_CHECK(accessor2.getNElements() == 5);
60 // A part with offset
61 auto accessor3 = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 3, 4);
62 BOOST_CHECK(accessor3.getNElements() == 3);
63
64 // some error cases:
65 // too many elements requested
66 BOOST_CHECK_THROW(std::ignore = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 11), ChimeraTK::logic_error);
67 // offset exceeds range (or would result in accessor with 0 elements)
68 BOOST_CHECK_THROW(
69 std::ignore = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 0, 10), ChimeraTK::logic_error);
70 BOOST_CHECK_THROW(
71 std::ignore = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 0, 11), ChimeraTK::logic_error);
72 BOOST_CHECK_THROW(
73 std::ignore = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 0, 2), ChimeraTK::logic_error);
74 // sum of requested elements and offset too large
75 BOOST_CHECK_THROW(
76 std::ignore = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 5, 6), ChimeraTK::logic_error);
77
78 // get accessor in raw mode
79 // FIXME: This was never used, so raw mode is never tested anywhere
80 auto accessor5 = device.getOneDRegisterAccessor<int32_t>("MODULE1/TEST_AREA", 0, 0, {AccessMode::raw});
81 BOOST_CHECK(accessor5.getNElements() == 10);
82 // only int32_t works, other types fail
83 BOOST_CHECK_THROW(std::ignore = device.getOneDRegisterAccessor<double>("MODULE1/TEST_AREA", 0, 0, {AccessMode::raw}),
85}
86
87/**********************************************************************************************************************/
88
89BOOST_AUTO_TEST_CASE(testReadWrite) {
91 device.open("(dummy?map=goodMapFile.map)");
92
93 auto accessor = device.getScalarRegisterAccessor<int>("MODULE0/WORD_USER1");
94
95 // FIXME: systematically test reading and writing. Currently is scattered all
96 // over the place...
97}
98
99/**********************************************************************************************************************/
100
101BOOST_AUTO_TEST_CASE(testReadOnly) {
103 device.open("(dummy?map=goodMapFile.map)");
104
105 auto accToReadOnly = device.getScalarRegisterAccessor<int>("MODULE1/WORD_USER3");
106
107 BOOST_CHECK(accToReadOnly.isReadOnly());
108 BOOST_CHECK(!accToReadOnly.isWriteable());
109
110 BOOST_CHECK_THROW(accToReadOnly.write(), ChimeraTK::logic_error);
111}
112
113/**********************************************************************************************************************/
114
115BOOST_AUTO_TEST_CASE(testRawWrite) {
117 device.open("(dummy?map=goodMapFile.map)");
118
119 auto accessor1 = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 0, 0, {AccessMode::raw});
120 for(auto& value : accessor1) {
121 value = 0xFF;
122 }
123 accessor1.write();
124
125 // another accessor for reading the same register
126 auto accessor2 = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 0, 0, {AccessMode::raw});
127 accessor2.read();
128 for(auto& value : accessor2) {
129 BOOST_CHECK(value == 0xFF);
130 }
131
132 for(auto& value : accessor1) {
133 value = 0x77;
134 }
135 accessor1.write();
136 for(auto& value : accessor1) {
137 BOOST_CHECK(value == 0x77);
138 }
139
140 accessor2.read();
141 for(auto& value : accessor2) {
142 BOOST_CHECK(value == 0x77);
143 }
144
145 // do not change the content of accessor1. suspicion: it has old, swapped data
146 accessor1.write();
147 accessor2.read();
148 for(auto& value : accessor2) {
149 BOOST_CHECK(value == 0x77);
150 }
151}
152
153/**********************************************************************************************************************/
154
155BOOST_AUTO_TEST_CASE(testRawWithTransferGroup) {
157 device.open("(dummy?map=goodMapFile.map)");
158
159 // the whole register
160 auto a1 = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 2, 0, {AccessMode::raw});
161 auto a2 = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 2, 2, {AccessMode::raw});
162
163 // the whole register in a separate accessor which is not in the group
164 auto standalone = device.getOneDRegisterAccessor<int>("MODULE1/TEST_AREA", 0, 0, {AccessMode::raw});
165
166 // start with a single accessor so the low level transfer element is not
167 // shared
168 TransferGroup group;
169 group.addAccessor(a1);
170
171 for(auto& value : a1) {
172 value = 0x77;
173 }
174 group.write();
175
176 standalone.read();
177 BOOST_CHECK(standalone[0] == 0x77);
178 BOOST_CHECK(standalone[1] == 0x77);
179
180 // check that the swapping works as intended
181 for(auto& value : a1) {
182 value = 0xFF;
183 }
184
185 // writing twice without modifying the buffer certainly has to work
186 // In case the old values have accidentally been swapped out and not back in
187 // this is not the case, which would be a bug
188 for(int i = 0; i < 2; ++i) {
189 group.write();
190 // writing must not swap away the buffer
191 for(auto& value : a1) {
192 BOOST_CHECK(value == 0xFF);
193 }
194 standalone.read();
195 BOOST_CHECK(standalone[0] == 0xFF);
196 BOOST_CHECK(standalone[1] == 0xFF);
197 }
198
199 // test reading and mixed reading/writing
200 standalone[0] = 0xAA;
201 standalone[1] = 0xAA;
202 standalone.write();
203
204 for(int i = 0; i < 2; ++i) {
205 group.read();
206 for(auto& value : a1) {
207 BOOST_CHECK(value == 0xAA);
208 }
209 }
210
211 standalone[0] = 0xAB;
212 standalone[1] = 0xAB;
213 standalone.write();
214
215 group.read();
216 group.write();
217 for(auto& value : a1) {
218 BOOST_CHECK(value == 0xAB);
219 }
220
221 standalone.read();
222 BOOST_CHECK(standalone[0] == 0xAB);
223 BOOST_CHECK(standalone[1] == 0xAB);
224
225 // initialise the words pointed to by a2
226 for(auto& value : a2) {
227 value = 0x77;
228 }
229 a2.write();
230
231 // Now add the second accessor of the same register to the group and repeat
232 // the tests They will share the same low level transfer element.
233 group.addAccessor(a2);
234 for(auto& value : a1) {
235 value = 0xFD;
236 }
237 for(auto& value : a2) {
238 value = 0xFE;
239 }
240
241 for(int i = 0; i < 2; ++i) {
242 group.write();
243 for(auto& value : a1) {
244 BOOST_CHECK(value == 0xFD);
245 }
246 for(auto& value : a2) {
247 BOOST_CHECK(value == 0xFE);
248 }
249 standalone.read();
250 BOOST_CHECK(standalone[0] == 0xFD);
251 BOOST_CHECK(standalone[1] == 0xFD);
252 BOOST_CHECK(standalone[2] == 0xFE);
253 BOOST_CHECK(standalone[3] == 0xFE);
254 }
255
256 standalone[0] = 0xA1;
257 standalone[1] = 0xA2;
258 standalone[2] = 0xA3;
259 standalone[3] = 0xA4;
260 standalone.write();
261
262 group.read();
263 group.write();
264 BOOST_CHECK(a1[0] == 0xA1);
265 BOOST_CHECK(a1[1] == 0xA2);
266 BOOST_CHECK(a2[0] == 0xA3);
267 BOOST_CHECK(a2[1] == 0xA4);
268
269 standalone.read();
270 BOOST_CHECK(standalone[0] == 0xA1);
271 BOOST_CHECK(standalone[1] == 0xA2);
272 BOOST_CHECK(standalone[2] == 0xA3);
273 BOOST_CHECK(standalone[3] == 0xA4);
274}
275
276/**********************************************************************************************************************/
277
278BOOST_AUTO_TEST_CASE(testConversionTypes) {
279 // The bit interpretation can either have a fixed number of fractional bits or be IEEE754 single precision.
280 // We test those scenarios, and that raw and coocked accessors are working for all of them.
281
282 // As we cannot rely on any NumericAddressedRegisterAccessor at the moment we use the
283 // DummyRegisterRawAccessor to monitor what is going on in the target memory space on
284 // the device
285 const char* deviceDescriptor = "(dummy?map=goodMapFile.map)";
286
287 auto dummyBackend =
288 boost::dynamic_pointer_cast<DummyBackend>(BackendFactory::getInstance().createBackend(deviceDescriptor));
289
291 device.open(deviceDescriptor);
292
293 // Fixed point convertion, raw and coocked accessors
294 // MODULE0.WORD_USER1 is fixed point, 16 bit, 3 fractional, signed
295 auto user1Dummy = dummyBackend->getRawAccessor("MODULE0", "WORD_USER1");
296 // Demonstrate the correct usage of the raw accessor, with using the lock. It would not be strictly needed here
297 // because this is single threaded, but in general it is required.
298 {
299 auto bufferLock = user1Dummy.getBufferLock();
300 user1Dummy = 0x4321;
301 }
302
303 auto user1Coocked = device.getScalarRegisterAccessor<float>("MODULE0/WORD_USER1");
304 user1Coocked.read();
305
306 BOOST_CHECK_CLOSE(float(user1Coocked), 2148.125, 0.0001);
307
308 user1Coocked = -1;
309 user1Coocked.write();
310
311 {
312 auto bufferLock = user1Dummy.getBufferLock();
313 BOOST_CHECK_EQUAL(int32_t(user1Dummy), 0xfff8);
314 }
315
316 auto user1Raw = device.getScalarRegisterAccessor<int32_t>("MODULE0/WORD_USER1", 0, {AccessMode::raw});
317 user1Raw.read();
318
319 BOOST_CHECK_EQUAL(int32_t(user1Raw), 0xfff8);
320 BOOST_CHECK_CLOSE(user1Raw.getAsCooked<float>(), -1, 0.0001);
321
322 user1Raw.setAsCooked(-2.5);
323
324 user1Raw.write();
325
326 {
327 auto bufferLock = user1Dummy.getBufferLock();
328 BOOST_CHECK_EQUAL(int32_t(user1Dummy), 0xffec);
329 }
330
331 // special case: int32 does not necessarily mean raw. There is also a cooked version:
332 auto user1CoockedInt = device.getScalarRegisterAccessor<int32_t>("MODULE0/WORD_USER1");
333 user1CoockedInt.read();
334
335 BOOST_CHECK_EQUAL(int(user1CoockedInt), -3);
336
337 user1CoockedInt = 16;
338 user1CoockedInt.write();
339
340 {
341 auto bufferLock = user1Dummy.getBufferLock();
342 BOOST_CHECK_EQUAL(int32_t(user1Dummy), 0x80);
343 }
344
345 // IEEE754 conversion, raw and coocked accessors
346 // FLOAT_TEST.ARRAY is IEEE754. We use the 1 D version in contrast to fixed point case, where we use scalar (just
347 // because we can)
348 auto floatTestDummy = dummyBackend->getRawAccessor("FLOAT_TEST", "ARRAY");
349
350 float testValue = 1.1;
351 {
352 auto bufferLock = floatTestDummy.getBufferLock();
353 floatTestDummy[0] = std::bit_cast<int32_t>(testValue);
354 testValue = 2.2;
355 floatTestDummy[1] = std::bit_cast<int32_t>(testValue);
356 testValue = 3.3;
357 floatTestDummy[2] = std::bit_cast<int32_t>(testValue);
358 testValue = 4.4;
359 floatTestDummy[3] = std::bit_cast<int32_t>(testValue);
360 } // release buffer lock
361
362 auto floatTestCoocked = device.getOneDRegisterAccessor<float>("FLOAT_TEST/ARRAY");
363 floatTestCoocked.read();
364
365 BOOST_CHECK_CLOSE(floatTestCoocked[0], 1.1, 0.0001);
366 BOOST_CHECK_CLOSE(floatTestCoocked[1], 2.2, 0.0001);
367 BOOST_CHECK_CLOSE(floatTestCoocked[2], 3.3, 0.0001);
368 BOOST_CHECK_CLOSE(floatTestCoocked[3], 4.4, 0.0001);
369
370 floatTestCoocked[3] = 44.4;
371 floatTestCoocked.write();
372
373 {
374 auto bufferLock = floatTestDummy.getBufferLock();
375 testValue = std::bit_cast<float>(floatTestDummy[3]);
376 }
377 BOOST_CHECK_CLOSE(testValue, 44.4, 0.0001);
378
379 auto floatTestRaw = device.getOneDRegisterAccessor<int32_t>("FLOAT_TEST/ARRAY", 0, 0, {AccessMode::raw});
380 floatTestRaw.read();
381
382 testValue = std::bit_cast<float>(floatTestRaw[2]);
383
384 BOOST_CHECK_CLOSE(testValue, 3.3, 0.0001);
385 BOOST_CHECK_CLOSE(floatTestRaw.getAsCooked<float>(0), 1.1, 0.0001);
386
387 floatTestRaw.setAsCooked(0, -2.5);
388
389 floatTestRaw.write();
390
391 {
392 auto bufferLock = floatTestDummy.getBufferLock();
393 testValue = std::bit_cast<float>(floatTestDummy[0]);
394 }
395 BOOST_CHECK_CLOSE(testValue, -2.5, 0.0001);
396
397 // special case: int32 does not necessarily mean raw. There is also a cooked version:
398 auto floatTestCoockedInt = device.getOneDRegisterAccessor<int32_t>("FLOAT_TEST/ARRAY");
399 floatTestCoockedInt.read();
400
401 BOOST_CHECK_EQUAL(floatTestCoockedInt[0], -3); // was -2.5
402 BOOST_CHECK_EQUAL(floatTestCoockedInt[1], 2); // was 2.2
403 BOOST_CHECK_EQUAL(floatTestCoockedInt[2], 3); // was 3.3
404 BOOST_CHECK_EQUAL(floatTestCoockedInt[3], 44); // was 44.4
405
406 floatTestCoockedInt[1] = 16;
407 floatTestCoockedInt.write();
408
409 {
410 auto bufferLock = floatTestDummy.getBufferLock();
411 testValue = std::bit_cast<float>(floatTestDummy[1]);
412 }
413 BOOST_CHECK_CLOSE(testValue, 16.0, 0.001);
414}
415
416/**********************************************************************************************************************/
417
418BOOST_AUTO_TEST_CASE(registerCatalogueCreation) {
419 Device d("(dummy?map=goodMapFile.map)");
420 auto catalogue = d.getRegisterCatalogue();
421 BOOST_CHECK_NO_THROW((void)catalogue.getRegister("MODULE0/WORD_USER1"));
422
423 BOOST_CHECK(d.isOpened() == false);
424 BOOST_CHECK_NO_THROW(d.open());
425 BOOST_CHECK(d.isOpened() == true);
426}
427
428/**********************************************************************************************************************/
429
430BOOST_AUTO_TEST_CASE(testMergeNumericRegisters) {
433
434 device.open("DUMMYD3");
435
436 // create register accessors of four registers with adjecent addresses
437 auto mux0 = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_0");
438 auto mux1 = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_1");
439 auto mux2 = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_2");
440 auto mux3 = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_3");
441
442 // create the same register accessors again, so we have a second set not part
443 // of the transfer group
444 auto mux0b = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_0");
445 auto mux1b = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_1");
446 auto mux2b = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_2");
447 auto mux3b = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_3");
448
449 // obtain the private pointers to the implementation of the accessor
450 auto mux0i = boost::dynamic_pointer_cast<NDRegisterAccessor<int>>(mux0.getHighLevelImplElement());
451 auto mux1i = boost::dynamic_pointer_cast<NDRegisterAccessor<int>>(mux1.getHighLevelImplElement());
452 auto mux2i = boost::dynamic_pointer_cast<NDRegisterAccessor<int>>(mux2.getHighLevelImplElement());
453 auto mux3i = boost::dynamic_pointer_cast<NDRegisterAccessor<int>>(mux3.getHighLevelImplElement());
454
455 // check that all underlying raw accessors are still different
456 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux1i->getHardwareAccessingElements()[0]);
457 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux2i->getHardwareAccessingElements()[0]);
458 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
459 BOOST_CHECK(mux1i->getHardwareAccessingElements()[0] != mux2i->getHardwareAccessingElements()[0]);
460 BOOST_CHECK(mux1i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
461 BOOST_CHECK(mux2i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
462
463 // check that the underlying raw accessors have the right address range
464 NumericAddressedLowLevelTransferElement* llelem; // operator ->* does not work on a shared_ptr
465 llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux0i->getHardwareAccessingElements()[0])
466 .get();
469 llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux1i->getHardwareAccessingElements()[0])
470 .get();
473 llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux2i->getHardwareAccessingElements()[0])
474 .get();
477 llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux3i->getHardwareAccessingElements()[0])
478 .get();
481
482 // add accessors to the transfer group. The accessors are intentionally added
483 // out of order to check if the behaviour is also correct in that case
484 TransferGroup group;
485 group.addAccessor(mux0);
486 group.addAccessor(mux2);
487 group.addAccessor(mux1);
488 group.addAccessor(mux3);
489
490 // check that all underlying raw accessors are now all the same
491 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux1i->getHardwareAccessingElements()[0]);
492 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux2i->getHardwareAccessingElements()[0]);
493 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux3i->getHardwareAccessingElements()[0]);
494
495 // check that the underlying raw accessor have the right address range
496 llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux0i->getHardwareAccessingElements()[0])
497 .get();
500
501 // check that reading and writing works
502 mux0 = 42;
503 mux1 = 120;
504 mux2 = 84;
505 mux3 = 240;
506 group.write();
507
508 mux0b.read();
509 BOOST_CHECK(mux0b == 42);
510 mux1b.read();
511 BOOST_CHECK(mux1b == 120);
512 mux2b.read();
513 BOOST_CHECK(mux2b == 84);
514 mux3b.read();
515 BOOST_CHECK(mux3b == 240);
516
517 mux0b = 123;
518 mux0b.write();
519 group.read();
520 BOOST_CHECK(mux0 == 123);
521 BOOST_CHECK(mux1 == 120);
522 BOOST_CHECK(mux2 == 84);
523 BOOST_CHECK(mux3 == 240);
524
525 mux1b = 234;
526 mux1b.write();
527 group.read();
528 BOOST_CHECK(mux0 == 123);
529 BOOST_CHECK(mux1 == 234);
530 BOOST_CHECK(mux2 == 84);
531 BOOST_CHECK(mux3 == 240);
532
533 mux2b = 345;
534 mux2b.write();
535 group.read();
536 BOOST_CHECK(mux0 == 123);
537 BOOST_CHECK(mux1 == 234);
538 BOOST_CHECK(mux2 == 345);
539 BOOST_CHECK(mux3 == 240);
540
541 mux3b = 456;
542 mux3b.write();
543 group.read();
544 BOOST_CHECK(mux0 == 123);
545 BOOST_CHECK(mux1 == 234);
546 BOOST_CHECK(mux2 == 345);
547 BOOST_CHECK(mux3 == 456);
548}
549
550/**********************************************************************************************************************/
551
552BOOST_AUTO_TEST_CASE(testMergeNumericRegistersDifferentTypes) {
555
556 device.open("DUMMYD3");
557
558 // create register accessors of four registers with adjecent addresses
559 auto mux0 = device.getScalarRegisterAccessor<uint16_t>("/ADC/WORD_CLK_MUX_0");
560 auto mux1 = device.getScalarRegisterAccessor<uint16_t>("/ADC/WORD_CLK_MUX_1");
561 auto mux2 = device.getScalarRegisterAccessor<int32_t>("/ADC/WORD_CLK_MUX_2", 0, {AccessMode::raw});
562 auto mux3 = device.getScalarRegisterAccessor<int64_t>("/ADC/WORD_CLK_MUX_3");
563
564 // create the same register accessors again, so we have a second set not part
565 // of the transfer group
566 auto mux0b = device.getScalarRegisterAccessor<uint16_t>("/ADC/WORD_CLK_MUX_0");
567 auto mux1b = device.getScalarRegisterAccessor<uint16_t>("/ADC/WORD_CLK_MUX_1");
568 auto mux2b = device.getScalarRegisterAccessor<int32_t>("/ADC/WORD_CLK_MUX_2", 0, {AccessMode::raw});
569 auto mux3b = device.getScalarRegisterAccessor<int64_t>("/ADC/WORD_CLK_MUX_3");
570
571 // obtain the private pointers to the implementation of the accessor
572 auto mux0i = boost::dynamic_pointer_cast<NDRegisterAccessor<uint16_t>>(mux0.getHighLevelImplElement());
573 auto mux1i = boost::dynamic_pointer_cast<NDRegisterAccessor<uint16_t>>(mux1.getHighLevelImplElement());
574 auto mux2i = boost::dynamic_pointer_cast<NDRegisterAccessor<int32_t>>(mux2.getHighLevelImplElement());
575 auto mux3i = boost::dynamic_pointer_cast<NDRegisterAccessor<int64_t>>(mux3.getHighLevelImplElement());
576
577 // check that all underlying raw accessors are still different
578 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux1i->getHardwareAccessingElements()[0]);
579 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux2i->getHardwareAccessingElements()[0]);
580 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
581 BOOST_CHECK(mux1i->getHardwareAccessingElements()[0] != mux2i->getHardwareAccessingElements()[0]);
582 BOOST_CHECK(mux1i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
583 BOOST_CHECK(mux2i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
584
585 // add accessors to the transfer group. The accessors are intentionally added
586 // out of order to check if the behaviour is also correct in that case
587 TransferGroup group;
588 group.addAccessor(mux2);
589 group.addAccessor(mux1);
590 group.addAccessor(mux3);
591 group.addAccessor(mux0);
592
593 // check that all underlying raw accessors are now all the same
594 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux1i->getHardwareAccessingElements()[0]);
595 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux2i->getHardwareAccessingElements()[0]);
596 BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux3i->getHardwareAccessingElements()[0]);
597
598 // also check that all high-level implementations are still the same as
599 // previously
600 BOOST_CHECK(mux0i == boost::dynamic_pointer_cast<NDRegisterAccessor<uint16_t>>(mux0.getHighLevelImplElement()));
601 BOOST_CHECK(mux1i == boost::dynamic_pointer_cast<NDRegisterAccessor<uint16_t>>(mux1.getHighLevelImplElement()));
602 BOOST_CHECK(mux2i == boost::dynamic_pointer_cast<NDRegisterAccessor<int32_t>>(mux2.getHighLevelImplElement()));
603 BOOST_CHECK(mux3i == boost::dynamic_pointer_cast<NDRegisterAccessor<int64_t>>(mux3.getHighLevelImplElement()));
604
605 // check that reading and writing works
606 mux0 = 42;
607 mux1 = 120;
608 mux2 = 84;
609 mux3 = 240;
610 group.write();
611
612 mux0b.read();
613 BOOST_CHECK(mux0b == 42);
614 mux1b.read();
615 BOOST_CHECK(mux1b == 120);
616 mux2b.read();
617 BOOST_CHECK(mux2b == 84);
618 mux3b.read();
619 BOOST_CHECK(mux3b == 240);
620
621 mux0b = 123;
622 mux0b.write();
623 group.read();
624 BOOST_CHECK(mux0 == 123);
625 BOOST_CHECK(mux1 == 120);
626 BOOST_CHECK(mux2 == 84);
627 BOOST_CHECK(mux3 == 240);
628
629 mux1b = 234;
630 mux1b.write();
631 group.read();
632 BOOST_CHECK(mux0 == 123);
633 BOOST_CHECK(mux1 == 234);
634 BOOST_CHECK(mux2 == 84);
635 BOOST_CHECK(mux3 == 240);
636
637 mux2b = 345;
638 mux2b.write();
639 group.read();
640 BOOST_CHECK(mux0 == 123);
641 BOOST_CHECK(mux1 == 234);
642 BOOST_CHECK(mux2 == 345);
643 BOOST_CHECK(mux3 == 240);
644
645 mux3b = 456;
646 mux3b.write();
647 group.read();
648 BOOST_CHECK(mux0 == 123);
649 BOOST_CHECK(mux1 == 234);
650 BOOST_CHECK(mux2 == 345);
651 BOOST_CHECK(mux3 == 456);
652}
653
654/**********************************************************************************************************************/
655
656BOOST_AUTO_TEST_SUITE_END()
static BackendFactory & getInstance()
Static function to get an instance of factory.
void setDMapFilePath(std::string dMapFilePath)
This function sets the _DMapFilePath.
Class allows to read/write registers from device.
Definition Device.h:39
bool isOpened() const
Check if the device is currently opened.
Definition Device.cc:73
ScalarRegisterAccessor< UserType > getScalarRegisterAccessor(const RegisterPath &registerPathName, size_t wordOffsetInRegister=0, const AccessModeFlags &flags=AccessModeFlags({})) const
Get a ScalarRegisterObject object for the given register.
Definition Device.h:266
RegisterCatalogue getRegisterCatalogue() const
Return the register catalogue with detailed information on all registers.
Definition Device.cc:22
OneDRegisterAccessor< UserType > getOneDRegisterAccessor(const RegisterPath &registerPathName, size_t numberOfWords=0, size_t wordOffsetInRegister=0, const AccessModeFlags &flags=AccessModeFlags({})) const
Get a OneDRegisterAccessor object for the given register.
Definition Device.h:276
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Definition Device.cc:58
N-dimensional register accessor.
Implementation of the NDRegisterAccessor for NumericAddressedBackends, responsible for the underlying...
Group multiple data accessors to efficiently trigger data transfers on the whole group.
void addAccessor(TransferElementAbstractor &accessor)
Add a register accessor to the group.
void write(VersionNumber versionNumber={})
Trigger write transfer for all accessors in the group.
void read()
Trigger read transfer for all accessors in the group.
Exception thrown when a logic error has occured.
Definition Exception.h:51
ctk::Device device