DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
uhallibs::Flx Class Reference

Transport protocol to transfer an IPbus buffer via device file, using mmap. More...

#include <ProtocolFlx.hpp>

Inheritance diagram for uhallibs::Flx:
[legend]
Collaboration diagram for uhallibs::Flx:
[legend]

Classes

class  Card
struct  HexTo

Public Member Functions

 Flx (const std::string &aId, const uhal::URI &aUri)
virtual ~Flx ()
 Destructor.

Private Types

typedef ipc::RobustMutex IPCMutex_t
typedef std::unique_lock< IPCMutex_t > IPCScopedLock_t
typedef IPbus< 2, 0 > InnerProtocol
typedef std::chrono::steady_clock SteadyClock_t

Private Member Functions

 Flx (const Flx &aFlx)
Flx & operator= (const Flx &aFlx)
void implementDispatch (std::shared_ptr< uhal::Buffers > aBuffers)
virtual void Flush ()
virtual void dispatchExceptionHandler ()
 Function which tidies up this protocol layer in the event of an exception.
uint32_t getMaxSendSize ()
uint32_t getMaxReplySize ()
void connect ()
 Set up the connection to the device.
void connect (IPCScopedLock_t &)
 Set up the connection to the device.
void disconnect ()
 Close the connection to the device.
void write (const std::shared_ptr< uhal::Buffers > &aBuffers)
 Write request packet to next page in host-to-FPGA device file.
void read ()
 Read next pending reply packet from appropriate page of FPGA-to-host device file, and validate contents.

Static Private Member Functions

static std::string getSharedMemName (const std::string &aPath)

Private Attributes

bool mConnected
Card mDeviceFile
ipc::SharedMemObject< IPCMutex_t > mIPCMutex
bool mIPCExternalSessionActive
uint64_t mIPCSessionCount
std::chrono::microseconds mSleepDuration
uint32_t mNumberOfPages
uint32_t mPageSize
uint32_t mIndexNextPage
uint32_t mPublishedReplyPageCount
uint32_t mReadReplyPageCount
std::deque< std::shared_ptr< uhal::Buffers > > mReplyQueue
 The list of buffers still awaiting a reply.
uhal::exception::exception * mAsynchronousException

Detailed Description

Transport protocol to transfer an IPbus buffer via device file, using mmap.

Definition at line 97 of file ProtocolFlx.hpp.

Member Typedef Documentation

◆ InnerProtocol

typedef IPbus<2, 0> uhallibs::Flx::InnerProtocol
private

Definition at line 186 of file ProtocolFlx.hpp.

◆ IPCMutex_t

Definition at line 166 of file ProtocolFlx.hpp.

◆ IPCScopedLock_t

typedef std::unique_lock<IPCMutex_t> uhallibs::Flx::IPCScopedLock_t
private

Definition at line 167 of file ProtocolFlx.hpp.

◆ SteadyClock_t

typedef std::chrono::steady_clock uhallibs::Flx::SteadyClock_t
private

Definition at line 188 of file ProtocolFlx.hpp.

Constructor & Destructor Documentation

◆ Flx() [1/2]

uhallibs::Flx::Flx ( const Flx & aFlx)
private

◆ Flx() [2/2]

uhallibs::Flx::Flx ( const std::string & aId,
const uhal::URI & aUri )

Constructor

Parameters
aIdthe uinique identifier that the client will be given.
aUria struct containing the full URI of the target.

Definition at line 318 of file ProtocolFlx.cpp.

