ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
testReverseRecovery.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 "ScalarAccessor.h"
4
5#include <ChimeraTK/DeviceBackend.h>
6#include <ChimeraTK/ReadAnyGroup.h>
7#include <ChimeraTK/SharedDummyBackend.h>
8#include <ChimeraTK/TransferElement.h>
9#include <ChimeraTK/VoidRegisterAccessor.h>
10
11#include <boost/smart_ptr/shared_ptr.hpp>
12
13#define BOOST_TEST_MODULE reverseRecoveryTest
14
15#include "Application.h"
16#include "ApplicationModule.h"
17#include "check_timeout.h"
18#include "DeviceModule.h"
19#include "Logger.h"
20#include "ScalarAccessor.h"
21#include "TestFacility.h"
22
23#include <ChimeraTK/BackendFactory.h>
24#include <ChimeraTK/Device.h>
25
26#include <boost/test/included/unit_test.hpp>
27
28#include <cstdint>
29
30namespace ctk = ChimeraTK;
31
33 using ctk::ApplicationModule::ApplicationModule;
34
35 std::function<void()> doMainLoop;
36
37 void mainLoop() final { doMainLoop(); }
38};
40 TestApplication() : ctk::Application("tagTestApplication") { debugMakeConnections(); }
41 ~TestApplication() override { shutdown(); }
42
43 ExternalMainLoopModule mod{this, "Module", ""};
44};
45
46/**********************************************************************************************************************/
47
48BOOST_AUTO_TEST_CASE(testDirectThreadedFanOutWithReturn) {
49 std::cout << "testDirectThreadedFanOutWithReturn" << std::endl;
50
51 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
52
54 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
55
56 std::atomic<bool> up{false};
57
58 app.mod.doMainLoop = [&]() {
59 up = true;
60 up.notify_one();
61 };
62
63 ctk::TestFacility test(app, false);
64
65 ctk::Device dev;
66 dev.open("baseDevice");
67
68 // Initialize the device with some values
69 dev.write<int32_t>("/readWrite", 4);
70 dev.write<int32_t>("/writeOnlyRB.DUMMY_WRITEABLE", 8);
71 dev.write<int32_t>("/secondReadWrite", 16);
72
73 // Set initial values for the variables
74 test.setScalarDefault<int32_t>("/taggedReadWrite", 12);
75 test.setScalarDefault<int32_t>("/taggedWriteOnly", 24);
76 test.setScalarDefault<int32_t>("/untagged", 36);
77
78 test.runApplication();
79
80 // Wait for the device to become ready
81 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
82
83 up.wait(false);
84
85 auto taggedReadWriteCs = test.getScalar<int32_t>("/taggedReadWrite");
86 auto taggedWriteOnlyCs = test.getScalar<int32_t>("/taggedWriteOnly");
87 auto untagged = test.getScalar<int32_t>("/untagged");
88
89 // Check that the values are still on the values we have written explicitly
90 // into the device, and not the initial values we configured above
91 BOOST_TEST(dev.read<int32_t>("/readWrite") == 4);
92 BOOST_TEST(dev.read<int32_t>("/writeOnlyRB") == 8);
93
94 // Check that instead those values have been propagated to the CS (where applicable)
95 CHECK_EQUAL_TIMEOUT((taggedReadWriteCs.readLatest(), int(taggedReadWriteCs)), 4, 2000);
96
97 // The untagged register should have received the initial value from the CS
98 BOOST_TEST(dev.read<int32_t>("/secondReadWrite") == 36);
99
100 // Just do normal operations
101 taggedReadWriteCs.setAndWrite(48);
102 taggedWriteOnlyCs.setAndWrite(96);
103 untagged.setAndWrite(128);
104
105 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 48, 2000);
106 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/writeOnlyRB"), 96, 2000);
107 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/secondReadWrite"), 128, 2000);
108
109 dev.write<int32_t>("/readWrite", 3);
110 dev.write<int32_t>("/writeOnlyRB.DUMMY_WRITEABLE", 7);
111 dev.write<int32_t>("/secondReadWrite", 15);
112 devModule.reportException("Trigger device recovery");
113
114 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 1, 1000);
115 // Wait for ApplicationCore to recover
116 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
117
118 // The two tagged registers should keep their values, the untagged register should receive the value written before
119 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 3, 1000);
120 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/writeOnlyRB"), 7, 1000);
121 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/secondReadWrite"), 128, 1000);
122
123 // The read-write register should have propagated its value to the CS
124 CHECK_EQUAL_TIMEOUT((taggedReadWriteCs.readLatest(), int32_t(taggedReadWriteCs)), 3, 2000);
125
126 app.shutdown();
127}
128
129/**********************************************************************************************************************/
130
131// Create a ThreadedFanOutWithReturn and check that we can use the
132// just the recovery value as an input
133BOOST_AUTO_TEST_CASE(testThreadedFanOutWithReturnOnlyRecoverValue) {
134 std::cout << "testThreadedFanOutWithReturnOnlyRecoverValue" << std::endl;
135 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
136
137 ctk::Device dev;
138 dev.open("baseDevice");
139
140 // Initialize the device with some values
141 dev.write<int32_t>("/readWrite", 4);
142
143 TestApplication app;
144 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
145
146 std::atomic<bool> up{false};
147
148 ctk::ScalarPushInput<int32_t> deviceInput{&app.mod, "/taggedReadWrite", "", ""};
149
150 app.mod.doMainLoop = [&]() {
151 up = true;
152 up.notify_one();
153 };
154
155 ctk::TestFacility test(app, false);
156
157 // Set initial values for the variables
158 test.setScalarDefault<int32_t>("/taggedReadWrite", 12);
159
160 test.runApplication();
161 up.wait(false);
162
163 // Check that the device did not receive the initial value in this setup
164 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 4, 1000);
165
166 // Check that the input is having the value from the device
167 CHECK_EQUAL_TIMEOUT(deviceInput, 4, 1000);
168
169 dev.write<int32_t>("/readWrite", 8);
170 devModule.reportException("Trigger device recovery");
171
172 // Wait for ApplicationCore to recover
173 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 1, 1000);
174 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
175
176 deviceInput.read();
177 CHECK_EQUAL_TIMEOUT(int32_t(deviceInput), 8, 1000);
178 app.shutdown();
179}
180
181/**********************************************************************************************************************/
182
183// Force the connection maker to create a direct connection with constant
184// feeder
185BOOST_AUTO_TEST_CASE(testConstantFeederInversion) {
186 std::cout << "testConstantFeederInversion" << std::endl;
187
188 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
189
190 ctk::Device dev;
191 dev.open("baseDevice");
192
193 // Initialize the device with some values
194 dev.write<int32_t>("/readWrite", 4);
195
196 TestApplication app;
197 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
198
199 std::atomic<bool> up{false};
200
201 ctk::ScalarPushInput<int32_t> deviceInput{&app.mod, "/taggedReadWrite", "", ""};
202
203 app.mod.doMainLoop = [&]() {
204 up = true;
205 up.notify_one();
206 };
207
208 ctk::TestFacility test(app, false);
209
210 app.optimiseUnmappedVariables({"/taggedReadWrite"});
211 test.runApplication();
212 up.wait(false);
213
214 CHECK_EQUAL_TIMEOUT(int32_t(deviceInput), 4, 1000);
215 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 4, 1000);
216
217 devModule.reportException("Trigger device recovery");
218
219 // Wait for ApplicationCore to recover
220 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 1, 1000);
221 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
222
223 deviceInput.read();
224 CHECK_EQUAL_TIMEOUT(int32_t(deviceInput), 4, 1000);
225 app.shutdown();
226}
227
228/**********************************************************************************************************************/
229
230// Have an application module that has an explicit accessor requesting reverse recovery
231BOOST_AUTO_TEST_CASE(testFeedingFanOutWithExplicitAccessor) {
232 std::cout << "testFeedingFanOutWithExplicitAccessor" << std::endl;
233
234 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
235
236 ctk::Device dev;
237 dev.open("baseDevice");
238
239 // Initialize the device with some values
240 dev.write<int32_t>("/readWrite", 4);
241
242 TestApplication app;
243 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
244
245 std::atomic<bool> up{false};
246
247 ctk::ScalarOutputReverseRecovery<int32_t> deviceInput{&app.mod, "/taggedReadWrite", "", ""};
248
249 app.mod.doMainLoop = [&]() {
250 up = true;
251 up.notify_one();
252 };
253
254 ctk::TestFacility test(app, false);
255
256 test.runApplication();
257 up.wait(false);
258
259 CHECK_EQUAL_TIMEOUT((int32_t(deviceInput)), 4, 1000);
260 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 4, 1000);
261
262 // Check that we can still write down to the device properly
263 deviceInput.setAndWrite(44);
264 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 44, 1000);
265
266 // Manipulate the device so we can check that the value is propagated
267 // from the device to the application, as expected, after the device recovers
268 dev.write<int32_t>("/readWrite", 111);
269
270 devModule.reportException("Trigger device recovery");
271
272 // Wait for ApplicationCore to recover
273 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 1, 1000);
274 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
275
276 deviceInput.read();
277 CHECK_EQUAL_TIMEOUT(int32_t(deviceInput), 111, 1000);
278 app.shutdown();
279}
280
281/**********************************************************************************************************************/
282
283// Have an application module that has an explicit accessor requesting reverse recovery
284BOOST_AUTO_TEST_CASE(testFanOutWithExplicitAccessor02) {
285 std::cout << "testFanOutWithExplicitAccessor02" << std::endl;
286 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
287
288 ctk::Device dev;
289 dev.open("baseDevice");
290
291 // Initialize the device with some values
292 dev.write<int32_t>("/readWrite", 4);
293
294 TestApplication app;
295 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
296
297 std::atomic<bool> up{false};
298
299 ctk::ScalarOutputReverseRecovery<int32_t> deviceInput{&app.mod, "/taggedReadWrite", "", ""};
300
301 app.mod.doMainLoop = [&]() {
302 up = true;
303 up.notify_one();
304 };
305
306 ctk::TestFacility test(app, false);
307
308 app.optimiseUnmappedVariables({"/taggedReadWrite"});
309 test.runApplication();
310 up.wait(false);
311
312 CHECK_EQUAL_TIMEOUT((int32_t(deviceInput)), 4, 1000);
313 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 4, 1000);
314
315 // Check that we can still write down to the device properly
316 deviceInput.setAndWrite(44);
317 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 44, 1000);
318
319 // Manipulate the device so we can check that the value is propagated
320 // from the device to the application, as expected, after the device recovers
321 dev.write<int32_t>("/readWrite", 111);
322
323 devModule.reportException("Trigger device recovery");
324
325 // Wait for ApplicationCore to recover
326 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 1, 1000);
327 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
328
329 deviceInput.read();
330 CHECK_EQUAL_TIMEOUT(int32_t(deviceInput), 111, 1000);
331 app.shutdown();
332}
333
334// Have an application module that has an explicit accessor requesting reverse recovery
335BOOST_AUTO_TEST_CASE(testFanOutWithExplicitAccessor03) {
336 std::cout << "testFanOutWithExplicitAccessor03" << std::endl;
337 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
338
339 ctk::Device dev;
340 dev.open("baseDevice");
341
342 // Initialize the device with some values
343 dev.write<int32_t>("/readWrite", 4);
344
345 TestApplication app;
346 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
347
348 std::atomic<bool> up{false};
349
350 ctk::ScalarPushInput<int32_t> deviceInput{&app.mod, "/taggedReadWrite", "", ""};
351
352 app.mod.doMainLoop = [&]() {
353 up = true;
354 up.notify_one();
355 };
356
357 ctk::TestFacility test(app, false);
358
359 app.optimiseUnmappedVariables({"/taggedReadWrite"});
360 test.runApplication();
361 up.wait(false);
362
363 CHECK_EQUAL_TIMEOUT((int32_t(deviceInput)), 4, 1000);
364 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 4, 1000);
365
366 // Check that we can still write down to the device properly
367 deviceInput.setAndWrite(44);
368 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/readWrite"), 44, 1000);
369
370 // Manipulate the device so we can check that the value is propagated
371 // from the device to the application, as expected, after the device recovers
372 dev.write<int32_t>("/readWrite", 111);
373
374 devModule.reportException("Trigger device recovery");
375
376 // Wait for ApplicationCore to recover
377 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 1, 1000);
378 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
379
380 deviceInput.read();
381 CHECK_EQUAL_TIMEOUT(int32_t(deviceInput), 111, 1000);
382 app.shutdown();
383}
384
385/**********************************************************************************************************************/
386
387// Request that we do the reverse recovery from an untagged device register by using the ReverseRecovery accessor
388BOOST_AUTO_TEST_CASE(testReverseRecoveryFromApp) {
389 std::cout << "testReverseRecoveryFromApp" << std::endl;
390
391 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
392
393 ctk::Device dev;
394 dev.open("baseDevice");
395
396 // Initialize the device with some values
397 dev.write<int32_t>("/secondReadWrite", 815);
398
399 TestApplication app;
400
401 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
402
403 std::atomic<bool> up{false};
404
405 ctk::ScalarOutputReverseRecovery<int32_t> deviceInput{&app.mod, "/untagged", "", ""};
406
407 app.mod.doMainLoop = [&]() {
408 up = true;
409 up.notify_one();
410 };
411
412 ctk::TestFacility test(app, false);
413 test.setScalarDefault("/untagged", 4711);
414
415 test.runApplication();
416
417 // Wait for the device to become ready
418 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
419
420 up.wait(false);
421 auto untagged = test.getScalar<int32_t>("/untagged");
422
423 BOOST_TEST(dev.read<int32_t>("/secondReadWrite") == 815);
424
425 deviceInput.setAndWrite(128);
426 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/secondReadWrite"), 128, 2000);
427
428 dev.write<int32_t>("/secondReadWrite", 3);
429 devModule.reportException("Trigger device recovery");
430
431 // Wait for ApplicationCore to recover
432 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 1, 1000);
433 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
434
435 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/secondReadWrite"), 3, 2000);
436
437 app.shutdown();
438}
439
440/**********************************************************************************************************************/
441
442BOOST_AUTO_TEST_CASE(testRecoveryFromAppDirect) {
443 std::cout << "testReverseRecoveryFromAppDirect" << std::endl;
444
445 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
446
447 ctk::Device dev;
448 dev.open("baseDevice");
449
450 // Initialize the device with some values
451 dev.write<int32_t>("/secondReadWrite", 815);
452
453 TestApplication app;
454 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
455
456 std::atomic<bool> up{false};
457
458 ctk::ScalarOutputReverseRecovery<int32_t> deviceInput{&app.mod, "/untagged", "", ""};
459
460 app.mod.doMainLoop = [&]() {
461 up = true;
462 up.notify_one();
463 };
464
465 ctk::TestFacility test(app, false);
466 test.setScalarDefault("/untagged", 4711);
467 app.optimiseUnmappedVariables({"/untagged"});
468 test.runApplication();
469
470 // Wait for the device to become ready
471 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
472
473 up.wait(false);
474 auto untagged = test.getScalar<int32_t>("/untagged");
475
476 BOOST_TEST(dev.read<int32_t>("/secondReadWrite") == 815);
477
478 deviceInput.setAndWrite(128);
479 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/secondReadWrite"), 128, 2000);
480
481 dev.write<int32_t>("/secondReadWrite", 3);
482 devModule.reportException("Trigger device recovery");
483
484 // Wait for ApplicationCore to recover
485 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 1, 1000);
486 CHECK_EQUAL_TIMEOUT(test.readScalar<int32_t>("/Devices/taggedDevice/status"), 0, 1000);
487
488 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/secondReadWrite"), 3, 2000);
489
490 app.shutdown();
491}
492
493/**********************************************************************************************************************/
494
495// Special case: Reverse recovery, but without any device
496BOOST_AUTO_TEST_CASE(testReverseRecoveryFromCS) {
497 std::cout << "testReverseRecoveryFromCS" << std::endl;
498 TestApplication app;
499
500 std::atomic<bool> up{false};
501
502 ctk::ScalarOutputReverseRecovery<int32_t> csOutput{&app.mod, "/taggedReadWrite", "", ""};
503
504 app.mod.doMainLoop = [&]() {
505 up = true;
506 up.notify_one();
507 };
508
509 ctk::TestFacility test(app, false);
510
511 test.setScalarDefault("/taggedReadWrite", 4711);
512
513 test.runApplication();
514 up.wait(false);
515
516 CHECK_EQUAL_TIMEOUT(csOutput, 4711, 2000);
517
518 app.shutdown();
519}
520
521/**********************************************************************************************************************/
522
523BOOST_AUTO_TEST_CASE(testReverseRecoveryWithAdditionalInput) {
524 std::cout << "testReverseRecoveryWithAdditionalInput" << std::endl;
525
526 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
527
528 TestApplication app;
529 ExternalMainLoopModule mod2{&app, "Module2", ""};
530
531 // One module with an ouptut that has reverse recovery, and another module that takes this as
532 // input
533 ctk::ScalarOutputReverseRecovery<uint32_t> out{&app.mod, "/Out/a", "", ""};
534 ctk::ScalarPushInput<uint32_t> in{&mod2, "/Out/a", "", ""};
535
536 std::atomic<bool> up{false};
537 std::atomic<bool> up2{false};
538
539 app.mod.doMainLoop = [&]() {
540 up = true;
541 up.notify_one();
542 };
543
544 mod2.doMainLoop = [&]() {
545 up2 = true;
546 up2.notify_one();
547 };
548
549 ctk::TestFacility test(app, false);
550 test.setScalarDefault<uint32_t>("/Out/a", 32);
551
552 test.runApplication();
553 up.wait(false);
554 up2.wait(false);
555
556 CHECK_EQUAL_TIMEOUT(out, 32, 2000);
557 CHECK_EQUAL_TIMEOUT(in, 32, 2000);
558
559 app.shutdown();
560}
561
562/**********************************************************************************************************************/
563
564BOOST_AUTO_TEST_CASE(testReverseRecoveryPromotingDeviceWoToFeeder) {
565 std::cout << "testReverseRecoveryPromotingDeviceWoToFeeder" << std::endl;
566
567 // This test just checks that we can connect this network successfully
568 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
569
570 TestApplication app;
571
572 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
573
574 ctk::Device dev;
575 dev.open("baseDevice");
576 dev.write<int32_t>("/writeOnlyRB.DUMMY_WRITEABLE", 8);
577
578 // Nothing to do
579 app.mod.doMainLoop = [&]() {};
580
581 ctk::TestFacility test(app, false);
582 app.optimiseUnmappedVariables({"/taggedWriteOnly"});
583
584 test.runApplication();
585
586 std::this_thread::sleep_for(std::chrono::seconds(1));
587
588 BOOST_TEST(dev.read<int32_t>("/writeOnlyRB") == 8);
589 app.shutdown();
590}
591
592/**********************************************************************************************************************/
593
594BOOST_AUTO_TEST_CASE(testReverseRecoveryNetworkWoOptimized) {
595 std::cout << "testReverseRecoveryNetworkWoOptimized" << std::endl;
596
597 // This test just checks that we can connect this network successfully
598 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
599
600 TestApplication app;
601
602 std::atomic<bool> up{false};
603
604 ctk::DeviceModule devModule{&app, "taggedDevice", "/trigger"};
605 ctk::ScalarPushInput<int32_t> modIn{&app.mod, "/taggedWriteOnly", "", ""};
606
607 ctk::Device dev;
608 dev.open("baseDevice");
609 dev.write<int32_t>("/writeOnlyRB.DUMMY_WRITEABLE", 8);
610
611 // Nothing to do
612 app.mod.doMainLoop = [&]() {
613 up = true;
614 up.notify_one();
615 };
616
617 ctk::TestFacility test(app, false);
618 test.setScalarDefault<int32_t>("/taggedWriteOnly", 12);
619 app.optimiseUnmappedVariables({"/taggedWriteOnly"});
620
621 test.runApplication();
622 up.wait(false);
623
624 // Gets value from constant feeder
625 CHECK_EQUAL_TIMEOUT(int(modIn), 0, 2000);
626
627 CHECK_EQUAL_TIMEOUT(dev.read<int32_t>("/writeOnlyRB"), 8, 2000);
628 app.shutdown();
629}
630
631/**********************************************************************************************************************/
632
633BOOST_AUTO_TEST_CASE(testReverseRecoveryBitAccessorFanOut) {
634 std::cout << "testReverseRecoveryBitAccessorFanOut" << std::endl;
635
636 // This test just checks that we can connect this network successfully
637 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
638
639 TestApplication app;
640
641 ctk::DeviceModule devModule{&app, "bitMappedDevice", "/trigger"};
642
643 ctk::Device dev;
644 dev.open("baseDevice");
645 dev.write<int32_t>("/readWrite", 0x7fff);
646
647 // Nothing to do
648 app.mod.doMainLoop = [&]() {};
649
650 ctk::TestFacility test(app, false);
651 test.setScalarDefault<ctk::Boolean>("/bit3", false);
652 test.runApplication();
653
654 std::this_thread::sleep_for(std::chrono::seconds(1));
655
656 BOOST_TEST(dev.read<int32_t>("/readWrite") == 0x7FFF);
657 app.shutdown();
658}
659
660/**********************************************************************************************************************/
661
662BOOST_AUTO_TEST_CASE(testReverseRecoveryBitAccessorDirect) {
663 std::cout << "testReverseRecoveryBitAccessorFanOut" << std::endl;
664
665 // This test just checks that we can connect this network successfully
666 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
667
668 TestApplication app;
669
670 ctk::DeviceModule devModule{&app, "bitMappedDevice", "/trigger"};
671
672 ctk::Device dev;
673 dev.open("baseDevice");
674 dev.write<int32_t>("/readWrite", 0x7fff);
675
676 // Nothing to do
677 app.mod.doMainLoop = [&]() {
678
679 };
680
681 ctk::TestFacility test(app, false);
682 test.setScalarDefault<ctk::Boolean>("/bit3", false);
683 app.optimiseUnmappedVariables({"/bit3"});
684 test.runApplication();
685
686 std::this_thread::sleep_for(std::chrono::seconds(1));
687
688 BOOST_TEST(dev.read<int32_t>("/readWrite") == 0x7FFF);
689 app.shutdown();
690}
691
692/**********************************************************************************************************************/
693
694BOOST_AUTO_TEST_CASE(testReverseRecoveryBitAccessorMultipleInModule) {
695 std::cout << "testReverseRecoveryBitAccessorMultipleInModule" << std::endl;
696
697 // Regression test whether this setup deadlocks itself
698 ctk::BackendFactory::getInstance().setDMapFilePath("testTagged.dmap");
699
700 TestApplication app;
701
702 ctk::DeviceModule devModule{&app, "bitMappedDevice", "/trigger"};
703 ctk::ScalarPollInput<ctk::Boolean> bit0{&app.mod, "/bit0", "", ""};
704 ctk::ScalarOutput<ctk::Boolean> bit1{&app.mod, "/bit1", "", ""};
705 ctk::ScalarOutput<ctk::Boolean> bit2{&app.mod, "/bit2", "", ""};
706 ctk::ScalarPollInput<ctk::Boolean> bit3{&app.mod, "/bit3", "", ""};
707 ctk::ScalarOutput<ctk::Boolean> bit4{&app.mod, "/bit4", "", ""};
708 ctk::ScalarOutput<ctk::Boolean> bit5{&app.mod, "/bit5", "", ""};
709 ctk::ScalarPollInput<ctk::Boolean> bit6{&app.mod, "/bit6", "", ""};
710 ctk::ScalarOutput<ctk::Boolean> bit7{&app.mod, "/bit7", "", ""};
711 ctk::ScalarOutput<ctk::Boolean> bit8{&app.mod, "/bit8", "", ""};
712
713 ctk::Device dev;
714 dev.open("baseDevice");
715 dev.write<int32_t>("/readWrite", 0x7fff);
716
717 std::atomic<bool> up{false};
718
719 // Nothing to do
720 app.mod.doMainLoop = [&]() {
721 up = true;
722 up.notify_all();
723 };
724
725 ctk::TestFacility test(app, false);
726 test.runApplication();
727
728 test.getVoid("/trigger").write();
729
730 up.wait(false);
731
732 // sanity check if the reverse recovery for the output bits still holds
733 BOOST_TEST(dev.read<int32_t>("/readWrite") == 0x7FFF);
734
735 app.shutdown();
736}
737
738/**********************************************************************************************************************/
#define CHECK_EQUAL_TIMEOUT(left, right, maxMilliseconds)
void debugMakeConnections()
Enable debug output for the ConnectionMaker.
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.
friend class Application
Definition ModuleGroup.h:47
Convenience class for input scalar accessors with UpdateMode::push.
Helper class to facilitate tests of applications based on ApplicationCore.
TYPE readScalar(const std::string &name)
Convenience function to read the latest value of a scalar process variable in a single call.
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.
void setScalarDefault(const ChimeraTK::RegisterPath &name, const T &value)
Set default value for scalar process variable.
InvalidityTracer application module.
Convenience class for output scalar accessors (always UpdateMode::push)
Convenience class for output scalar accessors with return channel ("read back") (always UpdateMode::p...
Convenience class for input scalar accessors with UpdateMode::poll.
std::function< void()> doMainLoop
void mainLoop() final
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ExternalMainLoopModule mod
BOOST_AUTO_TEST_CASE(testDirectThreadedFanOutWithReturn)