14 boost::shared_ptr<SubdeviceBackend> backend,
const std::string& registerPathName,
size_t numberOfWords,
15 size_t wordOffsetInRegister)
17 _numberOfWords(numberOfWords) {
18 auto& targetDevice = _backend->_targetDevice;
19 auto& parameters = _backend->_parameters;
20 if(!parameters[
"chipSelectRegister"].empty()) {
21 _accChipSelect.replace(targetDevice->getRegisterAccessor<uint64_t>(parameters[
"chipSelectRegister"], 1, 0, {}));
23 _accAddress.replace(targetDevice->getRegisterAccessor<uint64_t>(parameters[
"address"], 1, 0, {}));
24 if(!parameters[
"writeData"].empty()) {
25 _accWriteData.replace(targetDevice->getRegisterAccessor<ReadWriteDataType>(parameters[
"writeData"], 0, 0, {}));
27 else if(!parameters[
"data"].empty()) {
28 _accWriteData.replace(targetDevice->getRegisterAccessor<ReadWriteDataType>(parameters[
"data"], 0, 0, {}));
31 if(!parameters[
"busy"].empty()) {
32 _accBusy.replace(targetDevice->getRegisterAccessor<
ChimeraTK::Boolean>(parameters[
"busy"], 1, 0, {}));
34 else if(!parameters[
"status"].empty()) {
35 _accBusy.replace(targetDevice->getRegisterAccessor<
ChimeraTK::Boolean>(parameters[
"status"], 1, 0, {}));
38 if(!parameters[
"readData"].empty()) {
39 _accReadRequest.replace(targetDevice->getRegisterAccessor<
ChimeraTK::Void>(parameters[
"readRequest"], 1, 0, {}));
40 _accReadData.replace(targetDevice->getRegisterAccessor<ReadWriteDataType>(parameters[
"readData"], 0, 0, {}));
43 auto info = _backend->_registerMap.getBackendRegister(registerPathName);
44 _startAddress = info.address + info.elementPitchBits / 8 * wordOffsetInRegister;
48 if(_accReadData.isInitialised() && _accWriteData.isInitialised() &&
49 _accReadData.getNElements() != _accWriteData.getNElements()) {
51 "SubDeviceBackend: In RegisterWindow mode, read and write data register must have the same size!");
54 NDRegisterAccessor<RegisterRawType>::buffer_2D.resize(1);
55 NDRegisterAccessor<RegisterRawType>::buffer_2D[0].resize(numberOfWords);
56 _buffer.resize(numberOfWords);
58 _endAddress = _startAddress + _numberOfWords *
sizeof(RegisterRawType);
59 if(_accWriteData.isInitialised()) {
60 _transferSize =
sizeof(ReadWriteDataType) * _accWriteData.getNElements();
63 assert(_accReadData.isInitialised());
64 _transferSize =
sizeof(ReadWriteDataType) * _accReadData.getNElements();
69 _starTransferAddress = _startAddress / _transferSize;
71 _endTransferAddress = (_endAddress + _transferSize - 1) / _transferSize;
73 _zeros.assign(_transferSize, std::byte{0});
94 assert(_backend->_mutex);
95 std::lock_guard<std::mutex> lockGuard(*(_backend->_mutex));
98 if(_accChipSelect.isInitialised()) {
99 _accChipSelect.setAndWrite(_backend->_chipIndex);
102 size_t bufferCopyOffset = 0;
103 for(
size_t adr = _starTransferAddress; adr < _endTransferAddress; ++adr) {
105 auto thisTransfersStartAddress = adr * _transferSize;
106 auto thisTransfersEndAddress = thisTransfersStartAddress + _transferSize;
107 auto copyStartAddress = std::max(thisTransfersStartAddress, _startAddress);
108 auto copyEndAddress = std::min(thisTransfersEndAddress, _endAddress);
109 auto copyNBytes = copyEndAddress - copyStartAddress;
112 auto deviceAccessorCopyOffset =
113 (_startAddress > thisTransfersStartAddress ? _startAddress - thisTransfersStartAddress : 0);
116 auto* bufferStart =
reinterpret_cast<std::byte*
>(_buffer.data());
119 _accAddress.setAndWrite(adr);
120 usleep(_backend->_addressToDataDelay);
122 if(direction == TransferDirection::write) {
124 auto* accessorStart =
reinterpret_cast<std::byte*
>(_accWriteData.data());
129 if(deviceAccessorCopyOffset > 0) {
130 memcpy(accessorStart, _zeros.data(), deviceAccessorCopyOffset);
133 memcpy(accessorStart + deviceAccessorCopyOffset, bufferStart + bufferCopyOffset, copyNBytes);
136 if(copyEndAddress < thisTransfersEndAddress) {
137 memcpy(accessorStart + deviceAccessorCopyOffset + copyNBytes, _zeros.data(),
138 thisTransfersEndAddress - copyEndAddress);
141 _accWriteData.write();
144 assert(direction == TransferDirection::read);
145 _accReadRequest.write();
149 if(_accBusy.isInitialised()) {
152 size_t max_retry = _backend->_timeout * 1000 / _backend->_sleepTime;
154 usleep(_backend->_sleepTime);
155 if(!_accBusy.readAndGet()) {
158 if(++retry > max_retry) {
160 "' failed: timeout waiting for cleared busy flag (" + _accBusy.getName() +
")");
166 usleep(_backend->_sleepTime);
169 if(direction == TransferDirection::read) {
172 auto* accessorStart =
reinterpret_cast<std::byte*
>(_accReadData.data());
173 memcpy(bufferStart + bufferCopyOffset, accessorStart + deviceAccessorCopyOffset, copyNBytes);
176 bufferCopyOffset += copyNBytes;
180 this->_exceptionBackend->setException(ex.
what());
189 if(!_backend->isOpen()) {
195 "SubdeviceRegisterWindowAccessor[" + this->getName() +
"]: Register is not readable");
201 if(_accAddress.isInitialised() && !_accAddress.isWriteable()) {
202 throw ChimeraTK::logic_error(
"SubdeviceRegisterWindowAccessor[" + this->getName() +
"]: address register '" +
203 _accAddress.getName() +
"' is not writeable.");
205 if(!_accReadData.isReadable()) {
206 throw ChimeraTK::logic_error(
"SubdeviceRegisterWindowAccessor[" + this->getName() +
"]: read data register '" +
207 _accReadData.getName() +
"' is not readable.");
209 if(_accBusy.isInitialised() && !_accBusy.isReadable()) {
210 throw ChimeraTK::logic_error(
"SubdeviceRegisterWindowAccessor[" + this->getName() +
"]: status register '" +
211 _accBusy.getName() +
"' is not readable.");
213 assert(_accReadRequest.isInitialised());
214 if(!_accReadRequest.isWriteable()) {
215 throw ChimeraTK::logic_error(
"SubdeviceRegisterWindowAccessor[" + this->getName() +
"]: read request register '" +
216 _accReadRequest.getName() +
"' is not readable.");
323 WriteDataType>::getInternalElements() {
324 std::list<boost::shared_ptr<TransferElement>> retval = {_accAddress.getImpl()};
326 if(_accWriteData.isInitialised()) {
327 retval.emplace_back(_accWriteData.getImpl());
329 if(_accBusy.isInitialised()) {
330 retval.emplace_back(_accBusy.getImpl());
332 if(_accChipSelect.isInitialised()) {
333 retval.emplace_back(_accChipSelect.getImpl());
335 if(_accReadRequest.isInitialised()) {
336 retval.emplace_back(_accReadRequest.getImpl());
338 if(_accReadData.isInitialised()) {
339 retval.emplace_back(_accReadData.getImpl());