ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
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, const std::string& dataConsistencyKeyDescriptor)
18 : DummyBackendBase(mapFileName, dataConsistencyKeyDescriptor), _mapFile(mapFileName) {
20 }
21
23 std::lock_guard<std::mutex> lock(mutex);
24
26 }
27
29 std::lock_guard<std::mutex> lock(mutex);
30 std::map<uint64_t, size_t> barSizesInBytes = getBarSizesInBytesFromRegisterMapping();
31
32 for(auto& barSizesInByte : barSizesInBytes) {
33 // the size of the vector is in words, not in bytes -> convert fist with rounding up
34 auto nwords = (barSizesInByte.second + sizeof(int32_t) - 1) / sizeof(int32_t);
35 _barContents[barSizesInByte.first].resize(nwords, 0);
36 }
37 }
38
40 std::lock_guard<std::mutex> lock(mutex);
41
42 _opened = false;
43 }
44
45 void DummyBackend::writeRegisterWithoutCallback(uint64_t bar, uint64_t address, int32_t data) {
46 std::lock_guard<std::mutex> lock(mutex);
47 TRY_REGISTER_ACCESS(_barContents[bar].at(address / sizeof(int32_t)) = data;);
48 }
49
50 void DummyBackend::read(uint64_t bar, uint64_t address, int32_t* data, size_t sizeInBytes) {
51 {
52 std::lock_guard<std::mutex> lock(mutex);
53 assert(_opened);
56 unsigned int wordBaseIndex = address / sizeof(int32_t);
57 TRY_REGISTER_ACCESS(for(unsigned int wordIndex = 0; wordIndex < sizeInBytes / sizeof(int32_t);
58 ++wordIndex) { data[wordIndex] = _barContents[bar].at(wordBaseIndex + wordIndex); });
59 }
60 }
61
62 void DummyBackend::write(uint64_t bar, uint64_t address, int32_t const* data, size_t sizeInBytes) {
63 {
64 std::lock_guard<std::mutex> lock(mutex);
65 assert(_opened);
68 uint64_t wordBaseIndex = address / sizeof(int32_t);
69 TRY_REGISTER_ACCESS(for(unsigned int wordIndex = 0; wordIndex < sizeInBytes / sizeof(int32_t); ++wordIndex) {
70 if(isReadOnly(bar, address + wordIndex * sizeof(int32_t))) {
71 continue;
72 }
73 _barContents[bar].at(wordBaseIndex + wordIndex) = data[wordIndex];
74 })
75 }
76 // we call the callback functions after releasing the mutex in order to
77 // avoid the risk of deadlocks.
79 }
80
82 std::stringstream info;
83 info << "DummyBackend"; // TODO add map file name again
84 return info.str();
85 }
86
87 void DummyBackend::setReadOnly(uint64_t bar, uint64_t address, size_t sizeInWords) {
88 for(size_t i = 0; i < sizeInWords; ++i) {
89 _readOnlyAddresses.insert({bar, address + i * sizeof(int32_t)});
90 }
91 }
92
94 setReadOnly(addressRange.bar, addressRange.offset, addressRange.sizeInBytes / sizeof(int32_t));
95 }
96
97 bool DummyBackend::isReadOnly(uint64_t bar, uint64_t address) const {
98 return (_readOnlyAddresses.find({bar, address}) != _readOnlyAddresses.end());
99 }
100
102 AddressRange addressRange, boost::function<void(void)> const& writeCallbackFunction) {
104 std::pair<AddressRange, boost::function<void(void)>>(addressRange, writeCallbackFunction));
105 }
106
108 std::list<boost::function<void(void)>> callbackFunctionsForThisRange =
110 for(auto& function : callbackFunctionsForThisRange) {
111 function();
112 }
115 std::list<boost::function<void(void)>> DummyBackend::findCallbackFunctionsForAddressRange(AddressRange addressRange) {
116 // as callback functions are not sortable, we want to loop the multimap only
117 // once.
118 // FIXME: If the same function is registered more than one, it may be executed
119 // multiple times
120
121 // we only want the start address of the range, so we set size to 0
122 AddressRange firstAddressInBar(addressRange.bar, 0, 0);
123 AddressRange endAddress(addressRange.bar, addressRange.offset + addressRange.sizeInBytes, 0);
125 auto startIterator = _writeCallbackFunctions.lower_bound(firstAddressInBar);
126
127 auto endIterator = _writeCallbackFunctions.lower_bound(endAddress);
128
129 std::list<boost::function<void(void)>> returnList;
130 for(auto callbackIter = startIterator; callbackIter != endIterator; ++callbackIter) {
131 if(isWriteRangeOverlap(callbackIter->first, addressRange)) {
132 returnList.push_back(callbackIter->second);
133 }
134 }
135
136 return returnList;
137 }
138
140 if(firstRange.bar != secondRange.bar) {
141 return false;
142 }
143
144 uint64_t startAddress = std::max(firstRange.offset, secondRange.offset);
145 uint64_t endAddress =
146 std::min(firstRange.offset + firstRange.sizeInBytes, secondRange.offset + secondRange.sizeInBytes);
147
148 // if at least one register is writable there is an overlap of writable
149 // registers
150 for(uint64_t address = startAddress; address < endAddress; address += sizeof(int32_t)) {
151 if(!isReadOnly(firstRange.bar, address)) {
152 return true;
153 }
154 }
155
156 // we looped all possible registers, none is writable
157 return false;
158 }
159
160 boost::shared_ptr<DeviceBackend> DummyBackend::createInstance(
161 // FIXME #11279 Implement API breaking changes from linter warnings
162 // NOLINTNEXTLINE(performance-unnecessary-value-param)
163 std::string address, std::map<std::string, std::string> parameters) {
164 if(parameters["map"].empty()) {
165 throw ChimeraTK::logic_error("No map file name given.");
166 }
167
168 // when the factory is used to create the dummy device, mapfile path in the
169 // dmap file is relative to the dmap file location. Converting the relative
170 // mapFile path to an absolute path avoids issues when the dmap file is not
171 // in the working directory of the application.
172 return returnInstance<DummyBackend>(
173 address, convertPathRelativeToDmapToAbs(parameters["map"]), parameters["DataConsistencyKeys"]);
174 }
175
176 std::string DummyBackend::convertPathRelativeToDmapToAbs(const std::string& mapfileName) {
178 std::string absPathToDmapDir = parserUtilities::convertToAbsolutePath(dmapDir);
179 // the map file is relative to the dmap file location. Convert the relative
180 // mapfilename to an absolute path
181 return parserUtilities::concatenatePaths(absPathToDmapDir, mapfileName);
182 }
183
184 DummyRegisterRawAccessor DummyBackend::getRawAccessor(const std::string& module, const std::string& register_name) {
185 return {shared_from_this(), module, register_name};
186 }
187
189 auto asyncDomain = boost::dynamic_pointer_cast<async::DomainImpl<std::nullptr_t>>(
190 _asyncDomainsContainer.getDomain(interruptNumber));
191
192 if(asyncDomain) {
193 return asyncDomain->distribute(nullptr);
194 }
195
196 // If the asyncDomain is not there, the pointer in the _asyncDomainsContainer must be nullptr as well.
197 // Otherwise the dynamic cast failed, which should never happen.
198 assert(!_asyncDomainsContainer.getDomain(interruptNumber));
199 return VersionNumber{nullptr};
200 }
201
202} // 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.
std::map< uint64_t, std::vector< int32_t > > _barContents
DummyBackend(const std::string &mapFileName, const std::string &dataConsistencyKeyDescriptor="")
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.