LCOV - code coverage report
Current view: top level - mu2e-pcie-utils/cfoInterfaceLib - CFO.cpp (source / functions) Coverage Total Hit
Test: mu2edaq.info.cleaned Lines: 0.0 % 259 0
Test Date: 2026-07-30 01:56:44 Functions: 0.0 % 72 0

            Line data    Source code
       1              : 
       2              : #include "TRACE/tracemf.h"
       3              : #define TRACE_NAME "CFO.cpp"
       4              : 
       5              : #include "CFO.h"
       6              : #define TLVL_GetData TLVL_DEBUG + 5
       7              : #define TLVL_ReadBuffer TLVL_DEBUG + 7
       8              : #define TLVL_ReadNextDAQPacket TLVL_DEBUG + 8
       9              : #define TLVL_ReleaseBuffers TLVL_DEBUG + 20
      10              : #define TLVL_GetCurrentBuffer TLVL_DEBUG + 21
      11              : 
      12              : #include "dtcInterfaceLib/otsStyleCoutMacros.h"
      13              : 
      14              : #define CFO_TLOG(lvl) TLOG(lvl) << "CFO " << device_.getDeviceUID() << ": "
      15              : #undef __COUT_HDR__
      16              : #define __COUT_HDR__ "CFO " << device_.getDeviceUID() << ": "
      17              : 
      18              : #include <unistd.h>
      19              : #include <fstream>
      20              : #include <iostream>
      21              : #include <sstream>  // Convert uint to hex string
      22              : 
      23            0 : CFOLib::CFO::CFO(DTC_SimMode mode, int cfo, std::string expectedDesignVersion, bool skipInit, const std::string& uid)
      24            0 :         : CFO_Registers(mode, cfo, expectedDesignVersion, skipInit, uid), daqDMAInfo_()  //, dcsDMAInfo_()
      25              : {
      26            0 :         __COUT_INFO__ << "CONSTRUCTOR";
      27            0 : }
      28              : 
      29            0 : CFOLib::CFO::~CFO()
      30              : {
      31            0 :         __COUT_INFO__ << "DESTRUCTOR";
      32              :         // TLOG_ENTEX(-6);
      33            0 :         TRACE_EXIT
      34              :         {
      35            0 :                 __COUT__ << "DESTRUCTOR exit";
      36            0 :         };
      37              : 
      38              :         // do not want to release all from destructor, in case this instance of the device is not the 'owner' of a DMA-channel
      39              :         //      so do not call ReleaseAllBuffers(CFO_DMA_Engine_DAQ) or ReleaseAllBuffers(CFO_DMA_Engine_RunPlan);
      40            0 : }
      41              : 
      42              : //
      43              : // DMA Functions
      44              : //
      45            0 : bool CFOLib::CFO::GetData(std::vector<std::unique_ptr<CFOLib::CFO_Event>>& output,
      46              :                                                   DTC_EventWindowTag when, bool matchEventWindowTag)
      47              : {
      48            0 :         CFO_TLOG(TLVL_GetData) << "GetCFOEventData begin EventWindowTag=" << when.GetEventWindowTag(true) << ", matching=" << (matchEventWindowTag ? "true" : "false");
      49              :         // std::vector<std::unique_ptr<CFO_Event>> output;
      50            0 :         output.clear();  // start out with vector empty
      51            0 :         bool result = false;
      52              : 
      53              :         // Release read buffers here "I am done with everything I read before" (because the return may be pointers to the raw data, not copies)
      54            0 :         ReleaseBuffers(DTC_DMA_Engine_DAQ);  // Currently race condition because GetCurrentBuffer(info) is used inside to decide how many buffers to release.
      55              : 
      56              :         try
      57              :         {
      58              :                 // Read the next CFO_Event
      59            0 :                 auto tries = 0;
      60            0 :                 while (!result && tries < 3)
      61              :                 {
      62            0 :                         CFO_TLOG(TLVL_GetData) << "GetCFOEventData before ReadNextCFORecordDMA(...), tries = " << tries;
      63            0 :                         result = ReadNextCFORecordDMA(output, 100 /* ms */);
      64            0 :                         if (result)
      65              :                         {
      66            0 :                                 if (output.size() == 0)  // check that output vector is not empty
      67              : 
      68              :                                 {
      69            0 :                                         __SS__ << "Impossible empty ouput vector after returned success!" << __E__;
      70            0 :                                         __SS_THROW__;
      71            0 :                                 }
      72              : 
      73            0 :                                 CFO_TLOG(TLVL_GetData) << "GetCFOEventData after ReadNextCFORecordDMA, found tag = "
      74            0 :                                                                            << output.back()->GetEventWindowTag().GetEventWindowTag(true) << " (0x"
      75            0 :                                                                            << std::hex << output.back()->GetEventWindowTag().GetEventWindowTag(true) << "), expected tag = "
      76            0 :                                                                            << std::dec << when.GetEventWindowTag(true) << " (0x" << std::hex << when.GetEventWindowTag(true) << ")";
      77              :                         }
      78              :                         else
      79            0 :                                 CFO_TLOG(TLVL_GetData) << "GetCFOEventData after ReadNextCFORecordDMA, no data";
      80            0 :                         tries++;
      81              :                         // if (!result) usleep(5000); //causes loss of bandwidth
      82              :                 }
      83              : 
      84              :                 // return if no data found
      85            0 :                 if (!result)
      86              :                 {
      87            0 :                         CFO_TLOG(TLVL_GetData) << "GetData: Timeout Occurred! (CFO_Event is nullptr after retries); no data found; RETURNing output.size()=" << output.size();
      88            0 :                         return output.size();
      89              :                 }
      90              : 
      91              :                 // return if failed to match
      92            0 :                 if (matchEventWindowTag && output[0]->GetEventWindowTag() != when)
      93              :                 {
      94            0 :                         CFO_TLOG(TLVL_ERROR) << "GetData: Error: CFO_Event has wrong Event Window Tag! 0x" << std::hex << when.GetEventWindowTag(true)
      95            0 :                                                                  << "(expected) != 0x" << std::hex << output[0]->GetEventWindowTag().GetEventWindowTag(true);
      96              :                         // packet.reset(nullptr);
      97            0 :                         daqDMAInfo_.currentReadPtr = daqDMAInfo_.lastReadPtr;
      98            0 :                         return output.size();
      99              :                 }
     100              : 
     101              :                 // // increment for next packet search
     102              :                 // when = DTC_EventWindowTag(packet->GetEventWindowTag().GetEventWindowTag(true) + 1);
     103              : 
     104              :                 // CFO_TLOG(TLVL_GetData) << "GetData: Adding CFO_Event tag = " << packet->GetEventWindowTag().GetEventWindowTag(true) << " to the list, ptr=" << (void*)daqDMAInfo_.lastReadPtr;
     105              :                 // output.push_back(std::move(packet));
     106              :         }
     107            0 :         catch (DTC_WrongPacketTypeException& ex)
     108              :         {
     109            0 :                 daqDMAInfo_.currentReadPtr = nullptr;
     110            0 :                 CFO_TLOG(TLVL_ERROR) << "GetData: Bad omen: Wrong packet type at the current read position";
     111            0 :                 device_.spy(DTC_DMA_Engine_DAQ, 3 /* for once */ | 8 /* for wide view */ | 16 /* for stack trace */);
     112            0 :                 throw;
     113            0 :         }
     114            0 :         catch (DTC_IOErrorException& ex)
     115              :         {
     116            0 :                 daqDMAInfo_.currentReadPtr = nullptr;
     117            0 :                 CFO_TLOG(TLVL_ERROR) << "GetData: IO Exception Occurred!";
     118            0 :                 device_.spy(DTC_DMA_Engine_DAQ, 3 /* for once */ | 8 /* for wide view */ | 16 /* for stack trace */);
     119            0 :                 throw;
     120            0 :         }
     121            0 :         catch (DTC_DataCorruptionException& ex)
     122              :         {
     123            0 :                 daqDMAInfo_.currentReadPtr = nullptr;
     124            0 :                 CFO_TLOG(TLVL_ERROR) << "GetData: Data Corruption Exception Occurred!";
     125            0 :                 device_.spy(DTC_DMA_Engine_DAQ, 3 /* for once */ | 8 /* for wide view */ | 16 /* for stack trace */);
     126            0 :                 throw;
     127            0 :         }
     128              : 
     129            0 :         CFO_TLOG(TLVL_GetData) << "GetCFOEventData RETURN output.size()=" << output.size()
     130            0 :                                                    << " first tag=" << output[0]->GetEventWindowTag().GetEventWindowTag(true)
     131            0 :                                                    << " last tag=" << output.back()->GetEventWindowTag().GetEventWindowTag(true);
     132            0 :         return output.size();
     133              : }  // GetData
     134              : 
     135            0 : bool CFOLib::CFO::ReadNextCFORecordDMA(std::vector<std::unique_ptr<CFO_Event>>& output, int tmo_ms)
     136              : {
     137            0 :         TRACE_EXIT
     138              :         {
     139            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA EXIT"
     140            0 :                                                                                  << " currentReadPtr=" << (void*)daqDMAInfo_.currentReadPtr
     141            0 :                                                                                  << " lastReadPtr=" << (void*)daqDMAInfo_.lastReadPtr
     142            0 :                                                                                  << " buffer.size()=" << daqDMAInfo_.buffer.size();
     143            0 :         };
     144              : 
     145            0 :         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA BEGIN";
     146              : 
     147            0 :         if (daqDMAInfo_.currentReadPtr != nullptr)
     148              :         {
     149            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA BEFORE BUFFER CHECK daqDMAInfo_.currentReadPtr="
     150            0 :                                                                                  << (void*)daqDMAInfo_.currentReadPtr << " currentBufferTransferSize=0x" << std::hex
     151            0 :                                                                                  << *(uint16_t*)daqDMAInfo_.currentReadPtr;
     152              :         }
     153              :         else
     154              :         {
     155            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA BEFORE BUFFER CHECK daqDMAInfo_.currentReadPtr=nullptr";
     156              :         }
     157              : 
     158            0 :         auto index = CFOandDTC_DMAs::GetCurrentBuffer(&daqDMAInfo_);  // if buffers onhand, returns daqDMAInfo_.buffer.size().. which is count used by ReleaseBuffers()
     159              : 
     160            0 :         size_t metaBufferSize = 0;
     161              : 
     162              :         // Need new starting subevent buffer if GetCurrentBuffer returns -1 (no buffers) or -2 (done with all held buffers)
     163            0 :         if (index < 0)
     164              :         {
     165            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA Obtaining new DAQ Buffer";
     166              : 
     167            0 :                 void* oldBufferPtr = nullptr;
     168            0 :                 if (daqDMAInfo_.buffer.size() > 0) oldBufferPtr = &daqDMAInfo_.buffer.back()[0];
     169            0 :                 auto sts = ReadBuffer(DTC_DMA_Engine_DAQ, tmo_ms);  // does return code
     170            0 :                 if (sts <= 0)
     171              :                 {
     172            0 :                         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA: ReadBuffer returned " << sts << ", returning nullptr";
     173            0 :                         return false;
     174              :                 }
     175            0 :                 metaBufferSize = sts;
     176              : 
     177              :                 // MUST BE ABLE TO HANDLE daqbuffer_==nullptr OR retry forever?
     178            0 :                 daqDMAInfo_.currentReadPtr = &daqDMAInfo_.buffer.back()[0];
     179            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA daqDMAInfo_.currentReadPtr=" << (void*)daqDMAInfo_.currentReadPtr
     180            0 :                                                                                  << " currentBufferTransferSize=0x" << std::hex << *(unsigned*)daqDMAInfo_.currentReadPtr
     181            0 :                                                                                  << " lastReadPtr=0x" << (void*)daqDMAInfo_.lastReadPtr
     182            0 :                                                                                  << " metaBufferSize=0x" << metaBufferSize;
     183            0 :                 void* bufferIndexPointer = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
     184            0 :                 if (daqDMAInfo_.currentReadPtr == oldBufferPtr && daqDMAInfo_.bufferIndex == *static_cast<uint32_t*>(bufferIndexPointer))
     185              :                 {
     186            0 :                         daqDMAInfo_.currentReadPtr = nullptr;
     187              :                         // We didn't actually get a new buffer...this probably means there's no more data
     188              :                         // Try and see if we're merely stuck...hopefully, all the data is out of the buffers...
     189            0 :                         device_.read_release(DTC_DMA_Engine_DAQ, 1);
     190            0 :                         CFO_TLOG(TLVL_WARN)
     191            0 :                                 << "ReadNextCFORecordDMA: New buffer was the same as old. Released buffer and returning nullptr";
     192            0 :                         return false;
     193              :                 }
     194            0 :                 daqDMAInfo_.bufferIndex++;
     195              : 
     196            0 :                 daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
     197            0 :                 *static_cast<uint32_t*>(daqDMAInfo_.currentReadPtr) = daqDMAInfo_.bufferIndex;
     198            0 :                 daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
     199              : 
     200            0 :                 index = daqDMAInfo_.buffer.size() - 1;
     201            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "Creating CFO_EventRecord(s) from new DMA Buffer, index=" << index << " in " << daqDMAInfo_.buffer.size() << " buffers.";
     202              :         }
     203              :         else  // buffer already onhand
     204              :         {
     205            0 :                 __SS__ << "Impossible buffer already onhand!" << __E__;
     206            0 :                 __SS_THROW__;
     207              : 
     208              :                 // CFO_TLOG(TLVL_ReadNextDAQPacket) << "Creating CFO_EventRecord from current DMA Buffer, index=" << index <<
     209              :                 //      " in " << daqDMAInfo_.buffer.size() << " buffers.";
     210            0 :         }
     211              : 
     212            0 :         if (  // current read ptr sanity check
     213            0 :                 (void*)(static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) - 8) !=
     214            0 :                 (void*)(&daqDMAInfo_.buffer[index][0]))
     215              :         {
     216            0 :                 __SS__ << "Impossible current buffer pointer for index " << index << ".. " << (void*)(static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) - 8) << " != " << (void*)&daqDMAInfo_.buffer[index - 1][0] << __E__;
     217            0 :                 __SS_THROW__;
     218            0 :         }
     219              : 
     220              :         // Utilities::PrintBuffer(daqDMAInfo_.currentReadPtr, 128, TLVL_ReadNextDAQPacket);
     221              :         // auto res = std::make_unique<CFO_Event>(daqDMAInfo_.currentReadPtr);
     222              :         // complete data was copied into CFO Event Record
     223              : 
     224              :         // auto subEventByteCount = res->GetSubEventByteCount();
     225              :         // if (subEventByteCount < sizeof(CFO_EventRecord))
     226              :         // {
     227              :         //      __SS__ << "SubEvent inclusive byte count cannot be less than the size of the subevent header (" << sizeof(CFO_EventRecord) << "-bytes)!" << __E__;
     228              :         //      __SS_THROW__;
     229              :         // }
     230            0 :         size_t remainingBufferSize = CFOandDTC_DMAs::GetBufferByteCount(&daqDMAInfo_, index);
     231            0 :         CFO_TLOG(TLVL_ReadNextDAQPacket) << "sizeof(CFO_EventRecord) = " << sizeof(CFO_EventRecord)
     232            0 :                                                                          << " GetBufferByteCount=" << remainingBufferSize
     233            0 :                                                                          << " metaBufferSize=" << metaBufferSize;
     234              : 
     235              :         // Use DMA descriptor byte count from ReadBuffer (dont use the in-buffer DMA transfer size count because the CFO stacks transfers!)
     236              :         // Subtract 1 for tlast byte, but NOT when buffer is completely full (no room for tlast)
     237            0 :         remainingBufferSize = metaBufferSize < sizeof(mu2e_databuff_t) ? metaBufferSize - 1 : metaBufferSize;
     238              : 
     239              :         //      if (0)  // for deubbging
     240              :         //      {
     241              :         //              std::cout << "1st DMA buffer res size=" << remainingBufferSize << "\n";
     242              :         //              auto ptr = reinterpret_cast<const uint8_t*>(res->GetRawBufferPointer());
     243              :         //              for (size_t i = 0; i < remainingBufferSize + 16; i += 4)
     244              :         //                      std::cout << std::dec << "res#" << i << "/" << remainingBufferSize << "(" << i / 16 << "/" << remainingBufferSize / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
     245              :         //      }
     246              : 
     247            0 :         uint64_t lastTag = -1;
     248            0 :         while (remainingBufferSize >= sizeof(CFO_EventRecord))
     249              :         {
     250            0 :                 remainingBufferSize -= sizeof(uint64_t);  // remove DMA transfer size from remaining byte count
     251              : 
     252            0 :                 auto res = std::make_unique<CFO_Event>(daqDMAInfo_.currentReadPtr);
     253              : 
     254            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "subevent tag=" << res->GetEventWindowTag().GetEventWindowTag(true) << std::hex << "(0x" << res->GetEventWindowTag().GetEventWindowTag(true) << ")"
     255            0 :                                                                                  << " inclusive byte count: 0x" << std::hex << sizeof(CFO_EventRecord) << " (" << std::dec << sizeof(CFO_EventRecord) << ")"
     256            0 :                                                                                  << ", remaining buffer size: 0x" << std::hex << remainingBufferSize << " (" << std::dec << remainingBufferSize << ")";
     257              : 
     258            0 :                 if (res->GetEventWindowTag().GetEventWindowTag(true) == lastTag)
     259              :                 {
     260            0 :                         __SS__ << "Impossible repeating tag " << lastTag << __E__;
     261            0 :                         __SS_THROW__;
     262            0 :                 }
     263              : 
     264            0 :                 lastTag = res->GetEventWindowTag().GetEventWindowTag(true);
     265              : 
     266            0 :                 daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + sizeof(CFO_EventRecord) + sizeof(uint64_t);
     267            0 :                 remainingBufferSize -= sizeof(CFO_EventRecord);
     268              : 
     269            0 :                 output.push_back(std::move(res));
     270              : 
     271            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "CFO subevent record JSON=" << output.back()->GetEventRecord().toJson();
     272            0 :         }  // end primary CFO Event Record extraction loop
     273              : 
     274              :         // check that size is multiple of CFO Event Record side sanity
     275            0 :         if (remainingBufferSize != 0)
     276              :         {
     277            0 :                 __SS__ << "Impossible remainingBufferSize of " << remainingBufferSize << __E__;
     278            0 :                 __SS_THROW__;
     279            0 :         }
     280              : 
     281              :         // // Check if there are more than one CFO_EventRecords
     282              :         // if (subEventByteCount > remainingBufferSize)
     283              :         // {
     284              :         //      CFO_TLOG(TLVL_ReadNextDAQPacket) << "subevent needs more data by bytes " << std::hex << subEventByteCount - remainingBufferSize << " (" << std::dec << subEventByteCount - remainingBufferSize << ") packets " << (subEventByteCount - remainingBufferSize) / 16 << ". subEventByteCount=" << subEventByteCount << " remainingBufferSize=" << remainingBufferSize;
     285              : 
     286              :         //      // We're going to set lastReadPtr here, so that if this buffer isn't used by GetData, we start at the beginning of this event next time
     287              :         //      daqDMAInfo_.lastReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr);
     288              : 
     289              :         //      auto inmem = std::make_unique<CFO_EventRecord>(subEventByteCount);
     290              : 
     291              :         //      memcpy(const_cast<void*>(inmem->GetRawBufferPointer()), res->GetRawBufferPointer(), remainingBufferSize);
     292              : 
     293              :         //      if (0)  // for deubbging
     294              :         //      {
     295              :         //              std::cout << "1st DMA buffer inmem size=" << remainingBufferSize << "\n";
     296              :         //              auto ptr = reinterpret_cast<const uint8_t*>(inmem->GetRawBufferPointer());
     297              :         //              for (size_t i = 0; i < remainingBufferSize + 16; i += 4)
     298              :         //                      std::cout << std::dec << "inmem#" << i << "(" << i / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
     299              :         //      }
     300              : 
     301              :         //      auto bytes_read = remainingBufferSize;
     302              :         //      while (bytes_read < subEventByteCount)
     303              :         //      {
     304              :         //              CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA tag=" << inmem->GetEventWindowTag().GetEventWindowTag(true) << std::hex << "(0x" << inmem->GetEventWindowTag().GetEventWindowTag(true) << ")"
     305              :         //                                                                               << " Obtaining new DAQ Buffer, bytes_read=" << bytes_read << ", subEventByteCount=" << subEventByteCount;
     306              : 
     307              :         //              void* oldBufferPtr = nullptr;
     308              :         //              if (daqDMAInfo_.buffer.size() > 0) oldBufferPtr = &daqDMAInfo_.buffer.back()[0];
     309              : 
     310              :         //              if (0)  // for deubbging
     311              :         //              {
     312              :         //                      std::cout << "1st DMA buffer\n";
     313              :         //                      auto ptr = reinterpret_cast<const uint8_t*>(&daqDMAInfo_.buffer.back()[0]);
     314              :         //                      for (size_t i = 0; i < bytes_read + 32; i += 4)
     315              :         //                              std::cout << std::dec << "#" << i << "(" << i / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
     316              :         //              }
     317              : 
     318              :         //              int sts;
     319              :         //              int retry = 10;
     320              :         //              // timeout is an exception at this point because no way to resolve partial subevent record!
     321              :         //              while ((sts = ReadBuffer(CFO_DMA_Engine_DAQ, 10 /* retries */))  // does return code
     322              :         //                                 <= 0 &&
     323              :         //                         --retry > 0) usleep(1000);
     324              : 
     325              :         //              if (sts <= 0)
     326              :         //              {
     327              :         //                      __SS__ << "Timeout of " << tmo_ms << " ms after receiving only partial subevent! Subevent tag=" << inmem->GetEventWindowTag().GetEventWindowTag(true) << std::hex << "(0x" << inmem->GetEventWindowTag().GetEventWindowTag(true) << ")";
     328              :         //                      __SS_THROW__;
     329              :         //              }
     330              : 
     331              :         //              daqDMAInfo_.currentReadPtr = &daqDMAInfo_.buffer.back()[0];
     332              :         //              CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA daqDMAInfo_.currentReadPtr=" << (void*)daqDMAInfo_.currentReadPtr
     333              :         //                                                                               << " *daqDMAInfo_.currentReadPtr=0x" << std::hex << *(unsigned*)daqDMAInfo_.currentReadPtr
     334              :         //                                                                               << " lastReadPtr=" << (void*)daqDMAInfo_.lastReadPtr;
     335              : 
     336              :         //              if (0)  // for deubbging
     337              :         //              {
     338              :         //                      std::cout << "1st buffer\n";
     339              :         //                      auto ptr = reinterpret_cast<const uint8_t*>(inmem->GetRawBufferPointer());
     340              :         //                      for (size_t i = 0; i < bytes_read + 16; i += 4)
     341              :         //                              std::cout << std::dec << "#" << i << "(" << i / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
     342              :         //              }
     343              : 
     344              :         //              void* bufferIndexPointer = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
     345              :         //              if (daqDMAInfo_.currentReadPtr == oldBufferPtr && daqDMAInfo_.bufferIndex == *static_cast<uint32_t*>(bufferIndexPointer))
     346              :         //              {
     347              :         //                      // We didn't actually get a new buffer...this probably means there's no more data
     348              :         //                      // timeout is an exception at this point because no way to resolve partial subevent record!
     349              :         //                      __SS__ << "Received same buffer twice, only received partial subevent!! Subevent tag=" << inmem->GetEventWindowTag().GetEventWindowTag(true) << std::hex << "(0x" << inmem->GetEventWindowTag().GetEventWindowTag(true) << ")";
     350              :         //                      __SS_THROW__;
     351              :         //              }
     352              :         //              daqDMAInfo_.bufferIndex++;
     353              : 
     354              :         //              size_t buffer_size = *static_cast<uint16_t*>(daqDMAInfo_.currentReadPtr);
     355              :         //              daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
     356              :         //              *static_cast<uint32_t*>(daqDMAInfo_.currentReadPtr) = daqDMAInfo_.bufferIndex;
     357              :         //              daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
     358              : 
     359              :         //              size_t remainingEventSize = subEventByteCount - bytes_read;
     360              :         //              size_t copySize = remainingEventSize < buffer_size - 8 ? remainingEventSize : buffer_size - 8;
     361              : 
     362              :         //              if (0)  // for deubbging
     363              :         //              {
     364              :         //                      std::cout << "2nd buffer\n";
     365              :         //                      auto ptr = reinterpret_cast<const uint8_t*>(daqDMAInfo_.currentReadPtr);
     366              :         //                      for (size_t i = 0; i < copySize; i += 4)
     367              :         //                              std::cout << std::dec << "#" << i << "(" << i / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
     368              :         //              }
     369              : 
     370              :         //              CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA bytes_read = " << bytes_read << " packets = " << bytes_read / 16 - sizeof(CFO_EventRecord) / 16;
     371              :         //              CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA copySize = " << copySize << " packets = " << copySize / 16;
     372              :         //              memcpy(const_cast<uint8_t*>(static_cast<const uint8_t*>(inmem->GetRawBufferPointer()) + bytes_read), daqDMAInfo_.currentReadPtr, copySize);
     373              :         //              bytes_read += buffer_size - 8;
     374              : 
     375              :         //              // Increment by the size of the data block
     376              :         //              daqDMAInfo_.currentReadPtr = reinterpret_cast<char*>(daqDMAInfo_.currentReadPtr) + copySize;
     377              :         //      }  // end primary continuation of multi-DMA subevent transfers
     378              : 
     379              :         //      res.swap(inmem);
     380              :         // }
     381              :         // else  // SubEvent not split over multiple DMAs
     382              :         // {
     383              :         //      // Update the packet pointers
     384              : 
     385              :         //      // lastReadPtr_ is easy...
     386              :         //      daqDMAInfo_.lastReadPtr = daqDMAInfo_.currentReadPtr;
     387              : 
     388              :         //      // Increment by the size of the data block
     389              :         //      daqDMAInfo_.currentReadPtr = reinterpret_cast<char*>(daqDMAInfo_.currentReadPtr) + res->GetSubEventByteCount();
     390              :         // }
     391              : 
     392              :         // try
     393              :         // {
     394              :         //      res->SetupSubEvent();  // does setup of SubEvent header + all payload
     395              :         // }
     396              :         // catch (...)
     397              :         // {
     398              :         //      device_.spy(CFO_DMA_Engine_DAQ, 3 /* for once */ | 8 /* for wide view */);
     399              :         //      CFO_TLOG(TLVL_ERROR) << otsStyleStackTrace();
     400              :         //      throw;
     401              :         // }
     402              : 
     403            0 :         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA: RETURN vector of " << output.size() << " CFO Event Records";
     404              :         // return res;
     405            0 :         return true;
     406            0 : }  // end ReadNextCFORecordDMA()
     407              : 
     408            0 : std::unique_ptr<CFOLib::CFO_DataPacket> CFOLib::CFO::ReadNextPacket(const DTC_DMA_Engine& engine, int tmo_ms)
     409              : {
     410            0 :         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket BEGIN";
     411              :         CFOandDTC_DMAs::DMAInfo* info;
     412            0 :         if (engine == DTC_DMA_Engine_DAQ)
     413            0 :                 info = &daqDMAInfo_;
     414              :         // else if (engine == DTC_DMA_Engine_DCS)
     415              :         //      info = &dcsDMAInfo_;
     416              :         else
     417              :         {
     418            0 :                 __COUT_ERR__ << "ReadNextPacket: Invalid DMA Engine specified!";
     419            0 :                 throw new DTC_DataCorruptionException();
     420              :         }
     421              : 
     422            0 :         if (info->currentReadPtr != nullptr)
     423              :         {
     424            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket BEFORE BUFFER CHECK info->currentReadPtr="
     425            0 :                                                                                  << (void*)info->currentReadPtr << " *nextReadPtr_=0x" << std::hex
     426            0 :                                                                                  << *(uint16_t*)info->currentReadPtr;
     427              :         }
     428              :         else
     429              :         {
     430            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket BEFORE BUFFER CHECK info->currentReadPtr=nullptr";
     431              :         }
     432              : 
     433            0 :         auto index = CFOandDTC_DMAs::GetCurrentBuffer(info);
     434              : 
     435              :         // Need new buffer if GetCurrentBuffer returns -1 (no buffers) or -2 (done with all held buffers)
     436            0 :         if (index < 0)
     437              :         {
     438            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket Obtaining new " << (engine == DTC_DMA_Engine_DAQ ? "DAQ" : "DCS")
     439            0 :                                                                                  << " Buffer";
     440              : 
     441            0 :                 void* oldBufferPtr = nullptr;
     442            0 :                 if (info->buffer.size() > 0) oldBufferPtr = &info->buffer.back()[0];
     443            0 :                 auto sts = ReadBuffer(engine, tmo_ms);  // does return code
     444            0 :                 if (sts <= 0)
     445              :                 {
     446            0 :                         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: ReadBuffer returned " << sts << ", returning nullptr";
     447            0 :                         return nullptr;
     448              :                 }
     449              :                 // MUST BE ABLE TO HANDLE daqbuffer_==nullptr OR retry forever?
     450            0 :                 info->currentReadPtr = &info->buffer.back()[0];
     451            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket info->currentReadPtr=" << (void*)info->currentReadPtr
     452            0 :                                                                                  << " *info->currentReadPtr=0x" << std::hex << *(unsigned*)info->currentReadPtr
     453            0 :                                                                                  << " lastReadPtr_=" << (void*)info->lastReadPtr;
     454            0 :                 void* bufferIndexPointer = static_cast<uint8_t*>(info->currentReadPtr) + 2;
     455            0 :                 if (info->currentReadPtr == oldBufferPtr && info->bufferIndex == *static_cast<uint32_t*>(bufferIndexPointer))
     456              :                 {
     457            0 :                         CFO_TLOG(TLVL_ReadNextDAQPacket)
     458            0 :                                 << "ReadNextPacket: New buffer is the same as old. Releasing buffer and returning nullptr";
     459            0 :                         info->currentReadPtr = nullptr;
     460              :                         // We didn't actually get a new buffer...this probably means there's no more data
     461              :                         // Try and see if we're merely stuck...hopefully, all the data is out of the buffers...
     462            0 :                         device_.read_release(engine, 1);
     463            0 :                         return nullptr;
     464              :                 }
     465            0 :                 info->bufferIndex++;
     466              : 
     467            0 :                 info->currentReadPtr = reinterpret_cast<uint8_t*>(info->currentReadPtr) + 2;
     468            0 :                 *static_cast<uint32_t*>(info->currentReadPtr) = info->bufferIndex;
     469            0 :                 info->currentReadPtr = reinterpret_cast<uint8_t*>(info->currentReadPtr) + 6;
     470              : 
     471            0 :                 index = info->buffer.size() - 1;
     472              :         }
     473              : 
     474              :         // Read the next packet
     475            0 :         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket reading next packet from buffer: info->currentReadPtr="
     476            0 :                                                                          << (void*)info->currentReadPtr;
     477              : 
     478            0 :         auto blockByteCount = *reinterpret_cast<uint16_t*>(info->currentReadPtr);
     479            0 :         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: blockByteCount=" << blockByteCount
     480            0 :                                                                          << ", info->currentReadPtr=" << (void*)info->currentReadPtr
     481            0 :                                                                          << ", *nextReadPtr=" << (int)*((uint16_t*)info->currentReadPtr);
     482            0 :         if (blockByteCount == 0 || blockByteCount == 0xcafe)
     483              :         {
     484            0 :                 if (static_cast<size_t>(index) < info->buffer.size() - 1)
     485              :                 {
     486            0 :                         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: blockByteCount is invalid, moving to next buffer";
     487            0 :                         auto nextBufferPtr = *info->buffer[index + 1];
     488            0 :                         info->currentReadPtr = nextBufferPtr + 8;  // Offset past DMA header
     489            0 :                         return ReadNextPacket(engine, tmo_ms);     // Recursion
     490              :                 }
     491              :                 else
     492              :                 {
     493            0 :                         CFO_TLOG(TLVL_ReadNextDAQPacket)
     494            0 :                                 << "ReadNextPacket: blockByteCount is invalid, and this is the last buffer! Returning nullptr!";
     495            0 :                         info->currentReadPtr = nullptr;
     496              :                         // This buffer is invalid, release it!
     497              :                         // Try and see if we're merely stuck...hopefully, all the data is out of the buffers...
     498            0 :                         device_.read_release(engine, 1);
     499            0 :                         return nullptr;
     500              :                 }
     501              :         }
     502              : 
     503            0 :         auto test = std::make_unique<CFO_DataPacket>(info->currentReadPtr);
     504            0 :         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: current+blockByteCount="
     505            0 :                                                                          << (void*)(reinterpret_cast<uint8_t*>(info->currentReadPtr) + blockByteCount)
     506            0 :                                                                          << ", end of dma buffer="
     507            0 :                                                                          << (void*)(info->buffer[index][0] + CFOandDTC_DMAs::GetBufferByteCount(info, index) +
     508            0 :                                                                                                 8);  // +8 because first 8 bytes are not included in byte count
     509            0 :         if (reinterpret_cast<uint8_t*>(info->currentReadPtr) + blockByteCount >
     510            0 :                 info->buffer[index][0] + CFOandDTC_DMAs::GetBufferByteCount(info, index) + 8)
     511              :         {
     512            0 :                 blockByteCount = static_cast<uint16_t>(
     513            0 :                         info->buffer[index][0] + CFOandDTC_DMAs::GetBufferByteCount(info, index) + 8 -
     514            0 :                         reinterpret_cast<uint8_t*>(info->currentReadPtr));  // +8 because first 8 bytes are not included in byte count
     515            0 :                 CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: Adjusting blockByteCount to " << blockByteCount
     516            0 :                                                                                  << " due to end-of-DMA condition";
     517            0 :                 test->SetByte(0, blockByteCount & 0xFF);
     518            0 :                 test->SetByte(1, (blockByteCount >> 8));
     519              :         }
     520              : 
     521            0 :         CFO_TLOG(TLVL_ReadNextDAQPacket) << test->toJSON();
     522              : 
     523              :         // Update the packet pointers
     524              : 
     525              :         // lastReadPtr_ is easy...
     526            0 :         info->lastReadPtr = info->currentReadPtr;
     527              : 
     528              :         // Increment by the size of the data block
     529            0 :         info->currentReadPtr = reinterpret_cast<char*>(info->currentReadPtr) + blockByteCount;
     530              : 
     531            0 :         CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: RETURN";
     532            0 :         return test;
     533            0 : }
     534              : 
     535              : //
     536              : // Private Functions.
     537              : //
     538            0 : int CFOLib::CFO::ReadBuffer(const DTC_DMA_Engine& channel, int tmo_ms)
     539              : {
     540              :         mu2e_databuff_t* buffer;
     541              : 
     542            0 :         int retry = 1;
     543              : 
     544              :         // Break long timeouts into multiple 10 ms retries
     545            0 :         if (tmo_ms > 10)
     546              :         {
     547            0 :                 retry = tmo_ms / 10;
     548            0 :                 tmo_ms = 10;
     549              :         }
     550              : 
     551              :         int errorCode;
     552              :         do
     553              :         {
     554            0 :                 CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer before device_.read_data tmo=" << tmo_ms << " retry=" << retry;
     555            0 :                 errorCode = device_.read_data(channel, reinterpret_cast<void**>(&buffer), 1 /* tmo_ms */);
     556              :                 // if (errorCode == 0) usleep(1000);
     557              : 
     558            0 :         } while (retry-- > 0 && errorCode == 0);  // error code of 0 is timeout
     559              : 
     560            0 :         if (errorCode == 0)
     561              :         {
     562            0 :                 CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer: Device timeout occurred! ec=" << errorCode << ", rt=" << retry;
     563              :         }
     564            0 :         else if (errorCode < 0)
     565              :         {
     566            0 :                 CFO_TLOG(TLVL_ERROR) << "ReadBuffer: read_data returned " << errorCode << ", throwing CFO_IOErrorException!";
     567            0 :                 throw DTC_IOErrorException(errorCode);
     568              :         }
     569              :         else
     570              :         {
     571            0 :                 CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer buffer_=" << (void*)buffer << " errorCode=" << errorCode << " *buffer_=0x"
     572            0 :                                                                   << std::hex << *(unsigned*)buffer;
     573            0 :                 if (channel == DTC_DMA_Engine_DAQ)
     574              :                 {
     575            0 :                         daqDMAInfo_.buffer.push_back(buffer);
     576            0 :                         CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer: There are now " << daqDMAInfo_.buffer.size()
     577            0 :                                                                           << " DAQ buffers held in the DTC Library";
     578              :                 }
     579              :                 // else if (channel == DTC_DMA_Engine_DCS)
     580              :                 // {
     581              :                 //      dcsDMAInfo_.buffer.push_back(buffer);
     582              :                 //      CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer: There are now " << dcsDMAInfo_.buffer.size()
     583              :                 //                                                << " DCS buffers held in the DTC Library";
     584              :                 // }
     585              :         }
     586            0 :         return errorCode;
     587              : }
     588              : 
     589            0 : void CFOLib::CFO::ReleaseAllBuffers(const DTC_DMA_Engine& channel)
     590              : {
     591            0 :         TLOG_ENTEX(1) << "ReleaseAllBuffers - channel=" << channel;
     592              : 
     593            0 :         if (channel == DTC_DMA_Engine_DAQ)
     594              :         {
     595            0 :                 daqDMAInfo_.buffer.clear();
     596            0 :                 device_.release_all(channel);
     597              :         }
     598              :         // else if (channel == CFO_DMA_Engine_RunPlan)
     599              :         // {
     600              :         //      dcsDMAInfo_.buffer.clear();
     601              :         //      device_.release_all(channel);
     602              :         // }
     603              :         else
     604              :         {
     605            0 :                 CFO_TLOG(TLVL_ERROR) << "ReadNextPacket: Invalid DMA Engine specified!";
     606            0 :                 throw new DTC_DataCorruptionException();
     607              :         }
     608            0 : }
     609              : 
     610            0 : void CFOLib::CFO::ReleaseBuffers(const DTC_DMA_Engine& channel)
     611              : {
     612            0 :         CFO_TLOG(TLVL_ReleaseBuffers) << "ReleaseBuffers BEGIN";
     613              :         CFOandDTC_DMAs::DMAInfo* info;
     614            0 :         if (channel == DTC_DMA_Engine_DAQ)
     615            0 :                 info = &daqDMAInfo_;
     616              :         // else if (channel == CFO_DMA_Engine_RunPlan)
     617              :         //      info = &dcsDMAInfo_;
     618              :         else
     619              :         {
     620            0 :                 CFO_TLOG(TLVL_ERROR) << "ReadNextPacket: Invalid DMA Engine specified!\n\n"
     621            0 :                                                          << otsStyleStackTrace();
     622            0 :                 throw new DTC_DataCorruptionException();
     623              :         }
     624              : 
     625            0 :         auto releaseBufferCount = CFOandDTC_DMAs::GetCurrentBuffer(info);
     626            0 :         if (releaseBufferCount > 0)
     627              :         {
     628            0 :                 CFO_TLOG(TLVL_ReleaseBuffers) << "ReleaseBuffers releasing " << releaseBufferCount << " "
     629            0 :                                                                           << (channel == DTC_DMA_Engine_DAQ ? "DAQ" : "DCS") << " buffers.";
     630              : 
     631              :                 // if (channel == CFO_DMA_Engine_DCS)
     632              :                 //      device_.begin_dcs_transaction();
     633            0 :                 device_.read_release(channel, releaseBufferCount);
     634              :                 // if (channel == DTC_DMA_Engine_DCS)
     635              :                 //      device_.end_dcs_transaction();
     636              : 
     637            0 :                 for (int ii = 0; ii < releaseBufferCount; ++ii)
     638              :                 {
     639            0 :                         info->buffer.pop_front();
     640              :                 }
     641              :         }
     642              :         // else
     643              :         // {
     644              :         //      CFO_TLOG(TLVL_ReleaseBuffers) << "ReleaseBuffers releasing ALL " << (channel == DTC_DMA_Engine_DAQ ? "DAQ" : "DCS")
     645              :         //                                                        << " buffers.";
     646              :         //      ReleaseAllBuffers(channel);
     647              :         // }
     648            0 :         CFO_TLOG(TLVL_ReleaseBuffers) << "ReleaseBuffers END";
     649            0 : }
     650              : 
     651              : // int CFOLib::CFO::GetCurrentBuffer(DMAInfo* info)
     652              : // {
     653              : //      CFO_TLOG(TLVL_GetCurrentBuffer) << "GetCurrentBuffer BEGIN";
     654              : //      if (info->currentReadPtr == nullptr || info->buffer.size() == 0)
     655              : //      {
     656              : //              CFO_TLOG(TLVL_GetCurrentBuffer) << "GetCurrentBuffer returning -1 because not currently reading a buffer";
     657              : //              return -1;
     658              : //      }
     659              : 
     660              : //      for (size_t ii = 0; ii < info->buffer.size(); ++ii)
     661              : //      {
     662              : //              auto bufferptr = *info->buffer[ii];
     663              : //              uint16_t bufferSize = *reinterpret_cast<uint16_t*>(bufferptr);
     664              : //              if (info->currentReadPtr > bufferptr &&
     665              : //                      info->currentReadPtr < bufferptr + bufferSize)
     666              : //              {
     667              : //                      CFO_TLOG(TLVL_GetCurrentBuffer) << "Found matching buffer at index " << ii << ".";
     668              : //                      return ii;
     669              : //              }
     670              : //      }
     671              : //      CFO_TLOG(TLVL_GetCurrentBuffer) << "GetCurrentBuffer returning -2: Have buffers but none match, need new";
     672              : //      return -2;
     673              : // }
     674              : 
     675              : // uint16_t CFOLib::CFO::GetBufferByteCount(DMAInfo* info, size_t index)
     676              : // {
     677              : //      if (index >= info->buffer.size()) return 0;
     678              : //      auto bufferptr = *info->buffer[index];
     679              : //      uint16_t bufferSize = *reinterpret_cast<uint16_t*>(bufferptr);
     680              : //      return bufferSize;
     681              : // }
        

Generated by: LCOV version 2.0-1