LCOV - code coverage report
Current view: top level - uhallibs/src - ProtocolFlx.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 343 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 25 0

            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              : #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              : 
      69              : #include "uhallibs/formatters.hpp"
      70              : 
      71              : #include "regmap/regmap-struct.h"
      72              : 
      73              : UHAL_REGISTER_EXTERNAL_CLIENT(uhallibs::Flx, "ipbusflx-2.0", "A client description")
      74              : 
      75              : namespace uhallibs {
      76              : 
      77              : //-----------------------------------------------------------------------------
      78              : regmap_register_t*
      79            0 : Flx::Card::find_reg(const std::string& aName)
      80              : {
      81              : 
      82            0 :   regmap_register_t* reg;
      83            0 :   for (reg = regmap_registers; reg->name != NULL; reg++) {
      84            0 :     if (aName == reg->name) {
      85              :       return reg;
      86              :     }
      87              :   }
      88              : 
      89              :   return nullptr;
      90              : }
      91              : 
      92              : //-----------------------------------------------------------------------------
      93            0 : Flx::Card::Card(const std::string& aDevicePath, u_int aLockMask)
      94            0 :   : mPath(aDevicePath)
      95            0 :   , mLockMask(aLockMask)
      96            0 :   , mFlxCard()
      97            0 :   , mIsOpen(false)
      98              : {
      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            0 :   }
     107              : 
     108            0 :   std::string device_id_str = aDevicePath.substr(prefix.size()).data();
     109            0 :   try {
     110            0 :     mDeviceId = std::stoi(device_id_str);
     111            0 :   } catch (std::invalid_argument const& ex) {
     112              : 
     113            0 :     exception::FlxInvalidDevice lExc;
     114            0 :     log(lExc, "Invalid device id ", uhal::Quote(mPath));
     115            0 :     throw lExc;
     116            0 :   }
     117            0 : }
     118              : 
     119              : //-----------------------------------------------------------------------------
     120            0 : Flx::Card::~Card() {}
     121              : 
     122              : //-----------------------------------------------------------------------------
     123              : void
     124            0 : Flx::Card::open()
     125              : {
     126              : 
     127            0 :   log(uhal::Debug(), "Flx::Card client Opening felix endpoint ", mDeviceId, " on ", mPath);
     128              : 
     129            0 :   if (access(mPath.c_str(), F_OK) == -1) {
     130              : 
     131            0 :     exception::FlxInitialisationError lExc;
     132            0 :     log(lExc,
     133              :         "Failed to open device file ",
     134            0 :         uhal::Quote(mPath),
     135              :         "; errno=",
     136            0 :         uhal::Integer(errno),
     137              :         ", meaning ",
     138            0 :         uhal::Quote(strerror(errno)));
     139            0 :     throw lExc;
     140            0 :   }
     141              : 
     142            0 :   mFd = ::open(mPath.c_str(), O_RDWR);
     143            0 :   if (mFd < 0) {
     144              :     return;
     145              :   }
     146              : 
     147            0 :   mFlxCard.card_open(mDeviceId, mLockMask);
     148              : 
     149            0 :   mIsOpen = true;
     150              : }
     151              : 
     152              : //-----------------------------------------------------------------------------
     153              : void
     154            0 : Flx::Card::close()
     155              : {
     156              : 
     157            0 :   if (mIsOpen)
     158            0 :     mFlxCard.card_close();
     159              : 
     160            0 :   if (mFd != -1) {
     161            0 :     if (haveLock())
     162            0 :       unlock();
     163            0 :     int rc = ::close(mFd);
     164            0 :     mFd = -1;
     165            0 :     if (rc == -1)
     166            0 :       log(uhal::Error(),
     167              :           "Failed to close file ",
     168            0 :           uhal::Quote(mPath),
     169              :           "; errno=",
     170            0 :           uhal::Integer(errno),
     171              :           ", meaning ",
     172            0 :           uhal::Quote(strerror(errno)));
     173              :   }
     174            0 : }
     175              : 
     176              : //-----------------------------------------------------------------------------
     177              : const std::string&
     178            0 : Flx::Card::getPath() const
     179              : {
     180            0 :   return mPath;
     181              : }
     182              : 
     183              : //-----------------------------------------------------------------------------
     184              : int
     185            0 : Flx::Card::getDeviceId() const
     186              : {
     187            0 :   return mDeviceId;
     188              : }
     189              : 
     190              : //-----------------------------------------------------------------------------
     191              : void
     192            0 : Flx::Card::read(const uint32_t aAddr, const uint32_t aNrWords, std::vector<uint32_t>& aValues)
     193              : {
     194              : 
     195            0 :   if (!mIsOpen)
     196            0 :     open();
     197              : 
     198            0 :   flxcard_bar2_regs_t* bar2 = (flxcard_bar2_regs_t*)mFlxCard.openBackDoor(2);
     199              : 
     200              :   // +1 is ceiling rounding in integers
     201            0 :   uint32_t lNrReads64b = (aNrWords + 1) / 2;
     202            0 :   uint32_t lAddr = aAddr / 2;
     203              : 
     204            0 :   for (uint32_t i(0); i < lNrReads64b; i++) {
     205              :     // *lReadAddrPtr = lAddr+i;
     206            0 :     bar2->IPBUS_READ_ADDRESS = lAddr + i;
     207              :     // uint64_t lDataWord = *lReadDataPtr;
     208            0 :     uint64_t lDataWord = bar2->IPBUS_READ_DATA;
     209              :     // Split the 64b word in 32b chunks
     210            0 :     aValues.push_back(lDataWord & 0xffffffff);
     211            0 :     if (2 * i + 1 < aNrWords)
     212            0 :       aValues.push_back(lDataWord >> 32);
     213              :   }
     214              : 
     215            0 :   log(uhal::Debug(), "Flx::Card::read, ", aNrWords, " requested, ", aValues.size(), " read");
     216            0 : }
     217              : 
     218              : //-----------------------------------------------------------------------------
     219              : void
     220            0 : Flx::Card::write(const uint32_t aAddr, const std::vector<std::pair<const uint8_t*, size_t>>& aData)
     221              : {
     222              : 
     223            0 :   if (!mIsOpen)
     224            0 :     open();
     225              : 
     226            0 :   flxcard_bar2_regs_t* bar2 = (flxcard_bar2_regs_t*)mFlxCard.openBackDoor(2);
     227              : 
     228            0 :   size_t lNrBytes = 0;
     229            0 :   for (size_t i = 0; i < aData.size(); i++)
     230            0 :     lNrBytes += aData.at(i).second;
     231              : 
     232            0 :   assert((lNrBytes % 4) == 0);
     233              : 
     234            0 :   char* allocated = NULL;
     235            0 :   posix_memalign((void**)&allocated, 4096 /*alignment*/, lNrBytes + 4096);
     236            0 :   if (allocated == NULL) {
     237            0 :     exception::FlxCommunicationError lExc;
     238            0 :     log(lExc, "Failed to allocate ", uhal::Integer(lNrBytes + 4096), " bytes in File::write/2 function");
     239            0 :     throw lExc;
     240            0 :   }
     241              : 
     242              :   // data to write to register address
     243              :   char* buffer = allocated;
     244              :   size_t lNrBytesCopied = 0;
     245            0 :   for (size_t i = 0; i < aData.size(); i++) {
     246            0 :     memcpy(buffer + lNrBytesCopied, aData.at(i).first, aData.at(i).second);
     247            0 :     lNrBytesCopied += aData.at(i).second;
     248              :   }
     249              : 
     250            0 :   lNrBytesCopied = 0;
     251            0 :   uint32_t lAddr = aAddr / 2;
     252              : 
     253            0 :   while (lNrBytesCopied < lNrBytes) {
     254            0 :     bar2->IPBUS_WRITE_ADDRESS = lAddr;
     255            0 :     char* lSrcPtr = buffer + lNrBytesCopied;
     256            0 :     if ((lNrBytes - lNrBytesCopied) >= 8) {
     257            0 :       bar2->IPBUS_WRITE_DATA.DATA = *(uint64_t*)lSrcPtr;
     258            0 :       lNrBytesCopied += 8;
     259            0 :     } else if ((lNrBytes - lNrBytesCopied) >= 4) {
     260            0 :       bar2->IPBUS_WRITE_DATA.DATA = uint64_t(*(uint32_t*)lSrcPtr);
     261            0 :       lNrBytesCopied += 4;
     262              :     }
     263              : 
     264            0 :     ++lAddr;
     265              :   }
     266              : 
     267            0 :   free(allocated);
     268            0 : }
     269              : 
     270              : bool
     271            0 : Flx::Card::haveLock() const
     272              : {
     273            0 :   return mLocked;
     274              : }
     275              : 
     276              : void
     277            0 : Flx::Card::lock()
     278              : {
     279            0 :   if (flock(mFd, LOCK_EX) == -1) {
     280            0 :     ipc::exception::MutexError lExc;
     281            0 :     log(lExc,
     282              :         "Failed to lock device file ",
     283            0 :         uhal::Quote(mPath),
     284              :         "; errno=",
     285            0 :         uhal::Integer(errno),
     286              :         ", meaning ",
     287            0 :         uhal::Quote(strerror(errno)));
     288            0 :     throw lExc;
     289            0 :   }
     290            0 :   mLocked = true;
     291            0 : }
     292              : 
     293              : void
     294            0 : Flx::Card::unlock()
     295              : {
     296            0 :   if (flock(mFd, LOCK_UN) == -1) {
     297            0 :     log(uhal::Warning(),
     298              :         "Failed to unlock device file ",
     299            0 :         uhal::Quote(mPath),
     300              :         "; errno=",
     301            0 :         uhal::Integer(errno),
     302              :         ", meaning ",
     303            0 :         uhal::Quote(strerror(errno)));
     304              :   } else
     305            0 :     mLocked = false;
     306            0 : }
     307              : 
     308              : // Flx Transport
     309              : std::string
     310            0 : Flx::getSharedMemName(const std::string& aPath)
     311              : {
     312            0 :   std::string lSanitizedPath(aPath);
     313            0 :   std::replace(lSanitizedPath.begin(), lSanitizedPath.end(), '/', ':');
     314              : 
     315            0 :   return "/uhal::ipbusflx-2.0::" + lSanitizedPath;
     316            0 : }
     317              : 
     318            0 : Flx::Flx(const std::string& aId, const uhal::URI& aUri)
     319              :   : IPbus<2, 0>(aId, aUri)
     320            0 :   , mConnected(false)
     321            0 :   , mDeviceFile(aUri.mHostname, LOCK_NONE)
     322            0 :   , mIPCMutex(getSharedMemName(aUri.mHostname))
     323            0 :   , mNumberOfPages(0)
     324            0 :   , mPageSize(0)
     325            0 :   , mIndexNextPage(0)
     326            0 :   , mPublishedReplyPageCount(0)
     327            0 :   , mReadReplyPageCount(0)
     328            0 :   , mAsynchronousException(NULL)
     329              : {
     330            0 :   mSleepDuration = std::chrono::microseconds(50);
     331              : 
     332            0 :   for (uhal::NameValuePairVectorType::const_iterator lIt = aUri.mArguments.begin(); lIt != aUri.mArguments.end();
     333            0 :        lIt++) {
     334            0 :     if (lIt->first == "sleep") {
     335            0 :       mSleepDuration = std::chrono::microseconds(std::stoul(lIt->second));
     336            0 :       log(uhal::Notice(),
     337              :           "flx client with URI ",
     338            0 :           uhal::Quote(uri()),
     339              :           " : Inter-poll-/-interrupt sleep duration set to ",
     340            0 :           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            0 :       log(uhal::Warning(), "Unknown attribute ", uhal::Quote(lIt->first), " used in URI ", uhal::Quote(uri()));
     352              :     }
     353              :   }
     354            0 : }
     355              : 
     356            0 : Flx::~Flx()
     357              : {
     358            0 :   disconnect();
     359            0 : }
     360              : 
     361              : void
     362            0 : Flx::implementDispatch(std::shared_ptr<uhal::Buffers> aBuffers)
     363              : {
     364            0 :   log(uhal::Debug(), "flx client (URI: ", uhal::Quote(uri()), ") : implementDispatch method called");
     365              : 
     366            0 :   if (!mConnected)
     367            0 :     connect();
     368              : 
     369            0 :   if (mReplyQueue.size() == mNumberOfPages)
     370            0 :     read();
     371            0 :   write(aBuffers);
     372            0 : }
     373              : 
     374              : void
     375            0 : Flx::Flush()
     376              : {
     377            0 :   log(uhal::Debug(), "flx client (URI: ", uhal::Quote(uri()), ") : Flush method called");
     378            0 :   while (!mReplyQueue.empty())
     379            0 :     read();
     380              : 
     381            0 :   mDeviceFile.unlock();
     382              : 
     383            0 :   IPCScopedLock_t lLockGuard(*mIPCMutex);
     384            0 :   mIPCMutex->endSession();
     385            0 : }
     386              : 
     387              : void
     388            0 : Flx::dispatchExceptionHandler()
     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              : 
     396            0 :   mDeviceFile.unlock();
     397              : 
     398            0 :   disconnect();
     399              : 
     400            0 :   InnerProtocol::dispatchExceptionHandler();
     401            0 : }
     402              : 
     403              : uint32_t
     404            0 : Flx::getMaxSendSize()
     405              : {
     406            0 :   if (!mConnected)
     407            0 :     connect();
     408              : 
     409            0 :   return (mPageSize - 1) * 4;
     410              : }
     411              : 
     412              : uint32_t
     413            0 : Flx::getMaxReplySize()
     414              : {
     415            0 :   if (!mConnected)
     416            0 :     connect();
     417              : 
     418            0 :   return (mPageSize - 1) * 4;
     419              : }
     420              : 
     421              : void
     422            0 : Flx::connect()
     423              : {
     424            0 :   IPCScopedLock_t lLockGuard(*mIPCMutex);
     425            0 :   connect(lLockGuard);
     426            0 : }
     427              : 
     428              : void
     429            0 : Flx::connect(IPCScopedLock_t& aGuard)
     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)
     433            0 :   mIPCExternalSessionActive = mIPCMutex->isActive() and (not mDeviceFile.haveLock());
     434            0 :   mIPCSessionCount = mIPCMutex->getCounter();
     435              : 
     436            0 :   log(uhal::Debug(), "flx client is opening device file ", uhal::Quote(mDeviceFile.getPath()));
     437            0 :   std::vector<uint32_t> lValues;
     438            0 :   mDeviceFile.read(0x0, 4, lValues);
     439            0 :   log(uhal::Debug(),
     440              :       "Read status info from addr 0 (",
     441            0 :       uhal::Integer(lValues.at(0)),
     442              :       ", ",
     443            0 :       uhal::Integer(lValues.at(1)),
     444              :       ", ",
     445            0 :       uhal::Integer(lValues.at(2)),
     446              :       ", ",
     447            0 :       uhal::Integer(lValues.at(3)),
     448              :       "): ",
     449            0 :       PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
     450            0 :   aGuard.unlock();
     451              : 
     452            0 :   mNumberOfPages = lValues.at(0);
     453              :   // mPageSize = std::min(uint32_t(4096), lValues.at(1));
     454            0 :   mPageSize = lValues.at(1);
     455            0 :   mIndexNextPage = lValues.at(2);
     456            0 :   mPublishedReplyPageCount = lValues.at(3);
     457            0 :   mReadReplyPageCount = mPublishedReplyPageCount;
     458              : 
     459            0 :   if (lValues.at(1) > 0xFFFF) {
     460            0 :     exception::FlxInitialisationError lExc;
     461            0 :     log(lExc,
     462              :         "Invalid page size, ",
     463            0 :         uhal::Integer(lValues.at(1)),
     464              :         ", reported in device file ",
     465            0 :         uhal::Quote(mDeviceFile.getPath()));
     466            0 :     throw lExc;
     467            0 :   }
     468              : 
     469            0 :   if (mIndexNextPage >= mNumberOfPages) {
     470            0 :     exception::FlxInitialisationError lExc;
     471            0 :     log(lExc,
     472              :         "Next page index, ",
     473            0 :         uhal::Integer(mIndexNextPage),
     474              :         ", reported in device file ",
     475            0 :         uhal::Quote(mDeviceFile.getPath()),
     476              :         " is inconsistent with number of pages, ",
     477            0 :         uhal::Integer(mNumberOfPages));
     478            0 :     throw lExc;
     479            0 :   }
     480              : 
     481            0 :   mConnected = true;
     482            0 :   log(uhal::Info(),
     483              :       "flx client connected to device at ",
     484            0 :       uhal::Quote(mDeviceFile.getPath()),
     485              :       "; FPGA has ",
     486            0 :       uhal::Integer(mNumberOfPages),
     487              :       " pages, each of size ",
     488            0 :       uhal::Integer(mPageSize),
     489              :       " words, index ",
     490            0 :       uhal::Integer(mIndexNextPage),
     491              :       " should be filled next");
     492            0 : }
     493              : 
     494              : void
     495            0 : Flx::disconnect()
     496              : {
     497            0 :   log(uhal::Debug(), "flx client is closing device file ", uhal::Quote(mDeviceFile.getPath()));
     498            0 :   mDeviceFile.close();
     499            0 :   mConnected = false;
     500            0 : }
     501              : 
     502              : void
     503            0 : Flx::write(const std::shared_ptr<uhal::Buffers>& aBuffers)
     504              : {
     505            0 :   if (not mDeviceFile.haveLock()) {
     506            0 :     mDeviceFile.lock();
     507              : 
     508            0 :     IPCScopedLock_t lGuard(*mIPCMutex);
     509            0 :     mIPCMutex->startSession();
     510            0 :     mIPCSessionCount++;
     511              : 
     512            0 :     if (mIPCExternalSessionActive or (mIPCMutex->getCounter() != mIPCSessionCount)) {
     513            0 :       connect(lGuard);
     514              :     }
     515            0 :   }
     516              : 
     517            0 :   log(uhal::Info(),
     518              :       "flx client ",
     519            0 :       uhal::Quote(id()),
     520              :       " (URI: ",
     521            0 :       uhal::Quote(uri()),
     522              :       ") : writing ",
     523            0 :       uhal::Integer(aBuffers->sendCounter() / 4),
     524              :       "-word packet to page ",
     525            0 :       uhal::Integer(mIndexNextPage),
     526              :       " in ",
     527            0 :       uhal::Quote(mDeviceFile.getPath()));
     528              : 
     529            0 :   const uint32_t lHeaderWord = (0x10000 | (((aBuffers->sendCounter() / 4) - 1) & 0xFFFF));
     530            0 :   std::vector<std::pair<const uint8_t*, size_t>> lDataToWrite;
     531            0 :   lDataToWrite.push_back(std::make_pair(reinterpret_cast<const uint8_t*>(&lHeaderWord), sizeof lHeaderWord));
     532            0 :   lDataToWrite.push_back(std::make_pair(aBuffers->getSendBuffer(), aBuffers->sendCounter()));
     533              : 
     534            0 :   IPCScopedLock_t lGuard(*mIPCMutex);
     535            0 :   mDeviceFile.write(mIndexNextPage * mPageSize, lDataToWrite);
     536            0 :   log(uhal::Debug(),
     537              :       "Wrote ",
     538            0 :       uhal::Integer((aBuffers->sendCounter() / 4) + 1),
     539              :       " 32-bit words at address ",
     540            0 :       uhal::Integer(mIndexNextPage * 4 * mPageSize),
     541              :       " ... ",
     542            0 :       PacketFmt(lDataToWrite));
     543              : 
     544            0 :   mIndexNextPage = (mIndexNextPage + 1) % mNumberOfPages;
     545            0 :   mReplyQueue.push_back(aBuffers);
     546            0 : }
     547              : 
     548              : void
     549            0 : Flx::read()
     550              : {
     551            0 :   const size_t lPageIndexToRead = (mIndexNextPage - mReplyQueue.size() + mNumberOfPages) % mNumberOfPages;
     552            0 :   SteadyClock_t::time_point lStartTime = SteadyClock_t::now();
     553              : 
     554            0 :   if (mReadReplyPageCount == mPublishedReplyPageCount) {
     555            0 :     uint32_t lHwPublishedPageCount = 0x0;
     556              : 
     557            0 :     std::vector<uint32_t> lValues;
     558            0 :     while (true) {
     559            0 :       IPCScopedLock_t lGuard(*mIPCMutex);
     560              :       // FIXME : Improve by simply adding dmaWrite method that takes uint32_t ref as argument (or returns uint32_t)
     561            0 :       mDeviceFile.read(0, 4, lValues);
     562            0 :       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            0 :       log(uhal::Debug(),
     567              :           "Read status info from addr 0 (",
     568            0 :           uhal::Integer(lValues.at(0)),
     569              :           ", ",
     570            0 :           uhal::Integer(lValues.at(1)),
     571              :           ", ",
     572            0 :           uhal::Integer(lValues.at(2)),
     573              :           ", ",
     574            0 :           uhal::Integer(lValues.at(3)),
     575              :           "): ",
     576            0 :           PacketFmt((const uint8_t*)lValues.data(), 4 * lValues.size()));
     577              : 
     578            0 :       if (lHwPublishedPageCount != mPublishedReplyPageCount) {
     579            0 :         mPublishedReplyPageCount = lHwPublishedPageCount;
     580            0 :         break;
     581              :       }
     582              :       // FIXME: Throw if published page count is invalid number
     583              : 
     584            0 :       if (SteadyClock_t::now() - lStartTime > std::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
     585            0 :         exception::FlxTimeout lExc;
     586            0 :         log(lExc,
     587              :             "Next page (index ",
     588            0 :             uhal::Integer(lPageIndexToRead),
     589              :             " count ",
     590            0 :             uhal::Integer(mPublishedReplyPageCount + 1),
     591            0 :             ") of flx device '" + mDeviceFile.getPath() + "' is not ready after timeout period");
     592            0 :         throw lExc;
     593            0 :       }
     594              : 
     595            0 :       log(uhal::Debug(),
     596              :           "flx client ",
     597            0 :           uhal::Quote(id()),
     598              :           " (URI: ",
     599            0 :           uhal::Quote(uri()),
     600              :           ") : Trying to read page index ",
     601            0 :           uhal::Integer(lPageIndexToRead),
     602              :           " = count ",
     603            0 :           uhal::Integer(mReadReplyPageCount + 1),
     604              :           "; published page count is ",
     605            0 :           uhal::Integer(lHwPublishedPageCount),
     606              :           "; sleeping for ",
     607            0 :           mSleepDuration.count(),
     608              :           "us");
     609            0 :       if (mSleepDuration > std::chrono::microseconds(0))
     610            0 :         std::this_thread::sleep_for(mSleepDuration);
     611            0 :       lValues.clear();
     612            0 :     }
     613              : 
     614            0 :     log(uhal::Info(),
     615              :         "flx client ",
     616            0 :         uhal::Quote(id()),
     617              :         " (URI: ",
     618            0 :         uhal::Quote(uri()),
     619              :         ") : Reading page ",
     620            0 :         uhal::Integer(lPageIndexToRead),
     621              :         " (published count ",
     622            0 :         uhal::Integer(lHwPublishedPageCount),
     623              :         ", surpasses required, ",
     624            0 :         uhal::Integer(mReadReplyPageCount + 1),
     625              :         ")");
     626            0 :   }
     627            0 :   mReadReplyPageCount++;
     628              : 
     629              :   // PART 1 : Read the page
     630            0 :   std::shared_ptr<uhal::Buffers> lBuffers = mReplyQueue.front();
     631            0 :   mReplyQueue.pop_front();
     632              : 
     633            0 :   uint32_t lNrWordsToRead(lBuffers->replyCounter() >> 2);
     634            0 :   lNrWordsToRead += 1;
     635              : 
     636            0 :   std::vector<uint32_t> lPageContents;
     637            0 :   IPCScopedLock_t lGuard(*mIPCMutex);
     638            0 :   mDeviceFile.read(4 + lPageIndexToRead * mPageSize, lNrWordsToRead, lPageContents);
     639            0 :   lGuard.unlock();
     640            0 :   log(uhal::Debug(),
     641              :       "Read ",
     642            0 :       uhal::Integer(lNrWordsToRead),
     643              :       " 32-bit words from address ",
     644            0 :       uhal::Integer(4 + lPageIndexToRead * 4 * mPageSize),
     645              :       " ... ",
     646            0 :       PacketFmt((const uint8_t*)lPageContents.data(), 4 * lPageContents.size()));
     647              : 
     648              :   // PART 2 : Transfer to reply buffer
     649            0 :   const std::deque<std::pair<uint8_t*, uint32_t>>& lReplyBuffers(lBuffers->getReplyBuffer());
     650            0 :   size_t lNrWordsInPacket = (lPageContents.at(0) >> 16) + (lPageContents.at(0) & 0xFFFF);
     651            0 :   if (lNrWordsInPacket != (lBuffers->replyCounter() >> 2))
     652            0 :     log(uhal::Warning(),
     653              :         "Expected reply packet to contain ",
     654            0 :         uhal::Integer(lBuffers->replyCounter() >> 2),
     655              :         " words, but it actually contains ",
     656            0 :         uhal::Integer(lNrWordsInPacket),
     657              :         " words");
     658              : 
     659            0 :   size_t lNrBytesCopied = 0;
     660            0 :   for (std::deque<std::pair<uint8_t*, uint32_t>>::const_iterator lIt = lReplyBuffers.begin();
     661            0 :        lIt != lReplyBuffers.end();
     662            0 :        ++lIt) {
     663              :     // Don't copy more of page than was written to, for cases when less data received than expected
     664            0 :     if (lNrBytesCopied >= 4 * lNrWordsInPacket)
     665              :       break;
     666              : 
     667            0 :     size_t lNrBytesToCopy = std::min(lIt->second, uint32_t(4 * lNrWordsInPacket - lNrBytesCopied));
     668            0 :     memcpy(lIt->first, &lPageContents.at(1 + (lNrBytesCopied / 4)), lNrBytesToCopy);
     669            0 :     lNrBytesCopied += lNrBytesToCopy;
     670              :   }
     671              : 
     672              :   // PART 3 : Validate the packet contents
     673            0 :   try {
     674            0 :     if (uhal::exception::exception* lExc =
     675            0 :           ClientInterface::validate(lBuffers)) // Control of the pointer has been passed back to the client interface
     676              :     {
     677            0 :       mAsynchronousException = lExc;
     678              :     }
     679            0 :   } catch (uhal::exception::exception& aExc) {
     680            0 :     mAsynchronousException = new uhal::exception::ValidationError();
     681            0 :     log(*mAsynchronousException,
     682              :         "Exception caught during reply validation for flx device with URI ",
     683            0 :         uhal::Quote(this->uri()),
     684              :         "; what returned: ",
     685            0 :         uhal::Quote(aExc.what()));
     686            0 :   }
     687              : 
     688            0 :   if (mAsynchronousException) {
     689            0 :     mAsynchronousException->throwAsDerivedType();
     690              :   }
     691            0 : }
     692              : 
     693              : } // end ns uhal
        

Generated by: LCOV version 2.0-1