11 #include <boost/shared_ptr.hpp>
27 template<
typename DATA_TYPE>
28 struct pitched_iterator {
30 using iterator_category = std::random_access_iterator_tag;
31 using value_type = DATA_TYPE;
32 using difference_type = std::ptrdiff_t;
33 using pointer = DATA_TYPE*;
34 using reference = DATA_TYPE&;
37 pitched_iterator(
void* begin,
size_t pitch) : _ptr(
reinterpret_cast<std::byte*
>(begin)), _pitch(pitch) {}
39 template<
typename OTHER_DATA_TYPE>
40 explicit pitched_iterator(pitched_iterator<OTHER_DATA_TYPE>& other) : _ptr(other._ptr), _pitch(other._pitch) {}
42 pitched_iterator& operator++() {
46 pitched_iterator operator++(
int) {
47 pitched_iterator retval = *
this;
51 pitched_iterator
operator+(
size_t n) {
return pitched_iterator(_ptr + n * _pitch, _pitch); }
52 bool operator==(pitched_iterator other)
const {
return _ptr == other._ptr; }
53 bool operator!=(pitched_iterator other)
const {
return !(*
this == other); }
54 size_t operator-(pitched_iterator other)
const {
return _ptr - other._ptr; }
56 DATA_TYPE&
operator*()
const {
return *
reinterpret_cast<DATA_TYPE*
>(_ptr); }
62 template<
typename OTHER_DATA_TYPE>
63 friend struct pitched_iterator;
72 template<
class UserType,
class ConverterType>
76 size_t elementsOffset,
const boost::shared_ptr<DeviceBackend>& _backend);
90 [[nodiscard]]
bool mayReplaceOther(
const boost::shared_ptr<TransferElement const>& other)
const override {
92 boost::dynamic_pointer_cast<const NumericAddressedBackendMuxedRegisterAccessor<UserType, ConverterType>>(
94 if(!rhsCasted)
return false;
95 if(
_ioDevice != rhsCasted->_ioDevice)
return false;
97 if(
_converters != rhsCasted->_converters)
return false;
122 return {boost::enable_shared_from_this<TransferElement>::shared_from_this()};
135 template<
class UserType,
class ConverterType>
137 const RegisterPath& registerPathName,
size_t numberOfElements,
size_t elementsOffset,
138 const boost::shared_ptr<DeviceBackend>& _backend)
140 _ioDevice(boost::dynamic_pointer_cast<NumericAddressedBackend>(_backend)) {
142 _registerInfo = _ioDevice->_registerMap.getBackendRegister(registerPathName);
143 assert(!_registerInfo.channels.empty());
146 for(
size_t i = 0; i < _registerInfo.getNumberOfChannels(); ++i) {
147 if(_registerInfo.channels[i].bitOffset % 8 != 0) {
148 throw ChimeraTK::logic_error(
"NumericAddressedBackendMuxedRegisterAccessor: elements must be byte aligned.");
150 _converters.emplace_back(detail::createDataConverter<ConverterType>(_registerInfo, i));
153 if(_registerInfo.elementPitchBits % 8 != 0) {
154 throw ChimeraTK::logic_error(
"NumericAddressedBackendMuxedRegisterAccessor: blocks must be byte aligned.");
158 if(numberOfElements == 0) {
159 numberOfElements = _registerInfo.nElements;
163 if(numberOfElements + elementsOffset > _registerInfo.nElements) {
166 ") of the register '" + registerPathName +
"'!");
168 throw ChimeraTK::logic_error(
"Requested number of elements exceeds the size of the register! Requested end: " +
174 _registerInfo.nElements = numberOfElements;
175 assert(_registerInfo.elementPitchBits % 8 == 0);
176 _registerInfo.address += elementsOffset * _registerInfo.elementPitchBits / 8;
180 for(
size_t i = 0; i < _converters.size(); ++i) {
186 static_cast<size_t>(_registerInfo.elementPitchBits) / 8 * _registerInfo.nElements /
sizeof(int32_t) + 1);
193 auto* ioBuffer =
reinterpret_cast<uint8_t*
>(&_ioBuffer[0]);
194 for(
auto& c : _registerInfo.channels) {
195 assert(c.bitOffset % 8 == 0);
196 _startIterators.emplace_back(ioBuffer + c.bitOffset / 8, _registerInfo.elementPitchBits / 8);
197 _endIterators.push_back(_startIterators.back() + _registerInfo.nElements);
203 template<
class UserType,
class ConverterType>
205 assert(_registerInfo.elementPitchBits % 8 == 0);
207 auto nbt = _registerInfo.elementPitchBits / 8 * _registerInfo.nElements;
208 nbt = ((nbt - 1) / 4 + 1) * 4;
210 _ioDevice->read(_registerInfo.bar, _registerInfo.address, _ioBuffer.data(), nbt);
215 template<
class UserType,
class ConverterType>
219 for(
size_t i = 0; i < _converters.size(); ++i) {
220 _converters[i].template vectorToCooked<UserType>(_startIterators[i], _endIterators[i], buffer_2D[i].begin());
224 this->_versionNumber = {};
233 template<
class UserType,
class ConverterType>
235 assert(_registerInfo.elementPitchBits % 8 == 0);
237 auto nbt = _registerInfo.elementPitchBits / 8 * _registerInfo.nElements;
238 nbt = ((nbt - 1) / 4 + 1) * 4;
240 _ioDevice->write(_registerInfo.bar, _registerInfo.address, &(_ioBuffer[0]), nbt);
246 template<
class UserType,
class ConverterType>
250 assert(_registerInfo.channels.size() == _converters.size());
253 for(
size_t i = 0; i < _registerInfo.channels.size(); ++i) {
254 callForRawType(_registerInfo.channels[i].getRawType(), [&](
auto x) {
255 using RawType = decltype(x);
260 std::transform(buffer_2D[i].begin(), buffer_2D[i].end(), detail::pitched_iterator<RawType>(_startIterators[i]),
261 [&](UserType cookedValue) { return _converters[i].toRaw(cookedValue); });
270 NumericAddressedBackendMuxedRegisterAccessor, IEEE754_SingleConverter);