ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
testControlSystemAccessors.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 <future>
4
5#define BOOST_TEST_MODULE testControlSystemAccessors
6
7#include "Application.h"
8#include "ApplicationModule.h"
9#include "ScalarAccessor.h"
10
11#include <ChimeraTK/BackendFactory.h>
12#include <ChimeraTK/ControlSystemAdapter/ControlSystemPVManager.h>
13#include <ChimeraTK/ControlSystemAdapter/DevicePVManager.h>
14#include <ChimeraTK/ControlSystemAdapter/PVManager.h>
15
16#include <boost/mpl/list.hpp>
17#include <boost/test/included/unit_test.hpp>
18#include <boost/thread/barrier.hpp>
19
20using namespace boost::unit_test_framework;
21namespace ctk = ChimeraTK;
22
24
25 // list of user types the accessors are tested with
26 using test_types = boost::mpl::list<int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, float, double>;
27
28#define CHECK_TIMEOUT(condition, maxMilliseconds) \
29 { \
30 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); \
31 while(!(condition)) { \
32 bool timeout_reached = (std::chrono::steady_clock::now() - t0) > std::chrono::milliseconds(maxMilliseconds); \
33 BOOST_CHECK(!timeout_reached); \
34 if(timeout_reached) break; \
35 usleep(1000); \
36 } \
37 }
38
39 /********************************************************************************************************************/
40 /* the ApplicationModule for the test is a template of the user type */
41
42 template<typename T>
44 TestModule(ctk::ModuleGroup* owner, const std::string& name, const std::string& description,
45 const std::unordered_set<std::string>& tags = {})
46 : ApplicationModule(owner, name, description, tags), mainLoopStarted(2) {}
47
48 ctk::ScalarPushInput<T> consumer{this, "consumer", "", "No comment."};
49 ctk::ScalarOutput<T> feeder{this, "feeder", "MV/m", "Some fancy explanation about this variable"};
50
51 // We do not use testable mode for this test, so we need this barrier to synchronise to the beginning of the
52 // mainLoop(). This is required since the mainLoopWrapper accesses the module variables before the start of the
53 // mainLoop.
54 // execute this right after the Application::run():
55 // app.testModule.mainLoopStarted.wait(); // make sure the module's mainLoop() is entered
56 boost::barrier mainLoopStarted;
57
58 void mainLoop() override { mainLoopStarted.wait(); }
59 };
60
61 /********************************************************************************************************************/
62 /* dummy application */
63
64 template<typename T>
66 TestApplication() : Application("testSuite") {
67 ChimeraTK::BackendFactory::getInstance().setDMapFilePath("test.dmap");
68 }
69 ~TestApplication() override { shutdown(); }
70
71 TestModule<T> testModule{this, "TestModule", "The test module"};
72 };
73
74 /********************************************************************************************************************/
75 /* test feeding a scalar to the control system adapter */
76
79
81
82 auto pvManagers = ctk::createPVManager();
83 app.setPVManager(pvManagers.second);
84
85 // app.testModule.feeder >> app.cs("myFeeder");
86 app.initialise();
87
88 auto myFeeder = pvManagers.first->getProcessArray<T>("/TestModule/feeder");
89 auto consumer = pvManagers.first->getProcessArray<T>("/TestModule/consumer");
90
91 app.run();
92 consumer->write(); // send initial value so the application module can start up
93 app.testModule.mainLoopStarted.wait(); // make sure the module's mainLoop() is entered
94
95 BOOST_TEST(myFeeder->getName() == "/TestModule/feeder");
96 BOOST_TEST(myFeeder->getUnit() == "MV/m");
97 BOOST_TEST(myFeeder->getDescription() == "The test module - Some fancy explanation about this variable");
98
99 app.testModule.feeder = 42;
100 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), false);
101 app.testModule.feeder.write();
102 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), true);
103 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), false);
104 BOOST_CHECK(myFeeder->accessData(0) == 42);
105
106 app.testModule.feeder = 120;
107 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), false);
108 app.testModule.feeder.write();
109 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), true);
110 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), false);
111 BOOST_CHECK(myFeeder->accessData(0) == 120);
112 }
113
114 /********************************************************************************************************************/
115 /* test consuming a scalar from the control system adapter */
116
119
120 auto pvManagers = ctk::createPVManager();
121 app.setPVManager(pvManagers.second);
122
123 // app.cs("myConsumer") >> app.testModule.consumer;
124 app.initialise();
125
126 auto myConsumer = pvManagers.first->getProcessArray<T>("/TestModule/consumer");
127 BOOST_TEST(myConsumer->getName() == "/TestModule/consumer");
128 BOOST_TEST(myConsumer->getUnit() == "");
129 BOOST_TEST(myConsumer->getDescription() == "The test module - No comment.");
130
131 myConsumer->accessData(0) = 123; // set inital value
132 myConsumer->write();
133
134 app.run(); // should propagate initial value
135 app.testModule.mainLoopStarted.wait(); // make sure the module's mainLoop() is entered
136
137 BOOST_CHECK(app.testModule.consumer == 123); // check initial value
138
139 myConsumer->accessData(0) = 42;
140 myConsumer->write();
141 app.testModule.consumer.read();
142 BOOST_CHECK(app.testModule.consumer == 42);
143
144 myConsumer->accessData(0) = 120;
145 myConsumer->write();
146 app.testModule.consumer.read();
147 BOOST_CHECK(app.testModule.consumer == 120);
148 }
149
150 /********************************************************************************************************************/
151
152} // namespace Tests::testControlSystemAccessors
void run() override
Execute the module.
void initialise() override
void debugMakeConnections()
Enable debug output for the ConnectionMaker.
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
Convenience class for input scalar accessors with UpdateMode::push.
InvalidityTracer application module.
boost::mpl::list< int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, float, double > test_types
BOOST_AUTO_TEST_CASE_TEMPLATE(testFeedToCS, T, test_types)
Convenience class for output scalar accessors (always UpdateMode::push)
TestModule(ctk::ModuleGroup *owner, const std::string &name, const std::string &description, const std::unordered_set< std::string > &tags={})
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...