ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
testLMapMathPluginPushPars.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
5#define BOOST_TEST_DYN_LINK
6#define BOOST_TEST_MODULE LMapMathPluginTest
7#include <boost/test/unit_test.hpp>
8using namespace boost::unit_test_framework;
9
10#include "Device.h"
12
13using namespace ChimeraTK;
14
15BOOST_AUTO_TEST_SUITE(LMapMathPluginTestSuite)
16
17/**********************************************************************************************************************/
18
21
22 static boost::shared_ptr<DeviceBackend> createInstance(std::string, std::map<std::string, std::string>) {
23 return boost::make_shared<DummyForCleanupCheck>("mathPluginWithPushPars.xlmap");
24 }
26 std::cout << "~DummyForCleanupCheck()" << std::endl;
27 cleanupCalled = true;
28 }
29
30 struct BackendRegisterer {
35 };
36 static std::atomic_bool cleanupCalled;
37};
38std::atomic_bool DummyForCleanupCheck::cleanupCalled{false};
39static DummyForCleanupCheck::BackendRegisterer gDFCCRegisterer;
40
41BOOST_AUTO_TEST_CASE(testPushPars) {
42 setDMapFilePath("mathPluginWithPushPars.dmap");
43 {
44 // we enforce that initial values from variable definition in xlmap are never used in MathPugin
45 // - therefore, in test here, we must issue write for all push-parameters
46 // - then, version number check in MathPlugin will notice valid data has been provided after open
47 // - for poll-type accessors, version number check also succeeds since they get recent version numbers anyway
48 // Test needs to call activateAsyncRead but it must be irrelevant whether before or after writes
49
50 ChimeraTK::Device targetDevice;
51 auto targetWriteCount = [&targetDevice]() {
52 auto exceptionDummyForTargetDev = boost::static_pointer_cast<ExceptionDummy>(targetDevice.getBackend());
53 return exceptionDummyForTargetDev->getWriteCount("MATHTEST/TARGET");
54 };
55 size_t writeCount = 0; // this counter tracks expected writes to target register
56
57 targetDevice.open("HOLD");
58 auto accTarget = targetDevice.getScalarRegisterAccessor<uint32_t>("MATHTEST/TARGET");
59
60 ChimeraTK::Device logicalDevice("EOD");
61 logicalDevice.open();
62 logicalDevice.activateAsyncRead();
63 auto pushPar = logicalDevice.getScalarRegisterAccessor<uint32_t>("DET/PUSHPAR");
64
65 pushPar = 2;
66 pushPar.write();
67
68 auto accMathWrite = logicalDevice.getScalarRegisterAccessor<double>("DET/X");
69 // we don't have main value (x in formula) yet, since it wasn't yet written.
70 // therefore, we expect to have no value yet for formula output (0 is default from dummy construction)
71 accTarget.read();
72 BOOST_TEST(int(accTarget) == 0);
73 BOOST_TEST(targetWriteCount() == writeCount); // just a sanity check
74
75 // write to main value and check result
76 accMathWrite = 3;
77 accMathWrite.write();
78 accTarget.read();
79 BOOST_TEST(int(accTarget) == 10 * pushPar + accMathWrite);
80 // check that result was written exactly once
81 writeCount++;
82 BOOST_TEST(targetWriteCount() == writeCount);
83
84 // write to push-parameter and check result
85 // note, it's a new feature that result is completely written when write() returns.
86 pushPar = 4;
87 pushPar.write();
88 accTarget.read();
89 BOOST_TEST(int(accTarget) == 10 * pushPar + accMathWrite);
90 writeCount++;
91 BOOST_TEST(targetWriteCount() == writeCount);
92
93 // re-open and test again, with different write order (x,p) instead of (p,x)
94 logicalDevice.close();
95 targetDevice.open(); // open again since low-level device was closed by LNM
96 accTarget = 0; // reset result in dummy
97 accTarget.write();
98 writeCount++; // direct write from test also must be counted
99 logicalDevice.open();
100 logicalDevice.activateAsyncRead();
101
102 accMathWrite = 5;
103 accMathWrite.write();
104 // check that MathPlugin did not yet write to the device - it must wait on push-parameter value
105 accTarget.read();
106 BOOST_CHECK_EQUAL(int(accTarget), 0);
107 BOOST_TEST(targetWriteCount() == writeCount);
108
109 pushPar.write();
110 accTarget.read();
111 BOOST_TEST(int(accTarget) == 10 * pushPar + accMathWrite);
112 writeCount++;
113 BOOST_TEST(targetWriteCount() == writeCount);
114
115 // write-behavior does not depend on whether or when we call activateAsyncRead
116 logicalDevice.close();
117 logicalDevice.open();
118 accTarget = 0;
119 accTarget.write();
120 writeCount++; // direct write from test also counts
121 BOOST_TEST(targetWriteCount() == writeCount); // sanity check (that we are counting correctly)
122 accMathWrite = 7;
123 accMathWrite.write(); // not all parameters written after open -> no target write
124 pushPar = 6;
125 pushPar.write();
126 writeCount++;
127 BOOST_TEST(int(accTarget) == 0);
128 BOOST_TEST(targetWriteCount() == writeCount);
129 logicalDevice.activateAsyncRead(); // does not trigger target write
130 BOOST_TEST(targetWriteCount() == writeCount);
131 accTarget.read();
132 BOOST_TEST(int(accTarget) == 10 * pushPar + accMathWrite);
133
134 // we also need to test that write count is correct if there are two push-parameters
135 auto pushPar2 = logicalDevice.getScalarRegisterAccessor<uint32_t>("DET/PUSHPAR2");
136 auto accMathWrite2 = logicalDevice.getScalarRegisterAccessor<double>("DET/X2");
137 auto accTarget2 = targetDevice.getScalarRegisterAccessor<uint32_t>("MATHTEST/TARGET2");
138 auto targetWriteCount2 = [&targetDevice]() {
139 auto exceptionDummyForTargetDev = boost::static_pointer_cast<ExceptionDummy>(targetDevice.getBackend());
140 return exceptionDummyForTargetDev->getWriteCount("MATHTEST/TARGET2");
141 };
142 size_t writeCount2 = 0; // this counter tracks expected writes to target register TARGET2
143 pushPar = 1;
144 pushPar.write();
145 pushPar2 = 2;
146 pushPar2.write();
147 accMathWrite2 = 3;
148 accMathWrite2.write();
149 accTarget2.read();
150 BOOST_TEST(int(accTarget2) == 200 * pushPar2 + 20 * pushPar + 2 * accMathWrite2);
151 writeCount2++;
152 BOOST_TEST(targetWriteCount2() == writeCount2);
153 logicalDevice.close();
154 logicalDevice.open();
155 pushPar.write();
156 pushPar2.write();
157 accMathWrite2.write();
158 writeCount2++;
159 BOOST_TEST(targetWriteCount2() == writeCount2);
160 logicalDevice.activateAsyncRead();
161 BOOST_TEST(int(accTarget2) == 200 * pushPar2 + 20 * pushPar + 2 * accMathWrite2);
162 BOOST_TEST(targetWriteCount2() == writeCount2);
163 }
164 // regression test for bug https://redmine.msktools.desy.de/issues/11506
165 // (math plugin + push-parameter + shm has resource cleanup problem)
167}
168
169BOOST_AUTO_TEST_CASE(testPushParsLateOpen) {
170 // test that push-parameter logic also works if accessor to variable is obtained first, before device is opened
171 // this is a regression test for bug https://redmine.msktools.desy.de/issues/11910
172 setDMapFilePath("mathPluginWithPushPars.dmap");
173 {
174 ChimeraTK::Device targetDevice;
175 auto targetWriteCount = [&targetDevice]() {
176 auto exceptionDummyForTargetDev = boost::static_pointer_cast<ExceptionDummy>(targetDevice.getBackend());
177 return exceptionDummyForTargetDev->getWriteCount("MATHTEST/TARGET");
178 };
179 size_t writeCount = 0; // this counter tracks expected writes to target register
180
181 targetDevice.open("HOLD");
182 auto accTarget = targetDevice.getScalarRegisterAccessor<uint32_t>("MATHTEST/TARGET");
183
184 ChimeraTK::Device logicalDevice("EOD");
185 auto pushPar = logicalDevice.getScalarRegisterAccessor<uint32_t>("DET/PUSHPAR");
186 auto accMathWrite = logicalDevice.getScalarRegisterAccessor<double>("DET/X");
187 logicalDevice.open();
188 logicalDevice.activateAsyncRead();
189
190 pushPar = 2;
191 pushPar.write();
192
193 // write to main value and check result
194 accMathWrite = 3;
195 accMathWrite.write();
196 accTarget.read();
197 BOOST_TEST(int(accTarget) == 10 * pushPar + accMathWrite);
198 // check that result was written exactly once
199 writeCount++;
200 BOOST_TEST(targetWriteCount() == writeCount);
201
202 // write to push-parameter and check result
203 // note, it's a new feature that result is completely written when write() returns.
204 pushPar = 4;
205 pushPar.write();
206 accTarget.read();
207 BOOST_TEST(int(accTarget) == 10 * pushPar + accMathWrite);
208 writeCount++;
209 BOOST_TEST(targetWriteCount() == writeCount);
210 }
212}
213
214/**********************************************************************************************************************/
215
216BOOST_AUTO_TEST_SUITE_END()
static BackendFactory & getInstance()
Static function to get an instance of factory.
void registerBackendType(const std::string &backendType, boost::shared_ptr< DeviceBackend >(*creatorFunction)(std::string address, std::map< std::string, std::string > parameters), const std::vector< std::string > &sdmParameterNames={}, const std::string &deviceAccessVersion=CHIMERATK_DEVICEACCESS_VERSION)
Register a backend by the name backendType with the given creatorFunction.
Class allows to read/write registers from device.
Definition Device.h:39
boost::shared_ptr< DeviceBackend > getBackend()
Obtain the backend.
Definition Device.cc:111
ScalarRegisterAccessor< UserType > getScalarRegisterAccessor(const RegisterPath &registerPathName, size_t wordOffsetInRegister=0, const AccessModeFlags &flags=AccessModeFlags({})) const
Get a ScalarRegisterObject object for the given register.
Definition Device.h:266
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Definition Device.cc:58
Backend to map logical register names onto real hardware registers.
LogicalNameMappingBackend(std::string lmapFileName="")
void setDMapFilePath(std::string dmapFilePath)
Set the location of the dmap file.
static boost::shared_ptr< DeviceBackend > createInstance(std::string, std::map< std::string, std::string > parameters)
static boost::shared_ptr< DeviceBackend > createInstance(std::string, std::map< std::string, std::string >)
BOOST_AUTO_TEST_CASE(testPushPars)