ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
testTrigger.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#include "VoidAccessor.h"
4
5#define BOOST_TEST_MODULE testTrigger
6
7#include "Application.h"
8#include "ApplicationModule.h"
9#include "check_timeout.h"
10#include "DeviceModule.h"
11#include "ScalarAccessor.h"
12#include "TestFacility.h"
13
14#include <ChimeraTK/BackendFactory.h>
15#include <ChimeraTK/ControlSystemAdapter/ControlSystemPVManager.h>
16#include <ChimeraTK/ControlSystemAdapter/DevicePVManager.h>
17#include <ChimeraTK/ControlSystemAdapter/PVManager.h>
18#include <ChimeraTK/Device.h>
19#include <ChimeraTK/DeviceAccessVersion.h>
20#include <ChimeraTK/DummyBackend.h>
21
22#include <boost/mpl/list.hpp>
23#include <boost/test/included/unit_test.hpp>
24
25#include <latch>
26
28
29 using namespace boost::unit_test_framework;
30 namespace ctk = ChimeraTK;
31
32 /********************************************************************************************************************/
33 /********************************************************************************************************************/
34
35 // Application that has one polling consumer for a polling provider
36 // It should work without any trigger
38 TestApp1() : ctk::Application("testApp1") {}
39 ~TestApp1() override { shutdown(); }
40
41 struct : ctk::ApplicationModule {
42 using ctk::ApplicationModule::ApplicationModule;
43
44 ctk::ScalarPollInput<int> readBack{this, "/MyModule/readBack", "unit", "description"};
45
46 // This is just here so that we do not need a trigger - otherwise it would be connected to a pushing CS consumer
47 // automatically which would require a trigger
48 ctk::ScalarPollInput<int> tests{this, "/Deeper/hierarchies/need/tests", "unit", "description"};
49
50 ctk::VoidInput finger{this, "/finger", ""};
51
52 void mainLoop() override {
53 while(true) {
54 readAll();
55 }
56 }
57 } someModule{this, ".", ""};
58
61 };
62
63 /********************************************************************************************************************/
64
65 BOOST_AUTO_TEST_CASE(TestDev2AppWithPollTrigger) {
66 // TestApp1 should work without specifying any trigger
67 {
68 TestApp1 app;
69 app.dev = {&app, "Dummy0"};
71 auto finger = tf.getVoid("/finger");
72 auto rb = tf.getScalar<int>("/MyModule/readBack");
73
74 tf.runApplication();
75
76 ctk::Device dev("Dummy0");
77 dev.open();
78 dev.write("MyModule/actuator", 1);
79
80 BOOST_TEST(rb.readNonBlocking() == false);
81 finger.write();
82 tf.stepApplication();
83 BOOST_TEST(rb.readNonBlocking() == true);
84 BOOST_TEST(rb == 1);
85
86 dev.write("MyModule/actuator", 10);
87 finger.write();
88 tf.stepApplication();
89 BOOST_TEST(rb.readNonBlocking() == true);
90 BOOST_TEST(rb == 10);
91 }
92
93 // TestApp1 should also work with any trigger, but the trigger should be ignored
94 {
95 TestApp1 app;
96 app.dev = {&app, "Dummy0", "/cs/tick"};
98 auto tick = tf.getVoid("/cs/tick");
99 auto finger = tf.getVoid("/finger");
100 auto rb = tf.getScalar<int>("/MyModule/readBack");
101
102 tf.runApplication();
103
104 ctk::Device dev("Dummy0");
105 dev.open();
106 dev.write("MyModule/actuator", 2);
107
108 BOOST_TEST(rb.readNonBlocking() == false);
109 finger.write();
110 tf.stepApplication();
111 BOOST_TEST(rb.readNonBlocking() == true);
112 BOOST_TEST(rb == 2);
113
114 // Trigger device trigger - values should not change
115 tick.write();
116 tf.stepApplication();
117 BOOST_TEST(rb.readNonBlocking() == false);
118 BOOST_TEST(rb == 2);
119
120 dev.write("MyModule/actuator", 20);
121
122 // Trigger read-out of poll variables in main loop
123 finger.write();
124 tf.stepApplication();
125 BOOST_TEST(rb.readNonBlocking() == true);
126 BOOST_TEST(rb == 20);
127
128 // Trigger device trigger - values should not change
129 tick.write();
130 tf.stepApplication();
131 BOOST_TEST(rb.readNonBlocking() == false);
132 BOOST_TEST(rb == 20);
133 }
134 }
135
136 /********************************************************************************************************************/
137
139 TestApp2() : ctk::Application("testApp2") {}
140 ~TestApp2() override { shutdown(); }
141
142 struct : ctk::ApplicationModule {
143 using ctk::ApplicationModule::ApplicationModule;
144
145 ctk::ScalarPushInput<int> readBack{this, "/MyModule/readBack", "unit", "description"};
146
147 void mainLoop() override {
148 while(true) {
149 readAll();
150 }
151 }
152 } someModule{this, ".", ""};
153
156 };
157
158 /********************************************************************************************************************/
159
160 // Device that requires trigger, the trigger is 1:1 put into the CS
161 BOOST_AUTO_TEST_CASE(TestDev2AppWithCsDirectTrigger) {
162 // TestApp2 should not work without specifying any trigger
163 {
164 TestApp2 app;
165 app.dev = {&app, "Dummy0"};
166 BOOST_CHECK_THROW(
167 {
168 app.initialise();
169 app.run();
170 },
171 ChimeraTK::logic_error);
172 }
173
174 // TestApp2 also works with a trigger. If the trigger is triggered, no data transfer should happen
175 {
176 TestApp2 app;
177 app.dev = {&app, "Dummy0", "/cs/trigger"};
178
179 ChimeraTK::TestFacility tf{app, true};
180 auto tick = tf.getVoid("/cs/trigger");
181 auto rb = tf.getScalar<int>("/MyModule/readBack");
182
183 tf.runApplication();
184
185 ctk::Device dev("Dummy0");
186 dev.open();
187 dev.write("MyModule/actuator", 1);
188
189 tick.write();
190 tf.stepApplication();
191
192 BOOST_TEST(rb.readNonBlocking() == true);
193 BOOST_TEST(rb == 1);
194
195 dev.write("MyModule/actuator", 12);
196 BOOST_TEST(rb.readNonBlocking() == false);
197 BOOST_TEST(rb == 1);
198
199 tick.write();
200 tf.stepApplication();
201 BOOST_TEST(rb.readNonBlocking() == true);
202 BOOST_TEST(rb == 12);
203 }
204 }
205
206 /********************************************************************************************************************/
207 /********************************************************************************************************************/
208
210 TestApp3() : ctk::Application("testApp3") {}
211 ~TestApp3() override { shutdown(); }
212
213 struct : ctk::ApplicationModule {
214 using ctk::ApplicationModule::ApplicationModule;
215
216 ctk::VoidInput tick{this, "/cs/trigger", "description"};
217 ctk::ScalarOutput<int> tock{this, "/tock", "", ""};
218
219 void mainLoop() override {
220 tock = 0;
221 while(true) {
222 tock.write();
223 tock++;
224 readAll();
225 }
226 }
227 } tock{this, ".", ""};
228
229 struct : ctk::ApplicationModule {
230 using ctk::ApplicationModule::ApplicationModule;
231
232 ctk::ScalarPushInput<int> readBack{this, "/MyModule/readBack", "unit", "description"};
233 ctk::ScalarPollInput<int> tests{this, "/Deeper/hierarchies/need/tests", "unit", "description"};
234
235 void mainLoop() override {
236 while(true) {
237 readAll();
238 }
239 }
240 } someModule{this, ".", ""};
241
243 ctk::DeviceModule dev{this, "Dummy0", "/cs/trigger"};
244 };
245
246 /********************************************************************************************************************/
247
248 // Device that requires trigger, the trigger is distributed in the Application as well
249 BOOST_AUTO_TEST_CASE(TestDev2AppWithCsDistributedTrigger) {
250 TestApp3 app;
251
252 ChimeraTK::TestFacility tf{app, true};
253 auto tick = tf.getVoid("/cs/trigger");
254 auto tock = tf.getScalar<int>("/tock");
255 auto rb = tf.getScalar<int>("/MyModule/readBack");
256
257 tf.runApplication();
258
259 ctk::Device dev("Dummy0");
260 dev.open();
261 dev.write("MyModule/actuator", 1);
262
263 tick.write();
264 tf.stepApplication();
265
266 BOOST_TEST(tock.readNonBlocking() == true);
267 BOOST_TEST(tock == 1);
268 BOOST_TEST(rb.readNonBlocking() == true);
269 BOOST_TEST(rb == 1);
270
271 dev.write("MyModule/actuator", 12);
272 BOOST_TEST(tock.readNonBlocking() == false);
273 BOOST_TEST(tock == 1);
274 BOOST_TEST(rb.readNonBlocking() == false);
275 BOOST_TEST(rb == 1);
276
277 tick.write();
278 tf.stepApplication();
279 BOOST_TEST(tock.readNonBlocking() == true);
280 BOOST_TEST(tock == 2);
281 BOOST_TEST(rb.readNonBlocking() == true);
282 BOOST_TEST(rb == 12);
283 }
284
285 /********************************************************************************************************************/
286 /********************************************************************************************************************/
287
289 TestApp4() : ctk::Application("testApp4") {}
290 ~TestApp4() override { shutdown(); }
291
292 struct : ctk::ApplicationModule {
293 using ctk::ApplicationModule::ApplicationModule;
294
295 ctk::ScalarPushInput<float> singed32{this, "/Device/signed32", "unit", "description"};
296
297 void mainLoop() override {
298 while(true) {
299 readAll();
300 }
301 }
302 } someOtherModule{this, ".", ""};
303
304 struct : ctk::ApplicationModule {
305 using ctk::ApplicationModule::ApplicationModule;
306
307 ctk::ScalarPushInput<int> readBack{this, "/MyModule/readBack", "unit", "description"};
308 ctk::ScalarPollInput<int> tests{this, "/Deeper/hierarchies/need/tests", "unit", "description"};
309
310 void mainLoop() override {
311 while(true) {
312 readAll();
313 }
314 }
315 } someModule{this, ".", ""};
316
318 ctk::DeviceModule dev{this, "Dummy0", "/cs/trigger"};
319 ctk::DeviceModule dev2{this, "Dummy1Mapped", "/cs/trigger"};
320 };
321
322 /********************************************************************************************************************/
323
324 // Two devices using the same trigger
325 BOOST_AUTO_TEST_CASE(TestDev2App1Trigger2Devices) {
326 TestApp4 app;
327
328 ChimeraTK::TestFacility tf{app, true};
329 auto tick = tf.getVoid("/cs/trigger");
330 auto f = tf.getScalar<float>("/Device/signed32");
331 auto rb = tf.getScalar<int>("/MyModule/readBack");
332
333 ctk::Device dev("Dummy0");
334 dev.open();
335
336 ctk::Device dev2("Dummy1");
337 dev2.open();
338 dev2.write("FixedPoint/value", 12.4);
339
340 tf.runApplication();
341
342 dev.write("MyModule/actuator", 1);
343
344 BOOST_TEST(f.readNonBlocking() == false);
345 BOOST_TEST(rb.readNonBlocking() == false);
346
347 tick.write();
348 tf.stepApplication();
349 BOOST_TEST(f.readNonBlocking() == true);
350 BOOST_TEST(rb.readNonBlocking() == true);
351
352 BOOST_TEST((f - 12.4) < 0.01);
353 BOOST_TEST(rb == 1);
354
355 dev.write("MyModule/actuator", 2);
356 dev2.write("FixedPoint/value", 24.8);
357
358 BOOST_TEST(f.readNonBlocking() == false);
359 BOOST_TEST(rb.readNonBlocking() == false);
360
361 tick.write();
362 tf.stepApplication();
363 BOOST_TEST(f.readNonBlocking() == true);
364 BOOST_TEST(rb.readNonBlocking() == true);
365
366 BOOST_TEST((f - 24.8) < 0.001);
367 BOOST_TEST(rb == 2);
368 }
369
370 /********************************************************************************************************************/
371 /********************************************************************************************************************/
372
374 TestApp5() : ctk::Application("testApp5") {}
375 ~TestApp5() override { shutdown(); }
376
377 struct : ctk::ApplicationModule {
378 using ctk::ApplicationModule::ApplicationModule;
379
380 ctk::VoidInput finger{this, "/finger", ""};
381 ctk::VoidOutput trigger{this, "/trigger", ""};
382
383 void mainLoop() override {
384 while(true) {
385 readAll();
386 trigger.write();
387 }
388 }
389 } someModule{this, ".", ""};
390
393 };
394
395 /********************************************************************************************************************/
396
397 BOOST_AUTO_TEST_CASE(TestDev2CSCsTrigger) {
398 TestApp5 app;
399 app.dev = {&app, "Dummy0", "/cs/trigger"};
400
401 ChimeraTK::TestFacility tf{app, true};
402 auto tick = tf.getVoid("/cs/trigger");
403 auto rb = tf.getScalar<int>("/MyModule/readBack");
404
405 tf.runApplication();
406
407 ctk::Device dev("Dummy0");
408 dev.open();
409 dev.write("MyModule/actuator", 1);
410
411 tick.write();
412 tf.stepApplication();
413
414 BOOST_TEST(rb.readNonBlocking() == true);
415 BOOST_TEST(rb == 1);
416
417 dev.write("MyModule/actuator", 12);
418 BOOST_TEST(rb.readNonBlocking() == false);
419 BOOST_TEST(rb == 1);
420
421 tick.write();
422 tf.stepApplication();
423 BOOST_TEST(rb.readNonBlocking() == true);
424 BOOST_TEST(rb == 12);
425 }
426
427 /********************************************************************************************************************/
428
429 BOOST_AUTO_TEST_CASE(TestDev2CSAppTrigger) {
430 TestApp5 app;
431 app.dev = {&app, "Dummy0", "/trigger"};
432
433 ChimeraTK::TestFacility tf{app, true};
434 auto tick = tf.getVoid("/finger");
435 auto rb = tf.getScalar<int>("/MyModule/readBack");
436
437 tf.runApplication();
438
439 ctk::Device dev("Dummy0");
440 dev.open();
441 dev.write("MyModule/actuator", 1);
442
443 tick.write();
444 tf.stepApplication();
445
446 BOOST_TEST(rb.readNonBlocking() == true);
447 BOOST_TEST(rb == 1);
448
449 dev.write("MyModule/actuator", 12);
450 BOOST_TEST(rb.readNonBlocking() == false);
451 BOOST_TEST(rb == 1);
452
453 tick.write();
454 tf.stepApplication();
455 BOOST_TEST(rb.readNonBlocking() == true);
456 BOOST_TEST(rb == 12);
457 }
458
459 /********************************************************************************************************************/
460 /********************************************************************************************************************/
461
462 const std::string dummySdm{"(TestTransferGroupDummy?map=test_readonly.map)"};
463
464 // list of user types the accessors are tested with
465 using test_types = boost::mpl::list<int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, float, double>;
466
467 /********************************************************************************************************************/
468
469 class TestTransferGroupDummy : public ChimeraTK::DummyBackend {
470 public:
471 explicit TestTransferGroupDummy(const std::string& mapFileName) : DummyBackend(mapFileName) {}
472
473 // FIXME: This depends on the API from DeviceAccess. If this linter warning is fixed, code will not compile anymore
474 // NOLINTNEXTLINE(performance-unnecessary-value-param)
475 static boost::shared_ptr<DeviceBackend> createInstance(std::string, std::map<std::string, std::string> parameters) {
476 return boost::shared_ptr<DeviceBackend>(new TestTransferGroupDummy(parameters["map"]));
477 }
478
479 void read(uint64_t bar, uint64_t address, int32_t* data, size_t sizeInBytes) override {
480 lastBar = bar;
481 lastAddress = address;
482 lastSizeInBytes = sizeInBytes;
484 DummyBackend::read(bar, address, data, sizeInBytes);
485 }
486
487 std::atomic<size_t> numberOfTransfers{0};
488 std::atomic<uint64_t> lastBar;
489 std::atomic<uint64_t> lastAddress;
490 std::atomic<size_t> lastSizeInBytes;
491 };
492
493 /********************************************************************************************************************/
494 /* the ApplicationModule for the test is a template of the user type */
495
497 TestModule(ctk::ModuleGroup* owner, const std::string& name, const std::string& description,
498 const std::unordered_set<std::string>& tags = {})
499 : ApplicationModule(owner, name, description, tags), mainLoopStarted(2) {}
500
501 ctk::ScalarPushInput<int> consumingPush{this, "/REG1", "MV/m", "Description"};
502 ctk::ScalarPushInput<int> consumingPush2{this, "/REG2", "MV/m", "Description"};
503 ctk::ScalarPushInput<int> consumingPush3{this, "/REG3", "MV/m", "Description"};
504
505 ctk::ScalarOutput<int> theTrigger{this, "theTrigger", "MV/m", "Description"};
506
507 // We do not use testable mode for this test, so we need this barrier to synchronise to the beginning of the
508 // mainLoop(). This is required since the mainLoopWrapper accesses the module variables before the start of the
509 // mainLoop.
510 // execute this right after the Application::run():
511 // app.testModule.mainLoopStarted.wait(); // make sure the module's mainLoop() is entered
512 boost::barrier mainLoopStarted;
513
514 void prepare() override {
515 incrementDataFaultCounter(); // force data to be flagged as faulty
516 writeAll();
517 decrementDataFaultCounter(); // data validity depends on inputs
518 }
519
520 void mainLoop() override {
521 std::cout << "Start of main loop" << std::endl;
522 mainLoopStarted.wait();
523 std::cout << "End of main loop" << std::endl;
524 }
525 };
526
527 /********************************************************************************************************************/
528 /* dummy application */
529
531 TestApplication() : Application("testSuite") {
532 ChimeraTK::BackendFactory::getInstance().registerBackendType(
533 "TestTransferGroupDummy", &TestTransferGroupDummy::createInstance);
534 dev2 = {this, dummySdm, "/testModule/theTrigger"};
535 }
536 ~TestApplication() override { shutdown(); }
537
538 TestModule testModule{this, "testModule", "The test module"};
540 };
541
542 /********************************************************************************************************************/
543 /* test that multiple variables triggered by the same source are put into the
544 * same TransferGroup */
545
546 BOOST_AUTO_TEST_CASE(TestTriggerTransferGroup) {
547 std::cout << "***************************************************************"
548 "******************************************************"
549 << std::endl;
550 std::cout << "==> testTriggerTransferGroup" << std::endl;
551
552 ChimeraTK::BackendFactory::getInstance().setDMapFilePath("test.dmap");
553
554 TestApplication app;
555 auto pvManagers = ctk::createPVManager();
556 app.setPVManager(pvManagers.second);
557
559 dev.open(dummySdm);
560 auto backend = boost::dynamic_pointer_cast<TestTransferGroupDummy>(
561 ChimeraTK::BackendFactory::getInstance().createBackend(dummySdm));
562 BOOST_CHECK(backend != nullptr);
563
564 app.initialise();
565 app.run();
566 app.testModule.mainLoopStarted.wait(); // make sure the module's mainLoop() is entered
567
568 // initialise values
572 dev.write("/REG1.DUMMY_WRITEABLE", 11);
573 dev.write("/REG2.DUMMY_WRITEABLE", 22);
574 dev.write("/REG3.DUMMY_WRITEABLE", 33);
575
576 // from the initial value transfer
577 CHECK_TIMEOUT(backend->numberOfTransfers == 1, 10000);
578
579 // trigger the transfer
581 CHECK_TIMEOUT(backend->numberOfTransfers == 2, 10000);
582 BOOST_TEST(backend->lastBar == 0);
583 BOOST_TEST(backend->lastAddress == 0);
584
585 // We only explicitly connect the three registers in the app, but the connection code will also connect the other
586 // registers into the CS, hence we need to check for the full size
587 BOOST_TEST(backend->lastSizeInBytes == 32);
588
589 // check result
590 app.testModule.consumingPush.read();
591 app.testModule.consumingPush2.read();
592 app.testModule.consumingPush3.read();
593 BOOST_CHECK_EQUAL(app.testModule.consumingPush, 11);
594 BOOST_CHECK_EQUAL(app.testModule.consumingPush2, 22);
595 BOOST_CHECK_EQUAL(app.testModule.consumingPush3, 33);
596
597 // prepare a second transfer
598 dev.write("/REG1.DUMMY_WRITEABLE", 12);
599 dev.write("/REG2.DUMMY_WRITEABLE", 23);
600 dev.write("/REG3.DUMMY_WRITEABLE", 34);
601
602 // trigger the transfer
604 CHECK_TIMEOUT(backend->numberOfTransfers == 3, 10000);
605 BOOST_TEST(backend->lastBar == 0);
606 BOOST_TEST(backend->lastAddress == 0);
607
608 // We only explicitly connect the three registers in the app, but the connection code will also connect the other
609 // registers into the CS, hence we need to check for the full size
610 BOOST_TEST(backend->lastSizeInBytes == 32);
611
612 // check result
613 app.testModule.consumingPush.read();
614 app.testModule.consumingPush2.read();
615 app.testModule.consumingPush3.read();
616 BOOST_CHECK_EQUAL(app.testModule.consumingPush, 12);
617 BOOST_CHECK_EQUAL(app.testModule.consumingPush2, 23);
618 BOOST_CHECK_EQUAL(app.testModule.consumingPush3, 34);
619
620 dev.close();
621 }
622
623 /********************************************************************************************************************/
624 /********************************************************************************************************************/
625
626 /* dummy application */
627
629 TestApplication2() : Application("testSuite") {}
630 ~TestApplication2() override { shutdown(); }
631
632 std::atomic<bool> block{false};
633 std::latch confirmBlock{2};
634 std::latch unblock{2};
635
637 ctk::DeviceModule dev{this, "Dummy0", "/testModule/theTrigger", [&](ctk::Device&) {
638 if(block) {
639 std::cout << "Init Handler blocked." << std::endl;
640 confirmBlock.arrive_and_wait();
641 unblock.arrive_and_wait();
642 }
643 std::cout << "Init Handler completed." << std::endl;
644 }};
645 };
646
647 /********************************************************************************************************************/
648 /*
649 * Test that the init handler closing the device while executing does not interfer with the TransferGroup reading
650 * in the TriggerFanOut. See #14286 for background information.
651 *
652 * Just connecting a single variable to the control system with a trigger will already give us a TriggerFanOut which
653 * always uses internally a TransferGroup, so no complicated setup should be required here.
654 */
655
656 BOOST_AUTO_TEST_CASE(TestTriggerTransferGroupInitHandler) {
657 std::cout << "***************************************************************"
658 "******************************************************"
659 << std::endl;
660 std::cout << "==> TestTriggerTransferGroupInitHandler" << std::endl;
661
663
664 ctk::TestFacility test(app, false); // no testable mode, since we need to block the device recovery
665
666 auto trigger = test.getVoid("/testModule/theTrigger");
667 auto readBack = test.getScalar<int>("/MyModule/readBack");
668 auto devStatus = test.getScalar<int>("/Devices/Dummy0/status");
669
670 test.runApplication();
671
672 // await device to be opened
673 BOOST_REQUIRE(devStatus == 0);
674 devStatus.read();
675 BOOST_REQUIRE(devStatus == 1);
676
677 // trigger once and read the polled data, to make sure everything is running. Otherwise we would not (reliably)
678 // observe the failure below.
679 trigger.write();
680 readBack.read();
681
682 // trigger init handler and keep it blocked. The device will remain closed until the init handler is unblocked.
683 app.block = true;
684 app.dev.reportException("Force error");
685 app.confirmBlock.arrive_and_wait();
686
687 devStatus.read();
688 BOOST_REQUIRE(devStatus == 0);
689
690 // trigger the TriggerFanOut which will attempt to read from the closed device. The ExceptionHandlingDecorator
691 // should prevent this, so no logic_error should be thrown.
692 trigger.write();
693 // 0.5 seconds delay, give TriggerFanOut some time. In case of a bug, the logic_error will be thrown in the
694 // TriggerFanOut thread.
695 usleep(500000);
696
697 // unblock to finish recovery
698 app.block = false;
699 app.unblock.arrive_and_wait();
700 devStatus.read();
701 BOOST_REQUIRE(devStatus == 1);
702 }
703
704 /********************************************************************************************************************/
705
706} // namespace Tests::testTrigger
void run() override
Execute the module.
void initialise() 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.
void decrementDataFaultCounter() override
Decrement the fault counter and set the data validity flag to ok if the counter has reached 0.
void incrementDataFaultCounter() override
Set the data validity flag to fault and increment the fault counter.
void reportException(std::string errMsg)
Use this function to report an exception.
friend class Application
Definition ModuleGroup.h:47
void readAll(bool includeReturnChannels=false)
Read all readable variables in the group.
Definition Module.cc:72
void writeAll(bool includeReturnChannels=false)
Just call write() on all writable variables in the group.
Definition Module.cc:157
bool write(ChimeraTK::VersionNumber versionNumber)=delete
Convenience class for input scalar accessors with UpdateMode::push.
Helper class to set the DMAP file path.
Helper class to facilitate tests of applications based on ApplicationCore.
ChimeraTK::VoidRegisterAccessor getVoid(const ChimeraTK::RegisterPath &name) const
Obtain a void process variable from the application, which is published to the control system.
ChimeraTK::ScalarRegisterAccessor< T > getScalar(const ChimeraTK::RegisterPath &name) const
Obtain a scalar process variable from the application, which is published to the control system.
void runApplication() const
Start the application in testable mode.
bool write(ChimeraTK::VersionNumber versionNumber)=delete
TestTransferGroupDummy(const std::string &mapFileName)
static boost::shared_ptr< DeviceBackend > createInstance(std::string, std::map< std::string, std::string > parameters)
void read(uint64_t bar, uint64_t address, int32_t *data, size_t sizeInBytes) override
InvalidityTracer application module.
BOOST_AUTO_TEST_CASE(TestDev2AppWithPollTrigger)
boost::mpl::list< int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, float, double > test_types
const std::string dummySdm
Convenience class for output scalar accessors (always UpdateMode::push)
Convenience class for input scalar accessors with UpdateMode::poll.
Convenience class for input accessors.
Convenience class for output void (always UpdateMode::push)
ctk::ScalarPollInput< int > readBack
ctk::SetDMapFilePath path
ctk::ScalarPollInput< int > tests
ctk::SetDMapFilePath path
ctk::ScalarPushInput< int > readBack
ctk::ScalarOutput< int > tock
ctk::ScalarPollInput< int > tests
ctk::ScalarPushInput< int > readBack
ctk::SetDMapFilePath path
ctk::ScalarPushInput< float > singed32
ctk::SetDMapFilePath path
ctk::ScalarPushInput< int > readBack
ctk::ScalarPollInput< int > tests
ctk::SetDMapFilePath path
ctk::ScalarPushInput< int > consumingPush3
void prepare() override
Prepare the execution of the module.
ctk::ScalarPushInput< int > consumingPush2
ctk::ScalarPushInput< int > consumingPush
ctk::ScalarOutput< int > theTrigger
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
TestModule(ctk::ModuleGroup *owner, const std::string &name, const std::string &description, const std::unordered_set< std::string > &tags={})
#define CHECK_TIMEOUT(condition, maxMilliseconds)
ctk::ScalarOutput< uint64_t > tick
void mainLoop() override