ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
TestFacility.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
4#include "TestFacility.h"
5
6namespace ChimeraTK {
7
8 /********************************************************************************************************************/
9
10 std::map<ChimeraTK::RegisterPath, ChimeraTK::UserTypeVariantNoVoid> TestFacility::_configScalars;
11 std::map<ChimeraTK::RegisterPath, ChimeraTK::UserTypeTemplateVariantNoVoid<TestFacility::Vector>>
13
14 /********************************************************************************************************************/
15
16 TestFacility::TestFacility(Application& application, bool enableTestableMode) : _app(application) {
17 auto pvManagers = createPVManager();
18 _pvManager = pvManagers.first;
19 _app.setPVManager(pvManagers.second);
20 if(enableTestableMode) {
22 }
24 }
25
26 /********************************************************************************************************************/
27
30
31 // send default values for all control system variables
32 for(auto& pv : _pvManager->getAllProcessVariables()) {
33 callForType(pv->getValueType(), [&pv, this](auto arg) {
34 using T = decltype(arg);
35
36 // Applies only to writeable variables.
37 // @todo FIXME It should also NOT apply for application-to-controlsystem variables with a return channel,
38 // despite being writeable here!
39 if(!pv->isWriteable()) {
40 return;
41 }
42
43 // Safety check against incorrect usage
44 if(pv->getVersionNumber() != VersionNumber(nullptr)) {
45 throw ChimeraTK::logic_error("The variable '" + pv->getName() +
46 "' has been written before TestFacility::runApplication() was called. Instead use "
47 "TestFacility::setScalarDefault() resp. setArrayDefault() to set initial values.");
48 }
49
50 // Get the PV accessor
51 auto pv_casted = boost::dynamic_pointer_cast<NDRegisterAccessor<T>>(pv);
52
53 // If default value has been stored, copy the default value to the PV.
54 if constexpr(!std::is_same<T, ChimeraTK::Void>::value) {
55 auto table = boost::fusion::at_key<T>(_defaults.table);
56 if(table.find(pv->getName()) != table.end()) {
61 if(pv_casted->getNumberOfSamples() == 1) { // scalar
62 auto accessor = this->getScalar<T>(pv->getName());
63 accessor = table.at(pv->getName())[0];
64 }
65 else { // array
66 auto accessor = this->getArray<T>(pv->getName());
67 accessor = table.at(pv->getName());
68 }
69 // copy value also to undecorated PV
70 pv_casted->accessChannel(0) = table.at(pv->getName());
71 }
72 }
73
74 // Write the initial value. This must be done even if no default value has been stored, since it is expected
75 // by the application.
76 pv_casted->write();
77 });
78 }
79 // start the application
80 _app.run();
81 // set thread name
82 Application::registerThread("TestThread");
83 // make sure all initial values have been propagated when in testable mode
84 if(_app.getTestableMode()._enabled) {
85 // call stepApplication() only in testable mode and only if the queues are not empty
86 if(_app.getTestableMode()._counter != 0 || _app.getTestableMode()._deviceInitialisationCounter != 0) {
87 stepApplication();
88 }
89 }
90
91 // receive all initial values for the control system variables
92 if(_app.getTestableMode()._enabled) {
93 for(auto& pv : _pvManager->getAllProcessVariables()) {
94 if(!pv->isReadable()) {
95 continue;
96 }
97 callForTypeNoVoid(pv->getValueType(), [&](auto t) {
98 using UserType = decltype(t);
99 this->getArray<UserType>(pv->getName()).readNonBlocking();
100 });
101 }
102 }
103 }
104
105 /********************************************************************************************************************/
106
107 bool TestFacility::canStepApplication() const {
108 return _app.getTestableMode().canStep();
109 }
110
111 /********************************************************************************************************************/
112
113 void TestFacility::stepApplication(bool waitForDeviceInitialisation) const {
114 _app.getTestableMode().step(waitForDeviceInitialisation);
115 }
116
117 /********************************************************************************************************************/
118
119 ChimeraTK::VoidRegisterAccessor TestFacility::getVoid(const ChimeraTK::RegisterPath& name) const {
120 return getAccessor<ChimeraTK::Void>(name);
121 }
122
123 /********************************************************************************************************************/
124
125} // namespace ChimeraTK
void enableTestableMode()
Enable the testable mode.
bool _testFacilityRunApplicationCalled
Flag which is set by the TestFacility in runApplication() at the beginning.
void initialise() override
static void registerThread(const std::string &name)
Register the thread in the application system and give it a name.
TestFacility(Application &app, bool enableTestableMode=true)
The passed application will automatically be put into the testable mode and initialised.
ChimeraTK::TemplateUserTypeMap< Defaults > _defaults
static std::map< ChimeraTK::RegisterPath, ChimeraTK::UserTypeTemplateVariantNoVoid< Vector > > _configArrays
static std::map< ChimeraTK::RegisterPath, ChimeraTK::UserTypeVariantNoVoid > _configScalars
boost::shared_ptr< ControlSystemPVManager > _pvManager
void runApplication() const
Start the application in testable mode.
InvalidityTracer application module.