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