12 const RegisterPath& registerPathName,
size_t numberOfElements,
size_t elementsOffset,
13 const boost::shared_ptr<DeviceBackend>& _backend)
15 _ioDevice(boost::dynamic_pointer_cast<NumericAddressedBackend>(_backend)) {
17 _registerInfo = _ioDevice->_registerMap.getBackendRegister(registerPathName);
18 assert(!_registerInfo.channels.empty());
21 if(_registerInfo.elementPitchBits % 8 != 0) {
22 throw ChimeraTK::logic_error(
"NumericAddressedBackendMuxedRegisterAccessor: blocks must be byte aligned.");
28 if(_registerInfo.isBitRange) {
29 throw ChimeraTK::logic_error(
"NumericAddressedBackendMuxedRegisterAccessor: register '" + registerPathName +
30 "' contains bit-range channels. Access them through the named-channel slices.");
35 struct ConverterInfo {
36 NumericAddressedRegisterInfo::Type dataType;
38 int32_t nFractionalBits;
43 auto operator<=>(
const ConverterInfo& rhs)
const =
default;
46 explicit ConverterInfo(
const NumericAddressedRegisterInfo::ChannelInfo& o)
47 : dataType(o.dataType), width(o.width), nFractionalBits(o.nFractionalBits), signedFlag(o.signedFlag),
53 std::map<ConverterInfo, size_t> groupInfoMap;
54 for(
size_t channelIndex = 0; channelIndex < _registerInfo.getNumberOfChannels(); ++channelIndex) {
55 const auto& info = _registerInfo.channels[channelIndex];
57 if(info.bitOffset % 8 != 0) {
58 throw ChimeraTK::logic_error(
"NumericAddressedBackendMuxedRegisterAccessor: elements must be byte aligned.");
62 const auto converterInfo = ConverterInfo(info);
63 auto it = groupInfoMap.find(converterInfo);
64 if(it == groupInfoMap.end()) {
66 auto newGroupId = groupInfoMap.size();
67 groupInfoMap[converterInfo] = newGroupId;
69 ChannelGroup newGroup;
70 newGroup.channels.emplace_back(
71 channelIndex, 0,
typename std::vector<UserType>::iterator());
72 newGroup.converterLoopHelper = RawConverter::ConverterLoopHelper::makeConverterLoopHelper<UserType>(
73 _registerInfo, channelIndex, newGroupId, *
this);
74 newGroup.startOffset = info.bitOffset / 8;
77 _channelGroups.emplace_back(std::move(newGroup));
81 _channelGroups[it->second].channels.emplace_back(
82 channelIndex, 0,
typename std::vector<UserType>::iterator());
85 assert(_channelGroups.size() == groupInfoMap.size());
89 for(
auto& group : _channelGroups) {
90 assert(group.channels.size() >= 1);
92 for(
size_t i = 0; i < group.channels.size() - 1; ++i) {
93 auto bitOffset = _registerInfo.channels[group.channels[i + 1].index].bitOffset -
94 _registerInfo.channels[group.channels[i].index].bitOffset;
95 assert(bitOffset % 8 == 0);
96 group.channels[i].offsetToNext = bitOffset / 8;
99 auto lastBitOffset = _registerInfo.elementPitchBits -
100 _registerInfo.channels[group.channels.back().index].bitOffset +
101 _registerInfo.channels[group.channels.front().index].bitOffset;
102 assert(lastBitOffset % 8 == 0);
103 group.channels.back().offsetToNext = lastBitOffset / 8;
107 if(numberOfElements == 0) {
108 numberOfElements = _registerInfo.nElements;
112 if(numberOfElements + elementsOffset > _registerInfo.nElements) {
115 ") of the register '" + registerPathName +
"'!");
117 throw ChimeraTK::logic_error(
"Requested number of elements exceeds the size of the register! Requested end: " +
123 _registerInfo.nElements = numberOfElements;
124 assert(_registerInfo.elementPitchBits % 8 == 0);
125 _registerInfo.address += elementsOffset * _registerInfo.elementPitchBits / 8;
129 for(
auto& buf : NDRegisterAccessor<UserType>::buffer_2D) {
130 buf.resize(_registerInfo.nElements);
135 static_cast<size_t>(_registerInfo.elementPitchBits) / 8 * _registerInfo.nElements /
sizeof(int32_t) + 1);
176 static_assert(std::is_same_v<UserType, UserType2>);
177 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
178 auto& group = _channelGroups[channelGroupId];
181 for(
auto& channel : group.channels) {
182 channel.cookedIterator = buffer_2D[channel.index].begin();
188 auto* rawIterator =
reinterpret_cast<std::byte*
>(_ioBuffer.data()) + group.startOffset;
190 for(
size_t i = 0; i < this->getNumberOfSamples(); ++i) {
191 for(
auto& channel : group.channels) {
194 std::memcpy(&rawValue, rawIterator,
sizeof(RawType));
197 *channel.cookedIterator = converter.
toCooked(rawValue);
200 ++channel.cookedIterator;
201 rawIterator += channel.offsetToNext;
240 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
241 auto& group = _channelGroups[channelGroupId];
244 for(
auto& channel : group.channels) {
245 channel.cookedIterator = buffer_2D[channel.index].begin();
251 auto* rawIterator =
reinterpret_cast<std::byte*
>(_ioBuffer.data()) + group.startOffset;
253 for(
size_t i = 0; i < this->getNumberOfSamples(); ++i) {
254 for(
auto& channel : group.channels) {
255 RawType rawValue = converter.
toRaw(*channel.cookedIterator);
258 std::memcpy(rawIterator, &rawValue,
sizeof(RawType));
261 ++channel.cookedIterator;
262 rawIterator += channel.offsetToNext;