ChimeraTK-DeviceAccess 03.25.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 std::lock_guard<decltype(_backend->mutex)> lockGuard(_backend->mutex);
34 size_t nTransfers;
36 // for areaHandshake case with 1D array
37 // TODO FIXME shouldn't this be nTransfers = 1 ???
38 nTransfers = _numberOfWords;
39 }
40 else {
43 // This is "_numberOfWords / _accData->getNumberOfSamples()" rounded up:
44 nTransfers = (_numberOfWords + _accDataArea->getNumberOfSamples() - 1) / _accDataArea->getNumberOfSamples();
45 }
46 try {
47 size_t idx = 0;
48 for(size_t adr = _startAddress; adr < _startAddress + nTransfers; ++adr) {
49 // write address register (if applicable)
51 _accAddress->accessData(0) = static_cast<int32_t>(adr);
52 _accAddress->write();
53 usleep(_backend->addressToDataDelay);
54 }
55
56 // write data register
58 int32_t val = (idx < _numberOfWords) ? _buffer[idx] : 0;
59 _accDataArea->accessData(0, idx) = val;
60 ++idx;
61 }
62 else {
63 for(size_t innerOffset = 0; innerOffset < _accDataArea->getNumberOfSamples(); ++innerOffset) {
64 // pad data with zeros, if _numberOfWords isn't an integer multiple of _accData->getNumberOfSamples()
65 int32_t val = (idx < _numberOfWords) ? _buffer[idx] : 0;
66 _accDataArea->accessData(0, innerOffset) = val;
67 ++idx;
68 }
69 }
70 _accDataArea->write();
71
72 // wait until transaction is complete
75 // for 3regs/areaHandshake, wait until status register is 0 again
76 size_t retry = 0;
77 size_t max_retry = _backend->timeout * 1000 / _backend->sleepTime;
78 while(true) {
79 usleep(_backend->sleepTime);
80 _accStatus->read();
81 if(_accStatus->accessData(0) == 0) break;
82 if(++retry > max_retry) {
83 throw ChimeraTK::runtime_error("Write to register '" + _name +
84 "' failed: timeout waiting for cleared busy flag (" + _accStatus->getName() + ")");
85 }
86 }
87 }
88 else {
89 // for 2regs, wait given time
90 usleep(_backend->sleepTime);
91 }
92 }
93 }
94 catch(ChimeraTK::runtime_error& ex) {
95 _exceptionBackend->setException(ex.what());
96 throw;
97 }
98 return false;
99 }
100
101 /********************************************************************************************************************/
102
104 throw ChimeraTK::logic_error("Reading this register is not supported.");
105 }
106
107 /********************************************************************************************************************/
108
110 throw ChimeraTK::logic_error("Reading this register is not supported.");
111 }
112
113 /********************************************************************************************************************/
114
116 if(!_backend->isOpen()) {
117 throw ChimeraTK::logic_error("Device is not opened.");
118 }
119
120 if(_accAddress && !_accAddress->isWriteable()) {
121 throw ChimeraTK::logic_error("SubdeviceRegisterAccessor[" + this->getName() + "]: address register '" +
122 _accAddress->getName() + "' is not writeable.");
123 }
124 if(!_accDataArea->isWriteable()) {
125 throw ChimeraTK::logic_error("SubdeviceRegisterAccessor[" + this->getName() + "]: data/area register '" +
126 _accDataArea->getName() + "' is not writeable.");
127 }
128 if(_backend->needStatusParam()) {
129 if(!_accStatus->isReadable()) {
130 throw ChimeraTK::logic_error("SubdeviceRegisterAccessor[" + this->getName() + "]: status register '" +
131 _accStatus->getName() + "' is not readable.");
132 }
133 }
134
135 assert(NDRegisterAccessor<int32_t>::buffer_2D[0].size() == _buffer.size());
138 }
139
140 /********************************************************************************************************************/
141
145
146 /********************************************************************************************************************/
147
148 bool SubdeviceRegisterAccessor::mayReplaceOther(const boost::shared_ptr<TransferElement const>&) const {
149 return false;
150 }
151
152 /********************************************************************************************************************/
153
155 return false;
156 }
157
158 /********************************************************************************************************************/
159
161 return false;
162 }
163
164 /********************************************************************************************************************/
165
167 return true;
168 }
169
170 /********************************************************************************************************************/
171
172 std::vector<boost::shared_ptr<TransferElement>> SubdeviceRegisterAccessor::getHardwareAccessingElements() {
173 return {boost::enable_shared_from_this<TransferElement>::shared_from_this()};
174 }
175
176 /********************************************************************************************************************/
177
178 std::list<boost::shared_ptr<TransferElement>> SubdeviceRegisterAccessor::getInternalElements() {
180 // _accStatus is nullptr for twoReg
181 return {_accAddress, _accDataArea};
182 }
184 }
185
186 /********************************************************************************************************************/
187
188 void SubdeviceRegisterAccessor::replaceTransferElement(boost::shared_ptr<TransferElement>) {}
189
190} // 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.