ChimeraTK-DeviceAccess 03.27.00
Loading...
Searching...
No Matches
LNMBackendBitAccessor.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
8
9#include <ChimeraTK/cppext/finally.hpp>
10
11namespace ChimeraTK {
12
13 /********************************************************************************************************************/
14
15 template<typename UserType>
16 class LNMBackendBitAccessor : public NDRegisterAccessor<UserType> {
17 public:
18 LNMBackendBitAccessor(const boost::shared_ptr<DeviceBackend>& dev, const RegisterPath& registerPathName,
19 size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
20 : NDRegisterAccessor<UserType>(registerPathName, flags), _registerPathName(registerPathName) {
21 // check for unknown flags
23 // check for illegal parameter combinations
24 if(flags.has(AccessMode::raw)) {
25 throw ChimeraTK::logic_error("LNMBackendBitAccessor: raw access not supported: " + registerPathName);
26 }
27 _dev = boost::dynamic_pointer_cast<LogicalNameMappingBackend>(dev);
28 // copy the register info and create the internal accessors, if needed
29 auto info = _dev->_catalogue_mutable.getBackendRegister(_registerPathName);
30
31 // check for incorrect usage of this accessor
32 if(info.targetType != LNMBackendRegisterInfo::TargetType::BIT) {
33 throw ChimeraTK::logic_error("LNMBackendBitAccessor used for wrong register type."); // LCOV_EXCL_LINE
34 // (impossible to test...)
35 }
36 if(wordOffsetInRegister != 0) {
37 throw ChimeraTK::logic_error("LNMBackendBitAccessors cannot have a word offset: " + registerPathName);
38 }
39 if(numberOfWords > 1) {
40 throw ChimeraTK::logic_error("LNMBackendBitAccessors must have size 1, but " + registerPathName + " has size " +
41 std::to_string(numberOfWords) + ".");
42 // The case that the target size actually is 1 if numberOfWords == 0 cannot be checked here.
43 // 0 is allowed. It is tested after the target has created the accessor with 0 as length parameter.
44 }
45
46 // get target device and accessor
47 std::string devName = info.deviceName;
48 boost::shared_ptr<DeviceBackend> targetDevice;
49 if(devName != "this") {
50 targetDevice = _dev->_devices[devName];
51 }
52 else {
53 targetDevice = dev;
54 }
55 {
56 std::unique_lock<std::mutex> l{_dev->sharedAccessorMap_mutex};
57 auto& map = boost::fusion::at_key<uint64_t>(_dev->sharedAccessorMap.table);
58 // we need an identifier of the device in the key, in case the logical name mapping accesses more than one
59 // device with same set of register names
60 RegisterPath path{info.registerName};
61 path.setAltSeparator(".");
62 LogicalNameMappingBackend::AccessorKey key(targetDevice.get(), path);
63 auto it = map.find(key);
64 // Obtain accessor if not found in the map or if weak pointer has expired
65 // Note: we must not use boost::weak_ptr::expired() here, because we have to check the status and obtain the
66 // accessor in one atomic step.
67 if(it == map.end() || (_accessor = map[key].accessor.lock()) == nullptr) {
68 _accessor = targetDevice->getRegisterAccessor<uint64_t>(key.second, numberOfWords, wordOffsetInRegister, {});
69 if(_accessor->getNumberOfSamples() != 1) {
71 "LNMBackendBitAccessors only work with target registers of size 1: " + registerPathName);
72 }
73 map[key].accessor = _accessor;
74 }
75 lock = std::unique_lock<std::recursive_mutex>(map[key].mutex, std::defer_lock);
76 }
77 // allocate and initialise the buffer
80 NDRegisterAccessor<UserType>::buffer_2D[0][0] = numericToUserType<UserType>(false);
81 // set the bit mask
82 _bitMask = size_t(1) << info.bit;
83 }
84
86 assert(lock.owns_lock());
87 _accessor->readTransfer();
88 }
89
91 assert(lock.owns_lock());
92 return _accessor->writeTransfer(_versionNumberTemp);
93 }
94
95 void doPreRead(TransferType type) override {
96 lock.lock();
97 _accessor->preRead(type);
98 }
99
100 void doPostRead(TransferType type, bool hasNewData) override {
101 auto unlock = cppext::finally([this] { this->lock.unlock(); });
102 _accessor->postRead(type, hasNewData);
103 if(!hasNewData) return;
104 if(_accessor->accessData(0) & _bitMask) {
105 NDRegisterAccessor<UserType>::buffer_2D[0][0] = numericToUserType<UserType>(true);
106 }
107 else {
108 NDRegisterAccessor<UserType>::buffer_2D[0][0] = numericToUserType<UserType>(false);
109 }
110 this->_versionNumber = {}; // VersionNumber needs to be decoupled from target accessor
111 this->_dataValidity = _accessor->dataValidity();
112 }
113
114 void doPreWrite(TransferType type, VersionNumber) override {
115 lock.lock();
116
117 if(!userTypeToNumeric<ChimeraTK::Boolean>(NDRegisterAccessor<UserType>::buffer_2D[0][0])) {
118 _accessor->accessData(0) &= ~(_bitMask);
119 }
120 else {
121 _accessor->accessData(0) |= _bitMask;
122 }
123
125 _accessor->setDataValidity(this->_dataValidity);
126 _accessor->preWrite(type, _versionNumberTemp);
127 }
128
130 auto unlock = cppext::finally([this] { this->lock.unlock(); });
131 _accessor->postWrite(type, _versionNumberTemp);
132 }
133
134 [[nodiscard]] bool mayReplaceOther(const boost::shared_ptr<TransferElement const>& other) const override {
135 auto rhsCasted = boost::dynamic_pointer_cast<const LNMBackendBitAccessor<UserType>>(other);
136 if(rhsCasted.get() == this) {
137 return false;
138 }
139 if(!rhsCasted) return false;
140 if(_registerPathName != rhsCasted->_registerPathName) return false;
141 if(_dev != rhsCasted->_dev) return false;
142 return true;
143 }
144
145 [[nodiscard]] bool isReadOnly() const override {
146 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
147 return _accessor->isReadOnly();
148 }
149
150 [[nodiscard]] bool isReadable() const override {
151 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
152 return _accessor->isReadable();
153 }
154
155 [[nodiscard]] bool isWriteable() const override {
156 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
157 return _accessor->isWriteable();
158 }
159
160 void setExceptionBackend(boost::shared_ptr<DeviceBackend> exceptionBackend) override {
161 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
162 this->_exceptionBackend = exceptionBackend;
163 _accessor->setExceptionBackend(exceptionBackend);
164 }
165
166 protected:
168 boost::shared_ptr<NDRegisterAccessor<uint64_t>> _accessor;
169
172 std::unique_lock<std::recursive_mutex> lock;
173
176
181
183 boost::shared_ptr<LogicalNameMappingBackend> _dev;
184
186 size_t _bitMask;
187
188 std::vector<boost::shared_ptr<TransferElement>> getHardwareAccessingElements() override {
189 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
190 return _accessor->getHardwareAccessingElements();
191 }
192
193 std::list<boost::shared_ptr<TransferElement>> getInternalElements() override {
194 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
195 auto result = _accessor->getInternalElements();
196 result.push_front(_accessor);
197 return result;
198 }
199
200 void replaceTransferElement(boost::shared_ptr<TransferElement> newElement) override {
201 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
202 auto casted = boost::dynamic_pointer_cast<NDRegisterAccessor<uint64_t>>(newElement);
203 if(casted && _accessor->mayReplaceOther(newElement)) {
204 _accessor = detail::createCopyDecorator<uint64_t>(casted);
205 }
206 else {
207 _accessor->replaceTransferElement(newElement);
208 }
209 _accessor->setExceptionBackend(this->_exceptionBackend);
210 }
211 };
212
214
215} // namespace ChimeraTK
#define DECLARE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(TemplateClass)
Set of AccessMode flags with additional functionality for an easier handling.
Definition AccessMode.h:48
bool has(AccessMode flag) const
Check if a certain flag is in the set.
Definition AccessMode.cc:20
void checkForUnknownFlags(const std::set< AccessMode > &knownFlags) const
Check of any flag which is not in the given set "knownFlags" is set.
Definition AccessMode.cc:32
VersionNumber _versionNumberTemp
temporary version number passed to the target accessor in write transfers The VersionNumber needs to ...
std::vector< boost::shared_ptr< TransferElement > > getHardwareAccessingElements() override
Obtain the underlying TransferElements with actual hardware access.
void doPostRead(TransferType type, bool hasNewData) override
Backend specific implementation of postRead().
std::list< boost::shared_ptr< TransferElement > > getInternalElements() override
Obtain the full list of TransferElements internally used by this TransferElement.
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) override
Backend specific implementation of preWrite().
void doReadTransferSynchronously() override
Implementation version of readTransfer() for synchronous reads.
void replaceTransferElement(boost::shared_ptr< TransferElement > newElement) override
Search for all underlying TransferElements which are considered identical (see sameRegister()) with t...
void doPostWrite(TransferType type, VersionNumber) override
Backend specific implementation of postWrite().
bool isWriteable() const override
Check if transfer element is writeable.
void setExceptionBackend(boost::shared_ptr< DeviceBackend > exceptionBackend) override
Set the backend to which the exception has to be reported.
bool isReadOnly() const override
Check if transfer element is read only, i.e.
bool isReadable() const override
Check if transfer element is readable.
size_t _bitMask
bit mask for the bit we want to access
boost::shared_ptr< LogicalNameMappingBackend > _dev
backend device
LNMBackendBitAccessor(const boost::shared_ptr< DeviceBackend > &dev, const RegisterPath &registerPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
RegisterPath _registerPathName
register and module name
void doPreRead(TransferType type) override
Backend specific implementation of preRead().
boost::shared_ptr< NDRegisterAccessor< uint64_t > > _accessor
pointer to underlying accessor
std::unique_lock< std::recursive_mutex > lock
Lock to be held during a transfer.
bool doWriteTransfer(ChimeraTK::VersionNumber) override
Implementation version of writeTransfer().
std::pair< DeviceBackend *, RegisterPath > AccessorKey
Map of target accessors which are potentially shared across our accessors.
N-dimensional register accessor.
Class to store a register path name.
void setAltSeparator(const std::string &altSeparator)
set alternative separator.
DataValidity _dataValidity
The validity of the data in the application buffer.
VersionNumber _versionNumber
The version number of the last successful transfer.
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.
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)