ChimeraTK-DeviceAccess 03.29.00
Loading...
Searching...
No Matches
DummyRegisterAccessor.h
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#pragma once
4
5#include "DummyBackend.h"
6
7namespace ChimeraTK {
8
12 namespace proxies {
13
14 /******************************************************************************************************************/
15
20 template<typename UserType>
22 public:
23 virtual ~RawConverterCapsule() = default;
24 virtual UserType toCooked(std::byte* raw) = 0;
25 virtual void toRaw(UserType cooked, std::byte* raw) = 0;
26 static std::shared_ptr<RawConverterCapsule<UserType>> makeCapsule(
27 const ChimeraTK::NumericAddressedRegisterInfo& info, size_t channelIndex);
28 };
29
30 /******************************************************************************************************************/
35 template<typename T>
37 public:
38 DummyRegisterElement(std::shared_ptr<RawConverterCapsule<T>>& rc, int nbytes, std::byte* buffer)
39 : _rc(rc), _nbytes(nbytes), _buffer(buffer) {}
40
43 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
44 operator T() const { return _rc->toCooked(_buffer); }
45
48 _rc->toRaw(rhs, _buffer);
49 return *this;
50 }
51
54 T cooked = _rc->toCooked(_buffer);
55 return operator=(cooked + 1);
56 }
57
60 T cooked = _rc->toCooked(_buffer);
61
62 return operator=(cooked - 1);
63 }
64
66 T operator++(int) {
67 T cooked = _rc->toCooked(_buffer);
68
69 operator=(cooked + 1);
70 return cooked;
71 }
72
74 T operator--(int) {
75 T cooked = _rc->toCooked(_buffer);
76
77 operator=(cooked - 1);
78 return cooked;
79 }
80
81 protected:
83 std::shared_ptr<RawConverterCapsule<T>>& _rc;
84
87
89 std::byte* _buffer;
90 };
91
92 /******************************************************************************************************************/
95 template<typename T>
97 public:
99 std::shared_ptr<proxies::RawConverterCapsule<T>>& rc, int nbytes, int pitch, int32_t* buffer)
100 : _rc(rc), _nbytes(nbytes), _pitch(pitch), _buffer(buffer) {}
101
103 DummyRegisterElement<T> operator[](unsigned int sample) {
104 // todo: Probably ranges are the correct tool in cpp22. In cpp17 this is not available yet. We turn off the
105 // warning not to use reinterpret_cast for the time being
106 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
107 auto* basePtr = reinterpret_cast<std::byte*>(_buffer);
108 auto* startPtr = basePtr + static_cast<size_t>(_pitch) * sample;
109 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
110 return DummyRegisterElement<T>(_rc, _nbytes, startPtr);
111 }
112
114 void operator=(const DummyRegisterSequence& rightHandSide) const = delete;
115
116 protected:
118 std::shared_ptr<proxies::RawConverterCapsule<T>>& _rc;
119
122
125
127 int32_t* _buffer;
128 };
129
130 /******************************************************************************************************************/
131
132 } // namespace proxies
133
134 /********************************************************************************************************************/
150 template<typename T>
152 public:
157 DummyRegisterAccessor(DummyBackend* dev, std::string const& module, std::string const& name)
158 : proxies::DummyRegisterElement<T>(_rc, 0, nullptr), _dev(dev), _path(module + "/" + name),
159 _registerInfo(_dev->_registerMap.getBackendRegister(_path)),
160 _rc(proxies::RawConverterCapsule<T>::makeCapsule(_registerInfo, 0)) {
161 // initialise the base DummyRegisterElement
164 }
165 // declare that we want the default copy constructor. Needed because we have a custom = operator
167
169 void operator=(const DummyRegisterAccessor& rightHandSide) const = delete;
170
172 proxies::DummyRegisterElement<T> operator[](unsigned int index) { return getProxy(index); }
173
175 unsigned int getNumberOfElements() { return _registerInfo.nElements; }
176
178 using proxies::DummyRegisterElement<T>::operator=;
179
181 [[nodiscard]] DummyBackend& getBackend() const { return *_dev; }
182
184 [[nodiscard]] const RegisterPath& getRegisterPath() const { return _path; }
185
187 void setWriteCallback(const std::function<void()>& writeCallback) {
188 assert(_registerInfo.elementPitchBits % 8 == 0);
190 {static_cast<uint8_t>(_registerInfo.bar), static_cast<uint32_t>(_registerInfo.address),
192 writeCallback);
193 }
194
196
200 std::unique_lock<std::mutex> getBufferLock() { return std::unique_lock<std::mutex>(_dev->mutex); }
201
202 protected:
205
208
211
213 std::shared_ptr<proxies::RawConverterCapsule<T>> _rc;
214
216 std::byte* getElement(unsigned int index) {
217 // elements are strided by elementPitchBits (which equals the element size for ordinary contiguous
218 // registers, i.e. elementPitchBits / 32 == 1); a channel slice of a 2D register has a larger pitch
219 // FIXME: this is currently limited to pitches divisible by 32 bits, because the dummy uses 32 bit words as an
220 // internal representation.
221 if((_registerInfo.address % sizeof(int32_t)) != 0 ||
222 (_registerInfo.elementPitchBits % (8 * sizeof(int32_t))) != 0) {
223 throw ChimeraTK::logic_error("DummyRegisterAccessor: elementPitchBits/address must be 32-bit aligned for "
224 "strided element access. Register: " +
225 _path);
226 }
227 const auto strideWords = _registerInfo.elementPitchBits / (8 * sizeof(int32_t));
228 auto* ptr =
229 &(_dev->_barContents[_registerInfo.bar][_registerInfo.address / sizeof(int32_t) + index * strideWords]);
230 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
231 return reinterpret_cast<std::byte*>(ptr);
232 }
233
236 return proxies::DummyRegisterElement<T>(_rc, sizeof(int32_t), getElement(index));
237 }
238 };
239
240 /********************************************************************************************************************/
251 template<typename T>
253 public:
260 DummyMultiplexedRegisterAccessor(DummyBackend* dev, std::string const& module, std::string const& name)
261 : _dev(dev), _path(module + "/" + name) {
262 _registerInfo = _dev->_registerMap.getBackendRegister(module + "." + name);
263
264 // create fixed point converters for each channel
265 size_t ci = 0;
266 for(auto& c : _registerInfo.channels) {
267 // create fixed point converter for sequence
269 // store offsets and number of bytes per word
270 assert(c.bitOffset % 8 == 0);
271 _offsets.push_back(_registerInfo.address + c.bitOffset / 8);
272 _nbytes.push_back((c.width - 1) / 8 + 1); // width/8 rounded up
273 ++ci;
274 }
275
276 if(_rc.empty()) {
277 throw ChimeraTK::logic_error("No sequences found for name \"" + name + "\".");
278 }
279
280 // cache some information
282 assert(_registerInfo.elementPitchBits % 8 == 0);
284 }
285
287 void operator=(const DummyMultiplexedRegisterAccessor& rightHandSide) const = delete;
288
289 // declare that we want the default copy constructor. Needed because we have a custom = operator
291
293 unsigned int getNumberOfElements() { return _nElements; }
294
296 unsigned int getNumberOfSequences() { return _rc.size(); }
297
304 // todo: Probably ranges are the correct tool in cpp22. In cpp17 this is not available yet. We turn off the
305 // warning not to use reinterpret_cast for the time being
306 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
307 auto* basePtr = reinterpret_cast<std::byte*>(_dev->_barContents[_registerInfo.bar].data());
308 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
309 auto* seq = reinterpret_cast<int32_t*>(basePtr + _offsets[sequence]);
310 return proxies::DummyRegisterSequence<T>(_rc[sequence], _nbytes[sequence], _pitch, seq);
311 }
312
314 [[nodiscard]] DummyBackend& getBackend() const { return *_dev; }
315
317 [[nodiscard]] const RegisterPath& getRegisterPath() const { return _path; }
318
320
321 protected:
324
327
330
332 std::vector<std::shared_ptr<proxies::RawConverterCapsule<T>>> _rc;
333
335 std::vector<uint32_t> _offsets;
336
338 std::vector<uint32_t> _nbytes;
339
341 int _pitch = {0};
342
344 unsigned int _nElements;
345 };
346
358 public:
361 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
362 operator int32_t&() { return *_buffer; }
363
365 boost::shared_ptr<DeviceBackend> const& backend, std::string const& module, std::string const& name)
366 : _backend(boost::dynamic_pointer_cast<DummyBackend>(backend)) {
367 assert(_backend);
368 _registerInfo = _backend->_registerMap.getBackendRegister(module + "." + name);
369 _buffer = &(_backend->_barContents[_registerInfo.bar][_registerInfo.address / sizeof(int32_t)]);
370 }
371
372 // declare that we want the default copy constructor. Needed because we have a custom = operator
373 // The default copy/move constructor is fine. It will copy the raw pointer to the buffer,
374 // together with the shared pointer which holds the corresponding backend with the
375 // memory. So it is a consistent copy because the shared pointer is pointing to the
376 // same backend instance.
378
380 void operator=(const DummyRegisterRawAccessor& rightHandSide) const = delete;
381
383 _buffer[0] = rhs;
384 return *this;
385 }
386
388 int32_t& operator[](unsigned int index) { return _buffer[index]; }
389
391 [[nodiscard]] unsigned int getNumberOfElements() const { return _registerInfo.nElements; }
392
396 std::unique_lock<std::mutex> getBufferLock() { return std::unique_lock<std::mutex>(_backend->mutex); }
397
398 protected:
400 boost::shared_ptr<DummyBackend> _backend;
401
404
406 int32_t* _buffer;
407 };
408
409 /********************************************************************************************************************/
410
411} // namespace ChimeraTK
The dummy device opens a mapping file instead of a device, and implements all registers defined in th...
void setWriteCallbackFunction(AddressRange addressRange, boost::function< void(void)> const &writeCallbackFunction)
std::map< uint64_t, std::vector< int32_t > > _barContents
Register accessor for accessing multiplexed 2D array registers internally of a DummyBackend implement...
unsigned int _nElements
number of elements per sequence
DummyMultiplexedRegisterAccessor(DummyBackend *dev, std::string const &module, std::string const &name)
Constructor should normally be called in the constructor of the DummyBackend implementation.
std::vector< std::shared_ptr< proxies::RawConverterCapsule< T > > > _rc
pointer to fixed point converter
DummyBackend * _dev
pointer to VirtualDevice
DummyBackend & getBackend() const
Return the backend.
unsigned int getNumberOfSequences()
return number of sequences
const RegisterPath & getRegisterPath() const
Return the register path.
std::vector< uint32_t > _nbytes
number of bytes per word for sequences
const NumericAddressedRegisterInfo & getRegisterInfo()
DummyMultiplexedRegisterAccessor(const DummyMultiplexedRegisterAccessor &)=default
NumericAddressedRegisterInfo _registerInfo
register map information
int _pitch
pitch in bytes (distance between samples of the same sequence)
void operator=(const DummyMultiplexedRegisterAccessor &rightHandSide) const =delete
remove assignment operator since it will be confusing
unsigned int getNumberOfElements()
return number of elements per sequence
proxies::DummyRegisterSequence< T > operator[](unsigned int sequence)
Get or set register content by [] operators.
std::vector< uint32_t > _offsets
offsets in bytes for sequences
Register accessor for accessing single word or 1D array registers internally of a DummyBackend implem...
DummyBackend * _dev
pointer to VirtualDevice
DummyRegisterAccessor(const DummyRegisterAccessor &)=default
DummyBackend & getBackend() const
Return the backend.
void operator=(const DummyRegisterAccessor &rightHandSide) const =delete
remove assignment operator since it will be confusing *‍/
std::byte * getElement(unsigned int index)
return element
const RegisterPath & getRegisterPath() const
Return the register path.
std::shared_ptr< proxies::RawConverterCapsule< T > > _rc
fixed point converter
unsigned int getNumberOfElements()
return number of elements
RegisterPath _path
path of the register
proxies::DummyRegisterElement< T > operator[](unsigned int index)
Get or set register content by [] operator.
proxies::DummyRegisterElement< T > getProxy(int index)
return a proxy object
DummyRegisterAccessor(DummyBackend *dev, std::string const &module, std::string const &name)
Constructor should normally be called in the constructor of the DummyBackend implementation.
const NumericAddressedRegisterInfo & getRegisterInfo()
void setWriteCallback(const std::function< void()> &writeCallback)
Set callback function which is called when the register is written to (through the normal Device inte...
NumericAddressedRegisterInfo _registerInfo
register map information
std::unique_lock< std::mutex > getBufferLock()
Get a lock to safely modify the buffer in a multi-treaded environment.
Accessor for raw 32 bit integer access to the underlying memory space.
void operator=(const DummyRegisterRawAccessor &rightHandSide) const =delete
remove assignment operator since it will be confusing
DummyRegisterRawAccessor(boost::shared_ptr< DeviceBackend > const &backend, std::string const &module, std::string const &name)
unsigned int getNumberOfElements() const
return number of elements
boost::shared_ptr< DummyBackend > _backend
pointer to dummy backend
int32_t & operator[](unsigned int index)
Get or set register content by [] operator.
DummyRegisterRawAccessor(const DummyRegisterRawAccessor &)=default
NumericAddressedRegisterInfo _registerInfo
register map information
std::unique_lock< std::mutex > getBufferLock()
Get a lock to safely modify the buffer.
int32_t * _buffer
raw buffer of this accessor
DummyRegisterRawAccessor & operator=(int32_t rhs)
NumericAddressedRegisterCatalogue & _registerMap
NumericAddressedRegisterInfo getBackendRegister(const RegisterPath &registerPathName) const override
Note: Override this function if backend has "hidden" registers which are not added to the map and hen...
uint32_t nElements
Number of elements in register.
std::vector< ChannelInfo > channels
Define per-channel information (bit interpretation etc.), 1D/scalars have exactly one entry.
uint64_t bar
Upper part of the address (name originally from PCIe, meaning now generalised)
uint32_t elementPitchBits
Distance in bits (!) between two elements (of the same channel)
uint64_t address
Lower part of the address relative to BAR, in bytes.
Class to store a register path name.
Exception thrown when a logic error has occured.
Definition Exception.h:51
Temporary proxy class for use in the DummyRegister and DummyMultiplexedRegister classes.
std::byte * _buffer
raw buffer of this element
DummyRegisterElement< T > & operator=(T rhs)
assignment operator
DummyRegisterElement< T > operator++()
pre-increment operator
DummyRegisterElement(std::shared_ptr< RawConverterCapsule< T > > &rc, int nbytes, std::byte *buffer)
std::shared_ptr< RawConverterCapsule< T > > & _rc
fixed point converter to be used for this element
DummyRegisterElement< T > operator--()
pre-decrement operator
Temporary proxy class for sequences, used in the DummyMultiplexedRegister class.
int _pitch
pitch in bytes (distance between samples of the same sequence)
DummyRegisterElement< T > operator[](unsigned int sample)
Get or set register content by [] operator.
int32_t * _buffer
reference to the raw buffer (first word of the sequence)
DummyRegisterSequence(std::shared_ptr< proxies::RawConverterCapsule< T > > &rc, int nbytes, int pitch, int32_t *buffer)
std::shared_ptr< proxies::RawConverterCapsule< T > > & _rc
fixed point converter to be used for this sequence
void operator=(const DummyRegisterSequence &rightHandSide) const =delete
remove assignment operator since it will be confusing *‍/
This abstract class encapsulates a RawConverter to erase the exact RawConverter type (with all its te...
virtual UserType toCooked(std::byte *raw)=0
virtual void toRaw(UserType cooked, std::byte *raw)=0
static std::shared_ptr< RawConverterCapsule< UserType > > makeCapsule(const ChimeraTK::NumericAddressedRegisterInfo &info, size_t channelIndex)
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...