319 : IPbus<2, 0>(aId, aUri)
320 , mConnected(false)
321 , mDeviceFile(aUri.mHostname, LOCK_NONE)
322 , mIPCMutex(getSharedMemName(aUri.mHostname))
323 , mNumberOfPages(0)
324 , mPageSize(0)
325 , mIndexNextPage(0)
329{
330 mSleepDuration = std::chrono::microseconds(50);
331
332 for (uhal::NameValuePairVectorType::const_iterator lIt = aUri.mArguments.begin(); lIt != aUri.mArguments.end();
333 lIt++) {
334 if (lIt->first == "sleep") {
335 mSleepDuration = std::chrono::microseconds(std::stoul(lIt->second));
336 log(uhal::Notice(),
337 "flx client with URI ",
338 uhal::Quote(uri()),
339 " : Inter-poll-/-interrupt sleep duration set to ",
340 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 log(uhal::Warning(), "Unknown attribute ", uhal::Quote(lIt->first), " used in URI ", uhal::Quote(uri()));
352 }
353 }
354}
static std::string getSharedMemName(const std::string &aPath)
uint32_t mPublishedReplyPageCount
uint32_t mNumberOfPages
std::chrono::microseconds mSleepDuration
uint32_t mPageSize
ipc::SharedMemObject< IPCMutex_t > mIPCMutex
uint32_t mReadReplyPageCount
uhal::exception::exception * mAsynchronousException
uint32_t mIndexNextPage
Unsupported std::string uri Execution of command std::string error Failed to create CommandFacility uri
Definition Issues.hpp:71

◆ ~Flx()

uhallibs::Flx::~Flx ( )
virtual

Destructor.

Definition at line 356 of file ProtocolFlx.cpp.

357{
358 disconnect();
359}
void disconnect()
Close the connection to the device.

Member Function Documentation

◆ connect() [1/2]

void uhallibs::Flx::connect ( )
private

Set up the connection to the device.

Definition at line 422 of file ProtocolFlx.cpp.

423{
424 IPCScopedLock_t lLockGuard(*mIPCMutex);
425 connect(lLockGuard);
426}
void connect()
Set up the connection to the device.
std::unique_lock< IPCMutex_t > IPCScopedLock_t

◆ connect() [2/2]

void uhallibs::Flx::connect ( IPCScopedLock_t & aGuard)
private

Set up the connection to the device.

Definition at line 429 of file ProtocolFlx.cpp.

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)
434 mIPCSessionCount = mIPCMutex->getCounter();
435
436 log(uhal::Debug(), "flx client is opening device file ", uhal::Quote(mDeviceFile.getPath()));
437 std::vector<uint32_t> lValues;
438 mDeviceFile.read(0x0, 4, lValues);
439 log(uhal::Debug(),
440 "Read status info from addr 0 (",
441 uhal::Integer(lValues.at(0)),
442 ", ",
443 uhal::Integer(lValues.at(1)),
444 ", ",
445 uhal::Integer(lValues.at(2)),
446 ", ",
447 uhal::Integer(lValues.at(3)),
448 "): ",
449 PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
450 aGuard.unlock();
451
452 mNumberOfPages = lValues.at(0);
453 // mPageSize = std::min(uint32_t(4096), lValues.at(1));
454 mPageSize = lValues.at(1);
455 mIndexNextPage = lValues.at(2);
456 mPublishedReplyPageCount = lValues.at(3);
458
459 if (lValues.at(1) > 0xFFFF) {
460 exception::FlxInitialisationError lExc;
461 log(lExc,
462 "Invalid page size, ",
463 uhal::Integer(lValues.at(1)),
464 ", reported in device file ",
465 uhal::Quote(mDeviceFile.getPath()));
466 throw lExc;
467 }
468
470 exception::FlxInitialisationError lExc;
471 log(lExc,
472 "Next page index, ",
473 uhal::Integer(mIndexNextPage),
474 ", reported in device file ",
475 uhal::Quote(mDeviceFile.getPath()),
476 " is inconsistent with number of pages, ",
477 uhal::Integer(mNumberOfPages));
478 throw lExc;
479 }
480
481 mConnected = true;
482 log(uhal::Info(),
483 "flx client connected to device at ",
484 uhal::Quote(mDeviceFile.getPath()),
485 "; FPGA has ",
486 uhal::Integer(mNumberOfPages),
487 " pages, each of size ",
488 uhal::Integer(mPageSize),
489 " words, index ",
490 uhal::Integer(mIndexNextPage),
491 " should be filled next");
492}
const std::string & getPath() const
bool haveLock() const
void read(const uint32_t aAddr, const uint32_t aNrWords, std::vector< uint32_t > &aValues)
bool mIPCExternalSessionActive
uint64_t mIPCSessionCount

◆ disconnect()

void uhallibs::Flx::disconnect ( )
private

Close the connection to the device.

Definition at line 495 of file ProtocolFlx.cpp.

496{
497 log(uhal::Debug(), "flx client is closing device file ", uhal::Quote(mDeviceFile.getPath()));
499 mConnected = false;
500}

◆ dispatchExceptionHandler()

void uhallibs::Flx::dispatchExceptionHandler ( )
privatevirtual

Function which tidies up this protocol layer in the event of an exception.

Definition at line 388 of file ProtocolFlx.cpp.

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
397
398 disconnect();
399
400 InnerProtocol::dispatchExceptionHandler();
401}

◆ Flush()

void uhallibs::Flx::Flush ( )
privatevirtual

