ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
UioBackend.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 "UioBackend.h"
5
6namespace ChimeraTK {
7
9 const std::string& deviceName, const std::string& mapFileName, const std::string& dataConsistencyKeyDescriptor)
11 mapFileName, std::make_unique<NumericAddressedRegisterCatalogue>(), dataConsistencyKeyDescriptor) {
12 _uioAccess = std::make_shared<UioAccess>("/dev/" + deviceName);
13 }
14
18
19 boost::shared_ptr<DeviceBackend> UioBackend::createInstance(
20 // FIXME #11279 Implement API breaking changes from linter warnings
21 // NOLINTNEXTLINE(performance-unnecessary-value-param)
22 std::string address, std::map<std::string, std::string> parameters) {
23 if(address.empty()) {
24 throw ChimeraTK::logic_error("UIO: Device name not specified.");
25 }
26
27 if(parameters["map"].empty()) {
28 throw ChimeraTK::logic_error("UIO: No map file name given.");
29 }
30
31 return boost::make_shared<UioBackend>(address, parameters["map"], parameters["DataConsistencyKeys"]);
32 }
33
35 if(_opened) {
36 if(isFunctional()) {
37 return;
38 }
39 close();
40 }
41
42 _uioAccess->open();
44 }
45
47 if(_opened) {
48 if(_interruptWaitingThread.joinable()) {
49 _stopInterruptLoop = true;
50 _interruptWaitingThread.join();
51 }
52 _asyncDomain.reset();
53 _uioAccess->close();
54 }
55
56 _opened = false;
57 }
58
59 bool UioBackend::barIndexValid(uint64_t bar) {
60 return (bar == 0);
61 }
62
63 void UioBackend::read(uint64_t bar, uint64_t address, int32_t* data, size_t sizeInBytes) {
64 assert(_opened);
66
67 _uioAccess->read(bar, address, data, sizeInBytes);
68 }
69
70 void UioBackend::write(uint64_t bar, uint64_t address, int32_t const* data, size_t sizeInBytes) {
71 assert(_opened);
73
74 _uioAccess->write(bar, address, data, sizeInBytes);
75 }
76
78 uint32_t interruptNumber, boost::shared_ptr<async::DomainImpl<std::nullptr_t>> asyncDomain) {
79 std::promise<void> subscriptionDonePromise;
80
81 if(interruptNumber != 0) {
82 setException("UIO: Backend only uses interrupt number 0");
83 subscriptionDonePromise.set_value();
84 return subscriptionDonePromise.get_future();
85 }
86 if(_interruptWaitingThread.joinable()) {
87 subscriptionDonePromise.set_value();
88 return subscriptionDonePromise.get_future();
89 }
90
91 _stopInterruptLoop = false;
92 _asyncDomain = asyncDomain;
93 auto subscriptionDoneFuture = subscriptionDonePromise.get_future();
94 _interruptWaitingThread = std::thread(&UioBackend::waitForInterruptLoop, this, std::move(subscriptionDonePromise));
95 return subscriptionDoneFuture;
96 }
97
99 std::string result = std::string("UIO backend: Device path = " + _uioAccess->getDeviceFilePath());
100 if(!isOpen()) {
101 result += " (device closed)";
102 }
103
104 return result;
105 }
106
107 void UioBackend::waitForInterruptLoop(std::promise<void> subscriptionDonePromise) {
108 try { // also the scope for the promiseFulfiller
109
110 // The NumericAddressedBackend is waiting for subscription done to be fulfilled, so it can continue with
111 // polling the initial values. It is important to clear the old interrupts before this, so we don't clear any
112 // interrupts that are triggered after the polling, but before this tread is ready to process them.
113 //
114 // We put the code into a finally so it is always executed when the promiseFulfiller goes out of scope, even if
115 // there are exceptions in between.
116 //
117 auto promiseFulfiller = cppext::finally([&]() { subscriptionDonePromise.set_value(); });
118
119 // This also enables the interrupts if they are not active.
120 _uioAccess->clearInterrupts();
121
122 // Clearing active interrupts actually is only effective after a poll (inside waitForInterrupt)
123 if(_uioAccess->waitForInterrupt(0) > 0) {
124 _uioAccess->clearInterrupts();
125 }
126 } // end of the promiseFulfiller scope
127 catch(ChimeraTK::runtime_error& e) {
128 setException(e.what());
129 return;
130 }
131
132 while(!_stopInterruptLoop) {
133 try {
134 auto numberOfInterrupts = _uioAccess->waitForInterrupt(100);
135
136 if(numberOfInterrupts > 0) {
137 _uioAccess->clearInterrupts();
138
139 if(!isFunctional()) {
140 break;
141 }
142
143#ifdef _DEBUG_UIO
144 if(numberOfInterrupts > 1) {
145 std::cout << "UioBackend: Lost " << (numberOfInterrupts - 1) << " interrupts. " << std::endl;
146 }
147 std::cout << "dispatching interrupt " << std::endl;
148#endif
149
150 _asyncDomain->distribute(nullptr);
151 }
152 }
153 catch(ChimeraTK::runtime_error& ex) {
154 setException(ex.what());
155 break;
156 }
157 }
158 }
159
160} // namespace ChimeraTK
bool isFunctional() const noexcept final
Return whether a device is working as intended, usually this means it is opened and does not have any...
void setOpenedAndClearException() noexcept
Backends should call this function at the end of a (successful) open() call.
void setException(const std::string &message) noexcept final
Set the backend into an exception state.
void checkActiveException() final
Function to be called by backends when needing to check for an active exception.
bool isOpen() override
Return whether a device has been opened or not.
std::atomic< bool > _opened
flag if backend is opened
Base class for address-based device backends (e.g.
void close() final
Deactivates all asynchronous accessors and calls closeImpl().
static boost::shared_ptr< DeviceBackend > createInstance(std::string address, std::map< std::string, std::string > parameters)
Definition UioBackend.cc:19
void write(uint64_t bar, uint64_t address, int32_t const *data, size_t sizeInBytes) override
Write function to be implemented by backends.
Definition UioBackend.cc:70
void open() override
Open the device.
Definition UioBackend.cc:34
void closeImpl() override
All backends derrived from NumericAddressedBackend must implement closeImpl() instead of close.
Definition UioBackend.cc:46
void read(uint64_t bar, uint64_t address, int32_t *data, size_t sizeInBytes) override
Read function to be implemented by backends.
Definition UioBackend.cc:63
std::future< void > activateSubscription(uint32_t interruptNumber, boost::shared_ptr< async::DomainImpl< std::nullptr_t > > asyncDomain) override
Activate/create the subscription for a given interrupt (for instance by starting the according interr...
Definition UioBackend.cc:77
std::string readDeviceInfo() override
Return a device information string containing hardware details like the firmware version number or th...
Definition UioBackend.cc:98
boost::shared_ptr< async::DomainImpl< std::nullptr_t > > _asyncDomain
Definition UioBackend.h:44
UioBackend(const std::string &deviceName, const std::string &mapFileName, const std::string &dataConsistencyKeyDescriptor)
Definition UioBackend.cc:8
bool barIndexValid(uint64_t bar) override
Function to be implemented by the backends.
Definition UioBackend.cc:59
Exception thrown when a logic error has occured.
Definition Exception.h:51
Exception thrown when a runtime error has occured.
Definition Exception.h:18
const char * what() const noexcept override
Return the message describing what exactly went wrong.
Definition Exception.cpp:14
STL namespace.