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.");
27 struct ConverterInfo {
28 NumericAddressedRegisterInfo::Type dataType;
30 int32_t nFractionalBits;
35 auto operator<=>(
const ConverterInfo& rhs)
const =
default;
38 explicit ConverterInfo(
const NumericAddressedRegisterInfo::ChannelInfo& o)
39 : dataType(o.dataType), width(o.width), nFractionalBits(o.nFractionalBits), signedFlag(o.signedFlag),
45 std::map<ConverterInfo, size_t> groupInfoMap;
46 for(
size_t channelIndex = 0; channelIndex < _registerInfo.getNumberOfChannels(); ++channelIndex) {
47 const auto& info = _registerInfo.channels[channelIndex];
49 if(info.bitOffset % 8 != 0) {
50 throw ChimeraTK::logic_error(
"NumericAddressedBackendMuxedRegisterAccessor: elements must be byte aligned.");
54 const auto converterInfo = ConverterInfo(info);
55 auto it = groupInfoMap.find(converterInfo);
56 if(it == groupInfoMap.end()) {
58 auto newGroupId = groupInfoMap.size();
59 groupInfoMap[converterInfo] = newGroupId;
61 ChannelGroup newGroup;
62 newGroup.channels.emplace_back(
63 channelIndex, 0,
typename std::vector<UserType>::iterator());
64 newGroup.converterLoopHelper = RawConverter::ConverterLoopHelper::makeConverterLoopHelper<UserType>(
65 _registerInfo, channelIndex, newGroupId, *
this);
66 newGroup.startOffset = info.bitOffset / 8;
69 _channelGroups.emplace_back(std::move(newGroup));
73 _channelGroups[it->second].channels.emplace_back(
74 channelIndex, 0,
typename std::vector<UserType>::iterator());
77 assert(_channelGroups.size() == groupInfoMap.size());
81 for(
auto& group : _channelGroups) {
82 assert(group.channels.size() >= 1);
84 for(
size_t i = 0; i < group.channels.size() - 1; ++i) {
85 auto bitOffset = _registerInfo.channels[group.channels[i + 1].index].bitOffset -
86 _registerInfo.channels[group.channels[i].index].bitOffset;
87 assert(bitOffset % 8 == 0);
88 group.channels[i].offsetToNext = bitOffset / 8;
91 auto lastBitOffset = _registerInfo.elementPitchBits -
92 _registerInfo.channels[group.channels.back().index].bitOffset +
93 _registerInfo.channels[group.channels.front().index].bitOffset;
94 assert(lastBitOffset % 8 == 0);
95 group.channels.back().offsetToNext = lastBitOffset / 8;
99 if(numberOfElements == 0) {
100 numberOfElements = _registerInfo.nElements;
104 if(numberOfElements + elementsOffset > _registerInfo.nElements) {
107 ") of the register '" + registerPathName +
"'!");
109 throw ChimeraTK::logic_error(
"Requested number of elements exceeds the size of the register! Requested end: " +
115 _registerInfo.nElements = numberOfElements;
116 assert(_registerInfo.elementPitchBits % 8 == 0);
117 _registerInfo.address += elementsOffset * _registerInfo.elementPitchBits / 8;
121 for(
auto& buf : NDRegisterAccessor<UserType>::buffer_2D) {
122 buf.resize(_registerInfo.nElements);
127 static_cast<size_t>(_registerInfo.elementPitchBits) / 8 * _registerInfo.nElements /
sizeof(int32_t) + 1);
168 static_assert(std::is_same_v<UserType, UserType2>);
169 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
170 auto& group = _channelGroups[channelGroupId];
173 for(
auto& channel : group.channels) {
174 channel.cookedIterator = buffer_2D[channel.index].begin();
180 auto* rawIterator =
reinterpret_cast<std::byte*
>(_ioBuffer.data()) + group.startOffset;
182 for(
size_t i = 0; i < this->getNumberOfSamples(); ++i) {
183 for(
auto& channel : group.channels) {
186 std::memcpy(&rawValue, rawIterator,
sizeof(RawType));
189 *channel.cookedIterator = converter.
toCooked(rawValue);
192 ++channel.cookedIterator;
193 rawIterator += channel.offsetToNext;
232 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
233 auto& group = _channelGroups[channelGroupId];
236 for(
auto& channel : group.channels) {
237 channel.cookedIterator = buffer_2D[channel.index].begin();
243 auto* rawIterator =
reinterpret_cast<std::byte*
>(_ioBuffer.data()) + group.startOffset;
245 for(
size_t i = 0; i < this->getNumberOfSamples(); ++i) {
246 for(
auto& channel : group.channels) {
247 RawType rawValue = converter.
toRaw(*channel.cookedIterator);
250 std::memcpy(rawIterator, &rawValue,
sizeof(RawType));
253 ++channel.cookedIterator;
254 rawIterator += channel.offsetToNext;