ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
testLMapBackendUnified.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 BOOST_TEST_MODULE LMapBackendUnifiedTest
6#include <boost/test/unit_test.hpp>
7using namespace boost::unit_test_framework;
8
9#include "Device.h"
13#include "TransferGroup.h"
14#include "UnifiedBackendTest.h"
15
16using namespace ChimeraTK;
17
18BOOST_AUTO_TEST_SUITE(LMapBackendUnifiedTestSuite)
19
20/**********************************************************************************************************************/
21
22static boost::shared_ptr<ExceptionDummy> exceptionDummyLikeMtcadummy, exceptionDummyMuxed, exceptionDummyPush;
23static boost::shared_ptr<LogicalNameMappingBackend> lmapBackend;
24
25/**********************************************************************************************************************/
26/* First a number of base descriptors is defined to simplify the descriptors for the individual registers. */
27
29template<typename Derived>
31 Derived* derived{static_cast<Derived*>(this)};
32
33 static constexpr auto capabilities = TestCapabilities<>()
35 .disableAsyncReadInconsistency()
36 .disableSwitchReadOnly()
37 .disableSwitchWriteOnly()
38 .disableTestWriteNeverLosesData()
39 .enableTestRawTransfer();
40 // Note: I set enableTestRawTransfer to enabled here and disable it where necessary, so new registers will be tested
41 // by default.
42
43 bool isWriteable() { return true; }
44 bool isReadable() { return true; }
45 bool isPush() { return false; }
51 size_t writeQueueLength() { return std::numeric_limits<size_t>::max(); }
52 size_t nRuntimeErrorCases() { return 1; }
53
54 void setForceRuntimeError(bool enable, size_t) {
55 auto& dummy = dynamic_cast<ExceptionDummy&>(derived->acc.getBackend());
56 dummy.throwExceptionRead = enable;
57 dummy.throwExceptionWrite = enable;
58 dummy.throwExceptionOpen = enable;
59 if(derived->isPush() && enable) {
60 dummy.triggerInterrupt(6);
61 }
62 }
63};
64
66template<typename Derived>
69 static constexpr auto capabilities = RegisterDescriptorBase<Derived>::capabilities.disableTestRawTransfer();
70
71 size_t nChannels() { return 1; }
72 bool isWriteable() { return false; }
73
74 template<typename UserType>
75 std::vector<std::vector<UserType>> generateValue() {
76 std::vector<UserType> v;
77 for(size_t k = 0; k < derived->nElementsPerChannel(); ++k) {
78 v.push_back(derived->acc[derived->channel][k] + derived->increment * (k + 1));
79 }
80 return {v};
81 }
82
83 template<typename UserType>
84 std::vector<std::vector<UserType>> getRemoteValue() {
85 std::vector<UserType> v;
86 for(size_t k = 0; k < derived->nElementsPerChannel(); ++k) {
87 v.push_back(derived->acc[derived->channel][k]);
88 }
89 return {v};
90 }
91
93 auto v = generateValue<typename Derived::minimumUserType>()[0];
94 for(size_t k = 0; k < derived->nElementsPerChannel(); ++k) {
95 derived->acc[derived->channel][k] = v[k];
96 }
97 if(derived->isPush()) {
98 // At the moment only interrupt 6 is used, so we hard code it here. Can be made more flexible if needed.
99 dynamic_cast<DummyBackend&>(derived->acc.getBackend()).triggerInterrupt(6);
100 }
101 }
102};
103
105template<typename Derived>
107 using RegisterDescriptorBase<Derived>::derived;
108
109 size_t nChannels() { return 1; }
110
111 size_t myOffset() { return 0; }
112
113 // T is always minimumUserType, but C++ doesn't allow to use Derived::minimumUserType here (circular dependency)
114 template<typename T, typename Traw>
115 T convertRawToCooked(Traw value) {
116 return static_cast<T>(value);
117 }
118
119 template<typename UserType>
120 void generateValueHook(std::vector<UserType>&) {} // override in derived if needed
121
122 // type can be user type or raw type
123 template<typename Type>
124 std::vector<std::vector<Type>> generateValue(bool getRaw = false) {
125 std::vector<Type> v;
126 typedef typename Derived::rawUserType Traw;
127 typedef typename Derived::minimumUserType T;
128 auto cv = derived->template getRemoteValue<Traw>(true)[0];
129 for(size_t i = 0; i < derived->nElementsPerChannel(); ++i) {
130 Traw e = cv[i] + derived->increment * (static_cast<Traw>(i) + 1);
131 if(!getRaw) {
132 v.push_back(derived->template convertRawToCooked<T, Traw>(e));
133 }
134 else {
135 v.push_back(static_cast<T>(e));
136 }
137 }
138 derived->generateValueHook(v);
139 return {v};
140 }
141
142 template<typename UserType>
143 std::vector<std::vector<UserType>> getRemoteValue(bool getRaw = false) {
144 typedef typename Derived::rawUserType Traw;
145
146 std::vector<UserType> cookedValues(derived->nElementsPerChannel());
147 std::vector<Traw> rawValues(derived->nElementsPerChannel());
148
149 // Keep the scope of the dummy buffer lock as limited as possible (see #12332).
150 // The rawToCooked conversion will acquire a lock via the math pluging decorator,
151 // which will cause lock order inversion if you hold the dummy buffer lock at that point.
152 {
153 auto bufferLock = derived->acc.getBufferLock();
154
155 for(size_t i = 0; i < derived->nElementsPerChannel(); ++i) {
156 rawValues[i] = derived->acc[i + derived->myOffset()];
157 }
158 } // end of bufferLock scope
159
160 for(size_t i = 0; i < derived->nElementsPerChannel(); ++i) {
161 if(!getRaw) {
162 cookedValues[i] = derived->template convertRawToCooked<UserType, Traw>(rawValues[i]);
163 }
164 else {
165 cookedValues[i] = static_cast<UserType>(rawValues[i]); // you can only use raw if user type and raw type are
166 // the same, so the static cast is a no-op
167 }
168 }
169 return {cookedValues};
170 }
171
173 auto v = generateValue<typename Derived::rawUserType>(true)[0];
174 { // scope for the buffer lock
175 auto bufferLock = derived->acc.getBufferLock();
176 for(size_t i = 0; i < derived->nElementsPerChannel(); ++i) {
177 derived->acc[i + derived->myOffset()] = v[i];
178 }
179 } // release the buffer lock before triggering another thread
180 if(derived->isPush()) {
181 dynamic_cast<ExceptionDummy&>(derived->acc.getBackend()).triggerInterrupt(6);
182 }
183 }
184};
185
187template<typename Derived>
191
193template<typename Derived>
195 using RegisterDescriptorBase<Derived>::derived;
196 static constexpr auto capabilities =
197 RegisterDescriptorBase<Derived>::capabilities.disableTestRawTransfer().disableSetRemoteValueIncrementsVersion();
198
199 size_t nChannels() { return 1; }
200 bool isWriteable() { return false; }
202
203 size_t nRuntimeErrorCases() { return 0; }
204
205 template<typename UserType>
206 std::vector<std::vector<UserType>> generateValue() {
207 return this->getRemoteValue<UserType>();
208 }
209
210 template<typename UserType>
211 std::vector<std::vector<UserType>> getRemoteValue() {
212 std::vector<UserType> v;
213 for(size_t k = 0; k < derived->nElementsPerChannel(); ++k) {
214 v.push_back(derived->value[k]);
215 }
216 return {v};
217 }
218
220
221 void setForceRuntimeError(bool, size_t) { assert(false); }
222};
223
225template<typename Derived>
227 using RegisterDescriptorBase<Derived>::derived;
228 static constexpr auto capabilities = RegisterDescriptorBase<Derived>::capabilities.disableTestRawTransfer();
229
230 size_t nChannels() { return 1; }
232
233 size_t nRuntimeErrorCases() { return 0; }
234
235 template<typename UserType>
236 std::vector<std::vector<UserType>> getRemoteValue(bool = false) {
237 // For Variables we don't have a backdoor. We have to use the normal read and write
238 // functions which are good enough. It seems like a self consistency test, but all
239 // functionality the variable has to provide is that I can write something, and
240 // read it back, which is tested with it.
241
242 // We might have to open/recover the backend to perform the operation. We have to remember
243 // that we did so and close/set-exception it again it we did. Some tests require the backend to be closed.
244 bool backendWasOpened = lmapBackend->isOpen();
245 bool backendWasFunctional = lmapBackend->isFunctional();
246 if(!backendWasOpened || !backendWasFunctional) {
247 lmapBackend->open();
248 }
249 auto acc = lmapBackend->getRegisterAccessor<typename Derived::minimumUserType>(derived->path(), 0, 0, {});
250 acc->read();
251 if(!backendWasOpened) {
252 lmapBackend->close();
253 }
254 else if(!backendWasFunctional) {
255 lmapBackend->setException("Some message");
256 }
257 std::vector<UserType> v;
258 for(size_t k = 0; k < derived->nElementsPerChannel(); ++k) {
259 v.push_back(acc->accessData(k));
260 }
261 return {v};
262 }
263
265 auto acc = lmapBackend->getRegisterAccessor<typename Derived::minimumUserType>(derived->path(), 0, 0, {});
266 auto v = derived->template generateValue<typename Derived::minimumUserType>()[0];
267 for(size_t k = 0; k < derived->nElementsPerChannel(); ++k) {
268 acc->accessData(k) = v[k];
269 }
270 bool backendWasOpened = lmapBackend->isOpen();
271 if(!backendWasOpened) {
272 lmapBackend->open();
273 }
274 try {
275 acc->write();
276 }
277 catch(...) {
278 // ignore any exceptions: if the device is in an exception state, this write must not take place but the exception
279 // must not get through.
280 }
281 if(!backendWasOpened) {
282 lmapBackend->close();
283 }
284 }
285
286 void setForceRuntimeError(bool, size_t) { assert(false); }
287};
288
289// Base descriptor for bit accessors
290template<typename Derived>
292 using RegisterDescriptorBase<Derived>::derived;
293 static constexpr auto capabilities = RegisterDescriptorBase<Derived>::capabilities.disableTestRawTransfer();
294
295 size_t nChannels() { return 1; }
296 size_t nElementsPerChannel() { return 1; }
297
299 typedef int32_t rawUserType;
300
302
303 size_t nRuntimeErrorCases() { return derived->target.nRuntimeErrorCases(); }
304
305 template<typename UserType>
306 std::vector<std::vector<UserType>> generateValue() {
307 return {{!this->template getRemoteValue<uint64_t>()[0][0]}};
308 }
309
310 template<typename UserType>
311 std::vector<std::vector<UserType>> getRemoteValue() {
312 uint64_t v = derived->target.template getRemoteValue<uint64_t>()[0][0];
313 uint64_t mask = 1 << derived->bit;
314 bool result = v & mask;
315 return {{result}};
316 }
317
319 derived->target.setRemoteValue();
320 if(derived->isPush()) {
321 // At the moment only interrupt 6 is used, so we hard code it here. Can be made more flexible if needed.
322 exceptionDummyPush->triggerInterrupt(6);
323 }
324 }
325
326 void setForceRuntimeError(bool enable, size_t caseIndex) { derived->target.setForceRuntimeError(enable, caseIndex); }
327};
328
329/**********************************************************************************************************************/
330/* Now for each register in unifiedTest.xlmap we define a descriptor */
331
334 std::string path() { return "/SingleWord"; }
335
336 const uint32_t increment = 3;
337
338 typedef uint32_t minimumUserType;
339 typedef int32_t rawUserType;
340 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/BOARD.WORD_FIRMWARE"};
341};
342
346 std::string path() { return "/SingleWord"; }
347
348 const uint32_t increment = 3;
349
350 typedef uint32_t minimumUserType;
351 typedef int32_t rawUserType;
352 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyPush.get(), "", "/BOARD.WORD_FIRMWARE"};
353};
354
357 std::string path() { return "/SingleWord_push"; }
358 bool isPush() { return true; }
359 bool isWriteable() {
360 std::cout << "Warning: Writing test for /SingleWord_push has been disabled due to missing support in the dummy."
361 << std::endl;
362 return false;
363 }
364
365 const uint32_t increment = 3;
366
367 typedef uint32_t minimumUserType;
368 typedef int32_t rawUserType;
369 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyPush.get(), "", "/BOARD.WORD_FIRMWARE"};
370};
371
374 std::string path() { return "/FullArea"; }
375
376 const int32_t increment = 7;
377 size_t nElementsPerChannel() { return 0x400; }
378
379 typedef int32_t minimumUserType;
380 typedef int32_t rawUserType;
381 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/ADC.AREA_DMAABLE"};
382};
383
386 std::string path() { return "/PartOfArea"; }
387
388 const int32_t increment = 11;
389 size_t nElementsPerChannel() { return 20; }
390 size_t myOffset() { return 10; }
391
392 typedef int32_t minimumUserType;
393 typedef int32_t rawUserType;
394 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/ADC.AREA_DMAABLE"};
395};
396
399 std::string path() { return "/Channel3"; }
400
401 const int32_t increment = 17;
402 size_t nElementsPerChannel() { return 4; }
403 const size_t channel{3};
404
405 typedef int32_t minimumUserType;
406 typedef int32_t rawUserType;
407
408 // Multiplexed 2d accessors don't have access mode raw
410 DummyMultiplexedRegisterAccessor<minimumUserType> acc{exceptionDummyMuxed.get(), "TEST", "NODMA"};
411};
412
415 std::string path() { return "/Channel4_push"; }
416 bool isPush() { return true; }
417
418 const int32_t increment = 23;
419 size_t nElementsPerChannel() { return 4; }
420 const size_t channel{4};
421
422 typedef int32_t minimumUserType;
423 typedef int32_t rawUserType;
424
425 // Multiplexed 2d accessors don't have access mode raw
427 DummyMultiplexedRegisterAccessor<minimumUserType> acc{exceptionDummyMuxed.get(), "TEST", "NODMA"};
428};
429
432 std::string path() { return "/LastChannelInRegister"; }
433
434 const int32_t increment = 27;
435 size_t nElementsPerChannel() { return 4; }
436 const size_t channel{15};
437
438 typedef int32_t minimumUserType;
439 typedef int32_t rawUserType;
440
441 // Multiplexed 2d accessors don't have access mode raw
443 DummyMultiplexedRegisterAccessor<minimumUserType> acc{exceptionDummyMuxed.get(), "TEST", "NODMA"};
444};
445
448 std::string path() { return "/Constant"; }
449
450 size_t nElementsPerChannel() { return 1; }
451 const std::vector<int32_t> value{42};
452
453 typedef int32_t minimumUserType;
454 typedef int32_t rawUserType;
455};
456
459 std::string path() { return "/Constant2"; }
460
461 size_t nElementsPerChannel() { return 1; }
462 const std::vector<int32_t> value{666};
463
464 typedef int32_t minimumUserType;
465 typedef int32_t rawUserType;
466};
467
470 std::string path() { return "/MyModule/SomeSubmodule/Variable"; }
471
472 const int increment = 43;
473 size_t nElementsPerChannel() { return 1; }
474
475 typedef float minimumUserType;
476 typedef int32_t rawUserType;
477};
478
481 std::string path() { return "/ArrayConstant"; }
482
483 const std::vector<int32_t> value{1111, 2222, 3333, 4444, 5555};
484 size_t nElementsPerChannel() { return 5; }
485
486 typedef float minimumUserType;
487 typedef int32_t rawUserType;
488};
489
492 std::string path() { return "/ArrayVariable"; }
493
494 const int increment = 121;
495 size_t nElementsPerChannel() { return 6; }
496
497 typedef float minimumUserType;
498 typedef int32_t rawUserType;
499};
500
503 std::string path() { return "/Bit0ofVar"; }
504
506 size_t bit = 0;
507};
508
511 std::string path() { return "/Bit3ofVar"; }
512
514 size_t bit = 3;
515};
516
518struct RegBit2OfWordFirmware : BitRegisterDescriptorBase<RegBit2OfWordFirmware> {
519 std::string path() { return "/Bit2ofWordFirmwareA"; }
520
522 size_t bit = 2;
523};
524
526struct RegBit2OfWordFirmwareB : BitRegisterDescriptorBase<RegBit2OfWordFirmwareB> {
527 std::string path() { return "/Bit2ofWordFirmwareB"; }
528
530 size_t bit = 2;
531 // in order to make our test sensitive to incorrect (bit accessor->device) associations, we need an instance
532 // of a bit accessor to device A, same register path, as a fixture
533 boost::shared_ptr<NDRegisterAccessor<minimumUserType>> fixAccessorOnA{
534 lmapBackend->getRegisterAccessor<minimumUserType>("/Bit2ofWordFirmwareA", 1, 0, AccessModeFlags{})};
535};
536
538struct RegBit2OfWordFirmware_push : BitRegisterDescriptorBase<RegBit2OfWordFirmware_push> {
539 std::string path() { return "/Bit2ofWordFirmware_push"; }
540 bool isPush() { return true; }
541 bool isWriteable() {
542 std::cout
543 << "Warning: Writing test for /Bit2ofWordFirmware_push has been disabled due to missing support in the dummy."
544 << std::endl;
545 return false;
546 }
547
549 size_t bit = 2;
550};
551
553template<typename Derived>
555 std::string path() { return "/SingleWord_Scaled"; }
556
557 const double increment = std::exp(1.);
558
559 typedef double minimumUserType;
560 typedef uint32_t rawUserType;
561 // Mutliply plugin does not support access mode raw
562 static constexpr auto capabilities = ScalarRegisterDescriptorBase<Derived>::capabilities.disableTestRawTransfer();
564 DummyRegisterAccessor<rawUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/BOARD.WORD_FIRMWARE"};
565};
566
567struct RegSingleWordScaled_R : RegSingleWordScaled<RegSingleWordScaled_R> {
568 bool isWriteable() { return false; }
569 // turn off the catalogue check. It reports that the register is writeable, which is correct. Writing is just turned
570 // off for the test.
571 static constexpr auto capabilities = RegSingleWordScaled<RegSingleWordScaled_R>::capabilities.disableTestCatalogue();
572
573 template<typename T, typename Traw>
574 T convertRawToCooked(Traw value) {
575 return value * 4.2;
576 }
577};
578
579struct RegSingleWordScaled_W : RegSingleWordScaled<RegSingleWordScaled_W> {
580 bool isReadable() { return false; }
581 // turn off the catalogue check. It reports that the register is readable, which is correct. Reading is just turned
582 // off for the test.
583 static constexpr auto capabilities = RegSingleWordScaled<RegSingleWordScaled_W>::capabilities.disableTestCatalogue();
584
585 // the scale plugin applies the same factor in both directions, so we have to inverse it for write tests
586 template<typename T, typename Traw>
587 T convertRawToCooked(Traw value) {
588 return value / 4.2;
589 }
590};
591
592struct RegSingleWordScaled_RW : RegSingleWordScaled<RegSingleWordScaled_RW> {
593 std::string path() { return "/SingleWord_NotScaled"; }
594
595 // The scale plugin applies the same factor in both directions, so it has to be 1 to make the test pass
596 // for both reading and writing.
597 template<typename T, typename Traw>
598 T convertRawToCooked(Traw value) {
599 return value;
600 }
601};
602
604struct RegSingleWordScaledTwice_push : ScalarRegisterDescriptorBase<RegSingleWordScaledTwice_push> {
605 std::string path() { return "/SingleWord_Scaled_Twice_push"; }
606 bool isWriteable() { return false; }
607 bool isPush() { return true; }
608
609 const double increment = std::exp(3.);
610
611 template<typename T, typename Traw>
612 T convertRawToCooked(Traw value) {
613 return 6 * value;
614 }
615
616 typedef double minimumUserType;
618 // Mutliply plugin does not support access mode raw
619 static constexpr auto capabilities =
621 ChimeraTK::AccessModeFlags supportedFlags() { return {AccessMode::wait_for_new_data}; }
622 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyPush.get(), "", "/BOARD.WORD_FIRMWARE"};
623};
624
627 std::string path() { return "/FullArea_Scaled"; }
628 bool isWriteable() { return false; }
629 // Mutliply plugin does not support access mode raw
630 // turn off the catalogue check. It reports that the register is readable, which is correct. Reading is just turned
631 // off for the test.
632 static constexpr auto capabilities =
633 OneDRegisterDescriptorBase<RegFullAreaScaled>::capabilities.disableTestRawTransfer().disableTestCatalogue();
634
635 const double increment = std::exp(4.);
636 size_t nElementsPerChannel() { return 0x400; }
637
638 template<typename T, typename Traw>
639 T convertRawToCooked(Traw value) {
640 return 0.5 * value;
641 }
642
643 typedef double minimumUserType;
644 typedef int32_t rawUserType;
645 // Mutliply plugin does not support access mode raw. Capabilities already turned off above.
647 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/ADC.AREA_DMAABLE"};
648};
649
651struct RegWordFirmwareForcedReadOnly : ScalarRegisterDescriptorBase<RegWordFirmwareForcedReadOnly> {
652 std::string path() { return "/WordFirmwareForcedReadOnly"; }
653
654 const uint32_t increment = -47;
655 bool isWriteable() { return false; }
656
657 typedef uint32_t minimumUserType;
658 typedef int32_t rawUserType;
659 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/BOARD.WORD_FIRMWARE"};
660};
661
663struct RegWordFirmwareForcedReadOnly_push : ScalarRegisterDescriptorBase<RegWordFirmwareForcedReadOnly_push> {
664 std::string path() { return "/WordFirmwareForcedReadOnly_push"; }
665 bool isPush() { return true; }
666
667 const uint32_t increment = -47;
668 bool isWriteable() { return false; }
669
670 typedef uint32_t minimumUserType;
671 typedef int32_t rawUserType;
672 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyPush.get(), "", "/BOARD.WORD_FIRMWARE"};
673};
674
676template<typename Derived>
678 const double increment = 7;
679
680 typedef double minimumUserType;
681 typedef uint32_t rawUserType;
682 // Math plugin does not support access mode raw
683 static constexpr auto capabilities = ScalarRegisterDescriptorBase<Derived>::capabilities.disableTestRawTransfer();
685 DummyRegisterAccessor<rawUserType> acc{exceptionDummyPush.get(), "", "/BOARD.WORD_FIRMWARE"};
686};
687
688struct RegWordFirmwareWithMath_R : RegWordFirmwareWithMath<RegWordFirmwareWithMath_R> {
689 std::string path() { return "/WordFirmwareWithMath_r"; }
690 bool isWriteable() { return false; }
691
692 template<typename T, typename Traw>
693 T convertRawToCooked(Traw value) {
694 return value + 2.345;
695 }
696};
697
698struct RegWordFirmwareWithMath_R_push : RegWordFirmwareWithMath<RegWordFirmwareWithMath_R_push> {
699 bool isWriteable() { return false; }
700 bool isPush() { return true; }
701 std::string path() { return "/WordFirmwareWithMath_push"; }
702
703 template<typename T, typename Traw>
704 T convertRawToCooked(Traw value) {
705 return value + 2.345;
706 }
707 // Math plugin does not support access mode raw
708 ChimeraTK::AccessModeFlags supportedFlags() { return {AccessMode::wait_for_new_data}; }
709};
710
711struct RegWordFirmwareWithMath_W : RegWordFirmwareWithMath<RegWordFirmwareWithMath_W> {
712 std::string path() { return "/WordFirmwareWithMath_w"; }
713 bool isReadable() { return false; }
714
715 // the math plugin applies the same formula in both directions, so we have to reverse the formula for write tests
716 template<typename T, typename Traw>
717 T convertRawToCooked(Traw value) {
718 return value - 2.345;
719 }
720};
721
723struct RegWordFirmwareAsParameterInMath : ScalarRegisterDescriptorBase<RegWordFirmwareAsParameterInMath> {
724 std::string path() { return "/WordFirmwareAsParameterInMath"; }
725
726 // no write test, since we cannot write into a parameter...
727 bool isWriteable() { return false; }
728
729 const double increment = 91;
730
731 template<typename T, typename Traw>
732 T convertRawToCooked(Traw value) {
733 return value - 42;
734 }
735
736 typedef double minimumUserType;
738 // Math plugin does not support access mode raw
739 static constexpr auto capabilities =
742 DummyRegisterAccessor<rawUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/BOARD.WORD_FIRMWARE"};
743};
744
749static double RegVariableAsPushParameterInMathBase_lastX;
750
751/* We use a has-a-pattern mixin-like pattern to break the "diamond of death".
752 * - There is a convertRawToCooked() per variable (var1, var2, x)
753 * - There is a base implementation and a "not written" implementation of generateValue() and getRemoteValue()
754 * All combinations of them have to be tested, and each of them has a unique generateValueHook().
755 * If we try multiple inveritance this ends up in a diamond of death.
756 *
757 * Solution: The convertRawToCooked() is not done by inheritance but coming from a RawToCookedProvider, which is a
758 * template parameter. Like this RegVariableAsPushParameterInMathBase and RegVariableAsPushParameterInMath_not_written
759 * can be used with all conversion functions and there is no code duplication.
760 */
761template<typename Derived, typename RawToCookedProvider>
763 // Test only write direction, as we are writing to the variable parameter in this test
764 // Also turn off the catalogue test which would fail because the register actually is readable.
765 static constexpr auto capabilities = ScalarRegisterDescriptorBase<Derived>::capabilities.enableTestWriteOnly()
766 .disableTestRawTransfer()
767 .disableTestCatalogue();
768
769 // no runtime error test cases, as writes happen to the variable only!
770 size_t nRuntimeErrorCases() { return 0; }
771 void setForceRuntimeError(bool, size_t) { assert(false); }
772
773 // the test "sees" the variable which supports wait_for_new_data
775
776 template<typename T, typename Traw>
777 T convertRawToCooked(Traw value) {
778 return RawToCookedProvider::convertRawToCooked_impl(value, lmapBackend);
779 }
780
781 typedef double minimumUserType;
782 typedef minimumUserType rawUserType; // for this context raw means before the math conversion
783 DummyRegisterAccessor<rawUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/BOARD.WORD_STATUS"};
784};
785
786// template type UserType and RawType have to be double for the math plugin, so we make that explicit in this helper
787// function
789 static double convertRawToCooked_impl(double value, boost::shared_ptr<LogicalNameMappingBackend>& lmapBackend) {
790 auto variable2 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest2", 0, 0, {});
791 variable2->read();
792 return (value - variable2->accessData(0) * 121 - RegVariableAsPushParameterInMathBase_lastX) / 120;
793 }
794};
795
797: RegVariableAsPushParameterInMathBase<RegVariableAsPushParameterInMath_var1, RawToCookedProvider_Var1> {
798 std::string path() { return "/VariableForMathTest1"; }
799
800 const double increment = 17;
801
802 template<typename UserType>
803 void generateValueHook(std::vector<UserType>&) {
804 // this is a bit a hack: we know that the test has to generate a value before writing, so we can activate
805 // async read here which is required for the test to be successful. The assumption is that generateValue is not
806 // called before the device is open... FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
807 lmapBackend->activateAsyncRead();
808
809 // In addition we have to write the accessor which has the math plugin and the second parameter.
810 // Otherwise writing of the parameters will have no effect.
811 auto x = lmapBackend->getRegisterAccessor<double>("/RegisterWithVariableAsPushParameterInMath", 0, 0, {});
812 x->accessData(0) = RegVariableAsPushParameterInMathBase_lastX;
813 x->write();
814 auto p2 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest2", 0, 0, {});
815 p2->read();
816 p2->write();
817 }
818};
819
820template<typename Derived, typename RawToCookedProvider>
822: RegVariableAsPushParameterInMathBase<Derived, RawToCookedProvider> {
823 template<typename UserType>
824 std::vector<std::vector<UserType>> generateValue(bool /*getRaw */ = false) {
825 // raw has been set to true, so we get the value as it is on the device
826 registerValueBeforeWrite = getRemoteValue<double>(true)[0][0]; // remember for comparison later
827
828 auto generatedValue =
830 lastGeneratedValue = generatedValue[0][0]; // remember for comparison later
831 return generatedValue;
832 }
833
834 template<typename UserType>
835 std::vector<std::vector<UserType>> getRemoteValue(bool getRaw = false) {
836 // We have to trick the unified test into passing. It expects to see the data it has written.
837 // However, the test here is that the data actually has not been written.
838 // So we do the real test here, and return what we gave out in generateValue, so the unified test can succeed.
839
840 auto remoteRawValue =
842
843 // Hack:
844 // getRemoteValue is used by the generateValue implementation in raw mode to access the device. We still need that.
845 // As the register with math pluin does not have a raw value, the unified test will always see the tricked version
846 // with the data it expects.
847 if(getRaw) {
848 return remoteRawValue;
849 }
850
851 auto convertedValue = this->derived->template convertRawToCooked<double, double>(registerValueBeforeWrite);
852 assert(convertedValue != lastGeneratedValue); // test that the unified test does not accidentally pass because
853 // something in generateValue went wrong.
854 if(remoteRawValue[0][0] == registerValueBeforeWrite) {
855 // test successful. Return what is expected
856 return {{lastGeneratedValue}};
857 }
858 else {
859 // print limiter because this function is called many times in a timeout loop due to the multi-threading
860 if((lastReportedRemoteValue != remoteRawValue[0][0]) ||
862 std::cout << "FAILED TEST: Register content altered when it should not have been. (" << remoteRawValue[0][0]
863 << " != " << registerValueBeforeWrite << ")" << std::endl;
864 lastReportedRemoteValue = remoteRawValue[0][0];
866 }
867 return {{convertedValue}};
868 }
869 }
870
873 double lastReportedRemoteValue{0}; // for the print limiter
874 double lastReportedValueBeforeWrite{0}; // for the print limiter
875};
876
878: RegVariableAsPushParameterInMath_not_written<RegVariableAsPushParameterInMath_var1_not_written1,
879 RawToCookedProvider_Var1> {
880 std::string path() { return "/VariableForMathTest1"; }
881
882 const double increment = 18;
883
884 template<typename UserType>
885 void generateValueHook(std::vector<UserType>&) {
886 // this is a bit a hack: we know that the test has to generate a value before writing, so we can activate
887 // async read here which is required for the test to be successful. The assumption is that generateValue is not
888 // called before the device is open... FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
889 lmapBackend->close();
890 lmapBackend->open(); // this test is explicitly for writing after open
891 lmapBackend->activateAsyncRead();
892 // Only write the accessor, not the second parameter.
893 auto x = lmapBackend->getRegisterAccessor<double>("/RegisterWithVariableAsPushParameterInMath", 0, 0, {});
894 x->accessData(0) = RegVariableAsPushParameterInMathBase_lastX;
895 x->write();
896 }
897};
898
900: RegVariableAsPushParameterInMath_not_written<RegVariableAsPushParameterInMath_var1_not_written2,
901 RawToCookedProvider_Var1> {
902 std::string path() { return "/VariableForMathTest1"; }
903
904 const double increment = 19;
905
906 template<typename UserType>
907 void generateValueHook(std::vector<UserType>&) {
908 // this is a bit a hack: we know that the test has to generate a value before writing, so we can activate
909 // async read here which is required for the test to be successful. The assumption is that generateValue is not
910 // called before the device is open... FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
911 lmapBackend->close();
912 lmapBackend->open(); // this test is explicitly for writing after open
913 lmapBackend->activateAsyncRead();
914 // Only write the second parameter, not the accessor.
915 auto p2 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest2", 0, 0, {});
916 p2->read();
917 p2->write();
918 }
919};
920
922 static double convertRawToCooked_impl(double value, boost::shared_ptr<LogicalNameMappingBackend>& lmapBackend) {
923 auto variable1 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest1", 0, 0, {});
924 variable1->read();
925 return (value - variable1->accessData(0) * 120 - RegVariableAsPushParameterInMathBase_lastX) / 121;
926 }
927};
928
930: RegVariableAsPushParameterInMathBase<RegVariableAsPushParameterInMath_var2, RawToCookedProvider_Var2> {
931 std::string path() { return "/VariableForMathTest2"; }
932
933 const double increment = 23;
934
935 template<typename UserType>
936 void generateValueHook(std::vector<UserType>&) {
937 // this is a bit a hack: we know that the test has to generate a value before writing, so we can activate
938 // async read here which is required for the test to be successful. The assumption is that generateValue is not
939 // called before the device is open... FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
940 lmapBackend->activateAsyncRead();
941
942 // In addition we have to write the accessor which has the math plugin and the first parameter.
943 // Otherwise writing of the parameters will have no effect.
944 auto x = lmapBackend->getRegisterAccessor<double>("/RegisterWithVariableAsPushParameterInMath", 0, 0, {});
945 x->accessData(0) = RegVariableAsPushParameterInMathBase_lastX;
946 x->write();
947 auto p1 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest1", 0, 0, {});
948 p1->read();
949 p1->write();
950 }
951};
952
954 static double convertRawToCooked_impl(double value, boost::shared_ptr<LogicalNameMappingBackend>& lmapBackend) {
955 auto variable1 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest1", 0, 0, {});
956 variable1->read();
957 auto variable2 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest2", 0, 0, {});
958 variable2->read();
959 return value - variable1->accessData(0) * 120 - variable2->accessData(0) * 121;
960 }
961};
962
963// This is the actual register that is "decoreated" with the math plugin (the x in the formula)
965: RegVariableAsPushParameterInMathBase<RegVariableAsPushParameterInMath_x, RawToCookedProvider_x> {
966 std::string path() { return "/RegisterWithVariableAsPushParameterInMath"; }
967
968 const double increment = 42;
969
970 template<typename UserType>
971 void generateValueHook(std::vector<UserType>& v) {
972 // Note: This in particular is a hack, since we have no guarantee that this gets actually written!
973 // FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
974 RegVariableAsPushParameterInMathBase_lastX = v[0];
975 // this is a bit a hack: we know that the test has to generate a value before writing, so we can activate
976 // async read here which is required for the test to be successful. The assumption is that generateValue is not
977 // called before the device is open... FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
978 lmapBackend->activateAsyncRead();
979
980 // In addition we have to write the two parameters. Otherwise writing must have no effect.
981 auto p1 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest1", 0, 0, {});
982 p1->read();
983 p1->write();
984 auto p2 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest2", 0, 0, {});
985 p2->read();
986 p2->write();
987 }
988};
989
991: RegVariableAsPushParameterInMath_not_written<RegVariableAsPushParameterInMath_x_not_written1, RawToCookedProvider_x> {
992 std::string path() { return "/RegisterWithVariableAsPushParameterInMath"; }
993
994 const double increment = 43;
995
996 template<typename UserType>
997 void generateValueHook(std::vector<UserType>& v) {
998 // Note: This in particular is a hack, since we have no guarantee that this gets actually written!
999 // FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
1000 RegVariableAsPushParameterInMathBase_lastX = v[0];
1001 // this is a bit a hack: we know that the test has to generate a value before writing, so we can activate
1002 // async read here which is required for the test to be successful. The assumption is that generateValue is not
1003 // called before the device is open... FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
1004 lmapBackend->close();
1005 lmapBackend->open(); // this test is explicitly for writing after open
1006 lmapBackend->activateAsyncRead();
1007
1008 auto p1 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest1", 0, 0, {});
1009 p1->read();
1010 p1->write();
1011 // don't write p2
1012 }
1013};
1014
1016: RegVariableAsPushParameterInMath_not_written<RegVariableAsPushParameterInMath_x_not_written2, RawToCookedProvider_x> {
1017 std::string path() { return "/RegisterWithVariableAsPushParameterInMath"; }
1018
1019 const double increment = 44;
1020
1021 template<typename UserType>
1022 void generateValueHook(std::vector<UserType>& v) {
1023 // Note: This in particular is a hack, since we have no guarantee that this gets actually written!
1024 // FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
1025 RegVariableAsPushParameterInMathBase_lastX = v[0];
1026 // this is a bit a hack: we know that the test has to generate a value before writing, so we can activate
1027 // async read here which is required for the test to be successful. The assumption is that generateValue is not
1028 // called before the device is open... FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
1029 lmapBackend->close();
1030 lmapBackend->open(); // this test is explicitly for writing after open
1031 lmapBackend->activateAsyncRead();
1032
1033 auto p2 = lmapBackend->getRegisterAccessor<double>("/VariableForMathTest2", 0, 0, {});
1034 p2->read();
1035 p2->write();
1036 }
1037};
1038
1039// template type UserType and RawType have to be double for the math plugin, so we make that explicit in this helper
1040// function
1042 static constexpr double theOffset = 10;
1043
1044 static double convertRawToCooked_impl(double value, boost::shared_ptr<LogicalNameMappingBackend>&) {
1045 return ((uint32_t(value) >> 3) & 1) + theOffset;
1046 }
1047};
1048
1050: RegVariableAsPushParameterInMathBase<RegRedirectedBitWithMath, RawToCookedProvider_BitWithMath> {
1051 std::string path() { return "/RedirectedBitWithMath"; }
1052
1053 const double increment = 8;
1054 typedef int32_t rawUserType;
1055
1056 template<typename UserType>
1057 void generateValueHook(std::vector<UserType>&) {
1058 // this is a bit a hack: we know that the test has to generate a value before writing, so we can activate
1059 // async read here which is required for the test to be successful. The assumption is that generateValue is not
1060 // called before the device is open... FIXME: Better introduce a proper pre-write hook in the UnifiedBackendTest!
1061 lmapBackend->activateAsyncRead();
1062
1063 // In addition we have to write the accessor which has the math plugin.
1064 // Otherwise writing of the parameters will have no effect.
1065 auto x = lmapBackend->getRegisterAccessor<double>("/RedirectedBitWithMath_helper", 0, 0, {});
1067 x->write();
1068 }
1069};
1070
1073 std::string path() { return "/MonostableTrigger"; }
1074
1075 // Note: the test is rather trivial and does not cover much apart from exception handling, since it requires a special
1076 // dummy to test the intermediate value.
1077
1078 bool isReadable() { return false; }
1079
1080 uint32_t increment = 0; // unused but required to be present
1081
1082 template<typename UserType>
1083 std::vector<std::vector<UserType>> generateValue() {
1084 return {{0}};
1085 }
1086
1087 // Conceptually the monostable trigger is of data type void. The input value
1088 // is not written anywhere. To fulfill the requirements of the test, just return what
1089 // was generated so the comparison succeeds.
1090 template<typename UserType>
1091 std::vector<std::vector<UserType>> getRemoteValue(bool /*getRaw*/ = false) {
1092 return generateValue<UserType>();
1093 }
1094
1095 // FIXME: This is Boolean until the UnifiedTest is modified to support Void correctly
1098
1099 // Mutliply plugin does not support access mode raw
1100 static constexpr auto capabilities =
1103 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/BOARD.WORD_STATUS"};
1104};
1105
1106// Base descriptor for bit accessors
1107template<typename Derived>
1109 using RegisterDescriptorBase<Derived>::derived;
1110 static constexpr auto capabilities = RegisterDescriptorBase<Derived>::capabilities.disableTestRawTransfer();
1111
1112 size_t nChannels() { return 1; }
1113 size_t nElementsPerChannel() { return 1; }
1114
1116
1117 size_t nRuntimeErrorCases() { return derived->target.nRuntimeErrorCases(); }
1118
1119 template<typename UserType>
1120 std::vector<std::vector<UserType>> generateValue() {
1121 return derived->target.template generateValue<UserType>();
1122 }
1123
1124 template<typename UserType>
1125 std::vector<std::vector<UserType>> getRemoteValue() {
1126 uint64_t v = derived->target.template getRemoteValue<uint64_t>()[0][0];
1127 uint64_t mask = ((1 << derived->width) - 1) << derived->shift;
1128 UserType result = (v & mask) >> derived->shift;
1129 return {{result}};
1130 }
1131
1132 void setRemoteValue() { derived->target.setRemoteValue(); }
1133
1134 void setForceRuntimeError(bool enable, size_t caseIndex) { derived->target.setForceRuntimeError(enable, caseIndex); }
1135};
1136
1138 std::string path() { return "/BOARD.WORD_FIRMWARE"; }
1139
1140 const uint32_t increment = 0x1313'2131;
1141
1142 using minimumUserType = uint32_t;
1143 using rawUserType = int32_t;
1144 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/BOARD.WORD_FIRMWARE"};
1145};
1146
1147struct RegLowerHalfOfFirmware : RegBitRangeDescriptor<RegLowerHalfOfFirmware> {
1148 std::string path() { return "/BitRangeLower"; }
1149
1150 using minimumUserType = int8_t;
1151
1152 uint16_t width = 8;
1153 uint16_t shift = 8;
1154
1156};
1157
1158struct RegUpperHalfOfFirmware : RegBitRangeDescriptor<RegUpperHalfOfFirmware> {
1159 std::string path() { return "/BitRangeUpper"; }
1160
1161 using minimumUserType = int16_t;
1162
1163 uint16_t width = 16;
1164 uint16_t shift = 16;
1165
1167};
1168
1169struct Reg9BitsInChar : RegBitRangeDescriptor<Reg9BitsInChar> {
1170 std::string path() { return "/BitRangeMiddle"; }
1171
1172 using minimumUserType = int8_t;
1173
1174 uint16_t width = 9;
1175 uint16_t shift = 4;
1176
1178};
1179
1182 static std::string path() { return "/WithFanOut"; }
1183 static bool isWriteable() { return true; }
1184 static bool isReadable() { return false; }
1185 static bool isPush() { return false; }
1187 static constexpr auto capabilities =
1189
1190 const uint32_t increment = 17;
1191
1192 using minimumUserType = uint32_t;
1193 using rawUserType = int32_t;
1194 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/ADC/WORD_CLK_MUX_0"};
1195};
1196
1199 static std::string path() { return "/WithFanOut"; }
1200 static bool isWriteable() { return true; }
1201 static bool isReadable() { return false; }
1202 static bool isPush() { return false; }
1204 static constexpr auto capabilities =
1206
1207 const uint32_t increment = 13;
1208
1209 using minimumUserType = uint32_t;
1210 using rawUserType = int32_t;
1211 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/ADC/WORD_CLK_MUX_1"};
1212};
1213
1216 static std::string path() { return "/WithFanOut"; }
1217 static bool isWriteable() { return true; }
1218 static bool isReadable() { return false; }
1219 static bool isPush() { return false; }
1221 static constexpr auto capabilities =
1223
1224 const uint32_t increment = 19;
1225
1226 using minimumUserType = uint32_t;
1227 using rawUserType = int32_t;
1228 DummyRegisterAccessor<minimumUserType> acc{exceptionDummyLikeMtcadummy.get(), "", "/ADC/WORD_CLK_MUX_2"};
1229};
1230
1231/**********************************************************************************************************************/
1232
1233BOOST_AUTO_TEST_CASE(unifiedBackendTest) {
1234 std::string dummyCdd = "(ExceptionDummy?map=mtcadummy.map)";
1235 std::string muxedDummyCdd = "(ExceptionDummy?map=muxedDataAcessor.map)";
1236 std::string pushDummyCdd = "(ExceptionDummy?map=mtcadummyB.map)";
1237 std::string lmapCdd = "(logicalNameMap?map=unifiedTest.xlmap&target=" + dummyCdd + "&target2=" + muxedDummyCdd +
1238 "&target3=" + pushDummyCdd + ")";
1239 exceptionDummyLikeMtcadummy =
1240 boost::dynamic_pointer_cast<ExceptionDummy>(BackendFactory::getInstance().createBackend(dummyCdd));
1241 exceptionDummyMuxed =
1242 boost::dynamic_pointer_cast<ExceptionDummy>(BackendFactory::getInstance().createBackend(muxedDummyCdd));
1243 // needed for a test that redirected bit goes to right target device
1244 exceptionDummyPush =
1245 boost::dynamic_pointer_cast<ExceptionDummy>(BackendFactory::getInstance().createBackend(pushDummyCdd));
1246 lmapBackend =
1247 boost::dynamic_pointer_cast<LogicalNameMappingBackend>(BackendFactory::getInstance().createBackend(lmapCdd));
1248
1251 .addRegister<RegSingleWord_push>()
1252 .addRegister<RegFullArea>()
1253 .addRegister<RegPartOfArea>()
1254 .addRegister<RegChannel3>()
1255 .addRegister<RegChannel4_push>()
1256 .addRegister<RegChannelLast>()
1257 .addRegister<RegConstant>()
1258 .addRegister<RegConstant2>()
1259 .addRegister<RegVariable>()
1260 .addRegister<RegArrayConstant>()
1261 .addRegister<RegArrayVariable>()
1262 .addRegister<RegBit0OfVar>()
1263 .addRegister<RegBit3OfVar>()
1264 .addRegister<RegBit2OfWordFirmware>()
1265 .addRegister<RegBit2OfWordFirmwareB>()
1266 .addRegister<RegBit2OfWordFirmware_push>()
1267 .addRegister<RegSingleWordScaled_R>()
1268 .addRegister<RegSingleWordScaled_W>()
1269 .addRegister<RegSingleWordScaled_RW>()
1270 .addRegister<RegSingleWordScaledTwice_push>()
1271 .addRegister<RegFullAreaScaled>()
1272 .addRegister<RegWordFirmwareForcedReadOnly>()
1273 .addRegister<RegWordFirmwareForcedReadOnly_push>()
1274 .addRegister<RegWordFirmwareWithMath_R>()
1275 .addRegister<RegWordFirmwareWithMath_R_push>()
1276 .addRegister<RegWordFirmwareWithMath_W>()
1277 .addRegister<RegWordFirmwareAsParameterInMath>()
1279 .addRegister<RegVariableAsPushParameterInMath_var1_not_written1>()
1281 .addRegister<RegVariableAsPushParameterInMath_var2>()
1283 .addRegister<RegVariableAsPushParameterInMath_x_not_written1>()
1285 .addRegister<RegRedirectedBitWithMath>()
1286 .addRegister<RegMonostableTrigger>()
1287 .addRegister<RegLowerHalfOfFirmware>()
1288 .addRegister<RegUpperHalfOfFirmware>()
1289 .addRegister<Reg9BitsInChar>()
1290 .addRegister<RegWithFanOutMainTarget>()
1291 .addRegister<RegWithFanOutTarget2>()
1292 .addRegister<RegWithFanOutTarget3>()
1293 .runTests(lmapCdd);
1294}
1295
1296/**********************************************************************************************************************/
1297
1298BOOST_AUTO_TEST_SUITE_END()
Set of AccessMode flags with additional functionality for an easier handling.
Definition AccessMode.h:48
void add(AccessMode flag)
Add the given flag to the set.
Definition AccessMode.cc:62
static BackendFactory & getInstance()
Static function to get an instance of factory.
Wrapper Class to avoid vector<bool> problems.
std::atomic< bool > throwExceptionRead
The dummy device opens a mapping file instead of a device, and implements all registers defined in th...
Register accessor for accessing multiplexed 2D array registers internally of a DummyBackend implement...
Register accessor for accessing single word or 1D array registers internally of a DummyBackend implem...
Class to test any backend for correct behaviour.
UnifiedBackendTest< typename boost::mpl::push_back< VECTOR_OF_REGISTERS_T, REG_T >::type > addRegister()
Add a register to be used by the test.
@ wait_for_new_data
Make any read blocking until new data has arrived since the last read.
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
DummyRegisterAccessor< minimumUserType > acc
void setForceRuntimeError(bool enable, size_t caseIndex)
std::vector< std::vector< UserType > > getRemoteValue()
ChimeraTK::AccessModeFlags supportedFlags()
std::vector< std::vector< UserType > > generateValue()
Base descriptor for channel accessors.
std::vector< std::vector< UserType > > generateValue()
std::vector< std::vector< UserType > > getRemoteValue()
Descriptor for the test capabilities for each register.
constexpr TestCapabilities< _syncRead, TestCapability::disabled, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableForceDataLossWrite() const
Base descriptor for constant accessors.
std::vector< std::vector< UserType > > generateValue()
ChimeraTK::AccessModeFlags supportedFlags()
std::vector< std::vector< UserType > > getRemoteValue()
Base descriptor for 1D accessors (and scalars)
std::vector< std::vector< UserType > > getRemoteValue(bool getRaw=false)
void generateValueHook(std::vector< UserType > &)
std::vector< std::vector< Type > > generateValue(bool getRaw=false)
static double convertRawToCooked_impl(double value, boost::shared_ptr< LogicalNameMappingBackend > &)
static double convertRawToCooked_impl(double value, boost::shared_ptr< LogicalNameMappingBackend > &lmapBackend)
static double convertRawToCooked_impl(double value, boost::shared_ptr< LogicalNameMappingBackend > &lmapBackend)
static double convertRawToCooked_impl(double value, boost::shared_ptr< LogicalNameMappingBackend > &lmapBackend)
BitRangeAccessorTarget target
Test constant accessor with arrays.
const std::vector< int32_t > value
Test variable accessor with arrays.
Test bit accessor with a variable accessor as target.
Test bit accessor with a real dummy accessor as target.
Test bit accessor with another instance of a real dummy accessor as target.
boost::shared_ptr< NDRegisterAccessor< minimumUserType > > fixAccessorOnA
Test bit accessor with a real dummy accessor as target.
Test bit accessor with a variable accessor as target.
void setForceRuntimeError(bool enable, size_t caseIndex)
std::vector< std::vector< UserType > > generateValue()
static constexpr auto capabilities
std::vector< std::vector< UserType > > getRemoteValue()
ChimeraTK::AccessModeFlags supportedFlags()
Test channel accessor.
ChimeraTK::AccessModeFlags supportedFlags()
DummyMultiplexedRegisterAccessor< minimumUserType > acc
Test channel accessors.
ChimeraTK::AccessModeFlags supportedFlags()
DummyMultiplexedRegisterAccessor< minimumUserType > acc
Test channel accessors.
ChimeraTK::AccessModeFlags supportedFlags()
DummyMultiplexedRegisterAccessor< minimumUserType > acc
Test constant accessor.
const std::vector< int32_t > value
Test constant accessor.
const std::vector< int32_t > value
Test passing through 1D array accessors.
DummyRegisterAccessor< minimumUserType > acc
Test multiply plugin applied to array (just one direction for sake of simplicity)
DummyRegisterAccessor< minimumUserType > acc
static constexpr auto capabilities
ChimeraTK::AccessModeFlags supportedFlags()
Test monostable trigger plugin (rather minimal test, needs extension!)
static constexpr auto capabilities
std::vector< std::vector< UserType > > getRemoteValue(bool=false)
ChimeraTK::AccessModeFlags supportedFlags()
DummyRegisterAccessor< minimumUserType > acc
std::vector< std::vector< UserType > > generateValue()
Test passing through partial array accessors.
DummyRegisterAccessor< minimumUserType > acc
void generateValueHook(std::vector< UserType > &)
Test passing through push-type scalar accessors.
DummyRegisterAccessor< minimumUserType > acc
Test passing through scalar accessors - use another target.
DummyRegisterAccessor< minimumUserType > acc
Test passing through scalar accessors.
DummyRegisterAccessor< minimumUserType > acc
static constexpr auto capabilities
static constexpr auto capabilities
Test multiply plugin - needs to be done separately for reading and writing (see below)
static constexpr auto capabilities
ChimeraTK::AccessModeFlags supportedFlags()
DummyRegisterAccessor< rawUserType > acc
Test multiply plugin applied twice (just one direction for sake of simplicity)
DummyRegisterAccessor< minimumUserType > acc
ChimeraTK::AccessModeFlags supportedFlags()
std::vector< std::vector< UserType > > generateValue(bool=false)
std::vector< std::vector< UserType > > getRemoteValue(bool getRaw=false)
void generateValueHook(std::vector< UserType > &)
void generateValueHook(std::vector< UserType > &)
void generateValueHook(std::vector< UserType > &v)
DummyRegisterAccessor< rawUserType > acc
Test variable accessor.
Test for fanOut plugin - define 3 registers to check, one for each target of the fan out.
static ChimeraTK::AccessModeFlags supportedFlags()
DummyRegisterAccessor< minimumUserType > acc
Test for fanOut plugin - define 3 registers to check, one for each target of the fan out.
static ChimeraTK::AccessModeFlags supportedFlags()
static constexpr auto capabilities
DummyRegisterAccessor< minimumUserType > acc
Test for fanOut plugin - define 3 registers to check, one for each target of the fan out.
static ChimeraTK::AccessModeFlags supportedFlags()
DummyRegisterAccessor< minimumUserType > acc
static constexpr auto capabilities
Test math plugin with real dummy register as parameter (exception handling...)
DummyRegisterAccessor< rawUserType > acc
ChimeraTK::AccessModeFlags supportedFlags()
Test force readonly plugin with wait_for_new_data.
DummyRegisterAccessor< minimumUserType > acc
DummyRegisterAccessor< minimumUserType > acc
ChimeraTK::AccessModeFlags supportedFlags()
Test math plugin - needs to be done separately for reading and writing (see below)
ChimeraTK::AccessModeFlags supportedFlags()
DummyRegisterAccessor< rawUserType > acc
static constexpr auto capabilities
Base descriptor with defaults, used for all registers.
ChimeraTK::AccessModeFlags supportedFlags()
void setForceRuntimeError(bool enable, size_t)
static constexpr auto capabilities
Base descriptor for scalars.
Base descriptor for variable accessors.
std::vector< std::vector< UserType > > getRemoteValue(bool=false)
ChimeraTK::AccessModeFlags supportedFlags()
BOOST_AUTO_TEST_CASE(unifiedBackendTest)