ChimeraTK-ApplicationCore 04.08.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
80 auto pvManagers = ctk::createPVManager();
81 app.setPVManager(pvManagers.second);
82
83 // app.testModule.feeder >> app.cs("myFeeder");
84 app.initialise();
85
86 auto myFeeder = pvManagers.first->getProcessArray<T>("/TestModule/feeder");
87 auto consumer = pvManagers.first->getProcessArray<T>("/TestModule/consumer");
88
89 app.run();
90 consumer->write(); // send initial value so the application module can start up
91 app.testModule.mainLoopStarted.wait(); // make sure the module's mainLoop() is entered
92
93 BOOST_TEST(myFeeder->getName() == "/TestModule/feeder");
94 BOOST_TEST(myFeeder->getUnit() == "MV/m");
95 BOOST_TEST(myFeeder->getDescription() == "The test module - Some fancy explanation about this variable");
96
97 app.testModule.feeder = 42;
98 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), false);
99 app.testModule.feeder.write();
100 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), true);
101 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), false);
102 BOOST_CHECK(myFeeder->accessData(0) == 42);
103
104 app.testModule.feeder = 120;
105 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), false);
106 app.testModule.feeder.write();
107 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), true);
108 BOOST_CHECK_EQUAL(myFeeder->readNonBlocking(), false);
109 BOOST_CHECK(myFeeder->accessData(0) == 120);
110 }
111
112 /********************************************************************************************************************/
113 /* test consuming a scalar from the control system adapter */
114
117
118 auto pvManagers = ctk::createPVManager();
119 app.setPVManager(pvManagers.second);
120
121 // app.cs("myConsumer") >> app.testModule.consumer;
122 app.initialise();
123
124 auto myConsumer = pvManagers.first->getProcessArray<T>("/TestModule/consumer");
125 BOOST_TEST(myConsumer->getName() == "/TestModule/consumer");
126 BOOST_TEST(myConsumer->getUnit() == "");
127 BOOST_TEST(myConsumer->getDescription() == "The test module - No comment.");
128
129 myConsumer->accessData(0) = 123; // set inital value
130 myConsumer->write();
131
132 app.run(); // should propagate initial value
133 app.testModule.mainLoopStarted.wait(); // make sure the module's mainLoop() is entered
134
135 BOOST_CHECK(app.testModule.consumer == 123); // check initial value
136
137 myConsumer->accessData(0) = 42;
138 myConsumer->write();
139 app.testModule.consumer.read();
140 BOOST_CHECK(app.testModule.consumer == 42);
141
142 myConsumer->accessData(0) = 120;
143 myConsumer->write();
144 app.testModule.consumer.read();
145 BOOST_CHECK(app.testModule.consumer == 120);
146 }
147
148 /********************************************************************************************************************/
149
150} // namespace Tests::testControlSystemAccessors
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.
friend class Application
Definition ModuleGroup.h:47
Convenience class for output scalar accessors (always UpdateMode::push)
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)
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...