ChimeraTK-DeviceAccess 03.27.00
Loading...
Searching...
No Matches
SubdeviceRegisterAccessor.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
5
6#include <utility>
7
8namespace ChimeraTK {
9
10 /********************************************************************************************************************/
11
12 SubdeviceRegisterAccessor::SubdeviceRegisterAccessor(boost::shared_ptr<SubdeviceBackend> backend,
13 const std::string& registerPathName, boost::shared_ptr<NDRegisterAccessor<int32_t>> accAddress,
14 boost::shared_ptr<NDRegisterAccessor<int32_t>> accData, boost::shared_ptr<NDRegisterAccessor<int32_t>> accStatus,
15 size_t byteOffset, size_t numberOfWords)
16 : NDRegisterAccessor<int32_t>(registerPathName, {AccessMode::raw}), _backend(std::move(backend)),
17 _accAddress(std::move(accAddress)), _accDataArea(std::move(accData)), _accStatus(std::move(accStatus)),
18 _startAddress(byteOffset), _numberOfWords(numberOfWords) {
20 NDRegisterAccessor<int32_t>::buffer_2D[0].resize(numberOfWords);
21 _buffer.resize(numberOfWords);
22 }
23
24 /********************************************************************************************************************/
25
27 assert(false); // must never be called due to exception in doPreRead
28 }
29
30 /********************************************************************************************************************/
31
33 assert(_backend->_mutex);
34 std::lock_guard<std::mutex> lockGuard(*(_backend->_mutex));
35 size_t nTransfers;
37 // for areaHandshake case with 1D array
38 // TODO FIXME shouldn't this be nTransfers = 1 ???
39 nTransfers = _numberOfWords;
40 }
41 else {
44 // This is "_numberOfWords / _accData->getNumberOfSamples()" rounded up:
45 nTransfers = (_numberOfWords + _accDataArea->getNumberOfSamples() - 1) / _accDataArea->getNumberOfSamples();
46 }
47 try {
48 size_t idx = 0;
49 for(size_t adr = _startAddress; adr < _startAddress + nTransfers; ++adr) {
50 // write address register (if applicable)
52 _accAddress->accessData(0) = static_cast<int32_t>(adr);
53 _accAddress->write();
54 usleep(_backend->_addressToDataDelay);
55 }
56
57 // write data register
59 int32_t val = (idx < _numberOfWords) ? _buffer[idx] : 0;
60 _accDataArea->accessData(0, idx) = val;
61 ++idx;
62 }
63 else {
64 for(size_t innerOffset = 0; innerOffset < _accDataArea->getNumberOfSamples(); ++innerOffset) {
65 // pad data with zeros, if _numberOfWords isn't an integer multiple of _accData->getNumberOfSamples()
66 int32_t val = (idx < _numberOfWords) ? _buffer[idx] : 0;
67 _accDataArea->accessData(0, innerOffset) = val;
68 ++idx;
69 }
70 }
71 _accDataArea->write();
72
73 // wait until transaction is complete
76 // for 3regs/areaHandshake, wait until status register is 0 again
77 size_t retry = 0;
78 size_t max_retry = _backend->_timeout * 1000 / _backend->_sleepTime;
79 while(true) {
80 usleep(_backend->_sleepTime);
81 _accStatus->read();
82 if(_accStatus->accessData(0) == 0) {
83 break;
84 }
85 if(++retry > max_retry) {
86 throw ChimeraTK::runtime_error("Write to register '" + _name +
87 "' failed: timeout waiting for cleared busy flag (" + _accStatus->getName() + ")");
88 }
89 }
90 }
91 else {
92 // for 2regs, wait given time
93 usleep(_backend->_sleepTime);
94 }
95 }
96 }
97 catch(ChimeraTK::runtime_error& ex) {
98 _exceptionBackend->setException(ex.what());
99 throw;
100 }
101 return false;
102 }
103
104 /********************************************************************************************************************/
105
107 throw ChimeraTK::logic_error("Reading this register is not supported.");
108 }
109
110 /********************************************************************************************************************/
111
113 throw ChimeraTK::logic_error("Reading this register is not supported.");
114 }
115
116 /********************************************************************************************************************/
117
119 if(!_backend->isOpen()) {
120 throw ChimeraTK::logic_error("Device is not opened.");
121 }
122
123 if(_accAddress && !_accAddress->isWriteable()) {
124 throw ChimeraTK::logic_error("SubdeviceRegisterAccessor[" + this->getName() + "]: address register '" +
125 _accAddress->getName() + "' is not writeable.");
126 }
127 if(!_accDataArea->isWriteable()) {
128 throw ChimeraTK::logic_error("SubdeviceRegisterAccessor[" + this->getName() + "]: data/area register '" +
129 _accDataArea->getName() + "' is not writeable.");
130 }
131 if(_backend->needStatusParam()) {
132 if(!_accStatus->isReadable()) {
133 throw ChimeraTK::logic_error("SubdeviceRegisterAccessor[" + this->getName() + "]: status register '" +
134 _accStatus->getName() + "' is not readable.");
135 }
136 }
137
138 assert(NDRegisterAccessor<int32_t>::buffer_2D[0].size() == _buffer.size());
141 }
142
143 /********************************************************************************************************************/
144
148
149 /********************************************************************************************************************/
150
151 bool SubdeviceRegisterAccessor::mayReplaceOther(const boost::shared_ptr<TransferElement const>&) const {
152 return false;
153 }
154
155 /********************************************************************************************************************/
156
158 return false;
159 }
160
161 /********************************************************************************************************************/
162
164 return false;
165 }
166
167 /********************************************************************************************************************/
168
170 return true;
171 }
172
173 /********************************************************************************************************************/
174
175 std::vector<boost::shared_ptr<TransferElement>> SubdeviceRegisterAccessor::getHardwareAccessingElements() {
176 return {boost::enable_shared_from_this<TransferElement>::shared_from_this()};
177 }
178
179 /********************************************************************************************************************/
180
181 std::list<boost::shared_ptr<TransferElement>> SubdeviceRegisterAccessor::getInternalElements() {
183 // _accStatus is nullptr for twoReg
184 return {_accAddress, _accDataArea};
185 }
187 }
188
189 /********************************************************************************************************************/
190
191 void SubdeviceRegisterAccessor::replaceTransferElement(boost::shared_ptr<TransferElement>) {}
192
193} // namespace ChimeraTK
N-dimensional register accessor.
boost::shared_ptr< NDRegisterAccessor< int32_t > > _accDataArea
std::vector< int32_t > _buffer
internal buffer
SubdeviceRegisterAccessor(boost::shared_ptr< SubdeviceBackend > backend, const std::string &registerPathName, boost::shared_ptr< NDRegisterAccessor< int32_t > > accAddress, boost::shared_ptr< NDRegisterAccessor< int32_t > > accDataArea, boost::shared_ptr< NDRegisterAccessor< int32_t > > accStatus, size_t byteOffset, size_t numberOfWords)
bool isReadOnly() const override
Check if transfer element is read only, i.e.
void doReadTransferSynchronously() override
Implementation version of readTransfer() for synchronous reads.
size_t _startAddress
start address and length
void replaceTransferElement(boost::shared_ptr< TransferElement > newElement) override
Search for all underlying TransferElements which are considered identical (see sameRegister()) with t...
void doPostRead(TransferType type, bool hasNewData) override
Backend specific implementation of postRead().
std::list< boost::shared_ptr< TransferElement > > getInternalElements() override
Obtain the full list of TransferElements internally used by this TransferElement.
bool isWriteable() const override
Check if transfer element is writeable.
boost::shared_ptr< SubdeviceBackend > _backend
Pointer to the backend.
boost::shared_ptr< NDRegisterAccessor< int32_t > > _accAddress
Pointers to the three accessors.
bool isReadable() const override
Check if transfer element is readable.
bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber) override
Implementation version of writeTransfer().
void doPreRead(TransferType type) override
Backend specific implementation of preRead().
std::vector< boost::shared_ptr< TransferElement > > getHardwareAccessingElements() override
Obtain the underlying TransferElements with actual hardware access.
bool mayReplaceOther(const boost::shared_ptr< TransferElement const > &) const override
Check whether the TransferElement can be used in places where the TransferElement "other" is currentl...
void doPreWrite(TransferType type, VersionNumber) override
Backend specific implementation of preWrite().
void doPostWrite(TransferType type, VersionNumber) override
Backend specific implementation of postWrite().
boost::shared_ptr< NDRegisterAccessor< int32_t > > _accStatus
void setDataValidity(DataValidity validity=DataValidity::ok)
Set the current DataValidity for this TransferElement.
std::string _name
Identifier uniquely identifying the TransferElement.
DataValidity _dataValidity
The validity of the data in the application buffer.
const std::string & getName() const
Returns the name that identifies the process variable.
boost::shared_ptr< DeviceBackend > _exceptionBackend
The backend to which the runtime_errors are reported via DeviceBackend::setException().
Class for generating and holding version numbers without exposing a numeric representation.
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
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
TransferType
Used to indicate the applicable operation on a Transferelement.