ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
fixtures.h
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#pragma once
4
5#include "Application.h"
6#include "ApplicationModule.h"
7#include "DeviceManager.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#include <ChimeraTK/NDRegisterAccessor.h>
17
18#include <future>
19
20/**********************************************************************************************************************/
21/**********************************************************************************************************************/
22
27 std::promise<void> p;
28 void mainLoop() override { p.set_value(); }
29};
30
31/**********************************************************************************************************************/
32
37 ChimeraTK::ScalarPushInput<int> pushInput{this, "../REG1_PUSHED", "", ""};
38 } reg1{this, "PushModule", ""};
39
40 std::promise<void> p;
41 void mainLoop() override { p.set_value(); }
42};
43
44/**********************************************************************************************************************/
45
50 ChimeraTK::ScalarPushInput<int> pushInput{this, "../REG1_PUSHED", "", ""};
51 ChimeraTK::ScalarPushInput<int> pushInputCopy{this, "../REG1_PUSHED", "", ""};
52 } reg1{this, "PushModuleForFanOut", ""};
53
54 std::promise<void> p;
55 void mainLoop() override { p.set_value(); }
56};
57
58/**********************************************************************************************************************/
59
66 } reg1{this, "PushModuleForTrigger", ""};
67
68 std::promise<void> p;
69 void mainLoop() override { p.set_value(); }
70};
71
72/**********************************************************************************************************************/
73
76 // Note: REG1 is not writeable. REG1.DUMMY_WRITEABLE is not part of the catalogue and hence cannot be used.
79 ChimeraTK::ScalarOutput<int> trigger{this, "trigger", "", ""}; // must not be connected to any device
81 std::promise<void> p;
82 void prepare() override { writeAll(); }
83 void mainLoop() override { p.set_value(); }
84};
85
86/**********************************************************************************************************************/
87
89 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:1?map=test_with_push.map)";
90 constexpr static const char* ExceptionDummyCDD2 = "(ExceptionDummy:2?map=test_with_push.map)";
91 constexpr static const char* ExceptionDummyCDD3 = "(ExceptionDummy:3?map=test_with_push.map)";
92
93 DummyApplication() : Application("DummyApplication") {
94 // enable this for debugging:
95 // debugMakeConnections();
96 }
97 ~DummyApplication() override { shutdown(); }
98
106
110 PushModuleForTrigger pushModule2{this, ".", "With TriggerFanOut"};
111 PushModuleForFanOut pushModule3{this, ".", "With ThreadedFanOut"};
112 // PollModule pollModule2{this, ".", ""};
114 } group2{this, "Group2", ""};
115
121};
122
123/**********************************************************************************************************************/
124/**********************************************************************************************************************/
125
126template<bool enableTestFacility, bool addInitHandlers = false, bool breakSecondDeviceAtStart = false>
129
131
132 template<typename T>
133 auto read(ChimeraTK::DummyRegisterRawAccessor& accessor);
134
135 template<typename T>
136 auto read(ChimeraTK::DummyRegisterRawAccessor&& accessor);
137
138 template<typename T>
139 void write(ChimeraTK::DummyRegisterRawAccessor& accessor, T value);
140
141 template<typename T>
142 void write(ChimeraTK::DummyRegisterRawAccessor&& accessor, T value);
143
144 bool isDeviceInError();
145
146 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend;
147 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend2;
148 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend3;
151
152 ChimeraTK::ScalarRegisterAccessor<int> status, status2;
153 ChimeraTK::VoidRegisterAccessor deviceBecameFunctional;
154 ChimeraTK::ScalarRegisterAccessor<std::string> message;
155 ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister;
156 ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister2;
157 ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister3;
158 ChimeraTK::DummyRegisterRawAccessor exceptionDummy2Register;
159
160 ChimeraTK::ScalarPushInput<int>& pushVariable{application.group1.pushModule.reg1.pushInput};
163 ChimeraTK::ScalarOutput<int>& outputVariable2{application.group1.outputModule.deviceRegister2};
164 ChimeraTK::ScalarOutput<int>& outputVariable3{application.group1.outputModule.deviceRegister3};
165 ChimeraTK::VoidOutput& outputVariableV{application.group1.outputModule.deviceRegisterV};
166
167 ChimeraTK::ScalarPushInput<int>& triggeredInput{application.group2.pushModule2.reg1.pushInput};
168
169 ChimeraTK::ScalarPushInput<int>& pushVariable3{application.group2.pushModule3.reg1.pushInput};
170 ChimeraTK::ScalarPushInput<int>& pushVariable3copy{application.group2.pushModule3.reg1.pushInputCopy};
172
173 ChimeraTK::VoidRegisterAccessor interrupt;
174
175 std::atomic<bool> initHandler1Throws{false};
176 std::atomic<bool> initHandler2Throws{false};
177 std::atomic<bool> initHandler1Called{false};
178 std::atomic<bool> initHandler2Called{false};
179};
180
181/**********************************************************************************************************************/
182
183template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
184FixtureWithPollAndPushInput<enableTestFacility, addInitHandlers,
185 breakSecondDeviceAtStart>::FixtureWithPollAndPushInput()
186: deviceBackend(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
187 ChimeraTK::BackendFactory::getInstance().createBackend(DummyApplication::ExceptionDummyCDD1))),
188 deviceBackend2(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
189 ChimeraTK::BackendFactory::getInstance().createBackend(DummyApplication::ExceptionDummyCDD2))),
190 deviceBackend3(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
191 ChimeraTK::BackendFactory::getInstance().createBackend(DummyApplication::ExceptionDummyCDD3))),
192 exceptionDummyRegister(deviceBackend->getRawAccessor("", "REG1.DUMMY_WRITEABLE")),
193 exceptionDummyRegister2(deviceBackend->getRawAccessor("", "REG2")),
194 exceptionDummyRegister3(deviceBackend->getRawAccessor("", "REG3")),
195 exceptionDummy2Register(deviceBackend2->getRawAccessor("", "REG1.DUMMY_WRITEABLE")) {
196 try {
197 deviceBackend2->throwExceptionOpen = breakSecondDeviceAtStart;
198
199 if constexpr(addInitHandlers) {
200 auto initHandler1 = [this](ChimeraTK::Device& dev) {
201 if(&dev == &application.group1.device.getDeviceManager().getDevice()) {
202 initHandler1Called = true;
204 throw ChimeraTK::runtime_error("Init handler 1 throws by request");
205 }
206 }
207 };
208 auto initHandler2 = [this](ChimeraTK::Device& dev) {
209 if(&dev == &application.group1.device.getDeviceManager().getDevice()) {
210 initHandler2Called = true;
212 throw ChimeraTK::runtime_error("Init handler 2 throws by request");
213 }
214 }
215 };
216 application.group1.device.addInitialisationHandler(initHandler1);
217 application.group1.device.addInitialisationHandler(initHandler2);
218 }
219
220 // Make sure that some variables are not connected to the control system, to allow testing direct device-to-app
221 // connections without a ThreadedFanOut in between:
222 // "/Group1/REG1_PUSHED" aka "application.group1.pushModule.reg1.pushInput" aka "pushVariable"
223 // "/Group1/REG1_WRITE" aka "application.group1.outputModule.deviceRegister" aka "outputVariable"
224 application.optimiseUnmappedVariables({"/Group1/REG1_PUSHED", "/Group1/REG2"});
225
227
230 status.replace(testFacitiy.getScalar<int>(ChimeraTK::RegisterPath("/Devices") / dm1 / "status"));
231 message.replace(testFacitiy.getScalar<std::string>(ChimeraTK::RegisterPath("/Devices") / dm1 / "status_message"));
233 testFacitiy.getVoid(ChimeraTK::RegisterPath("/Devices") / dm1 / "deviceBecameFunctional"));
234
235 status2.replace(testFacitiy.getScalar<int>(ChimeraTK::RegisterPath("/Devices") / dm2 / "status"));
236
238 interrupt.replace(dev.getVoidRegisterAccessor("DUMMY_INTERRUPT_1"));
239
240 // wait until all modules have been properly started, to ensure the initial value propagation is complete
241 application.group1.pollModule.p.get_future().wait();
242 application.group1.pushModule.p.get_future().wait();
243 application.group1.outputModule.p.get_future().wait();
244 if(!breakSecondDeviceAtStart) {
245 application.group2.outputModule2.p.get_future().wait();
246 // application.group2.pollModule2.p.get_future().wait();
247 application.group2.pushModule2.p.get_future().wait();
248 application.group2.pushModule3.p.get_future().wait();
249 }
250 application.group3.pollModule3.p.get_future().wait();
252 }
253 catch(std::exception& e) {
254 std::cout << "Exception caught in constructor: " << e.what() << std::endl;
255 throw;
256 }
257}
258
259/**********************************************************************************************************************/
260
261template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
262FixtureWithPollAndPushInput<enableTestFacility, addInitHandlers,
263 breakSecondDeviceAtStart>::~FixtureWithPollAndPushInput() {
264 // make sure no exception throwing is still enabled from previous test
265 deviceBackend->throwExceptionOpen = false;
266 deviceBackend->throwExceptionRead = false;
267 deviceBackend->throwExceptionWrite = false;
268 deviceBackend2->throwExceptionOpen = false;
269 deviceBackend2->throwExceptionRead = false;
270 deviceBackend2->throwExceptionWrite = false;
271 deviceBackend3->throwExceptionOpen = false;
272 deviceBackend3->throwExceptionRead = false;
273 deviceBackend3->throwExceptionWrite = false;
274}
275
276/**********************************************************************************************************************/
277
278template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
280 // By definition, the DeviceModule has finished the recovery procedure when the status is 0 again.
281 status.readLatest();
282 return static_cast<int>(status);
283}
284
285/**********************************************************************************************************************/
286
287template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
288template<typename T>
290 ChimeraTK::DummyRegisterRawAccessor& accessor) {
291 auto lock = accessor.getBufferLock();
292 return static_cast<T>(accessor);
293}
294
295/**********************************************************************************************************************/
296
297template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
298template<typename T>
300 ChimeraTK::DummyRegisterRawAccessor&& accessor) {
301 read<T>(accessor);
302}
303
304/**********************************************************************************************************************/
305
306template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
307template<typename T>
309 ChimeraTK::DummyRegisterRawAccessor& accessor, T value) {
310 auto lock = accessor.getBufferLock();
311 accessor = static_cast<int32_t>(value);
312}
313
314/**********************************************************************************************************************/
315
316template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
317template<typename T>
319 ChimeraTK::DummyRegisterRawAccessor&& accessor, T value) {
320 write(accessor, value);
321}
322
323/**********************************************************************************************************************/
324/**********************************************************************************************************************/
boost::shared_ptr< DeviceManager > getDeviceManager(const std::string &aliasOrCDD)
Return the DeviceManager for the given alias name or CDD.
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
ModuleGroup()=default
Default constructor to allow late initialisation of module groups.
void writeAll(bool includeReturnChannels=false)
Just call write() on all writable variables in the group.
Definition Module.cc:157
Convenience class for input scalar accessors with UpdateMode::push.
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.
VariableGroup()=default
Default constructor: Allows late initialisation of VariableGroups (e.g.
std::string escapeName(const std::string &name, bool allowDotsAndSlashes)
Convert all characters which are not allowed in variable or module names into underscores followed by...
Definition Utilities.cc:45
InvalidityTracer application module.
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)
ChimeraTK::DeviceModule device
Definition fixtures.h:101
OutputModule outputModule
Definition fixtures.h:104
PushModuleForFanOut pushModule3
Definition fixtures.h:111
ChimeraTK::DeviceModule device2
Definition fixtures.h:109
PushModuleForTrigger pushModule2
Definition fixtures.h:110
OutputModule outputModule2
Definition fixtures.h:113
ChimeraTK::DeviceModule device3
Definition fixtures.h:118
static constexpr const char * ExceptionDummyCDD2
Definition fixtures.h:90
~DummyApplication() override
Definition fixtures.h:97
static constexpr const char * ExceptionDummyCDD1
Definition fixtures.h:89
static constexpr const char * ExceptionDummyCDD3
Definition fixtures.h:91
ChimeraTK::ScalarRegisterAccessor< int > status2
Definition fixtures.h:152
ChimeraTK::ScalarRegisterAccessor< std::string > message
Definition fixtures.h:154
ChimeraTK::TestFacility testFacitiy
Definition fixtures.h:150
ChimeraTK::DummyRegisterRawAccessor exceptionDummy2Register
Definition fixtures.h:158
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend3
Definition fixtures.h:148
ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister2
Definition fixtures.h:156
ChimeraTK::ScalarOutput< int > & outputVariable3
Definition fixtures.h:164
std::atomic< bool > initHandler2Called
Definition fixtures.h:178
ChimeraTK::ScalarPushInput< int > & pushVariable3copy
Definition fixtures.h:170
ChimeraTK::ScalarPollInput< int > & pollVariable2
Definition fixtures.h:162
DummyApplication application
Definition fixtures.h:149
void write(ChimeraTK::DummyRegisterRawAccessor &accessor, T value)
Definition fixtures.h:308
std::atomic< bool > initHandler1Called
Definition fixtures.h:177
ChimeraTK::ScalarPushInput< int > & pushVariable3
Definition fixtures.h:169
ChimeraTK::ScalarPushInput< int > & triggeredInput
Definition fixtures.h:167
ChimeraTK::ScalarRegisterAccessor< int > status
Definition fixtures.h:152
std::atomic< bool > initHandler1Throws
Definition fixtures.h:175
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend2
Definition fixtures.h:147
ChimeraTK::ScalarOutput< int > & outputVariable2
Definition fixtures.h:163
ChimeraTK::VoidRegisterAccessor deviceBecameFunctional
Definition fixtures.h:153
ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister3
Definition fixtures.h:157
std::atomic< bool > initHandler2Throws
Definition fixtures.h:176
ChimeraTK::ScalarPushInput< int > & pushVariable
Definition fixtures.h:160
ChimeraTK::ScalarPollInput< int > & pollVariable3
Definition fixtures.h:171
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend
Definition fixtures.h:146
ChimeraTK::VoidRegisterAccessor interrupt
Definition fixtures.h:173
ChimeraTK::VoidOutput & outputVariableV
Definition fixtures.h:165
ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister
Definition fixtures.h:155
auto read(ChimeraTK::DummyRegisterRawAccessor &accessor)
Definition fixtures.h:289
ChimeraTK::ScalarPollInput< int > & pollVariable
Definition fixtures.h:161
void prepare() override
Prepare the execution of the module.
Definition fixtures.h:82
ChimeraTK::ScalarOutput< int > deviceRegister3
Definition fixtures.h:78
ChimeraTK::ScalarOutput< int > deviceRegister2
Definition fixtures.h:77
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:83
ChimeraTK::VoidOutput deviceRegisterV
Definition fixtures.h:80
ChimeraTK::ScalarOutput< int > trigger
Definition fixtures.h:79
std::promise< void > p
Definition fixtures.h:81
std::promise< void > p
Definition fixtures.h:27
ChimeraTK::ScalarPollInput< int > pollInput2
Definition fixtures.h:26
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:28
ChimeraTK::ScalarPollInput< int > pollInput
Definition fixtures.h:25
std::promise< void > p
Definition fixtures.h:54
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:55
ChimeraTK::ScalarPushInput< int > pushInputCopy
Definition fixtures.h:51
ChimeraTK::ScalarPushInput< int > pushInput
Definition fixtures.h:50
ChimeraTK::ScalarPushInput< int > pushInput
Definition fixtures.h:64
std::promise< void > p
Definition fixtures.h:68
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:69
ChimeraTK::ScalarPushInput< int > pushInputCopy
Definition fixtures.h:65
std::promise< void > p
Definition fixtures.h:40
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:41
ChimeraTK::ScalarPushInput< int > pushInput
Definition fixtures.h:37