57 #include <boost/chrono/duration.hpp> 58 #include <boost/chrono/time_point.hpp> 59 #include <boost/lexical_cast.hpp> 60 #include <boost/thread/thread.hpp> 61 #include <boost/date_time/posix_time/posix_time_types.hpp> 67 #include "uhal/log/log.hpp" 76 mData(1,
std::pair<const uint8_t*, size_t>(aPtr, aNrBytes))
89 std::ios::fmtflags lOrigFlags( aStream.flags() );
91 size_t lNrBytesWritten = 0;
92 for (
size_t i = 0; i < aPacket.
mData.size(); i++) {
93 for (
const uint8_t* lPtr = aPacket.
mData.at(i).first; lPtr != (aPacket.
mData.at(i).first + aPacket.
mData.at(i).second); lPtr++, lNrBytesWritten++) {
94 if ((lNrBytesWritten & 3) == 0)
95 aStream << std::endl <<
" @ " << std::setw(3) << std::dec << (lNrBytesWritten >> 2) <<
" : x";
96 aStream << std::setw(2) <<
std::hex << uint16_t(*lPtr) <<
" ";
100 aStream.flags( lOrigFlags );
139 exception::PCIeInitialisationError lExc;
140 log(lExc,
"Failed to open device file ",
Quote(
mPath),
"; errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
168 posix_memalign((
void**)&
mBuffer, 4096, aNrBytes + 4096);
169 if (mBuffer == NULL) {
170 exception::PCIeCommunicationError lExc;
171 log(lExc,
"Failed to allocate ",
Integer(aNrBytes + 4096),
" bytes in PCIe::File::createBuffer");
177 void PCIe::File::read(
const uint32_t aAddr,
const uint32_t aNrWords, std::vector<uint32_t>& aValues)
185 off_t off = lseek(
mFd, 4*aAddr, SEEK_SET);
186 if ( off != (4 * aAddr)) {
187 exception::PCIeCommunicationError lExc;
188 log(lExc,
"Offset returned by lseek, ",
Integer(off),
", does not match that requested, ",
Integer(4*aAddr),
" (in preparation for read of ",
Integer(aNrWords),
" words)");
195 exception::PCIeCommunicationError lExc;
196 log(lExc,
"Read of ",
Integer(4*aNrWords),
" bytes at address ",
Integer(4 * aAddr),
" failed! errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
199 else if (
size_t(rc) < 4*aNrWords) {
200 exception::PCIeCommunicationError lExc;
201 log(lExc,
"Only ",
Integer(rc),
" bytes transferred in read of ",
Integer(4*aNrWords),
" bytes at address ",
Integer(4 * aAddr));
205 aValues.insert(aValues.end(),
reinterpret_cast<uint32_t*
>(
mBuffer), reinterpret_cast<uint32_t*>(
mBuffer)+ aNrWords);
211 write(4 * aAddr, reinterpret_cast<const uint8_t* const>(aValues.data()), 4 * aValues.size());
220 assert((aNrBytes % 4) == 0);
225 memcpy(
mBuffer, aPtr, aNrBytes);
228 off_t off = lseek(
mFd, aAddr, SEEK_SET);
231 if (fstat(
mFd, &st) or (not S_ISFIFO(st.st_mode))) {
232 exception::PCIeCommunicationError lExc;
233 log(lExc,
"Offset returned by lseek, ",
Integer(off),
", does not match that requested, ",
Integer(aAddr),
" (in preparation for write of ",
Integer(aNrBytes),
" bytes)");
241 exception::PCIeCommunicationError lExc;
242 log(lExc,
"Write of ",
Integer(aNrBytes),
" bytes at address ",
Integer(aAddr),
" failed! errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
245 else if (
size_t(rc) < aNrBytes) {
246 exception::PCIeCommunicationError lExc;
247 log(lExc,
"Only ",
Integer(rc),
" bytes transferred in write of ",
Integer(aNrBytes),
" bytes at address ",
Integer(aAddr));
253 void PCIe::File::write(
const uint32_t aAddr,
const std::vector<std::pair<const uint8_t*, size_t> >& aData)
259 for (
size_t i = 0; i < aData.size(); i++)
260 lNrBytes += aData.at(i).second;
262 assert((lNrBytes % 4) == 0);
267 size_t lNrBytesCopied = 0;
268 for (
size_t i = 0; i < aData.size(); i++) {
269 memcpy(
mBuffer + lNrBytesCopied, aData.at(i).first, aData.at(i).second);
270 lNrBytesCopied += aData.at(i).second;
274 off_t off = lseek(
mFd, aAddr, SEEK_SET);
277 if (fstat(
mFd, &st) or (not S_ISFIFO(st.st_mode))) {
278 exception::PCIeCommunicationError lExc;
279 log(lExc,
"Offset returned by lseek, ",
Integer(off),
", does not match that requested, ",
Integer(aAddr),
" (in preparation for write of ",
Integer(lNrBytes),
" bytes)");
287 exception::PCIeCommunicationError lExc;
288 log(lExc,
"Write of ",
Integer(lNrBytes),
" bytes at address ",
Integer(aAddr),
" failed! errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
291 else if (
size_t(rc) < lNrBytes) {
292 exception::PCIeCommunicationError lExc;
293 log(lExc,
"Only ",
Integer(rc),
" bytes transferred in write of ",
Integer(lNrBytes),
" bytes at address ",
Integer(aAddr));
302 IPbus< 2 , 0 > ( aId , aUri ),
318 if ( aUri.
mHostname.find(
",") == std::string::npos ) {
319 exception::PCIeInitialisationError lExc;
320 log(lExc,
"No comma found in hostname of PCIe client URI '" +
uri() +
"'; cannot construct 2 paths for device files");
324 exception::PCIeInitialisationError lExc;
325 log(lExc,
"Hostname of PCIe client URI '" +
uri() +
"' starts/ends with a comma; cannot construct 2 paths for device files");
331 for (NameValuePairVectorType::const_iterator lIt = aUri.
mArguments.begin(); lIt != aUri.
mArguments.end(); lIt++) {
332 if (lIt->first ==
"events") {
334 exception::PCIeInitialisationError lExc;
335 log(lExc,
"PCIe client URI ",
Quote(
uri()),
": 'events' attribute is specified multiple times");
341 log (
Info() ,
"PCIe client with URI ",
Quote (
uri()),
" is configured to use interrupts");
343 else if (lIt->first ==
"sleep") {
344 mSleepDuration = boost::chrono::microseconds(boost::lexical_cast<size_t>(lIt->second));
345 log (
Notice() ,
"PCIe client with URI ",
Quote (
uri()),
" : Inter-poll-/-interrupt sleep duration set to ", boost::lexical_cast<size_t>(lIt->second),
" us by URI 'sleep' attribute");
347 else if (lIt->first ==
"max_in_flight") {
348 mMaxInFlight = boost::lexical_cast<
size_t>(lIt->second);
349 log (
Notice() ,
"PCIe client with URI ",
Quote (
uri()),
" : 'Maximum number of packets in flight' set to ", boost::lexical_cast<size_t>(lIt->second),
" by URI 'max_in_flight' attribute");
351 else if (lIt->first ==
"max_packet_size") {
353 log (
Notice() ,
"PCIe client with URI ",
Quote (
uri()),
" : 'Maximum packet size (in 32-bit words) set to ", boost::lexical_cast<size_t>(lIt->second),
" by URI 'max_packet_size' attribute");
355 else if (lIt->first ==
"xdma_7series_workaround") {
357 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");
373 log(
Debug(),
"PCIe client (URI: ",
Quote(
uri()),
") : implementDispatch method called");
386 log(
Debug(),
"PCIe client (URI: ",
Quote(
uri()),
") : Flush method called");
395 log(
Notice(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : closing device files since exception detected");
400 InnerProtocol::dispatchExceptionHandler();
428 std::vector<uint32_t> lValues;
430 log (
Info(),
"Read status info from addr 0 (",
Integer(lValues.at(0)),
", ",
Integer(lValues.at(1)),
", ",
Integer(lValues.at(2)),
", ",
Integer(lValues.at(3)),
"): ",
PacketFmt((
const uint8_t*)lValues.data(), 4 * lValues.size()));
445 if (lValues.at(1) > 0xFFFF) {
446 exception::PCIeInitialisationError lExc;
452 exception::PCIeInitialisationError lExc;
461 log (
Info() ,
"PCIe client 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" );
477 log (
Info(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : writing ",
Integer(aBuffers->sendCounter() / 4),
"-word packet to page ",
Integer(
mIndexNextPage),
" in ",
Quote(
mDeviceFileHostToFPGA.
getPath()));
479 const uint32_t lHeaderWord = (0x10000 | (((aBuffers->sendCounter() / 4) - 1) & 0xFFFF));
480 std::vector<std::pair<const uint8_t*, size_t> > lDataToWrite;
481 lDataToWrite.push_back( std::make_pair(reinterpret_cast<const uint8_t*>(&lHeaderWord),
sizeof lHeaderWord) );
482 lDataToWrite.push_back( std::make_pair(aBuffers->getSendBuffer(), aBuffers->sendCounter()) );
497 SteadyClock_t::time_point lStartTime = SteadyClock_t::now();
503 std::vector<uint32_t> lRxEvent;
507 if (lRxEvent.at(0) == 1) {
512 if (SteadyClock_t::now() - lStartTime > boost::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
513 exception::PCIeTimeout lExc;
524 log(
Info(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : Reading page ",
Integer(lPageIndexToRead),
" (interrupt received)");
528 uint32_t lHwPublishedPageCount = 0x0;
530 std::vector<uint32_t> lValues;
534 lHwPublishedPageCount = lValues.at(3);
535 log (
Debug(),
"Read status info from addr 0 (",
Integer(lValues.at(0)),
", ",
Integer(lValues.at(1)),
", ",
Integer(lValues.at(2)),
", ",
Integer(lValues.at(3)),
"): ",
PacketFmt((
const uint8_t*)lValues.data(), 4 * lValues.size()));
543 if (SteadyClock_t::now() - lStartTime > boost::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
544 exception::PCIeTimeout lExc;
549 log(
Debug(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : Trying to read page index ",
Integer(lPageIndexToRead),
" = count ",
Integer(
mReadReplyPageCount+1),
"; published page count is ",
Integer(lHwPublishedPageCount),
"; sleeping for ",
mSleepDuration.count(),
"us");
555 log(
Info(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : Reading page ",
Integer(lPageIndexToRead),
" (published count ",
Integer(lHwPublishedPageCount),
", surpasses required, ",
Integer(
mReadReplyPageCount + 1),
")");
564 uint32_t lNrWordsToRead(lBuffers->replyCounter() >> 2);
565 if(
mXdma7seriesWorkaround and (lNrWordsToRead % 32 == 0 || lNrWordsToRead % 32 == 28 || lNrWordsToRead < 4))
569 std::vector<uint32_t> lPageContents;
571 log (
Debug(),
"Read " ,
Integer(lNrWordsToRead),
" 32-bit words from address " ,
Integer(4 + lPageIndexToRead * 4 * mPageSize),
" ... ",
PacketFmt((
const uint8_t*)lPageContents.data(), 4 * lPageContents.size()));
574 const std::deque< std::pair< uint8_t* , uint32_t > >& lReplyBuffers ( lBuffers->getReplyBuffer() );
575 size_t lNrWordsInPacket = (lPageContents.at(0) >> 16) + (lPageContents.at(0) & 0xFFFF);
576 if (lNrWordsInPacket != (lBuffers->replyCounter() >> 2))
577 log (
Warning(),
"Expected reply packet to contain ",
Integer(lBuffers->replyCounter() >> 2),
" words, but it actually contains ",
Integer(lNrWordsInPacket),
" words");
579 size_t lNrBytesCopied = 0;
580 for ( std::deque< std::pair< uint8_t* , uint32_t > >::const_iterator lIt = lReplyBuffers.begin() ; lIt != lReplyBuffers.end() ; ++lIt )
583 if ( lNrBytesCopied >= 4*lNrWordsInPacket)
586 size_t lNrBytesToCopy =
std::min( lIt->second , uint32_t(4*lNrWordsInPacket - lNrBytesCopied) );
587 memcpy ( lIt->first, &lPageContents.at(1 + (lNrBytesCopied / 4)), lNrBytesToCopy );
588 lNrBytesCopied += lNrBytesToCopy;
void returnBufferToPool(boost::shared_ptr< Buffers > &aBuffers)
Function to return a buffer to the buffer pool.
void connect()
Set up the connection to the device.
PacketFmt(const uint8_t *const, const size_t)
A class which provides the version-specific functionality for IPbus.
uint32_t getMaxSendSize()
Return the maximum size to be sent based on the buffer size in the target.
void read()
Read next pending reply packet from appropriate page of FPGA-to-host device file, and validate conten...
std::string mHostname
The "host" part of a URI of the form "protocol://host:port/patha/pathb/blah.ext?key1=val1&key2=val2&k...
minutes past the hour formatted as two digits e.g.
void setPath(const std::string &aPath)
uint32_t mReadReplyPageCount
const std::vector< std::pair< const uint8_t *, size_t > > mData
File mDeviceFileFPGAToHost
FPGA-to-host device file.
An abstract base exception class providing an interface to a throw/ThrowAsDerivedType mechanism which...
uint32_t mPublishedReplyPageCount
uhal::exception::exception * mAsynchronousException
A pointer to an exception object for passing exceptions from the worker thread to the main thread...
virtual void dispatchExceptionHandler()
Function which tidies up this protocol layer in the event of an exception.
void write(const uint32_t aAddr, const std::vector< uint32_t > &aValues)
virtual void Flush()
Concrete implementation of the synchronization function to block until all buffers have been sent...
NameValuePairVectorType mArguments
The "key1=val1&key2=val2&key3=val3" part of a URI of the form "protocol://host:port/patha/pathb/blah...
_Quote< T > Quote(const T &aT)
void createBuffer(const size_t aNrBytes)
virtual const char * what() const
Function which returns the error message associated with an exception If no error message has previou...
File(const std::string &aPath, int aFlags)
File mDeviceFileHostToFPGA
Host-to-FPGA device file.
bool mXdma7seriesWorkaround
void write(const boost::shared_ptr< Buffers > &aBuffers)
Write request packet to next page in host-to-FPGA device file.
File mDeviceFileFPGAEvent
FPGA-to-host interrupt (event) file.
void implementDispatch(boost::shared_ptr< Buffers > aBuffers)
Send the IPbus buffer to the target, read back the response and call the packing-protocol's validate ...
virtual exception::exception * validate(boost::shared_ptr< Buffers > aBuffers)
Function which dispatch calls when the reply is received to check that the headers are as expected...
uint32_t getMaxReplySize()
Return the maximum size of reply packet based on the buffer size in the target.
void disconnect()
Close the connection to the device.
std::ostream & operator<<(std::ostream &aStr, const uhal::HttpResponseType &aHttpResponse)
const std::string & getPath() const
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
Struct to store a URI when parsed by boost spirit.
void read(const uint32_t aAddr, const uint32_t aNrWords, std::vector< uint32_t > &aValues)
boost::chrono::microseconds mSleepDuration
virtual ~PCIe()
Destructor.
std::deque< boost::shared_ptr< Buffers > > mReplyQueue
The list of buffers still awaiting a reply.