Concrete implementation of the synchronization function to block until all buffers have been sent, all replies received and all data validated

Definition at line 375 of file ProtocolFlx.cpp.

376{
377 log(uhal::Debug(), "flx client (URI: ", uhal::Quote(uri()), ") : Flush method called");
378 while (!mReplyQueue.empty())
379 read();
380
382
383 IPCScopedLock_t lLockGuard(*mIPCMutex);
384 mIPCMutex->endSession();
385}
void read()
Read next pending reply packet from appropriate page of FPGA-to-host device file, and validate conten...
std::deque< std::shared_ptr< uhal::Buffers > > mReplyQueue
The list of buffers still awaiting a reply.

◆ getMaxReplySize()

uint32_t uhallibs::Flx::getMaxReplySize ( )
private

Return the maximum size of reply packet based on the buffer size in the target

Returns
the maximum size of reply packet

Definition at line 413 of file ProtocolFlx.cpp.

414{
415 if (!mConnected)
416 connect();
417
418 return (mPageSize - 1) * 4;
419}

◆ getMaxSendSize()

uint32_t uhallibs::Flx::getMaxSendSize ( )
private

Return the maximum size to be sent based on the buffer size in the target

Returns
the maximum size to be sent

Definition at line 404 of file ProtocolFlx.cpp.

405{
406 if (!mConnected)
407 connect();
408
409 return (mPageSize - 1) * 4;
410}

◆ getSharedMemName()

std::string uhallibs::Flx::getSharedMemName ( const std::string & aPath)
staticprivate

Definition at line 310 of file ProtocolFlx.cpp.

311{
312 std::string lSanitizedPath(aPath);
313 std::replace(lSanitizedPath.begin(), lSanitizedPath.end(), '/', ':');
314
315 return "/uhal::ipbusflx-2.0::" + lSanitizedPath;
316}

◆ implementDispatch()

void uhallibs::Flx::implementDispatch ( std::shared_ptr< uhal::Buffers > aBuffers)
private

Send the IPbus buffer to the target, read back the response and call the packing-protocol's validate function

Parameters
aBuffersthe buffer object wrapping the send and recieve buffers that are to be transported If multithreaded, adds buffer to the dispatch queue and returns. If single-threaded, calls the dispatch-worker dispatch function directly and blocks until the response is validated.

Definition at line 362 of file ProtocolFlx.cpp.

363{
364 log(uhal::Debug(), "flx client (URI: ", uhal::Quote(uri()), ") : implementDispatch method called");
365
366 if (!mConnected)
367 connect();
368
369 if (mReplyQueue.size() == mNumberOfPages)
370 read();
371 write(aBuffers);
372}
void write(const std::shared_ptr< uhal::Buffers > &aBuffers)
Write request packet to next page in host-to-FPGA device file.

◆ operator=()

Flx & uhallibs::Flx::operator= ( const Flx & aFlx)
private

◆ read()

void uhallibs::Flx::read ( )
private

Read next pending reply packet from appropriate page of FPGA-to-host device file, and validate contents.

Definition at line 549 of file ProtocolFlx.cpp.

