ChimeraTK-DeviceAccess  03.18.00
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"
7 #include "FixedPointConverter.h"
9 #include "NDRegisterAccessor.h"
10 #include "TwoDRegisterAccessor.h"
11 
12 #include <ChimeraTK/cppext/finally.hpp>
13 
14 #include <algorithm>
15 
16 namespace 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!");
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.");
44  }
45  if(numberOfWords > 1) {
46  throw ChimeraTK::logic_error("LNMBackendBitAccessors must have size 1.");
47  // The case that the target size actually is 1 if numberOfWords == 0 cannot be checked here.
48  // 0 is allowed. It is tested after the target has created the accessor with 0 as length parameter.
49  }
50 
51  // get target device and accessor
52  std::string devName = info.deviceName;
53  boost::shared_ptr<DeviceBackend> targetDevice;
54  if(devName != "this") {
55  targetDevice = _dev->_devices[devName];
56  }
57  else {
58  targetDevice = dev;
59  }
60  {
61  std::unique_lock<std::mutex> l{_dev->sharedAccessorMap_mutex};
62  auto& map = boost::fusion::at_key<uint64_t>(_dev->sharedAccessorMap.table);
63  // we need an identifier of the device in the key, in case the logical name mapping accesses more than one
64  // device with same set of register names
65  RegisterPath path{info.registerName};
66  path.setAltSeparator(".");
67  LogicalNameMappingBackend::AccessorKey key(targetDevice.get(), path);
68  auto it = map.find(key);
69  // Obtain accessor if not found in the map or if weak pointer has expired
70  // Note: we must not use boost::weak_ptr::expired() here, because we have to check the status and obtain the
71  // accessor in one atomic step.
72  if(it == map.end() || (_accessor = map[key].accessor.lock()) == nullptr) {
73  _accessor = targetDevice->getRegisterAccessor<uint64_t>(key.second, numberOfWords, wordOffsetInRegister, {});
74  if(_accessor->getNumberOfSamples() != 1) {
75  throw ChimeraTK::logic_error("LNMBackendBitAccessors only work with registers of size 1");
76  }
77  map[key].accessor = _accessor;
78  }
79  lock = std::unique_lock<std::recursive_mutex>(map[key].mutex, std::defer_lock);
80  }
81  // allocate and initialise the buffer
84  NDRegisterAccessor<UserType>::buffer_2D[0][0] = numericToUserType<UserType>(false);
85  // set the bit mask
86  _bitMask = size_t(1) << info.bit;
87  }
88 
89  void doReadTransferSynchronously() override {
90  assert(lock.owns_lock());
91  _accessor->readTransfer();
92  }
93 
95  assert(lock.owns_lock());
96  return _accessor->writeTransfer(_versionNumberTemp);
97  }
98 
99  void doPreRead(TransferType type) override {
100  lock.lock();
101  _accessor->preRead(type);
102  }
103 
104  void doPostRead(TransferType type, bool hasNewData) override {
105  auto unlock = cppext::finally([this] { this->lock.unlock(); });
106  _accessor->postRead(type, hasNewData);
107  if(!hasNewData) return;
108  if(_accessor->accessData(0) & _bitMask) {
109  NDRegisterAccessor<UserType>::buffer_2D[0][0] = numericToUserType<UserType>(true);
110  }
111  else {
112  NDRegisterAccessor<UserType>::buffer_2D[0][0] = numericToUserType<UserType>(false);
113  }
114  this->_versionNumber = {}; // VersionNumber needs to be decoupled from target accessor
115  this->_dataValidity = _accessor->dataValidity();
116  }
117 
118  void doPreWrite(TransferType type, VersionNumber) override {
119  lock.lock();
120 
122  _accessor->accessData(0) &= ~(_bitMask);
123  }
124  else {
125  _accessor->accessData(0) |= _bitMask;
126  }
127 
128  _versionNumberTemp = {};
129  _accessor->setDataValidity(this->_dataValidity);
130  _accessor->preWrite(type, _versionNumberTemp);
131  }
132 
133  void doPostWrite(TransferType type, VersionNumber) override {
134  auto unlock = cppext::finally([this] { this->lock.unlock(); });
135  _accessor->postWrite(type, _versionNumberTemp);
136  }
137 
138  [[nodiscard]] bool mayReplaceOther(const boost::shared_ptr<TransferElement const>& other) const override {
139  auto rhsCasted = boost::dynamic_pointer_cast<const LNMBackendBitAccessor<UserType>>(other);
140  if(!rhsCasted) return false;
141  if(_registerPathName != rhsCasted->_registerPathName) return false;
142  if(_dev != rhsCasted->_dev) return false;
143  return true;
144  }
145 
146  [[nodiscard]] bool isReadOnly() const override {
147  std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
148  return _accessor->isReadOnly();
149  }
150 
151  [[nodiscard]] bool isReadable() const override {
152  std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
153  return _accessor->isReadable();
154  }
155 
156  [[nodiscard]] bool isWriteable() const override {
157  std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
158  return _accessor->isWriteable();
159  }
160 
161  void setExceptionBackend(boost::shared_ptr<DeviceBackend> exceptionBackend) override {
162  std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
163  this->_exceptionBackend = exceptionBackend;
164  _accessor->setExceptionBackend(exceptionBackend);
165  }
166 
167  protected:
169  boost::shared_ptr<NDRegisterAccessor<uint64_t>> _accessor;
170 
173  std::unique_lock<std::recursive_mutex> lock;
174 
177 
182 
184  boost::shared_ptr<LogicalNameMappingBackend> _dev;
185 
190 
192  size_t _bitMask;
193 
194  std::vector<boost::shared_ptr<TransferElement>> getHardwareAccessingElements() override {
195  std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
196  return _accessor->getHardwareAccessingElements();
197  }
198 
199  std::list<boost::shared_ptr<TransferElement>> getInternalElements() override {
200  std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
201  auto result = _accessor->getInternalElements();
202  result.push_front(_accessor);
203  return result;
204  }
205 
206  void replaceTransferElement(boost::shared_ptr<TransferElement> newElement) override {
207  std::lock_guard<std::recursive_mutex> guard(*lock.mutex());
208  auto casted = boost::dynamic_pointer_cast<NDRegisterAccessor<uint64_t>>(newElement);
209  if(casted && _accessor->mayReplaceOther(newElement)) {
210  _accessor = detail::createCopyDecorator<uint64_t>(casted);
211  }
212  else {
213  _accessor->replaceTransferElement(newElement);
214  }
215  _accessor->setExceptionBackend(this->_exceptionBackend);
216  }
217  };
218 
219  DECLARE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(LNMBackendBitAccessor);
220 
221 } // namespace ChimeraTK
ChimeraTK::LNMBackendBitAccessor::LNMBackendBitAccessor
LNMBackendBitAccessor(const boost::shared_ptr< DeviceBackend > &dev, const RegisterPath &registerPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
Definition: LNMBackendBitAccessor.h:23
ChimeraTK::LogicalNameMappingBackend::AccessorKey
std::pair< DeviceBackend *, RegisterPath > AccessorKey
Map of target accessors which are potentially shared across our accessors.
Definition: LogicalNameMappingBackend.h:82
ChimeraTK::LNMBackendBitAccessor::setExceptionBackend
void setExceptionBackend(boost::shared_ptr< DeviceBackend > exceptionBackend) override
Definition: LNMBackendBitAccessor.h:161
ChimeraTK::AccessMode::raw
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
ChimeraTK::LNMBackendBitAccessor::isWriteable
bool isWriteable() const override
Definition: LNMBackendBitAccessor.h:156
FixedPointConverter.h
ChimeraTK::LNMBackendBitAccessor::_versionNumberTemp
VersionNumber _versionNumberTemp
temporary version number passed to the target accessor in write transfers The VersionNumber needs to ...
Definition: LNMBackendBitAccessor.h:181
TwoDRegisterAccessor.h
ChimeraTK::LNMBackendBitAccessor::_dev
boost::shared_ptr< LogicalNameMappingBackend > _dev
backend device
Definition: LNMBackendBitAccessor.h:184
ChimeraTK::LNMBackendBitAccessor::_fixedPointConverter
FixedPointConverter _fixedPointConverter
fixed point converter to handle type conversions from our "raw" type int to the requested user type.
Definition: LNMBackendBitAccessor.h:189
LogicalNameMappingBackend.h
ChimeraTK::LNMBackendBitAccessor::getInternalElements
std::list< boost::shared_ptr< TransferElement > > getInternalElements() override
Definition: LNMBackendBitAccessor.h:199
ChimeraTK::LNMBackendBitAccessor::doPreWrite
void doPreWrite(TransferType type, VersionNumber) override
Definition: LNMBackendBitAccessor.h:118
ChimeraTK::RegisterPath::setAltSeparator
void setAltSeparator(const std::string &altSeparator)
set alternative separator.
Definition: RegisterPath.h:37
ChimeraTK::LNMBackendBitAccessor::doPostWrite
void doPostWrite(TransferType type, VersionNumber) override
Definition: LNMBackendBitAccessor.h:133
ChimeraTK::AccessModeFlags::has
bool has(AccessMode flag) const
Check if a certain flag is in the set.
Definition: AccessMode.cc:20
NDRegisterAccessor.h
ChimeraTK::LNMBackendBitAccessor::doReadTransferSynchronously
void doReadTransferSynchronously() override
Definition: LNMBackendBitAccessor.h:89
ChimeraTK::LNMBackendBitAccessor::doPreRead
void doPreRead(TransferType type) override
Definition: LNMBackendBitAccessor.h:99
Device.h
ChimeraTK::TransferType
TransferType
Used to indicate the applicable operation on a Transferelement.
Definition: TransferElement.h:51
ChimeraTK::LNMBackendBitAccessor::_bitMask
size_t _bitMask
bit mask for the bit we want to access
Definition: LNMBackendBitAccessor.h:192
ChimeraTK::AccessModeFlags::checkForUnknownFlags
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
ChimeraTK::LNMBackendBitAccessor::getHardwareAccessingElements
std::vector< boost::shared_ptr< TransferElement > > getHardwareAccessingElements() override
Definition: LNMBackendBitAccessor.h:194
ChimeraTK::LNMBackendBitAccessor::doPostRead
void doPostRead(TransferType type, bool hasNewData) override
Definition: LNMBackendBitAccessor.h:104
ChimeraTK::LNMBackendBitAccessor::isReadable
bool isReadable() const override
Definition: LNMBackendBitAccessor.h:151
CopyRegisterDecorator.h
ChimeraTK::LNMBackendBitAccessor::_accessor
boost::shared_ptr< NDRegisterAccessor< uint64_t > > _accessor
pointer to underlying accessor
Definition: LNMBackendBitAccessor.h:169
ChimeraTK::RegisterPath
Class to store a register path name.
Definition: RegisterPath.h:16
ChimeraTK::VersionNumber
Class for generating and holding version numbers without exposing a numeric representation.
Definition: VersionNumber.h:23
ChimeraTK::FixedPointConverter
The fixed point converter provides conversion functions between a user type and up to 32 bit fixed po...
Definition: FixedPointConverter.h:28
ChimeraTK::AccessModeFlags
Set of AccessMode flags with additional functionality for an easier handling.
Definition: AccessMode.h:48
ChimeraTK::FixedPointConverter::toRaw
uint32_t toRaw(UserType cookedValue) const
Conversion function from type T to fixed point.
Definition: FixedPointConverter.h:336
ChimeraTK::LNMBackendBitAccessor::doWriteTransfer
bool doWriteTransfer(ChimeraTK::VersionNumber) override
Definition: LNMBackendBitAccessor.h:94
ChimeraTK::LNMBackendBitAccessor::mayReplaceOther
bool mayReplaceOther(const boost::shared_ptr< TransferElement const > &other) const override
Definition: LNMBackendBitAccessor.h:138
ChimeraTK::DECLARE_TEMPLATE_FOR_CHIMERATK_USER_TYPES
DECLARE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(DummyInterruptTriggerAccessor)
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::LNMBackendBitAccessor::isReadOnly
bool isReadOnly() const override
Definition: LNMBackendBitAccessor.h:146
ChimeraTK::LNMBackendBitAccessor::replaceTransferElement
void replaceTransferElement(boost::shared_ptr< TransferElement > newElement) override
Definition: LNMBackendBitAccessor.h:206
ChimeraTK::LNMBackendBitAccessor::lock
std::unique_lock< std::recursive_mutex > lock
Lock to be held during a transfer.
Definition: LNMBackendBitAccessor.h:173
ChimeraTK::NDRegisterAccessor
N-dimensional register accessor.
Definition: ForwardDeclarations.h:17
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51
ChimeraTK::LNMBackendBitAccessor
Definition: LNMBackendBitAccessor.h:21
ChimeraTK::LNMBackendBitAccessor::_registerPathName
RegisterPath _registerPathName
register and module name
Definition: LNMBackendBitAccessor.h:176