DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
ProtocolFlx.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
41
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
70
71#include "regmap/regmap-struct.h"
72
73UHAL_REGISTER_EXTERNAL_CLIENT(uhallibs::Flx, "ipbusflx-2.0", "A client description")
74
75namespace uhallibs {
76
77//-----------------------------------------------------------------------------
78regmap_register_t*
79Flx::Card::find_reg(const std::string& aName)
80{
81
82 regmap_register_t* reg;
83 for (reg = regmap_registers; reg->name != NULL; reg++) {
84 if (aName == reg->name) {
85 return reg;
86 }
87 }
88
89 return nullptr;
90}
91
92//-----------------------------------------------------------------------------
93Flx::Card::Card(const std::string& aDevicePath, u_int aLockMask)
94 : mPath(aDevicePath)
95 , mLockMask(aLockMask)
96 , mFlxCard()
97 , mIsOpen(false)
98{
99
100 const std::string prefix("/dev/flx");
101 if (aDevicePath.rfind(prefix, 0) != 0) {
102
103 exception::FlxInvalidDevice lExc;
104 log(lExc, "Invalid device path ", uhal::Quote(mPath));
105 throw lExc;
106 }
107
108 std::string device_id_str = aDevicePath.substr(prefix.size()).data();
109 try {
110 mDeviceId = std::stoi(device_id_str);
111 } catch (std::invalid_argument const& ex) {
112
113 exception::FlxInvalidDevice lExc;
114 log(lExc, "Invalid device id ", uhal::Quote(mPath));
115 throw lExc;
116 }
117}
118
119//-----------------------------------------------------------------------------
121
122//-----------------------------------------------------------------------------
123void
125{
126
127 log(uhal::Debug(), "Flx::Card client Opening felix endpoint ", mDeviceId, " on ", mPath);
128
129 if (access(mPath.c_str(), F_OK) == -1) {
130
131 exception::FlxInitialisationError lExc;
132 log(lExc,
133 "Failed to open device file ",
134 uhal::Quote(mPath),
135 "; errno=",
136 uhal::Integer(errno),
137 ", meaning ",
138 uhal::Quote(strerror(errno)));
139 throw lExc;
140 }
141
142 mFd = ::open(mPath.c_str(), O_RDWR);
143 if (mFd < 0) {
144 return;
145 }
146
147 mFlxCard.card_open(mDeviceId, mLockMask);
148
149 mIsOpen = true;
150}
151
152//-----------------------------------------------------------------------------
153void
155{
156
157 if (mIsOpen)
158 mFlxCard.card_close();
159
160 if (mFd != -1) {
161 if (haveLock())
162 unlock();
163 int rc = ::close(mFd);
164 mFd = -1;
165 if (rc == -1)
166 log(uhal::Error(),
167 "Failed to close file ",
168 uhal::Quote(mPath),
169 "; errno=",
170 uhal::Integer(errno),
171 ", meaning ",
172 uhal::Quote(strerror(errno)));
173 }
174}
175
176//-----------------------------------------------------------------------------
177const std::string&
179{
180 return mPath;
181}
182
183//-----------------------------------------------------------------------------
184int
186{
187 return mDeviceId;
188}
189
190//-----------------------------------------------------------------------------
191void
192Flx::Card::read(const uint32_t aAddr, const uint32_t aNrWords, std::vector<uint32_t>& aValues)
193{
194
195 if (!mIsOpen)
196 open();
197
198 flxcard_bar2_regs_t* bar2 = (flxcard_bar2_regs_t*)mFlxCard.openBackDoor(2);
199
200 // +1 is ceiling rounding in integers
201 uint32_t lNrReads64b = (aNrWords + 1) / 2;
202 uint32_t lAddr = aAddr / 2;
203
204 for (uint32_t i(0); i < lNrReads64b; i++) {
205 // *lReadAddrPtr = lAddr+i;
206 bar2->IPBUS_READ_ADDRESS = lAddr + i;
207 // uint64_t lDataWord = *lReadDataPtr;
208 uint64_t lDataWord = bar2->IPBUS_READ_DATA;
209 // Split the 64b word in 32b chunks
210 aValues.push_back(lDataWord & 0xffffffff);
211 if (2 * i + 1 < aNrWords)
212 aValues.push_back(lDataWord >> 32);
213 }
214
215 log(uhal::Debug(), "Flx::Card::read, ", aNrWords, " requested, ", aValues.size(), " read");
216}
217
218//-----------------------------------------------------------------------------
219void
220Flx::Card::write(const uint32_t aAddr, const std::vector<std::pair<const uint8_t*, size_t>>& aData)
221{
222
223 if (!mIsOpen)
224 open();
225
226 flxcard_bar2_regs_t* bar2 = (flxcard_bar2_regs_t*)mFlxCard.openBackDoor(2);
227
228 size_t lNrBytes = 0;
229 for (size_t i = 0; i < aData.size(); i++)
230 lNrBytes += aData.at(i).second;
231
232 assert((lNrBytes % 4) == 0);
233
234 char* allocated = NULL;
235 posix_memalign((void**)&allocated, 4096 /*alignment*/, lNrBytes + 4096);
236 if (allocated == NULL) {
237 exception::FlxCommunicationError lExc;
238 log(lExc, "Failed to allocate ", uhal::Integer(lNrBytes + 4096), " bytes in File::write/2 function");
239 throw lExc;
240 }
241
242 // data to write to register address
243 char* buffer = allocated;
244 size_t lNrBytesCopied = 0;
245 for (size_t i = 0; i < aData.size(); i++) {
246 memcpy(buffer + lNrBytesCopied, aData.at(i).first, aData.at(i).second);
247 lNrBytesCopied += aData.at(i).second;
248 }
249
250 lNrBytesCopied = 0;
251 uint32_t lAddr = aAddr / 2;
252
253 while (lNrBytesCopied < lNrBytes) {
254 bar2->IPBUS_WRITE_ADDRESS = lAddr;
255 char* lSrcPtr = buffer + lNrBytesCopied;
256 if ((lNrBytes - lNrBytesCopied) >= 8) {
257 bar2->IPBUS_WRITE_DATA.DATA = *(uint64_t*)lSrcPtr;
258 lNrBytesCopied += 8;
259 } else if ((lNrBytes - lNrBytesCopied) >= 4) {
260 bar2->IPBUS_WRITE_DATA.DATA = uint64_t(*(uint32_t*)lSrcPtr);
261 lNrBytesCopied += 4;
262 }
263
264 ++lAddr;
265 }
266
267 free(allocated);
268}
269
270bool
272{
273 return mLocked;
274}
275
276void
278{
279 if (flock(mFd, LOCK_EX) == -1) {
280 ipc::exception::MutexError lExc;
281 log(lExc,
282 "Failed to lock device file ",
283 uhal::Quote(mPath),
284 "; errno=",
285 uhal::Integer(errno),
286 ", meaning ",
287 uhal::Quote(strerror(errno)));
288 throw lExc;
289 }
290 mLocked = true;
291}
292
293void
295{
296 if (flock(mFd, LOCK_UN) == -1) {
297 log(uhal::Warning(),
298 "Failed to unlock device file ",
299 uhal::Quote(mPath),
300 "; errno=",
301 uhal::Integer(errno),
302 ", meaning ",
303 uhal::Quote(strerror(errno)));
304 } else
305 mLocked = false;
306}
307
308// Flx Transport
309std::string
310Flx::getSharedMemName(const std::string& aPath)
311{
312 std::string lSanitizedPath(aPath);
313 std::replace(lSanitizedPath.begin(), lSanitizedPath.end(), '/', ':');
314
315 return "/uhal::ipbusflx-2.0::" + lSanitizedPath;
316}
317
318Flx::Flx(const std::string& aId, const uhal::URI& aUri)
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}
355
357{
358 disconnect();
359}
360
361void
362Flx::implementDispatch(std::shared_ptr<uhal::Buffers> aBuffers)
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}
373
374void
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}
386
387void
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}
402
403uint32_t
405{
406 if (!mConnected)
407 connect();
408
409 return (mPageSize - 1) * 4;
410}
411
412uint32_t
414{
415 if (!mConnected)
416 connect();
417
418 return (mPageSize - 1) * 4;
419}
420
421void
423{
424 IPCScopedLock_t lLockGuard(*mIPCMutex);
425 connect(lLockGuard);
426}
427
428void
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}
493
494void
496{
497 log(uhal::Debug(), "flx client is closing device file ", uhal::Quote(mDeviceFile.getPath()));
499 mConnected = false;
500}
501
502void
503Flx::write(const std::shared_ptr<uhal::Buffers>& aBuffers)
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}
547
548void
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}
692
693} // end ns uhal
const std::string & getPath() const
Card(const std::string &aPath, u_int aLockMask)
void write(const uint32_t aAddr, const std::vector< std::pair< const uint8_t *, size_t > > &aData)
bool haveLock() const
int getDeviceId() const
static regmap_register_t * find_reg(const std::string &aName)
void read(const uint32_t aAddr, const uint32_t aNrWords, std::vector< uint32_t > &aValues)
Transport protocol to transfer an IPbus buffer via device file, using mmap.
virtual void dispatchExceptionHandler()
Function which tidies up this protocol layer in the event of an exception.
uint32_t getMaxReplySize()
static std::string getSharedMemName(const std::string &aPath)
uint32_t mPublishedReplyPageCount
void connect()
Set up 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.
uint32_t mNumberOfPages
void implementDispatch(std::shared_ptr< uhal::Buffers > aBuffers)
uint32_t getMaxSendSize()
std::chrono::microseconds mSleepDuration
virtual void Flush()
uint32_t mPageSize
Flx(const Flx &aFlx)
bool mIPCExternalSessionActive
ipc::SharedMemObject< IPCMutex_t > mIPCMutex
uint32_t mReadReplyPageCount
void read()
Read next pending reply packet from appropriate page of FPGA-to-host device file, and validate conten...
void disconnect()
Close the connection to the device.
uhal::exception::exception * mAsynchronousException
uint32_t mIndexNextPage
uint64_t mIPCSessionCount
std::unique_lock< IPCMutex_t > IPCScopedLock_t
std::deque< std::shared_ptr< uhal::Buffers > > mReplyQueue
The list of buffers still awaiting a reply.
virtual ~Flx()
Destructor.
PacketFmt(const uint8_t *const, const size_t)
Definition formatters.cpp:7