ChimeraTK-DeviceAccess 03.29.00
Loading...
Searching...
No Matches
testLMapBitRangePlugin.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 "TransferGroup.h"
5#define BOOST_TEST_DYN_LINK
6#define BOOST_TEST_MODULE LMapBitRangePluginTest
7#include <boost/test/unit_test.hpp>
8using namespace boost::unit_test_framework;
9
10#include "Device.h"
11
12using namespace ChimeraTK;
13
14BOOST_AUTO_TEST_SUITE(LMapBitRangeTestSuite)
15
16/**********************************************************************************************************************/
17
18BOOST_AUTO_TEST_CASE(testSimpleRead) {
20 device.open("(logicalNameMap?map=bitRangeReadPlugin.xlmap)");
21
22 auto accTarget = device.getScalarRegisterAccessor<int>("SimpleScalar");
23
24 auto accRangedHi = device.getScalarRegisterAccessor<uint16_t>("HiByte");
25 auto accRangedMid = device.getScalarRegisterAccessor<uint16_t>("MidByte");
26 auto accRangedLo = device.getScalarRegisterAccessor<uint16_t>("LoByte");
27
28 accTarget.setAndWrite(0x1f0f);
29
30 accRangedLo.read();
31 accRangedHi.read();
32 accRangedMid.read();
33
34 BOOST_TEST(accRangedLo == 0x0f);
35 BOOST_TEST(accRangedHi == 0x1f);
36 BOOST_TEST(accRangedMid == 0xf0);
37
38 TransferGroup group;
39 group.addAccessor(accRangedLo);
40 group.addAccessor(accRangedHi);
41
42 accTarget.setAndWrite(0);
43 group.read();
44 BOOST_TEST(accRangedLo == 0);
45 BOOST_TEST(accRangedHi == 0);
46
47 accTarget.setAndWrite(0x5a1f);
48 group.read();
49 BOOST_TEST(accRangedLo == 0x1f);
50 BOOST_TEST(accRangedHi == 0x5a);
51}
52
53BOOST_AUTO_TEST_CASE(testSimpleWrite) {
55 device.open("(logicalNameMap?map=bitRangeReadPlugin.xlmap)");
56
57 auto accTarget = device.getScalarRegisterAccessor<int>("SimpleScalar");
58
59 auto accRangedHi = device.getScalarRegisterAccessor<uint16_t>("HiByte");
60 auto accRangedMid = device.getScalarRegisterAccessor<uint16_t>("MidByte");
61 auto accRangedLo = device.getScalarRegisterAccessor<uint16_t>("LoByte");
62
63 accTarget.setAndWrite(0x1f0f);
64 accRangedHi = 0x76;
65 accRangedHi.write();
66
67 accRangedMid.read();
68 BOOST_TEST(accRangedMid == 0x60);
69 accTarget.read();
70 BOOST_TEST(accTarget == 0x760f);
71
72 // Use of overlapping ranges in transfer groups is undefined, so only use
73 // the distinct accessors
74 auto group = TransferGroup();
75 group.addAccessor(accRangedLo);
76 group.addAccessor(accRangedHi);
77
78 accRangedHi = 0x75;
79 accRangedLo = 0x80;
80
81 group.write();
82 accTarget.read();
83
84 BOOST_TEST(accTarget == 0x7580);
85
86 // Add overlapping accessor to group, check that the group cannot be written anymore
87 group.addAccessor(accRangedMid);
88 BOOST_CHECK_THROW(group.write(), ChimeraTK::logic_error);
89}
90
91/**********************************************************************************************************************/
92
93BOOST_AUTO_TEST_CASE(testAccessorSanity) {
95 device.open("(logicalNameMap?map=bitRangeReadPlugin.xlmap)");
96
97 // Manual test for spec B.2.4
98 // Accessor too small for the configured number of bits
99 auto accTarget = device.getScalarRegisterAccessor<int>("SimpleScalar");
100
101 auto accMiddle = device.getScalarRegisterAccessor<int8_t>("Middle");
102 accTarget.setAndWrite(0x1ff0);
103 accMiddle.read();
104 BOOST_TEST(accMiddle == 127);
105 BOOST_CHECK(accMiddle.dataValidity() == ChimeraTK::DataValidity::faulty);
106
107 // The Number of bits requested from the target register is larger than the register
108 auto accTooLarge = device.getScalarRegisterAccessor<int16_t>("TooLarge");
109 accTooLarge.setAndWrite(0xff1);
110 accTarget.read();
111 BOOST_CHECK(accTarget == std::numeric_limits<int16_t>::max());
112
113 // The number of bits requested is smaller than what is available in the user type and the value
114 // written in the accessor is larger than maximum value in those bits
115 accTarget.setAndWrite(0);
116 accMiddle.read(); // To get the 0 into the shared buffer.
117
118 auto accMiddle2 = device.getScalarRegisterAccessor<int16_t>("MidByte");
119 accMiddle2.setAndWrite(0x100);
120 accTarget.read();
121 BOOST_TEST(accTarget == 0x0ff0);
122 // FIXME: This is currently not implemented in the plugin, because it needs changes in the fixed point converter
123 // see https://redmine.msktools.desy.de/issues/12912
124 // BOOST_CHECK(accMiddle2.dataValidity() == ChimeraTK::DataValidity::faulty);
125}
126
127/**********************************************************************************************************************/
128
129BOOST_AUTO_TEST_CASE(testMathPluginChaining) {
131 // Regression test that you can chain the bit range plugin with the math plugin
132 // The LoByteClamped register is the low-byte of SimpleScalar, but has a math plugin
133 // chained that will clamp the written value
134 device.open("(logicalNameMap?map=bitRangeReadPlugin.xlmap)");
135
136 auto accTarget = device.getScalarRegisterAccessor<int>("SimpleScalar");
137 accTarget.setAndWrite(0x1fff);
138
139 // Write some value in range (range is 0-5).
140 auto accClamped = device.getScalarRegisterAccessor<int8_t>("LoByteClamped");
141 accClamped.setAndWrite(0x01);
142 accTarget.read();
143 // Check that the value is passed through correctly and that the upper byte is unchanged.
144 BOOST_TEST(accTarget == 0x1f01);
145 BOOST_CHECK(accTarget.dataValidity() == ChimeraTK::DataValidity::ok);
146
147 // Write some value outside of the range clamped by the math plugin.
148 accClamped.setAndWrite(55);
149 accTarget.read();
150
151 // Check that the value is passed through the math plugin (clamped to max) and that the upper byte is unchanged.
152 BOOST_TEST(accTarget == 0x1f05);
153 BOOST_CHECK(accTarget.dataValidity() == ChimeraTK::DataValidity::ok);
154}
155
156/**********************************************************************************************************************/
157
158BOOST_AUTO_TEST_CASE(testBitExtraction) {
160 device.open("(logicalNameMap?map=bitRangeReadPlugin.xlmap)");
161
162 auto accTarget = device.getScalarRegisterAccessor<int>("SimpleScalar");
163 accTarget.setAndWrite(0x5555);
164
165 auto accRangedHi = device.getScalarRegisterAccessor<uint16_t>("HiByte");
166
171
172 // See that the bits we get match the value we have
173 accBit0.read();
174 accBit1.read();
175 accBit2.read();
176 accBit3.read();
177
178 BOOST_TEST(accBit0);
179 BOOST_TEST(!accBit1);
180 BOOST_TEST(accBit2);
181 BOOST_TEST(!accBit3);
182
183 // Write to the part that is not mapped to single bits
184 // make sure the single bits are not modified
185 accRangedHi.setAndWrite(0x11);
186 accTarget.read();
187
188 BOOST_TEST(accTarget == 0x1155);
189
190 accBit0.read();
191 accBit1.read();
192 accBit2.read();
193 accBit3.read();
194
195 BOOST_TEST(accBit0);
196 BOOST_TEST(!accBit1);
197 BOOST_TEST(accBit2);
198 BOOST_TEST(!accBit3);
199
200 // Toggle single bits, make sure that this does not spread across the rest of the bits
201 accBit1.setAndWrite(true);
202 accBit3.setAndWrite(true);
203
204 accTarget.read();
205
206 BOOST_TEST(accTarget == 0x115F);
207 accRangedHi.read();
208 BOOST_TEST(accRangedHi == 0x11);
209}
210
211/**********************************************************************************************************************/
212
213BOOST_AUTO_TEST_CASE(TestReadOnceRememberModifyWrite) {
214 ChimeraTK::Device device("(logicalNameMap?map=bitRangeReadPlugin.xlmap)");
215 device.open();
216
217 auto accTarget = device.getScalarRegisterAccessor<int>("SimpleScalar");
218 auto accLo = device.getScalarRegisterAccessor<uint16_t>("LoByte");
219
220 // Set initial value on the device. SimpleScalar is int16 so values must stay within range.
221 accTarget.setAndWrite(0x1234);
222
223 // First write to LoByte: this is the "read once" step.
224 // The decorator reads 0x1234 from the device into the shared buffer,
225 // modifies the low byte (0xAB → 0x34→0xAB), and writes back 0x12AB.
226 accLo = 0xAB;
227 accLo.write();
228 accTarget.read();
229 BOOST_TEST(accTarget == 0x12AB);
230
231 // Simulate another accessor modifying the underlying register directly.
232 // This bypasses the shared buffer.
233 accTarget.setAndWrite(0x3FFF); // still within int16
234
235 // Second write to LoByte: this is the "remember" step.
236 // The decorator does NOT re-read from the device. It uses the cached
237 // shared-buffer value (still 0x12AB, not the current device value 0x3FFF).
238 // So the write modifies 0x12AB → 0x1201, not 0x3FFF → 0x3F01.
239 accLo = 0x01;
240 accLo.write();
241 accTarget.read();
242 BOOST_TEST(accTarget == 0x1201);
243
244 // Demonstrate shared buffer between two bit-range accessors.
245 // Write to HiByte (first write): since shared buffer version is already >= versionOnOpen
246 // (set by previous LoByte writes), it also uses the cached value 0x1201 without reading.
247 accTarget.setAndWrite(0x7F23);
248 auto accHi = device.getScalarRegisterAccessor<uint16_t>("HiByte");
249 accHi = 0x3B;
250 accHi.write();
251 accTarget.read();
252 BOOST_TEST(accTarget == 0x3B01);
253
254 // Close and re-open the device.
255 device.close();
256 device.open();
257
258 // Modify value on the device.
259 accTarget.setAndWrite(0x7F00);
260
261 // First write to LoByte after re-open: must re-read from device.
262 accLo = 0x55;
263 accLo.write();
264 accTarget.read();
265 BOOST_TEST(accTarget == 0x7F55);
266}
267
268/**********************************************************************************************************************/
269
270BOOST_AUTO_TEST_CASE(testDataDescription) {
272 device.open("(logicalNameMap?map=bitRangeReadPlugin.xlmap)");
273
274 auto accTarget = device.getScalarRegisterAccessor<int>("SimpleScalar");
275 accTarget.setAndWrite(0x5555);
276
277 auto accLo = device.getScalarRegisterAccessor<uint8_t>("LoByte");
278 auto accLoSigned = device.getScalarRegisterAccessor<int8_t>("LowerSigned");
279
280 accLo.read();
281 accLoSigned.read();
282 BOOST_TEST(accLo == 85);
283 BOOST_TEST(accLoSigned == 85);
284
285 accTarget.setAndWrite(0x5580);
286
287 accLo.read();
288 accLoSigned.read();
289
290 BOOST_TEST(int(accLo) == 128);
291 BOOST_TEST(int(accLoSigned) == -128);
292
293 accTarget.setAndWrite(0x5555);
294 auto accFixed = device.getScalarRegisterAccessor<float>("LowerFixedPoint");
295 accFixed.read();
296 BOOST_TEST(accFixed == 5.3125);
297}
298
299/**********************************************************************************************************************/
300
301BOOST_AUTO_TEST_SUITE_END()
Wrapper Class to avoid vector<bool> problems.
Definition Boolean.h:16
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 open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Definition Device.cc:58
Group multiple data accessors to efficiently trigger data transfers on the whole group.
void addAccessor(TransferElementAbstractor &accessor)
Add a register accessor to the group.
void read()
Trigger read transfer for all accessors in the group.
Exception thrown when a logic error has occured.
Definition Exception.h:51
@ faulty
The data is considered valid.
ctk::Device device
BOOST_AUTO_TEST_CASE(testSimpleRead)