ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
NumericAddressedLowLevelTransferElement.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
6#include "TransferElement.h"
7
8namespace ChimeraTK {
9
10 template<typename UserType, typename DataConverterType, bool isRaw>
11 class NumericAddressedBackendRegisterAccessor;
12
13 class NumericAddressedBackendASCIIAccessor;
14
15 namespace detail {
16 template<typename UserType, typename DataConverterType, bool isRaw>
17 struct NumericAddressedPrePostActionsImplementor;
18 } // namespace detail
19
20 /********************************************************************************************************************/
31 public:
33 const boost::shared_ptr<NumericAddressedBackend>& dev, size_t bar, size_t startAddress, size_t numberOfBytes)
34 : TransferElement("", {AccessMode::raw}), _dev(dev), _bar(bar),
35 _unalignedAccess(_dev->_unalignedAccess, std::defer_lock) {
36 if(!dev->barIndexValid(bar)) {
37 std::stringstream errorMessage;
38 errorMessage << "Invalid bar number: " << bar << std::endl;
39 throw ChimeraTK::logic_error(errorMessage.str());
40 }
41 setAddress(startAddress, numberOfBytes);
42 }
43
45
47 // There is nothing we can do about reinterpet_casting with the C-style interface
48 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
49 _dev->read(_bar, _startAddress, reinterpret_cast<int32_t*>(rawDataBuffer.data()), _numberOfBytes);
50 }
51
53 // There is nothing we can do about reinterpet_casting with the C-style interface
54 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
55 _dev->write(_bar, _startAddress, reinterpret_cast<int32_t*>(rawDataBuffer.data()), _numberOfBytes);
56 return false;
57 }
58
59 void doPostRead(TransferType, bool hasNewData) override {
60 if(hasNewData) {
61 // it is acceptable to create a new version number only in doPostRead because the LowLevelTransferElement never
62 // has wait_for_new_data.
63 _versionNumber = {};
64 }
65 }
66
68 if(_isUnaligned) {
69 _unalignedAccess.lock();
70 // There is nothing we can do about reinterpet_casting with the C-style interface
71 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
72 _dev->read(_bar, _startAddress, reinterpret_cast<int32_t*>(rawDataBuffer.data()), _numberOfBytes);
73 }
74 }
75
77 if(_unalignedAccess.owns_lock()) {
78 _unalignedAccess.unlock();
79 }
80 }
81
87 bool isMergeable(const boost::shared_ptr<TransferElement const>& other) const {
88 if(!_dev->canMergeRequests()) return false;
89
90 // accessor type, device and bar must be the same
91 auto rhsCasted = boost::dynamic_pointer_cast<const NumericAddressedLowLevelTransferElement>(other);
92 if(!rhsCasted) return false;
93 if(_dev != rhsCasted->_dev) return false;
94 if(_bar != rhsCasted->_bar) return false;
95
96 // only allow adjacent and overlapping address areas to be merged
97 if(_startAddress + _numberOfBytes < rhsCasted->_startAddress) return false;
98 if(_startAddress > rhsCasted->_startAddress + rhsCasted->_numberOfBytes) return false;
99 return true;
100 }
101
102 bool mayReplaceOther(const boost::shared_ptr<TransferElement const>&) const override {
103 return false; // never used, since isMergeable() is used instead
104 }
105
106 const std::type_info& getValueType() const override {
107 // This implementation is for int32_t only (as all numerically addressed
108 // backends under the hood.
109 return typeid(int32_t);
110 }
111
112 bool isReadOnly() const override { return false; }
113
114 bool isReadable() const override { return true; }
115
116 bool isWriteable() const override { return true; }
117
125 uint8_t* begin(size_t addressInBar) { return rawDataBuffer.data() + (addressInBar - _startAddress); }
126
129 void changeAddress(size_t startAddress, size_t numberOfWords) {
130 setAddress(startAddress, numberOfWords);
131 isShared = true;
132 }
133
134 boost::shared_ptr<TransferElement> makeCopyRegisterDecorator() override { // LCOV_EXCL_LINE
135 throw ChimeraTK::logic_error("NumericAddressedLowLevelTransferElement::makeCopyRegisterDecorator() "
136 "is not implemented"); // LCOV_EXCL_LINE
137 } // LCOV_EXCL_LINE
138
139 protected:
142 void setAddress(size_t startAddress, size_t numberOfBytes) {
143 // change address
144 _startAddress = startAddress;
145 _numberOfBytes = numberOfBytes;
146
147 // make sure access is properly aligned
148 _isUnaligned = false;
149 auto alignment = _dev->minimumTransferAlignment(_bar);
150 auto start_padding = _startAddress % alignment;
151 assert(_startAddress >= start_padding);
152 if(start_padding > 0) _isUnaligned = true;
153 _startAddress -= start_padding;
154 _numberOfBytes += start_padding;
155 auto end_padding = alignment - _numberOfBytes % alignment;
156 if(end_padding != alignment) {
157 _isUnaligned = true;
158 _numberOfBytes += end_padding;
159 }
160
161 // Allocated the buffer
163
164 // update the name
166 }
167
169 boost::shared_ptr<NumericAddressedBackend> _dev;
170
172 uint64_t _bar;
173
175 uint64_t _startAddress{};
176
179
182 bool isShared{false};
183
185 bool _isUnaligned{false};
186
188 std::unique_lock<std::mutex> _unalignedAccess;
189
191 std::vector<uint8_t> rawDataBuffer;
192
193 std::vector<boost::shared_ptr<TransferElement>> getHardwareAccessingElements() override {
194 return {boost::enable_shared_from_this<TransferElement>::shared_from_this()};
195 }
196
197 std::list<boost::shared_ptr<TransferElement>> getInternalElements() override { return {}; }
198
199 void replaceTransferElement(boost::shared_ptr<TransferElement> /*newElement*/) override {} // LCOV_EXCL_LINE
200
201 template<typename UserType, typename DataConverterType, bool isRaw>
203
204 template<typename UserType, typename DataConverterType, bool isRaw>
206
208 };
209
210} // namespace ChimeraTK
Implementation of the NDRegisterAccessor for NumericAddressedBackends for ASCII data.
Implementation of the NDRegisterAccessor for NumericAddressedBackends for scalar and 1D registers.
Implementation of the NDRegisterAccessor for NumericAddressedBackends, responsible for the underlying...
void doPostRead(TransferType, bool hasNewData) override
Backend specific implementation of postRead().
boost::shared_ptr< TransferElement > makeCopyRegisterDecorator() override
Create a CopyRegisterDecorator of the right type decorating this TransferElement.
bool isReadOnly() const override
Check if transfer element is read only, i.e.
void doReadTransferSynchronously() override
Implementation version of readTransfer() for synchronous reads.
void replaceTransferElement(boost::shared_ptr< TransferElement >) override
Search for all underlying TransferElements which are considered identical (see sameRegister()) with t...
const std::type_info & getValueType() const override
Returns the std::type_info for the value type of this transfer element.
bool doWriteTransfer(ChimeraTK::VersionNumber) override
Implementation version of writeTransfer().
std::vector< boost::shared_ptr< TransferElement > > getHardwareAccessingElements() override
Obtain the underlying TransferElements with actual hardware access.
std::unique_lock< std::mutex > _unalignedAccess
Lock to protect unaligned access (with mutex from backend)
void changeAddress(size_t startAddress, size_t numberOfWords)
Change the start address (inside the bar given in the constructor) and number of words of this access...
bool isWriteable() const override
Check if transfer element is writeable.
bool isShared
flag if changeAddress() has been called, which is this low-level transfer element is shared between m...
NumericAddressedLowLevelTransferElement(const boost::shared_ptr< NumericAddressedBackend > &dev, size_t bar, size_t startAddress, size_t numberOfBytes)
bool isReadable() const override
Check if transfer element is readable.
uint8_t * begin(size_t addressInBar)
Return pointer to the begin of the raw buffer matching the given address.
void doPostWrite(TransferType, VersionNumber) override
Backend specific implementation of postWrite().
void doPreWrite(TransferType, VersionNumber) override
Backend specific implementation of preWrite().
std::list< boost::shared_ptr< TransferElement > > getInternalElements() override
Obtain the full list of TransferElements internally used by this TransferElement.
boost::shared_ptr< NumericAddressedBackend > _dev
the backend to use for the actual hardware access
void setAddress(size_t startAddress, size_t numberOfBytes)
Set the start address (inside the bar given in the constructor) and number of words of this accessor.
bool mayReplaceOther(const boost::shared_ptr< TransferElement const > &) const override
Check whether the TransferElement can be used in places where the TransferElement "other" is currentl...
bool isMergeable(const boost::shared_ptr< TransferElement const > &other) const
Check if the address areas are adjacent and/or overlapping.
Base class for register accessors which can be part of a TransferGroup.
std::string _name
Identifier uniquely identifying the TransferElement.
VersionNumber _versionNumber
The version number of the last successful transfer.
Class for generating and holding version numbers without exposing a numeric representation.
Exception thrown when a logic error has occured.
Definition Exception.h:51
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
TransferType
Used to indicate the applicable operation on a Transferelement.
std::string to_string(const std::string &v)