ChimeraTK-DeviceAccess 03.26.00
Loading...
Searching...
No Matches
NumericAddressedBackendMuxedRegisterAccessor.cc
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
5
6namespace ChimeraTK {
7
8 /********************************************************************************************************************/
9
10 template<class UserType>
12 const RegisterPath& registerPathName, size_t numberOfElements, size_t elementsOffset,
13 const boost::shared_ptr<DeviceBackend>& _backend)
14 : NDRegisterAccessor<UserType>(registerPathName, {}),
15 _ioDevice(boost::dynamic_pointer_cast<NumericAddressedBackend>(_backend)) {
16 // Obtain information about the area
17 _registerInfo = _ioDevice->_registerMap.getBackendRegister(registerPathName);
18 assert(!_registerInfo.channels.empty());
19
20 // Create a RawConverter for each channel
21 for(size_t i = 0; i < _registerInfo.getNumberOfChannels(); ++i) {
22 if(_registerInfo.channels[i].bitOffset % 8 != 0) {
23 throw ChimeraTK::logic_error("NumericAddressedBackendMuxedRegisterAccessor: elements must be byte aligned.");
24 }
25 _converterLoopHelpers.emplace_back(
26 RawConverter::ConverterLoopHelper::makeConverterLoopHelper<UserType>(_registerInfo, i, *this));
27 }
28 // check information
29 if(_registerInfo.elementPitchBits % 8 != 0) {
30 throw ChimeraTK::logic_error("NumericAddressedBackendMuxedRegisterAccessor: blocks must be byte aligned.");
31 }
32
33 // compute effective numberOfElements
34 if(numberOfElements == 0) {
35 numberOfElements = _registerInfo.nElements;
36 }
37
38 // check number of words
39 if(numberOfElements + elementsOffset > _registerInfo.nElements) {
40 throw ChimeraTK::logic_error("Requested number of elements (" + std::to_string(numberOfElements) + " + " +
41 std::to_string(elementsOffset) + ") exceeds the size (" + std::to_string(_registerInfo.nElements) +
42 ") of the register '" + registerPathName + "'!");
43
44 throw ChimeraTK::logic_error("Requested number of elements exceeds the size of the register! Requested end: " +
45 std::to_string(numberOfElements + elementsOffset) +
46 ", register length: " + std::to_string(_registerInfo.nElements));
47 }
48
49 // update register info
50 _registerInfo.nElements = numberOfElements;
51 assert(_registerInfo.elementPitchBits % 8 == 0);
52 _registerInfo.address += elementsOffset * _registerInfo.elementPitchBits / 8;
53
54 // allocate the buffer for the converted data
55 NDRegisterAccessor<UserType>::buffer_2D.resize(_converterLoopHelpers.size());
56 for(size_t i = 0; i < _converterLoopHelpers.size(); ++i) {
57 NDRegisterAccessor<UserType>::buffer_2D[i].resize(_registerInfo.nElements);
58 }
59
60 // allocate the raw io buffer. Make it one element larger to make sure we can access the last byte via int32_t*
61 _ioBuffer.resize(
62 static_cast<size_t>(_registerInfo.elementPitchBits) / 8 * _registerInfo.nElements / sizeof(int32_t) + 1);
63
64 // compute pitched iterators for accessing the channels
65 // Silence the linter: Yes, we are doing a reinterpet cast. There is nothing we can do about it when we're
66 // bit-fiddling
67
68 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
69 auto* ioBuffer = reinterpret_cast<uint8_t*>(&_ioBuffer[0]);
70 for(auto& c : _registerInfo.channels) {
71 assert(c.bitOffset % 8 == 0);
72 _startIterators.emplace_back(ioBuffer + c.bitOffset / 8, _registerInfo.elementPitchBits / 8);
73 _endIterators.push_back(_startIterators.back() + _registerInfo.nElements);
74 }
75 }
76
77 /********************************************************************************************************************/
78
79 template<class UserType>
81 assert(_registerInfo.elementPitchBits % 8 == 0);
82
83 auto nbt = _registerInfo.elementPitchBits / 8 * _registerInfo.nElements;
84 nbt = ((nbt - 1) / 4 + 1) * 4; // round up to multiple of 4 bytes
85
86 _ioDevice->read(_registerInfo.bar, _registerInfo.address, _ioBuffer.data(), nbt);
87 }
88
89 /********************************************************************************************************************/
90
91 template<class UserType>
93 if(hasNewData) {
94 for(size_t channelIndex = 0; channelIndex < _registerInfo.channels.size(); ++channelIndex) {
95 _converterLoopHelpers[channelIndex]->doPostRead();
96 }
97
98 // it is acceptable to create the version number in post read because this accessor does not have
99 // wait_for_new_data. It is basically synchronous.
100 this->_versionNumber = {};
101
102 // we just read good data. Set validity back to ok if someone marked it faulty for writing.
103 this->_dataValidity = DataValidity::ok;
104 }
105 }
106
107 /********************************************************************************************************************/
108
109 template<class UserType>
110 template<class UserType2, typename RawType, RawConverter::SignificantBitsCase sc, RawConverter::FractionalCase fc,
111 bool isSigned>
114 static_assert(std::is_same_v<UserType, UserType2>);
115 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
116 std::transform(_startIterators[channelIndex], _endIterators[channelIndex], buffer_2D[channelIndex].begin(),
117 [&](auto rawValue) { return converter.toCooked(rawValue); });
118 }
119 }
120
121 /********************************************************************************************************************/
122
123 template<class UserType>
125 assert(_registerInfo.elementPitchBits % 8 == 0);
126
127 auto nbt = _registerInfo.elementPitchBits / 8 * _registerInfo.nElements;
128 nbt = ((nbt - 1) / 4 + 1) * 4; // round up to multiple of 4 bytes
129
130 _ioDevice->write(_registerInfo.bar, _registerInfo.address, &(_ioBuffer[0]), nbt);
131 return false;
132 }
133
134 /********************************************************************************************************************/
135
136 template<class UserType>
138 if(!_ioDevice->isOpen()) {
139 throw ChimeraTK::logic_error("Device not opened.");
140 }
141
142 assert(_registerInfo.channels.size() == _converterLoopHelpers.size());
143
144 for(size_t channelIndex = 0; channelIndex < _registerInfo.channels.size(); ++channelIndex) {
145 _converterLoopHelpers[channelIndex]->doPreWrite();
146 }
147 }
148
149 /********************************************************************************************************************/
150
151 template<class UserType>
152 template<class UserType2, typename RawType, RawConverter::SignificantBitsCase sc, RawConverter::FractionalCase fc,
153 bool isSigned>
156 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
157 std::transform(buffer_2D[channelIndex].begin(), buffer_2D[channelIndex].end(),
158 detail::pitched_iterator<RawType>(_startIterators[channelIndex]),
159 [&](UserType cookedValue) { return converter.toRaw(cookedValue); });
160 }
161 }
162
163 /********************************************************************************************************************/
164
166} // namespace ChimeraTK
#define INSTANTIATE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(TemplateClass)
N-dimensional register accessor.
std::vector< std::vector< UserType > > buffer_2D
Buffer of converted data elements.
Implementation of the NDRegisterAccessor for NumericAddressedBackends for multiplexd 2D registers.
void doPreWriteImpl(RawConverter::Converter< UserType2, RawType, sc, fc, isSigned > converter, size_t channelIndex)
void doPostReadImpl(RawConverter::Converter< UserType2, RawType, sc, fc, isSigned > converter, size_t channelIndex)
void doReadTransferSynchronously() override
Implementation version of readTransfer() for synchronous reads.
void doPostRead(TransferType type, bool hasNewData) override
Backend specific implementation of postRead().
bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber) override
Implementation version of writeTransfer().
void doPreWrite(TransferType type, VersionNumber versionNumber) override
Backend specific implementation of preWrite().
NumericAddressedBackendMuxedRegisterAccessor(const RegisterPath &registerPathName, size_t numberOfElements, size_t elementsOffset, const boost::shared_ptr< DeviceBackend > &_backend)
Converter class for conversions from raw to cooked values.
UserType toCooked(RawType rawValue)
RawType toRaw(UserType cookedValue)
Class to store a register path name.
Class for generating and holding version numbers without exposing a numeric representation.
Exception thrown when a logic error has occured.
Definition Exception.h:51
TransferType
Used to indicate the applicable operation on a Transferelement.
std::string to_string(const std::string &v)