ChimeraTK-DeviceAccess  03.18.00
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>
9 using namespace boost::unit_test_framework;
10 
11 #include "accessPrivateData.h"
12 #include "BackendFactory.h"
13 #include "Device.h"
14 #include "DummyBackend.h"
15 #include "DummyRegisterAccessor.h"
16 #include "TransferGroup.h"
17 
18 namespace ChimeraTK {
19  using namespace ChimeraTK;
20 }
21 using 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!
27 };
30 
33 };
36 
37 // Create a test suite which holds all your tests.
38 BOOST_AUTO_TEST_SUITE(NumericAddressedBackendRegisterAccessorTestSuite)
39 
40 /**********************************************************************************************************************/
41 
42 // Test the creation by using all possible options in Device
43 BOOST_AUTO_TEST_CASE(testCreation) {
44  // it is always a 1D-type register (for scalar it's just 1x1)
45  BackendFactory::getInstance().setDMapFilePath(TEST_DMAP_FILE_PATH);
46  Device device;
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 
89 BOOST_AUTO_TEST_CASE(testReadWrite) {
90  Device device;
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 
101 BOOST_AUTO_TEST_CASE(testReadOnly) {
102  Device device;
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 
115 BOOST_AUTO_TEST_CASE(testRawWrite) {
116  Device device;
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 
155 BOOST_AUTO_TEST_CASE(testRawWithTransferGroup) {
156  Device device;
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 
278 BOOST_AUTO_TEST_CASE(testConverterTypes) {
279  // After the introduction of the IEEE754 floating point converter we have to test
280  // that all possible converters (two at the moment) are created when they should,
281  // and that raw and coocked accessors are working for all of them.
282 
283  // As we cannot rely on any NumericAddressedRegisterAccessor at the moment we use the
284  // DummyRegisterRawAccessor to monitor what is going on in the target memory space on
285  // the device
286  auto deviceDescriptor = "(dummy?map=goodMapFile.map)";
287 
288  auto dummyBackend =
289  boost::dynamic_pointer_cast<DummyBackend>(BackendFactory::getInstance().createBackend(deviceDescriptor));
290 
291  Device device;
292  device.open(deviceDescriptor);
293 
294  // FixedPointConverter, raw and coocked accessors
295  // MODULE0.WORD_USER1 is fixed point, 16 bit, 3 fractional, signed
296  auto user1Dummy = dummyBackend->getRawAccessor("MODULE0", "WORD_USER1");
297  // Demonstrate the correct usage of the raw accessor, with using the lock. It would not be strictly needed here
298  // because this is single threaded, but in general it is required.
299  {
300  auto bufferLock = user1Dummy.getBufferLock();
301  user1Dummy = 0x4321;
302  }
303 
304  auto user1Coocked = device.getScalarRegisterAccessor<float>("MODULE0/WORD_USER1");
305  user1Coocked.read();
306 
307  BOOST_CHECK_CLOSE(float(user1Coocked), 2148.125, 0.0001);
308 
309  user1Coocked = -1;
310  user1Coocked.write();
311 
312  {
313  auto bufferLock = user1Dummy.getBufferLock();
314  BOOST_CHECK_EQUAL(int32_t(user1Dummy), 0xfff8);
315  }
316 
317  auto user1Raw = device.getScalarRegisterAccessor<int32_t>("MODULE0/WORD_USER1", 0, {AccessMode::raw});
318  user1Raw.read();
319 
320  BOOST_CHECK_EQUAL(int32_t(user1Raw), 0xfff8);
321  BOOST_CHECK_CLOSE(user1Raw.getAsCooked<float>(), -1, 0.0001);
322 
323  user1Raw.setAsCooked(-2.5);
324 
325  user1Raw.write();
326 
327  {
328  auto bufferLock = user1Dummy.getBufferLock();
329  BOOST_CHECK_EQUAL(int32_t(user1Dummy), 0xffec);
330  }
331 
332  // special case: int32 does not necessarily mean raw. There is also a cooked version:
333  auto user1CoockedInt = device.getScalarRegisterAccessor<int32_t>("MODULE0/WORD_USER1");
334  user1CoockedInt.read();
335 
336  BOOST_CHECK_EQUAL(int(user1CoockedInt), -3);
337 
338  user1CoockedInt = 16;
339  user1CoockedInt.write();
340 
341  {
342  auto bufferLock = user1Dummy.getBufferLock();
343  BOOST_CHECK_EQUAL(int32_t(user1Dummy), 0x80);
344  }
345 
346  // IEEE754 converter, raw and coocked accessors
347  // FLOAT_TEST.ARRAY is IEEE754. We use the 1 D version in constrast to FixedPoint where we use scalar (just because we
348  // can)
349  auto floatTestDummy = dummyBackend->getRawAccessor("FLOAT_TEST", "ARRAY");
350 
351  float testValue = 1.1;
352  void* warningAvoider = &testValue; // directly reinterpret-casting float gives compiler warnings
353  {
354  auto bufferLock = floatTestDummy.getBufferLock();
355  floatTestDummy[0] = *(reinterpret_cast<int32_t*>(warningAvoider));
356  testValue = 2.2;
357  floatTestDummy[1] = *(reinterpret_cast<int32_t*>(warningAvoider));
358  testValue = 3.3;
359  floatTestDummy[2] = *(reinterpret_cast<int32_t*>(warningAvoider));
360  testValue = 4.4;
361  floatTestDummy[3] = *(reinterpret_cast<int32_t*>(warningAvoider));
362  } // release buffer lock
363 
364  auto floatTestCoocked = device.getOneDRegisterAccessor<float>("FLOAT_TEST/ARRAY");
365  floatTestCoocked.read();
366 
367  BOOST_CHECK_CLOSE(floatTestCoocked[0], 1.1, 0.0001);
368  BOOST_CHECK_CLOSE(floatTestCoocked[1], 2.2, 0.0001);
369  BOOST_CHECK_CLOSE(floatTestCoocked[2], 3.3, 0.0001);
370  BOOST_CHECK_CLOSE(floatTestCoocked[3], 4.4, 0.0001);
371 
372  floatTestCoocked[3] = 44.4;
373  floatTestCoocked.write();
374 
375  {
376  auto bufferLock = floatTestDummy.getBufferLock();
377  *(reinterpret_cast<int32_t*>(warningAvoider)) = floatTestDummy[3];
378  }
379  BOOST_CHECK_CLOSE(testValue, 44.4, 0.0001);
380 
381  auto floatTestRaw = device.getOneDRegisterAccessor<int32_t>("FLOAT_TEST/ARRAY", 0, 0, {AccessMode::raw});
382  floatTestRaw.read();
383 
384  *(reinterpret_cast<int32_t*>(warningAvoider)) = floatTestRaw[2];
385 
386  BOOST_CHECK_CLOSE(testValue, 3.3, 0.0001);
387  BOOST_CHECK_CLOSE(floatTestRaw.getAsCooked<float>(0), 1.1, 0.0001);
388 
389  floatTestRaw.setAsCooked(0, -2.5);
390 
391  floatTestRaw.write();
392 
393  {
394  auto bufferLock = floatTestDummy.getBufferLock();
395  *(reinterpret_cast<int32_t*>(warningAvoider)) = floatTestDummy[0];
396  }
397  BOOST_CHECK_CLOSE(testValue, -2.5, 0.0001);
398 
399  // special case: int32 does not necessarily mean raw. There is also a cooked version:
400  auto floatTestCoockedInt = device.getOneDRegisterAccessor<int32_t>("FLOAT_TEST/ARRAY");
401  floatTestCoockedInt.read();
402 
403  BOOST_CHECK_EQUAL(floatTestCoockedInt[0], -3); // was -2.5
404  BOOST_CHECK_EQUAL(floatTestCoockedInt[1], 2); // was 2.2
405  BOOST_CHECK_EQUAL(floatTestCoockedInt[2], 3); // was 3.3
406  BOOST_CHECK_EQUAL(floatTestCoockedInt[3], 44); // was 44.4
407 
408  floatTestCoockedInt[1] = 16;
409  floatTestCoockedInt.write();
410 
411  {
412  auto bufferLock = floatTestDummy.getBufferLock();
413  *(reinterpret_cast<int32_t*>(warningAvoider)) = floatTestDummy[1];
414  }
415  BOOST_CHECK_CLOSE(testValue, 16.0, 0.001);
416 }
417 
418 /**********************************************************************************************************************/
419 
420 BOOST_AUTO_TEST_CASE(registerCatalogueCreation) {
421  Device d("(dummy?map=goodMapFile.map)");
422  auto catalogue = d.getRegisterCatalogue();
423  BOOST_CHECK_NO_THROW((void)catalogue.getRegister("MODULE0/WORD_USER1"));
424 
425  BOOST_CHECK(d.isOpened() == false);
426  BOOST_CHECK_NO_THROW(d.open());
427  BOOST_CHECK(d.isOpened() == true);
428 }
429 
430 /**********************************************************************************************************************/
431 
432 BOOST_AUTO_TEST_CASE(testMergeNumericRegisters) {
433  BackendFactory::getInstance().setDMapFilePath("dummies.dmap");
435 
436  device.open("DUMMYD3");
437 
438  // create register accessors of four registers with adjecent addresses
439  auto mux0 = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_0");
440  auto mux1 = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_1");
441  auto mux2 = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_2");
442  auto mux3 = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_3");
443 
444  // create the same register accessors again, so we have a second set not part
445  // of the transfer group
446  auto mux0b = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_0");
447  auto mux1b = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_1");
448  auto mux2b = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_2");
449  auto mux3b = device.getScalarRegisterAccessor<int>("/ADC/WORD_CLK_MUX_3");
450 
451  // obtain the private pointers to the implementation of the accessor
452  auto mux0i = boost::dynamic_pointer_cast<NDRegisterAccessor<int>>(mux0.getHighLevelImplElement());
453  auto mux1i = boost::dynamic_pointer_cast<NDRegisterAccessor<int>>(mux1.getHighLevelImplElement());
454  auto mux2i = boost::dynamic_pointer_cast<NDRegisterAccessor<int>>(mux2.getHighLevelImplElement());
455  auto mux3i = boost::dynamic_pointer_cast<NDRegisterAccessor<int>>(mux3.getHighLevelImplElement());
456 
457  // check that all underlying raw accessors are still different
458  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux1i->getHardwareAccessingElements()[0]);
459  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux2i->getHardwareAccessingElements()[0]);
460  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
461  BOOST_CHECK(mux1i->getHardwareAccessingElements()[0] != mux2i->getHardwareAccessingElements()[0]);
462  BOOST_CHECK(mux1i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
463  BOOST_CHECK(mux2i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
464 
465  // check that the underlying raw accessors have the right address range
466  NumericAddressedLowLevelTransferElement* llelem; // operator ->* does not work on a shared_ptr
467  llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux0i->getHardwareAccessingElements()[0])
468  .get();
471  llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux1i->getHardwareAccessingElements()[0])
472  .get();
475  llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux2i->getHardwareAccessingElements()[0])
476  .get();
479  llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux3i->getHardwareAccessingElements()[0])
480  .get();
483 
484  // add accessors to the transfer group. The accessors are intentionally added
485  // out of order to check if the behaviour is also correct in that case
486  TransferGroup group;
487  group.addAccessor(mux0);
488  group.addAccessor(mux2);
489  group.addAccessor(mux1);
490  group.addAccessor(mux3);
491 
492  // check that all underlying raw accessors are now all the same
493  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux1i->getHardwareAccessingElements()[0]);
494  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux2i->getHardwareAccessingElements()[0]);
495  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux3i->getHardwareAccessingElements()[0]);
496 
497  // check that the underlying raw accessor have the right address range
498  llelem = boost::static_pointer_cast<NumericAddressedLowLevelTransferElement>(mux0i->getHardwareAccessingElements()[0])
499  .get();
502 
503  // check that reading and writing works
504  mux0 = 42;
505  mux1 = 120;
506  mux2 = 84;
507  mux3 = 240;
508  group.write();
509 
510  mux0b.read();
511  BOOST_CHECK(mux0b == 42);
512  mux1b.read();
513  BOOST_CHECK(mux1b == 120);
514  mux2b.read();
515  BOOST_CHECK(mux2b == 84);
516  mux3b.read();
517  BOOST_CHECK(mux3b == 240);
518 
519  mux0b = 123;
520  mux0b.write();
521  group.read();
522  BOOST_CHECK(mux0 == 123);
523  BOOST_CHECK(mux1 == 120);
524  BOOST_CHECK(mux2 == 84);
525  BOOST_CHECK(mux3 == 240);
526 
527  mux1b = 234;
528  mux1b.write();
529  group.read();
530  BOOST_CHECK(mux0 == 123);
531  BOOST_CHECK(mux1 == 234);
532  BOOST_CHECK(mux2 == 84);
533  BOOST_CHECK(mux3 == 240);
534 
535  mux2b = 345;
536  mux2b.write();
537  group.read();
538  BOOST_CHECK(mux0 == 123);
539  BOOST_CHECK(mux1 == 234);
540  BOOST_CHECK(mux2 == 345);
541  BOOST_CHECK(mux3 == 240);
542 
543  mux3b = 456;
544  mux3b.write();
545  group.read();
546  BOOST_CHECK(mux0 == 123);
547  BOOST_CHECK(mux1 == 234);
548  BOOST_CHECK(mux2 == 345);
549  BOOST_CHECK(mux3 == 456);
550 }
551 
552 /**********************************************************************************************************************/
553 
554 BOOST_AUTO_TEST_CASE(testMergeNumericRegistersDifferentTypes) {
555  BackendFactory::getInstance().setDMapFilePath("dummies.dmap");
557 
558  device.open("DUMMYD3");
559 
560  // create register accessors of four registers with adjecent addresses
561  auto mux0 = device.getScalarRegisterAccessor<uint16_t>("/ADC/WORD_CLK_MUX_0");
562  auto mux1 = device.getScalarRegisterAccessor<uint16_t>("/ADC/WORD_CLK_MUX_1");
563  auto mux2 = device.getScalarRegisterAccessor<int32_t>("/ADC/WORD_CLK_MUX_2", 0, {AccessMode::raw});
564  auto mux3 = device.getScalarRegisterAccessor<int64_t>("/ADC/WORD_CLK_MUX_3");
565 
566  // create the same register accessors again, so we have a second set not part
567  // of the transfer group
568  auto mux0b = device.getScalarRegisterAccessor<uint16_t>("/ADC/WORD_CLK_MUX_0");
569  auto mux1b = device.getScalarRegisterAccessor<uint16_t>("/ADC/WORD_CLK_MUX_1");
570  auto mux2b = device.getScalarRegisterAccessor<int32_t>("/ADC/WORD_CLK_MUX_2", 0, {AccessMode::raw});
571  auto mux3b = device.getScalarRegisterAccessor<int64_t>("/ADC/WORD_CLK_MUX_3");
572 
573  // obtain the private pointers to the implementation of the accessor
574  auto mux0i = boost::dynamic_pointer_cast<NDRegisterAccessor<uint16_t>>(mux0.getHighLevelImplElement());
575  auto mux1i = boost::dynamic_pointer_cast<NDRegisterAccessor<uint16_t>>(mux1.getHighLevelImplElement());
576  auto mux2i = boost::dynamic_pointer_cast<NDRegisterAccessor<int32_t>>(mux2.getHighLevelImplElement());
577  auto mux3i = boost::dynamic_pointer_cast<NDRegisterAccessor<int64_t>>(mux3.getHighLevelImplElement());
578 
579  // check that all underlying raw accessors are still different
580  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux1i->getHardwareAccessingElements()[0]);
581  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux2i->getHardwareAccessingElements()[0]);
582  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
583  BOOST_CHECK(mux1i->getHardwareAccessingElements()[0] != mux2i->getHardwareAccessingElements()[0]);
584  BOOST_CHECK(mux1i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
585  BOOST_CHECK(mux2i->getHardwareAccessingElements()[0] != mux3i->getHardwareAccessingElements()[0]);
586 
587  // add accessors to the transfer group. The accessors are intentionally added
588  // out of order to check if the behaviour is also correct in that case
589  TransferGroup group;
590  group.addAccessor(mux2);
591  group.addAccessor(mux1);
592  group.addAccessor(mux3);
593  group.addAccessor(mux0);
594 
595  // check that all underlying raw accessors are now all the same
596  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux1i->getHardwareAccessingElements()[0]);
597  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux2i->getHardwareAccessingElements()[0]);
598  BOOST_CHECK(mux0i->getHardwareAccessingElements()[0] == mux3i->getHardwareAccessingElements()[0]);
599 
600  // also check that all high-level implementations are still the same as
601  // previously
602  BOOST_CHECK(mux0i == boost::dynamic_pointer_cast<NDRegisterAccessor<uint16_t>>(mux0.getHighLevelImplElement()));
603  BOOST_CHECK(mux1i == boost::dynamic_pointer_cast<NDRegisterAccessor<uint16_t>>(mux1.getHighLevelImplElement()));
604  BOOST_CHECK(mux2i == boost::dynamic_pointer_cast<NDRegisterAccessor<int32_t>>(mux2.getHighLevelImplElement()));
605  BOOST_CHECK(mux3i == boost::dynamic_pointer_cast<NDRegisterAccessor<int64_t>>(mux3.getHighLevelImplElement()));
606 
607  // check that reading and writing works
608  mux0 = 42;
609  mux1 = 120;
610  mux2 = 84;
611  mux3 = 240;
612  group.write();
613 
614  mux0b.read();
615  BOOST_CHECK(mux0b == 42);
616  mux1b.read();
617  BOOST_CHECK(mux1b == 120);
618  mux2b.read();
619  BOOST_CHECK(mux2b == 84);
620  mux3b.read();
621  BOOST_CHECK(mux3b == 240);
622 
623  mux0b = 123;
624  mux0b.write();
625  group.read();
626  BOOST_CHECK(mux0 == 123);
627  BOOST_CHECK(mux1 == 120);
628  BOOST_CHECK(mux2 == 84);
629  BOOST_CHECK(mux3 == 240);
630 
631  mux1b = 234;
632  mux1b.write();
633  group.read();
634  BOOST_CHECK(mux0 == 123);
635  BOOST_CHECK(mux1 == 234);
636  BOOST_CHECK(mux2 == 84);
637  BOOST_CHECK(mux3 == 240);
638 
639  mux2b = 345;
640  mux2b.write();
641  group.read();
642  BOOST_CHECK(mux0 == 123);
643  BOOST_CHECK(mux1 == 234);
644  BOOST_CHECK(mux2 == 345);
645  BOOST_CHECK(mux3 == 240);
646 
647  mux3b = 456;
648  mux3b.write();
649  group.read();
650  BOOST_CHECK(mux0 == 123);
651  BOOST_CHECK(mux1 == 234);
652  BOOST_CHECK(mux2 == 345);
653  BOOST_CHECK(mux3 == 456);
654 }
655 
656 /**********************************************************************************************************************/
657 
658 BOOST_AUTO_TEST_SUITE_END()
TransferGroup.h
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(testCreation)
Definition: testNumericAddressedBackendRegisterAccessor.cpp:43
device
ctk::Device device
Definition: testExceptionDummyDevice.cc:18
ChimeraTK::TransferGroup::write
void write(VersionNumber versionNumber={})
Trigger write transfer for all accessors in the group.
Definition: TransferGroup.cc:123
ChimeraTK::Device::getOneDRegisterAccessor
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:273
DummyBackend.h
ChimeraTK::TransferGroup::addAccessor
void addAccessor(TransferElementAbstractor &accessor)
Add a register accessor to the group.
Definition: TransferGroup.cc:305
NumericAddressedLowLevelTransferElement_startAddress
Definition: testNumericAddressedBackendRegisterAccessor.cpp:25
ChimeraTK::TransferGroup
Group multiple data accessors to efficiently trigger data transfers on the whole group.
Definition: TransferGroup.h:26
ChimeraTK::NumericAddressedLowLevelTransferElement::_startAddress
uint64_t _startAddress
start address w.r.t.
Definition: NumericAddressedLowLevelTransferElement.h:175
accessPrivateData.h
ChimeraTK::TransferGroup::read
void read()
Trigger read transfer for all accessors in the group.
Definition: TransferGroup.cc:44
accessPrivateData::stowed
Definition: accessPrivateData.h:23
ChimeraTK::NumericAddressedLowLevelTransferElement::_numberOfBytes
size_t _numberOfBytes
number of bytes to access
Definition: NumericAddressedLowLevelTransferElement.h:178
Device.h
ChimeraTK::Device::getRegisterCatalogue
RegisterCatalogue getRegisterCatalogue() const
Return the register catalogue with detailed information on all registers.
Definition: Device.cc:22
accessPrivateData::stow_private
Definition: accessPrivateData.h:34
ChimeraTK::Device
Class allows to read/write registers from device.
Definition: Device.h:39
ChimeraTK::NumericAddressedLowLevelTransferElement
Implementation of the NDRegisterAccessor for NumericAddressedBackends, responsible for the underlying...
Definition: NumericAddressedLowLevelTransferElement.h:30
ChimeraTK::Device::open
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Definition: Device.cc:58
NumericAddressedLowLevelTransferElement_numberOfBytes
Definition: testNumericAddressedBackendRegisterAccessor.cpp:31
DummyRegisterAccessor.h
ChimeraTK::Device::getScalarRegisterAccessor
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:263
BackendFactory.h
ChimeraTK::Device::isOpened
bool isOpened() const
Check if the device is currently opened.
Definition: Device.cc:73
NumericAddressedLowLevelTransferElement_numberOfBytes::type
size_t NumericAddressedLowLevelTransferElement::* type
Definition: testNumericAddressedBackendRegisterAccessor.cpp:32
TEST_DMAP_FILE_PATH
#define TEST_DMAP_FILE_PATH
Definition: BackendFactory.h:18
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::NDRegisterAccessor
N-dimensional register accessor.
Definition: ForwardDeclarations.h:17
NumericAddressedLowLevelTransferElement_startAddress::type
uint64_t NumericAddressedLowLevelTransferElement::* type
Definition: testNumericAddressedBackendRegisterAccessor.cpp:26
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51