ChimeraTK-DeviceAccess 03.31.00
Loading...
Searching...
No Matches
testDataConsistencyRealm.cpp
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 a name for the test module.
7#define BOOST_TEST_MODULE DataConsistencyRealmTest
8// Only after defining the name include the unit test header.
9#include <boost/test/unit_test.hpp>
10using namespace boost::unit_test_framework;
11
12#include "BackendFactory.h"
13#include "Device.h"
14#include "DummyBackend.h"
16
17namespace ctk = ChimeraTK;
18
19// Create a test suite which holds all your tests.
20BOOST_AUTO_TEST_SUITE(DataConsistencyRealmTestSuite)
21
22/**********************************************************************************************************************/
23
24static std::string cdd(
25 R"((dummy:1?map=testDataConsistencyRealm.map&DataConsistencyKeys={"/theKey":"MyIdRealm", "/anotherKey":"MyIdRealm"}))");
26static auto dummy =
27 boost::dynamic_pointer_cast<ctk::DummyBackend>(ctk::BackendFactory::getInstance().createBackend(cdd));
28static auto& realmStore = ctk::async::DataConsistencyRealmStore::getInstance();
29
30/**********************************************************************************************************************/
31
33 std::cout << "TestRealm" << std::endl;
34 auto realm = realmStore.getRealm("SingleRealm");
35
36 auto b = realm->getVersion(ctk::async::DataConsistencyKey(42));
37 auto c = realm->getVersion(ctk::async::DataConsistencyKey(42));
38 BOOST_TEST(b == c);
39
40 auto d = realm->getVersion(ctk::async::DataConsistencyKey(43));
41 BOOST_TEST(d > b);
42
43 ctk::VersionNumber last{nullptr};
44 for(uint64_t i = 1; i < 42; ++i) {
45 auto a = realm->getVersion(ctk::async::DataConsistencyKey(i));
46 BOOST_TEST(a != ctk::VersionNumber{nullptr});
47 BOOST_TEST(a < b);
48 if(last != ctk::VersionNumber{nullptr}) {
49 BOOST_TEST(a > last);
50 }
51 last = a;
52 }
53
54 auto b2 = realm->getVersion(ctk::async::DataConsistencyKey(42));
55 BOOST_TEST(b2 == b);
56
57 auto x = realm->getVersion(ctk::async::DataConsistencyKey(1000000000));
58 BOOST_TEST(x > d);
59
60 auto y = realm->getVersion(ctk::async::DataConsistencyKey(42));
61 BOOST_TEST(y == ctk::VersionNumber{nullptr});
62}
63
64/**********************************************************************************************************************/
65
66BOOST_AUTO_TEST_CASE(TestMultipleRealms) {
67 std::cout << "TestMultipleRealms" << std::endl;
68 auto realmA = realmStore.getRealm("RealmA");
69 auto realmB = realmStore.getRealm("RealmB");
70
71 // Two different realms shall not hand out the same version for the same key value. Also the realm store shall
72 // gives out different realms for different names.
73
74 auto a = realmA->getVersion(ctk::async::DataConsistencyKey(42));
75 auto b = realmB->getVersion(ctk::async::DataConsistencyKey(42));
76 BOOST_TEST(a != b);
77}
78
79/**********************************************************************************************************************/
80
81BOOST_AUTO_TEST_CASE(TestVersionConsistencyBetweenAccessors) {
82 std::cout << "TestVersionConsistencyBetweenAccessors" << std::endl;
83 ctk::Device dev(cdd);
84 dev.open();
85
86 auto realm = realmStore.getRealm("MyIdRealm");
88
89 auto key = dev.getScalarRegisterAccessor<uint32_t>("/theKey.DUMMY_WRITEABLE");
90 auto dataA = dev.getScalarRegisterAccessor<int32_t>("/dataA", 0, {ctk::AccessMode::wait_for_new_data});
91 auto dataB = dev.getScalarRegisterAccessor<int32_t>("/dataB", 0, {ctk::AccessMode::wait_for_new_data});
92 auto interrupt6 = dev.getScalarRegisterAccessor<int32_t>("/interrupt6", 0, {ctk::AccessMode::wait_for_new_data});
93
94 BOOST_REQUIRE(!dataA.readNonBlocking());
95 BOOST_REQUIRE(!dataB.readNonBlocking());
96 BOOST_REQUIRE(!interrupt6.readNonBlocking());
97
98 // check for initial value
99 key.setAndWrite(12);
100 dev.activateAsyncRead();
101
102 BOOST_REQUIRE(dataA.readNonBlocking());
103 BOOST_REQUIRE(dataB.readNonBlocking());
104 BOOST_REQUIRE(interrupt6.readNonBlocking());
105 BOOST_REQUIRE(!dataA.readNonBlocking());
106 BOOST_REQUIRE(!dataB.readNonBlocking());
107 BOOST_REQUIRE(!interrupt6.readNonBlocking());
108
109 auto v1 = realm->getVersion(ctk::async::DataConsistencyKey(key));
110 BOOST_REQUIRE(v1 > v0);
111 BOOST_TEST(dataA.getVersionNumber() == v1);
112 BOOST_TEST(dataB.getVersionNumber() == v1);
113 BOOST_TEST(interrupt6.getVersionNumber() == v1);
114 BOOST_TEST(dataA.dataValidity() == ctk::DataValidity::ok);
115 BOOST_TEST(dataB.dataValidity() == ctk::DataValidity::ok);
116 BOOST_TEST(interrupt6.dataValidity() == ctk::DataValidity::ok);
117
118 // check for triggered interrupt
119 key.setAndWrite(42);
120 dummy->triggerInterrupt(6);
121
122 BOOST_REQUIRE(dataA.readNonBlocking());
123 BOOST_REQUIRE(dataB.readNonBlocking());
124 BOOST_REQUIRE(interrupt6.readNonBlocking());
125 BOOST_REQUIRE(!dataA.readNonBlocking());
126 BOOST_REQUIRE(!dataB.readNonBlocking());
127 BOOST_REQUIRE(!interrupt6.readNonBlocking());
128
129 auto v2 = realm->getVersion(ctk::async::DataConsistencyKey(key));
130 BOOST_REQUIRE(v2 > v1);
131 BOOST_TEST(dataA.getVersionNumber() == v2);
132 BOOST_TEST(dataB.getVersionNumber() == v2);
133 BOOST_TEST(interrupt6.getVersionNumber() == v2);
134 BOOST_TEST(dataA.dataValidity() == ctk::DataValidity::ok);
135 BOOST_TEST(dataB.dataValidity() == ctk::DataValidity::ok);
136 BOOST_TEST(interrupt6.dataValidity() == ctk::DataValidity::ok);
137
138 // check for repeated key value
139 dummy->triggerInterrupt(6);
140
141 BOOST_REQUIRE(dataA.readNonBlocking());
142 BOOST_REQUIRE(dataB.readNonBlocking());
143 BOOST_REQUIRE(interrupt6.readNonBlocking());
144 BOOST_REQUIRE(!dataA.readNonBlocking());
145 BOOST_REQUIRE(!dataB.readNonBlocking());
146 BOOST_REQUIRE(!interrupt6.readNonBlocking());
147
148 BOOST_TEST(dataA.getVersionNumber() == v2);
149 BOOST_TEST(dataB.getVersionNumber() == v2);
150 BOOST_TEST(interrupt6.getVersionNumber() == v2);
151 BOOST_TEST(dataA.dataValidity() == ctk::DataValidity::ok);
152 BOOST_TEST(dataB.dataValidity() == ctk::DataValidity::ok);
153 BOOST_TEST(interrupt6.dataValidity() == ctk::DataValidity::ok);
154
155 // check with backwards going key value
156 key.setAndWrite(40);
157 dummy->triggerInterrupt(6);
158
159 BOOST_REQUIRE(dataA.readNonBlocking());
160 BOOST_REQUIRE(dataB.readNonBlocking());
161 BOOST_REQUIRE(interrupt6.readNonBlocking());
162 BOOST_REQUIRE(!dataA.readNonBlocking());
163 BOOST_REQUIRE(!dataB.readNonBlocking());
164 BOOST_REQUIRE(!interrupt6.readNonBlocking());
165
166 auto v3 = realm->getVersion(ctk::async::DataConsistencyKey(key));
167 BOOST_REQUIRE(v3 < v2);
168 BOOST_REQUIRE(v3 > v1);
169 BOOST_TEST(dataA.getVersionNumber() == v2); // cannot go backwards with version numbers
170 BOOST_TEST(dataB.getVersionNumber() == v2);
171 BOOST_TEST(interrupt6.getVersionNumber() == v2);
172 BOOST_TEST(dataA.dataValidity() == ctk::DataValidity::faulty);
173 BOOST_TEST(dataB.dataValidity() == ctk::DataValidity::faulty);
174 BOOST_TEST(interrupt6.dataValidity() == ctk::DataValidity::ok);
175
176 dev.close();
177}
178
179/**********************************************************************************************************************/
180
181BOOST_AUTO_TEST_CASE(TestMultiInterrupt) {
182 std::cout << "TestMultiInterrupt" << std::endl;
183 ctk::Device dev(cdd);
184 dev.open();
185
186 auto realm = realmStore.getRealm("MyIdRealm");
188
189 auto keyA = dev.getScalarRegisterAccessor<uint32_t>("/theKey.DUMMY_WRITEABLE");
190 auto dataA = dev.getScalarRegisterAccessor<int32_t>("/dataA", 0, {ctk::AccessMode::wait_for_new_data});
191 auto intA = dev.getScalarRegisterAccessor<int32_t>("/interrupt6", 0, {ctk::AccessMode::wait_for_new_data});
192
193 auto keyB = dev.getScalarRegisterAccessor<uint32_t>("/anotherKey.DUMMY_WRITEABLE");
194 auto dataB = dev.getScalarRegisterAccessor<int32_t>("/dataC", 0, {ctk::AccessMode::wait_for_new_data});
195 auto intB = dev.getScalarRegisterAccessor<int32_t>("/interrupt123", 0, {ctk::AccessMode::wait_for_new_data});
196
197 BOOST_REQUIRE(!dataA.readNonBlocking());
198 BOOST_REQUIRE(!dataB.readNonBlocking());
199 BOOST_REQUIRE(!intA.readNonBlocking());
200 BOOST_REQUIRE(!intB.readNonBlocking());
201
202 // check for initial value
203 keyA.setAndWrite(12);
204 keyB.setAndWrite(15);
205 dev.activateAsyncRead();
206
207 BOOST_REQUIRE(dataA.readNonBlocking());
208 BOOST_REQUIRE(dataB.readNonBlocking());
209 BOOST_REQUIRE(intA.readNonBlocking());
210 BOOST_REQUIRE(intB.readNonBlocking());
211 BOOST_REQUIRE(!dataA.readNonBlocking());
212 BOOST_REQUIRE(!dataB.readNonBlocking());
213 BOOST_REQUIRE(!intA.readNonBlocking());
214 BOOST_REQUIRE(!intB.readNonBlocking());
215
216 auto v1 = realm->getVersion(ctk::async::DataConsistencyKey(keyA));
217 auto v2 = realm->getVersion(ctk::async::DataConsistencyKey(keyB));
218 BOOST_REQUIRE(v1 > v0);
219 BOOST_REQUIRE(v2 > v1);
220 BOOST_TEST(dataA.getVersionNumber() == v1);
221 BOOST_TEST(intA.getVersionNumber() == v1);
222 BOOST_TEST(dataB.getVersionNumber() == v2);
223 BOOST_TEST(intB.getVersionNumber() == v2);
224
225 // check for triggered interrupt
226 keyA.setAndWrite(15);
227 dummy->triggerInterrupt(6);
228
229 BOOST_REQUIRE(dataA.readNonBlocking());
230 BOOST_REQUIRE(intA.readNonBlocking());
231 BOOST_REQUIRE(!dataA.readNonBlocking());
232 BOOST_REQUIRE(!dataB.readNonBlocking());
233 BOOST_REQUIRE(!intA.readNonBlocking());
234 BOOST_REQUIRE(!intB.readNonBlocking());
235
236 BOOST_TEST(dataA.getVersionNumber() == v2);
237 BOOST_TEST(intA.getVersionNumber() == v2);
238
239 dev.close();
240}
241
242/**********************************************************************************************************************/
243
244namespace {
245
249 void runDoubleBufferScenario(const std::string& keyCdd, const std::string& realmName, const std::string& keyRegister,
250 const std::vector<uint16_t>& dataValue) {
251 auto backend =
252 boost::dynamic_pointer_cast<ctk::DummyBackend>(ctk::BackendFactory::getInstance().createBackend(keyCdd));
253 ctk::Device dev(keyCdd);
254 dev.open();
255 auto realm = realmStore.getRealm(realmName);
256
257 auto data = dev.getOneDRegisterAccessor<uint16_t>("/TEST/DBLASYNC.1", 0, 0, {ctk::AccessMode::wait_for_new_data});
258
259 dev.activateAsyncRead();
260 BOOST_REQUIRE(data.readNonBlocking()); // consume the initial value
261
262 ctk::DummyRegisterAccessor<uint32_t> keyBuf1{backend.get(), "", keyRegister};
263 ctk::DummyRegisterAccessor<uint16_t> dataBuf1{backend.get(), "TEST/DBLASYNC.1", "BUF1"};
264 ctk::DummyRegisterAccessor<uint32_t> inactiveBuf{backend.get(), "TEST/DOUBLE_BUF", "INACTIVE_BUF_ID"};
265
266 // write a distinguishable value into buffer 1 of both key and data
267 for(size_t e = 0; e < dataValue.size(); ++e) {
268 dataBuf1[e] = dataValue[e];
269 }
270 // set the inactive-buffer id to 0 so buffer 1 is the freshly finished buffer
271 inactiveBuf[0] = 0;
272
273 const uint32_t keyValue = 42;
274 keyBuf1[0] = keyValue;
275 backend->triggerInterrupt(7);
276
277 BOOST_REQUIRE(data.readNonBlocking());
278 BOOST_TEST(data.getVersionNumber() == realm->getVersion(ctk::async::DataConsistencyKey(keyValue)));
279 for(size_t e = 0; e < data.getNElements(); ++e) {
280 BOOST_TEST(data[e] == dataValue[e]);
281 }
282
283 dev.close();
284 }
285
286} // namespace
287
288/**********************************************************************************************************************/
289
290BOOST_AUTO_TEST_CASE(TestDataConsistencyKeyDoubleBuffer) {
291 // The plain-key and the correlated-key configurations both drive an interrupt-driven wait_for_new_data read of the
292 // double-buffered data register TEST/DBLASYNC.1, which belongs to the TEST.DOUBLE_BUF control state. Each scenario
293 // finishes buffer 1 once. In the correlated configuration the key register TEST.KEYDB shares the data register's
294 // control state, so both accessors resolve to one control state and swap together.
295
296 std::cout << "TestDataConsistencyKeyDoubleBuffer: running the plain key configuration" << std::endl;
297 std::string plainKeyCdd =
298 R"((ExceptionDummy:1?map=muxedDataAccessor.jmap&DataConsistencyKeys={"/TEST.KEY":"DoubleBufferKeyRealm"}))";
299 runDoubleBufferScenario(plainKeyCdd, "DoubleBufferKeyRealm", "TEST.KEY", std::vector<uint16_t>{100, 101, 102, 103});
300
301 std::cout << "TestDataConsistencyKeyDoubleBuffer: running the correlated key configuration" << std::endl;
302 std::string correlatedKeyCdd =
303 R"((ExceptionDummy:1?map=muxedDataAccessor.jmap&DataConsistencyKeys={"/TEST.KEYDB":"DoubleBufferKeyRealm"}))";
304 runDoubleBufferScenario(
305 correlatedKeyCdd, "DoubleBufferKeyRealm", "TEST.KEYDB.BUF1", std::vector<uint16_t>{200, 201, 202, 203});
306}
307
308/**********************************************************************************************************************/
309
310BOOST_AUTO_TEST_SUITE_END()
Class allows to read/write registers from device.
Definition Device.h:39
void close()
Close the device.
Definition Device.cc:66
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 activateAsyncRead() noexcept
Activate asyncronous read for all transfer elements where AccessMode::wait_for_new_data is set.
Definition Device.cc:91
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Definition Device.cc:58
Register accessor for accessing single word or 1D array registers internally of a DummyBackend implem...
Class for generating and holding version numbers without exposing a numeric representation.
This header collects some conversion routines which should be useful both for ApplicationCore Python ...
std::string cdd
BOOST_AUTO_TEST_CASE(TestRealm)