ChimeraTK-DeviceAccess  03.18.00
DummyBackend.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 
4 #include "BackendFactory.h"
6 #include "Exception.h"
7 #include "parserUtilities.h"
8 
9 #include <boost/lambda/lambda.hpp>
10 
11 #include <algorithm>
12 #include <regex>
13 #include <sstream>
14 
15 namespace ChimeraTK {
16 
17  DummyBackend::DummyBackend(const std::string& mapFileName) : DummyBackendBase(mapFileName), _mapFile(mapFileName) {
19  }
20 
22  std::lock_guard<std::mutex> lock(mutex);
23 
25  }
26 
28  std::lock_guard<std::mutex> lock(mutex);
29  std::map<uint64_t, size_t> barSizesInBytes = getBarSizesInBytesFromRegisterMapping();
30 
31  for(auto& barSizesInByte : barSizesInBytes) {
32  // the size of the vector is in words, not in bytes -> convert fist with rounding up
33  auto nwords = (barSizesInByte.second + sizeof(int32_t) - 1) / sizeof(int32_t);
34  _barContents[barSizesInByte.first].resize(nwords, 0);
35  }
36  }
37 
39  std::lock_guard<std::mutex> lock(mutex);
40 
41  _opened = false;
42  }
43 
44  void DummyBackend::writeRegisterWithoutCallback(uint64_t bar, uint64_t address, int32_t data) {
45  std::lock_guard<std::mutex> lock(mutex);
46  TRY_REGISTER_ACCESS(_barContents[bar].at(address / sizeof(int32_t)) = data;);
47  }
48 
49  void DummyBackend::read(uint64_t bar, uint64_t address, int32_t* data, size_t sizeInBytes) {
50  {
51  std::lock_guard<std::mutex> lock(mutex);
52  assert(_opened);
54  checkSizeIsMultipleOfWordSize(sizeInBytes);
55  unsigned int wordBaseIndex = address / sizeof(int32_t);
56  TRY_REGISTER_ACCESS(for(unsigned int wordIndex = 0; wordIndex < sizeInBytes / sizeof(int32_t);
57  ++wordIndex) { data[wordIndex] = _barContents[bar].at(wordBaseIndex + wordIndex); });
58  }
59  }
60 
61  void DummyBackend::write(uint64_t bar, uint64_t address, int32_t const* data, size_t sizeInBytes) {
62  {
63  std::lock_guard<std::mutex> lock(mutex);
64  assert(_opened);
66  checkSizeIsMultipleOfWordSize(sizeInBytes);
67  uint64_t wordBaseIndex = address / sizeof(int32_t);
68  TRY_REGISTER_ACCESS(for(unsigned int wordIndex = 0; wordIndex < sizeInBytes / sizeof(int32_t); ++wordIndex) {
69  if(isReadOnly(bar, address + wordIndex * sizeof(int32_t))) {
70  continue;
71  }
72  _barContents[bar].at(wordBaseIndex + wordIndex) = data[wordIndex];
73  })
74  }
75  // we call the callback functions after releasing the mutex in order to
76  // avoid the risk of deadlocks.
77  runWriteCallbackFunctionsForAddressRange(AddressRange(bar, address, sizeInBytes));
78  }
79 
81  std::stringstream info;
82  info << "DummyBackend"; // TODO add map file name again
83  return info.str();
84  }
85 
86  void DummyBackend::setReadOnly(uint64_t bar, uint64_t address, size_t sizeInWords) {
87  for(size_t i = 0; i < sizeInWords; ++i) {
88  _readOnlyAddresses.insert({bar, address + i * sizeof(int32_t)});
89  }
90  }
91 
93  setReadOnly(addressRange.bar, addressRange.offset, addressRange.sizeInBytes / sizeof(int32_t));
94  }
95 
96  bool DummyBackend::isReadOnly(uint64_t bar, uint64_t address) const {
97  return (_readOnlyAddresses.find({bar, address}) != _readOnlyAddresses.end());
98  }
99 
101  AddressRange addressRange, boost::function<void(void)> const& writeCallbackFunction) {
103  std::pair<AddressRange, boost::function<void(void)>>(addressRange, writeCallbackFunction));
104  }
105 
107  std::list<boost::function<void(void)>> callbackFunctionsForThisRange =
109  for(auto& function : callbackFunctionsForThisRange) {
110  function();
111  }
112  }
113 
114  std::list<boost::function<void(void)>> DummyBackend::findCallbackFunctionsForAddressRange(AddressRange addressRange) {
115  // as callback functions are not sortable, we want to loop the multimap only
116  // once.
117  // FIXME: If the same function is registered more than one, it may be executed
118  // multiple times
119 
120  // we only want the start address of the range, so we set size to 0
121  AddressRange firstAddressInBar(addressRange.bar, 0, 0);
122  AddressRange endAddress(addressRange.bar, addressRange.offset + addressRange.sizeInBytes, 0);
123 
124  auto startIterator = _writeCallbackFunctions.lower_bound(firstAddressInBar);
125 
126  auto endIterator = _writeCallbackFunctions.lower_bound(endAddress);
127 
128  std::list<boost::function<void(void)>> returnList;
129  for(auto callbackIter = startIterator; callbackIter != endIterator; ++callbackIter) {
130  if(isWriteRangeOverlap(callbackIter->first, addressRange)) {
131  returnList.push_back(callbackIter->second);
132  }
133  }
134 
135  return returnList;
136  }
137 
139  if(firstRange.bar != secondRange.bar) {
140  return false;
141  }
142 
143  uint64_t startAddress = std::max(firstRange.offset, secondRange.offset);
144  uint64_t endAddress =
145  std::min(firstRange.offset + firstRange.sizeInBytes, secondRange.offset + secondRange.sizeInBytes);
146 
147  // if at least one register is writable there is an overlap of writable
148  // registers
149  for(uint64_t address = startAddress; address < endAddress; address += sizeof(int32_t)) {
150  if(!isReadOnly(firstRange.bar, address)) {
151  return true;
152  }
153  }
154 
155  // we looped all possible registers, none is writable
156  return false;
157  }
158 
159  boost::shared_ptr<DeviceBackend> DummyBackend::createInstance(
160  // FIXME #11279 Implement API breaking changes from linter warnings
161  // NOLINTNEXTLINE(performance-unnecessary-value-param)
162  std::string address, std::map<std::string, std::string> parameters) {
163  if(parameters["map"].empty()) {
164  throw ChimeraTK::logic_error("No map file name given.");
165  }
166 
167  // when the factory is used to create the dummy device, mapfile path in the
168  // dmap file is relative to the dmap file location. Converting the relative
169  // mapFile path to an absolute path avoids issues when the dmap file is not
170  // in the working directory of the application.
171  return returnInstance<DummyBackend>(address, convertPathRelativeToDmapToAbs(parameters["map"]));
172  }
173 
174  std::string DummyBackend::convertPathRelativeToDmapToAbs(const std::string& mapfileName) {
176  std::string absPathToDmapDir = parserUtilities::convertToAbsolutePath(dmapDir);
177  // the map file is relative to the dmap file location. Convert the relative
178  // mapfilename to an absolute path
179  return parserUtilities::concatenatePaths(absPathToDmapDir, mapfileName);
180  }
181 
182  DummyRegisterRawAccessor DummyBackend::getRawAccessor(const std::string& module, const std::string& register_name) {
183  return {shared_from_this(), module, register_name};
184  }
185 
186  VersionNumber DummyBackend::triggerInterrupt(uint32_t interruptNumber) {
187  auto asyncDomain = boost::dynamic_pointer_cast<async::DomainImpl<std::nullptr_t>>(
188  _asyncDomainsContainer.getDomain(interruptNumber));
189 
190  if(asyncDomain) {
191  return asyncDomain->distribute(nullptr);
192  }
193 
194  // If the asyncDomain is not there, the pointer in the _asyncDomainsContainer must be nullptr as well.
195  // Otherwise the dynamic cast failed, which should never happen.
196  assert(!_asyncDomainsContainer.getDomain(interruptNumber));
197  return VersionNumber{nullptr};
198  }
199 
200 } // namespace ChimeraTK
ChimeraTK::DummyBackendBase::getBarSizesInBytesFromRegisterMapping
std::map< uint64_t, size_t > getBarSizesInBytesFromRegisterMapping() const
Determines the size of each bar because the DummyBackends allocate memory per bar.
Definition: DummyBackendBase.cc:23
ChimeraTK::DummyBackendBase
Base class for DummyBackends, provides common functionality.
Definition: DummyBackendBase.h:31
ChimeraTK::DummyBackend::write
void write(uint64_t bar, uint64_t address, int32_t const *data, size_t sizeInBytes) override
Write function to be implemented by backends.
Definition: DummyBackend.cc:61
ChimeraTK::DummyBackend::DummyBackend
DummyBackend(const std::string &mapFileName)
Definition: DummyBackend.cc:17
ChimeraTK::BackendFactory::getInstance
static BackendFactory & getInstance()
Static function to get an instance of factory.
Definition: BackendFactory.cc:191
ChimeraTK::DummyBackend::findCallbackFunctionsForAddressRange
std::list< boost::function< void(void)> > findCallbackFunctionsForAddressRange(AddressRange addressRange)
Definition: DummyBackend.cc:114
ChimeraTK::DeviceBackendImpl::setOpenedAndClearException
void setOpenedAndClearException() noexcept
Backends should call this function at the end of a (successful) open() call.
Definition: DeviceBackendImpl.cc:12
ChimeraTK::DummyBackend::writeRegisterWithoutCallback
void writeRegisterWithoutCallback(uint64_t bar, uint64_t address, int32_t data)
Not write-protected function for internal use only.
Definition: DummyBackend.cc:44
ChimeraTK::DummyBackend::isReadOnly
bool isReadOnly(uint64_t bar, uint64_t address) const
Definition: DummyBackend.cc:96
ChimeraTK::DummyBackend::_readOnlyAddresses
std::set< std::pair< uint64_t, uint64_t > > _readOnlyAddresses
Definition: DummyBackend.h:104
ChimeraTK::DummyBackend::setWriteCallbackFunction
void setWriteCallbackFunction(AddressRange addressRange, boost::function< void(void)> const &writeCallbackFunction)
Definition: DummyBackend.cc:100
ChimeraTK::DummyBackend::mutex
std::mutex mutex
Definition: DummyBackend.h:106
ChimeraTK::DummyBackend::resizeBarContents
void resizeBarContents()
Definition: DummyBackend.cc:27
ChimeraTK::DummyBackend::AddressRange
Definition: DummyBackend.h:82
ChimeraTK::DummyBackend::open
void open() override
Open the device.
Definition: DummyBackend.cc:21
ChimeraTK::DeviceBackendImpl::_opened
std::atomic< bool > _opened
flag if backend is opened
Definition: DeviceBackendImpl.h:60
ChimeraTK::DummyBackend::getRawAccessor
DummyRegisterRawAccessor getRawAccessor(const std::string &module, const std::string &register_name)
Get a raw accessor to the underlying memory with the convenience of using register names.
Definition: DummyBackend.cc:182
parserUtilities.h
ChimeraTK::DeviceBackendImpl::checkActiveException
void checkActiveException() final
Function to be called by backends when needing to check for an active exception.
Definition: DeviceBackendImpl.h:94
ChimeraTK::parserUtilities::convertToAbsolutePath
std::string convertToAbsolutePath(std::string const &relativePath)
Converts a relative path to its absolute path.
Definition: parserUtilities.cc:23
ChimeraTK::DummyBackend::_writeCallbackFunctions
std::multimap< AddressRange, boost::function< void(void)> > _writeCallbackFunctions
Definition: DummyBackend.h:105
ChimeraTK::DummyBackend::runWriteCallbackFunctionsForAddressRange
void runWriteCallbackFunctionsForAddressRange(AddressRange addressRange)
Definition: DummyBackend.cc:106
ChimeraTK::DummyBackend::AddressRange::bar
const uint64_t bar
Definition: DummyBackend.h:85
ChimeraTK::DeviceBackendImpl::_asyncDomainsContainer
async::DomainsContainer _asyncDomainsContainer
Container for async::Domains to support wait_for_new_data.
Definition: DeviceBackendImpl.h:66
ChimeraTK::async::DomainsContainer::getDomain
boost::shared_ptr< Domain > getDomain(size_t key)
Return the shared pointer to the Domain for a key.
Definition: DomainsContainer.cc:82
ChimeraTK::DummyBackendBase::checkSizeIsMultipleOfWordSize
static void checkSizeIsMultipleOfWordSize(size_t sizeInBytes)
Definition: DummyBackendBase.cc:35
ChimeraTK::parserUtilities::extractDirectory
std::string extractDirectory(std::string const &path)
Returns the path to the directory containing the file provided as the input parameter.
Definition: parserUtilities.cc:35
ChimeraTK::DummyBackend::setReadOnly
void setReadOnly(uint64_t bar, uint64_t address, size_t sizeInWords)
Definition: DummyBackend.cc:86
ChimeraTK::parserUtilities::concatenatePaths
std::string concatenatePaths(const std::string &path1, const std::string &path2)
Concatenates two given paths using custom rules.
Definition: parserUtilities.cc:27
ChimeraTK::DummyBackend::AddressRange::sizeInBytes
const uint32_t sizeInBytes
Definition: DummyBackend.h:84
ChimeraTK::DummyBackend::_barContents
std::map< uint64_t, std::vector< int32_t > > _barContents
Definition: DummyBackend.h:103
ChimeraTK::DummyBackend::read
void read(uint64_t bar, uint64_t address, int32_t *data, size_t sizeInBytes) override
Read function to be implemented by backends.
Definition: DummyBackend.cc:49
ChimeraTK::DummyRegisterRawAccessor
Accessor for raw 32 bit integer access to the underlying memory space.
Definition: DummyRegisterAccessor.h:324
ChimeraTK::getDMapFilePath
std::string getDMapFilePath()
Returns the dmap file name which the library currently uses for looking up device(alias) names.
Definition: Utilities.cpp:321
DummyRegisterAccessor.h
BackendFactory.h
TRY_REGISTER_ACCESS
#define TRY_REGISTER_ACCESS(COMMAND)
Definition: DummyBackendBase.h:15
ChimeraTK::DummyBackend::AddressRange::offset
const uint64_t offset
Definition: DummyBackend.h:83
ChimeraTK::VersionNumber
Class for generating and holding version numbers without exposing a numeric representation.
Definition: VersionNumber.h:23
ChimeraTK::DummyBackend::triggerInterrupt
VersionNumber triggerInterrupt(uint32_t interruptNumber) override
Simulate the arrival of an interrupt.
Definition: DummyBackend.cc:186
ChimeraTK::DummyBackend::convertPathRelativeToDmapToAbs
static std::string convertPathRelativeToDmapToAbs(std::string const &mapfileName)
Definition: DummyBackend.cc:174
Exception.h
ChimeraTK::DummyBackend::isWriteRangeOverlap
bool isWriteRangeOverlap(AddressRange firstRange, AddressRange secondRange)
returns true if the ranges overlap and at least one of the overlapping registers can be written
Definition: DummyBackend.cc:138
ChimeraTK::DummyBackend::readDeviceInfo
std::string readDeviceInfo() override
Return a device information string containing hardware details like the firmware version number or th...
Definition: DummyBackend.cc:80
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::DummyBackend::createInstance
static boost::shared_ptr< DeviceBackend > createInstance(std::string address, std::map< std::string, std::string > parameters)
Definition: DummyBackend.cc:159
ChimeraTK::DummyBackend::closeImpl
void closeImpl() override
This closes the device, clears all internal registers, read-only settings and callback functions.
Definition: DummyBackend.cc:38
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51