ChimeraTK-DeviceAccess 03.27.00
Loading...
Searching...
No Matches
testSubdeviceBackendRegisterWindowUnified.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
4#define BOOST_TEST_DYN_LINK
5#define BOOST_TEST_MODULE SubdeviceBackendUnifiedTest
6#include <boost/test/unit_test.hpp>
7using namespace boost::unit_test_framework;
8
11#include "UnifiedBackendTest.h"
12
13using namespace ChimeraTK;
14
15BOOST_AUTO_TEST_SUITE(SubdeviceBackendUnifiedTestSuite)
16
17/**********************************************************************************************************************/
18
19static std::string cdd("(ExceptionDummy:1?map=SubdeviceTarget.map)");
20
21static auto target = boost::dynamic_pointer_cast<ExceptionDummy>(BackendFactory::getInstance().createBackend(cdd));
22
23/**********************************************************************************************************************/
24
25struct StaticCore {
27 assert(target != nullptr);
28 data.setWriteCallback([this] { this->writeCallback(); });
29 area.setWriteCallback([this] { this->writeCallback(); });
30 readRequest.setWriteCallback([this] { this->readCallback(); });
31 }
32
33 DummyRegisterAccessor<uint32_t> transferAddress{target.get(), "APP.1", "ADDRESS"};
34 DummyRegisterAccessor<uint32_t> data{target.get(), "APP.1", "DATA"};
35 DummyRegisterAccessor<uint32_t> area{target.get(), "APP.0", "THE_AREA"};
36 DummyRegisterAccessor<uint32_t> status{target.get(), "APP.1", "STATUS"};
37 DummyRegisterAccessor<uint32_t> readData{target.get(), "APP.REG_WIN", "READOUT_SINGLE"};
38 DummyRegisterAccessor<uint32_t> readArea{target.get(), "APP.REG_WIN", "READOUT_AREA"};
39 DummyRegisterAccessor<uint32_t> readRequest{target.get(), "APP.REG_WIN", "READ_REQUEST"};
40 DummyRegisterAccessor<uint32_t> chipSelect{target.get(), "APP.REG_WIN", "CHIP_SELECT"};
41
42 // last address must be able to hold the full transfer width of the last transfer, even of the described register end earlier.
43 static constexpr uint32_t lastAddress{140}; // in bytes. End of APP.0.SIXTYFOUR_BIT is a complete transfer.
44 std::vector<std::byte> currentValue{std::vector<std::byte>(lastAddress)};
45 static constexpr size_t areaSize{10};
46 bool useStatus{true};
47 bool useArea{false};
48
49 size_t chipId{0};
50 size_t transferSize{4}; // in bytes
51
53 if(chipSelect != chipId) {
54 std::cout << "Error in writeCallback: chipSelect is " << chipSelect << ", expected " << chipId << std::endl;
55 return;
56 }
57
58 if(useStatus) {
59 status = 1;
60 }
62 lastAddress) { // the transfer address is in size of the transfer (up to 4 bytes)
63 std::cout << "Error: address (" << transferAddress << "*" << transferSize << ") >= lastAddress (" << lastAddress
64 << ")!" << std::endl;
65 }
66
67 BOOST_REQUIRE(transferAddress * transferSize < lastAddress);
68 if(!useArea) {
69 uint32_t theData = data;
71 }
72 else {
74 BOOST_REQUIRE((transferAddress + 1) * transferSize * areaSize <= lastAddress);
75 for(size_t i = 0; i < areaSize; ++i) {
76 uint32_t theData = area[i];
77 memcpy(&(currentValue[(transferAddress * areaSize + i) * transferSize]), &theData, transferSize);
78 }
79 }
80 usleep(432);
81 if(useStatus) {
82 status = 0;
83 }
84 }
85
86 void readCallback() {
87 if(chipSelect != chipId) {
88 std::cout << "Error in readCallback: chipSelect is " << chipSelect << ", expected " << chipId << std::endl;
89 return;
90 }
91
92 status = 1;
94 std::cout << "Error: address (" << transferAddress << "*" << transferSize << ") >= lastAddress (" << lastAddress
95 << ")!" << std::endl;
96 }
97
98 BOOST_REQUIRE(transferAddress * transferSize < lastAddress);
99 if(!useArea) {
100 uint32_t theData{0};
101 memcpy(&theData, &(currentValue[transferAddress * transferSize]), transferSize);
102 readData = theData;
103 }
104 else {
105 assert(area.getNumberOfElements() == areaSize);
106 BOOST_REQUIRE((transferAddress + 1) * transferSize * areaSize <= lastAddress);
107 for(size_t i = 0; i < areaSize; ++i) {
108 uint32_t theData{0};
109 memcpy(&theData, &(currentValue[(transferAddress * areaSize + i) * transferSize]), transferSize);
110 readArea[i] = theData;
111 }
112 }
113 usleep(432);
114 status = 0;
115 }
116};
117static StaticCore core;
118
119/**********************************************************************************************************************/
120
121template<typename Register>
122struct RegWindowType : Register {
123 bool isWriteable() { return true; }
124 bool isReadable() { return true; }
126 size_t nChannels() { return 1; }
127 size_t writeQueueLength() { return std::numeric_limits<size_t>::max(); }
128 size_t nRuntimeErrorCases() { return 1; }
129
130 static constexpr auto capabilities = TestCapabilities<>()
132 .disableAsyncReadInconsistency()
133 .enableTestRawTransfer()
134 .disableTestPartialAccessor();
135
136 using RegisterRawType = typename Register::rawUserType;
137
138 template<typename Type>
139 std::vector<std::vector<Type>> generateValue(bool raw = false) {
140 std::vector<Type> v;
141
142 assert(this->address() + this->nElementsPerChannel() * sizeof(RegisterRawType) <= core.lastAddress);
143 for(size_t i = 0; i < this->nElementsPerChannel(); ++i) {
145 auto* bufferStart = core.currentValue.data();
146 memcpy(&cv, bufferStart + i * sizeof(RegisterRawType) + this->address(), sizeof(RegisterRawType));
147
148 // Do the calculation in cooked, and convert back to raw if necessary
149 typename Register::minimumUserType e = this->fromRaw(cv) + this->increment * (i + 1);
150 auto limited = this->limitGenerated(e);
151 v.push_back(raw ? this->toRaw(limited) : limited);
152 }
153 return {v};
154 }
155
156 template<typename Type>
157 std::vector<std::vector<Type>> getRemoteValue(bool raw = false) {
158 std::vector<Type> v;
159
160 assert(this->address() + this->nElementsPerChannel() * sizeof(RegisterRawType) <= core.lastAddress);
161 for(size_t i = 0; i < this->nElementsPerChannel(); ++i) {
162 RegisterRawType rawValue;
163 auto* bufferStart = std::bit_cast<std::byte*>(core.currentValue.data());
164 memcpy(&rawValue, bufferStart + i * sizeof(RegisterRawType) + this->address(), sizeof(RegisterRawType));
165 v.push_back(raw ? rawValue : this->fromRaw(rawValue));
166 }
167 return {v};
168 }
169
171 auto v = generateValue<typename Register::minimumUserType>()[0];
172 auto* bufferStart = std::bit_cast<std::byte*>(core.currentValue.data());
173
174 assert(this->address() + this->nElementsPerChannel() * sizeof(RegisterRawType) <= core.lastAddress);
175 for(size_t i = 0; i < this->nElementsPerChannel(); ++i) {
176 auto rawVal = this->toRaw(v[i]);
177 static_assert(std::is_same_v<decltype(rawVal), RegisterRawType>);
178 memcpy(bufferStart + i * sizeof(RegisterRawType) + this->address(), &rawVal, sizeof(RegisterRawType));
179 }
180 }
181
182 void setForceRuntimeError(bool enable, size_t) {
183 target->throwExceptionRead = enable;
184 target->throwExceptionWrite = enable;
185 target->throwExceptionOpen = enable;
186 }
187};
188
189/**********************************************************************************************************************/
190
191template<typename Register>
192struct Regs3Type : RegWindowType<Register> {
193 bool isReadable() { return false; }
194};
195
196/**********************************************************************************************************************/
197
198template<typename Register>
199struct ReadOnlyType : RegWindowType<Register> {
200 bool isWriteable() { return false; }
201};
202
203/**********************************************************************************************************************/
204
206 std::string path() { return "/APP.0/MY_REGISTER1"; }
207 size_t nElementsPerChannel() { return 1; }
208 size_t address() { return 0; }
209 uint32_t toRaw(uint32_t v) { return v; }
210 uint32_t fromRaw(uint32_t v) { return v; }
211 uint32_t limitGenerated(uint32_t e) { return e; }
212 uint32_t increment = 7;
213 typedef uint32_t minimumUserType;
214 typedef uint32_t rawUserType;
215};
216
217/**********************************************************************************************************************/
218
219struct MyArea1 {
220 std::string path() { return "/APP.0/MY_AREA1"; }
221 size_t nElementsPerChannel() { return 6; }
222 size_t address() { return 8; }
223 uint32_t toRaw(double v) { return int32_t(v * 65536.); }
224 double fromRaw(uint32_t v) { return std::bit_cast<int32_t>(v) / 65536.; }
225 double limitGenerated(double e) {
226 while(e > 32768.F) e -= 65535.;
227 while(e < -32767.F) e += 65535.;
228 return e;
229 }
230 float increment = 666. / 65536.;
231 typedef double minimumUserType;
232 typedef uint32_t rawUserType;
233};
234
235/**********************************************************************************************************************/
236
238 std::string path() { return "/APP.0/THE_AREA_1"; }
239 size_t nElementsPerChannel() { return 10; }
240 size_t address() { return 0; }
241 uint32_t toRaw(uint32_t v) { return v; }
242 uint32_t fromRaw(uint32_t v) { return v; }
243 uint32_t limitGenerated(uint32_t e) { return e; }
244 uint32_t increment = 17;
245 typedef uint32_t minimumUserType;
246 typedef uint32_t rawUserType;
247};
248
249/**********************************************************************************************************************/
250
252 std::string path() { return "/APP.0/THE_AREA_2"; }
253 size_t nElementsPerChannel() { return 25; }
254 size_t address() { return 7; }
255 uint32_t toRaw(float v) { return v * 65536.F; }
256 float fromRaw(uint32_t v) { return v / 65536.F; }
257 float limitGenerated(float e) {
258 while(e > 32768.F) e -= 65535.F;
259 while(e < -32767.F) e += 65535.F;
260 return e;
261 }
262 float increment = 42. / 65536.;
263 typedef float minimumUserType;
264 typedef uint32_t rawUserType;
265};
266
267/**********************************************************************************************************************/
268
269struct EightBit {
270 static std::string path() { return "/APP.0/EIGHT_BIT"; }
271 static size_t nElementsPerChannel() { return 1; }
272 static size_t address() { return 100; }
273 static uint8_t toRaw(int8_t v) { return std::bit_cast<uint8_t>(v); }
274 static int8_t fromRaw(uint8_t v) { return std::bit_cast<int8_t>(v); }
275 static int8_t limitGenerated(int8_t e) { return e; }
276 int8_t increment{2};
277 using minimumUserType = int8_t;
278 using rawUserType = uint8_t;
279};
280
281/**********************************************************************************************************************/
282
284 static std::string path() { return "/APP.0/EIGHT_BIT_ARRAY"; }
285 static size_t nElementsPerChannel() { return 8; }
286 static size_t address() { return 100; }
287 static uint8_t toRaw(int8_t v) { return std::bit_cast<uint8_t>(v); }
288 static int8_t fromRaw(uint8_t v) { return std::bit_cast<int8_t>(v); }
289 static int8_t limitGenerated(int8_t e) { return e; }
290 int8_t increment{3};
291 using minimumUserType = int8_t;
292 using rawUserType = uint8_t;
293};
294
295/**********************************************************************************************************************/
296
298 static std::string path() { return "/APP.0/SIXTEEN_BIT"; }
299 static size_t nElementsPerChannel() { return 1; }
300 static size_t address() { return 108; }
301 static uint16_t toRaw(int16_t v) { return std::bit_cast<uint16_t>(v); }
302 static int16_t fromRaw(uint16_t v) { return std::bit_cast<int16_t>(v); }
303 static int16_t limitGenerated(int16_t e) { return e; }
304 int16_t increment{0x202};
305 using minimumUserType = int16_t;
306 using rawUserType = uint16_t;
307};
308
309/**********************************************************************************************************************/
310
312 static std::string path() { return "/APP.0/SIXTEEN_OFF1"; }
313 static size_t nElementsPerChannel() { return 1; }
314 static size_t address() { return 109; }
315 static uint16_t toRaw(int16_t v) { return std::bit_cast<uint16_t>(v); }
316 static int16_t fromRaw(uint16_t v) { return std::bit_cast<int16_t>(v); }
317 static int16_t limitGenerated(int16_t e) { return e; }
318 int16_t increment{0x303};
319 using minimumUserType = int16_t;
320 using rawUserType = uint16_t;
321};
322
323/**********************************************************************************************************************/
324
326 static std::string path() { return "/APP.0/SIXTEEN_OFF2"; }
327 static size_t nElementsPerChannel() { return 1; }
328 static size_t address() { return 110; }
329 static uint16_t toRaw(int16_t v) { return std::bit_cast<uint16_t>(v); }
330 static int16_t fromRaw(uint16_t v) { return std::bit_cast<int16_t>(v); }
331 static int16_t limitGenerated(int16_t e) { return e; }
332 int16_t increment{0x404};
333 using minimumUserType = int16_t;
334 using rawUserType = uint16_t;
335};
336
337/**********************************************************************************************************************/
338
340 static std::string path() { return "/APP.0/SIXTEEN_BIT_ARRAY"; }
341 static size_t nElementsPerChannel() { return 8; }
342 static size_t address() { return 112; }
343 static uint16_t toRaw(int16_t v) { return std::bit_cast<uint16_t>(v); }
344 static int16_t fromRaw(uint16_t v) { return std::bit_cast<int16_t>(v); }
345 static int16_t limitGenerated(int16_t e) { return e; }
346 int16_t increment{0x505};
347 using minimumUserType = int16_t;
348 using rawUserType = uint16_t;
349};
350
351/**********************************************************************************************************************/
352
354 static std::string path() { return "/APP.0/SIXTEEN_ARRAY_OFF2"; }
355 static size_t nElementsPerChannel() { return 8; }
356 static size_t address() { return 114; }
357 static uint16_t toRaw(int16_t v) { return std::bit_cast<uint16_t>(v); }
358 static int16_t fromRaw(uint16_t v) { return std::bit_cast<int16_t>(v); }
359 static int16_t limitGenerated(int16_t e) { return e; }
360 int16_t increment{0x606};
361 using minimumUserType = int16_t;
362 using rawUserType = uint16_t;
363};
364
365/**********************************************************************************************************************/
366
368 static std::string path() { return "/APP.0/SIXTYFOUR_BIT"; }
369 static size_t nElementsPerChannel() { return 1; }
370 static size_t address() { return 132; }
371 static uint64_t toRaw(int64_t v) { return std::bit_cast<uint64_t>(v); }
372 static int64_t fromRaw(uint64_t v) { return std::bit_cast<int64_t>(v); }
373 static int64_t limitGenerated(int64_t e) { return e; }
374 int64_t increment{0x600000006};
375 using minimumUserType = int64_t;
376 using rawUserType = uint64_t;
377};
378
379/**********************************************************************************************************************/
380
381BOOST_AUTO_TEST_CASE(TestUnified3Reg) {
382 // test 3regs type
384 "(subdevice?type=regWindow&device=" + cdd +
385 "&address=APP.1.ADDRESS&data=APP.1.DATA&status=APP.1.STATUS&map=Subdevice.map)");
386}
387
388/**********************************************************************************************************************/
389
390BOOST_AUTO_TEST_CASE(TestUnified2Reg) {
391 // test 2regs type
392 core.useStatus = false;
394 "(subdevice?type=regWindow&device=" + cdd +
395 "&address=APP.1.ADDRESS&data=APP.1.DATA&sleep=1000&map=Subdevice.map)");
396}
397
398/**********************************************************************************************************************/
399
400BOOST_AUTO_TEST_CASE(TestUnifiedMuxed3Reg) {
401 // test different use case of 3regs mode: multiplexing of an area
402
403 core.useStatus = true;
404 core.useArea = true;
406 "(subdevice?type=regWindow&device=" + cdd +
407 "&address=APP.1.ADDRESS&data=APP.0.THE_AREA&status=APP.1.STATUS&map=SubdeviceMuxedArea.map)");
408}
409
410/**********************************************************************************************************************/
411
412BOOST_AUTO_TEST_CASE(TestUnifiedRegWindow) {
413 core.chipId = 3;
414 core.useArea = false;
416 "(subdevice?type=regWindow&device=" + cdd +
417 "&address=APP.1.ADDRESS&writeData=APP.1.DATA&busy=APP.1.STATUS&readRequest=APP.REG_WIN.READ_REQUEST&readData=APP."
418 "REG_WIN.READOUT_SINGLE&chipSelectRegister=APP.REG_WIN.CHIP_SELECT&chipIndex=3&map=Subdevice.map)");
419}
420
421/**********************************************************************************************************************/
422
423BOOST_AUTO_TEST_CASE(TestUnifiedMuxedRegwindow) {
424 // multiplexing of an area (whatever that means? Why multiplexing?) with read and write
425 core.chipId = 0; // test without the optional chipIndex parameter
426 core.useArea = true;
428 "(subdevice?type=regWindow&device=" + cdd +
429 "&address=APP.1.ADDRESS&writeData=APP.0.THE_AREA&busy=APP.1.STATUS&readRequest=APP.REG_WIN.READ_REQUEST&readData="
430 "APP.REG_WIN.READOUT_AREA&chipSelectRegister=APP.REG_WIN.CHIP_SELECT&map=SubdeviceMuxedArea.map)");
431}
432
433/**********************************************************************************************************************/
434
435BOOST_AUTO_TEST_CASE(TestUnifiedReadOnly) {
436 core.chipId = 3;
437 core.useArea = false;
440 .addRegister<ReadOnlyType<MyArea1>>()
441 .runTests("(subdevice?type=regWindow&device=" + cdd +
442 "&address=APP.1.ADDRESS&busy=APP.1.STATUS&readRequest=APP.REG_WIN.READ_REQUEST&readData=APP."
443 "REG_WIN.READOUT_SINGLE&chipSelectRegister=APP.REG_WIN.CHIP_SELECT&chipIndex=3&map=Subdevice.map)");
444}
445
446/**********************************************************************************************************************/
447
449 core.chipId = 0;
452 .addRegister<RegWindowType<EightBitArray>>()
453 .runTests("(subdevice?type=regWindow&device=" + cdd +
454 "&address=APP.1.ADDRESS&writeData=APP.1.DATA&busy=APP.1.STATUS&readRequest=APP.REG_WIN.READ_REQUEST&readData="
455 "APP.REG_WIN.READOUT_SINGLE&chipSelectRegister=APP.REG_WIN.CHIP_SELECT&map=Subdevice.map)");
456}
457
458/**********************************************************************************************************************/
459
463 .addRegister<RegWindowType<SixteenBitOff1>>()
464 .addRegister<RegWindowType<SixteenBitOff2>>()
465 .addRegister<RegWindowType<SixteenBitArray>>()
467 .runTests("(subdevice?type=regWindow&device=" + cdd +
468 "&address=APP.1.ADDRESS&writeData=APP.1.DATA&busy=APP.1.STATUS&readRequest=APP.REG_WIN.READ_REQUEST&readData="
469 "APP.REG_WIN.READOUT_SINGLE&chipSelectRegister=APP.REG_WIN.CHIP_SELECT&map=Subdevice.map)");
470}
471
472/**********************************************************************************************************************/
473
475 core.chipId = 0;
477 "(subdevice?type=regWindow&device=" + cdd +
478 "&address=APP.1.ADDRESS&writeData=APP.1.DATA&busy=APP.1.STATUS&readRequest=APP.REG_WIN.READ_REQUEST&readData="
479 "APP.REG_WIN.READOUT_SINGLE&chipSelectRegister=APP.REG_WIN.CHIP_SELECT&map=Subdevice.map)");
480}
481
482/**********************************************************************************************************************/
483
484BOOST_AUTO_TEST_CASE(TestTransfer8) {
485 core.transferSize = 1;
488 .addRegister<RegWindowType<EightBitArray>>()
489 .addRegister<RegWindowType<SixteenBit>>()
490 .addRegister<RegWindowType<SixteenBitOff1>>()
491 .addRegister<RegWindowType<SixteenBitOff2>>()
492 .addRegister<RegWindowType<SixteenBitArray>>()
494 .addRegister<RegWindowType<MyRegister1>>()
495 .addRegister<RegWindowType<MyArea1>>()
496 .addRegister<RegWindowType<SixtyFourBit>>()
497 .runTests("(subdevice?type=regWindow&device=" + cdd +
498 "&address=APP.1.ADDRESS&writeData=APP.1.WRITE_DATA_8BIT&busy=APP.1.STATUS&readRequest=APP.REG_WIN.READ_"
499 "REQUEST&readData=APP.REG_WIN.READOUT_8BIT&chipSelectRegister=APP.REG_WIN.CHIP_SELECT&map=Subdevice.map)");
500}
501/**********************************************************************************************************************/
502
503BOOST_AUTO_TEST_SUITE_END()
Set of AccessMode flags with additional functionality for an easier handling.
Definition AccessMode.h:48
static BackendFactory & getInstance()
Static function to get an instance of factory.
Register accessor for accessing single word or 1D array registers internally of a DummyBackend implem...
unsigned int getNumberOfElements()
return number of elements
void setWriteCallback(const std::function< void()> &writeCallback)
Set callback function which is called when the register is written to (through the normal Device inte...
Class to test any backend for correct behaviour.
UnifiedBackendTest< typename boost::mpl::push_back< VECTOR_OF_REGISTERS_T, REG_T >::type > addRegister()
Add a register to be used by the test.
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
Descriptor for the test capabilities for each register.
constexpr TestCapabilities< _syncRead, TestCapability::disabled, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableForceDataLossWrite() const
static int8_t limitGenerated(int8_t e)
std::vector< std::vector< Type > > generateValue(bool raw=false)
std::vector< std::vector< Type > > getRemoteValue(bool raw=false)
ChimeraTK::AccessModeFlags supportedFlags()
typename Register::rawUserType RegisterRawType
void setForceRuntimeError(bool enable, size_t)
static int16_t limitGenerated(int16_t e)
DummyRegisterAccessor< uint32_t > area
std::vector< std::byte > currentValue
DummyRegisterAccessor< uint32_t > data
DummyRegisterAccessor< uint32_t > transferAddress
DummyRegisterAccessor< uint32_t > readArea
DummyRegisterAccessor< uint32_t > status
DummyRegisterAccessor< uint32_t > chipSelect
DummyRegisterAccessor< uint32_t > readRequest
DummyRegisterAccessor< uint32_t > readData
static constexpr uint32_t lastAddress
std::string cdd
BOOST_AUTO_TEST_CASE(TestUnified3Reg)