μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ProtocolPCIe.cpp
Go to the documentation of this file.
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
42#include "uhal/ProtocolPCIe.hpp"
43
44
45#include <algorithm> // for min
46#include <assert.h>
47#include <chrono>
48#include <cstdlib>
49#include <errno.h>
50#include <fcntl.h>
51#include <iomanip> // for operator<<
52#include <iostream> // for operator<<
53#include <sys/file.h>
54#include <sys/stat.h>
55#include <stdlib.h> // for size_t, free
56#include <stdio.h>
57#include <string.h> // for memcpy
58#include <thread>
59#include <unistd.h>
60
61#include <boost/lexical_cast.hpp>
62#include <boost/date_time/posix_time/posix_time_types.hpp> // for time_dura...
63
65#include "uhal/grammars/URI.hpp" // for URI
66#include "uhal/log/LogLevels.hpp" // for BaseLogLevel
67#include "uhal/log/log_inserters.integer.hpp" // for Integer
68#include "uhal/log/log_inserters.quote.hpp" // for Quote
69#include "uhal/log/log.hpp"
70#include "uhal/Buffers.hpp"
72
73
74namespace uhal {
75
76PCIe::File::File(const std::string& aPath, int aFlags) :
77 mPath(aPath),
78 mFd(-1),
79 mFlags(aFlags),
80 mLocked(false),
81 mBufferSize(0),
82 mBuffer(NULL)
83{
84}
85
86
88{
89 free(mBuffer);
90 close();
91}
92
93
94const std::string& PCIe::File::getPath() const
95{
96 return mPath;
97}
98
99
100void PCIe::File::setPath(const std::string& aPath)
101{
102 mPath = aPath;
103}
104
105
107{
108 if (mFd != -1)
109 return;
110
111 mFd = ::open(mPath.c_str(), mFlags);
112 if ( mFd == -1 ) {
113 exception::PCIeInitialisationError lExc;
114 log(lExc, "Failed to open device file ", Quote(mPath), "; errno=", Integer(errno), ", meaning ", Quote (strerror(errno)));
115 throw lExc;
116 }
117}
118
119
121{
122 if (mFd != -1) {
123 if (haveLock())
124 unlock();
125 int rc = ::close(mFd);
126 mFd = -1;
127 if (rc == -1)
128 log (Error(), "Failed to close file ", Quote(mPath), "; errno=", Integer(errno), ", meaning ", Quote (strerror(errno)));
129 }
130}
131
132
133
134void PCIe::File::createBuffer(const size_t aNrBytes)
135{
136 if (mBuffer != NULL) {
137 if (mBufferSize >= aNrBytes)
138 return;
139 else {
140 free(mBuffer);
141 mBuffer = NULL;
142 mBufferSize = 0;
143 }
144 }
145
146 posix_memalign((void**)&mBuffer, 4096/*alignment*/, aNrBytes + 4096);
147 if (mBuffer == NULL) {
148 exception::PCIeCommunicationError lExc;
149 log(lExc, "Failed to allocate ", Integer(aNrBytes + 4096), " bytes in PCIe::File::createBuffer");
150 throw lExc;
151 }
152
153 mBufferSize=aNrBytes+4096;
154}
155
156
157void PCIe::File::read(const uint32_t aAddr, const uint32_t aNrWords, std::vector<uint32_t>& aValues)
158{
159 if (mFd == -1)
160 open();
161
162 createBuffer(4 * aNrWords);
163
164 /* select AXI MM address */
165 off_t off = lseek(mFd, 4*aAddr, SEEK_SET);
166 if ( off != off_t(4 * aAddr)) {
167 exception::PCIeCommunicationError lExc;
168 log(lExc, "Offset returned by lseek, ", Integer(off), ", does not match that requested, ", Integer(4*aAddr), " (in preparation for read of ", Integer(aNrWords), " words)");
169 throw lExc;
170 }
171
172 /* read data from AXI MM into buffer using SGDMA */
173 int rc = ::read(mFd, mBuffer, 4*aNrWords);
174 if (rc == -1) {
175 exception::PCIeCommunicationError lExc;
176 log(lExc, "Read of ", Integer(4*aNrWords), " bytes at address ", Integer(4 * aAddr), " failed! errno=", Integer(errno), ", meaning ", Quote (strerror(errno)));
177 throw lExc;
178 }
179 else if (size_t(rc) < 4*aNrWords) {
180 exception::PCIeCommunicationError lExc;
181 log(lExc, "Only ", Integer(rc), " bytes transferred in read of ", Integer(4*aNrWords), " bytes at address ", Integer(4 * aAddr));
182 throw lExc;
183 }
184
185 aValues.insert(aValues.end(), reinterpret_cast<uint32_t*>(mBuffer), reinterpret_cast<uint32_t*>(mBuffer)+ aNrWords);
186}
187
188
189void PCIe::File::write(const uint32_t aAddr, const std::vector<uint32_t>& aValues)
190{
191 write(4 * aAddr, reinterpret_cast<const uint8_t*>(aValues.data()), 4 * aValues.size());
192}
193
194
195void PCIe::File::write(const uint32_t aAddr, const uint8_t* const aPtr, const size_t aNrBytes)
196{
197 if (mFd == -1)
198 open();
199
200 assert((aNrBytes % 4) == 0);
201
202 createBuffer(aNrBytes);
203
204 // data to write to register address
205 memcpy(mBuffer, aPtr, aNrBytes);
206
207 /* select AXI MM address */
208 off_t off = lseek(mFd, aAddr, SEEK_SET);
209 if ( off != off_t(aAddr)) {
210 struct stat st;
211 if (fstat(mFd, &st) or (not S_ISFIFO(st.st_mode))) {
212 exception::PCIeCommunicationError lExc;
213 log(lExc, "Offset returned by lseek, ", Integer(off), ", does not match that requested, ", Integer(aAddr), " (in preparation for write of ", Integer(aNrBytes), " bytes)");
214 throw lExc;
215 }
216 }
217
218 /* write buffer to AXI MM address using SGDMA */
219 int rc = ::write(mFd, mBuffer, aNrBytes);
220 if (rc == -1) {
221 exception::PCIeCommunicationError lExc;
222 log(lExc, "Write of ", Integer(aNrBytes), " bytes at address ", Integer(aAddr), " failed! errno=", Integer(errno), ", meaning ", Quote (strerror(errno)));
223 throw lExc;
224 }
225 else if (size_t(rc) < aNrBytes) {
226 exception::PCIeCommunicationError lExc;
227 log(lExc, "Only ", Integer(rc), " bytes transferred in write of ", Integer(aNrBytes), " bytes at address ", Integer(aAddr));
228 throw lExc;
229 }
230}
231
232
233void PCIe::File::write(const uint32_t aAddr, const std::vector<std::pair<const uint8_t*, size_t> >& aData)
234{
235 if (mFd == -1)
236 open();
237
238 size_t lNrBytes = 0;
239 for (size_t i = 0; i < aData.size(); i++)
240 lNrBytes += aData.at(i).second;
241
242 assert((lNrBytes % 4) == 0);
243
244 createBuffer(lNrBytes);
245
246 // data to write to register address
247 size_t lNrBytesCopied = 0;
248 for (size_t i = 0; i < aData.size(); i++) {
249 memcpy(mBuffer + lNrBytesCopied, aData.at(i).first, aData.at(i).second);
250 lNrBytesCopied += aData.at(i).second;
251 }
252
253 /* select AXI MM address */
254 off_t off = lseek(mFd, aAddr, SEEK_SET);
255 if ( off != off_t(aAddr)) {
256 struct stat st;
257 if (fstat(mFd, &st) or (not S_ISFIFO(st.st_mode))) {
258 exception::PCIeCommunicationError lExc;
259 log(lExc, "Offset returned by lseek, ", Integer(off), ", does not match that requested, ", Integer(aAddr), " (in preparation for write of ", Integer(lNrBytes), " bytes)");
260 throw lExc;
261 }
262 }
263
264 /* write buffer to AXI MM address using SGDMA */
265 int rc = ::write(mFd, mBuffer, lNrBytes);
266 if (rc == -1) {
267 exception::PCIeCommunicationError lExc;
268 log(lExc, "Write of ", Integer(lNrBytes), " bytes at address ", Integer(aAddr), " failed! errno=", Integer(errno), ", meaning ", Quote (strerror(errno)));
269 throw lExc;
270 }
271 else if (size_t(rc) < lNrBytes) {
272 exception::PCIeCommunicationError lExc;
273 log(lExc, "Only ", Integer(rc), " bytes transferred in write of ", Integer(lNrBytes), " bytes at address ", Integer(aAddr));
274 throw lExc;
275 }
276}
277
278
280{
281 return mLocked;
282}
283
284
286{
287 if ( flock(mFd, LOCK_EX) == -1 ) {
288 detail::MutexError lExc;
289 log(lExc, "Failed to lock device file ", Quote(mPath), "; errno=", Integer(errno), ", meaning ", Quote (strerror(errno)));
290 throw lExc;
291 }
292 mLocked = true;
293}
294
295
297{
298 if ( flock(mFd, LOCK_UN) == -1 ) {
299 log(Warning(), "Failed to unlock device file ", Quote(mPath), "; errno=", Integer(errno), ", meaning ", Quote (strerror(errno)));
300 }
301 else
302 mLocked = false;
303}
304
305
306std::string PCIe::getSharedMemName(const std::string& aPath)
307{
308 std::string lSanitizedPath(aPath);
309 std::replace(lSanitizedPath.begin(), lSanitizedPath.end(), '/', ':');
310
311 return "/uhal::ipbuspcie-2.0::" + lSanitizedPath;
312}
313
314
315PCIe::PCIe ( const std::string& aId, const URI& aUri ) :
316 IPbus< 2 , 0 > ( aId , aUri ),
317 mConnected(false),
318 mDeviceFileHostToFPGA(aUri.mHostname.substr(0, aUri.mHostname.find(",")), O_RDWR ),
319 mDeviceFileFPGAToHost(aUri.mHostname.substr(aUri.mHostname.find(",")+1), O_RDWR | O_NONBLOCK /* for read might need O_RDWR | O_NONBLOCK */),
320 mDeviceFileFPGAEvent("", O_RDONLY),
323 mUseInterrupt(false),
325 mMaxInFlight(0),
326 mPageSize(0),
331{
332 if ( aUri.mHostname.find(",") == std::string::npos ) {
333 exception::PCIeInitialisationError lExc;
334 log(lExc, "No comma found in hostname of PCIe client URI '" + uri() + "'; cannot construct 2 paths for device files");
335 throw lExc;
336 }
337 else if ( aUri.mHostname.find(",") == 0 || aUri.mHostname.find(",") == aUri.mHostname.size()-1) {
338 exception::PCIeInitialisationError lExc;
339 log(lExc, "Hostname of PCIe client URI '" + uri() + "' starts/ends with a comma; cannot construct 2 paths for device files");
340 throw lExc;
341 }
342
343 mSleepDuration = std::chrono::microseconds(mUseInterrupt ? 0 : 50);
344
345 for (const auto& lArg: aUri.mArguments) {
346 if (lArg.first == "events") {
347 if (mUseInterrupt) {
348 exception::PCIeInitialisationError lExc;
349 log(lExc, "PCIe client URI ", Quote(uri()), ": 'events' attribute is specified multiple times");
350 throw lExc;
351 }
352
353 mUseInterrupt = true;
354 mDeviceFileFPGAEvent.setPath(lArg.second);
355 log (Info() , "PCIe client with URI ", Quote (uri()), " is configured to use interrupts");
356 }
357 else if (lArg.first == "sleep") {
358 mSleepDuration = std::chrono::microseconds(boost::lexical_cast<size_t>(lArg.second));
359 log (Notice() , "PCIe client with URI ", Quote (uri()), " : Inter-poll-/-interrupt sleep duration set to ", boost::lexical_cast<size_t>(lArg.second), " us by URI 'sleep' attribute");
360 }
361 else if (lArg.first == "max_in_flight") {
362 mMaxInFlight = boost::lexical_cast<size_t>(lArg.second);
363 log (Notice() , "PCIe client with URI ", Quote (uri()), " : 'Maximum number of packets in flight' set to ", boost::lexical_cast<size_t>(lArg.second), " by URI 'max_in_flight' attribute");
364 }
365 else if (lArg.first == "max_packet_size") {
366 mMaxPacketSize = boost::lexical_cast<size_t>(lArg.second);
367 log (Notice() , "PCIe client with URI ", Quote (uri()), " : 'Maximum packet size (in 32-bit words) set to ", boost::lexical_cast<size_t>(lArg.second), " by URI 'max_packet_size' attribute");
368 }
369 else if (lArg.first == "xdma_7series_workaround") {
371 log (Notice() , "PCIe client with URI ", Quote (uri()), " : Adjusting size of PCIe reads to a few fixed sizes as workaround for 7-series xdma firmware bug");
372 }
373 else
374 log (Warning() , "Unknown attribute ", Quote (lArg.first), " used in URI ", Quote(uri()));
375 }
376}
377
378
380{
381 disconnect();
382}
383
384
385void PCIe::implementDispatch ( std::shared_ptr< Buffers > aBuffers )
386{
387 log(Debug(), "PCIe client ", Quote(id()), ": implementDispatch method called");
388
389 if ( ! mConnected )
390 connect();
391
392 if ( mReplyQueue.size() == mMaxInFlight )
393 read();
394 write(aBuffers);
395}
396
397
399{
400 log(Debug(), "PCIe client ", Quote(id()), ": Flush method called");
401 while ( !mReplyQueue.empty() )
402 read();
403
405
407 mIPCMutex->endSession();
408}
409
410
412{
413 log(Info(), "PCIe client ", Quote(id()), ": closing device files since exception detected");
414
416
418
419 disconnect();
420
421 InnerProtocol::dispatchExceptionHandler();
422}
423
424
426{
427 if ( ! mConnected )
428 connect();
429
430 return mMaxPacketSize * 4;
431}
432
433
435{
436 if ( ! mConnected )
437 connect();
438
439 return mMaxPacketSize * 4;
440}
441
442
444{
446 connect(lLockGuard);
447}
448
449
451{
452 // Read current value of session counter when reading status info from FPGA
453 // (So that can check whether this info is up-to-date later on, when sending next request packet)
455 mIPCSessionCount = mIPCMutex->getCounter();
456
457 log ( Debug() , "PCIe client ", Quote(id()), ": Opening device file " , Quote ( mDeviceFileFPGAToHost.getPath() ) , " (device-to-client)" );
459
460 std::vector<uint32_t> lValues;
461 mDeviceFileFPGAToHost.read(0x0, 4, lValues);
462 aGuard.unlock();
463 log ( Debug(), "PCIe client ", Quote(id()), ": Read status info from addr 0 (", Integer(lValues.at(0)), ", ", Integer(lValues.at(1)), ", ", Integer(lValues.at(2)), ", ", Integer(lValues.at(3)), "): ", detail::PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
464
465 mNumberOfPages = lValues.at(0);
466 if ( (mMaxInFlight == 0) or (mMaxInFlight > mNumberOfPages) )
468 mPageSize = lValues.at(1);
469 if ( (mMaxPacketSize == 0) or (mMaxPacketSize >= mPageSize) )
471 mIndexNextPage = lValues.at(2);
472 mPublishedReplyPageCount = lValues.at(3);
474
475 if (lValues.at(1) > 0xFFFF) {
476 exception::PCIeInitialisationError lExc;
477 log (lExc, "Invalid page size, ", Integer(lValues.at(1)), ", reported in device file ", Quote(mDeviceFileFPGAToHost.getPath()));
478 throw lExc;
479 }
480
482 exception::PCIeInitialisationError lExc;
483 log (lExc, "Next page index, ", Integer(mIndexNextPage), ", reported in device file ", Quote(mDeviceFileFPGAToHost.getPath()), " is inconsistent with number of pages, ", Integer(mNumberOfPages));
484 throw lExc;
485 }
486
487 log ( Debug() , "PCIe client ", Quote(id()), ": Opening device file " , Quote ( mDeviceFileHostToFPGA.getPath() ) , " (client-to-device)" );
489
492
493 if (mUseInterrupt)
495
496 mConnected = true;
497 log ( Info() , "PCIe client ", Quote(id()), ": Connected to device at ", Quote(mDeviceFileHostToFPGA.getPath()), ", ", Quote(mDeviceFileFPGAToHost.getPath()), "; FPGA has ", Integer(mNumberOfPages), " pages, each of size ", Integer(mPageSize), " words, index ", Integer(mIndexNextPage), " should be filled next" );
498}
499
500
502{
506 mConnected = false;
507}
508
509
510void PCIe::write(const std::shared_ptr<Buffers>& aBuffers)
511{
514
516 mIPCMutex->startSession();
518
519 // If these two numbers don't match, another client/process has sent packets
520 // more recently than this client has, so must re-read status info
521 if (mIPCExternalSessionActive or (mIPCMutex->getCounter() != mIPCSessionCount)) {
522 connect(lGuard);
523 }
524 }
525
526 log (Info(), "PCIe client ", Quote(id()), ": Writing ", Integer(aBuffers->sendCounter() / 4), "-word packet to page ", Integer(mIndexNextPage), " in ", Quote(mDeviceFileHostToFPGA.getPath()));
527
528 const uint32_t lHeaderWord = (0x10000 | (((aBuffers->sendCounter() / 4) - 1) & 0xFFFF));
529 std::vector<std::pair<const uint8_t*, size_t> > lDataToWrite;
530 lDataToWrite.push_back( std::make_pair(reinterpret_cast<const uint8_t*>(&lHeaderWord), sizeof lHeaderWord) );
531 lDataToWrite.push_back( std::make_pair(aBuffers->getSendBuffer(), aBuffers->sendCounter()) );
532
535 log (Debug(), "PCIe client ", Quote(id()), ": Wrote " , Integer((aBuffers->sendCounter() / 4) + 1), " 32-bit words at address " , Integer(mIndexNextPage * 4 * mPageSize), " ... ", detail::PacketFmt(lDataToWrite));
536
538 mReplyQueue.push_back(aBuffers);
539}
540
541
543{
544 const size_t lPageIndexToRead = (mIndexNextPage - mReplyQueue.size() + mNumberOfPages) % mNumberOfPages;
545 SteadyClock_t::time_point lStartTime = SteadyClock_t::now();
546
548 {
549 if (mUseInterrupt)
550 {
551 std::vector<uint32_t> lRxEvent;
552 // wait for interrupt; read events file node to see if user interrupt has come
553 while (true) {
554 mDeviceFileFPGAEvent.read(0, 1, lRxEvent);
555 if (lRxEvent.at(0) == 1) {
556 break;
557 }
558 lRxEvent.clear();
559
560 if (SteadyClock_t::now() - lStartTime > std::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
561 exception::PCIeTimeout lExc;
562 log(lExc, "Next page (index ", Integer(lPageIndexToRead), " count ", Integer(mPublishedReplyPageCount+1), ") of PCIe device '" + mDeviceFileHostToFPGA.getPath() + "' is not ready after timeout period");
563 throw lExc;
564 }
565
566 log(Debug(), "PCIe client ", Quote(id()), ": Waiting for interrupt; sleeping for ", mSleepDuration.count(), "us");
567 if (mSleepDuration > std::chrono::microseconds(0))
568 std::this_thread::sleep_for( mSleepDuration );
569
570 } // end of while (true)
571
572 log(Info(), "PCIe client ", Quote(id()), ": Reading page ", Integer(lPageIndexToRead), " (interrupt received)");
573 }
574 else
575 {
576 uint32_t lHwPublishedPageCount = 0x0;
577
578 std::vector<uint32_t> lValues;
579 while ( true ) {
580 // FIXME : Improve by simply adding fileWrite method that takes uint32_t ref as argument (or returns uint32_t)
583 lHwPublishedPageCount = lValues.at(3);
584 log (Debug(), "Read status info from addr 0 (", Integer(lValues.at(0)), ", ", Integer(lValues.at(1)), ", ", Integer(lValues.at(2)), ", ", Integer(lValues.at(3)), "): ", detail::PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
585
586 if (lHwPublishedPageCount != mPublishedReplyPageCount) {
587 mPublishedReplyPageCount = lHwPublishedPageCount;
588 break;
589 }
590 // FIXME: Throw if published page count is invalid number
591
592 if (SteadyClock_t::now() - lStartTime > std::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
593 exception::PCIeTimeout lExc;
594 log(lExc, "Next page (index ", Integer(lPageIndexToRead), " count ", Integer(mPublishedReplyPageCount+1), ") of PCIe device '" + mDeviceFileHostToFPGA.getPath() + "' is not ready after timeout period");
595 throw lExc;
596 }
597
598 log(Debug(), "PCIe client ", Quote(id()), ": Trying to read page index ", Integer(lPageIndexToRead), " = count ", Integer(mReadReplyPageCount+1), "; published page count is ", Integer(lHwPublishedPageCount), "; sleeping for ", mSleepDuration.count(), "us");
599 if (mSleepDuration > std::chrono::microseconds(0))
600 std::this_thread::sleep_for( mSleepDuration );
601 lValues.clear();
602 }
603
604 log(Info(), "PCIe client ", Quote(id()), ": Reading page ", Integer(lPageIndexToRead), " (published count ", Integer(lHwPublishedPageCount), ", surpasses required, ", Integer(mReadReplyPageCount + 1), ")");
605 }
606 }
608
609 // PART 1 : Read the page
610 std::shared_ptr<Buffers> lBuffers = mReplyQueue.front();
611 mReplyQueue.pop_front();
612
613 uint32_t lNrWordsToRead(lBuffers->replyCounter() >> 2);
614 if(mXdma7seriesWorkaround and (lNrWordsToRead % 32 == 0 || lNrWordsToRead % 32 == 28 || lNrWordsToRead < 4))
615 lNrWordsToRead += 4;
616 lNrWordsToRead += 1;
617
618 std::vector<uint32_t> lPageContents;
620 mDeviceFileFPGAToHost.read(4 + lPageIndexToRead * mPageSize, lNrWordsToRead , lPageContents);
621 lGuard.unlock();
622 log (Debug(), "PCIe client ", Quote(id()), ": Read " , Integer(lNrWordsToRead), " 32-bit words from address " , Integer(16 + lPageIndexToRead * 4 * mPageSize), " ... ", detail::PacketFmt((const uint8_t*)lPageContents.data(), 4 * lPageContents.size()));
623
624 // PART 2 : Transfer to reply buffer
625 const std::deque< std::pair< uint8_t* , uint32_t > >& lReplyBuffers ( lBuffers->getReplyBuffer() );
626 size_t lNrWordsInPacket = (lPageContents.at(0) >> 16) + (lPageContents.at(0) & 0xFFFF);
627 if (lNrWordsInPacket != (lBuffers->replyCounter() >> 2))
628 log (Warning(), "PCIe client ", Quote(id()), ": Expected reply packet to contain ", Integer(lBuffers->replyCounter() >> 2), " words, but it actually contains ", Integer(lNrWordsInPacket), " words");
629
630 size_t lNrBytesCopied = 0;
631 for (const auto& lBuffer: lReplyBuffers)
632 {
633 // Don't copy more of page than was written to, for cases when less data received than expected
634 if ( lNrBytesCopied >= 4*lNrWordsInPacket)
635 break;
636
637 size_t lNrBytesToCopy = std::min( lBuffer.second , uint32_t(4*lNrWordsInPacket - lNrBytesCopied) );
638 memcpy ( lBuffer.first, &lPageContents.at(1 + (lNrBytesCopied / 4)), lNrBytesToCopy );
639 lNrBytesCopied += lNrBytesToCopy;
640 }
641
642
643 // PART 3 : Validate the packet contents
644 uhal::exception::exception* lExc = NULL;
645 try
646 {
647 lExc = ClientInterface::validate ( lBuffers );
648 }
649 catch ( exception::exception& aExc )
650 {
651 exception::ValidationError lExc2;
652 log ( lExc2 , "Exception caught during reply validation for PCIe device with URI " , Quote ( this->uri() ) , "; what returned: " , Quote ( aExc.what() ) );
653 throw lExc2;
654 }
655
656 if (lExc != NULL)
657 lExc->throwAsDerivedType();
658}
659
660
661} // end ns uhal
void returnBufferToPool(std::shared_ptr< Buffers > &aBuffers)
Function to return a buffer to the buffer pool.
virtual exception::exception * validate(std::shared_ptr< Buffers > aBuffers)
Function which dispatch calls when the reply is received to check that the headers are as expected.
A class which provides the version-specific functionality for IPbus.
bool haveLock() const
void setPath(const std::string &aPath)
void createBuffer(const size_t aNrBytes)
void write(const uint32_t aAddr, const std::vector< uint32_t > &aValues)
const std::string & getPath() const
void read(const uint32_t aAddr, const uint32_t aNrWords, std::vector< uint32_t > &aValues)
File(const std::string &aPath, int aFlags)
uint32_t mMaxInFlight
void read()
Read next pending reply packet from appropriate page of FPGA-to-host device file, and validate conten...
uint32_t mIndexNextPage
File mDeviceFileFPGAToHost
FPGA-to-host device file.
uint64_t mIPCSessionCount
uint32_t mPageSize
PCIe(const std::string &aId, const URI &aUri)
Constructor.
virtual void Flush()
Concrete implementation of the synchronization function to block until all buffers have been sent,...
uint32_t getMaxReplySize()
Return the maximum size of reply packet based on the buffer size in the target.
std::deque< std::shared_ptr< Buffers > > mReplyQueue
The list of buffers still awaiting a reply.
std::chrono::microseconds mSleepDuration
void connect()
Set up the connection to the device.
bool mXdma7seriesWorkaround
bool mUseInterrupt
virtual void dispatchExceptionHandler()
Function which tidies up this protocol layer in the event of an exception.
bool mIPCExternalSessionActive
File mDeviceFileFPGAEvent
FPGA-to-host interrupt (event) file.
void disconnect()
Close the connection to the device.
uint32_t getMaxSendSize()
Return the maximum size to be sent based on the buffer size in the target.
static std::string getSharedMemName(const std::string &)
virtual ~PCIe()
Destructor.
detail::SharedObject< detail::RobustSessionMutex > mIPCMutex
uint32_t mPublishedReplyPageCount
void implementDispatch(std::shared_ptr< Buffers > aBuffers)
Send the IPbus buffer to the target, read back the response and call the packing-protocol's validate ...
uint32_t mReadReplyPageCount
uint32_t mMaxPacketSize
void write(const std::shared_ptr< Buffers > &aBuffers)
Write request packet to next page in host-to-FPGA device file.
File mDeviceFileHostToFPGA
Host-to-FPGA device file.
uint32_t mNumberOfPages
Class used to display IPbus packet contents in human-readable format (e.g. in log messages)
Definition: PacketFmt.hpp:16
An abstract base exception class, including an interface to throw as the derived type (for passing ex...
Definition: exception.hpp:71
virtual const char * what() const
Function which returns the error message associated with an exception If no error message has previou...
Definition: exception.cpp:87
virtual void throwAsDerivedType()=0
Function which casts a pointer from the base type of this object to a derived type of this object and...
std::unique_lock< RobustSessionMutex > ScopedSessionLock
DebugLevel Debug
Definition: LogLevels.cpp:133
_Quote< T > Quote(const T &aT)
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
ErrorLevel Error
Definition: LogLevels.cpp:61
void log(FatalLevel &aFatal, const T0 &aArg0)
Function to add a log entry at Fatal level.
Definition: log.hxx:18
WarningLevel Warning
Definition: LogLevels.cpp:79
InfoLevel Info
Definition: LogLevels.cpp:115
NoticeLevel Notice
Definition: LogLevels.cpp:97
Struct to store a URI when parsed by boost spirit.
Definition: URI.hpp:50
std::string mHostname
The "host" part of a URI of the form "protocol://host:port/patha/pathb/blah.ext?key1=val1&key2=val2&k...
Definition: URI.hpp:54
NameValuePairVectorType mArguments
The "key1=val1&key2=val2&key3=val3" part of a URI of the form "protocol://host:port/patha/pathb/blah....
Definition: URI.hpp:62