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 :
45 : #include <algorithm> // for min
46 : #include <assert.h>
47 : #include <cstdlib>
48 : #include <fcntl.h>
49 : #include <iomanip> // for operator<<
50 : #include <iostream> // for operator<<
51 : #include <sys/mman.h>
52 : #include <sys/stat.h>
53 : #include <sys/file.h>
54 : #include <stdlib.h> // for size_t, free
55 : #include <string.h> // for memcpy
56 : #include <unistd.h>
57 :
58 : #include <chrono> // for operator>
59 : #include <thread> // for sleep_for
60 : #include <filesystem>
61 :
62 : #include "uhal/grammars/URI.hpp" // for URI
63 : #include "uhal/log/LogLevels.hpp" // for BaseLogLevel
64 : #include "uhal/log/log_inserters.integer.hpp" // for uhal::Integer
65 : #include "uhal/log/log_inserters.quote.hpp" // for uhal::Quote
66 : #include "uhal/log/log.hpp"
67 : #include "uhal/Buffers.hpp"
68 : #include "uhal/ClientFactory.hpp"
69 :
70 : #include "uhallibs/formatters.hpp"
71 :
72 : #include "regmap/regmap-struct.h"
73 :
74 : UHAL_REGISTER_EXTERNAL_CLIENT(uhallibs::Flx, "ipbusflx-2.0", "A client description")
75 :
76 :
77 : namespace uhallibs {
78 :
79 :
80 : //-----------------------------------------------------------------------------
81 0 : regmap_register_t* Flx::Card::find_reg( const std::string& aName ) {
82 :
83 0 : regmap_register_t *reg;
84 0 : for (reg = regmap_registers; reg->name != NULL; reg++) {
85 0 : if (aName == reg->name) {
86 0 : return reg;
87 : }
88 : }
89 :
90 : return nullptr;
91 : }
92 :
93 : //-----------------------------------------------------------------------------
94 0 : Flx::Card::Card(const std::string& aDevicePath, u_int aLockMask) :
95 0 : mPath(aDevicePath),
96 0 : mLockMask(aLockMask),
97 0 : mFlxCard(),
98 0 : mIsOpen(false) {
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 :
107 0 : }
108 :
109 0 : std::string device_id_str = aDevicePath.substr(prefix.size()).data();
110 0 : try {
111 0 : mDeviceId = std::stoi(device_id_str);
112 0 : } catch (std::invalid_argument const& ex) {
113 :
114 0 : exception::FlxInvalidDevice lExc;
115 0 : log(lExc, "Invalid device id ", uhal::Quote(mPath));
116 0 : throw lExc;
117 :
118 0 : }
119 0 : }
120 :
121 :
122 : //-----------------------------------------------------------------------------
123 0 : Flx::Card::~Card() {
124 0 : }
125 :
126 :
127 : //-----------------------------------------------------------------------------
128 0 : void Flx::Card::open() {
129 :
130 0 : log(uhal::Debug(), "Flx::Card client Opening felix endpoint ", mDeviceId, " on ", mPath);
131 :
132 0 : if( access( mPath.c_str(), F_OK ) == -1 ) {
133 :
134 0 : exception::FlxInitialisationError lExc;
135 0 : log(lExc, "Failed to open device file ", uhal::Quote(mPath), "; errno=", uhal::Integer(errno), ", meaning ", uhal::Quote (strerror(errno)));
136 0 : throw lExc;
137 0 : }
138 :
139 0 : mFd = ::open(mPath.c_str(), O_RDWR);
140 0 : if (mFd < 0) {
141 : return;
142 : }
143 :
144 0 : mFlxCard.card_open(mDeviceId, mLockMask);
145 :
146 0 : mIsOpen = true;
147 : }
148 :
149 :
150 : //-----------------------------------------------------------------------------
151 0 : void Flx::Card::close() {
152 :
153 0 : if (mIsOpen)
154 0 : mFlxCard.card_close();
155 :
156 0 : if (mFd != -1) {
157 0 : if (haveLock())
158 0 : unlock();
159 0 : int rc = ::close(mFd);
160 0 : mFd = -1;
161 0 : if (rc == -1)
162 0 : log (uhal::Error(), "Failed to close file ", uhal::Quote(mPath), "; errno=", uhal::Integer(errno), ", meaning ", uhal::Quote (strerror(errno)));
163 : }
164 0 : }
165 :
166 :
167 : //-----------------------------------------------------------------------------
168 0 : const std::string& Flx::Card::getPath() const {
169 0 : return mPath;
170 : }
171 :
172 : //-----------------------------------------------------------------------------
173 0 : int Flx::Card::getDeviceId() const {
174 0 : return mDeviceId;
175 : }
176 :
177 : //-----------------------------------------------------------------------------
178 0 : void Flx::Card::read(const uint32_t aAddr, const uint32_t aNrWords, std::vector<uint32_t>& aValues) {
179 :
180 0 : if (!mIsOpen)
181 0 : open();
182 :
183 0 : flxcard_bar2_regs_t *bar2 = (flxcard_bar2_regs_t *) mFlxCard.openBackDoor( 2 );
184 :
185 : // +1 is ceiling rounding in integers
186 0 : uint32_t lNrReads64b = (aNrWords+1)/2;
187 0 : uint32_t lAddr = aAddr/2;
188 :
189 0 : for ( uint32_t i(0); i<lNrReads64b; i++) {
190 : // *lReadAddrPtr = lAddr+i;
191 0 : bar2->IPBUS_READ_ADDRESS = lAddr+i;
192 : // uint64_t lDataWord = *lReadDataPtr;
193 0 : uint64_t lDataWord = bar2->IPBUS_READ_DATA;
194 : // Split the 64b word in 32b chunks
195 0 : aValues.push_back(lDataWord & 0xffffffff);
196 0 : if ( 2*i+1 < aNrWords )
197 0 : aValues.push_back(lDataWord >> 32);
198 : }
199 :
200 0 : log(uhal::Debug(), "Flx::Card::read, ", aNrWords, " requested, ", aValues.size(), " read");
201 :
202 0 : }
203 :
204 :
205 : //-----------------------------------------------------------------------------
206 0 : void Flx::Card::write(const uint32_t aAddr, const std::vector<std::pair<const uint8_t*, size_t> >& aData)
207 : {
208 :
209 0 : if (!mIsOpen)
210 0 : open();
211 :
212 0 : flxcard_bar2_regs_t *bar2 = (flxcard_bar2_regs_t *) mFlxCard.openBackDoor( 2 );
213 :
214 0 : size_t lNrBytes = 0;
215 0 : for (size_t i = 0; i < aData.size(); i++)
216 0 : lNrBytes += aData.at(i).second;
217 :
218 0 : assert((lNrBytes % 4) == 0);
219 :
220 0 : char *allocated = NULL;
221 0 : posix_memalign((void **)&allocated, 4096/*alignment*/, lNrBytes + 4096);
222 0 : if (allocated == NULL) {
223 0 : exception::FlxCommunicationError lExc;
224 0 : log(lExc, "Failed to allocate ", uhal::Integer(lNrBytes + 4096), " bytes in File::write/2 function");
225 0 : throw lExc;
226 0 : }
227 :
228 : // data to write to register address
229 : char* buffer = allocated;
230 : size_t lNrBytesCopied = 0;
231 0 : for (size_t i = 0; i < aData.size(); i++) {
232 0 : memcpy(buffer + lNrBytesCopied, aData.at(i).first, aData.at(i).second);
233 0 : lNrBytesCopied += aData.at(i).second;
234 : }
235 :
236 0 : lNrBytesCopied = 0;
237 0 : uint32_t lAddr = aAddr/2;
238 :
239 0 : while (lNrBytesCopied < lNrBytes) {
240 0 : bar2->IPBUS_WRITE_ADDRESS = lAddr;
241 0 : char* lSrcPtr = buffer + lNrBytesCopied;
242 0 : if ((lNrBytes - lNrBytesCopied) >= 8) {
243 0 : bar2->IPBUS_WRITE_DATA.DATA = *(uint64_t*) lSrcPtr;
244 0 : lNrBytesCopied += 8;
245 : }
246 0 : else if ((lNrBytes - lNrBytesCopied) >= 4) {
247 0 : bar2->IPBUS_WRITE_DATA.DATA = uint64_t(*(uint32_t*) lSrcPtr);
248 0 : lNrBytesCopied += 4;
249 : }
250 :
251 0 : ++lAddr;
252 : }
253 :
254 0 : free(allocated);
255 0 : }
256 :
257 0 : bool Flx::Card::haveLock() const { return mLocked; }
258 :
259 :
260 0 : void Flx::Card::lock() {
261 0 : if (flock(mFd, LOCK_EX) == -1) {
262 0 : ipc::exception::MutexError lExc;
263 0 : log(lExc, "Failed to lock device file ", uhal::Quote(mPath),
264 0 : "; errno=", uhal::Integer(errno), ", meaning ", uhal::Quote(strerror(errno)));
265 0 : throw lExc;
266 0 : }
267 0 : mLocked = true;
268 0 : }
269 :
270 0 : void Flx::Card::unlock() {
271 0 : if (flock(mFd, LOCK_UN) == -1) {
272 0 : log(uhal::Warning(), "Failed to unlock device file ", uhal::Quote(mPath),
273 0 : "; errno=", uhal::Integer(errno), ", meaning ", uhal::Quote(strerror(errno)));
274 : } else
275 0 : mLocked = false;
276 0 : }
277 :
278 :
279 : // Flx Transport
280 0 : std::string Flx::getSharedMemName(const std::string& aPath)
281 : {
282 0 : std::string lSanitizedPath(aPath);
283 0 : std::replace(lSanitizedPath.begin(), lSanitizedPath.end(), '/', ':');
284 :
285 0 : return "/uhal::ipbusflx-2.0::" + lSanitizedPath;
286 0 : }
287 :
288 :
289 0 : Flx::Flx ( const std::string& aId, const uhal::URI& aUri ) :
290 : IPbus< 2 , 0 > ( aId , aUri ),
291 0 : mConnected(false),
292 0 : mDeviceFile(aUri.mHostname, LOCK_NONE),
293 0 : mIPCMutex(getSharedMemName(aUri.mHostname)),
294 0 : mNumberOfPages(0),
295 0 : mPageSize(0),
296 0 : mIndexNextPage(0),
297 0 : mPublishedReplyPageCount(0),
298 0 : mReadReplyPageCount(0),
299 0 : mAsynchronousException ( NULL )
300 : {
301 0 : mSleepDuration = std::chrono::microseconds(50);
302 :
303 0 : for (uhal::NameValuePairVectorType::const_iterator lIt = aUri.mArguments.begin(); lIt != aUri.mArguments.end(); lIt++) {
304 0 : if (lIt->first == "sleep") {
305 0 : mSleepDuration = std::chrono::microseconds(std::stoul(lIt->second));
306 0 : log (uhal::Notice() , "flx client with URI ", uhal::Quote (uri()), " : Inter-poll-/-interrupt sleep duration set to ", std::stoul(lIt->second), " us by URI 'sleep' attribute");
307 : }
308 : // else if (lIt->first == "offset") {
309 : // const bool lIsHex = (lIt->second.find("0x") == 0) or (lIt->second.find("0X") == 0);
310 : // const size_t lOffset = (lIsHex ? std::lexical_cast<HexTo<size_t> >(lIt->second) : std::stoul(lIt->second));
311 : // mDeviceFile.setOffset(lOffset);
312 : // log (uhal::Notice(), "flx client with URI ", uhal::Quote (uri()), " : Address offset set to ", uhal::Integer(lOffset, IntFmt<hex>()));
313 : // }
314 : else {
315 0 : log (uhal::Warning() , "Unknown attribute ", uhal::Quote (lIt->first), " used in URI ", uhal::Quote(uri()));
316 : }
317 : }
318 0 : }
319 :
320 :
321 0 : Flx::~Flx()
322 : {
323 0 : disconnect();
324 0 : }
325 :
326 :
327 0 : void Flx::implementDispatch ( std::shared_ptr< uhal::Buffers > aBuffers )
328 : {
329 0 : log(uhal::Debug(), "flx client (URI: ", uhal::Quote(uri()), ") : implementDispatch method called");
330 :
331 0 : if ( ! mConnected )
332 0 : connect();
333 :
334 0 : if ( mReplyQueue.size() == mNumberOfPages )
335 0 : read();
336 0 : write(aBuffers);
337 0 : }
338 :
339 :
340 0 : void Flx::Flush( )
341 : {
342 0 : log(uhal::Debug(), "flx client (URI: ", uhal::Quote(uri()), ") : Flush method called");
343 0 : while ( !mReplyQueue.empty() )
344 0 : read();
345 :
346 0 : mDeviceFile.unlock();
347 :
348 0 : IPCScopedLock_t lLockGuard(*mIPCMutex);
349 0 : mIPCMutex->endSession();
350 :
351 0 : }
352 :
353 :
354 0 : void Flx::dispatchExceptionHandler()
355 : {
356 : // FIXME: Adapt to PCIe implementation
357 : // log(uhal::Notice(), "flx client ", uhal::Quote(id()), " (URI: ", uhal::Quote(uri()), ") : closing device files since exception detected");
358 :
359 : // ClientInterface::returnBufferToPool ( mReplyQueue );
360 :
361 0 : mDeviceFile.unlock();
362 :
363 0 : disconnect();
364 :
365 0 : InnerProtocol::dispatchExceptionHandler();
366 0 : }
367 :
368 :
369 0 : uint32_t Flx::getMaxSendSize()
370 : {
371 0 : if ( ! mConnected )
372 0 : connect();
373 :
374 0 : return (mPageSize - 1) * 4;
375 : }
376 :
377 :
378 0 : uint32_t Flx::getMaxReplySize()
379 : {
380 0 : if ( ! mConnected )
381 0 : connect();
382 :
383 0 : return (mPageSize - 1) * 4;
384 : }
385 :
386 :
387 0 : void Flx::connect()
388 : {
389 0 : IPCScopedLock_t lLockGuard(*mIPCMutex);
390 0 : connect(lLockGuard);
391 0 : }
392 :
393 :
394 0 : void Flx::connect(IPCScopedLock_t& aGuard)
395 : {
396 : // Read current value of session counter when reading status info from FPGA
397 : // (So that can check whether this info is up-to-date later on, when sending next request packet)
398 0 : mIPCExternalSessionActive = mIPCMutex->isActive() and (not mDeviceFile.haveLock());
399 0 : mIPCSessionCount = mIPCMutex->getCounter();
400 :
401 0 : log ( uhal::Debug() , "flx client is opening device file " , uhal::Quote ( mDeviceFile.getPath() ) );
402 0 : std::vector<uint32_t> lValues;
403 0 : mDeviceFile.read(0x0, 4, lValues);
404 0 : log (uhal::Debug(), "Read status info from addr 0 (", uhal::Integer(lValues.at(0)), ", ", uhal::Integer(lValues.at(1)), ", ", uhal::Integer(lValues.at(2)), ", ", uhal::Integer(lValues.at(3)), "): ", PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
405 0 : aGuard.unlock();
406 :
407 0 : mNumberOfPages = lValues.at(0);
408 : // mPageSize = std::min(uint32_t(4096), lValues.at(1));
409 0 : mPageSize = lValues.at(1);
410 0 : mIndexNextPage = lValues.at(2);
411 0 : mPublishedReplyPageCount = lValues.at(3);
412 0 : mReadReplyPageCount = mPublishedReplyPageCount;
413 :
414 0 : if (lValues.at(1) > 0xFFFF) {
415 0 : exception::FlxInitialisationError lExc;
416 0 : log (lExc, "Invalid page size, ", uhal::Integer(lValues.at(1)), ", reported in device file ", uhal::Quote(mDeviceFile.getPath()));
417 0 : throw lExc;
418 0 : }
419 :
420 0 : if (mIndexNextPage >= mNumberOfPages) {
421 0 : exception::FlxInitialisationError lExc;
422 0 : log (lExc, "Next page index, ", uhal::Integer(mIndexNextPage), ", reported in device file ", uhal::Quote(mDeviceFile.getPath()), " is inconsistent with number of pages, ", uhal::Integer(mNumberOfPages));
423 0 : throw lExc;
424 0 : }
425 :
426 0 : mConnected = true;
427 0 : log ( uhal::Info() , "flx client connected to device at ", uhal::Quote(mDeviceFile.getPath()), "; FPGA has ", uhal::Integer(mNumberOfPages), " pages, each of size ", uhal::Integer(mPageSize), " words, index ", uhal::Integer(mIndexNextPage), " should be filled next" );
428 0 : }
429 :
430 :
431 0 : void Flx::disconnect()
432 : {
433 0 : log ( uhal::Debug() , "flx client is closing device file " , uhal::Quote ( mDeviceFile.getPath() ) );
434 0 : mDeviceFile.close();
435 0 : mConnected = false;
436 0 : }
437 :
438 :
439 0 : void Flx::write(const std::shared_ptr<uhal::Buffers>& aBuffers)
440 : {
441 0 : if (not mDeviceFile.haveLock()) {
442 0 : mDeviceFile.lock();
443 :
444 0 : IPCScopedLock_t lGuard(*mIPCMutex);
445 0 : mIPCMutex->startSession();
446 0 : mIPCSessionCount++;
447 :
448 0 : if (mIPCExternalSessionActive or (mIPCMutex->getCounter() != mIPCSessionCount)) {
449 0 : connect(lGuard);
450 : }
451 0 : }
452 :
453 0 : log (uhal::Info(), "flx client ", uhal::Quote(id()), " (URI: ", uhal::Quote(uri()), ") : writing ", uhal::Integer(aBuffers->sendCounter() / 4), "-word packet to page ", uhal::Integer(mIndexNextPage), " in ", uhal::Quote(mDeviceFile.getPath()));
454 :
455 0 : const uint32_t lHeaderWord = (0x10000 | (((aBuffers->sendCounter() / 4) - 1) & 0xFFFF));
456 0 : std::vector<std::pair<const uint8_t*, size_t> > lDataToWrite;
457 0 : lDataToWrite.push_back( std::make_pair(reinterpret_cast<const uint8_t*>(&lHeaderWord), sizeof lHeaderWord) );
458 0 : lDataToWrite.push_back( std::make_pair(aBuffers->getSendBuffer(), aBuffers->sendCounter()) );
459 :
460 0 : IPCScopedLock_t lGuard(*mIPCMutex);
461 0 : mDeviceFile.write(mIndexNextPage * mPageSize, lDataToWrite);
462 0 : log (uhal::Debug(), "Wrote " , uhal::Integer((aBuffers->sendCounter() / 4) + 1), " 32-bit words at address " , uhal::Integer(mIndexNextPage * 4 * mPageSize), " ... ", PacketFmt(lDataToWrite));
463 :
464 0 : mIndexNextPage = (mIndexNextPage + 1) % mNumberOfPages;
465 0 : mReplyQueue.push_back(aBuffers);
466 0 : }
467 :
468 :
469 0 : void Flx::read()
470 : {
471 0 : const size_t lPageIndexToRead = (mIndexNextPage - mReplyQueue.size() + mNumberOfPages) % mNumberOfPages;
472 0 : SteadyClock_t::time_point lStartTime = SteadyClock_t::now();
473 :
474 0 : if (mReadReplyPageCount == mPublishedReplyPageCount)
475 : {
476 0 : uint32_t lHwPublishedPageCount = 0x0;
477 :
478 0 : std::vector<uint32_t> lValues;
479 0 : while ( true ) {
480 0 : IPCScopedLock_t lGuard(*mIPCMutex);
481 : // FIXME : Improve by simply adding dmaWrite method that takes uint32_t ref as argument (or returns uint32_t)
482 0 : mDeviceFile.read(0, 4, lValues);
483 0 : lHwPublishedPageCount = lValues.at(3);
484 : // log (uhal::Info(), "Read status info from addr 0 (", uhal::Integer(lValues.at(0)), ", ", uhal::Integer(lValues.at(1)), ", ", uhal::Integer(lValues.at(2)), ", ", uhal::Integer(lValues.at(3)), "): ", PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
485 0 : log (uhal::Debug(), "Read status info from addr 0 (", uhal::Integer(lValues.at(0)), ", ", uhal::Integer(lValues.at(1)), ", ", uhal::Integer(lValues.at(2)), ", ", uhal::Integer(lValues.at(3)), "): ", PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
486 :
487 0 : if (lHwPublishedPageCount != mPublishedReplyPageCount) {
488 0 : mPublishedReplyPageCount = lHwPublishedPageCount;
489 0 : break;
490 : }
491 : // FIXME: Throw if published page count is invalid number
492 :
493 0 : if (SteadyClock_t::now() - lStartTime > std::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
494 0 : exception::FlxTimeout lExc;
495 0 : log(lExc, "Next page (index ", uhal::Integer(lPageIndexToRead), " count ", uhal::Integer(mPublishedReplyPageCount+1), ") of flx device '" + mDeviceFile.getPath() + "' is not ready after timeout period");
496 0 : throw lExc;
497 0 : }
498 :
499 0 : log(uhal::Debug(), "flx client ", uhal::Quote(id()), " (URI: ", uhal::Quote(uri()), ") : Trying to read page index ", uhal::Integer(lPageIndexToRead), " = count ", uhal::Integer(mReadReplyPageCount+1), "; published page count is ", uhal::Integer(lHwPublishedPageCount), "; sleeping for ", mSleepDuration.count(), "us");
500 0 : if (mSleepDuration > std::chrono::microseconds(0))
501 0 : std::this_thread::sleep_for( mSleepDuration );
502 0 : lValues.clear();
503 0 : }
504 :
505 0 : log(uhal::Info(), "flx client ", uhal::Quote(id()), " (URI: ", uhal::Quote(uri()), ") : Reading page ", uhal::Integer(lPageIndexToRead), " (published count ", uhal::Integer(lHwPublishedPageCount), ", surpasses required, ", uhal::Integer(mReadReplyPageCount + 1), ")");
506 0 : }
507 0 : mReadReplyPageCount++;
508 :
509 : // PART 1 : Read the page
510 0 : std::shared_ptr<uhal::Buffers> lBuffers = mReplyQueue.front();
511 0 : mReplyQueue.pop_front();
512 :
513 0 : uint32_t lNrWordsToRead(lBuffers->replyCounter() >> 2);
514 0 : lNrWordsToRead += 1;
515 :
516 0 : std::vector<uint32_t> lPageContents;
517 0 : IPCScopedLock_t lGuard(*mIPCMutex);
518 0 : mDeviceFile.read(4 + lPageIndexToRead * mPageSize, lNrWordsToRead , lPageContents);
519 0 : lGuard.unlock();
520 0 : log (uhal::Debug(), "Read " , uhal::Integer(lNrWordsToRead), " 32-bit words from address " , uhal::Integer(4 + lPageIndexToRead * 4 * mPageSize), " ... ", PacketFmt((const uint8_t*)lPageContents.data(), 4 * lPageContents.size()));
521 :
522 : // PART 2 : Transfer to reply buffer
523 0 : const std::deque< std::pair< uint8_t* , uint32_t > >& lReplyBuffers ( lBuffers->getReplyBuffer() );
524 0 : size_t lNrWordsInPacket = (lPageContents.at(0) >> 16) + (lPageContents.at(0) & 0xFFFF);
525 0 : if (lNrWordsInPacket != (lBuffers->replyCounter() >> 2))
526 0 : log (uhal::Warning(), "Expected reply packet to contain ", uhal::Integer(lBuffers->replyCounter() >> 2), " words, but it actually contains ", uhal::Integer(lNrWordsInPacket), " words");
527 :
528 0 : size_t lNrBytesCopied = 0;
529 0 : for ( std::deque< std::pair< uint8_t* , uint32_t > >::const_iterator lIt = lReplyBuffers.begin() ; lIt != lReplyBuffers.end() ; ++lIt )
530 : {
531 : // Don't copy more of page than was written to, for cases when less data received than expected
532 0 : if ( lNrBytesCopied >= 4*lNrWordsInPacket)
533 : break;
534 :
535 0 : size_t lNrBytesToCopy = std::min( lIt->second , uint32_t(4*lNrWordsInPacket - lNrBytesCopied) );
536 0 : memcpy ( lIt->first, &lPageContents.at(1 + (lNrBytesCopied / 4)), lNrBytesToCopy );
537 0 : lNrBytesCopied += lNrBytesToCopy;
538 : }
539 :
540 :
541 : // PART 3 : Validate the packet contents
542 0 : try
543 : {
544 0 : if ( uhal::exception::exception* lExc = ClientInterface::validate ( lBuffers ) ) //Control of the pointer has been passed back to the client interface
545 : {
546 0 : mAsynchronousException = lExc;
547 : }
548 : }
549 0 : catch ( uhal::exception::exception& aExc )
550 : {
551 0 : mAsynchronousException = new uhal::exception::ValidationError ();
552 0 : log ( *mAsynchronousException , "Exception caught during reply validation for flx device with URI " , uhal::Quote ( this->uri() ) , "; what returned: " , uhal::Quote ( aExc.what() ) );
553 0 : }
554 :
555 0 : if ( mAsynchronousException )
556 : {
557 0 : mAsynchronousException->throwAsDerivedType();
558 : }
559 0 : }
560 :
561 :
562 : } // end ns uhal
|