550{
551 const size_t lPageIndexToRead = (mIndexNextPage - mReplyQueue.size() + mNumberOfPages) % mNumberOfPages;
552 SteadyClock_t::time_point lStartTime = SteadyClock_t::now();
553
555 uint32_t lHwPublishedPageCount = 0x0;
556
557 std::vector<uint32_t> lValues;
558 while (true) {
559 IPCScopedLock_t lGuard(*mIPCMutex);
560 // FIXME : Improve by simply adding dmaWrite method that takes uint32_t ref as argument (or returns uint32_t)
561 mDeviceFile.read(0, 4, lValues);
562 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 log(uhal::Debug(),
567 "Read status info from addr 0 (",
568 uhal::Integer(lValues.at(0)),
569 ", ",
570 uhal::Integer(lValues.at(1)),
571 ", ",
572 uhal::Integer(lValues.at(2)),
573 ", ",
574 uhal::Integer(lValues.at(3)),
575 "): ",
576 PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
577
578 if (lHwPublishedPageCount != mPublishedReplyPageCount) {
579 mPublishedReplyPageCount = lHwPublishedPageCount;
580 break;
581 }
582 // FIXME: Throw if published page count is invalid number
583
584 if (SteadyClock_t::now() - lStartTime > std::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
585 exception::FlxTimeout lExc;
586 log(lExc,
587 "Next page (index ",
588 uhal::Integer(lPageIndexToRead),
589 " count ",
590 uhal::Integer(mPublishedReplyPageCount + 1),
591 ") of flx device '" + mDeviceFile.getPath() + "' is not ready after timeout period");
592 throw lExc;
593 }
594
595 log(uhal::Debug(),
596 "flx client ",
597 uhal::Quote(id()),
598 " (URI: ",
599 uhal::Quote(uri()),
600 ") : Trying to read page index ",
601 uhal::Integer(lPageIndexToRead),
602 " = count ",
603 uhal::Integer(mReadReplyPageCount + 1),
604 "; published page count is ",
605 uhal::Integer(lHwPublishedPageCount),
606 "; sleeping for ",
607 mSleepDuration.count(),
608 "us");
609 if (mSleepDuration > std::chrono::microseconds(0))
610 std::this_thread::sleep_for(mSleepDuration);
611 lValues.clear();
612 }
613
614 log(uhal::Info(),
615 "flx client ",
616 uhal::Quote(id()),
617 " (URI: ",
618 uhal::Quote(uri()),
619 ") : Reading page ",
620 uhal::Integer(lPageIndexToRead),
621 " (published count ",
622 uhal::Integer(lHwPublishedPageCount),
623 ", surpasses required, ",
624 uhal::Integer(mReadReplyPageCount + 1),
625 ")");
626 }
628
629 // PART 1 : Read the page
630 std::shared_ptr<uhal::Buffers> lBuffers = mReplyQueue.front();
631 mReplyQueue.pop_front();
632
633 uint32_t lNrWordsToRead(lBuffers->replyCounter() >> 2);
634 lNrWordsToRead += 1;
635
636 std::vector<uint32_t> lPageContents;
637 IPCScopedLock_t lGuard(*mIPCMutex);
638 mDeviceFile.read(4 + lPageIndexToRead * mPageSize, lNrWordsToRead, lPageContents);
639 lGuard.unlock();
640 log(uhal::Debug(),
641 "Read ",
642 uhal::Integer(lNrWordsToRead),
643 " 32-bit words from address ",
644 uhal::Integer(4 + lPageIndexToRead * 4 * mPageSize),
645 " ... ",
646 PacketFmt((const uint8_t*)lPageContents.data(), 4 * lPageContents.size()));
647
648 // PART 2 : Transfer to reply buffer
649 const std::deque<std::pair<uint8_t*, uint32_t>>& lReplyBuffers(lBuffers->getReplyBuffer());
650 size_t lNrWordsInPacket = (lPageContents.at(0) >> 16) + (lPageContents.at(0) & 0xFFFF);
651 if (lNrWordsInPacket != (lBuffers->replyCounter() >> 2))
652 log(uhal::Warning(),
653 "Expected reply packet to contain ",
654 uhal::Integer(lBuffers->replyCounter() >> 2),
655 " words, but it actually contains ",
656 uhal::Integer(lNrWordsInPacket),
657 " words");
658
659 size_t lNrBytesCopied = 0;
660 for (std::deque<std::pair<uint8_t*, uint32_t>>::const_iterator lIt = lReplyBuffers.begin();
661 lIt != lReplyBuffers.end();
662 ++lIt) {
663 // Don't copy more of page than was written to, for cases when less data received than expected
664 if (lNrBytesCopied >= 4 * lNrWordsInPacket)
665 break;
666
667 size_t lNrBytesToCopy = std::min(lIt->second, uint32_t(4 * lNrWordsInPacket - lNrBytesCopied));
668 memcpy(lIt->first, &lPageContents.at(1 + (lNrBytesCopied / 4)), lNrBytesToCopy);
669 lNrBytesCopied += lNrBytesToCopy;
670 }
671
672 // PART 3 : Validate the packet contents
673 try {
674 if (uhal::exception::exception* lExc =
675 ClientInterface::validate(lBuffers)) // Control of the pointer has been passed back to the client interface
676 {
678 }
679 } catch (uhal::exception::exception& aExc) {
680 mAsynchronousException = new uhal::exception::ValidationError();
682 "Exception caught during reply validation for flx device with URI ",
683 uhal::Quote(this->uri()),
684 "; what returned: ",
685 uhal::Quote(aExc.what()));
686 }
687
689 mAsynchronousException->throwAsDerivedType();
690 }
691}
PacketFmt(const uint8_t *const, const size_t)
Definition formatters.cpp:7

◆ write()

