ChimeraTK-DeviceAccess  03.18.00
testSubdeviceBackendUnified.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>
7 using namespace boost::unit_test_framework;
8 
9 #include "Device.h"
10 #include "DummyRegisterAccessor.h"
11 #include "ExceptionDummyBackend.h"
12 #include "UnifiedBackendTest.h"
13 
14 using namespace ChimeraTK;
15 
16 BOOST_AUTO_TEST_SUITE(SubdeviceBackendUnifiedTestSuite)
17 
18 /**********************************************************************************************************************/
19 
20 static std::string cdd("(ExceptionDummy:1?map=SubdeviceTarget.map)");
21 static auto target = boost::dynamic_pointer_cast<ExceptionDummy>(BackendFactory::getInstance().createBackend(cdd));
22 
23 /**********************************************************************************************************************/
24 
25 template<typename Register>
26 struct AreaType : Register {
27  bool isWriteable() { return true; }
28  bool isReadable() { return true; }
30  size_t nChannels() { return 1; }
31  size_t writeQueueLength() { return std::numeric_limits<size_t>::max(); }
32  size_t nRuntimeErrorCases() { return 1; }
33 
34  static constexpr auto capabilities =
35  TestCapabilities<>().disableForceDataLossWrite().disableAsyncReadInconsistency().enableTestRawTransfer();
36 
37  DummyRegisterAccessor<uint32_t> acc{target.get(), "APP.0", "THE_AREA"};
38 
39  template<typename UserType>
40  std::vector<std::vector<UserType>> generateValue(bool raw = false) {
41  std::vector<UserType> v;
42  for(size_t i = 0; i < this->nElementsPerChannel(); ++i) {
43  assert(i + this->address() / 4 < 10);
44  typename Register::minimumUserType e = acc[i + this->address() / 4] + this->increment * (i + 1);
45  auto limited = this->limitGenerated(e);
46  v.push_back(raw ? this->toRaw(limited) : limited);
47  }
48  return {v};
49  }
50 
51  // Use the same implementation for raw and cooked.
52  // Type can be UserType or RawType
53  template<typename Type>
54  std::vector<std::vector<Type>> getRemoteValue(bool raw = false) {
55  std::vector<Type> v;
56  for(size_t i = 0; i < this->nElementsPerChannel(); ++i) {
57  assert(i + this->address() / 4 < 10);
58  auto rawVal = acc[i + this->address() / 4];
59  v.push_back((raw ? rawVal : this->fromRaw(rawVal)));
60  }
61  return {v};
62  }
63 
64  void setRemoteValue() {
65  auto v = generateValue<typename Register::minimumUserType>()[0];
66  for(size_t i = 0; i < this->nElementsPerChannel(); ++i) {
67  assert(i + this->address() / 4 < 10);
68  acc[i + this->address() / 4] = this->toRaw(v[i]);
69  }
70  }
71 
72  void setForceRuntimeError(bool enable, size_t) {
73  target->throwExceptionRead = enable;
74  target->throwExceptionWrite = enable;
75  target->throwExceptionOpen = enable;
76  }
77 };
78 
79 /**********************************************************************************************************************/
80 
81 struct StaticCore {
83  assert(target != nullptr);
84  data.setWriteCallback([this] { this->writeCallback(); });
85  area.setWriteCallback([this] { this->writeCallback(); });
86  }
87 
88  DummyRegisterAccessor<uint32_t> address{target.get(), "APP.1", "ADDRESS"};
89  DummyRegisterAccessor<uint32_t> data{target.get(), "APP.1", "DATA"};
90  DummyRegisterAccessor<uint32_t> area{target.get(), "APP.0", "THE_AREA"};
91  DummyRegisterAccessor<uint32_t> status{target.get(), "APP.1", "STATUS"};
92  size_t lastAddress{32};
93  std::vector<uint32_t> currentValue{std::vector<uint32_t>(lastAddress)};
94  size_t areaSize{10};
95  std::vector<std::vector<uint32_t>> currentAreaValue{lastAddress, std::vector<uint32_t>(areaSize)};
96 
97  bool useStatus{true};
98  bool useArea{false};
99 
100  void writeCallback() {
101  if(useStatus) status = 1;
102  if(address >= lastAddress) {
103  std::cout << "Error: address (" << address << ") >= lastAddress (" << lastAddress << ")!" << std::endl;
104  }
105  BOOST_REQUIRE(address < lastAddress);
106  if(!useArea) {
107  currentValue[address] = data;
108  }
109  else {
110  assert(area.getNumberOfElements() == areaSize);
111  for(size_t i = 0; i < areaSize; ++i) {
112  currentAreaValue[address][i] = area[i];
113  }
114  }
115  usleep(432);
116  if(useStatus) status = 0;
117  }
118 };
119 static StaticCore core;
120 
121 /**********************************************************************************************************************/
122 
123 template<typename Register>
124 struct Regs3Type : Register {
125  bool isWriteable() { return true; }
126  bool isReadable() { return false; }
128  size_t nChannels() { return 1; }
129  size_t writeQueueLength() { return std::numeric_limits<size_t>::max(); }
130  size_t nRuntimeErrorCases() { return 1; }
131 
132  static constexpr auto capabilities =
133  TestCapabilities<>().disableForceDataLossWrite().disableAsyncReadInconsistency().enableTestRawTransfer();
134 
135  template<typename Type>
136  std::vector<std::vector<Type>> generateValue(bool raw = false) {
137  std::vector<Type> v;
138  for(size_t i = 0; i < this->nElementsPerChannel(); ++i) {
139  uint32_t cv;
140  if(!core.useArea) {
141  cv = core.currentValue[i + this->address()];
142  }
143  else {
144  cv = core.currentAreaValue[this->address() + i / core.areaSize][i % core.areaSize];
145  }
146  // Do the calculation in cooked, and convert back to raw if necessary
147  typename Register::minimumUserType e = this->fromRaw(cv) + this->increment * (i + 1);
148  auto limited = this->limitGenerated(e);
149  v.push_back(raw ? this->toRaw(limited) : limited);
150  }
151  return {v};
152  }
153 
154  template<typename Type>
155  std::vector<std::vector<Type>> getRemoteValue(bool raw = false) {
156  std::vector<Type> v;
157  for(size_t i = 0; i < this->nElementsPerChannel(); ++i) {
158  Type rawValue;
159  if(!core.useArea) {
160  rawValue = core.currentValue[i + this->address()];
161  }
162  else {
163  rawValue = core.currentAreaValue[this->address() + i / core.areaSize][i % core.areaSize];
164  }
165  v.push_back(raw ? rawValue : this->fromRaw(rawValue));
166  }
167  return {v};
168  }
169 
170  void setRemoteValue() {
171  auto v = generateValue<typename Register::minimumUserType>()[0];
172  for(size_t i = 0; i < this->nElementsPerChannel(); ++i) {
173  if(!core.useArea) {
174  core.currentValue[i + this->address()] = this->toRaw(v[i]);
175  }
176  else {
177  core.currentAreaValue[this->address() + i / core.areaSize][i % core.areaSize] = this->toRaw(v[i]);
178  }
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 
191 struct MyRegister1 {
192  std::string path() { return "/APP.0/MY_REGISTER1"; }
193  size_t nElementsPerChannel() { return 1; }
194  size_t address() { return 0; }
195  uint32_t toRaw(uint32_t v) { return v; }
196  uint32_t fromRaw(uint32_t v) { return v; }
197  uint32_t limitGenerated(uint32_t e) { return e; }
198  uint32_t increment = 7;
199  typedef uint32_t minimumUserType;
200  typedef int32_t rawUserType;
201 };
202 
203 /**********************************************************************************************************************/
204 
205 struct MyArea1 {
206  std::string path() { return "/APP.0/MY_AREA1"; }
207  size_t nElementsPerChannel() { return 6; }
208  size_t address() { return 8; }
209  uint32_t toRaw(float v) { return v * 65536.F; }
210  float fromRaw(uint32_t v) { return v / 65536.F; }
211  float limitGenerated(float e) {
212  while(e > 32768.F) e -= 65535.F;
213  while(e < -32767.F) e += 65535.F;
214  return e;
215  }
216  float increment = 666. / 65536.;
217  typedef float minimumUserType;
218  typedef int32_t rawUserType;
219 };
220 
221 /**********************************************************************************************************************/
222 
223 struct MuxedArea1 {
224  std::string path() { return "/APP.0/THE_AREA_1"; }
225  size_t nElementsPerChannel() { return 10; }
226  size_t address() { return 0; }
227  uint32_t toRaw(uint32_t v) { return v; }
228  uint32_t fromRaw(uint32_t v) { return v; }
229  uint32_t limitGenerated(uint32_t e) { return e; }
230  uint32_t increment = 17;
231  typedef uint32_t minimumUserType;
232  typedef int32_t rawUserType;
233 };
234 
235 /**********************************************************************************************************************/
236 
237 struct MuxedArea2 {
238  std::string path() { return "/APP.0/THE_AREA_2"; }
239  size_t nElementsPerChannel() { return 25; }
240  size_t address() { return 7; }
241  uint32_t toRaw(float v) { return v * 65536.F; }
242  float fromRaw(uint32_t v) { return v / 65536.F; }
243  float limitGenerated(float e) {
244  while(e > 32768.F) e -= 65535.F;
245  while(e < -32767.F) e += 65535.F;
246  return e;
247  }
248  float increment = 42. / 65536.;
249  typedef float minimumUserType;
250  typedef int32_t rawUserType;
251 };
252 
253 /**********************************************************************************************************************/
254 
255 BOOST_AUTO_TEST_CASE(testUnified) {
256  // test area type
258  "(subdevice?type=area&device=" + cdd + "&area=APP.0.THE_AREA&map=Subdevice.map)");
259 
260  // test 3regs type
262  "(subdevice?type=3regs&device=" + cdd +
263  "&address=APP.1.ADDRESS&data=APP.1.DATA&status=APP.1.STATUS&map=Subdevice.map)");
264 
265  // test 2regs type
266  core.useStatus = false;
268  "(subdevice?type=2regs&device=" + cdd + "&address=APP.1.ADDRESS&data=APP.1.DATA&sleep=1000&map=Subdevice.map)");
269 
270  // test different use case of 3regs mode: multiplexing of an area
271  core.useStatus = true;
272  core.useArea = true;
273  core.lastAddress = 10;
275  "(subdevice?type=3regs&device=" + cdd +
276  "&address=APP.1.ADDRESS&data=APP.0.THE_AREA&status=APP.1.STATUS&map=SubdeviceMuxedArea.map)");
277 }
278 
279 /**********************************************************************************************************************/
280 
281 BOOST_AUTO_TEST_SUITE_END()
ExceptionDummyBackend.h
MuxedArea1::nElementsPerChannel
size_t nElementsPerChannel()
Definition: testSubdeviceBackendUnified.cpp:225
MuxedArea2::rawUserType
int32_t rawUserType
Definition: testSubdeviceBackendUnified.cpp:250
Regs3Type::generateValue
std::vector< std::vector< Type > > generateValue(bool raw=false)
Definition: testSubdeviceBackendUnified.cpp:136
AreaType
Definition: testDoubleBuffering.cpp:81
StaticCore::writeCallback
void writeCallback()
Definition: testSubdeviceBackendUnified.cpp:100
ChimeraTK::AccessMode::raw
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
StaticCore::areaSize
size_t areaSize
Definition: testSubdeviceBackendUnified.cpp:94
MyArea1::address
size_t address()
Definition: testSubdeviceBackendUnified.cpp:208
AreaType::setForceRuntimeError
void setForceRuntimeError(bool enable, size_t)
Definition: testSubdeviceBackendUnified.cpp:72
ChimeraTK::DummyRegisterAccessor< uint32_t >
MuxedArea1
Definition: testSubdeviceBackendUnified.cpp:223
MuxedArea2::path
std::string path()
Definition: testSubdeviceBackendUnified.cpp:238
MuxedArea1::minimumUserType
uint32_t minimumUserType
Definition: testSubdeviceBackendUnified.cpp:231
MuxedArea2::nElementsPerChannel
size_t nElementsPerChannel()
Definition: testSubdeviceBackendUnified.cpp:239
AreaType::nChannels
size_t nChannels()
Definition: testSubdeviceBackendUnified.cpp:30
Regs3Type::isWriteable
bool isWriteable()
Definition: testSubdeviceBackendUnified.cpp:125
MyRegister1::address
size_t address()
Definition: testSubdeviceBackendUnified.cpp:194
Regs3Type::isReadable
bool isReadable()
Definition: testSubdeviceBackendUnified.cpp:126
MyArea1::limitGenerated
float limitGenerated(float e)
Definition: testSubdeviceBackendUnified.cpp:211
AreaType::getRemoteValue
std::vector< std::vector< Type > > getRemoteValue(bool raw=false)
Definition: testSubdeviceBackendUnified.cpp:54
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(testUnified)
Definition: testSubdeviceBackendUnified.cpp:255
AreaType::supportedFlags
ChimeraTK::AccessModeFlags supportedFlags()
Definition: testSubdeviceBackendUnified.cpp:29
Regs3Type
Definition: testSubdeviceBackendUnified.cpp:124
Regs3Type::supportedFlags
ChimeraTK::AccessModeFlags supportedFlags()
Definition: testSubdeviceBackendUnified.cpp:127
Regs3Type::writeQueueLength
size_t writeQueueLength()
Definition: testSubdeviceBackendUnified.cpp:129
MyRegister1::toRaw
uint32_t toRaw(uint32_t v)
Definition: testSubdeviceBackendUnified.cpp:195
StaticCore::useArea
bool useArea
Definition: testSubdeviceBackendUnified.cpp:98
StaticCore::StaticCore
StaticCore()
Definition: testSubdeviceBackendUnified.cpp:82
AreaType::generateValue
std::vector< std::vector< UserType > > generateValue(bool raw=false)
Definition: testSubdeviceBackendUnified.cpp:40
cdd
std::string cdd
Definition: testAsyncRead.cpp:25
ChimeraTK::TestCapabilities
Descriptor for the test capabilities for each register.
Definition: UnifiedBackendTest.h:54
MuxedArea2
Definition: testSubdeviceBackendUnified.cpp:237
AreaType::nRuntimeErrorCases
size_t nRuntimeErrorCases()
Definition: testSubdeviceBackendUnified.cpp:32
MyRegister1
Definition: testSubdeviceBackendUnified.cpp:191
MyArea1
Definition: testDoubleBuffering.cpp:205
Regs3Type::setRemoteValue
void setRemoteValue()
Definition: testSubdeviceBackendUnified.cpp:170
F
Definition: testRebotConnectionTimeouts.cpp:20
MyRegister1::minimumUserType
uint32_t minimumUserType
Definition: testSubdeviceBackendUnified.cpp:199
MyRegister1::limitGenerated
uint32_t limitGenerated(uint32_t e)
Definition: testSubdeviceBackendUnified.cpp:197
AreaType::isReadable
bool isReadable()
Definition: testSubdeviceBackendUnified.cpp:28
MuxedArea1::fromRaw
uint32_t fromRaw(uint32_t v)
Definition: testSubdeviceBackendUnified.cpp:228
MyArea1::path
std::string path()
Definition: testSubdeviceBackendUnified.cpp:206
StaticCore
Definition: testSubdeviceBackendUnified.cpp:81
Device.h
MuxedArea1::rawUserType
int32_t rawUserType
Definition: testSubdeviceBackendUnified.cpp:232
StaticCore::lastAddress
size_t lastAddress
Definition: testSubdeviceBackendUnified.cpp:92
MyRegister1::rawUserType
int32_t rawUserType
Definition: testSubdeviceBackendUnified.cpp:200
MuxedArea1::toRaw
uint32_t toRaw(uint32_t v)
Definition: testSubdeviceBackendUnified.cpp:227
ChimeraTK::UnifiedBackendTest
Class to test any backend for correct behaviour.
Definition: UnifiedBackendTest.h:259
Regs3Type::nChannels
size_t nChannels()
Definition: testSubdeviceBackendUnified.cpp:128
MuxedArea2::address
size_t address()
Definition: testSubdeviceBackendUnified.cpp:240
MuxedArea2::minimumUserType
float minimumUserType
Definition: testSubdeviceBackendUnified.cpp:249
Regs3Type::nRuntimeErrorCases
size_t nRuntimeErrorCases()
Definition: testSubdeviceBackendUnified.cpp:130
AreaType::setRemoteValue
void setRemoteValue()
Definition: testSubdeviceBackendUnified.cpp:64
ChimeraTK::TestCapabilities::disableForceDataLossWrite
constexpr TestCapabilities< _syncRead, TestCapability::disabled, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion > disableForceDataLossWrite() const
Definition: UnifiedBackendTest.h:81
MuxedArea2::fromRaw
float fromRaw(uint32_t v)
Definition: testSubdeviceBackendUnified.cpp:242
MyRegister1::nElementsPerChannel
size_t nElementsPerChannel()
Definition: testSubdeviceBackendUnified.cpp:193
MyArea1::rawUserType
int32_t rawUserType
Definition: testSubdeviceBackendUnified.cpp:218
MuxedArea2::limitGenerated
float limitGenerated(float e)
Definition: testSubdeviceBackendUnified.cpp:243
MyRegister1::path
std::string path()
Definition: testSubdeviceBackendUnified.cpp:192
Regs3Type::setForceRuntimeError
void setForceRuntimeError(bool enable, size_t)
Definition: testSubdeviceBackendUnified.cpp:182
DummyRegisterAccessor.h
StaticCore::currentValue
std::vector< uint32_t > currentValue
Definition: testSubdeviceBackendUnified.cpp:93
MuxedArea1::path
std::string path()
Definition: testSubdeviceBackendUnified.cpp:224
MuxedArea1::address
size_t address()
Definition: testSubdeviceBackendUnified.cpp:226
AreaType::isWriteable
bool isWriteable()
Definition: testSubdeviceBackendUnified.cpp:27
AreaType::writeQueueLength
size_t writeQueueLength()
Definition: testSubdeviceBackendUnified.cpp:31
MyArea1::nElementsPerChannel
size_t nElementsPerChannel()
Definition: testSubdeviceBackendUnified.cpp:207
ChimeraTK::AccessModeFlags
Set of AccessMode flags with additional functionality for an easier handling.
Definition: AccessMode.h:48
MuxedArea2::toRaw
uint32_t toRaw(float v)
Definition: testSubdeviceBackendUnified.cpp:241
MyRegister1::fromRaw
uint32_t fromRaw(uint32_t v)
Definition: testSubdeviceBackendUnified.cpp:196
StaticCore::useStatus
bool useStatus
Definition: testSubdeviceBackendUnified.cpp:97
Regs3Type::getRemoteValue
std::vector< std::vector< Type > > getRemoteValue(bool raw=false)
Definition: testSubdeviceBackendUnified.cpp:155
MuxedArea1::limitGenerated
uint32_t limitGenerated(uint32_t e)
Definition: testSubdeviceBackendUnified.cpp:229
ChimeraTK
Definition: DummyBackend.h:16
UnifiedBackendTest.h
StaticCore::currentAreaValue
std::vector< std::vector< uint32_t > > currentAreaValue
Definition: testSubdeviceBackendUnified.cpp:95
MyArea1::minimumUserType
float minimumUserType
Definition: testSubdeviceBackendUnified.cpp:217
MyArea1::toRaw
uint32_t toRaw(float v)
Definition: testSubdeviceBackendUnified.cpp:209
ChimeraTK::UnifiedBackendTest::addRegister
UnifiedBackendTest< typename boost::mpl::push_back< VECTOR_OF_REGISTERS_T, REG_T >::type > addRegister()
Add a register to be used by the test.
Definition: UnifiedBackendTest.h:352
MyArea1::fromRaw
float fromRaw(uint32_t v)
Definition: testSubdeviceBackendUnified.cpp:210