ChimeraTK-DeviceAccess  03.18.00
LogicalNameMappingBackend.cc
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 
5 
10 #include "LogicalNameMapParser.h"
11 #include "SupportedUserTypes.h"
12 
13 namespace ChimeraTK {
14 
16  : hasParsed(false), _lmapFileName(std::move(lmapFileName)) {
18  }
19 
20  /********************************************************************************************************************/
21 
23  // don't run, if already parsed
24  if(hasParsed) return;
25  hasParsed = true;
26 
27  // parse the map file
30 
31  // create all devices referenced in the map
32  for(const auto& devName : getTargetDevices()) {
34  }
35  // iterate over plugins and call postParsingHook
36  for(auto& reg : _catalogue_mutable) {
37  for(auto& p : reg.plugins) {
38  auto thisp = boost::static_pointer_cast<const LogicalNameMappingBackend>(shared_from_this());
39  p->postParsingHook(thisp);
40  }
41  }
42  }
43 
44  /********************************************************************************************************************/
45 
47  if(isFunctional()) return;
48  parse();
49 
50  // open all referenced devices (unconditionally, open() is also used for recovery)
51  for(const auto& device : _devices) {
52  device.second->open();
53  }
54 
55  // flag as opened
56  _versionOnOpen = ChimeraTK::VersionNumber{};
57  _asyncReadActive = false;
59 
60  // make sure to update the catalogue from target devices in case they change their catalogue upon open
61  catalogueCompleted = false;
62 
63  // call the openHook for all plugins
64  for(auto& reg : _catalogue_mutable) {
65  for(auto& plug : dynamic_cast<LNMBackendRegisterInfo&>(reg).plugins) {
66  plug->openHook(boost::dynamic_pointer_cast<LogicalNameMappingBackend>(shared_from_this()));
67  }
68  }
69 
70  // update versions of constants
71  auto versionForConstants = ChimeraTK::VersionNumber{}; // needs to be bigger than _versionOnOpen
72  for(auto& nameAndVar : _variables) {
73  auto& variable = nameAndVar.second;
74  if(variable.isConstant) {
75  std::lock_guard<std::mutex> lk(variable.valueTable_mutex);
76  ChimeraTK::callForType(variable.valueType, [&](auto v) {
77  boost::fusion::at_key<decltype(v)>(variable.valueTable.table).latestVersion = versionForConstants;
78  });
79  }
80  }
81  }
82 
83  /********************************************************************************************************************/
84 
86  if(!_opened) return;
87 
88  // call the closeHook for all plugins
89  for(auto& reg : _catalogue_mutable) {
90  for(auto& plug : dynamic_cast<LNMBackendRegisterInfo&>(reg).plugins) {
91  plug->closeHook();
92  }
93  }
94 
95  // close all referenced devices
96  for(const auto& device : _devices) {
97  if(device.second->isOpen()) device.second->close();
98  }
99  // flag as closed
100  _opened = false;
101  _asyncReadActive = false;
102  }
103 
104  /********************************************************************************************************************/
105 
106  // FIXME #11279 Implement API breaking changes from linter warnings
107  // NOLINTBEGIN(performance-unnecessary-value-param)
108  boost::shared_ptr<DeviceBackend> LogicalNameMappingBackend::createInstance(
109  std::string /*address*/, std::map<std::string, std::string> parameters) {
110  // NOLINTEND(performance-unnecessary-value-param)
111  if(parameters["map"].empty()) {
112  throw ChimeraTK::logic_error("Map file name not specified.");
113  }
114  auto ptr = boost::make_shared<LogicalNameMappingBackend>(parameters["map"]);
115  parameters.erase(parameters.find("map"));
116  ptr->_parameters = parameters;
117  return boost::static_pointer_cast<DeviceBackend>(ptr);
118  }
119 
120  /********************************************************************************************************************/
121 
122  template<typename UserType>
123  boost::shared_ptr<NDRegisterAccessor<UserType>> LogicalNameMappingBackend::getRegisterAccessor_impl(
124  const RegisterPath& registerPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags,
125  size_t omitPlugins) {
126  parse();
127  // check if accessor plugin present
128  boost::shared_ptr<NDRegisterAccessor<UserType>> returnValue;
129  auto info = _catalogue_mutable.getBackendRegister(registerPathName);
130  if(info.plugins.size() <= omitPlugins) {
131  // no plugin: directly return the accessor
132  returnValue =
133  getRegisterAccessor_internal<UserType>(registerPathName, numberOfWords, wordOffsetInRegister, flags);
134  }
135  else {
136  returnValue = info.plugins[omitPlugins]->getAccessor<UserType>(
137  boost::static_pointer_cast<LogicalNameMappingBackend>(shared_from_this()), numberOfWords,
138  wordOffsetInRegister, flags, omitPlugins);
139  }
140 
141  returnValue->setExceptionBackend(shared_from_this());
142 
143  return returnValue;
144  }
145 
146  /********************************************************************************************************************/
147 
148  template<typename UserType>
149  boost::shared_ptr<NDRegisterAccessor<UserType>> LogicalNameMappingBackend::getRegisterAccessor_internal(
150  const RegisterPath& registerPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags) {
151  // obtain register info
152  auto info = _catalogue_mutable.getBackendRegister(registerPathName);
153 
154  // Check that the requested requested accessor fits into the register as described by the info. It is not enough to
155  // let the target do the check. It might be a sub-register of a much larger one and for the target it is fine.
156  if(info.length != 0) {
157  // If info->length is 0 we let the target device do the checking. Nothing we can decide here.
158  if(numberOfWords == 0) numberOfWords = info.length;
159  if((numberOfWords + wordOffsetInRegister) > info.length) {
161  std::string(
162  "LogicalNameMappingBackend: Error creating accessor. Number of words plus offset too large in ") +
163  registerPathName);
164  }
165  }
166 
167  // determine the offset and length
168  size_t actualOffset = size_t(info.firstIndex) + wordOffsetInRegister;
169  size_t actualLength = (numberOfWords > 0 ? numberOfWords : size_t(info.length));
170 
171  // implementation for each type
172  boost::shared_ptr<NDRegisterAccessor<UserType>> ptr;
173  if(info.targetType == LNMBackendRegisterInfo::TargetType::REGISTER) {
174  DeviceBackend* _targetDevice;
175  std::string devName = info.deviceName;
176  if(devName != "this") {
177  _targetDevice = _devices[info.deviceName].get();
178  }
179  else {
180  _targetDevice = this;
181  }
182  // make sure the target device exists
183  if(_targetDevice == nullptr) {
184  throw ChimeraTK::logic_error("Target device for this logical register is not opened. See "
185  "exception thrown in open()!");
186  }
187  // obtain underlying register accessor
188  ptr = _targetDevice->getRegisterAccessor<UserType>(
189  RegisterPath(info.registerName), actualLength, actualOffset, flags);
190  }
191  else if(info.targetType == LNMBackendRegisterInfo::TargetType::CHANNEL) {
192  ptr = boost::shared_ptr<NDRegisterAccessor<UserType>>(new LNMBackendChannelAccessor<UserType>(
193  shared_from_this(), registerPathName, actualLength, actualOffset, flags));
194  }
195  else if(info.targetType == LNMBackendRegisterInfo::TargetType::BIT) {
196  ptr = boost::shared_ptr<NDRegisterAccessor<UserType>>(
197  new LNMBackendBitAccessor<UserType>(shared_from_this(), registerPathName, actualLength, actualOffset, flags));
198  }
199  else if(info.targetType == LNMBackendRegisterInfo::TargetType::CONSTANT ||
200  info.targetType == LNMBackendRegisterInfo::TargetType::VARIABLE) {
201  ptr = boost::shared_ptr<NDRegisterAccessor<UserType>>(new LNMBackendVariableAccessor<UserType>(
202  shared_from_this(), registerPathName, actualLength, actualOffset, flags));
203  }
204  else {
206  "For this register type, a RegisterAccessor cannot be obtained (name of logical register: " +
207  registerPathName + ").");
208  }
209 
210  return ptr;
211  }
212 
213  /********************************************************************************************************************/
214 
217  parse();
218 
219  // fill in information to the catalogue from the target devices
220  for(auto& lnmInfo : _catalogue_mutable) {
221  auto targetType = lnmInfo.targetType;
222  if(targetType != LNMBackendRegisterInfo::TargetType::REGISTER &&
223  targetType != LNMBackendRegisterInfo::TargetType::CHANNEL &&
224  targetType != LNMBackendRegisterInfo::TargetType::BIT) {
225  continue;
226  }
227 
228  std::string devName = lnmInfo.deviceName;
229 
230  RegisterInfo target_info(lnmInfo.clone()); // Start with a clone of this info as there is not default constructor
231  // In case the device is not "this" replace it with the real target register info
232  if(devName != "this") {
233  auto cat = _devices.at(devName)->getRegisterCatalogue();
234  if(!cat.hasRegister(lnmInfo.registerName)) continue;
235  target_info = cat.getRegister(lnmInfo.registerName);
236  }
237  else {
238  target_info = _catalogue_mutable.getRegister(lnmInfo.registerName);
239  // target_info might also be affected by plugins. e.g. forceReadOnly plugin
240  // we need to process plugin list of target register before taking over anything
241  auto& i = dynamic_cast<LNMBackendRegisterInfo&>(target_info.getImpl());
242  for(auto& plugin : i.plugins) {
243  plugin->updateRegisterInfo(_catalogue_mutable);
244  }
245  target_info = _catalogue_mutable.getRegister(lnmInfo.registerName);
246  }
247 
248  lnmInfo.supportedFlags = target_info.getSupportedAccessModes();
249  if(targetType != LNMBackendRegisterInfo::TargetType::BIT) {
250  lnmInfo._dataDescriptor = target_info.getDataDescriptor();
251  }
252  else {
253  lnmInfo._dataDescriptor = DataDescriptor(DataDescriptor::FundamentalType::boolean, true, false, 1, 0);
254  lnmInfo.supportedFlags.remove(AccessMode::raw);
255  }
256  lnmInfo.readable = target_info.isReadable();
257  lnmInfo.writeable = target_info.isWriteable();
258 
259  if(targetType == LNMBackendRegisterInfo::TargetType::CHANNEL) {
260  lnmInfo.writeable = false;
261  }
262 
263  if(targetType == LNMBackendRegisterInfo::TargetType::REGISTER) {
264  lnmInfo.nChannels = target_info.getNumberOfChannels();
265  }
266  if(lnmInfo.length == 0) lnmInfo.length = target_info.getNumberOfElements();
267 
268  _catalogue_mutable.modifyRegister(lnmInfo);
269  }
270 
271  // update catalogue info by plugins
272  for(auto& lnmInfo : _catalogue_mutable) {
273  for(auto& plugin : lnmInfo.plugins) {
274  plugin->updateRegisterInfo(_catalogue_mutable);
275  }
276  }
277 
278  catalogueCompleted = true;
279  return RegisterCatalogue(_catalogue_mutable.clone());
280  }
281 
282  /********************************************************************************************************************/
283  // Instantiate templated members - this is required for some gcc versions like the one on Ubuntu 18.04
284 
285  template<typename UserType>
287  LogicalNameMappingBackend* p{nullptr};
288 
289  void getRegisterAccessor_impl(const RegisterPath& registerPathName, size_t numberOfWords,
290  size_t wordOffsetInRegister, AccessModeFlags flags, size_t omitPlugins) {
291  p->getRegisterAccessor_impl<UserType>(registerPathName, numberOfWords, wordOffsetInRegister, flags, omitPlugins);
292  }
293 
294  void getRegisterAccessor_internal(const RegisterPath& registerPathName, size_t numberOfWords,
295  size_t wordOffsetInRegister, AccessModeFlags flags) {
296  p->getRegisterAccessor_internal<UserType>(registerPathName, numberOfWords, wordOffsetInRegister, flags);
297  }
298  };
300 
301  /********************************************************************************************************************/
302 
304  auto message = getActiveExceptionMessage();
305  for(auto& d : _devices) {
306  d.second->setException(message);
307  }
308 
309  // iterate all push subscriptions of variables and place exception into queue
310  if(_asyncReadActive) {
311  VersionNumber v{};
312  for(auto& r : _catalogue_mutable) {
313  auto& info = dynamic_cast<LNMBackendRegisterInfo&>(r);
314  if(info.targetType == LNMBackendRegisterInfo::TargetType::VARIABLE) {
315  callForType(info.valueType, [&](auto arg) {
316  auto& lnmVariable = _variables[info.name];
317  auto& vtEntry = boost::fusion::at_key<decltype(arg)>(lnmVariable.valueTable.table);
318  for(auto& sub : vtEntry.subscriptions) {
319  try {
320  throw ChimeraTK::runtime_error(message);
321  }
322  catch(...) {
323  sub.second.push_overwrite_exception(std::current_exception());
324  }
325  }
326  });
327  }
328  }
329  }
330 
331  // deactivate async read
332  _asyncReadActive = false;
333 
334  // call the exceptionHook for all plugins
335  for(auto& reg : _catalogue_mutable) {
336  for(auto& plug : dynamic_cast<LNMBackendRegisterInfo&>(reg).plugins) {
337  plug->exceptionHook();
338  }
339  }
340  }
341 
342  /********************************************************************************************************************/
343 
344  void LogicalNameMappingBackend::activateAsyncRead() noexcept {
345  if(!isFunctional()) return;
346 
347  // store information locally, as variable accessors have async read
348  _asyncReadActive = true;
349 
350  // delegate to target devices
351  for(auto& d : _devices) {
352  d.second->activateAsyncRead();
353  }
354 
355  // iterate all push subscriptions of variables and place initial value into queue
356  VersionNumber v = getVersionOnOpen();
357  for(auto& r : _catalogue_mutable) {
358  auto& info = dynamic_cast<LNMBackendRegisterInfo&>(r);
359  if(info.targetType == LNMBackendRegisterInfo::TargetType::VARIABLE) {
360  auto& lnmVariable = _variables[info.name];
361  try {
362  callForType(info.valueType, [&](auto arg) {
363  auto& vtEntry = boost::fusion::at_key<decltype(arg)>(lnmVariable.valueTable.table);
364  // override version number if last write to variable was before reopening the device
365  if(vtEntry.latestVersion < v) {
366  vtEntry.latestVersion = v; // store in case an accessor is created after calling activateAsyncRead
367  }
368  for(auto& sub : vtEntry.subscriptions) {
369  try {
370  sub.second.push_overwrite({vtEntry.latestValue, vtEntry.latestValidity, vtEntry.latestVersion});
371  }
372  catch(std::system_error& e) {
373  std::cerr << "Caught system error in activateAsyncRead(): " << e.what() << std::endl;
374  std::terminate();
375  }
376  }
377  });
378  }
379  catch(std::bad_cast& e) {
380  // bad_cast is thrown by callForType if the type is not known. This should not happen at this point any more
381  // because we are iterating a list that has already been processed before.
382  std::ignore = e;
383  assert(false);
384  }
385  }
386  }
387  }
388 
389  /********************************************************************************************************************/
390 
391  std::unordered_set<std::string> LogicalNameMappingBackend::getTargetDevices() const {
392  std::unordered_set<std::string> ret;
393  for(const auto& info : _catalogue_mutable) {
394  if(info.deviceName != "this" && !info.deviceName.empty()) ret.insert(info.deviceName);
395  }
396  return ret;
397  }
398 
399  /********************************************************************************************************************/
400 
401  ChimeraTK::VersionNumber LogicalNameMappingBackend::getVersionOnOpen() const {
402  return _versionOnOpen;
403  }
404 
405  /********************************************************************************************************************/
406 
407 } // namespace ChimeraTK
ChimeraTK::BackendFactory::createBackend
boost::shared_ptr< DeviceBackend > createBackend(const std::string &aliasOrUri)
Create a new backend and return the instance as a shared pointer.
Definition: BackendFactory.cc:201
ChimeraTK::AccessMode::raw
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
device
ctk::Device device
Definition: testExceptionDummyDevice.cc:18
ChimeraTK::LogicalNameMappingBackend::getRegisterAccessor_impl
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor_impl(const RegisterPath &registerPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags, size_t omitPlugins=0)
Definition: LogicalNameMappingBackend.cc:123
ChimeraTK::LogicalNameMappingBackend::_lmapFileName
std::string _lmapFileName
name of the logical map file
Definition: LogicalNameMappingBackend.h:53
ChimeraTK::LogicalNameMappingBackend::LogicalNameMappingBackend
LogicalNameMappingBackend(std::string lmapFileName="")
Definition: LogicalNameMappingBackend.cc:15
ChimeraTK::Device::close
void close()
Close the device.
Definition: Device.cc:66
ChimeraTK::BackendFactory::getInstance
static BackendFactory & getInstance()
Static function to get an instance of factory.
Definition: BackendFactory.cc:191
ChimeraTK::DeviceBackendImpl::setOpenedAndClearException
void setOpenedAndClearException() noexcept
Backends should call this function at the end of a (successful) open() call.
Definition: DeviceBackendImpl.cc:12
ChimeraTK::LogicalNameMappingBackend::_asyncReadActive
std::atomic< bool > _asyncReadActive
Flag storing whether asynchronous read has been activated.
Definition: LogicalNameMappingBackend.h:107
ChimeraTK::InstantiateLogicalNameMappingBackendFunctions
Definition: LogicalNameMappingBackend.cc:286
LogicalNameMappingBackend.h
FILL_VIRTUAL_FUNCTION_TEMPLATE_VTABLE
#define FILL_VIRTUAL_FUNCTION_TEMPLATE_VTABLE(functionName)
Fill the vtable of a virtual function template defined with DEFINE_VIRTUAL_FUNCTION_TEMPLATE.
Definition: VirtualFunctionTemplate.h:84
ChimeraTK::LogicalNameMappingBackend::catalogueCompleted
bool catalogueCompleted
Flag whether the catalogue has already been filled with extra information from the target backends.
Definition: LogicalNameMappingBackend.h:67
ChimeraTK::LogicalNameMappingBackend::getRegisterAccessor_internal
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor_internal(const RegisterPath &registerPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
Definition: LogicalNameMappingBackend.cc:149
ChimeraTK::LogicalNameMappingBackend::setExceptionImpl
void setExceptionImpl() noexcept override
Function to be (optionally) implemented by backends if additional actions are needed when switching t...
Definition: LogicalNameMappingBackend.cc:303
ChimeraTK::DeviceBackendImpl::_opened
std::atomic< bool > _opened
flag if backend is opened
Definition: DeviceBackendImpl.h:60
ChimeraTK::LogicalNameMappingBackend::getRegisterCatalogue
RegisterCatalogue getRegisterCatalogue() const override
Return the register catalogue with detailed information on all registers.
Definition: LogicalNameMappingBackend.cc:215
ChimeraTK::LogicalNameMapParser
Logical name map: store information from xlmap file and provide it to the LogicalNameMappingBackend a...
Definition: LogicalNameMapParser.h:26
SupportedUserTypes.h
ChimeraTK::RegisterInfo::getNumberOfChannels
unsigned int getNumberOfChannels() const
Return number of channels in register.
Definition: RegisterInfo.cpp:44
LNMMathPluginFormulaHelper.h
ChimeraTK::RegisterCatalogue
Catalogue of register information.
Definition: RegisterCatalogue.h:20
ChimeraTK::DeviceBackend
The base class for backends providing IO functionality for the Device class.
Definition: DeviceBackend.h:28
ChimeraTK::DataDescriptor
Class describing the actual payload data format of a register in an abstract manner.
Definition: DataDescriptor.h:19
ChimeraTK::LogicalNameMappingBackend::parse
void parse() const
parse the logical map file, if not yet done
Definition: LogicalNameMappingBackend.cc:22
ChimeraTK::DeviceBackendImpl::getActiveExceptionMessage
std::string getActiveExceptionMessage() noexcept
Definition: DeviceBackendImpl.cc:50
ChimeraTK::DataDescriptor::FundamentalType::boolean
@ boolean
ChimeraTK::LogicalNameMappingBackend::_variables
std::map< std::string, LNMVariable > _variables
Map of variables and constants.
Definition: LogicalNameMappingBackend.h:92
ChimeraTK::LogicalNameMappingBackend::_devices
std::map< std::string, boost::shared_ptr< DeviceBackend > > _devices
map of target devices
Definition: LogicalNameMappingBackend.h:56
ChimeraTK::LogicalNameMappingBackend::_catalogue_mutable
BackendRegisterCatalogue< LNMBackendRegisterInfo > _catalogue_mutable
We need to make the catalogue mutable, since we fill it within getRegisterCatalogue()
Definition: LogicalNameMappingBackend.h:63
LNMBackendBitAccessor.h
ChimeraTK::LNMBackendRegisterInfo
RegisterInfo structure for the LogicalNameMappingBackend.
Definition: LNMBackendRegisterInfo.h:22
ChimeraTK::LogicalNameMappingBackend::open
void open() override
Open the device.
Definition: LogicalNameMappingBackend.cc:46
ChimeraTK::LNMBackendChannelAccessor
Definition: LNMBackendChannelAccessor.h:17
ChimeraTK::RegisterInfo
Definition: RegisterInfo.h:12
ChimeraTK::RegisterInfo::getDataDescriptor
const DataDescriptor & getDataDescriptor() const
Return desciption of the actual payload data for this register.
Definition: RegisterInfo.cpp:56
ChimeraTK::RegisterInfo::getSupportedAccessModes
AccessModeFlags getSupportedAccessModes() const
Return all supported AccessModes for this register.
Definition: RegisterInfo.cpp:74
ChimeraTK::RegisterInfo::isWriteable
bool isWriteable() const
Return whether the register is writeable.
Definition: RegisterInfo.cpp:68
ChimeraTK::RegisterInfo::getImpl
BackendRegisterInfoBase & getImpl()
Return a reference to the implementation object.
Definition: RegisterInfo.cpp:86
LogicalNameMapParser.h
ChimeraTK::LogicalNameMapParser::parseFile
BackendRegisterCatalogue< LNMBackendRegisterInfo > parseFile(const std::string &fileName)
parse the given XML file
Definition: LogicalNameMapParser.cc:261
ChimeraTK::INSTANTIATE_TEMPLATE_FOR_CHIMERATK_USER_TYPES
INSTANTIATE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(LNMBackendBitAccessor)
ChimeraTK::LogicalNameMappingBackend
Backend to map logical register names onto real hardware registers.
Definition: LogicalNameMappingBackend.h:19
ChimeraTK::LogicalNameMappingBackend::getTargetDevices
std::unordered_set< std::string > getTargetDevices() const
Obtain list of all target devices referenced in the catalogue.
Definition: LogicalNameMappingBackend.cc:391
LNMBackendChannelAccessor.h
ChimeraTK::DeviceBackendImpl::isFunctional
bool isFunctional() const noexcept final
Return whether a device is working as intended, usually this means it is opened and does not have any...
Definition: DeviceBackendImpl.h:85
ChimeraTK::LogicalNameMappingBackend::hasParsed
bool hasParsed
flag if already parsed
Definition: LogicalNameMappingBackend.h:50
ChimeraTK::Device::open
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Definition: Device.cc:58
ChimeraTK::DeviceBackend::getRegisterAccessor
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor(const RegisterPath &registerPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
Get a NDRegisterAccessor object from the register name.
Definition: DeviceBackend.h:109
ChimeraTK::callForType
void callForType(const std::type_info &type, LAMBDATYPE lambda)
Helper function for running code which uses some compile-time type that is specified at runtime as a ...
Definition: SupportedUserTypes.h:919
ChimeraTK::RegisterPath
Class to store a register path name.
Definition: RegisterPath.h:16
ChimeraTK::LogicalNameMappingBackend::createInstance
static boost::shared_ptr< DeviceBackend > createInstance(std::string address, std::map< std::string, std::string > parameters)
Definition: LogicalNameMappingBackend.cc:108
ChimeraTK::VersionNumber
Class for generating and holding version numbers without exposing a numeric representation.
Definition: VersionNumber.h:23
ChimeraTK::LogicalNameMappingBackend::close
void close() override
Close the device.
Definition: LogicalNameMappingBackend.cc:85
LNMBackendVariableAccessor.h
ChimeraTK::AccessModeFlags
Set of AccessMode flags with additional functionality for an easier handling.
Definition: AccessMode.h:48
ChimeraTK::LogicalNameMappingBackend::_parameters
std::map< std::string, std::string > _parameters
map of parameters passed through the CDD
Definition: LogicalNameMappingBackend.h:59
ChimeraTK::LNMBackendVariableAccessor
Definition: LNMBackendVariableAccessor.h:21
ChimeraTK::RegisterInfo::isReadable
bool isReadable() const
Return whether the register is readable.
Definition: RegisterInfo.cpp:62
ChimeraTK::RegisterInfo::getNumberOfElements
unsigned int getNumberOfElements() const
Return number of elements per channel.
Definition: RegisterInfo.cpp:38
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51
ChimeraTK::LNMBackendBitAccessor
Definition: LNMBackendBitAccessor.h:21