void uhallibs::Flx::write ( const std::shared_ptr< uhal::Buffers > & aBuffers)
private

Write request packet to next page in host-to-FPGA device file.

Definition at line 503 of file ProtocolFlx.cpp.

504{
505 if (not mDeviceFile.haveLock()) {
507
508 IPCScopedLock_t lGuard(*mIPCMutex);
509 mIPCMutex->startSession();
511
512 if (mIPCExternalSessionActive or (mIPCMutex->getCounter() != mIPCSessionCount)) {
513 connect(lGuard);
514 }
515 }
516
517 log(uhal::Info(),
518 "flx client ",
519 uhal::Quote(id()),
520 " (URI: ",
521 uhal::Quote(uri()),
522 ") : writing ",
523 uhal::Integer(aBuffers->sendCounter() / 4),
524 "-word packet to page ",
525 uhal::Integer(mIndexNextPage),
526 " in ",
527 uhal::Quote(mDeviceFile.getPath()));
528
529 const uint32_t lHeaderWord = (0x10000 | (((aBuffers->sendCounter() / 4) - 1) & 0xFFFF));
530 std::vector<std::pair<const uint8_t*, size_t>> lDataToWrite;
531 lDataToWrite.push_back(std::make_pair(reinterpret_cast<const uint8_t*>(&lHeaderWord), sizeof lHeaderWord));
532 lDataToWrite.push_back(std::make_pair(aBuffers->getSendBuffer(), aBuffers->sendCounter()));
533
534 IPCScopedLock_t lGuard(*mIPCMutex);
535 mDeviceFile.write(mIndexNextPage * mPageSize, lDataToWrite);
536 log(uhal::Debug(),
537 "Wrote ",
538 uhal::Integer((aBuffers->sendCounter() / 4) + 1),
539 " 32-bit words at address ",
540 uhal::Integer(mIndexNextPage * 4 * mPageSize),
541 " ... ",
542 PacketFmt(lDataToWrite));
543
545 mReplyQueue.push_back(aBuffers);
546}
void write(const uint32_t aAddr, const std::vector< std::pair< const uint8_t *, size_t > > &aData)

Member Data Documentation

◆ mAsynchronousException

uhal::exception::exception* uhallibs::Flx::mAsynchronousException
private

A pointer to an exception object for passing exceptions from the worker thread to the main thread. Exceptions must always be created on the heap (i.e. using new) and deletion will be handled in the main thread

Definition at line 236 of file ProtocolFlx.hpp.

◆ mConnected

bool uhallibs::Flx::mConnected
private

Definition at line 217 of file ProtocolFlx.hpp.

◆ mDeviceFile

Card uhallibs::Flx::mDeviceFile
private

Definition at line 219 of file ProtocolFlx.hpp.

◆ mIndexNextPage

uint32_t uhallibs::Flx::mIndexNextPage
private

Definition at line 227 of file ProtocolFlx.hpp.

◆ mIPCExternalSessionActive

bool uhallibs::Flx::mIPCExternalSessionActive
private

Definition at line 222 of file ProtocolFlx.hpp.

◆ mIPCMutex

ipc::SharedMemObject<IPCMutex_t> uhallibs::Flx::mIPCMutex
private

Definition at line 221 of file ProtocolFlx.hpp.

◆ mIPCSessionCount

uint64_t uhallibs::Flx::mIPCSessionCount
private

Definition at line 223 of file ProtocolFlx.hpp.

◆ mNumberOfPages

uint32_t uhallibs::Flx::mNumberOfPages
private

Definition at line 227 of file ProtocolFlx.hpp.

◆ mPageSize

uint32_t uhallibs::Flx::mPageSize
private

Definition at line 227 of file ProtocolFlx.hpp.

◆ mPublishedReplyPageCount

uint32_t uhallibs::Flx::mPublishedReplyPageCount
private

Definition at line 227 of file ProtocolFlx.hpp.

◆ mReadReplyPageCount

uint32_t uhallibs::Flx::mReadReplyPageCount
private

Definition at line 227 of file ProtocolFlx.hpp.

◆ mReplyQueue

std::deque<std::shared_ptr<uhal::Buffers> > uhallibs::Flx::mReplyQueue
private

The list of buffers still awaiting a reply.

Definition at line 230 of file ProtocolFlx.hpp.

◆ mSleepDuration

std::chrono::microseconds uhallibs::Flx::mSleepDuration
private

Definition at line 225 of file ProtocolFlx.hpp.


The documentation for this class was generated from the following files: