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.get() ==
this) {
97 if(!rhsCasted)
return false;
98 if(
_ioDevice != rhsCasted->_ioDevice)
return false;
100 if(
_converters != rhsCasted->_converters)
return false;
125 return {boost::enable_shared_from_this<TransferElement>::shared_from_this()};
138 template<
class UserType,
class ConverterType>
140 const RegisterPath& registerPathName,
size_t numberOfElements,
size_t elementsOffset,
141 const boost::shared_ptr<DeviceBackend>& _backend)
143 _ioDevice(boost::dynamic_pointer_cast<NumericAddressedBackend>(_backend)) {
145 _registerInfo = _ioDevice->_registerMap.getBackendRegister(registerPathName);
146 assert(!_registerInfo.channels.empty());
149 for(
size_t i = 0; i < _registerInfo.getNumberOfChannels(); ++i) {
150 if(_registerInfo.channels[i].bitOffset % 8 != 0) {
151 throw ChimeraTK::logic_error(
"NumericAddressedBackendMuxedRegisterAccessor: elements must be byte aligned.");
153 _converters.emplace_back(detail::createDataConverter<ConverterType>(_registerInfo, i));
156 if(_registerInfo.elementPitchBits % 8 != 0) {
157 throw ChimeraTK::logic_error(
"NumericAddressedBackendMuxedRegisterAccessor: blocks must be byte aligned.");
161 if(numberOfElements == 0) {
162 numberOfElements = _registerInfo.nElements;
166 if(numberOfElements + elementsOffset > _registerInfo.nElements) {
169 ") of the register '" + registerPathName +
"'!");
171 throw ChimeraTK::logic_error(
"Requested number of elements exceeds the size of the register! Requested end: " +
177 _registerInfo.nElements = numberOfElements;
178 assert(_registerInfo.elementPitchBits % 8 == 0);
179 _registerInfo.address += elementsOffset * _registerInfo.elementPitchBits / 8;
183 for(
size_t i = 0; i < _converters.size(); ++i) {
189 static_cast<size_t>(_registerInfo.elementPitchBits) / 8 * _registerInfo.nElements /
sizeof(int32_t) + 1);
196 auto* ioBuffer =
reinterpret_cast<uint8_t*
>(&_ioBuffer[0]);
197 for(
auto& c : _registerInfo.channels) {
198 assert(c.bitOffset % 8 == 0);
199 _startIterators.emplace_back(ioBuffer + c.bitOffset / 8, _registerInfo.elementPitchBits / 8);
200 _endIterators.push_back(_startIterators.back() + _registerInfo.nElements);
206 template<
class UserType,
class ConverterType>
208 assert(_registerInfo.elementPitchBits % 8 == 0);
210 auto nbt = _registerInfo.elementPitchBits / 8 * _registerInfo.nElements;
211 nbt = ((nbt - 1) / 4 + 1) * 4;
213 _ioDevice->read(_registerInfo.bar, _registerInfo.address, _ioBuffer.data(), nbt);
218 template<
class UserType,
class ConverterType>
222 for(
size_t i = 0; i < _converters.size(); ++i) {
223 _converters[i].template vectorToCooked<UserType>(_startIterators[i], _endIterators[i], buffer_2D[i].begin());
227 this->_versionNumber = {};
236 template<
class UserType,
class ConverterType>
238 assert(_registerInfo.elementPitchBits % 8 == 0);
240 auto nbt = _registerInfo.elementPitchBits / 8 * _registerInfo.nElements;
241 nbt = ((nbt - 1) / 4 + 1) * 4;
243 _ioDevice->write(_registerInfo.bar, _registerInfo.address, &(_ioBuffer[0]), nbt);
249 template<
class UserType,
class ConverterType>
253 assert(_registerInfo.channels.size() == _converters.size());
256 for(
size_t i = 0; i < _registerInfo.channels.size(); ++i) {
257 callForRawType(_registerInfo.channels[i].getRawType(), [&](
auto x) {
258 using RawType = decltype(x);
263 std::transform(buffer_2D[i].begin(), buffer_2D[i].end(), detail::pitched_iterator<RawType>(_startIterators[i]),
264 [&](UserType cookedValue) { return _converters[i].toRaw(cookedValue); });
#define DECLARE_MULTI_TEMPLATE_FOR_CHIMERATK_USER_TYPES(TemplateClass,...)
Macro to declare a template class with multiple template parameters for all supported user types.
The fixed point converter provides conversion functions between a user type and up to 32 bit fixed po...
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.
std::vector< detail::pitched_iterator< int32_t > > _startIterators
std::vector< boost::shared_ptr< TransferElement > > getHardwareAccessingElements() override
Obtain the underlying TransferElements with actual hardware access.
std::vector< int32_t > _ioBuffer
NumericAddressedBackendMuxedRegisterAccessor(const RegisterPath ®isterPathName, size_t numberOfElements, size_t elementsOffset, const boost::shared_ptr< DeviceBackend > &_backend)
void doReadTransferSynchronously() override
Implementation version of readTransfer() for synchronous reads.
void doPostRead(TransferType type, bool hasNewData) override
Backend specific implementation of postRead().
boost::shared_ptr< NumericAddressedBackend > _ioDevice
The device from (/to) which to perform the DMA transfer.
NumericAddressedRegisterInfo _registerInfo
std::vector< detail::pitched_iterator< int32_t > > _endIterators
bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber) override
Implementation version of writeTransfer().
std::list< boost::shared_ptr< TransferElement > > getInternalElements() override
Obtain the full list of TransferElements internally used by this TransferElement.
void doPreRead(TransferType) override
Backend specific implementation of preRead().
bool isWriteable() const override
Check if transfer element is writeable.
bool isReadable() const override
Check if transfer element is readable.
bool mayReplaceOther(const boost::shared_ptr< TransferElement const > &other) const override
Check whether the TransferElement can be used in places where the TransferElement "other" is currentl...
void doPreWrite(TransferType type, VersionNumber versionNumber) override
Backend specific implementation of preWrite().
void replaceTransferElement(boost::shared_ptr< TransferElement >) override
Search for all underlying TransferElements which are considered identical (see sameRegister()) with t...
std::vector< ConverterType > _converters
One converter for each sequence.
bool isReadOnly() const override
Check if transfer element is read only, i.e.
bool isReadable() const override
Return whether the register is readable.
bool isWriteable() const override
Return whether the register is writeable.
Class to store a register path name.
boost::shared_ptr< DeviceBackend > _exceptionBackend
The backend to which the runtime_errors are reported via DeviceBackend::setException().
Class for generating and holding version numbers without exposing a numeric representation.
Exception thrown when a logic error has occured.
std::string operator+(const std::string &leftHandSide, const RegisterPath &rightHandSide)
non-member + operator for RegisterPath: concatenate with normal strings.
void callForRawType(const DataType &type, LAMBDATYPE lambda)
callForRawType() is similar to callForType(), just with a subset of supported data types which can be...
constexpr auto MULTIPLEXED_SEQUENCE_PREFIX
constexpr auto SEQUENCE_PREFIX
constexpr auto MEM_MULTIPLEXED_PREFIX
TransferType
Used to indicate the applicable operation on a Transferelement.
RegisterPath operator*(const RegisterPath &leftHandSide, int rightHandSide)
std::string to_string(const std::string &v)
Needs to have the same interface as FixedPointConverter, except for the constructor.