Line data Source code
1 : /*
2 : ---------------------------------------------------------------------------
3 :
4 : This file is part of uHAL.
5 :
6 : uHAL is a hardware access library and programming framework
7 : originally developed for upgrades of the Level-1 trigger of the CMS
8 : experiment at CERN.
9 :
10 : uHAL is free software: you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation, either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : uHAL is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with uHAL. If not, see <http://www.gnu.org/licenses/>.
22 :
23 :
24 : Andrew Rose, Imperial College, London
25 : email: awr01 <AT> imperial.ac.uk
26 :
27 : Marc Magrans de Abril, CERN
28 : email: marc.magrans.de.abril <AT> cern.ch
29 :
30 : Tom Williams, Rutherford Appleton Laboratory, Oxfordshire
31 : email: tom.williams <AT> cern.ch
32 :
33 : ---------------------------------------------------------------------------
34 : */
35 :
36 : /**
37 : @file
38 : @author Alessandro Thea
39 : @date September 2019
40 : */
41 :
42 : #include "uhallibs/ProtocolFlx.hpp"
43 :
44 : #include <algorithm> // for min
45 : #include <assert.h>
46 : #include <cstdlib>
47 : #include <fcntl.h>
48 : #include <iomanip> // for operator<<
49 : #include <iostream> // for operator<<
50 : #include <stdlib.h> // for size_t, free
51 : #include <string.h> // for memcpy
52 : #include <sys/file.h>
53 : #include <sys/mman.h>
54 : #include <sys/stat.h>
55 : #include <unistd.h>
56 :
57 : #include <chrono> // for operator>
58 : #include <filesystem>
59 : #include <thread> // for sleep_for
60 :
61 : #include "uhal/Buffers.hpp"
62 : #include "uhal/ClientFactory.hpp"
63 : #include "uhal/grammars/URI.hpp" // for URI
64 : #include "uhal/log/LogLevels.hpp" // for BaseLogLevel
65 : #include "uhal/log/log.hpp"
66 : #include "uhal/log/log_inserters.integer.hpp" // for uhal::Integer
67 : #include "uhal/log/log_inserters.quote.hpp" // for uhal::Quote
68 :
69 : #include "uhallibs/formatters.hpp"
70 :
71 : #include "regmap/regmap-struct.h"
72 :
73 : UHAL_REGISTER_EXTERNAL_CLIENT(uhallibs::Flx, "ipbusflx-2.0", "A client description")
74 :
75 : namespace uhallibs {
76 :
77 : //-----------------------------------------------------------------------------
78 : regmap_register_t*
79 0 : Flx::Card::find_reg(const std::string& aName)
80 : {
81 :
82 0 : regmap_register_t* reg;
83 0 : for (reg = regmap_registers; reg->name != NULL; reg++) {
84 0 : if (aName == reg->name) {
85 : return reg;
86 : }
87 : }
88 :
89 : return nullptr;
90 : }
91 :
92 : //-----------------------------------------------------------------------------
93 0 : Flx::Card::Card(const std::string& aDevicePath, u_int aLockMask)
94 0 : : mPath(aDevicePath)
95 0 : , mLockMask(aLockMask)
96 0 : , mFlxCard()
97 0 : , mIsOpen(false)
98 : {
99 :
100 0 : const std::string prefix("/dev/flx");
101 0 : if (aDevicePath.rfind(prefix, 0) != 0) {
102 :
103 0 : exception::FlxInvalidDevice lExc;
104 0 : log(lExc, "Invalid device path ", uhal::Quote(mPath));
105 0 : throw lExc;
106 0 : }
107 :
108 0 : std::string device_id_str = aDevicePath.substr(prefix.size()).data();
109 0 : try {
110 0 : mDeviceId = std::stoi(device_id_str);
111 0 : } catch (std::invalid_argument const& ex) {
112 :
113 0 : exception::FlxInvalidDevice lExc;
114 0 : log(lExc, "Invalid device id ", uhal::Quote(mPath));
115 0 : throw lExc;
116 0 : }
117 0 : }
118 :
119 : //-----------------------------------------------------------------------------
120 0 : Flx::Card::~Card() {}
121 :
122 : //-----------------------------------------------------------------------------
123 : void
124 0 : Flx::Card::open()
125 : {
126 :
127 0 : log(uhal::Debug(), "Flx::Card client Opening felix endpoint ", mDeviceId, " on ", mPath);
128 :
129 0 : if (access(mPath.c_str(), F_OK) == -1) {
130 :
131 0 : exception::FlxInitialisationError lExc;
132 0 : log(lExc,
133 : "Failed to open device file ",
134 0 : uhal::Quote(mPath),
135 : "; errno=",
136 0 : uhal::Integer(errno),
137 : ", meaning ",
138 0 : uhal::Quote(strerror(errno)));
139 0 : throw lExc;
140 0 : }
141 :
142 0 : mFd = ::open(mPath.c_str(), O_RDWR);
143 0 : if (mFd < 0) {
144 : return;
145 : }
146 :
147 0 : mFlxCard.card_open(mDeviceId, mLockMask);
148 :
149 0 : mIsOpen = true;
150 : }
151 :
152 : //-----------------------------------------------------------------------------
153 : void
154 0 : Flx::Card::close()
155 : {
156 :
157 0 : if (mIsOpen)
158 0 : mFlxCard.card_close();
159 :
160 0 : if (mFd != -1) {
161 0 : if (haveLock())
162 0 : unlock();
163 0 : int rc = ::close(mFd);
164 0 : mFd = -1;
165 0 : if (rc == -1)
166 0 : log(uhal::Error(),
167 : "Failed to close file ",
168 0 : uhal::Quote(mPath),
169 : "; errno=",
170 0 : uhal::Integer(errno),
171 : ", meaning ",
172 0 : uhal::Quote(strerror(errno)));
173 : }
174 0 : }
175 :
176 : //-----------------------------------------------------------------------------
177 : const std::string&
178 0 : Flx::Card::getPath() const
179 : {
180 0 : return mPath;
181 : }
182 :
183 : //-----------------------------------------------------------------------------
184 : int
185 0 : Flx::Card::getDeviceId() const
186 : {
187 0 : return mDeviceId;
188 : }
189 :
190 : //-----------------------------------------------------------------------------
191 : void
192 0 : Flx::Card::read(const uint32_t aAddr, const uint32_t aNrWords, std::vector<uint32_t>& aValues)
193 : {
194 :
195 0 : if (!mIsOpen)
196 0 : open();
197 :
198 0 : flxcard_bar2_regs_t* bar2 = (flxcard_bar2_regs_t*)mFlxCard.openBackDoor(2);
199 :
200 : // +1 is ceiling rounding in integers
201 0 : uint32_t lNrReads64b = (aNrWords + 1) / 2;
202 0 : uint32_t lAddr = aAddr / 2;
203 :
204 0 : for (uint32_t i(0); i < lNrReads64b; i++) {
205 : // *lReadAddrPtr = lAddr+i;
206 0 : bar2->IPBUS_READ_ADDRESS = lAddr + i;
207 : // uint64_t lDataWord = *lReadDataPtr;
208 0 : uint64_t lDataWord = bar2->IPBUS_READ_DATA;
209 : // Split the 64b word in 32b chunks
210 0 : aValues.push_back(lDataWord & 0xffffffff);
211 0 : if (2 * i + 1 < aNrWords)
212 0 : aValues.push_back(lDataWord >> 32);
213 : }
214 :
215 0 : log(uhal::Debug(), "Flx::Card::read, ", aNrWords, " requested, ", aValues.size(), " read");
216 0 : }
217 :
218 : //-----------------------------------------------------------------------------
219 : void
220 0 : Flx::Card::write(const uint32_t aAddr, const std::vector<std::pair<const uint8_t*, size_t>>& aData)
221 : {
222 :
223 0 : if (!mIsOpen)
224 0 : open();
225 :
226 0 : flxcard_bar2_regs_t* bar2 = (flxcard_bar2_regs_t*)mFlxCard.openBackDoor(2);
227 :
228 0 : size_t lNrBytes = 0;
229 0 : for (size_t i = 0; i < aData.size(); i++)
230 0 : lNrBytes += aData.at(i).second;
231 :
232 0 : assert((lNrBytes % 4) == 0);
233 :
234 0 : char* allocated = NULL;
235 0 : posix_memalign((void**)&allocated, 4096 /*alignment*/, lNrBytes + 4096);
236 0 : if (allocated == NULL) {
237 0 : exception::FlxCommunicationError lExc;
238 0 : log(lExc, "Failed to allocate ", uhal::Integer(lNrBytes + 4096), " bytes in File::write/2 function");
239 0 : throw lExc;
240 0 : }
241 :
242 : // data to write to register address
243 : char* buffer = allocated;
244 : size_t lNrBytesCopied = 0;
245 0 : for (size_t i = 0; i < aData.size(); i++) {
246 0 : memcpy(buffer + lNrBytesCopied, aData.at(i).first, aData.at(i).second);
247 0 : lNrBytesCopied += aData.at(i).second;
248 : }
249 :
250 0 : lNrBytesCopied = 0;
251 0 : uint32_t lAddr = aAddr / 2;
252 :
253 0 : while (lNrBytesCopied < lNrBytes) {
254 0 : bar2->IPBUS_WRITE_ADDRESS = lAddr;
255 0 : char* lSrcPtr = buffer + lNrBytesCopied;
256 0 : if ((lNrBytes - lNrBytesCopied) >= 8) {
257 0 : bar2->IPBUS_WRITE_DATA.DATA = *(uint64_t*)lSrcPtr;
258 0 : lNrBytesCopied += 8;
259 0 : } else if ((lNrBytes - lNrBytesCopied) >= 4) {
260 0 : bar2->IPBUS_WRITE_DATA.DATA = uint64_t(*(uint32_t*)lSrcPtr);
261 0 : lNrBytesCopied += 4;
262 : }
263 :
264 0 : ++lAddr;
265 : }
266 :
267 0 : free(allocated);
268 0 : }
269 :
270 : bool
271 0 : Flx::Card::haveLock() const
272 : {
273 0 : return mLocked;
274 : }
275 :
276 : void
277 0 : Flx::Card::lock()
278 : {
279 0 : if (flock(mFd, LOCK_EX) == -1) {
280 0 : ipc::exception::MutexError lExc;
281 0 : log(lExc,
282 : "Failed to lock device file ",
283 0 : uhal::Quote(mPath),
284 : "; errno=",
285 0 : uhal::Integer(errno),
286 : ", meaning ",
287 0 : uhal::Quote(strerror(errno)));
288 0 : throw lExc;
289 0 : }
290 0 : mLocked = true;
291 0 : }
292 :
293 : void
294 0 : Flx::Card::unlock()
295 : {
296 0 : if (flock(mFd, LOCK_UN) == -1) {
297 0 : log(uhal::Warning(),
298 : "Failed to unlock device file ",
299 0 : uhal::Quote(mPath),
300 : "; errno=",
301 0 : uhal::Integer(errno),
302 : ", meaning ",
303 0 : uhal::Quote(strerror(errno)));
304 : } else
305 0 : mLocked = false;
306 0 : }
307 :
308 : // Flx Transport
309 : std::string
310 0 : Flx::getSharedMemName(const std::string& aPath)
311 : {
312 0 : std::string lSanitizedPath(aPath);
313 0 : std::replace(lSanitizedPath.begin(), lSanitizedPath.end(), '/', ':');
314 :
315 0 : return "/uhal::ipbusflx-2.0::" + lSanitizedPath;
316 0 : }
317 :
318 0 : Flx::Flx(const std::string& aId, const uhal::URI& aUri)
319 : : IPbus<2, 0>(aId, aUri)
320 0 : , mConnected(false)
321 0 : , mDeviceFile(aUri.mHostname, LOCK_NONE)
322 0 : , mIPCMutex(getSharedMemName(aUri.mHostname))
323 0 : , mNumberOfPages(0)
324 0 : , mPageSize(0)
325 0 : , mIndexNextPage(0)
326 0 : , mPublishedReplyPageCount(0)
327 0 : , mReadReplyPageCount(0)
328 0 : , mAsynchronousException(NULL)
329 : {
330 0 : mSleepDuration = std::chrono::microseconds(50);
331 :
332 0 : for (uhal::NameValuePairVectorType::const_iterator lIt = aUri.mArguments.begin(); lIt != aUri.mArguments.end();
333 0 : lIt++) {
334 0 : if (lIt->first == "sleep") {
335 0 : mSleepDuration = std::chrono::microseconds(std::stoul(lIt->second));
336 0 : log(uhal::Notice(),
337 : "flx client with URI ",
338 0 : uhal::Quote(uri()),
339 : " : Inter-poll-/-interrupt sleep duration set to ",
340 0 : std::stoul(lIt->second),
341 : " us by URI 'sleep' attribute");
342 : }
343 : // else if (lIt->first == "offset") {
344 : // const bool lIsHex = (lIt->second.find("0x") == 0) or (lIt->second.find("0X") == 0);
345 : // const size_t lOffset = (lIsHex ? std::lexical_cast<HexTo<size_t> >(lIt->second) : std::stoul(lIt->second));
346 : // mDeviceFile.setOffset(lOffset);
347 : // log (uhal::Notice(), "flx client with URI ", uhal::Quote (uri()), " : Address offset set to ",
348 : // uhal::Integer(lOffset, IntFmt<hex>()));
349 : // }
350 : else {
351 0 : log(uhal::Warning(), "Unknown attribute ", uhal::Quote(lIt->first), " used in URI ", uhal::Quote(uri()));
352 : }
353 : }
354 0 : }
355 :
356 0 : Flx::~Flx()
357 : {
358 0 : disconnect();
359 0 : }
360 :
361 : void
362 0 : Flx::implementDispatch(std::shared_ptr<uhal::Buffers> aBuffers)
363 : {
364 0 : log(uhal::Debug(), "flx client (URI: ", uhal::Quote(uri()), ") : implementDispatch method called");
365 :
366 0 : if (!mConnected)
367 0 : connect();
368 :
369 0 : if (mReplyQueue.size() == mNumberOfPages)
370 0 : read();
371 0 : write(aBuffers);
372 0 : }
373 :
374 : void
375 0 : Flx::Flush()
376 : {
377 0 : log(uhal::Debug(), "flx client (URI: ", uhal::Quote(uri()), ") : Flush method called");
378 0 : while (!mReplyQueue.empty())
379 0 : read();
380 :
381 0 : mDeviceFile.unlock();
382 :
383 0 : IPCScopedLock_t lLockGuard(*mIPCMutex);
384 0 : mIPCMutex->endSession();
385 0 : }
386 :
387 : void
388 0 : Flx::dispatchExceptionHandler()
389 : {
390 : // FIXME: Adapt to PCIe implementation
391 : // log(uhal::Notice(), "flx client ", uhal::Quote(id()), " (URI: ", uhal::Quote(uri()), ") : closing device files
392 : // since exception detected");
393 :
394 : // ClientInterface::returnBufferToPool ( mReplyQueue );
395 :
396 0 : mDeviceFile.unlock();
397 :
398 0 : disconnect();
399 :
400 0 : InnerProtocol::dispatchExceptionHandler();
401 0 : }
402 :
403 : uint32_t
404 0 : Flx::getMaxSendSize()
405 : {
406 0 : if (!mConnected)
407 0 : connect();
408 :
409 0 : return (mPageSize - 1) * 4;
410 : }
411 :
412 : uint32_t
413 0 : Flx::getMaxReplySize()
414 : {
415 0 : if (!mConnected)
416 0 : connect();
417 :
418 0 : return (mPageSize - 1) * 4;
419 : }
420 :
421 : void
422 0 : Flx::connect()
423 : {
424 0 : IPCScopedLock_t lLockGuard(*mIPCMutex);
425 0 : connect(lLockGuard);
426 0 : }
427 :
428 : void
429 0 : Flx::connect(IPCScopedLock_t& aGuard)
430 : {
431 : // Read current value of session counter when reading status info from FPGA
432 : // (So that can check whether this info is up-to-date later on, when sending next request packet)
433 0 : mIPCExternalSessionActive = mIPCMutex->isActive() and (not mDeviceFile.haveLock());
434 0 : mIPCSessionCount = mIPCMutex->getCounter();
435 :
436 0 : log(uhal::Debug(), "flx client is opening device file ", uhal::Quote(mDeviceFile.getPath()));
437 0 : std::vector<uint32_t> lValues;
438 0 : mDeviceFile.read(0x0, 4, lValues);
439 0 : log(uhal::Debug(),
440 : "Read status info from addr 0 (",
441 0 : uhal::Integer(lValues.at(0)),
442 : ", ",
443 0 : uhal::Integer(lValues.at(1)),
444 : ", ",
445 0 : uhal::Integer(lValues.at(2)),
446 : ", ",
447 0 : uhal::Integer(lValues.at(3)),
448 : "): ",
449 0 : PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
450 0 : aGuard.unlock();
451 :
452 0 : mNumberOfPages = lValues.at(0);
453 : // mPageSize = std::min(uint32_t(4096), lValues.at(1));
454 0 : mPageSize = lValues.at(1);
455 0 : mIndexNextPage = lValues.at(2);
456 0 : mPublishedReplyPageCount = lValues.at(3);
457 0 : mReadReplyPageCount = mPublishedReplyPageCount;
458 :
459 0 : if (lValues.at(1) > 0xFFFF) {
460 0 : exception::FlxInitialisationError lExc;
461 0 : log(lExc,
462 : "Invalid page size, ",
463 0 : uhal::Integer(lValues.at(1)),
464 : ", reported in device file ",
465 0 : uhal::Quote(mDeviceFile.getPath()));
466 0 : throw lExc;
467 0 : }
468 :
469 0 : if (mIndexNextPage >= mNumberOfPages) {
470 0 : exception::FlxInitialisationError lExc;
471 0 : log(lExc,
472 : "Next page index, ",
473 0 : uhal::Integer(mIndexNextPage),
474 : ", reported in device file ",
475 0 : uhal::Quote(mDeviceFile.getPath()),
476 : " is inconsistent with number of pages, ",
477 0 : uhal::Integer(mNumberOfPages));
478 0 : throw lExc;
479 0 : }
480 :
481 0 : mConnected = true;
482 0 : log(uhal::Info(),
483 : "flx client connected to device at ",
484 0 : uhal::Quote(mDeviceFile.getPath()),
485 : "; FPGA has ",
486 0 : uhal::Integer(mNumberOfPages),
487 : " pages, each of size ",
488 0 : uhal::Integer(mPageSize),
489 : " words, index ",
490 0 : uhal::Integer(mIndexNextPage),
491 : " should be filled next");
492 0 : }
493 :
494 : void
495 0 : Flx::disconnect()
496 : {
497 0 : log(uhal::Debug(), "flx client is closing device file ", uhal::Quote(mDeviceFile.getPath()));
498 0 : mDeviceFile.close();
499 0 : mConnected = false;
500 0 : }
501 :
502 : void
503 0 : Flx::write(const std::shared_ptr<uhal::Buffers>& aBuffers)
504 : {
505 0 : if (not mDeviceFile.haveLock()) {
506 0 : mDeviceFile.lock();
507 :
508 0 : IPCScopedLock_t lGuard(*mIPCMutex);
509 0 : mIPCMutex->startSession();
510 0 : mIPCSessionCount++;
511 :
512 0 : if (mIPCExternalSessionActive or (mIPCMutex->getCounter() != mIPCSessionCount)) {
513 0 : connect(lGuard);
514 : }
515 0 : }
516 :
517 0 : log(uhal::Info(),
518 : "flx client ",
519 0 : uhal::Quote(id()),
520 : " (URI: ",
521 0 : uhal::Quote(uri()),
522 : ") : writing ",
523 0 : uhal::Integer(aBuffers->sendCounter() / 4),
524 : "-word packet to page ",
525 0 : uhal::Integer(mIndexNextPage),
526 : " in ",
527 0 : uhal::Quote(mDeviceFile.getPath()));
528 :
529 0 : const uint32_t lHeaderWord = (0x10000 | (((aBuffers->sendCounter() / 4) - 1) & 0xFFFF));
530 0 : std::vector<std::pair<const uint8_t*, size_t>> lDataToWrite;
531 0 : lDataToWrite.push_back(std::make_pair(reinterpret_cast<const uint8_t*>(&lHeaderWord), sizeof lHeaderWord));
532 0 : lDataToWrite.push_back(std::make_pair(aBuffers->getSendBuffer(), aBuffers->sendCounter()));
533 :
534 0 : IPCScopedLock_t lGuard(*mIPCMutex);
535 0 : mDeviceFile.write(mIndexNextPage * mPageSize, lDataToWrite);
536 0 : log(uhal::Debug(),
537 : "Wrote ",
538 0 : uhal::Integer((aBuffers->sendCounter() / 4) + 1),
539 : " 32-bit words at address ",
540 0 : uhal::Integer(mIndexNextPage * 4 * mPageSize),
541 : " ... ",
542 0 : PacketFmt(lDataToWrite));
543 :
544 0 : mIndexNextPage = (mIndexNextPage + 1) % mNumberOfPages;
545 0 : mReplyQueue.push_back(aBuffers);
546 0 : }
547 :
548 : void
549 0 : Flx::read()
550 : {
551 0 : const size_t lPageIndexToRead = (mIndexNextPage - mReplyQueue.size() + mNumberOfPages) % mNumberOfPages;
552 0 : SteadyClock_t::time_point lStartTime = SteadyClock_t::now();
553 :
554 0 : if (mReadReplyPageCount == mPublishedReplyPageCount) {
555 0 : uint32_t lHwPublishedPageCount = 0x0;
556 :
557 0 : std::vector<uint32_t> lValues;
558 0 : while (true) {
559 0 : IPCScopedLock_t lGuard(*mIPCMutex);
560 : // FIXME : Improve by simply adding dmaWrite method that takes uint32_t ref as argument (or returns uint32_t)
561 0 : mDeviceFile.read(0, 4, lValues);
562 0 : lHwPublishedPageCount = lValues.at(3);
563 : // log (uhal::Info(), "Read status info from addr 0 (", uhal::Integer(lValues.at(0)), ", ",
564 : // uhal::Integer(lValues.at(1)), ", ", uhal::Integer(lValues.at(2)), ", ", uhal::Integer(lValues.at(3)), "): ",
565 : // PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
566 0 : log(uhal::Debug(),
567 : "Read status info from addr 0 (",
568 0 : uhal::Integer(lValues.at(0)),
569 : ", ",
570 0 : uhal::Integer(lValues.at(1)),
571 : ", ",
572 0 : uhal::Integer(lValues.at(2)),
573 : ", ",
574 0 : uhal::Integer(lValues.at(3)),
575 : "): ",
576 0 : PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
577 :
578 0 : if (lHwPublishedPageCount != mPublishedReplyPageCount) {
579 0 : mPublishedReplyPageCount = lHwPublishedPageCount;
580 0 : break;
581 : }
582 : // FIXME: Throw if published page count is invalid number
583 :
584 0 : if (SteadyClock_t::now() - lStartTime > std::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
585 0 : exception::FlxTimeout lExc;
586 0 : log(lExc,
587 : "Next page (index ",
588 0 : uhal::Integer(lPageIndexToRead),
589 : " count ",
590 0 : uhal::Integer(mPublishedReplyPageCount + 1),
591 0 : ") of flx device '" + mDeviceFile.getPath() + "' is not ready after timeout period");
592 0 : throw lExc;
593 0 : }
594 :
595 0 : log(uhal::Debug(),
596 : "flx client ",
597 0 : uhal::Quote(id()),
598 : " (URI: ",
599 0 : uhal::Quote(uri()),
600 : ") : Trying to read page index ",
601 0 : uhal::Integer(lPageIndexToRead),
602 : " = count ",
603 0 : uhal::Integer(mReadReplyPageCount + 1),
604 : "; published page count is ",
605 0 : uhal::Integer(lHwPublishedPageCount),
606 : "; sleeping for ",
607 0 : mSleepDuration.count(),
608 : "us");
609 0 : if (mSleepDuration > std::chrono::microseconds(0))
610 0 : std::this_thread::sleep_for(mSleepDuration);
611 0 : lValues.clear();
612 0 : }
613 :
614 0 : log(uhal::Info(),
615 : "flx client ",
616 0 : uhal::Quote(id()),
617 : " (URI: ",
618 0 : uhal::Quote(uri()),
619 : ") : Reading page ",
620 0 : uhal::Integer(lPageIndexToRead),
621 : " (published count ",
622 0 : uhal::Integer(lHwPublishedPageCount),
623 : ", surpasses required, ",
624 0 : uhal::Integer(mReadReplyPageCount + 1),
625 : ")");
626 0 : }
627 0 : mReadReplyPageCount++;
628 :
629 : // PART 1 : Read the page
630 0 : std::shared_ptr<uhal::Buffers> lBuffers = mReplyQueue.front();
631 0 : mReplyQueue.pop_front();
632 :
633 0 : uint32_t lNrWordsToRead(lBuffers->replyCounter() >> 2);
634 0 : lNrWordsToRead += 1;
635 :
636 0 : std::vector<uint32_t> lPageContents;
637 0 : IPCScopedLock_t lGuard(*mIPCMutex);
638 0 : mDeviceFile.read(4 + lPageIndexToRead * mPageSize, lNrWordsToRead, lPageContents);
639 0 : lGuard.unlock();
640 0 : log(uhal::Debug(),
641 : "Read ",
642 0 : uhal::Integer(lNrWordsToRead),
643 : " 32-bit words from address ",
644 0 : uhal::Integer(4 + lPageIndexToRead * 4 * mPageSize),
645 : " ... ",
646 0 : PacketFmt((const uint8_t*)lPageContents.data(), 4 * lPageContents.size()));
647 :
648 : // PART 2 : Transfer to reply buffer
649 0 : const std::deque<std::pair<uint8_t*, uint32_t>>& lReplyBuffers(lBuffers->getReplyBuffer());
650 0 : size_t lNrWordsInPacket = (lPageContents.at(0) >> 16) + (lPageContents.at(0) & 0xFFFF);
651 0 : if (lNrWordsInPacket != (lBuffers->replyCounter() >> 2))
652 0 : log(uhal::Warning(),
653 : "Expected reply packet to contain ",
654 0 : uhal::Integer(lBuffers->replyCounter() >> 2),
655 : " words, but it actually contains ",
656 0 : uhal::Integer(lNrWordsInPacket),
657 : " words");
658 :
659 0 : size_t lNrBytesCopied = 0;
660 0 : for (std::deque<std::pair<uint8_t*, uint32_t>>::const_iterator lIt = lReplyBuffers.begin();
661 0 : lIt != lReplyBuffers.end();
662 0 : ++lIt) {
663 : // Don't copy more of page than was written to, for cases when less data received than expected
664 0 : if (lNrBytesCopied >= 4 * lNrWordsInPacket)
665 : break;
666 :
667 0 : size_t lNrBytesToCopy = std::min(lIt->second, uint32_t(4 * lNrWordsInPacket - lNrBytesCopied));
668 0 : memcpy(lIt->first, &lPageContents.at(1 + (lNrBytesCopied / 4)), lNrBytesToCopy);
669 0 : lNrBytesCopied += lNrBytesToCopy;
670 : }
671 :
672 : // PART 3 : Validate the packet contents
673 0 : try {
674 0 : if (uhal::exception::exception* lExc =
675 0 : ClientInterface::validate(lBuffers)) // Control of the pointer has been passed back to the client interface
676 : {
677 0 : mAsynchronousException = lExc;
678 : }
679 0 : } catch (uhal::exception::exception& aExc) {
680 0 : mAsynchronousException = new uhal::exception::ValidationError();
681 0 : log(*mAsynchronousException,
682 : "Exception caught during reply validation for flx device with URI ",
683 0 : uhal::Quote(this->uri()),
684 : "; what returned: ",
685 0 : uhal::Quote(aExc.what()));
686 0 : }
687 :
688 0 : if (mAsynchronousException) {
689 0 : mAsynchronousException->throwAsDerivedType();
690 : }
691 0 : }
692 :
693 : } // end ns uhal
|