ChimeraTK-DeviceAccess 03.25.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
6#include "Device.h"
11
12#include <ChimeraTK/cppext/finally.hpp>
13
14#include <algorithm>
15
16namespace ChimeraTK {
17
18 /********************************************************************************************************************/
19
20 template<typename UserType>
21 class LNMBackendBitAccessor : public NDRegisterAccessor<UserType> {
22 public:
23 LNMBackendBitAccessor(const boost::shared_ptr<DeviceBackend>& dev, const RegisterPath& registerPathName,
24 size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
25 : NDRegisterAccessor<UserType>(registerPathName, flags), _registerPathName(registerPathName),
26 _fixedPointConverter(registerPathName, 32, 0, true) {
27 // check for unknown flags
29 // check for illegal parameter combinations
30 if(flags.has(AccessMode::raw)) {
31 throw ChimeraTK::logic_error("LNMBackendBitAccessor: raw access not supported: " + registerPathName);
32 }
33 _dev = boost::dynamic_pointer_cast<LogicalNameMappingBackend>(dev);
34 // copy the register info and create the internal accessors, if needed
35 auto info = _dev->_catalogue_mutable.getBackendRegister(_registerPathName);
36
37 // check for incorrect usage of this accessor
38 if(info.targetType != LNMBackendRegisterInfo::TargetType::BIT) {
39 throw ChimeraTK::logic_error("LNMBackendBitAccessor used for wrong register type."); // LCOV_EXCL_LINE
40 // (impossible to test...)
41 }
42 if(wordOffsetInRegister != 0) {
43 throw ChimeraTK::logic_error("LNMBackendBitAccessors cannot have a word offset: " + registerPathName);
44 }
45 if(numberOfWords > 1) {
46 throw ChimeraTK::logic_error("LNMBackendBitAccessors must have size 1, but " + registerPathName + " has size " +
47 std::to_string(numberOfWords) + ".");
48 // The case that the target size actually is 1 if numberOfWords == 0 cannot be checked here.
49 // 0 is allowed. It is tested after the target has created the accessor with 0 as length parameter.
50 }
51
52 // get target device and accessor
53 std::string devName = info.deviceName;
54 boost::shared_ptr<DeviceBackend> targetDevice;
55 if(devName != "this") {
56 targetDevice = _dev->_devices[devName];
57 }
58 else {
59 targetDevice = dev;
60 }
61 {
62 std::unique_lock<std::mutex> l{_dev->sharedAccessorMap_mutex};
63 auto& map = boost::fusion::at_key<uint64_t>(_dev->sharedAccessorMap.table);
64 // we need an identifier of the device in the key, in case the logical name mapping accesses more than one
65 // device with same set of register names
66 RegisterPath path{info.registerName};
67 path.setAltSeparator(".");
68 LogicalNameMappingBackend::AccessorKey key(targetDevice.get(), path);
69 auto it = map.find(key);
70 // Obtain accessor if not found in the map or if weak pointer has expired
71 // Note: we must not use boost::weak_ptr::expired() here, because we have to check the status and obtain the
72 // accessor in one atomic step.
73 if(it == map.end() || (_accessor = map[key].accessor.lock()) == nullptr) {
74 _accessor = targetDevice->getRegisterAccessor<uint64_t>(key.second, numberOfWords, wordOffsetInRegister, {});
75 if(_accessor->getNumberOfSamples() != 1) {
77 "LNMBackendBitAccessors only work with target registers of size 1: " + registerPathName);
78 }
79 map[key].accessor = _accessor;
80 }
81 lock = std::unique_lock<std::recursive_mutex>(map[key].mutex, std::defer_lock);
82 }
83 // allocate and initialise the buffer
86 NDRegisterAccessor<UserType>::buffer_2D[0][0] = numericToUserType<UserType>(false);
87 // set the bit mask
88 _bitMask = size_t(1) << info.bit;
89 }
90
92 assert(lock.owns_lock());
93 _accessor->readTransfer();
94 }
95
97 assert(lock.owns_lock());
98 return _accessor->writeTransfer(_versionNumberTemp);
99 }
100
101 void doPreRead(TransferType type) override {
102 lock.lock();
103 _accessor->preRead(type);
104 }
105
106 void doPostRead(TransferType type, bool hasNewData) override {
107 auto unlock = cppext::finally([this] { this->lock.unlock(); });
108 _accessor->postRead(type, hasNewData);
109 if(!hasNewData) return;
110 if(_accessor->accessData(0) & _bitMask) {
111 NDRegisterAccessor<UserType>::buffer_2D[0][0] = numericToUserType<UserType>(true);
112 }
113 else {
114 NDRegisterAccessor<UserType>::buffer_2D[0][0] = numericToUserType<UserType>(false);
115 }
116 this->_versionNumber = {}; // VersionNumber needs to be decoupled from target accessor
117 this->_dataValidity = _accessor->dataValidity();
118 }
119
120 void doPreWrite(TransferType type, VersionNumber) override {
121 lock.lock();
122
124 _accessor->accessData(0) &= ~(_bitMask);
125 }
126 else {
127 _accessor->accessData(0) |= _bitMask;
128 }
129
131 _accessor->setDataValidity(this->_dataValidity);
132 _accessor->preWrite(type, _versionNumberTemp);
133 }
134
136 auto unlock = cppext::finally([this] { this->lock.unlock(); });
137 _accessor->postWrite(type, _versionNumberTemp);
138 }
139
140 [[nodiscard]] bool mayReplaceOther(const boost::shared_ptr<TransferElement const>& other) const override {
141 auto rhsCasted = boost::dynamic_pointer_cast<const LNMBackendBitAccessor<UserType>>(other);
142 if(rhsCasted.get() == this) {
143 return false;
144 }
145 if(!rhsCasted) return false;
146 if(_registerPathName != rhsCasted->_registerPathName) return false;
147 if(_dev != rhsCasted->_dev) return false;
148 return true;
149 }
150
151 [[nodiscard]] bool isReadOnly() const override {
152 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
153 return _accessor->isReadOnly();
154 }
155
156 [[nodiscard]] bool isReadable() const override {
157 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
158 return _accessor->isReadable();
159 }
160
161 [[nodiscard]] bool isWriteable() const override {
162 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
163 return _accessor->isWriteable();
164 }
165
166 void setExceptionBackend(boost::shared_ptr<DeviceBackend> exceptionBackend) override {
167 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
168 this->_exceptionBackend = exceptionBackend;
169 _accessor->setExceptionBackend(exceptionBackend);
170 }
171
172 protected:
174 boost::shared_ptr<NDRegisterAccessor<uint64_t>> _accessor;
175
178 std::unique_lock<std::recursive_mutex> lock;
179
182
187
189 boost::shared_ptr<LogicalNameMappingBackend> _dev;
190
195
197 size_t _bitMask;
198
199 std::vector<boost::shared_ptr<TransferElement>> getHardwareAccessingElements() override {
200 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
201 return _accessor->getHardwareAccessingElements();
202 }
203
204 std::list<boost::shared_ptr<TransferElement>> getInternalElements() override {
205 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
206 auto result = _accessor->getInternalElements();
207 result.push_front(_accessor);
208 return result;
209 }
210
211 void replaceTransferElement(boost::shared_ptr<TransferElement> newElement) override {
212 std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
213 auto casted = boost::dynamic_pointer_cast<NDRegisterAccessor<uint64_t>>(newElement);
214 if(casted && _accessor->mayReplaceOther(newElement)) {
215 _accessor = detail::createCopyDecorator<uint64_t>(casted);
216 }
217 else {
218 _accessor->replaceTransferElement(newElement);
219 }
220 _accessor->setExceptionBackend(this->_exceptionBackend);
221 }
222 };
223
225
226} // 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
The fixed point converter provides conversion functions between a user type and up to 32 bit fixed po...
RawType toRaw(UserType cookedValue) const
Conversion function from type T to fixed point.
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.
FixedPointConverter< DEPRECATED_FIXEDPOINT_DEFAULT > _fixedPointConverter
fixed point converter to handle type conversions from our "raw" type int to the requested user type.
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)