8#include <boost/fusion/include/at_key.hpp>
9#include <boost/test/unit_test.hpp>
19#pragma GCC diagnostic ignored "-Wshadow"
64 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
65 _setRemoteValueIncrementsVersion, _testPartialAccessor>
73 _setRemoteValueIncrementsVersion, _testPartialAccessor>
76 "enableTestWriteNeverLosesData() and enableForceDataLossWrite() are mutually exclusive.");
80 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
81 _setRemoteValueIncrementsVersion, _testPartialAccessor>
88 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
89 _setRemoteValueIncrementsVersion, _testPartialAccessor>
94 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
95 _setRemoteValueIncrementsVersion, _testPartialAccessor>
102 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
103 _setRemoteValueIncrementsVersion, _testPartialAccessor>
108 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
109 _setRemoteValueIncrementsVersion, _testPartialAccessor>
115 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
116 TestCapability::enabled, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
117 _setRemoteValueIncrementsVersion, _testPartialAccessor>
121 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
123 _setRemoteValueIncrementsVersion, _testPartialAccessor>
133 _setRemoteValueIncrementsVersion, _testPartialAccessor>
136 "enableTestWriteNeverLosesData() and enableForceDataLossWrite() are mutualy exclusive.");
139 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
141 _setRemoteValueIncrementsVersion, _testPartialAccessor>
147 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
149 _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor>
153 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
155 _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor>
161 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
163 _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor>
167 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
169 _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor>
175 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
177 _setRemoteValueIncrementsVersion, _testPartialAccessor>
181 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
182 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly,
TestCapability::enabled, _testCatalogue,
183 _setRemoteValueIncrementsVersion, _testPartialAccessor>
189 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
190 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer,
195 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
196 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer,
203 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
204 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
209 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
210 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
217 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
218 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
223 constexpr TestCapabilities<_syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly,
224 _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue,
274 template<
typename VECTOR_OF_REGISTERS_T = boost::mpl::vector<>>
367 template<
typename REG_T>
379 using std::list<std::pair<std::function<void(
void)>, std::function<void(
void)>>>::list;
388 void runTests(
const std::string& cdd_,
const std::string& cdd2_ =
"");
452 template<
typename REG_T>
456 return x.isReadable();
458 template<
typename REG_T>
461 return x.isWriteable();
463 template<
typename REG_T>
468 template<
typename REG_T>
473 template<
typename REG_T>
477 template<
typename REG_T>
479 return !x.isWriteable() && x.isReadable();
481 template<
typename REG_T>
483 return x.isWriteable() && !x.isReadable();
501 _hasSeenException =
true;
510 bool ret = _hasSeenException;
511 _hasSeenException =
false;
522 boost::shared_ptr<DeviceBackend> _target;
523 bool _hasSeenException{
false};
535 std::cout <<
"Unexpected use of disabled capability." << std::endl;
554 std::cout <<
"Unexpected use of disabled capability." << std::endl;
573 std::cout <<
"Unexpected use of disabled capability." << std::endl;
592 std::cout <<
"Unexpected use of disabled capability." << std::endl;
614 std::cout <<
"Unexpected use of disabled capability." << std::endl;
634 static one test(
decltype(&C::nValuesToTest));
636 static two test(...);
639 enum { value =
sizeof(test<T>(0)) ==
sizeof(
char) };
642 template<typename T, bool hasFn = has_nValuesToTest<T>::value>
671 template<
typename UserType>
678 return std::abs(a - b) <= std::numeric_limits<double>::epsilon() * 10. * std::max(std::abs(a), std::abs(b));
683 return std::abs(a - b) <= std::numeric_limits<float>::epsilon() * 10.F * std::max(std::abs(a), std::abs(b));
714#define CHECK_EQUALITY(accessor, expectedValue) \
716 typedef typename decltype(expectedValue)::value_type::value_type CHECK_EQUALITY_UserType; \
718 BOOST_CHECK_EQUAL(accessor.getNChannels(), expectedValue.size()); \
719 BOOST_CHECK_EQUAL(accessor.getNElementsPerChannel(), expectedValue[0].size()); \
720 bool CHECK_EQUALITY_warnExpectedZero = true; \
721 for(size_t CHECK_EQUALITY_i = 0; CHECK_EQUALITY_i < expectedValue.size(); ++CHECK_EQUALITY_i) { \
722 for(size_t CHECK_EQUALITY_k = 0; CHECK_EQUALITY_k < expectedValue[0].size(); ++CHECK_EQUALITY_k) { \
723 if(CHECK_EQUALITY_warnExpectedZero && \
724 !compareHelper(expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k], CHECK_EQUALITY_UserType())) { \
726 CHECK_EQUALITY_warnExpectedZero = false; \
729 accessor[CHECK_EQUALITY_i][CHECK_EQUALITY_k], expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k])) { \
731 fail = "Accessor content differs from expected value. First difference at index [" + \
732 std::to_string(CHECK_EQUALITY_i) + "][" + std::to_string(CHECK_EQUALITY_k) + \
733 "]: " + std::to_string(accessor[CHECK_EQUALITY_i][CHECK_EQUALITY_k]) + \
734 " != " + std::to_string(expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k]); \
739 if(!fail.empty()) { \
742 if(CHECK_EQUALITY_warnExpectedZero && !std::is_same<CHECK_EQUALITY_UserType, ChimeraTK::Boolean>::value) { \
743 BOOST_ERROR("Comparison with all-zero expectedValue! Test may be insensitive! Check the " \
744 "generateValue() implementations!"); \
750#define CHECK_EQUALITY_VECTOR(foundValue, expectedValue) \
752 typedef typename decltype(expectedValue)::value_type::value_type CHECK_EQUALITY_UserType; \
754 BOOST_CHECK_EQUAL(foundValue.size(), expectedValue.size()); \
755 BOOST_CHECK_EQUAL(foundValue[0].size(), expectedValue[0].size()); \
756 bool CHECK_EQUALITY_warnExpectedZero = true; \
757 for(size_t CHECK_EQUALITY_i = 0; CHECK_EQUALITY_i < expectedValue.size(); ++CHECK_EQUALITY_i) { \
758 for(size_t CHECK_EQUALITY_k = 0; CHECK_EQUALITY_k < expectedValue[0].size(); ++CHECK_EQUALITY_k) { \
759 if(CHECK_EQUALITY_warnExpectedZero && \
760 !compareHelper(expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k], CHECK_EQUALITY_UserType())) { \
762 CHECK_EQUALITY_warnExpectedZero = false; \
765 foundValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k], expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k])) { \
767 fail = "Data content differs from expected value. First difference at index [" + \
768 std::to_string(CHECK_EQUALITY_i) + "][" + std::to_string(CHECK_EQUALITY_k) + \
769 "]: " + std::to_string(foundValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k]) + \
770 " != " + std::to_string(expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k]); \
775 if(!fail.empty()) { \
778 if(CHECK_EQUALITY_warnExpectedZero && !std::is_same<CHECK_EQUALITY_UserType, ChimeraTK::Boolean>::value) { \
779 BOOST_ERROR("Comparison with all-zero expectedValue! Test may be insensitive! Check the " \
780 "generateValue() implementations!"); \
787#define CHECK_EQUALITY_TIMEOUT(accessor, expectedValue, maxMilliseconds) \
789 typedef typename decltype(expectedValue)::value_type::value_type CHECK_EQUALITY_UserType; \
790 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); \
791 bool CHECK_EQUALITY_warnExpectedZero = true; \
793 accessor.readLatest(); \
795 BOOST_CHECK_EQUAL(accessor.getNChannels(), expectedValue.size()); \
796 BOOST_CHECK_EQUAL(accessor.getNElementsPerChannel(), expectedValue[0].size()); \
797 for(size_t CHECK_EQUALITY_i = 0; CHECK_EQUALITY_i < expectedValue.size(); ++CHECK_EQUALITY_i) { \
798 for(size_t CHECK_EQUALITY_k = 0; CHECK_EQUALITY_k < expectedValue[0].size(); ++CHECK_EQUALITY_k) { \
799 if(CHECK_EQUALITY_warnExpectedZero && \
800 !compareHelper(expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k], CHECK_EQUALITY_UserType())) { \
802 CHECK_EQUALITY_warnExpectedZero = false; \
805 accessor[CHECK_EQUALITY_i][CHECK_EQUALITY_k], expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k])) { \
807 fail = "Accessor content differs from expected value. First difference at index [" + \
808 std::to_string(CHECK_EQUALITY_i) + "][" + std::to_string(CHECK_EQUALITY_k) + \
809 "]: " + std::to_string(accessor[CHECK_EQUALITY_i][CHECK_EQUALITY_k]) + \
810 " != " + std::to_string(expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k]); \
815 if(fail.empty()) break; \
816 bool timeout_reached = (std::chrono::steady_clock::now() - t0) > std::chrono::milliseconds(maxMilliseconds); \
817 BOOST_CHECK_MESSAGE(!timeout_reached, fail); \
818 if(timeout_reached) break; \
821 if(CHECK_EQUALITY_warnExpectedZero && !std::is_same<CHECK_EQUALITY_UserType, ChimeraTK::Boolean>::value) { \
822 BOOST_ERROR("Comparison with all-zero expectedValue! Test may be insensitive! Check the " \
823 "generateValue() implementations!"); \
829#define CHECK_EQUALITY_VECTOR_TIMEOUT(foundValue, expectedValue, maxMilliseconds) \
831 typedef typename decltype(expectedValue)::value_type::value_type CHECK_EQUALITY_UserType; \
832 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); \
833 bool CHECK_EQUALITY_warnExpectedZero = true; \
836 auto CHECK_EQUALITY_value = foundValue; \
837 BOOST_CHECK_EQUAL(theValue.size(), expectedValue.size()); \
838 BOOST_CHECK_EQUAL(theValue[0].size(), expectedValue[0].size()); \
839 for(size_t CHECK_EQUALITY_i = 0; CHECK_EQUALITY_i < expectedValue.size(); ++CHECK_EQUALITY_i) { \
840 for(size_t CHECK_EQUALITY_k = 0; CHECK_EQUALITY_k < expectedValue[0].size(); ++CHECK_EQUALITY_k) { \
841 if(CHECK_EQUALITY_warnExpectedZero && \
842 !compareHelper(expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k], CHECK_EQUALITY_UserType())) { \
844 CHECK_EQUALITY_warnExpectedZero = false; \
846 if(!compareHelper(CHECK_EQUALITY_value[CHECK_EQUALITY_i][CHECK_EQUALITY_k], \
847 expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k])) { \
849 fail = "Data content differs from expected value. First difference at index [" + \
850 std::to_string(CHECK_EQUALITY_i) + "][" + std::to_string(CHECK_EQUALITY_k) + \
851 "]: " + std::to_string(CHECK_EQUALITY_value[CHECK_EQUALITY_i][CHECK_EQUALITY_k]) + \
852 " != " + std::to_string(expectedValue[CHECK_EQUALITY_i][CHECK_EQUALITY_k]); \
857 if(fail.empty()) break; \
858 bool timeout_reached = (std::chrono::steady_clock::now() - t0) > std::chrono::milliseconds(maxMilliseconds); \
859 BOOST_CHECK_MESSAGE(!timeout_reached, fail); \
860 if(timeout_reached) break; \
863 if(CHECK_EQUALITY_warnExpectedZero && !std::is_same<CHECK_EQUALITY_UserType, ChimeraTK::Boolean>::value) { \
864 BOOST_ERROR("Comparison with all-zero expectedValue! Test may be insensitive! Check the " \
865 "generateValue() implementations!"); \
871#define CHECK_TIMEOUT(condition, maxMilliseconds) \
873 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); \
874 while(!(condition)) { \
875 bool timeout_reached = (std::chrono::steady_clock::now() - t0) > std::chrono::milliseconds(maxMilliseconds); \
876 BOOST_CHECK(!timeout_reached); \
877 if(timeout_reached) break; \
885 template<
typename VECTOR_OF_REGISTERS_T>
889 std::cout <<
"=== UnifiedBackendTest for " <<
cdd;
890 if(!cdd2.empty()) std::cout <<
" and " << cdd2;
891 std::cout << std::endl;
893 size_t nSyncReadRegisters = 0;
894 size_t nAsyncReadRegisters = 0;
895 size_t nWriteRegisters = 0;
896 size_t nRawRegisters = 0;
897 size_t nReadOnlyRegisters = 0;
898 size_t nWriteOnlyRegisters = 0;
899 size_t nPartialReadRegisters = 0;
900 size_t nPartialWriteRegisters = 0;
901 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
902 if(this->isAsyncRead(x)) ++nAsyncReadRegisters;
903 if(this->isSyncRead(x)) ++nSyncReadRegisters;
904 if(this->isWrite(x)) ++nWriteRegisters;
905 if(this->isWrite(x) && !this->isRead(x)) ++nWriteOnlyRegisters;
906 if(!this->isWrite(x) && this->isRead(x)) ++nReadOnlyRegisters;
907 if(this->isRaw(x)) ++nRawRegisters;
908 if(this->isRead(x) && (x.nElementsPerChannel() > 4) &&
910 ++nPartialReadRegisters;
912 if(this->isWrite(x) && (x.nElementsPerChannel() > 4) &&
914 ++nPartialWriteRegisters;
918 std::cout <<
"WARNING: Register " << x.path() <<
" has unspecified capability forceDataLossWrite!" << std::endl;
921 std::cout <<
"WARNING: Register " << x.path() <<
" has unspecified capability asyncReadInconsistency!"
925 std::cout <<
"WARNING: Register " << x.path() <<
" has unspecified capability switchReadOnly!" << std::endl;
928 std::cout <<
"WARNING: Register " << x.path() <<
" has unspecified capability switchWriteOnly!" << std::endl;
931 std::cout <<
"WARNING: Register " << x.path() <<
" has unspecified capability writeNeverLosesData!"
936 std::cout <<
"Using " << nSyncReadRegisters <<
" synchronous and " << nAsyncReadRegisters
937 <<
" asynchronous read and " << nWriteRegisters <<
" write test registers." << std::endl;
938 std::cout <<
"Of those are " << nRawRegisters <<
" supporting raw mode, " << nReadOnlyRegisters
939 <<
" are read-only and " << nWriteOnlyRegisters <<
" write-only." << std::endl;
941 if(nSyncReadRegisters + nAsyncReadRegisters + nWriteRegisters == 0) {
942 std::cout <<
"ERROR: No test registers specified. Cannot perform tests." << std::endl;
946 if(nSyncReadRegisters + nAsyncReadRegisters == 0) {
947 std::cout <<
"WARNING: No read test registers specified. This is acceptable only if the backend does not "
948 <<
"support reading at all." << std::endl;
950 else if(nSyncReadRegisters == 0) {
952 <<
"WARNING: No synchronous read test registers specified. This is acceptable only if the backend has only "
953 <<
"registers which support AccessMode::wait_for_new_data." << std::endl;
955 else if(nAsyncReadRegisters == 0) {
957 <<
"WARNING: No asynchronous read test registers specified. This is acceptable only if the backend does not "
958 <<
"support AccessMode::wait_for_new_data at all." << std::endl;
960 if(nWriteRegisters == 0) {
961 std::cout <<
"WARNING: No write test registers specified. This is acceptable only if the backend does not "
962 <<
"support writing at all." << std::endl;
965 if(nRawRegisters == 0) {
966 std::cout <<
"WARNING: No raw registers specified. This is acceptable only if the backend does not "
967 <<
"support raw access mode at all." << std::endl;
969 if(nReadOnlyRegisters == 0) {
970 std::cout <<
"WARNING: No read-only registers specified." << std::endl;
972 if(nWriteOnlyRegisters == 0) {
973 std::cout <<
"WARNING: No write-only registers specified." << std::endl;
975 if(nPartialReadRegisters == 0) {
976 std::cout <<
"WARNING: No read registers large enough to test partial reading (>= 4 elements)." << std::endl;
978 if(nPartialWriteRegisters == 0) {
979 std::cout <<
"WARNING: No partial write registers defined. This is acceptable only if the backend does not "
980 <<
"support partial write." << std::endl;
984 test_NOSPEC_partial_read();
986 test_NOSPEC_partial_write();
1009 test_NOSPEC_newVersionAfterOpen();
1024 test_NOSPEC_valueAfterConstruction();
1025 test_NOSPEC_backendNotClosedAfterException();
1026 test_NOSPEC_rawTransfer();
1027 test_NOSPEC_catalogueRaw();
1028 test_NOSPEC_catalogueReadWrite();
1033 template<
typename VECTOR_OF_REGISTERS_T>
1035 auto stopTime = std::chrono::steady_clock::now() + std::chrono::seconds(60);
1036 for(
size_t i = 0;; ++i) {
1044 if((i > 10) && (std::chrono::steady_clock::now() > stopTime)) {
1045 BOOST_FAIL(
"Device did not recover within 60 seconds after forced ChimeraTK::runtime_error.");
1057 template<
typename VECTOR_OF_REGISTERS_T>
1059 std::cout <<
"--- test_B_3_1_2_1 - synchronous read" << std::endl;
1062 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1063 if(!this->isRead(x))
return;
1064 typedef typename decltype(x)::minimumUserType UserType;
1065 auto registerName = x.path();
1066 std::cout <<
"... registerName = " << registerName << std::endl;
1071 std::vector<std::vector<UserType>> v1 = x.template getRemoteValue<UserType>();
1087 std::vector<std::vector<UserType>> v2;
1088 for(
size_t iter = 0; iter < this->nValuesToTest(x); ++iter) {
1091 v2 = x.template getRemoteValue<UserType>();
1119 template<
typename VECTOR_OF_REGISTERS_T>
1121 std::cout <<
"--- test_NOSPEC_partial_read" << std::endl;
1124 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1125 if(!this->isRead(x))
return;
1126 if(x.nElementsPerChannel() < 4)
return;
1127 typedef typename decltype(x)::minimumUserType UserType;
1128 auto registerName = x.path();
1129 std::cout <<
"... registerName = " << registerName << std::endl;
1140 std::vector<std::vector<UserType>> partialV1;
1141 for(
size_t iter = 0; iter < this->nValuesToTest(x); ++iter) {
1145 partialV1 = x.template getRemoteValue<UserType>();
1146 for(
auto& chan : partialV1) {
1147 auto val1 = chan[1];
1148 auto val2 = chan[2];
1180 template<
typename VECTOR_OF_REGISTERS_T>
1182 std::cout <<
"--- test_NOSPEC_write - write" << std::endl;
1188 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1189 if(!this->isWrite(x))
return;
1191 typedef typename decltype(x)::minimumUserType UserType;
1192 auto registerName = x.path();
1194 std::cout <<
"... registerName = " << registerName << std::endl;
1198 for(
size_t iter = 0; iter < this->nValuesToTest(x); ++iter) {
1199 auto theValue = x.template generateValue<UserType>();
1219 template<
typename VECTOR_OF_REGISTERS_T>
1221 std::cout <<
"--- test_NOSPEC_partial_write" << std::endl;
1227 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1228 if(!this->isWrite(x))
return;
1229 if(x.nElementsPerChannel() < 4)
return;
1232 typedef typename decltype(x)::minimumUserType UserType;
1233 auto registerName = x.path();
1235 std::cout <<
"... registerName = " << registerName << std::endl;
1239 for(
size_t iter = 0; iter < this->nValuesToTest(x); ++iter) {
1242 auto theValue = x.template getRemoteValue<UserType>();
1244 auto partialValue = x.template generateValue<UserType>();
1245 for(
size_t i = 0; i < partialValue.size(); ++i) {
1246 auto& chan = partialValue[i];
1247 auto val1 = chan[1];
1248 auto val2 = chan[2];
1253 theValue[i][1] = val1;
1254 theValue[i][2] = val2;
1278 template<
typename VECTOR_OF_REGISTERS_T>
1280 std::cout <<
"--- test_B_3_2_1_2 - write() does not destroy application buffer" << std::endl;
1286 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1287 if(!this->isWrite(x))
return;
1288 typedef typename decltype(x)::minimumUserType UserType;
1289 auto registerName = x.path();
1290 std::cout <<
"... registerName = " << registerName << std::endl;
1294 auto theValue = x.template generateValue<UserType>();
1300 BOOST_CHECK(reg.getNChannels() == theValue.size());
1301 BOOST_CHECK(reg.getNElementsPerChannel() == theValue[0].size());
1305 BOOST_CHECK(reg.getVersionNumber() == ver);
1318 template<
typename VECTOR_OF_REGISTERS_T>
1320 std::cout <<
"--- test_B_3_2_2 - destructive write" << std::endl;
1326 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1327 if(!this->isWrite(x))
return;
1328 typedef typename decltype(x)::minimumUserType UserType;
1329 auto registerName = x.path();
1331 std::cout <<
"... registerName = " << registerName << std::endl;
1335 auto theValue = x.template generateValue<UserType>();
1338 reg.writeDestructively(ver);
1341 BOOST_CHECK(reg.getNChannels() == theValue.size());
1342 BOOST_CHECK(reg.getNElementsPerChannel() == theValue[0].size());
1345 BOOST_CHECK(reg.getVersionNumber() == ver);
1362#define STORE_APPLICATION_DATA_BUFFER(UserType, accessor) \
1363 std::vector<std::vector<UserType>> STORE_APPLICATION_BUFFER_data; \
1364 for(size_t i = 0; i < accessor.getNChannels(); ++i) { \
1365 STORE_APPLICATION_BUFFER_data.push_back(accessor[i]); \
1369#define ALTER_AND_STORE_APPLICATION_BUFFER(UserType, accessor) \
1370 for(size_t i = 0; i < accessor.getNChannels(); ++i) { \
1371 if constexpr(std::is_arithmetic_v<UserType>) \
1372 std::iota(accessor[i].begin(), accessor[i].end(), std::numeric_limits<UserType>::min() + 1); \
1373 if constexpr(std::is_same_v<std::string, UserType>) std::fill(accessor[i].begin(), accessor[i].end(), "FACECAFE"); \
1375 STORE_APPLICATION_DATA_BUFFER(UserType, accessor); \
1376 VersionNumber STORE_APPLICATION_BUFFER_version; \
1377 DataValidity STORE_APPLICATION_BUFFER_validity; \
1378 STORE_APPLICATION_BUFFER_version = accessor.getVersionNumber(); \
1379 STORE_APPLICATION_BUFFER_validity = accessor.dataValidity()
1381#define CHECK_APPLICATION_DATA_BUFFER(UserType, accessor) CHECK_EQUALITY(accessor, STORE_APPLICATION_BUFFER_data)
1383#define CHECK_APPLICATION_BUFFER(UserType, accessor) \
1384 CHECK_APPLICATION_DATA_BUFFER(UserType, accessor); \
1385 BOOST_CHECK(STORE_APPLICATION_BUFFER_version == accessor.getVersionNumber()); \
1386 BOOST_CHECK(STORE_APPLICATION_BUFFER_validity == accessor.dataValidity())
1394 template<
typename VECTOR_OF_REGISTERS_T>
1396 std::cout <<
"--- test_B_4_2_4 - transfer implementations do not change the application buffer" << std::endl;
1402 std::cout <<
"... writeTransfer()" << std::endl;
1403 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1404 if(!this->isWrite(x))
return;
1405 typedef typename decltype(x)::minimumUserType UserType;
1406 auto registerName = x.path();
1407 std::cout <<
"... registerName = " << registerName << std::endl;
1409 auto te = reg.getHighLevelImplElement();
1412 auto theValue = x.template generateValue<UserType>();
1417 te->writeTransfer(ver);
1422 std::cout <<
"... writeTransferDestructively()" << std::endl;
1423 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1424 if(!this->isWrite(x))
return;
1425 typedef typename decltype(x)::minimumUserType UserType;
1426 auto registerName = x.path();
1427 std::cout <<
"... registerName = " << registerName << std::endl;
1429 auto te = reg.getHighLevelImplElement();
1432 auto theValue = x.template generateValue<UserType>();
1437 te->writeTransferDestructively(ver);
1442 std::cout <<
"... readTransferSynchronously()" << std::endl;
1443 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1444 if(!this->isRead(x))
return;
1445 typedef typename decltype(x)::minimumUserType UserType;
1446 auto registerName = x.path();
1447 std::cout <<
"... registerName = " << registerName << std::endl;
1449 auto te = reg.getHighLevelImplElement();
1452 auto theValue = x.template generateValue<UserType>();
1473 template<
typename VECTOR_OF_REGISTERS_T>
1475 std::cout <<
"--- test_B_4_2_5 - xxxTransferYyy() can be skipped between preXxx() and postXxx()" << std::endl;
1481 std::cout <<
"... writeTransfer()" << std::endl;
1482 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1483 if(!this->isWrite(x)) {
1486 using UserType =
typename decltype(x)::minimumUserType;
1487 auto registerName = x.path();
1488 std::cout <<
"... registerName = " << registerName << std::endl;
1490 auto te = reg.getHighLevelImplElement();
1493 auto theValue = x.template generateValue<UserType>();
1502 std::cout <<
"... writeTransferDestructively()" << std::endl;
1503 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1504 if(!this->isWrite(x)) {
1507 using UserType =
typename decltype(x)::minimumUserType;
1508 auto registerName = x.path();
1509 std::cout <<
"... registerName = " << registerName << std::endl;
1511 auto te = reg.getHighLevelImplElement();
1514 auto theValue = x.template generateValue<UserType>();
1523 std::cout <<
"... readTransferSynchronously()" << std::endl;
1524 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1525 if(!this->isRead(x)) {
1528 using UserType =
typename decltype(x)::minimumUserType;
1529 auto registerName = x.path();
1530 std::cout <<
"... registerName = " << registerName << std::endl;
1532 auto te = reg.getHighLevelImplElement();
1535 auto theValue = x.template generateValue<UserType>();
1553 template<
typename VECTOR_OF_REGISTERS_T>
1555 if(_testOnlyTransferElement)
return;
1556 std::cout <<
"--- test_B_6_4 - application buffer unchanged after exception" << std::endl;
1559 std::cout <<
"... synchronous read " << std::endl;
1560 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1561 if(!this->isRead(x))
return;
1562 typedef typename decltype(x)::minimumUserType UserType;
1563 auto registerName = x.path();
1564 int someNumber = 42;
1566 std::cout <<
" registerName = " << registerName << std::endl;
1570 reg[0][0] = numericToUserType<UserType>(someNumber);
1572 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
1578 BOOST_CHECK(reg[0][0] == numericToUserType<UserType>(someNumber));
1580 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
1582 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
1583 std::cout <<
" -> runtime_error case: " << i << std::endl;
1588 x.setForceRuntimeError(
true, i);
1594 BOOST_CHECK(reg[0][0] == numericToUserType<UserType>(someNumber));
1596 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
1599 x.setForceRuntimeError(
false, i);
1602 this->recoverDevice(d);
1609 std::cout <<
"... asynchronous read " << std::endl;
1610 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1611 if(!this->isAsyncRead(x))
return;
1612 typedef typename decltype(x)::minimumUserType UserType;
1613 auto registerName = x.path();
1614 int someNumber = 42;
1616 std::cout <<
" registerName = " << registerName << std::endl;
1620 reg[0][0] = numericToUserType<UserType>(someNumber);
1622 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
1628 BOOST_CHECK(reg[0][0] == numericToUserType<UserType>(someNumber));
1630 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
1633 BOOST_CHECK_THROW(reg.readNonBlocking(),
logic_error);
1636 BOOST_CHECK(reg[0][0] == numericToUserType<UserType>(someNumber));
1638 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
1640 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
1641 std::cout <<
" -> runtime_error case: " << i << std::endl;
1648 x.setForceRuntimeError(
true, i);
1651 reg[0][0] = numericToUserType<UserType>(someNumber);
1653 auto ver = reg.getVersionNumber();
1659 BOOST_CHECK(reg[0][0] == numericToUserType<UserType>(someNumber));
1661 BOOST_CHECK(reg.getVersionNumber() == ver);
1664 x.setForceRuntimeError(
false, i);
1665 this->recoverDevice(d);
1668 x.setForceRuntimeError(
true, i);
1671 reg[0][0] = numericToUserType<UserType>(someNumber);
1673 ver = reg.getVersionNumber();
1677 while(!reg.readNonBlocking()) usleep(10000);
1683 BOOST_CHECK(reg[0][0] == numericToUserType<UserType>(someNumber));
1685 BOOST_CHECK(reg.getVersionNumber() == ver);
1688 x.setForceRuntimeError(
false, i);
1691 this->recoverDevice(d);
1698 std::cout <<
"... write " << std::endl;
1699 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1700 if(!this->isWrite(x))
return;
1701 typedef typename decltype(x)::minimumUserType UserType;
1702 auto registerName = x.path();
1703 int someNumber = 42;
1705 std::cout <<
" registerName = " << registerName << std::endl;
1709 reg[0][0] = numericToUserType<UserType>(someNumber);
1711 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
1717 BOOST_CHECK(reg[0][0] == numericToUserType<UserType>(someNumber));
1719 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
1721 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
1722 std::cout <<
" -> runtime_error case: " << i << std::endl;
1727 x.setForceRuntimeError(
true, i);
1733 BOOST_CHECK(reg[0][0] == numericToUserType<UserType>(someNumber));
1735 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
1738 x.setForceRuntimeError(
false, i);
1741 this->recoverDevice(d);
1755 template<
typename VECTOR_OF_REGISTERS_T>
1757 std::cout <<
"--- test_B_7_2 - data loss in write" << std::endl;
1760 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1761 if(!this->isWrite(x))
return;
1763 typedef typename decltype(x)::minimumUserType UserType;
1764 auto registerName = x.path();
1765 std::cout <<
"... registerName = " << registerName <<
" (data loss expected)" << std::endl;
1768 size_t attempts = this->writeQueueLength(x) + 1;
1769 this->setForceDataLossWrite(x, true);
1774 auto reg = d.getTwoDRegisterAccessor<UserType>(registerName);
1777 for(size_t i = 0; i < attempts; ++i) {
1778 auto theValue = x.template generateValue<UserType>();
1780 VersionNumber someVersion;
1781 bool dataLost = reg.write(someVersion);
1782 if(i < attempts - 1) {
1783 BOOST_CHECK(dataLost == false);
1786 BOOST_CHECK(dataLost == true);
1789 CHECK_EQUALITY(reg, theValue);
1790 BOOST_CHECK(reg.dataValidity() == DataValidity::ok);
1791 BOOST_CHECK(reg.getVersionNumber() == someVersion);
1795 this->setForceDataLossWrite(x,
false);
1798 auto v1 = x.template getRemoteValue<UserType>();
1805 typedef typename decltype(x)::minimumUserType UserType;
1806 auto registerName = x.path();
1807 std::cout <<
"... registerName = " << registerName <<
" (data loss never expected)" << std::endl;
1810 size_t attempts = this->writeQueueLength(x) + 1;
1818 for(
size_t i = 0; i < attempts; ++i) {
1819 auto theValue = x.template generateValue<UserType>();
1822 bool dataLost = reg.write(someVersion);
1823 BOOST_CHECK(dataLost ==
false);
1827 auto v1 = x.template getRemoteValue<UserType>();
1845 template<
typename VECTOR_OF_REGISTERS_T>
1847 std::cout <<
"--- test_B_8_2 - async read fills _readQueue" << std::endl;
1854 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1855 if(!this->isAsyncRead(x))
return;
1856 typedef typename decltype(x)::minimumUserType UserType;
1857 auto registerName = x.path();
1860 std::cout <<
"... registerName = " << registerName << std::endl;
1869 BOOST_CHECK(reg.readNonBlocking() ==
false);
1873 auto v1 = x.template getRemoteValue<UserType>();
1878 BOOST_CHECK(reg.readNonBlocking() ==
false);
1882 BOOST_CHECK(reg.dataValidity() == DataValidity::ok);
1883 BOOST_CHECK(reg.getVersionNumber() > someVersion);
1884 someVersion = reg.getVersionNumber();
1887 helper.readLatest();
1891 auto v2 = x.template getRemoteValue<UserType>();
1895 auto v3 = x.template getRemoteValue<UserType>();
1899 auto v4 = x.template getRemoteValue<UserType>();
1905 BOOST_CHECK(reg.dataValidity() == DataValidity::ok);
1906 BOOST_CHECK(reg.getVersionNumber() > someVersion);
1907 someVersion = reg.getVersionNumber();
1912 BOOST_CHECK(reg.dataValidity() == DataValidity::ok);
1913 BOOST_CHECK(reg.getVersionNumber() > someVersion);
1914 someVersion = reg.getVersionNumber();
1919 BOOST_CHECK(reg.dataValidity() == DataValidity::ok);
1920 BOOST_CHECK(reg.getVersionNumber() > someVersion);
1921 someVersion = reg.getVersionNumber();
1924 BOOST_CHECK(reg.readNonBlocking() ==
false);
1926 BOOST_CHECK(reg.dataValidity() == DataValidity::ok);
1927 BOOST_CHECK(reg.getVersionNumber() == someVersion);
1944 template<
typename VECTOR_OF_REGISTERS_T>
1946 std::cout <<
"--- test_B_8_2_1 - _readQueue overrun" << std::endl;
1955 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
1956 if(!this->isAsyncRead(x))
return;
1957 typedef typename decltype(x)::minimumUserType UserType;
1958 auto registerName = x.path();
1961 std::cout <<
"... registerName = " << registerName << std::endl;
1962 auto overrunningReg = d.
getTwoDRegisterAccessor<UserType>(registerName, 0, 0, {AccessMode::wait_for_new_data});
1968 overrunningReg.read();
1969 referenceReg.read();
1971 BOOST_CHECK(overrunningReg.readNonBlocking() ==
false);
1974 for(
size_t i = 0; i < 10; ++i) {
1977 referenceReg.read();
1979 auto val = x.template getRemoteValue<UserType>();
1982 BOOST_CHECK(overrunningReg.readLatest() ==
true);
1986 BOOST_CHECK(overrunningReg.dataValidity() == DataValidity::ok);
1987 BOOST_CHECK(overrunningReg.getVersionNumber() > someVersion);
1988 someVersion = overrunningReg.getVersionNumber();
2001 template<
typename VECTOR_OF_REGISTERS_T>
2003 std::cout <<
"--- test_B_8_3 - new runtime errors are put to _readQueue in async reads" << std::endl;
2010 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2011 if(!this->isAsyncRead(x))
return;
2012 typedef typename decltype(x)::minimumUserType UserType;
2013 auto registerName = x.path();
2016 std::cout <<
"... registerName = " << registerName << std::endl;
2021 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
2022 std::cout <<
" -> runtime_error case: " << i << std::endl;
2027 reg.getHighLevelImplElement()->preRead(TransferType::read);
2030 x.setForceRuntimeError(
true, i);
2040 reg.getHighLevelImplElement()->postRead(TransferType::read,
false);
2043 x.setForceRuntimeError(
false, i);
2046 this->recoverDevice(d);
2062 template<
typename VECTOR_OF_REGISTERS_T>
2064 if(_testOnlyTransferElement)
return;
2065 std::cout <<
"--- test_B_8_4 - async read consistency heartbeat" << std::endl;
2069 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2070 if(!this->isAsyncRead(x) || x.capabilities.asyncReadInconsistency != TestCapability::enabled)
return;
2071 typedef typename decltype(x)::minimumUserType UserType;
2072 auto registerName = x.path();
2075 std::cout <<
"... registerName = " << registerName << std::endl;
2085 auto v1 = x.template getRemoteValue<UserType>();
2093 BOOST_CHECK(reg.dataValidity() == DataValidity::ok);
2094 BOOST_CHECK(reg.getVersionNumber() > someVersion);
2095 someVersion = reg.getVersionNumber();
2098 this->forceAsyncReadInconsistency(x);
2104 this->recoverDevice(d);
2105 auto v2 = x.template getRemoteValue<UserType>();
2113 BOOST_CHECK(reg.dataValidity() == DataValidity::ok);
2114 BOOST_CHECK(reg.getVersionNumber() > someVersion);
2115 someVersion = reg.getVersionNumber();
2128 template<
typename VECTOR_OF_REGISTERS_T>
2130 if(_testOnlyTransferElement)
return;
2131 std::cout <<
"--- test_B_8_5 - no async transfers until activateAsyncRead()" << std::endl;
2134 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2135 if(!this->isAsyncRead(x))
return;
2136 typedef typename decltype(x)::minimumUserType UserType;
2137 auto registerName = x.path();
2138 std::cout <<
"... registerName = " << registerName << std::endl;
2142 std::chrono::duration<double> timeToInitialValue{};
2145 auto t0 = std::chrono::steady_clock::now();
2158 auto t1 = std::chrono::steady_clock::now();
2159 timeToInitialValue = t1 - t0;
2172 std::this_thread::sleep_for(timeToInitialValue * 2);
2175 BOOST_CHECK(reg.readNonBlocking() ==
false);
2179 std::this_thread::sleep_for(timeToInitialValue * 2);
2182 BOOST_CHECK(reg.readNonBlocking() ==
false);
2196 template<
typename VECTOR_OF_REGISTERS_T>
2198 if(_testOnlyTransferElement)
return;
2199 std::cout <<
"--- test_B_8_5_1 - activateAsynchronousRead" << std::endl;
2207 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2208 if(!this->isAsyncRead(x))
return;
2209 typedef typename decltype(x)::minimumUserType UserType;
2210 auto registerName = x.path();
2211 std::cout <<
"... registerName = " << registerName << std::endl;
2218 if(!cdd2.empty()) BOOST_CHECK(reg2.readNonBlocking() ==
false);
2223 auto v1 = x.template getRemoteValue<UserType>();
2227 if(!cdd2.empty()) BOOST_CHECK(reg2.readNonBlocking() ==
false);
2240 using namespace std::chrono_literals;
2241 std::this_thread::sleep_for(10ms);
2242 BOOST_CHECK(reg2.readNonBlocking() ==
false);
2261 template<
typename VECTOR_OF_REGISTERS_T>
2263 if(_testOnlyTransferElement)
return;
2264 std::cout <<
"--- test_B_8_5_2 - initial value" << std::endl;
2266 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2267 if(!this->isAsyncRead(x))
return;
2268 typedef typename decltype(x)::minimumUserType UserType;
2269 auto registerName = x.path();
2270 std::cout <<
"... registerName = " << registerName << std::endl;
2276 auto v1 = x.template getRemoteValue<UserType>();
2308 auto v2 = x.template getRemoteValue<UserType>();
2325 template<
typename VECTOR_OF_REGISTERS_T>
2327 std::cout <<
"--- test_B_8_5_3 - accessors created after activateAsyncRead() are immediately active" << std::endl;
2334 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2335 if(!this->isAsyncRead(x))
return;
2336 typedef typename decltype(x)::minimumUserType UserType;
2337 auto registerName = x.path();
2339 std::cout <<
"... registerName = " << registerName <<
" (activated async read)" << std::endl;
2356 template<
typename VECTOR_OF_REGISTERS_T>
2358 std::cout <<
"--- test_B_8_5_4_3 - calling activateAsyncRead() when already active has no effect" << std::endl;
2365 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2366 if(!this->isAsyncRead(x)) {
2369 using UserType =
typename decltype(x)::minimumUserType;
2370 auto registerName = x.path();
2372 std::cout <<
"... registerName = " << registerName <<
" (activated async read)" << std::endl;
2382 BOOST_CHECK(reg.readNonBlocking() ==
false);
2395 template<
typename VECTOR_OF_REGISTERS_T>
2397 std::cout <<
"--- test_B_8_6_6 - interrupt()" << std::endl;
2406 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2407 if(!this->isAsyncRead(x))
return;
2408 typedef typename decltype(x)::minimumUserType UserType;
2409 auto registerName = x.path();
2412 std::cout <<
"... registerName = " << registerName << std::endl;
2416 for(
size_t i = 0; i < 2; ++i) {
2418 boost::thread anotherThread([&] {
2420 BOOST_ERROR(
"boost::thread_interrupt exception expected but not thrown.");
2424 reg.getHighLevelImplElement()->interrupt();
2427 anotherThread.join();
2431 auto v1 = x.template getRemoteValue<UserType>();
2434 BOOST_CHECK(reg.dataValidity() == DataValidity::ok);
2435 BOOST_CHECK(reg.getVersionNumber() > someVersion);
2436 someVersion = reg.getVersionNumber();
2450 template<
typename VECTOR_OF_REGISTERS_T>
2452 if(_testOnlyTransferElement)
return;
2453 std::cout <<
"--- test_B_9_1 - reporting exceptions to exception backend" << std::endl;
2459 std::cout <<
"... synchronous read" << std::endl;
2460 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2461 if(!this->isRead(x))
return;
2462 if(x.nRuntimeErrorCases() == 0)
return;
2463 typedef typename decltype(x)::minimumUserType UserType;
2464 auto registerName = x.path();
2465 std::cout <<
" registerName = " << registerName << std::endl;
2469 auto erb = boost::make_shared<ExceptionReportingBackend>(d.
getBackend());
2470 reg.getHighLevelImplElement()->setExceptionBackend(erb);
2472 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
2473 std::cout <<
" -> runtime_error case: " << i << std::endl;
2475 x.setForceRuntimeError(
true, i);
2478 BOOST_CHECK(!erb->hasSeenException());
2480 BOOST_CHECK(erb->hasSeenException());
2483 x.setForceRuntimeError(
false, i);
2486 this->recoverDevice(d);
2489 BOOST_CHECK_NO_THROW(reg.read());
2490 BOOST_CHECK(!erb->hasSeenException());
2494 std::cout <<
"... asynchronous read" << std::endl;
2496 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2497 if(!this->isAsyncRead(x))
return;
2498 if(x.nRuntimeErrorCases() == 0)
return;
2499 typedef typename decltype(x)::minimumUserType UserType;
2500 auto registerName = x.path();
2501 std::cout <<
" registerName = " << registerName << std::endl;
2506 auto erb = boost::make_shared<ExceptionReportingBackend>(d.
getBackend());
2507 reg.getHighLevelImplElement()->setExceptionBackend(erb);
2509 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
2510 std::cout <<
" -> runtime_error case: " << i << std::endl;
2512 x.setForceRuntimeError(
true, i);
2515 BOOST_CHECK(!erb->hasSeenException());
2517 BOOST_CHECK(erb->hasSeenException());
2520 x.setForceRuntimeError(
false, i);
2523 this->recoverDevice(d);
2528 BOOST_CHECK_NO_THROW(reg.readNonBlocking());
2529 BOOST_CHECK(!erb->hasSeenException());
2533 std::cout <<
"... write" << std::endl;
2534 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2535 if(!this->isWrite(x))
return;
2536 if(x.nRuntimeErrorCases() == 0)
return;
2537 typedef typename decltype(x)::minimumUserType UserType;
2538 auto registerName = x.path();
2539 std::cout <<
" registerName = " << registerName << std::endl;
2543 auto erb = boost::make_shared<ExceptionReportingBackend>(d.
getBackend());
2544 reg.getHighLevelImplElement()->setExceptionBackend(erb);
2546 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
2547 std::cout <<
" -> runtime_error case: " << i << std::endl;
2549 x.setForceRuntimeError(
true, i);
2552 BOOST_CHECK(!erb->hasSeenException());
2554 BOOST_CHECK(erb->hasSeenException());
2557 x.setForceRuntimeError(
false, i);
2560 this->recoverDevice(d);
2563 BOOST_CHECK_NO_THROW(reg.write());
2564 BOOST_CHECK(!erb->hasSeenException());
2568 std::cout <<
"... isReadable" << std::endl;
2569 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2570 if(x.nRuntimeErrorCases() == 0)
return;
2571 typedef typename decltype(x)::minimumUserType UserType;
2572 auto registerName = x.path();
2573 std::cout <<
" registerName = " << registerName;
2577 auto erb = boost::make_shared<ExceptionReportingBackend>(d.
getBackend());
2578 reg.getHighLevelImplElement()->setExceptionBackend(erb);
2580 bool didThrow =
false;
2581 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
2582 std::cout <<
" -> runtime_error case: " << i << std::endl;
2584 x.setForceRuntimeError(
true, i);
2587 BOOST_CHECK(!erb->hasSeenException());
2589 [[maybe_unused]]
auto result = reg.isReadable();
2593 BOOST_CHECK(erb->hasSeenException());
2597 x.setForceRuntimeError(
false, i);
2600 this->recoverDevice(d);
2604 std::cout <<
" (doesn't throw)" << std::endl;
2607 std::cout <<
" (throws)" << std::endl;
2611 std::cout <<
"... isWriteable" << std::endl;
2612 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2613 if(x.nRuntimeErrorCases() == 0)
return;
2614 typedef typename decltype(x)::minimumUserType UserType;
2615 auto registerName = x.path();
2616 std::cout <<
" registerName = " << registerName;
2620 auto erb = boost::make_shared<ExceptionReportingBackend>(d.
getBackend());
2621 reg.getHighLevelImplElement()->setExceptionBackend(erb);
2623 bool didThrow =
false;
2624 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
2625 std::cout <<
" -> runtime_error case: " << i << std::endl;
2627 x.setForceRuntimeError(
true, i);
2630 BOOST_CHECK(!erb->hasSeenException());
2632 [[maybe_unused]]
auto result = reg.isWriteable();
2636 BOOST_CHECK(erb->hasSeenException());
2640 x.setForceRuntimeError(
false, i);
2643 this->recoverDevice(d);
2647 std::cout <<
" (doesn't throw)" << std::endl;
2650 std::cout <<
" (throws)" << std::endl;
2654 std::cout <<
"... isReadOnly" << std::endl;
2655 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2656 typedef typename decltype(x)::minimumUserType UserType;
2657 auto registerName = x.path();
2658 std::cout <<
" registerName = " << registerName;
2662 auto erb = boost::make_shared<ExceptionReportingBackend>(d.
getBackend());
2663 reg.getHighLevelImplElement()->setExceptionBackend(erb);
2665 bool didThrow =
false;
2666 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
2667 std::cout <<
" -> runtime_error case: " << i << std::endl;
2669 x.setForceRuntimeError(
true, i);
2672 BOOST_CHECK(!erb->hasSeenException());
2674 [[maybe_unused]]
auto result = reg.isReadOnly();
2678 BOOST_CHECK(erb->hasSeenException());
2682 x.setForceRuntimeError(
false, i);
2685 this->recoverDevice(d);
2689 std::cout <<
" (doesn't throw)" << std::endl;
2692 std::cout <<
" (throws)" << std::endl;
2705 template<
typename VECTOR_OF_REGISTERS_T>
2707 if(_testOnlyTransferElement)
return;
2708 std::cout <<
"--- test_B_9_2_2 - repeated setException() has no effect" << std::endl;
2714 std::list<TransferElementAbstractor> accessors;
2715 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2716 if(!this->isAsyncRead(x))
return;
2717 typedef typename decltype(x)::minimumUserType UserType;
2718 auto registerName = x.path();
2719 std::cout <<
"... registerName = " << registerName << std::endl;
2723 accessors.push_back(reg);
2733 for(
auto& accessor : accessors) {
2745 for(
auto& accessor : accessors) {
2746 BOOST_CHECK(accessor.readNonBlocking() ==
false);
2759 template<
typename VECTOR_OF_REGISTERS_T>
2761 if(_testOnlyTransferElement)
return;
2762 std::cout <<
"--- test_B_9_3_1 - setException() disables asynchronous read transfers" << std::endl;
2768 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2769 if(!this->isAsyncRead(x))
return;
2770 typedef typename decltype(x)::minimumUserType UserType;
2771 auto registerName = x.path();
2772 std::cout <<
"... registerName = " << registerName << std::endl;
2793 BOOST_CHECK(reg.readNonBlocking() ==
false);
2796 this->recoverDevice(d);
2810 template<
typename VECTOR_OF_REGISTERS_T>
2812 if(_testOnlyTransferElement)
return;
2813 std::cout <<
"--- test_B_9_3_2 - exactly one runtime_error in the _readQueue per async read accessor" << std::endl;
2819 std::list<TransferElementAbstractor> accessors;
2820 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2821 if(!this->isAsyncRead(x))
return;
2822 typedef typename decltype(x)::minimumUserType UserType;
2823 auto registerName = x.path();
2824 std::cout <<
"... registerName = " << registerName << std::endl;
2828 accessors.push_back(reg);
2840 for(
auto& accessor : accessors) {
2842 accessor.getHighLevelImplElement()->preRead(TransferType::read);
2843 BOOST_CHECK_THROW(accessor.getHighLevelImplElement()->readTransfer(),
runtime_error);
2844 accessor.getHighLevelImplElement()->postRead(TransferType::read,
false);
2846 BOOST_CHECK(accessor.readNonBlocking() ==
false);
2859 template<
typename VECTOR_OF_REGISTERS_T>
2861 if(_testOnlyTransferElement)
return;
2863 <<
"--- test_B_9_4_1 - doReadTransferSynchronously throws runtime_error after setException() until recovery"
2868 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2869 if(!this->isRead(x))
return;
2870 typedef typename decltype(x)::minimumUserType UserType;
2871 auto registerName = x.path();
2872 std::cout <<
"... registerName = " << registerName << std::endl;
2882 this->recoverDevice(d);
2885 BOOST_CHECK_NO_THROW(reg.read());
2897 template<
typename VECTOR_OF_REGISTERS_T>
2899 if(_testOnlyTransferElement)
return;
2900 std::cout <<
"--- test_B_9_5 - write operations throw after setException()" << std::endl;
2904 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2905 if(!this->isWrite(x))
return;
2906 typedef typename decltype(x)::minimumUserType UserType;
2907 auto registerName = x.path();
2908 std::cout <<
"... registerName = " << registerName << std::endl;
2918 this->recoverDevice(d);
2921 BOOST_CHECK_NO_THROW(reg.write());
2933 template<
typename VECTOR_OF_REGISTERS_T>
2935 std::cout <<
"--- test_B_11_2_1 - version number bigger for newer values" << std::endl;
2942 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2943 if(!this->isRead(x))
return;
2944 if(x.capabilities.setRemoteValueIncrementsVersion == TestCapability::disabled)
return;
2945 typedef typename decltype(x)::minimumUserType UserType;
2946 auto registerName = x.path();
2949 std::cout <<
"... registerName = " << registerName << std::endl;
2952 for(
size_t i = 0; i < 2; ++i) {
2960 BOOST_CHECK(reg.getVersionNumber() > someVersion);
2961 someVersion = reg.getVersionNumber();
2967 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
2968 if(!this->isAsyncRead(x))
return;
2969 typedef typename decltype(x)::minimumUserType UserType;
2970 auto registerName = x.path();
2972 std::cout <<
"... registerName = " << registerName <<
" (async)" << std::endl;
2987 for(
size_t i = 0; i < 2; ++i) {
2989 auto val = x.template getRemoteValue<UserType>();
2991 BOOST_TEST(reg.getVersionNumber() > someVersion);
2992 someVersion = reg.getVersionNumber();
3009 template<
typename VECTOR_OF_REGISTERS_T>
3011 std::cout <<
"--- test_NOSPEC_newVersionsAfterOpen - version numbers after open() are newer" << std::endl;
3021 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3022 if(!this->isRead(x))
return;
3023 typedef typename decltype(x)::minimumUserType UserType;
3024 auto registerName = x.path();
3026 std::cout <<
"... registerName = " << registerName << std::endl;
3036 BOOST_CHECK(reg.getVersionNumber() > someVersion);
3041 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3042 if(!this->isAsyncRead(x))
return;
3043 typedef typename decltype(x)::minimumUserType UserType;
3044 auto registerName = x.path();
3046 std::cout <<
"... registerName = " << registerName <<
" (async1)" << std::endl;
3053 BOOST_CHECK(reg.getVersionNumber() > someVersion);
3060 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3061 if(!this->isAsyncRead(x))
return;
3062 typedef typename decltype(x)::minimumUserType UserType;
3063 auto registerName = x.path();
3068 std::cout <<
"... registerName = " << registerName <<
" (async2)" << std::endl;
3077 BOOST_CHECK(reg.getVersionNumber() > someVersion);
3093 template<
typename VECTOR_OF_REGISTERS_T>
3095 if(_testOnlyTransferElement)
return;
3096 std::cout <<
"--- test_B_11_2_2 - consistent data gets same VersionNumber" << std::endl;
3104 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3105 if(!this->isAsyncRead(x))
return;
3106 typedef typename decltype(x)::minimumUserType UserType;
3107 auto registerName = x.path();
3108 std::cout <<
"... registerName = " << registerName << std::endl;
3134 auto val = x.template getRemoteValue<UserType>();
3138 BOOST_CHECK_EQUAL(reg.getVersionNumber(), reg2.getVersionNumber());
3151 template<
typename VECTOR_OF_REGISTERS_T>
3153 std::cout <<
"--- B.11.6 - value after construction for the version number in the application buffer" << std::endl;
3156 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3157 typedef typename decltype(x)::minimumUserType UserType;
3158 auto registerName = x.path();
3159 std::cout <<
"... registerName = " << registerName << std::endl;
3163 BOOST_CHECK(reg.getVersionNumber() ==
VersionNumber(
nullptr));
3175 template<
typename VECTOR_OF_REGISTERS_T>
3177 std::cout <<
"--- B.12.1.3.1 - call replaceTransferElement() with internal element does nothing" << std::endl;
3180 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3181 using UserType =
typename decltype(x)::minimumUserType;
3182 auto registerName = x.path();
3183 std::cout <<
"... registerName = " << registerName << std::endl;
3186 auto internalElements = reg.getInternalElements();
3187 for(
auto& elem : internalElements) {
3188 reg.replaceTransferElement(elem);
3192 BOOST_TEST(reg.getInternalElements() == internalElements);
3202 template<
typename VECTOR_OF_REGISTERS_T>
3204 std::cout <<
"--- B.12.1.5.1 - mayReplaceOther() of itself returns \"false\"" << std::endl;
3207 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3208 using UserType =
typename decltype(x)::minimumUserType;
3209 auto registerName = x.path();
3210 std::cout <<
"... registerName = " << registerName << std::endl;
3212 auto transferElement = reg.getHighLevelImplElement();
3213 BOOST_CHECK(transferElement->mayReplaceOther(transferElement) ==
false);
3223 template<
typename VECTOR_OF_REGISTERS_T>
3225 if(_testOnlyTransferElement)
return;
3226 std::cout <<
"--- test_C_5_2_1_2 - logic_error for non-existing register" << std::endl;
3253 template<
typename VECTOR_OF_REGISTERS_T>
3255 if(_testOnlyTransferElement)
return;
3256 std::cout <<
"--- test_C_5_2_2_2 - logic_error for exceeding register size" << std::endl;
3259 std::map<std::string, size_t> sizeMap;
3262 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3263 typedef typename decltype(x)::minimumUserType UserType;
3264 auto registerName = x.path();
3265 std::cout <<
"... registerName = " << registerName << std::endl;
3267 sizeMap[registerName] = reg.getNElementsPerChannel();
3271 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3272 typedef typename decltype(x)::minimumUserType UserType;
3273 auto registerName = x.path();
3274 std::cout <<
"... registerName = " << registerName << std::endl;
3304 if((sizeMap[registerName] > 1) && (x.capabilities.testPartialAccessor == TestCapability::enabled)) {
3306 BOOST_CHECK_NO_THROW(
3318 template<
typename VECTOR_OF_REGISTERS_T>
3320 std::cout <<
"--- test_C_5_2_3_2 - logic_error for wrong access mode flags" << std::endl;
3323 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3325 typedef typename decltype(x)::minimumUserType UserType;
3326 auto registerName = x.path();
3327 std::cout <<
"... registerName = " << registerName <<
" (wait_for_new_data throws)" << std::endl;
3331 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3333 typedef typename decltype(x)::minimumUserType UserType;
3334 auto registerName = x.path();
3335 std::cout <<
"... registerName = " << registerName <<
" (raw throws)" << std::endl;
3346 template<
typename VECTOR_OF_REGISTERS_T>
3348 if(_testOnlyTransferElement)
return;
3349 std::cout <<
"--- test_C_5_2_5_2 - logic_error on operation while backend closed" << std::endl;
3352 std::cout <<
"... synchronous read" << std::endl;
3353 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3354 if(!this->isRead(x))
return;
3355 typedef typename decltype(x)::minimumUserType UserType;
3356 auto registerName = x.path();
3357 std::cout <<
" registerName = " << registerName << std::endl;
3362 std::cout <<
"... asynchronous read" << std::endl;
3363 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3364 if(!this->isAsyncRead(x))
return;
3365 typedef typename decltype(x)::minimumUserType UserType;
3366 auto registerName = x.path();
3367 std::cout <<
" registerName = " << registerName << std::endl;
3370 BOOST_CHECK_THROW(reg.readNonBlocking(),
logic_error);
3373 std::cout <<
"... write" << std::endl;
3374 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3375 if(!this->isWrite(x))
return;
3376 typedef typename decltype(x)::minimumUserType UserType;
3377 auto registerName = x.path();
3378 std::cout <<
" registerName = " << registerName << std::endl;
3390 template<
typename VECTOR_OF_REGISTERS_T>
3392 std::cout <<
"--- test_C_5_2_6_2 - logic_error on read operation on write-only register" << std::endl;
3395 std::cout <<
"... synchronous read" << std::endl;
3396 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3397 if(!this->isWriteOnly(x))
return;
3398 typedef typename decltype(x)::minimumUserType UserType;
3399 auto registerName = x.path();
3400 std::cout <<
" registerName = " << registerName << std::endl;
3405 std::cout <<
"... asynchronous read" << std::endl;
3406 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3407 if(!this->isWriteOnly(x))
return;
3408 typedef typename decltype(x)::minimumUserType UserType;
3409 auto registerName = x.path();
3410 std::cout <<
" registerName = " << registerName << std::endl;
3422 template<
typename VECTOR_OF_REGISTERS_T>
3424 std::cout <<
"--- test_C_5_2_7_2 - logic_error on write operation on read-only register" << std::endl;
3427 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3428 if(!this->isReadOnly(x))
return;
3429 typedef typename decltype(x)::minimumUserType UserType;
3430 auto registerName = x.path();
3431 std::cout <<
" registerName = " << registerName << std::endl;
3444 template<
typename VECTOR_OF_REGISTERS_T>
3446 std::cout <<
"--- test_C_5_3 - read-only/write-only information changes after runtime_error" << std::endl;
3451 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3452 if(!this->isRead(x) || !this->isWrite(x) || x.capabilities.switchReadOnly != TestCapability::enabled)
return;
3453 typedef typename decltype(x)::minimumUserType UserType;
3454 auto registerName = x.path();
3455 std::cout <<
" registerName = " << registerName << std::endl;
3457 this->switchReadOnly(x,
true);
3458 BOOST_CHECK(reg.isWriteable() ==
true);
3460 BOOST_CHECK(reg.isWriteable() ==
false);
3461 this->switchReadOnly(x,
false);
3465 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3466 if(!this->isRead(x) || !this->isWrite(x) || x.capabilities.switchWriteOnly != TestCapability::enabled)
return;
3467 typedef typename decltype(x)::minimumUserType UserType;
3468 auto registerName = x.path();
3469 std::cout <<
" registerName = " << registerName << std::endl;
3471 this->switchWriteOnly(x,
true);
3472 BOOST_CHECK(reg.isReadable() ==
true);
3474 BOOST_CHECK(reg.isReadable() ==
false);
3475 this->switchWriteOnly(x,
false);
3485 template<
typename VECTOR_OF_REGISTERS_T>
3487 std::cout <<
"--- test_C_5_3_2 - read-only/write-only information cached per accessor" << std::endl;
3492 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3493 if(!this->isRead(x) || !this->isWrite(x) || x.capabilities.switchReadOnly != TestCapability::enabled)
return;
3494 typedef typename decltype(x)::minimumUserType UserType;
3495 auto registerName = x.path();
3496 std::cout <<
" registerName = " << registerName << std::endl;
3499 this->switchReadOnly(x,
true);
3501 BOOST_CHECK(reg2.isWriteable() ==
true);
3502 this->switchReadOnly(x,
false);
3506 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3507 if(!this->isRead(x) || !this->isWrite(x) || x.capabilities.switchWriteOnly != TestCapability::enabled)
return;
3508 typedef typename decltype(x)::minimumUserType UserType;
3509 auto registerName = x.path();
3510 std::cout <<
" registerName = " << registerName << std::endl;
3513 this->switchWriteOnly(x,
true);
3515 BOOST_CHECK(reg2.isReadable() ==
true);
3516 this->switchWriteOnly(x,
false);
3526 template<
typename VECTOR_OF_REGISTERS_T>
3528 std::cout <<
"--- test_C_5_3_3 - read-only/write-only information always returned from cache if available"
3533 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3534 typedef typename decltype(x)::minimumUserType UserType;
3535 auto registerName = x.path();
3536 std::cout <<
" registerName = " << registerName << std::endl;
3540 auto isReadable = reg.isReadable();
3541 auto isWriteable = reg.isWriteable();
3543 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
3544 std::cout <<
" -> runtime_error case: " << i << std::endl;
3546 x.setForceRuntimeError(
true, i);
3550 BOOST_CHECK(reg.isReadable() == isReadable);
3551 BOOST_CHECK(reg.isWriteable() == isWriteable);
3554 x.setForceRuntimeError(
false, i);
3568 template<
typename VECTOR_OF_REGISTERS_T>
3570 std::cout <<
"--- test_NOSPEC_valueAfterConstruction - content of the application data buffer after construction."
3574 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3575 typedef typename decltype(x)::minimumUserType UserType;
3576 auto registerName = x.path();
3577 std::cout <<
"... registerName = " << registerName << std::endl;
3581 std::vector<UserType> v(reg.getNElementsPerChannel(), UserType());
3582 for(
size_t i = 0; i < reg.getNChannels(); ++i) BOOST_CHECK(reg[i] == v);
3592 template<
typename VECTOR_OF_REGISTERS_T>
3594 if(_testOnlyTransferElement)
return;
3595 std::cout <<
"--- test_NOSPEC_backendNotClosedAfterException - backend not closed after exception" << std::endl;
3601 std::cout <<
"... synchronous read" << std::endl;
3602 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3603 if(!this->isRead(x))
return;
3604 if(x.nRuntimeErrorCases() == 0)
return;
3605 typedef typename decltype(x)::minimumUserType UserType;
3606 auto registerName = x.path();
3607 std::cout <<
" registerName = " << registerName << std::endl;
3610 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
3611 std::cout <<
" -> runtime_error case: " << i << std::endl;
3613 x.setForceRuntimeError(
true, i);
3628 x.setForceRuntimeError(
false, i);
3631 this->recoverDevice(d);
3635 std::cout <<
"... asynchronous read" << std::endl;
3637 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3638 if(!this->isAsyncRead(x))
return;
3639 if(x.nRuntimeErrorCases() == 0)
return;
3640 typedef typename decltype(x)::minimumUserType UserType;
3641 auto registerName = x.path();
3642 std::cout <<
" registerName = " << registerName << std::endl;
3645 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
3646 std::cout <<
" -> runtime_error case: " << i << std::endl;
3650 x.setForceRuntimeError(
true, i);
3665 x.setForceRuntimeError(
false, i);
3668 this->recoverDevice(d);
3673 std::cout <<
"... write" << std::endl;
3674 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3675 if(!this->isWrite(x))
return;
3676 if(x.nRuntimeErrorCases() == 0)
return;
3677 typedef typename decltype(x)::minimumUserType UserType;
3678 auto registerName = x.path();
3679 std::cout <<
" registerName = " << registerName << std::endl;
3682 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
3683 std::cout <<
" -> runtime_error case: " << i << std::endl;
3685 x.setForceRuntimeError(
true, i);
3700 x.setForceRuntimeError(
false, i);
3703 this->recoverDevice(d);
3707 std::cout <<
"... isReadable" << std::endl;
3708 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3709 if(x.nRuntimeErrorCases() == 0)
return;
3710 typedef typename decltype(x)::minimumUserType UserType;
3711 auto registerName = x.path();
3712 std::cout <<
" registerName = " << registerName;
3715 bool didThrow =
false;
3716 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
3717 std::cout <<
" -> runtime_error case: " << i << std::endl;
3719 x.setForceRuntimeError(
true, i);
3723 [[maybe_unused]]
auto result = reg.isReadable();
3738 x.setForceRuntimeError(
false, i);
3741 this->recoverDevice(d);
3745 std::cout <<
" (doesn't throw)" << std::endl;
3748 std::cout <<
" (throws)" << std::endl;
3752 std::cout <<
"... isWriteable" << std::endl;
3753 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3754 if(x.nRuntimeErrorCases() == 0)
return;
3755 typedef typename decltype(x)::minimumUserType UserType;
3756 auto registerName = x.path();
3757 std::cout <<
" registerName = " << registerName;
3760 bool didThrow =
false;
3761 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
3762 std::cout <<
" -> runtime_error case: " << i << std::endl;
3764 x.setForceRuntimeError(
true, i);
3768 [[maybe_unused]]
auto result = reg.isWriteable();
3783 x.setForceRuntimeError(
false, i);
3786 this->recoverDevice(d);
3790 std::cout <<
" (doesn't throw)" << std::endl;
3793 std::cout <<
" (throws)" << std::endl;
3797 std::cout <<
"... isReadOnly" << std::endl;
3798 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3799 typedef typename decltype(x)::minimumUserType UserType;
3800 auto registerName = x.path();
3801 std::cout <<
" registerName = " << registerName;
3804 bool didThrow =
false;
3805 for(
size_t i = 0; i < x.nRuntimeErrorCases(); ++i) {
3806 std::cout <<
" -> runtime_error case: " << i << std::endl;
3808 x.setForceRuntimeError(
true, i);
3812 [[maybe_unused]]
auto result = reg.isReadOnly();
3827 x.setForceRuntimeError(
false, i);
3830 this->recoverDevice(d);
3834 std::cout <<
" (doesn't throw)" << std::endl;
3837 std::cout <<
" (throws)" << std::endl;
3850 template<
typename VECTOR_OF_REGISTERS_T>
3852 std::cout <<
"--- test_NOSPEC_rawTransfer - test creation and reading/writing with access mode raw." << std::endl;
3856 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3858 if constexpr(x.capabilities.testRawTransfer == TestCapability::enabled) {
3859 auto registerName = x.path();
3860 std::cout <<
"... registerName = " << registerName << std::endl;
3862 BOOST_REQUIRE_MESSAGE(this->isRaw(x),
3863 "Test configuration error: testRawTransfer is enabled for register without AccessMode::raw!");
3865 typedef typename decltype(x)::minimumUserType UserType;
3866 typedef typename decltype(x)::rawUserType RawType;
3874 if(x.isReadable()) {
3877 auto expectedRawValue = x.template getRemoteValue<RawType>(
true);
3880 auto expectedCookedValue = x.template getRemoteValue<UserType>();
3883 std::vector<std::vector<UserType>> readCookedValue;
3884 for(
size_t channel = 0; channel < reg.getNChannels(); ++channel) {
3885 std::vector<UserType> readCookedChannel;
3886 for(
size_t element = 0; element < reg.getNElementsPerChannel(); ++element) {
3887 readCookedChannel.push_back(reg.template getAsCooked<UserType>(channel, element));
3889 readCookedValue.push_back(readCookedChannel);
3893 if(x.isWriteable()) {
3894 auto newValue = x.template generateValue<RawType>(
true);
3897 auto readbackValue = x.template getRemoteValue<RawType>(
true);
3901 auto newCookedValue = x.template generateValue<UserType>();
3902 for(
size_t channel = 0; channel < reg.getNChannels(); ++channel) {
3903 for(
size_t element = 0; element < reg.getNElementsPerChannel(); ++element) {
3904 reg.template setAsCooked<UserType>(channel, element, newCookedValue[channel][element]);
3909 auto readbackCookedValue = x.template getRemoteValue<UserType>();
3913 catch(std::exception& e) {
3914 BOOST_CHECK_MESSAGE(
false, std::string(
"Unexpected expeption: ") + e.what());
3917 if(this->isRaw(x)) {
3918 if(x.capabilities.testRawTransfer == TestCapability::disabled) {
3919 BOOST_REQUIRE_MESSAGE(
false,
3920 "Test configuration error: testRawTransfer is disabled for register '" + std::string(x.path()) +
3921 "' with AccessMode::raw!");
3923 else if(x.capabilities.testRawTransfer == TestCapability::unspecified) {
3924 std::cout <<
"WARNING: testRawTransfer capability unspecified for register '" + std::string(x.path()) +
3925 "' with AccessMode::raw. This will turn into a test configuration error in a future release!"
3930 if(x.capabilities.testRawTransfer == TestCapability::unspecified) {
3931 std::cout <<
"Warning: testRawTransfer capability unspecified for register '" + std::string(x.path()) +
3932 "' without AccessMode::raw. Please explicitly disable this test."
3945 template<
typename VECTOR_OF_REGISTERS_T>
3947 std::cout <<
"--- test_NOSPEC_catalogueRaw - test catalogue entries for access mode raw." << std::endl;
3950 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3951 if(x.capabilities.testCatalogue == TestCapability::disabled) {
3955 auto registerName = x.path();
3956 std::cout <<
"... registerName = " << registerName << std::endl;
3959 if(std::string(registerName).find(
"DUMMY_WRITEABLE") != std::string::npos) {
3963 if(std::string(registerName).find(
"DUMMY_INTERRUPT_") != std::string::npos) {
3969 if(this->isRaw(x)) {
3970 BOOST_CHECK(registerInfo.getSupportedAccessModes().has(AccessMode::raw));
3971 BOOST_TEST(registerInfo.getDataDescriptor().rawDataType() != DataType::none);
3974 BOOST_CHECK(not registerInfo.getSupportedAccessModes().has(AccessMode::raw));
3975 BOOST_CHECK((registerInfo.getDataDescriptor().rawDataType() == DataType::none) ||
3976 (registerInfo.getDataDescriptor().rawDataType() == DataType::Void));
3985 template<
typename VECTOR_OF_REGISTERS_T>
3987 std::cout <<
"--- test_NOSPEC_catalogueReadWrite- test catalogue and accessor entries for read/write." << std::endl;
3990 boost::mpl::for_each<VECTOR_OF_REGISTERS_T>([&](
auto x) {
3991 if(x.capabilities.testCatalogue == TestCapability::disabled) {
3995 typedef typename decltype(x)::minimumUserType UserType;
3997 auto registerName = x.path();
3998 std::cout <<
"... registerName = " << registerName << std::endl;
4003 BOOST_CHECK_EQUAL(this->isRead(x), registerInfo.isReadable());
4004 BOOST_CHECK_EQUAL(this->isRead(x), accessor.isReadable());
4005 BOOST_CHECK_EQUAL(this->isWrite(x), registerInfo.isWriteable());
4006 BOOST_CHECK_EQUAL(this->isWrite(x), accessor.isWriteable());
#define CHECK_APPLICATION_BUFFER(UserType, accessor)
#define CHECK_EQUALITY_TIMEOUT(accessor, expectedValue, maxMilliseconds)
#define CHECK_EQUALITY_VECTOR(foundValue, expectedValue)
#define CHECK_TIMEOUT(condition, maxMilliseconds)
#define CHECK_EQUALITY_VECTOR_TIMEOUT(foundValue, expectedValue, maxMilliseconds)
#define CHECK_EQUALITY(accessor, expectedValue)
#define ALTER_AND_STORE_APPLICATION_BUFFER(UserType, accessor)
#define CHECK_APPLICATION_DATA_BUFFER(UserType, accessor)
#define STORE_APPLICATION_DATA_BUFFER(UserType, accessor)
Helper macros for test_B_4_2_4 and test_B_4_2_5.
DeviceBackendImpl implements some basic functionality which should be available for all backends.
void setOpenedAndClearException() noexcept
Backends should call this function at the end of a (successful) open() call.
std::string getActiveExceptionMessage() noexcept
Class allows to read/write registers from device.
TwoDRegisterAccessor< UserType > getTwoDRegisterAccessor(const RegisterPath ®isterPathName, size_t numberOfElements=0, size_t elementsOffset=0, const AccessModeFlags &flags=AccessModeFlags({})) const
Get a TwoDRegisterAccessor object for the given register.
bool isOpened() const
Check if the device is currently opened.
void close()
Close the device.
void setException(const std::string &message)
Set the device into an exception state.
boost::shared_ptr< DeviceBackend > getBackend()
Obtain the backend.
RegisterCatalogue getRegisterCatalogue() const
Return the register catalogue with detailed information on all registers.
bool isFunctional() const
Return wether a device is working as intended, usually this means it is opened and does not have any ...
void activateAsyncRead() noexcept
Activate asyncronous read for all transfer elements where AccessMode::wait_for_new_data is set.
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Catalogue of register information.
RegisterInfo getRegister(const RegisterPath ®isterPathName) const
Get register information for a given full path name.
Accessor class to read and write 2D registers.
"Strong typedef" for list of pairs of functors for enabling and disabling a test condition.
Class to test any backend for correct behaviour.
void test_B_8_4()
Test async read consistency heartbeat.
void test_B_11_6()
Test the value after construction for the version number in the application buffer.
void switchWriteOnly(T t, bool enable)
void test_B_8_2_1()
Test _readQueue overrun.
VECTOR_OF_REGISTERS_T registers
boost::mpl::vector with all register descriptors
void test_B_9_3_2()
Test exactly one runtime_error in the _readQueue per async read accessor.
void test_NOSPEC_valueAfterConstruction()
Test the content of the application data buffer after construction.
bool isAsyncRead(REG_T x={})
void test_C_5_3_2()
Test read-only/write-only information cached per accessor.
void test_NOSPEC_partial_write()
Test partial write.
void test_B_12_1_5_1()
mayReplaceOther() of itself returns "false"
void test_NOSPEC_catalogueRaw()
Test that the catalogue information for the raw accessor is correct.
void recoverDevice(ChimeraTK::Device &d)
Utility functions for recurring tasks.
void test_B_8_5_1()
Test activateAsynchronousRead.
void test_C_5_2_5_2()
Test logic_error on operation while backend closed.
void test_B_6_4()
Test application buffer unchanged after exception.
void test_B_9_5()
Test write operations throw after setException()
void test_B_9_2_2()
Test repeated setException() has no effect (in particular, no additional exceptions in async transfer...
void test_NOSPEC_rawTransfer()
Test that the backend does not close itself after seeing an exception.
void test_B_9_3_1()
Test setException() disables asynchronous read transfers.
void test_NOSPEC_backendNotClosedAfterException()
Test that the backend does not close itself after seeing an exception.
bool isRead(REG_T x={})
Utility functions for register traits.
bool isSyncRead(REG_T x={})
void test_B_4_2_4()
Test transfer implementations do not change the application buffer.
UnifiedBackendTest< VECTOR_OF_REGISTERS_T > & testOnlyTransferElement()
Call if not a real backend is tested but just a special TransferElement implementation.
void test_B_3_2_2()
Test destructive write.
size_t writeQueueLength(T t)
void test_B_8_3()
Test new runtime errors are put to _readQueue in async reads.
void test_B_8_5_2()
Test initial value.
void test_B_4_2_5()
Test that xxxTransferYyy() can be skipped between preXxx() and postXxx()
void test_B_8_6_6()
Test interrupt()
void test_B_11_2_2()
Test consistent data gets same VersionNumber.
void test_B_3_2_1_2()
Test write() does not destroy application buffer.
void test_NOSPEC_newVersionAfterOpen()
Test versions after calling open() are newer than any version before.
void test_C_5_3()
Test read-only/write-only information changes after runtime_error.
void runTests(const std::string &cdd_, const std::string &cdd2_="")
Execute all tests.
void test_NOSPEC_partial_read()
Partial accessor read.
size_t nValuesToTest(T t)
void test_C_5_2_2_2()
Test logic_error for exceeding register size.
void test_B_9_1()
Test reporting exceptions to exception backend.
void test_B_11_2_1()
Test version number bigger for newer values.
void forceAsyncReadInconsistency(T t)
void test_B_7_2()
Test data loss in write.
void test_C_5_2_7_2()
Test logic_error on write operation on read-only register.
void test_C_5_3_3()
Test read-only/write-only information always returned from cache if available.
void test_B_8_2()
Test async read fills _readQueue.
void test_C_5_2_6_2()
Test logic_error on read operation on write-only register.
void setForceDataLossWrite(T t, bool enable)
void test_B_8_5()
Test no async transfers until activateAsyncRead().
void test_B_3_1_2_1()
Test synchronous read.
std::string cdd
CDD for backend to test.
void test_B_9_4_1()
Test doReadTransferSynchronously throws runtime_error after setException() until recovery.
UnifiedBackendTest< typename boost::mpl::push_back< VECTOR_OF_REGISTERS_T, REG_T >::type > addRegister()
Add a register to be used by the test.
void test_C_5_2_3_2()
Test logic_error for wrong access mode flags.
bool _testOnlyTransferElement
Flag whether to disable tests for the backend itself.
void test_B_8_5_4_3()
Calling activateAsyncRead() when already active has no effect.
void test_NOSPEC_write()
Test write.
void test_B_12_1_3_1()
If an element that is already in the list of internal elements is passed to TransferElement::replaceT...
bool isReadOnly(REG_T x={})
void switchReadOnly(T t, bool enable)
void test_NOSPEC_catalogueReadWrite()
Test that the catalogue and accessor information for read and write are correct.
void test_C_5_2_1_2()
Test logic_error for non-existing register.
bool isWriteOnly(REG_T x={})
void test_B_8_5_3()
Accessors created after activateAsyncRead() are immediately active.
Class for generating and holding version numbers without exposing a numeric representation.
Exception thrown when a logic error has occured.
Exception thrown when a runtime error has occured.
bool compareHelper< float >(float a, float b)
bool compareHelper< double >(double a, double b)
bool compareHelper< std::string >(std::string a, std::string b)
@ wait_for_new_data
Make any read blocking until new data has arrived since the last read.
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
TestCapability
Used by the Capabilities descriptor.
@ disabled
Disable tests requiring this capability and do not warn.
@ enabled
Enable tests requiring this capability.
@ unspecified
Capability is not specified, hence it is disabled and a warning is printed. Usually default.
bool compareHelper(UserType a, UserType b)
std::string to_string(const std::string &v)
Descriptor for the test capabilities for each register.
static constexpr TestCapability writeNeverLosesData
static constexpr TestCapability testPartialAccessor
static constexpr TestCapability switchReadOnly
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, TestCapability::enabled, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > enableTestReadOnly() const
Enable/disable testing only read operations, even if the register is readable.
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, TestCapability::disabled, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableSwitchReadOnly() const
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, TestCapability::disabled, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableTestRawTransfer() const
Enable/disable testing the raw accessors.
constexpr TestCapabilities< _syncRead, TestCapability::enabled, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, TestCapability::disabled, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > enableForceDataLossWrite() const
See setForceDataLossWrite() function in the register descriptor.
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, TestCapability::disabled, _testPartialAccessor > disableSetRemoteValueIncrementsVersion() const
Enable/disable testing of version number increment in read operations after setRemoteValue.
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, TestCapability::enabled, _setRemoteValueIncrementsVersion, _testPartialAccessor > enableTestCatalogue() const
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, TestCapability::disabled, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableTestWriteOnly() const
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, TestCapability::enabled, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > enableTestWriteOnly() const
Enable/disable testing only write operations, even if the register is readable.
static constexpr TestCapability forceDataLossWrite
constexpr TestCapabilities< _syncRead, TestCapability::disabled, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableForceDataLossWrite() const
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, TestCapability::disabled, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableAsyncReadInconsistency() const
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, TestCapability::disabled > disableTestPartialAccessor() const
Enable/disable testing for writing with a partial accessor.
constexpr TestCapabilities< _syncRead, TestCapability::disabled, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, TestCapability::enabled, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > enableTestWriteNeverLosesData() const
Enable/disable test whether write transfers never report lost data (part of B.7.2).
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, TestCapability::enabled, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > enableTestRawTransfer() const
static constexpr TestCapability syncRead
constexpr TestCapabilities()=default
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, TestCapability::enabled, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > enableSwitchWriteOnly() const
See switchWriteOnly() function in the register descriptor.
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, TestCapability::disabled, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableTestWriteNeverLosesData() const
static constexpr TestCapability testRawTransfer
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, TestCapability::enabled, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > enableSwitchReadOnly() const
See switchReadOnly() function in the register descriptor.
static constexpr TestCapability switchWriteOnly
constexpr TestCapabilities< TestCapability::disabled, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableSyncRead() const
Allows to prevent the test from executing any synchronous read tests.
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, TestCapability::disabled, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableTestReadOnly() const
static constexpr TestCapability testWriteOnly
static constexpr TestCapability setRemoteValueIncrementsVersion
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, TestCapability::disabled, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableSwitchWriteOnly() const
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, TestCapability::enabled, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, _testPartialAccessor > enableAsyncReadInconsistency() const
See forceAsyncReadInconsistency() function in the register descriptor.
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, _setRemoteValueIncrementsVersion, TestCapability::enabled > enableTestPartialAccessor() const
static constexpr TestCapability testCatalogue
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, TestCapability::disabled, _setRemoteValueIncrementsVersion, _testPartialAccessor > disableTestCatalogue() const
Enable/disable testing of catalogue content.
static constexpr TestCapability testReadOnly
static constexpr TestCapability asyncReadInconsistency
constexpr TestCapabilities< _syncRead, _forceDataLossWrite, _asyncReadInconsistency, _switchReadOnly, _switchWriteOnly, _writeNeverLosesData, _testWriteOnly, _testReadOnly, _testRawTransfer, _testCatalogue, TestCapability::enabled, _testPartialAccessor > enableSetRemoteValueIncrementsVersion() const
Special DeviceBackend used for testing the exception reporting to the backend.
void open() override
Open the device.
void setExceptionImpl() noexcept override
Function to be (optionally) implemented by backends if additional actions are needed when switching t...
~ExceptionReportingBackend() override=default
bool hasSeenException()
Check whether setException() has been called since the last call to hasSeenException().
RegisterCatalogue getRegisterCatalogue() const override
Return the register catalogue with detailed information on all registers.
std::string readDeviceInfo() override
Return a device information string containing hardware details like the firmware version number or th...
void close() override
Close the device.
ExceptionReportingBackend(boost::shared_ptr< DeviceBackend > target)
forceAsyncReadInconsistency_proxy_helper(T)
forceAsyncReadInconsistency_proxy_helper(T t)
nValuesToTest_proxy_helper(T)
nValuesToTest_proxy_helper(T t)
setForceDataLossWrite_proxy_helper(T, bool)
setForceDataLossWrite_proxy_helper(T t, bool enable)
switchReadOnly_proxy_helper(T, bool)
switchReadOnly_proxy_helper(T t, bool enable)
switchWriteOnly_proxy_helper(T, bool)
switchWriteOnly_proxy_helper(T t, bool enable)
writeQueueLength_proxy_helper(T)
writeQueueLength_proxy_helper(T t)