ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
testInitialValueSpecD8.cc
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#define BOOST_TEST_MODULE testInitialValues
4
5#include "Application.h"
6#include "ApplicationModule.h"
7#include "check_timeout.h"
8#include "DeviceModule.h"
9#include "ScalarAccessor.h"
10#include "TestFacility.h"
11
12#include <ChimeraTK/BackendFactory.h>
13#include <ChimeraTK/Device.h>
14#include <ChimeraTK/DummyRegisterAccessor.h>
15#include <ChimeraTK/ExceptionDummyBackend.h>
16
17#include <boost/mpl/list.hpp>
18#include <boost/test/included/unit_test.hpp>
19
20#include <VoidAccessor.h>
21
22#include <chrono>
23#include <functional>
24#include <future>
25
27
28 /********************************************************************************************************************/
29
30 // Base Application module that provides flags for the various phases
31 // of module lifetime and full-fills a promise when the main loop has been reached
34
35 std::promise<void> p;
36 std::atomic_bool enteredTheMainLoop{false};
37 std::atomic_bool enteredThePrepareLoop{false};
38 void mainLoop() override {
39 enteredTheMainLoop = true;
40 p.set_value();
41 }
42 void prepare() override { enteredThePrepareLoop = true; }
43 };
44
45 /********************************************************************************************************************/
46
47 using namespace boost::unit_test_framework;
48 namespace ctk = ChimeraTK;
49 // A generic module with just one input. It is connected manually, so we just call the register "REG1" so we easily
50 // connect to that register in the device It has a flag and a promise to check whether the module has entered the main
51 // loop, and to wait for it.
52 template<class INPUT_TYPE>
55 INPUT_TYPE input{this, "/REG1", "", ""};
56 std::promise<void> p;
57 std::atomic_bool enteredTheMainLoop{false};
58 void mainLoop() override {
59 enteredTheMainLoop = true;
60 p.set_value();
61 }
62 };
63
65 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:1?map=test-ro.map)";
66 PollDummyApplication() : Application("DummyApplication") {}
68
71 };
72
73 // for the push type we need different connection code
75 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:2?map=test-async.map)";
76 PushDummyApplication() : Application("DummyApplication") {}
78
81 };
82
83 template<class APPLICATION_TYPE>
86 : deviceBackend(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
87 ChimeraTK::BackendFactory::getInstance().createBackend(APPLICATION_TYPE::ExceptionDummyCDD1))) {}
88 ~TestFixtureWithEceptionDummy() { deviceBackend->throwExceptionRead = false; }
89
90 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend;
91 APPLICATION_TYPE application;
93 ChimeraTK::ScalarRegisterAccessor<int> exceptionDummyRegister;
94 };
99 BOOST_AUTO_TEST_SUITE(testInitialValuesInputsOfApplicationCore_D_8)
101
106 BOOST_AUTO_TEST_CASE_TEMPLATE(testInitValueAtDevice8bi, APPLICATION_TYPE, DeviceTestApplicationTypes) {
107 std::cout << "=== testInitValueAtDevice8bi " << typeid(APPLICATION_TYPE).name() << " ===" << std::endl;
108 std::chrono::time_point<std::chrono::steady_clock> start, end;
109 { // Here the time is stopped until you reach the mainloop.
110 TestFixtureWithEceptionDummy<APPLICATION_TYPE> dummyToStopTimeUntilOpen;
111 start = std::chrono::steady_clock::now();
112 dummyToStopTimeUntilOpen.application.run();
113 dummyToStopTimeUntilOpen.application.inputModule.p.get_future().wait();
114 std::this_thread::sleep_for(std::chrono::milliseconds(10));
115 end = std::chrono::steady_clock::now();
116 }
117 { // waiting 2 x the time stopped above, in the assumption that it is then frozen,
118 // as it is described in the spec.
120 d.deviceBackend->throwExceptionOpen = true;
121 BOOST_CHECK_THROW(d.deviceBackend->open(), std::exception);
122 d.deviceBackend->throwExceptionOpen = true;
123 d.application.run();
124 auto elapsed_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
125 BOOST_CHECK(d.application.inputModule.enteredTheMainLoop == false);
126 std::this_thread::sleep_for(std::chrono::milliseconds(2 * elapsed_milliseconds));
127 BOOST_CHECK(d.application.inputModule.enteredTheMainLoop == false);
128 BOOST_CHECK(d.application.inputModule.input.getVersionNumber() == ctk::VersionNumber(std::nullptr_t()));
129 d.deviceBackend->throwExceptionOpen = false;
130 d.application.inputModule.p.get_future().wait();
131 BOOST_CHECK(d.application.inputModule.enteredTheMainLoop == true);
132 BOOST_CHECK(d.application.inputModule.input.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
133 }
134 }
135
137
141 std::promise<void> p;
142 std::atomic_bool enteredTheMainLoop{false};
143 void mainLoop() override {
144 enteredTheMainLoop = true;
145 p.set_value();
146 }
147 };
148
149 template<class INPUT_TYPE>
151 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:1?map=test.map)";
152 ProcessArryDummyApplication() : Application("DummyApplication") {}
154
157 };
158
159 using TestInputTypes = boost::mpl::list<ctk::ScalarPollInput<int>, ctk::ScalarPushInput<int>>;
160
165 BOOST_AUTO_TEST_CASE_TEMPLATE(testProcessArrayInitValueAtDevice8bii, INPUT_TYPE, TestInputTypes) {
166 std::cout << "=== testPollProcessArrayInitValueAtDevice8bii " << typeid(INPUT_TYPE).name()
167 << " === " << std::endl;
168 std::chrono::time_point<std::chrono::steady_clock> start, end;
169 {
170 // we don't need the exception dummy in this test. But no need to write a new fixture for it.
172 start = std::chrono::steady_clock::now();
173 dummyToStopTimeForApplicationStart.application.run();
174 dummyToStopTimeForApplicationStart.application.scalarOutputModule.output.write();
175 dummyToStopTimeForApplicationStart.application.inputModule.p.get_future().wait();
176 end = std::chrono::steady_clock::now();
177 }
178 {
180 d.application.run();
181 BOOST_CHECK(d.application.inputModule.enteredTheMainLoop == false);
182 std::this_thread::sleep_for(end - start);
183 BOOST_CHECK(d.application.inputModule.enteredTheMainLoop == false);
184 BOOST_CHECK(d.application.inputModule.input.getVersionNumber() == ctk::VersionNumber(std::nullptr_t()));
185 d.application.scalarOutputModule.output.write();
186 d.application.inputModule.p.get_future().wait();
187 BOOST_CHECK(d.application.inputModule.enteredTheMainLoop == true);
188 BOOST_CHECK(d.application.inputModule.input.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
189 }
190 }
191
193
194 template<class INPUT_TYPE>
196 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:1?map=test.map)";
197 ConstantTestApplication() : Application("DummyApplication") {}
199
200 InputModule<INPUT_TYPE> inputModule{this, "constantPollModule", ""};
201 };
202
211 BOOST_AUTO_TEST_CASE_TEMPLATE(testConstantInitValueAtDevice8biii, INPUT_TYPE, TestInputTypes) {
212 std::cout << "=== testConstantInitValueAtDevice8biii " << typeid(INPUT_TYPE).name() << " === " << std::endl;
214
215 // make sure, inputModule.input is not connected to anything, not even the control system.
216 d.application.optimiseUnmappedVariables({"/REG1"});
217
218 d.application.run();
219 d.application.inputModule.p.get_future().wait();
220
221 BOOST_CHECK(d.application.inputModule.input.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
222 if(d.application.inputModule.input.getAccessModeFlags().has(ctk::AccessMode::wait_for_new_data)) {
223 BOOST_CHECK(d.application.inputModule.input.readNonBlocking() ==
224 false); // no new data. Calling read() would block infinitely
225 }
226 else {
227 BOOST_CHECK(d.application.inputModule.input.readNonBlocking() == true);
228 }
229 }
230
232
236 std::promise<void> p;
237 std::atomic_bool enteredTheMainLoop{false};
238 void mainLoop() override {
239 enteredTheMainLoop = true;
240 p.set_value();
241 }
242 };
246 std::promise<void> p;
247 std::atomic_bool enteredTheMainLoop{false};
248 void mainLoop() override {
249 enteredTheMainLoop = true;
250 p.set_value();
251 }
252 };
253
255 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:1?map=test-async.map)";
256 PushD9DummyApplication() : Application("DummyApplication") {}
258
259 PushModuleD91 pushModuleD91{this, "PushModule1", ""};
260 PushModuleD92 pushModuleD92{this, "PushModule2", ""};
261
263 };
264
267 : deviceBackend(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
268 ChimeraTK::BackendFactory::getInstance().createBackend(PushD9DummyApplication::ExceptionDummyCDD1))) {}
269 ~D9InitialValueEceptionDummy() { deviceBackend->throwExceptionRead = false; }
270
271 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend;
274 ChimeraTK::ScalarRegisterAccessor<int> exceptionDummyRegister;
277 };
278
283 BOOST_AUTO_TEST_CASE(testPushInitValueAtDeviceD9) {
284 std::cout << "=== testPushInitValueAtDeviceD9 === " << std::endl;
285 std::chrono::time_point<std::chrono::steady_clock> start, end;
286 {
287 D9InitialValueEceptionDummy dummyToStopTimeUntilOpen;
288 start = std::chrono::steady_clock::now();
289 dummyToStopTimeUntilOpen.application.run();
290 dummyToStopTimeUntilOpen.application.pushModuleD91.p.get_future().wait();
291 dummyToStopTimeUntilOpen.application.pushModuleD92.p.get_future().wait();
292 std::this_thread::sleep_for(std::chrono::milliseconds(10));
293 end = std::chrono::steady_clock::now();
294 }
295 {
297 d.deviceBackend->throwExceptionOpen = true;
298 BOOST_CHECK_THROW(d.deviceBackend->open(), std::exception);
299 d.application.run();
300 BOOST_CHECK(d.application.pushModuleD91.enteredTheMainLoop == false);
301 std::this_thread::sleep_for(2 * (end - start));
302 BOOST_CHECK(d.application.pushModuleD91.enteredTheMainLoop == false);
303 BOOST_CHECK(d.pushVariable1.getVersionNumber() == ctk::VersionNumber(std::nullptr_t()));
304 d.deviceBackend->throwExceptionOpen = false;
305 d.application.pushModuleD91.p.get_future().wait();
306 BOOST_CHECK(d.application.pushModuleD91.enteredTheMainLoop == true);
307 BOOST_CHECK(d.pushVariable1.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
308 }
309 }
310
312
315 ChimeraTK::VoidOutput trigger{this, "/TRIG1/PUSH_OUT", ""};
316 std::promise<void> p;
317 std::atomic_bool enteredTheMainLoop{false};
318 void mainLoop() override {
319 enteredTheMainLoop = true;
320 p.set_value();
321 }
322 };
323
325 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:1?map=test-trigger-fanout-iv.map)";
328
329 PushModuleD91 pushModuleD91{this, "PushModule1", ""};
330 PushModuleD92 pushModuleD92{this, "PushModule2", ""};
331 TriggerModule triggerModule{this, "TriggerModule", ""};
332
334 };
335
350
355 BOOST_AUTO_TEST_CASE(testTriggerFanOutInitValueAtDeviceD9) {
356 std::cout << "=== testTriggerFanOutInitValueAtDeviceD9 === " << std::endl;
357 std::chrono::time_point<std::chrono::steady_clock> start, end;
358 {
359 TriggerFanOutInitialValueEceptionDummy dummyToStopTimeUntilOpen;
360 start = std::chrono::steady_clock::now();
361 dummyToStopTimeUntilOpen.application.run();
362 dummyToStopTimeUntilOpen.application.triggerModule.trigger.write();
363 dummyToStopTimeUntilOpen.application.pushModuleD91.p.get_future().wait();
364 dummyToStopTimeUntilOpen.application.pushModuleD92.p.get_future().wait();
365 std::this_thread::sleep_for(std::chrono::milliseconds(10));
366 end = std::chrono::steady_clock::now();
367 }
368 {
370 d.deviceBackend->throwExceptionOpen = true;
371 BOOST_CHECK_THROW(d.deviceBackend->open(), std::exception);
372 d.application.run();
373 BOOST_CHECK(d.application.pushModuleD91.enteredTheMainLoop == false);
374 std::this_thread::sleep_for(2 * (end - start));
375 BOOST_CHECK(d.application.pushModuleD91.enteredTheMainLoop == false);
376 BOOST_CHECK(d.pushVariable1.getVersionNumber() == ctk::VersionNumber(std::nullptr_t()));
377 d.deviceBackend->throwExceptionOpen = false;
379 d.application.pushModuleD91.p.get_future().wait();
380 BOOST_CHECK(d.application.pushModuleD91.enteredTheMainLoop == true);
381 BOOST_CHECK(d.pushVariable1.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
382 }
383 }
384
386
389
390 struct : ChimeraTK::VariableGroup {
393 } reg1{this, ".", ""};
394
395 std::promise<void> p;
396 std::atomic_bool enteredTheMainLoop{false};
397
398 void prepare() override {
399 reg1.constant = 543; // some non-zero value to detect if the 0 constant is written later
400 }
401
402 void mainLoop() override {
403 enteredTheMainLoop = true;
404 p.set_value();
405 }
406 };
407
409 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:1?map=test.map)";
410 ConstantD10DummyApplication() : Application("DummyApplication") {}
412
413 ConstantModule constantModule{this, "ConstantModule", ""};
414
416 };
417
420 : deviceBackend(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
421 ChimeraTK::BackendFactory::getInstance().createBackend("(ExceptionDummy:1?map=test.map)"))) {}
422 ~ConstantD10InitialValueEceptionDummy() { deviceBackend->throwExceptionRead = false; }
423
424 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend;
427 };
428
433 BOOST_AUTO_TEST_CASE(testConstantD10InitialValue) {
434 std::cout << "=== testConstantD10InitialValue === " << std::endl;
437
438 ChimeraTK::Device dev("(ExceptionDummy:1?map=test.map)");
439 dev.open();
440 dev.write<int>("REG1", 1234); // place some value, we expect it to be overwritten with 0
441
442 d.deviceBackend->throwExceptionOpen = true;
443 BOOST_CHECK_THROW(d.deviceBackend->open(), std::exception);
444
445 d.application.run();
446 d.application.constantModule.p.get_future().wait();
447
448 BOOST_CHECK(d.application.constantModule.enteredTheMainLoop == true);
449 BOOST_CHECK(d.application.constantModule.reg1.constant == 0); // no longer at the value set in prepare()
450 BOOST_CHECK(d.application.constantModule.reg1.constant.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
451
452 ChimeraTK::DummyRegisterAccessor<int> reg1(
453 boost::dynamic_pointer_cast<ChimeraTK::DummyBackend>(dev.getBackend()).get(), "", "REG1");
454 {
455 auto lk = reg1.getBufferLock();
456 BOOST_CHECK(reg1 == 1234);
457 }
458 d.deviceBackend->throwExceptionOpen = false;
459 CHECK_TIMEOUT((reg1.getBufferLock(), reg1 == 0), 1000000);
460 }
461
463
467 ChimeraTK::ScalarOutput<int> output{this, "SomeOutput", "", ""};
468 std::promise<void> p;
469 std::atomic_bool enteredTheMainLoop{false};
470 void mainLoop() override {
471 enteredTheMainLoop = true;
472 p.set_value();
473 }
474 };
475
477 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:1?map=test-async.map)";
478 TestDummyApplication() : Application("DummyApplication") {}
480
481 TestModule testModule{this, "TestModule", ""};
483 };
484
487 : deviceBackend(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
488 ChimeraTK::BackendFactory::getInstance().createBackend(TestDummyApplication::ExceptionDummyCDD1))) {}
489 ~TestInitialValueExceptionDummy() { deviceBackend->throwExceptionRead = false; }
490
491 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend;
496 };
497
502 // Todo add missing tests for bi-directional variables
503 BOOST_AUTO_TEST_CASE(testD1InitialValue) {
504 std::cout << "=== testD1InitialValue === " << std::endl;
505
507
508 d.application.run();
509 d.application.testModule.p.get_future().wait();
510 BOOST_CHECK(d.application.testModule.enteredTheMainLoop == true);
511 BOOST_CHECK(d.pushVariable.dataValidity() == ctk::DataValidity::ok);
513 BOOST_CHECK(d.outputVariable.dataValidity() == ctk::DataValidity::ok);
514 }
515
520 BOOST_AUTO_TEST_CASE(testD2InitialValue) {
521 std::cout << "=== testD2InitialValue === " << std::endl;
522
524 d.application.run();
525 d.application.testModule.p.get_future().wait();
527 BOOST_CHECK(d.application.testModule.enteredTheMainLoop == true);
528 BOOST_CHECK(d.pushVariable.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
529 BOOST_CHECK(d.outputVariable.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
530 }
531
536 BOOST_AUTO_TEST_CASE(testD3InitialValue) {
537 std::cout << "=== testD3InitialValue === " << std::endl;
538
540 d.application.run();
541 d.application.testModule.p.get_future().wait();
542 BOOST_CHECK(d.application.testModule.enteredTheMainLoop == true);
543 BOOST_CHECK(d.pushVariable.dataValidity() == ctk::DataValidity::ok);
544 BOOST_CHECK(d.outputVariable.dataValidity() == ctk::DataValidity::ok);
545 // Todo. The initial value can also be faulty. Change backend so that it allows to override the data validity
546 // without going to an exception state.
547 }
548
550
553 ChimeraTK::ScalarOutput<int> output1{this, "/REG1", "", ""};
554 ChimeraTK::ScalarOutput<int> output2{this, "/REG2", "", ""};
555 std::atomic_bool enteredTheMainLoop{false};
556 std::atomic_bool enteredThePrepareLoop{false};
557 void mainLoop() override {
558 enteredTheMainLoop = true;
559 output2 = 555;
560 output2.write();
561 }
562 void prepare() override {
564 output1 = 777;
565 output1.write();
566 }
567 };
568
570 using NotifyingModule::NotifyingModule;
571
572 ChimeraTK::ScalarPushInput<int> reg1{this, "/REG1", "", ""};
573 ChimeraTK::ScalarPushInput<int> reg2{this, "/REG2", "", ""};
574 };
575
577 Test7DummyApplication() : Application("DummyApplication") {}
579
580 WriterModule writerModule{this, "WriterModule", ""};
581 ReaderModule readerModule{this, "ReaderModule", ""};
582 };
583
589 BOOST_AUTO_TEST_CASE(testD7_1_InitialValue) {
590 std::cout << "=== testD7_1_InitialValue === " << std::endl;
591
592 Test7DummyApplication application;
593 ChimeraTK::TestFacility testFacitiy{application, false};
594 application.run();
595 BOOST_CHECK(application.writerModule.enteredThePrepareLoop == true);
596 application.readerModule.p.get_future().wait();
597 CHECK_TIMEOUT(application.readerModule.reg1 == 777, 500);
598 }
599
604 BOOST_AUTO_TEST_CASE(testD7_2_InitialValue) {
605 std::cout << "=== testD7_2_InitialValue === " << std::endl;
606
607 Test7DummyApplication application;
608 ChimeraTK::TestFacility testFacitiy{application, false};
609 application.run();
610 application.readerModule.p.get_future().wait();
611 BOOST_CHECK(application.readerModule.enteredTheMainLoop == true);
612 CHECK_TIMEOUT(application.readerModule.reg2 == 555, 500);
613 }
614
616
618 // This application connects the CS to the device and and the input of the readerModule
619 constexpr static const char* CDD = "(dummy:1?map=test.map)";
620 Test6A1DummyApplication() : Application("DummyApplication") {}
622
623 struct : NotifyingModule {
624 using NotifyingModule::NotifyingModule;
625
626 ChimeraTK::ScalarPushInput<int> reg1{this, "/REG1", "", ""};
627 } readerModule{this, ".", ""};
628
630 };
631
640
646 BOOST_AUTO_TEST_CASE(testD6_a1_InitialValue) {
647 std::cout << "=== testD6_a1_InitialValue === " << std::endl;
649 d.application.run();
650 BOOST_CHECK(d.pushVariable.getVersionNumber() == ctk::VersionNumber(std::nullptr_t()));
651 d.testFacitiy.writeScalar<int>("REG1", 27);
654 CHECK_TIMEOUT(dev.read<int>("REG1") == 27, 1000000);
655 // wait until the main loop has been entered. then we know the version number of the inputs must not be 0.
656 // FIXME: I think this does not belong into this test....
657 d.application.readerModule.p.get_future().wait(); // synchronisation point for the thread sanitizer
658 BOOST_CHECK(d.pushVariable.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
659 }
660
663 constexpr static const char* CDD1 = "(dummy:1?map=one-register.map)";
664 constexpr static const char* CDD2 = "(dummy:2?map=test-ro.map)";
665 Test6A2DummyApplication() : Application("DummyApplication") {}
667
668 struct : NotifyingModule {
669 using NotifyingModule::NotifyingModule;
670 ChimeraTK::ScalarPushInput<int> reg1{this, "/REG1", "", ""};
671 } readerModule{this, "ReaderModule", ""};
672
673 TriggerModule triggerModule{this, "ReaderModule", ""};
675 ChimeraTK::DeviceModule device2{this, CDD2, "/TRIG1/PUSH_OUT"};
676 };
677
686
695 BOOST_AUTO_TEST_CASE(testD6_a2_InitialValue) {
696 std::cout << "=== testD6_a2_InitialValue === " << std::endl;
697
699
702 dev2.write<int>("REG1/DUMMY_WRITEABLE", 99); // value now in in dev2
703
704 d.application.run();
705 // no trigger yet and the value is not on dev1 yet
706 BOOST_CHECK(d.pushVariable.getVersionNumber() == ctk::VersionNumber(std::nullptr_t()));
709 BOOST_CHECK(dev.read<int>("REG1") != 99);
710
711 // send the trigger and check that the data arrives on the device
713
714 CHECK_TIMEOUT(dev.read<int>("REG1") == 99, 1000000);
715 }
716
718
720 constexpr static const char* CDD1 = "(dummy:1?map=one-register.map)";
721 constexpr static const char* CDD2 = "(dummy:2?map=test-async.map)";
722 Test6A3DummyApplication() : Application("DummyApplication") {}
724
725 struct : NotifyingModule {
726 using NotifyingModule::NotifyingModule;
727 ChimeraTK::ScalarPushInput<int> reg1{this, "/REG1", "", ""};
728 } readerModule{this, "ReaderModule", ""};
729
732 };
733
742
747 BOOST_AUTO_TEST_CASE(testD6_a3_InitialValue) {
748 std::cout << "=== testD6_a3_InitialValue === " << std::endl;
749
751
754 dev2.write<int>("REG1/DUMMY_WRITEABLE", 99);
755
756 d.application.run();
757
760 CHECK_TIMEOUT(dev.read<int>("REG1") == 99, 1000000);
761 d.application.readerModule.p.get_future().wait();
762 BOOST_CHECK(d.pushVariable.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
763 }
764
766
768 Test6A4DummyApplication() : Application("DummyApplication") {}
770
771 struct : NotifyingModule {
772 using NotifyingModule::NotifyingModule;
773 ChimeraTK::ScalarPushInput<int> reg1{this, "/REG1", "", ""};
774 } readerModule{this, "ReaderModule", ""};
775
776 WriterModule writerModule{this, "WriterModule", ""};
777 };
778
787
792 BOOST_AUTO_TEST_CASE(testD6_a4_InitialValue) {
793 std::cout << "=== testD6_a4_InitialValue === " << std::endl;
794
796
797 d.application.run();
798 d.application.readerModule.p.get_future().wait();
799 BOOST_CHECK(d.application.readerModule.enteredTheMainLoop == true);
800 CHECK_TIMEOUT(d.pushVariable == 777, 100000);
801 BOOST_CHECK(d.pushVariable.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
802 }
803
805
807 using NotifyingModule::NotifyingModule;
808
810 };
811
813 constexpr static const char* CDD = "(dummy?map=test-ro.map)";
814 Test6BDummyApplication() : Application("DummyApplication") {}
816
817 PollModule pollModule{this, "PollModule", ""};
819 };
820
829
835 BOOST_AUTO_TEST_CASE(testD6_b_InitialValue) {
836 std::cout << "=== testD6_b_InitialValue === " << std::endl;
837
839
840 d.application.run();
841
844 dev.write<int>("REG1/DUMMY_WRITEABLE", 99);
845 d.application.pollModule.p.get_future().wait();
846 BOOST_CHECK(d.application.pollModule.enteredTheMainLoop == true);
847 BOOST_CHECK(d.pollVariable == 99);
848 BOOST_CHECK(d.pollVariable.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
849 }
850
852
854 constexpr static const char* ExceptionDummyCDD1 = "(dummy:1?map=test-async.map)";
855 Test6CDummyApplication() : Application("DummyApplication") {}
857
858 struct : NotifyingModule {
859 using NotifyingModule::NotifyingModule;
860 ChimeraTK::ScalarPushInput<int> reg1{this, "/REG1", "", ""};
861 } readerModule{this, "ReaderModule", ""};
862
864 };
865
879 BOOST_AUTO_TEST_CASE(testD6_c_InitialValue) {
880 std::cout << "=== testD6_c_InitialValue === " << std::endl;
881
883
884 d.application.run();
885
888 dev.write<int>("REG1/DUMMY_WRITEABLE", 99);
889 dev.getVoidRegisterAccessor("/DUMMY_INTERRUPT_3").write();
890 d.application.readerModule.p.get_future().wait();
891 BOOST_CHECK(d.application.readerModule.enteredTheMainLoop == true);
892 BOOST_TEST(d.pushVariable == 99);
893 BOOST_CHECK(d.pushVariable.getVersionNumber() != ctk::VersionNumber(std::nullptr_t()));
894 }
895
896 BOOST_AUTO_TEST_SUITE_END()
897
898} // namespace Tests::testInitialValues
void run() override
Execute the module.
void optimiseUnmappedVariables(const std::set< std::string > &names) override
void shutdown() override
This will remove the global pointer to the instance and allows creating another instance afterwards.
ApplicationModule()=default
Default constructor: Allows late initialisation of modules (e.g.
friend class Application
Definition ModuleGroup.h:47
bool write(ChimeraTK::VersionNumber versionNumber)=delete
Convenience class for input scalar accessors with UpdateMode::push.
Helper class to facilitate tests of applications based on ApplicationCore.
void writeScalar(const std::string &name, TYPE value)
Convenience function to write a scalar process variable in a single call.
VariableGroup()=default
Default constructor: Allows late initialisation of VariableGroups (e.g.
bool write(ChimeraTK::VersionNumber versionNumber)=delete
InvalidityTracer application module.
boost::mpl::list< PushDummyApplication, PollDummyApplication > DeviceTestApplicationTypes
Test Initial Values - Inputs of ApplicationModules InitialValuesInputsOfApplicationCore_D_8 "D....
BOOST_AUTO_TEST_CASE(testPushInitValueAtDeviceD9)
D 9 b for ThreadedFanOut initialValueThreadedFanOut_D_9_b.
boost::mpl::list< ctk::ScalarPollInput< int >, ctk::ScalarPushInput< int > > TestInputTypes
BOOST_AUTO_TEST_CASE_TEMPLATE(testInitValueAtDevice8bi, APPLICATION_TYPE, DeviceTestApplicationTypes)
For device variables the ExceptionHandlingDecorator freezes the variable until the device is availabl...
Convenience class for output scalar accessors (always UpdateMode::push)
Convenience class for input scalar accessors with UpdateMode::poll.
Convenience class for output void (always UpdateMode::push)
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ChimeraTK::ScalarPushInput< int > constant
void prepare() override
Prepare the execution of the module.
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend
ChimeraTK::ScalarRegisterAccessor< int > exceptionDummyRegister
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
void prepare() override
Prepare the execution of the module.
InputModule< ctk::ScalarPollInput< int > > inputModule
ChimeraTK::ScalarPollInput< int > pollInput
InputModule< ctk::ScalarPushInput< int > > inputModule
ChimeraTK::ScalarPushInput< int > pushInput
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ChimeraTK::ScalarPushInput< int > pushInput
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ChimeraTK::ScalarPushInput< int > reg1
ChimeraTK::ScalarPushInput< int > reg2
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ChimeraTK::ScalarRegisterAccessor< int > exceptionDummyRegister
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend
ChimeraTK::ScalarRegisterAccessor< int > exceptionDummyRegister
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend
ChimeraTK::ScalarPushInput< int > pushInput
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
void prepare() override
Prepare the execution of the module.
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
#define CHECK_TIMEOUT(condition, maxMilliseconds)