ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
DummyBackendBase.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 "DummyBackendBase.h"
5
6#include <regex>
7
8using namespace std::string_literals;
9
10namespace ChimeraTK {
11
12 constexpr auto DUMMY_WRITEABLE_SUFFIX = "DUMMY_WRITEABLE";
13 constexpr auto DUMMY_READABLE_SUFFIX = "DUMMY_READABLE";
14 constexpr auto DUMMY_INTERRUPT_REGISTER_PREFIX = "/DUMMY_INTERRUPT_";
15
16 /********************************************************************************************************************/
17
18 DummyBackendBase::DummyBackendBase(std::string const& mapFileName, const std::string& dataConsistencyKeyDescriptor)
20 mapFileName, std::make_unique<NumericAddressedRegisterCatalogue>(), dataConsistencyKeyDescriptor) {
21 // Copy the old vtable
23
24 // Add dummy writeable for each read-only and dummy readable for each write-only register
25 for(const auto& reg : _registerMap) {
26 RegisterPath name = reg.pathName;
27 if(reg.isReadable() && !reg.isWriteable()) {
29 }
30 else if(!reg.isReadable() && reg.isWriteable()) {
32 }
33 else {
34 // already readable + writeable -> do not add dummy register
35 continue;
36 }
38 info.pathName = name;
40 info.hidden = true;
42 }
43
44 // Add dummy interrupt registers for each primary interrupt
45 for(const auto& interruptID : _registerMap.getListOfInterrupts()) {
46 if(interruptID.size() == 1) {
48 NumericAddressedRegisterInfo info(name, 0 /*nElements*/, 0 /*address*/, 0 /*nBytes*/, 0 /*bar*/, 0 /*width*/,
49 0 /*facBits*/, false /*signed*/, NumericAddressedRegisterInfo::Access::WRITE_ONLY,
51 info.hidden = true;
53 }
54 }
55 }
56
57 /********************************************************************************************************************/
58
59 size_t DummyBackendBase::minimumTransferAlignment([[maybe_unused]] uint64_t bar) const {
60 return 4;
61 }
62
63 /********************************************************************************************************************/
64
66 bool DummyBackendBase::barIndexValid([[maybe_unused]] uint64_t bar) {
67 return true;
68 }
69
70 /********************************************************************************************************************/
71
73 std::map<uint64_t, size_t> barSizesInBytes;
74 for(auto const& info : _registerMap) {
75 if(info.elementPitchBits % 8 != 0) {
76 throw ChimeraTK::logic_error("DummyBackendBase: Elements have to be byte aligned.");
77 }
78 barSizesInBytes[info.bar] = std::max(
79 barSizesInBytes[info.bar], static_cast<size_t>(info.address + info.nElements * info.elementPitchBits / 8));
80 }
81 return barSizesInBytes;
82 }
83
84 /********************************************************************************************************************/
85
87 if(sizeInBytes % sizeof(int32_t)) {
88 throw ChimeraTK::logic_error("Read/write size has to be a multiple of 4");
89 }
90 }
91
92 /********************************************************************************************************************/
93
94 template<typename UserType>
95 boost::shared_ptr<NDRegisterAccessor<UserType>> DummyBackendBase::getRegisterAccessor_impl(
96 const RegisterPath& registerPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags) {
97 // First check if the request is for one of the special DUMMY_INTEERRUPT_X registers. if so, early return
98 // this special accessor.
99 if(registerPathName.startsWith("DUMMY_INTERRUPT_")) {
100 bool interruptFound;
101 uint32_t interrupt;
102
103 std::tie(interruptFound, interrupt) = extractControllerInterrupt(registerPathName);
104 if(!interruptFound) {
105 throw ChimeraTK::logic_error("Unknown dummy interrupt " + registerPathName);
106 }
107
108 // Delegate the other parameters down to the accessor which will throw accordingly, to satisfy the specification
109 // Since the accessor will keep a shared pointer to the backend, we can safely capture "this"
111 shared_from_this(), [this, interrupt]() { return triggerInterrupt(interrupt); }, registerPathName,
112 numberOfWords, wordOffsetInRegister, flags);
113
114 return boost::shared_ptr<NDRegisterAccessor<UserType>>(d);
115 }
116
117 // Chain up to to the base class using the previously stored function
119 numberOfWords, wordOffsetInRegister, flags);
120 }
121
122 /********************************************************************************************************************/
123
124 std::pair<bool, int> DummyBackendBase::extractControllerInterrupt(const RegisterPath& registerPathName) const {
125 static const std::string DUMMY_INTERRUPT_REGISTER_NAME{"^"s + DUMMY_INTERRUPT_REGISTER_PREFIX + "([0-9]+)$"};
126
127 const std::string regPathNameStr{registerPathName};
128 const static std::regex dummyInterruptRegex{DUMMY_INTERRUPT_REGISTER_NAME};
129 std::smatch match;
130 std::regex_search(regPathNameStr, match, dummyInterruptRegex);
131
132 if(not match.empty()) {
133 // FIXME: Ideally, this test and the need for passing in the lambda function should be done
134 // in the constructor of the accessor. But passing down the base-class of the backend is very weird
135 // due to the sort-of CRTP pattern used in this base class.
136 auto primaryInterrupt = static_cast<unsigned int>(std::stoul(match[1].str()));
137 for(const auto& interruptID : _registerMap.getListOfInterrupts()) {
138 if(interruptID.front() == primaryInterrupt) {
139 return {true, primaryInterrupt};
140 }
141 }
142 }
143 return {false, 0};
144 }
145
146 /********************************************************************************************************************/
147
148} // namespace ChimeraTK
#define OVERRIDE_VIRTUAL_FUNCTION_TEMPLATE(BaseClass, functionName)
Save the old vtable to be accessible by CALL_BASE_FUNCTION_TEMPLATE and overwrite it with the new imp...
#define CALL_BASE_FUNCTION_TEMPLATE(BaseClass, functionName, templateArgument,...)
Execute the virtual function template call to the base implementation of the function.
Set of AccessMode flags with additional functionality for an easier handling.
Definition AccessMode.h:48
std::pair< bool, int > extractControllerInterrupt(const RegisterPath &registerPathName) const
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor_impl(const RegisterPath &registerPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
Specific override which allows to create "DUMMY_INTEERRUPT_X" accessors.
static void checkSizeIsMultipleOfWordSize(size_t sizeInBytes)
size_t minimumTransferAlignment(uint64_t bar) const override
Determines the supported minimum alignment for any read/write requests.
std::map< uint64_t, size_t > getBarSizesInBytesFromRegisterMapping() const
Determines the size of each bar because the DummyBackends allocate memory per bar.
virtual VersionNumber triggerInterrupt(uint32_t interruptNumber)=0
Simulate the arrival of an interrupt.
bool barIndexValid(uint64_t bar) override
All bars are valid in dummies.
DummyBackendBase(std::string const &mapFileName, const std::string &dataConsistencyKeyDescriptor="")
The DummyInterruptTriggerAccessor class.
Base class for address-based device backends (e.g.
NumericAddressedRegisterCatalogue & _registerMap
const std::set< std::vector< size_t > > & getListOfInterrupts() const
void addRegister(const NumericAddressedRegisterInfo &registerInfo)
Access registerAccess
Data access direction: Read, write, read and write or interrupt.
Class to store a register path name.
bool startsWith(const RegisterPath &compare) const
check if the register path starts with the given path
Exception thrown when a logic error has occured.
Definition Exception.h:51
constexpr auto DUMMY_INTERRUPT_REGISTER_PREFIX
constexpr auto DUMMY_WRITEABLE_SUFFIX
constexpr auto DUMMY_READABLE_SUFFIX
STL namespace.
std::string to_string(const std::string &v)