ChimeraTK-DeviceAccess 03.19.00
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
15namespace 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);
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);
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.
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 }
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
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
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
#define TRY_REGISTER_ACCESS(COMMAND)
static BackendFactory & getInstance()
Static function to get an instance of factory.
async::DomainsContainer _asyncDomainsContainer
Container for async::Domains to support wait_for_new_data.
void setOpenedAndClearException() noexcept
Backends should call this function at the end of a (successful) open() call.
void checkActiveException() final
Function to be called by backends when needing to check for an active exception.
std::atomic< bool > _opened
flag if backend is opened
Base class for DummyBackends, provides common functionality.
static void checkSizeIsMultipleOfWordSize(size_t sizeInBytes)
std::map< uint64_t, size_t > getBarSizesInBytesFromRegisterMapping() const
Determines the size of each bar because the DummyBackends allocate memory per bar.
void write(uint64_t bar, uint64_t address, int32_t const *data, size_t sizeInBytes) override
Write function to be implemented by backends.
std::string readDeviceInfo() override
Return a device information string containing hardware details like the firmware version number or th...
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.
void read(uint64_t bar, uint64_t address, int32_t *data, size_t sizeInBytes) override
Read function to be implemented by backends.
std::set< std::pair< uint64_t, uint64_t > > _readOnlyAddresses
void setWriteCallbackFunction(AddressRange addressRange, boost::function< void(void)> const &writeCallbackFunction)
std::multimap< AddressRange, boost::function< void(void)> > _writeCallbackFunctions
void open() override
Open the device.
DummyBackend(const std::string &mapFileName)
std::map< uint64_t, std::vector< int32_t > > _barContents
static std::string convertPathRelativeToDmapToAbs(std::string const &mapfileName)
void closeImpl() override
This closes the device, clears all internal registers, read-only settings and callback functions.
static boost::shared_ptr< DeviceBackend > createInstance(std::string address, std::map< std::string, std::string > parameters)
std::list< boost::function< void(void)> > findCallbackFunctionsForAddressRange(AddressRange addressRange)
bool isWriteRangeOverlap(AddressRange firstRange, AddressRange secondRange)
returns true if the ranges overlap and at least one of the overlapping registers can be written
void writeRegisterWithoutCallback(uint64_t bar, uint64_t address, int32_t data)
Not write-protected function for internal use only.
bool isReadOnly(uint64_t bar, uint64_t address) const
void setReadOnly(uint64_t bar, uint64_t address, size_t sizeInWords)
VersionNumber triggerInterrupt(uint32_t interruptNumber) override
Simulate the arrival of an interrupt.
void runWriteCallbackFunctionsForAddressRange(AddressRange addressRange)
Accessor for raw 32 bit integer access to the underlying memory space.
Class for generating and holding version numbers without exposing a numeric representation.
boost::shared_ptr< Domain > getDomain(size_t key)
Return the shared pointer to the Domain for a key.
Exception thrown when a logic error has occured.
Definition Exception.h:51
std::string extractDirectory(std::string const &path)
Returns the path to the directory containing the file provided as the input parameter.
std::string concatenatePaths(const std::string &path1, const std::string &path2)
Concatenates two given paths using custom rules.
std::string convertToAbsolutePath(std::string const &relativePath)
Converts a relative path to its absolute path.
std::string getDMapFilePath()
Returns the dmap file name which the library currently uses for looking up device(alias) names.