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

            Line data    Source code
       1              : // This file (mu2edev.cc) was created by Ron Rechenmacher <ron@fnal.gov> on
       2              : // Feb 13, 2014. "TERMS AND CONDITIONS" governing this file are in the README
       3              : // or COPYING file. If you do not have such a file, one can be obtained by
       4              : // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
       5              : // $RCSfile: .emacs.gnu,v $
       6              : // rev="$Revision: 1.23 $$Date: 2012/01/23 15:32:40 $";
       7              : 
       8              : /*
       9              :  *    make mu2edev.o CFLAGS='-g -Wall -std=c++0x'
      10              :  */
      11              : 
      12              : #include "TRACE/tracemf.h"
      13              : #define TRACE_NAME "mu2esim"
      14              : 
      15              : #define TLVL_Constructor TLVL_DEBUG + 2
      16              : #define TLVL_Init TLVL_DEBUG + 3
      17              : #define TLVL_ReadData TLVL_DEBUG + 4
      18              : #define TLVL_ReadData2 TLVL_DEBUG + 5
      19              : #define TLVL_WriteData TLVL_DEBUG + 6
      20              : #define TLVL_ReadRelease TLVL_DEBUG + 7
      21              : #define TLVL_ReadRegister TLVL_DEBUG + 8
      22              : #define TLVL_ReadRegister2 TLVL_DEBUG + 9
      23              : #define TLVL_WriteRegister TLVL_DEBUG + 10
      24              : #define TLVL_WriteRegister2 TLVL_DEBUG + 11
      25              : #define TLVL_CFOEmulator TLVL_DEBUG + 12
      26              : #define TLVL_CFOEmulator2 TLVL_DEBUG + 13
      27              : #define TLVL_DeltaChn TLVL_DEBUG + 14
      28              : #define TLVL_ClearBuffer TLVL_DEBUG + 15
      29              : #define TLVL_ClearBuffer2 TLVL_DEBUG + 16
      30              : #define TLVL_OpenEvent TLVL_DEBUG + 17
      31              : #define TLVL_CloseEvent TLVL_DEBUG + 18
      32              : #define TLVL_DCSPacketSimulator TLVL_DEBUG + 19
      33              : #define TLVL_PacketSimulator TLVL_DEBUG + 20
      34              : #define TLVL_EventSimulator TLVL_DEBUG + 21
      35              : 
      36              : #define CURRENT_EMULATED_TRACKER_VERSION 1
      37              : #define CURRENT_EMULATED_CALORIMETER_VERSION 0
      38              : #define CURRENT_EMULATED_CRV_VERSION 0
      39              : 
      40              : #include "mu2esim.h"
      41              : #include "DTC_Registers.h"
      42              : 
      43              : #include <cmath>
      44              : #include <vector>
      45              : 
      46              : #define THREADED_CFO_EMULATOR 0
      47              : 
      48            0 : mu2esim::mu2esim(std::string ddrFileName)
      49            0 :         : registers_()
      50            0 :         , swIdx_()
      51              :         /*, detSimLoopCount_(0)*/
      52            0 :         , dmaData_()
      53            0 :         , ddrFileName_(ddrFileName)
      54            0 :         , ddrFile_(nullptr)
      55            0 :         , mode_(DTCLib::DTC_SimMode_Disabled)
      56            0 :         , cancelCFO_(true)
      57            0 :         , readoutRequestReceived_()
      58            0 :         , event_(nullptr)
      59            0 :         , sub_event_(nullptr)
      60              : {
      61            0 :         TLOG(TLVL_Constructor) << "mu2esim::mu2esim BEGIN";
      62            0 :         for (unsigned ii = 0; ii < MU2E_MAX_CHANNELS; ++ii)
      63            0 :                 swIdx_[ii] = 0;
      64            0 :         for (unsigned ii = 0; ii < MU2E_MAX_CHANNELS; ++ii)
      65            0 :                 hwIdx_[ii] = 0;
      66            0 :         for (unsigned ii = 0; ii < SIM_BUFFCOUNT; ++ii)
      67              :         {
      68            0 :                 dmaData_[0][ii] = reinterpret_cast<mu2e_databuff_t *>(new char[0x10000]);
      69            0 :                 dmaData_[1][ii] = reinterpret_cast<mu2e_databuff_t *>(new char[0x10000]);
      70              :         }
      71            0 :         release_all(0);
      72            0 :         release_all(1);
      73              : 
      74            0 :         event_mode_num_tracker_blocks_ = 6;
      75            0 :         auto tracker_count_c = getenv("DTCLIB_NUM_TRACKER_BLOCKS");
      76            0 :         if (tracker_count_c != nullptr)
      77              :         {
      78            0 :                 event_mode_num_tracker_blocks_ = std::atoi(tracker_count_c);
      79              :         }
      80              :         // Max is 134
      81            0 :         event_mode_num_calo_blocks_ = 6;
      82            0 :         auto calo_count_c = getenv("DTCLIB_NUM_CALORIMETER_BLOCKS");
      83            0 :         if (calo_count_c != nullptr)
      84              :         {
      85            0 :                 event_mode_num_calo_blocks_ = std::atoi(calo_count_c);
      86              :         }
      87            0 :         event_mode_num_calo_hits_ = 6;
      88            0 :         auto calo_hit_count_c = getenv("DTCLIB_NUM_CALORIMETER_HITS");
      89            0 :         if (calo_hit_count_c != nullptr)
      90              :         {
      91            0 :                 event_mode_num_calo_hits_ = std::atoi(calo_hit_count_c);
      92              :         }
      93            0 :         event_mode_num_crv_blocks_ = 0;
      94            0 :         auto crv_count_c = getenv("DTCLIB_NUM_CRV_BLOCKS");
      95            0 :         if (crv_count_c != nullptr)
      96              :         {
      97            0 :                 event_mode_num_crv_blocks_ = std::atoi(crv_count_c);
      98              :         }
      99              : 
     100            0 :         reopenDDRFile_();
     101              : 
     102            0 :         TLOG(TLVL_Constructor) << "mu2esim::mu2esim END";
     103            0 : }
     104              : 
     105            0 : mu2esim::~mu2esim()
     106              : {
     107            0 :         cancelCFO_ = true;
     108            0 :         if (cfoEmulatorThread_.joinable()) cfoEmulatorThread_.join();
     109            0 :         for (unsigned ii = 0; ii < SIM_BUFFCOUNT; ++ii)
     110              :         {
     111            0 :                 delete[] dmaData_[0][ii];
     112            0 :                 delete[] dmaData_[1][ii];
     113              :         }
     114            0 :         ddrFile_.reset(nullptr);
     115            0 : }
     116              : 
     117            0 : int mu2esim::init(DTCLib::DTC_SimMode mode)
     118              : {
     119            0 :         TLOG(TLVL_Init) << "mu2e Simulator::init";
     120            0 :         mode_ = mode;
     121              : 
     122            0 :         TLOG(TLVL_Init) << "Initializing registers";
     123              :         // Set initial register values...
     124            0 :         registers_[DTCLib::CFOandDTC_Register_DesignVersion] = 0x00006363;          // v99.99
     125            0 :         registers_[DTCLib::CFOandDTC_Register_DesignDate] = 0xA5020796;             // A for sim mode, 6-ROC, and date sim functionaliy was last modified
     126            0 :         registers_[DTCLib::CFOandDTC_Register_Control] = 0x00000003;                // System Clock, Timing Enable
     127            0 :         registers_[DTCLib::CFOandDTC_Register_DMATransferLength] = 0x80000010;      // Default value from HWUG
     128            0 :         registers_[DTCLib::CFOandDTC_Register_SERDES_LoopbackEnable] = 0x00000000;  // SERDES Loopback Disabled
     129            0 :         registers_[DTCLib::CFOandDTC_Register_ClockOscillatorStatus] = 0x20002;     // Initialization Complete, no IIC Error
     130            0 :         registers_[DTCLib::DTC_Register_ROCEmulationEnable] = 0x3F;                 // ROC Emulators enabled (of course!)
     131            0 :         registers_[DTCLib::CFOandDTC_Register_LinkEnable] = 0x3F3F;                 // All links Tx/Rx enabled, CFO and timing disabled
     132            0 :         registers_[DTCLib::CFOandDTC_Register_SERDES_PLLLocked] = 0x7F;             // SERDES PLL Locked
     133            0 :         registers_[DTCLib::CFOandDTC_Register_SERDES_ResetDone] = 0xFFFFFFFF;       // SERDES Resets Done
     134            0 :         registers_[DTCLib::DTC_Register_SERDES_RXCDRLockStatus] = 0x7F00007F;       // RX CDR Locked
     135            0 :         registers_[DTCLib::DTC_Register_DMATimeoutPreset] = 0x800;                  // DMA Timeout Preset
     136            0 :         registers_[DTCLib::DTC_Register_ROCReplyTimeout] = 0x200000;                // ROC Timeout Preset
     137            0 :         registers_[DTCLib::CFOandDTC_Register_SERDESClock_IICBusLow] = 0xFFFFFFFF;
     138            0 :         registers_[DTCLib::CFOandDTC_Register_SERDESClock_IICBusHigh] = 0x77f3f;
     139              :         // registers_[DTCLib::DTC_Register_DDRReferenceClockFrequency] = 0xbebc200;
     140              :         // registers_[DTCLib::DTC_Register_DDRClock_IICBusLow] = 0x1074f43b;
     141              :         // registers_[DTCLib::DTC_Register_DDRClock_IICBusHigh] = 0x30303;
     142            0 :         registers_[DTCLib::DTC_Register_EthernetFramePayloadSize] = 0x5D4;
     143            0 :         registers_[DTCLib::DTC_Register_FPGAPROMProgramStatus] = 0x1;
     144              : 
     145            0 :         TLOG(TLVL_Init) << "mu2e Simulator::init finished";
     146            0 :         return 0;
     147              : }
     148              : 
     149              : /*****************************
     150              :    read_data
     151              :    returns number of bytes read; negative value indicates an error
     152              :    */
     153            0 : int mu2esim::read_data(int chn, void **buffer, int tmo_ms)
     154              : {
     155            0 :         auto start = std::chrono::steady_clock::now();
     156            0 :         size_t bytesReturned = 0;
     157            0 :         if (delta_(chn, C2S) == 0)  // no data, generate if ddrFile
     158              :         {
     159            0 :                 TLOG(TLVL_ReadData) << "mu2esim::read_data: Clearing output buffer";
     160            0 :                 clearBuffer_(chn, false);
     161              : 
     162            0 :                 if (chn == 0)
     163              :                 {
     164            0 :                         if (!ddrFile_->is_open() || ddrFile_->fail())
     165              :                         {
     166            0 :                                 TLOG(TLVL_ReadData) << "mu2esim::read_data: Simulating DTC data DMA subevent trasfer...";
     167            0 :                                 sleep(1);
     168            0 :                                 TLOG(TLVL_ReadData) << "mu2esim::read_data: Simulating DTC data DMA subevent trasfer, after sleep.";
     169              : 
     170            0 :                                 auto ptr = reinterpret_cast<uint8_t *>(dmaData_[chn][swIdx_[chn]]);
     171            0 :                                 ptr += sizeof(uint64_t);  // advance past data size
     172              : 
     173            0 :                                 DTCLib::DTC_SubEventHeader header;
     174            0 :                                 uint64_t size = sizeof(header) + 6 * 16 + 6 * 3 * 16;  // subevent header + ROC headers + ROC payloads
     175              : 
     176            0 :                                 header.event_tag_low = simDataEWT_++;
     177            0 :                                 header.event_mode = 1;
     178            0 :                                 memcpy(ptr, &header, sizeof(header));
     179            0 :                                 header.inclusive_subevent_byte_count = size;
     180              : 
     181            0 :                                 TLOG(TLVL_DEBUG + 6) << "Found sub event inclusive byte count as: " << header.inclusive_subevent_byte_count << " 0x" << std::hex << std::setw(4) << std::setfill('0') << header.inclusive_subevent_byte_count << ". i.e., " << std::dec << std::setw(0) << (header.inclusive_subevent_byte_count - sizeof(header)) / 16 << " subevent packets.";
     182              : 
     183            0 :                                 ptr += sizeof(header);  // moving ptr past subevent header
     184              : 
     185            0 :                                 size_t num_of_packets = (header.inclusive_subevent_byte_count - sizeof(header)) / 16;
     186            0 :                                 size_t packets_per_roc = num_of_packets / 6;
     187            0 :                                 TLOG(TLVL_DEBUG + 6) << "num_of_packets = " << num_of_packets;
     188            0 :                                 TLOG(TLVL_DEBUG + 6) << "packets_per_roc = " << packets_per_roc;
     189              : 
     190            0 :                                 for (int i = 0; i > 6; ++i)
     191              :                                 {
     192            0 :                                         size_t packets_this_roc = packets_per_roc;
     193            0 :                                         if (i == 5) packets_this_roc = num_of_packets;
     194            0 :                                         if (packets_this_roc > 2023) packets_this_roc = 0;  // assume wrapped around negative
     195            0 :                                         TLOG(TLVL_TRACE) << "Setup ROC-" << i << " data header. packets_this_roc = " << packets_this_roc;
     196              : 
     197            0 :                                         *((uint16_t *)(&(ptr[1 * 2]))) = 0x8000 | (i << 8) | (5 << 4);  // packet type Data Header 0x5
     198            0 :                                         *((uint16_t *)(&(ptr[2 * 2]))) = packets_this_roc;              // packet count
     199            0 :                                         *((uint16_t *)(&(ptr[3 * 2]))) = simDataEWT_;                   // tag.GetEventWindowTag(true); //packet count
     200            0 :                                         *((uint16_t *)(&(ptr[4 * 2]))) = simDataEWT_ >> 16;             // tag.GetEventWindowTag(true)>>16; //packet count
     201            0 :                                         *((uint16_t *)(&(ptr[5 * 2]))) = 0;                             // tag.GetEventWindowTag(true)>>32; //packet count
     202              : 
     203            0 :                                         ptr += 16 * 1 + 16 * packets_this_roc;  // move ptr past ROC header + data
     204              :                                 }                                           // end ROC loop
     205              : 
     206            0 :                                 memcpy(dmaData_[chn][swIdx_[chn]], &size, sizeof(uint64_t));
     207            0 :                                 bytesReturned = size;
     208              :                         }  // end generate sim data
     209              :                         else
     210              :                         {
     211            0 :                                 TLOG(TLVL_ReadData) << "mu2esim::read_data: Reading size from memory file";
     212              :                                 uint64_t size;
     213            0 :                                 ddrFile_->read(reinterpret_cast<char *>(&size), sizeof(uint64_t) / sizeof(char));
     214              : 
     215            0 :                                 TLOG(TLVL_ReadData) << "mu2esim::read_data: Size is " << size;
     216              : 
     217            0 :                                 if (ddrFile_->eof() || size == 0)
     218              :                                 {
     219            0 :                                         TLOG(TLVL_ReadData) << "mu2esim::read_data: End of file reached, looping back to start";
     220            0 :                                         ddrFile_->clear();
     221            0 :                                         ddrFile_->seekg(std::ios::beg);
     222              : 
     223            0 :                                         TLOG(TLVL_ReadData) << " mu2esim::read_data: Re-reading size from memory file";
     224            0 :                                         ddrFile_->read(reinterpret_cast<char *>(&size), sizeof(uint64_t));
     225            0 :                                         TLOG(TLVL_ReadData) << "mu2esim::read_data: Size is " << size;
     226            0 :                                         if (ddrFile_->eof())
     227              :                                         {
     228            0 :                                                 TLOG(TLVL_ReadData) << "mu2esim::read_data: 0-size file detected!";
     229            0 :                                                 return -1;
     230              :                                         }
     231              :                                 }
     232            0 :                                 TLOG(TLVL_ReadData) << "Size of data is " << size - sizeof(uint64_t) << ", reading into buffer " << swIdx_[chn] << ", at "
     233            0 :                                                                         << (void *)dmaData_[chn][swIdx_[chn]];
     234            0 :                                 memcpy(dmaData_[chn][swIdx_[chn]], &size, sizeof(uint64_t));
     235            0 :                                 ddrFile_->read(reinterpret_cast<char *>(dmaData_[chn][swIdx_[chn]]) + sizeof(uint64_t), size - sizeof(uint64_t));
     236            0 :                                 bytesReturned = size;
     237              :                         }  // end DDR File sim read
     238              :                 }
     239            0 :                 else if (chn == 1)
     240              :                 {
     241              :                         // Data should already be in appropriate buffer, generated by dcsPacketSimulator_()
     242              :                 }
     243              :         }
     244              :         else  // there is data to read, calculate size
     245            0 :                 if (chn == 1)
     246              :                 {
     247            0 :                         uint64_t dcsSize = *reinterpret_cast<uint64_t *>(dmaData_[chn][swIdx_[chn]]);
     248            0 :                         TLOG(TLVL_ReadData2) << "mu2esim::read_data: dcsSize = " << dcsSize;
     249            0 :                         bytesReturned = (size_t)dcsSize;
     250              :                 }
     251              : 
     252            0 :         *buffer = dmaData_[chn][swIdx_[chn]];
     253            0 :         TLOG(TLVL_ReadData2) << "mu2esim::read_data: *buffer (" << (void *)*buffer << ") should now be equal to dmaData_[" << chn << "]["
     254            0 :                                                  << swIdx_[chn] << "] (" << (void *)dmaData_[chn][swIdx_[chn]] << "), bytesReturned = " << bytesReturned << " data = 0x" << std::hex << *reinterpret_cast<uint64_t *>(dmaData_[chn][swIdx_[chn]]);
     255            0 :         swIdx_[chn] = (swIdx_[chn] + 1) % SIM_BUFFCOUNT;
     256              : 
     257              :         auto duration =
     258            0 :                 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
     259            0 :         TLOG(TLVL_ReadData2) << "mu2esim::read_data took " << duration << " milliseconds out of tmo_ms=" << tmo_ms;
     260            0 :         return static_cast<int>(bytesReturned);
     261              : }
     262              : 
     263            0 : int mu2esim::write_data(int chn, void *buffer, size_t bytes)
     264              : {
     265            0 :         if (chn == 0)
     266              :         {
     267            0 :                 TLOG(TLVL_WriteData) << "mu2esim::write_data: adding buffer to simulated DDR memory sz=" << bytes
     268            0 :                                                          << ", *buffer=" << *((uint64_t *)buffer);
     269            0 :                 if (bytes <= sizeof(mu2e_databuff_t))
     270              :                 {
     271            0 :                         if (event_) closeEvent_();
     272              : 
     273              :                         // Strip off first 64-bit word
     274            0 :                         auto writeBytes = *reinterpret_cast<uint64_t *>(buffer) - sizeof(uint64_t);
     275            0 :                         auto ptr = reinterpret_cast<char *>(buffer) + (sizeof(uint64_t) / sizeof(char));
     276            0 :                         ddrFile_->write(ptr, writeBytes);
     277            0 :                         registers_[DTCLib::DTC_Register_DetEmulation_DataEndAddress] += static_cast<uint32_t>(writeBytes);
     278            0 :                         ddrFile_->flush();
     279            0 :                         return 0;
     280              :                 }
     281            0 :                 TLOG(TLVL_WriteData) << "mu2esim::write_data: I was asked to write more than one buffer's worth of data. Cowardly refusing.";
     282              :         }
     283            0 :         else if (chn == 1)
     284              :         {
     285            0 :                 TLOG(TLVL_WriteData) << "mu2esim::write_data start: chn=" << chn << ", buf=" << buffer << ", bytes=" << bytes;
     286              : 
     287              :                 // extract target ROC link "activeDAQLink" from bufer
     288              :                 uint32_t worda;
     289            0 :                 memcpy(&worda, reinterpret_cast<uint64_t *>(buffer) + 1, sizeof worda);
     290            0 :                 auto word = static_cast<uint16_t>(worda >> 16);
     291            0 :                 TLOG(TLVL_WriteData) << "mu2esim::write_data worda is 0x" << std::hex << worda << " and word is 0x" << std::hex << word;
     292            0 :                 auto activeLink = static_cast<DTCLib::DTC_Link_ID>((word & 0x0F00) >> 8);
     293              : 
     294            0 :                 DTCLib::DTC_EventWindowTag ts(reinterpret_cast<uint8_t *>(buffer) + 6);
     295            0 :                 if ((word & 0x8010) == 0x8010)
     296              :                 {
     297            0 :                         TLOG(TLVL_WriteData) << "mu2esim::write_data: Readout Request: activeDAQLink=" << activeLink
     298            0 :                                                                  << ", ts=" << ts.GetEventWindowTag(true);
     299            0 :                         readoutRequestReceived_[ts.GetEventWindowTag(true)][activeLink] = true;
     300              :                 }
     301            0 :                 else if ((word & 0x8020) == 0x8020)
     302              :                 {
     303            0 :                         TLOG(TLVL_WriteData) << "mu2esim::write_data: Data Request: activeDAQLink=" << activeLink << ", ts=" << ts.GetEventWindowTag(true);
     304            0 :                         if (activeLink != DTCLib::DTC_Link_Unused)
     305              :                         {
     306            0 :                                 if (!readoutRequestReceived_[ts.GetEventWindowTag(true)][activeLink])
     307              :                                 {
     308            0 :                                         TLOG(TLVL_WriteData) << "mu2esim::write_data: Data Request Received but missing Readout Request!";
     309              :                                 }
     310              :                                 else
     311              :                                 {
     312            0 :                                         openEvent_(ts);
     313              : 
     314            0 :                                         if (mode_ == DTCLib::DTC_SimMode_Performance || mode_ == DTCLib::DTC_SimMode_Timeout)
     315              :                                         {
     316            0 :                                                 auto packetCount = *(reinterpret_cast<uint16_t *>(buffer) + 7);
     317            0 :                                                 packetSimulator_(ts, activeLink, packetCount);
     318            0 :                                         }
     319            0 :                                         else if (mode_ == DTCLib::DTC_SimMode_Tracker)
     320              :                                         {
     321            0 :                                                 trackerBlockSimulator_(ts, activeLink, 0);
     322              :                                         }
     323            0 :                                         else if (mode_ == DTCLib::DTC_SimMode_Calorimeter)
     324              :                                         {
     325            0 :                                                 calorimeterBlockSimulator_(ts, activeLink, 0);
     326              :                                         }
     327            0 :                                         else if (mode_ == DTCLib::DTC_SimMode_CosmicVeto)
     328              :                                         {
     329            0 :                                                 crvBlockSimulator_(ts, activeLink, 0);
     330              :                                         }
     331              : 
     332            0 :                                         readoutRequestReceived_[ts.GetEventWindowTag(true)][activeLink] = false;
     333            0 :                                         if (readoutRequestReceived_[ts.GetEventWindowTag(true)].count() == 0)
     334              :                                         {
     335            0 :                                                 closeEvent_();
     336            0 :                                                 readoutRequestReceived_.erase(ts.GetEventWindowTag(true));
     337              :                                         }
     338              :                                 }
     339              :                         }
     340              :                 }
     341            0 :                 if ((word & 0x0080) == 0)
     342              :                 {
     343            0 :                         TLOG(TLVL_WriteData) << "mu2esim::write_data activeDCSLink is " << activeLink;
     344            0 :                         if (activeLink != DTCLib::DTC_Link_Unused)
     345              :                         {
     346            0 :                                 DTCLib::DTC_DataPacket packet(reinterpret_cast<uint64_t *>(buffer) + 1);  // skip 64-bit packet size
     347            0 :                                 TLOG(TLVL_WriteData) << "packet " << packet.toJSON();
     348              : 
     349            0 :                                 DTCLib::DTC_DCSRequestPacket thisPacket(packet);
     350              : 
     351            0 :                                 if (thisPacket.GetType() == DTCLib::DTC_DCSOperationType_Write ||
     352            0 :                                         thisPacket.GetType() == DTCLib::DTC_DCSOperationType_BlockWrite)
     353              :                                 {
     354            0 :                                         TLOG(TLVL_WriteData) << "mu2esim::write_data: Recieved DCS Write Request:" << thisPacket.toJSON();
     355              : 
     356            0 :                                         auto request1 = thisPacket.GetRequest(false);
     357            0 :                                         rocRegisters_[activeLink][request1.first] = request1.second;
     358              : 
     359            0 :                                         if (thisPacket.GetType() == DTCLib::DTC_DCSOperationType_BlockWrite)
     360              :                                         {
     361            0 :                                                 auto request2 = thisPacket.GetRequest(true);
     362            0 :                                                 rocRegisters_[activeLink][request2.first] = request2.second;
     363              :                                         }
     364              :                                 }
     365              : 
     366              :                                 // Note: write's can request ack
     367            0 :                                 if (thisPacket.GetType() == DTCLib::DTC_DCSOperationType_Read ||
     368            0 :                                         thisPacket.GetType() == DTCLib::DTC_DCSOperationType_BlockRead || thisPacket.RequestsAck())
     369              :                                 {
     370            0 :                                         TLOG(TLVL_WriteData) << "mu2esim::write_data: Recieved DCS Request:" << thisPacket.toJSON();
     371            0 :                                         dcsPacketSimulator_(thisPacket, activeLink);
     372              :                                 }
     373            0 :                         }
     374              :                 }
     375            0 :         }
     376              : 
     377            0 :         return 0;
     378              : }
     379              : 
     380            0 : int mu2esim::read_release(int chn, unsigned num)
     381              : {
     382              :         // Always succeeds
     383            0 :         TLOG(TLVL_ReadRelease) << "mu2esim::read_release: Simulating a release of " << num << "u buffers of channel " << chn;
     384            0 :         for (unsigned ii = 0; ii < num; ++ii)
     385              :         {
     386            0 :                 if (delta_(chn, C2S) != 0) swIdx_[chn] = (swIdx_[chn] + 1) % SIM_BUFFCOUNT;
     387              :         }
     388            0 :         TLOG(TLVL_DeltaChn) << "mu2esim::read_release: After release... chn=" << chn << " hw=" << hwIdx_[chn] << " sw=" << swIdx_[chn];
     389            0 :         return 0;
     390              : }
     391              : 
     392            0 : int mu2esim::release_all(int chn)
     393              : {
     394            0 :         read_release(chn, SIM_BUFFCOUNT);
     395              :         // swIdx_[chn] = 0; //do not reset, just release up to hw pointer
     396            0 :         return 0;
     397              : }
     398              : 
     399            0 : int mu2esim::read_register(uint16_t address, int tmo_ms, uint32_t *output)
     400              : {
     401            0 :         auto start = std::chrono::steady_clock::now();
     402            0 :         *output = 0;
     403            0 :         if (registers_.count(address) > 0)
     404              :         {
     405            0 :                 TLOG(TLVL_ReadRegister) << "mu2esim::read_register: Returning value 0x" << std::hex << registers_[address] << " for address 0x"
     406            0 :                                                                 << std::hex << address;
     407            0 :                 *output = registers_[address];
     408              :         }
     409              :         auto duration =
     410            0 :                 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
     411            0 :         TLOG(TLVL_ReadRegister2) << "mu2esim::read_register took " << duration << " milliseconds out of tmo_ms=" << tmo_ms;
     412            0 :         return 0;
     413              : }
     414              : 
     415            0 : int mu2esim::write_register(uint16_t address, int tmo_ms, uint32_t data)
     416              : {
     417            0 :         auto start = std::chrono::steady_clock::now();
     418              :         // Write the register!!!
     419            0 :         TLOG(TLVL_WriteRegister) << "mu2esim::write_register: Writing value 0x" << std::hex << data << " into address 0x" << std::hex
     420            0 :                                                          << address;
     421            0 :         registers_[address] = data;
     422              :         auto duration =
     423            0 :                 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
     424            0 :         TLOG(TLVL_WriteRegister2) << "mu2esim::write_register took " << duration << " milliseconds out of tmo_ms=" << tmo_ms;
     425            0 :         std::bitset<32> dataBS(data);
     426            0 :         if (address == DTCLib::CFOandDTC_Register_Control)
     427              :         {
     428            0 :                 auto detectorEmulationMode = (registers_[DTCLib::DTC_Register_DetEmulation_Control0] & 0x3) != 0;
     429            0 :                 if (dataBS[30] == 1 && !detectorEmulationMode)
     430              :                 {
     431            0 :                         TLOG(TLVL_WriteRegister2) << "mu2esim::write_register: CFO Emulator Enable Detected!";
     432            0 :                         cancelCFO_ = true;
     433            0 :                         if (cfoEmulatorThread_.joinable()) cfoEmulatorThread_.join();
     434            0 :                         cancelCFO_ = false;
     435              : #if THREADED_CFO_EMULATOR
     436              :                         if (registers_[0x91AC] > 10)
     437              :                         {
     438              :                                 cfoEmulatorThread_ = std::thread(&mu2esim::CFOEmulator_, this);
     439              :                         }
     440              :                         else
     441              : #endif
     442              :                         {
     443            0 :                                 CFOEmulator_();
     444              :                         }
     445              :                 }
     446            0 :                 else if (dataBS[26] == 1 && detectorEmulationMode)
     447              :                 {
     448            0 :                         TLOG(TLVL_WriteRegister2) << "mu2esim::write_register: IGNORING CFO Emulator Enable because we're in Detector Simulator mode!";
     449              :                 }
     450            0 :                 if (dataBS[31] == 1)
     451              :                 {
     452            0 :                         TLOG(TLVL_WriteRegister2) << "mu2esim::write_register: RESETTING DTC EMULATOR!";
     453            0 :                         init(mode_);
     454            0 :                         reopenDDRFile_();
     455              :                 }
     456              :         }
     457            0 :         if (address == DTCLib::DTC_Register_DetEmulation_Control0)
     458              :         {
     459            0 :                 if (dataBS[0] == 0)
     460              :                 {
     461            0 :                         reopenDDRFile_();
     462              :                 }
     463              :         }
     464            0 :         if (address == DTCLib::DTC_Register_DetEmulation_DataStartAddress)
     465              :         {
     466            0 :                 ddrFile_->seekg(data);
     467              :         }
     468            0 :         return 0;
     469              : }
     470              : 
     471            0 : void mu2esim::CFOEmulator_()
     472              : {
     473            0 :         if (cancelCFO_)
     474              :         {
     475            0 :                 std::bitset<32> ctrlReg(registers_[0x9100]);
     476            0 :                 ctrlReg[30] = 0;
     477            0 :                 registers_[0x9100] = ctrlReg.to_ulong();
     478            0 :                 return;
     479              :         }
     480            0 :         DTCLib::DTC_EventWindowTag start(registers_[DTCLib::DTC_Register_CFOEmulation_TimestampLow],
     481            0 :                                                                          static_cast<uint16_t>(registers_[DTCLib::DTC_Register_CFOEmulation_TimestampHigh]));
     482            0 :         auto count = registers_[DTCLib::DTC_Register_CFOEmulation_NumHeartbeats];
     483            0 :         auto ticksToWait = static_cast<long long>(registers_[DTCLib::DTC_Register_CFOEmulation_HeartbeatInterval] * 0.0064);
     484            0 :         TLOG(TLVL_CFOEmulator) << "mu2esim::CFOEmulator_ start timestamp=" << start.GetEventWindowTag(true) << ", count=" << count
     485            0 :                                                    << ", delayBetween=" << ticksToWait;
     486              :         bool linkEnabled[6];
     487            0 :         for (auto link : DTCLib::DTC_ROC_Links)
     488              :         {
     489            0 :                 std::bitset<32> linkRocs(registers_[DTCLib::CFOandDTC_Register_LinkEnable]);
     490            0 :                 auto number = linkRocs[link] + linkRocs[link + 8];
     491            0 :                 TLOG(TLVL_CFOEmulator) << "mu2esim::CFOEmulator_ linkRocs[" << static_cast<int>(link) << "]=" << number;
     492            0 :                 linkEnabled[link] = number != 0;
     493              :         }
     494              : 
     495            0 :         unsigned sentCount = 0;
     496            0 :         while (sentCount < count && !cancelCFO_)
     497              :         {
     498            0 :                 if (mode_ == DTCLib::DTC_SimMode_Event)
     499              :                 {
     500            0 :                         TLOG(TLVL_CFOEmulator) << "Event mode enabled, calling eventSimulator_";
     501            0 :                         eventSimulator_(start + sentCount);
     502              :                 }
     503              :                 else
     504              :                 {
     505            0 :                         openEvent_(start + sentCount);
     506            0 :                         for (auto link : DTCLib::DTC_ROC_Links)
     507              :                         {
     508              :                                 uint16_t packetCount;
     509            0 :                                 switch (link)
     510              :                                 {
     511            0 :                                         case DTCLib::DTC_Link_0:
     512            0 :                                                 packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks10]);
     513            0 :                                                 break;
     514            0 :                                         case DTCLib::DTC_Link_1:
     515            0 :                                                 packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks10] >> 16);
     516            0 :                                                 break;
     517            0 :                                         case DTCLib::DTC_Link_2:
     518            0 :                                                 packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks32]);
     519            0 :                                                 break;
     520            0 :                                         case DTCLib::DTC_Link_3:
     521            0 :                                                 packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks32] >> 16);
     522            0 :                                                 break;
     523            0 :                                         case DTCLib::DTC_Link_4:
     524            0 :                                                 packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks54]);
     525            0 :                                                 break;
     526            0 :                                         case DTCLib::DTC_Link_5:
     527            0 :                                                 packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks54] >> 16);
     528            0 :                                                 break;
     529            0 :                                         default:
     530            0 :                                                 packetCount = 0;
     531            0 :                                                 break;
     532              :                                 }
     533            0 :                                 if (linkEnabled[link] != 0)
     534              :                                 {
     535            0 :                                         TLOG(TLVL_CFOEmulator) << "mu2esim::CFOEmulator_ linkRocs[" << static_cast<int>(link) << "]=" << linkEnabled[link];
     536            0 :                                         if (mode_ == DTCLib::DTC_SimMode_Performance || mode_ == DTCLib::DTC_SimMode_Timeout)
     537              :                                         {
     538            0 :                                                 TLOG(TLVL_CFOEmulator) << "Performance or Timeout mode enabled, calling packetSimulator_";
     539            0 :                                                 packetSimulator_(start + sentCount, link, packetCount);
     540            0 :                                         }
     541            0 :                                         else if (mode_ == DTCLib::DTC_SimMode_Tracker)
     542              :                                         {
     543            0 :                                                 TLOG(TLVL_CFOEmulator) << "Tracker mode enabled, calling trackerBlockSimulator_";
     544            0 :                                                 trackerBlockSimulator_(start + sentCount, link, 0);
     545              :                                         }
     546            0 :                                         else if (mode_ == DTCLib::DTC_SimMode_Calorimeter)
     547              :                                         {
     548            0 :                                                 TLOG(TLVL_CFOEmulator) << "Calorimeter mode enabled, calling calorimeterBlockSimulator_";
     549            0 :                                                 calorimeterBlockSimulator_(start + sentCount, link, 0);
     550              :                                         }
     551            0 :                                         else if (mode_ == DTCLib::DTC_SimMode_CosmicVeto)
     552              :                                         {
     553            0 :                                                 TLOG(TLVL_CFOEmulator) << "CRV mode enabled, calling crvBlockSimulator_";
     554            0 :                                                 crvBlockSimulator_(start + sentCount, link, 0);
     555              :                                         }
     556              :                                 }
     557              :                         }
     558            0 :                         closeEvent_();
     559              :                 }
     560              : 
     561            0 :                 if (ticksToWait > 100)
     562              :                 {
     563            0 :                         usleep(ticksToWait);
     564              :                 }
     565            0 :                 sentCount++;
     566              :         }
     567            0 :         std::bitset<32> ctrlReg(registers_[0x9100]);
     568            0 :         ctrlReg[30] = 0;
     569            0 :         registers_[0x9100] = ctrlReg.to_ulong();
     570            0 : }
     571              : 
     572            0 : unsigned mu2esim::delta_(int chn, int dir)
     573              : {
     574            0 :         if (chn == 0) return 0;
     575            0 :         TLOG(TLVL_DeltaChn) << "delta_ " << chn << " " << dir << " = 0";
     576            0 :         unsigned hw = hwIdx_[chn];
     577            0 :         unsigned sw = swIdx_[chn];
     578            0 :         TLOG(TLVL_DeltaChn) << "mu2esim::delta_ chn=" << chn << " dir=" << dir << " hw=" << hw << " sw=" << sw
     579            0 :                                                 << " num_buffs=" << SIM_BUFFCOUNT;
     580            0 :         if (dir == C2S)
     581            0 :                 return ((hw >= sw) ? hw - sw : SIM_BUFFCOUNT + hw - sw);
     582              :         else
     583            0 :                 return ((sw >= hw) ? SIM_BUFFCOUNT - (sw - hw) : hw - sw);
     584              : }
     585              : 
     586            0 : void mu2esim::clearBuffer_(int chn, bool increment)
     587              : {
     588            0 :         TLOG(TLVL_ClearBuffer2) << "mu2esim::clearBuffer_(" << chn << ", " << increment << "): NOP";
     589            0 : }
     590              : 
     591            0 : void mu2esim::openEvent_(DTCLib::DTC_EventWindowTag ts)
     592              : {
     593            0 :         TLOG(TLVL_OpenEvent) << "mu2esim::openEvent_ Checking timestamp " << ts.GetEventWindowTag(true) << " vs current timestamp "
     594            0 :                                                  << (event_ ? std::to_string(event_->GetEventWindowTag().GetEventWindowTag(true)) : std::string(" NONE"));
     595            0 :         if (event_ && ts == event_->GetEventWindowTag()) return;
     596            0 :         if (event_) closeEvent_();
     597              : 
     598            0 :         TLOG(TLVL_OpenEvent) << "mu2esim::openEvent_: Setting up initial buffer";
     599              : 
     600            0 :         event_ = std::make_unique<DTCLib::DTC_Event>();
     601            0 :         event_->SetEventWindowTag(ts);
     602            0 :         event_->SetEventMode(getEventMode_());
     603              : 
     604            0 :         sub_event_ = std::make_unique<DTCLib::DTC_SubEvent>();
     605            0 :         sub_event_->SetEventWindowTag(ts);
     606            0 :         sub_event_->SetEventMode(getEventMode_());
     607              : }
     608              : 
     609            0 : void mu2esim::closeSubEvent_()
     610              : {
     611            0 :         if (!event_ || !sub_event_ || sub_event_->GetDataBlockCount() == 0) return;
     612              : 
     613            0 :         event_->AddSubEvent(*(sub_event_.release()));
     614              : 
     615            0 :         sub_event_ = std::make_unique<DTCLib::DTC_SubEvent>();
     616            0 :         sub_event_->SetEventWindowTag(event_->GetEventWindowTag());
     617            0 :         sub_event_->SetEventMode(getEventMode_());
     618              : }
     619              : 
     620            0 : DTCLib::DTC_EventMode mu2esim::getEventMode_()
     621              : {
     622            0 :         DTCLib::DTC_EventMode event_mode;
     623              : 
     624            0 :         event_mode.mode0 = static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF);
     625            0 :         event_mode.mode1 = static_cast<uint8_t>((registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF00) >> 8);
     626            0 :         event_mode.mode2 = static_cast<uint8_t>((registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF0000) >> 16);
     627            0 :         event_mode.mode3 = static_cast<uint8_t>((registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF000000) >> 24);
     628            0 :         event_mode.mode4 = static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode2] & 0xFF);
     629              : 
     630            0 :         return event_mode;
     631              : }
     632              : 
     633            0 : void mu2esim::closeEvent_()
     634              : {
     635            0 :         TLOG(TLVL_CloseEvent) << "mu2esim::closeEvent_: Checking current event";
     636            0 :         if (sub_event_) closeSubEvent_();
     637            0 :         if (event_ && ddrFile_)
     638              :         {
     639            0 :                 event_->WriteEvent(*ddrFile_, false);
     640            0 :                 ddrFile_->flush();
     641              : 
     642            0 :                 event_.reset(nullptr);
     643            0 :                 sub_event_.reset(nullptr);
     644              :         }
     645            0 :         TLOG(TLVL_CloseEvent) << "mu2esim::closeEvent_ FINISH";
     646            0 : }
     647              : 
     648            0 : void mu2esim::dcsPacketSimulator_(DTCLib::DTC_DCSRequestPacket in, DTCLib::DTC_Link_ID rocLink)
     649              : {
     650            0 :         auto packetCount = 0;
     651            0 :         if (in.GetType() == DTCLib::DTC_DCSOperationType_BlockRead)
     652              :         {
     653            0 :                 packetCount = 1;
     654              :         }
     655            0 :         TLOG(TLVL_DCSPacketSimulator) << "mu2esim::dcsPacketSimulator_: Constructing DCS Response";
     656            0 :         DTCLib::DTC_DMAPacket packet(DTCLib::DTC_PacketType_DCSReply, in.GetLinkID(), (1 + packetCount) * 16, true);
     657              : 
     658            0 :         TLOG(TLVL_DCSPacketSimulator) << "mu2esim::dcsPacketSimulator_: copying response into new buffer";
     659            0 :         auto dataPacket = packet.ConvertToDataPacket();
     660              : 
     661            0 :         dataPacket.SetByte(4, static_cast<int>(in.GetType()) + (in.RequestsAck() ? 0x8 : 0) + (in.IsDoubleOp() ? 0x4 : 0) +
     662            0 :                                                           ((packetCount & 0x2) << 6));
     663            0 :         dataPacket.SetByte(5, (packetCount & 0x3FC) >> 2);
     664              : 
     665            0 :         auto request1 = in.GetRequest(false);
     666            0 :         dataPacket.SetByte(6, request1.first & 0xFF);
     667            0 :         dataPacket.SetByte(7, (request1.first & 0xFF00) >> 8);
     668            0 :         dataPacket.SetByte(8, rocRegisters_[rocLink][request1.first] & 0xFF);
     669            0 :         dataPacket.SetByte(9, (rocRegisters_[rocLink][request1.first] & 0xFF00) >> 8);
     670              : 
     671            0 :         if (in.GetType() != DTCLib::DTC_DCSOperationType_BlockRead)
     672              :         {
     673            0 :                 auto request2 = in.GetRequest(true);
     674            0 :                 dataPacket.SetByte(10, request2.first & 0xFF);
     675            0 :                 dataPacket.SetByte(11, (request2.first & 0xFF00) >> 8);
     676            0 :                 dataPacket.SetByte(12, rocRegisters_[rocLink][request2.first] & 0xFF);
     677            0 :                 dataPacket.SetByte(13, (rocRegisters_[rocLink][request2.first] & 0xFF00) >> 8);
     678              :         }
     679              :         else
     680              :         {
     681            0 :                 for (int ii = 10; ii < dataPacket.GetSize(); ++ii)
     682              :                 {
     683            0 :                         dataPacket.SetByte(ii, ii);
     684              :                 }
     685              :         }
     686              : 
     687            0 :         TLOG(TLVL_DCSPacketSimulator) << "in.toJSON() " << in.toJSON();
     688            0 :         TLOG(TLVL_DCSPacketSimulator) << "dataPacket.toJSON() " << dataPacket.toJSON();
     689              : 
     690            0 :         size_t packetSize = dataPacket.GetSize();
     691            0 :         TLOG(TLVL_DCSPacketSimulator) << "packetSize = " << packetSize << " into buffer hw=" << hwIdx_[1] << " sw=" << swIdx_[1];
     692            0 :         *reinterpret_cast<uint64_t *>(dmaData_[1][hwIdx_[1]]) = packetSize;
     693            0 :         memcpy(reinterpret_cast<uint64_t *>(dmaData_[1][hwIdx_[1]]) + 1, dataPacket.GetData(), packetSize);
     694            0 :         TLOG(TLVL_DCSPacketSimulator) << "mu2esim::dcsPacketSimulator_: copied packetSize=" << packetSize << " into buffer #" << hwIdx_[1] << " data = 0x" << std::hex << *reinterpret_cast<uint64_t *>(dmaData_[1][hwIdx_[1]]);
     695            0 :         hwIdx_[1] = (hwIdx_[1] + 1) % SIM_BUFFCOUNT;
     696              : 
     697            0 :         TLOG(TLVL_DCSPacketSimulator) << "After... hw=" << hwIdx_[1] << " sw=" << swIdx_[1];
     698            0 : }
     699              : 
     700            0 : void mu2esim::eventSimulator_(DTCLib::DTC_EventWindowTag ts)
     701              : {
     702            0 :         openEvent_(ts);
     703              : 
     704            0 :         auto num_trk_dtcs = ceil(event_mode_num_tracker_blocks_ / 6);
     705            0 :         auto num_calo_dtcs = ceil(event_mode_num_calo_blocks_ / 6);
     706            0 :         auto num_crv_dtcs = ceil(event_mode_num_crv_blocks_ / 6);
     707              : 
     708            0 :         size_t generated_trk_blocks = 0;
     709            0 :         size_t generated_calo_blocks = 0;
     710            0 :         size_t generated_crv_blocks = 0;
     711              : 
     712            0 :         int DTCID = 0;
     713              : 
     714            0 :         for (auto ii = 0; ii < num_trk_dtcs; ++ii, ++DTCID)
     715              :         {
     716            0 :                 TLOG(TLVL_EventSimulator) << "Generating Tracker data, DTCID " << DTCID << ", TRK DTC " << ii + 1 << "/" << num_trk_dtcs;
     717            0 :                 sub_event_->SetDTCMAC(DTCID);
     718            0 :                 sub_event_->SetSourceDTC(DTCID, DTCLib::DTC_Subsystem_Tracker);
     719              : 
     720            0 :                 for (auto link : DTCLib::DTC_ROC_Links)
     721              :                 {
     722            0 :                         TLOG(TLVL_EventSimulator) << "Generating Tracker data block for DTC " << DTCID << " link " << static_cast<int>(link);
     723            0 :                         trackerBlockSimulator_(ts, link, ii);
     724            0 :                         if (++generated_trk_blocks >= event_mode_num_tracker_blocks_) break;
     725              :                 }
     726            0 :                 closeSubEvent_();
     727              :         }
     728            0 :         for (auto ii = 0; ii < num_calo_dtcs; ++ii, ++DTCID)
     729              :         {
     730            0 :                 TLOG(TLVL_EventSimulator) << "Generating Calorimeter data, DTCID " << DTCID << ", Calo DTC " << ii + 1 << "/" << num_calo_dtcs;
     731            0 :                 sub_event_->SetDTCMAC(DTCID);
     732            0 :                 sub_event_->SetSourceDTC(DTCID, DTCLib::DTC_Subsystem_Calorimeter);
     733              : 
     734            0 :                 for (auto link : DTCLib::DTC_ROC_Links)
     735              :                 {
     736            0 :                         TLOG(TLVL_EventSimulator) << "Generating Calorimeter data block for DTC " << DTCID << " link " << static_cast<int>(link);
     737            0 :                         calorimeterBlockSimulator_(ts, link, ii);
     738            0 :                         if (++generated_calo_blocks >= event_mode_num_calo_blocks_) break;
     739              :                 }
     740            0 :                 closeSubEvent_();
     741              :         }
     742            0 :         for (auto ii = 0; ii < num_crv_dtcs; ++ii, ++DTCID)
     743              :         {
     744            0 :                 TLOG(TLVL_EventSimulator) << "Generating CRV data, DTCID " << DTCID << ", CRV DTC " << ii + 1 << "/" << num_crv_dtcs;
     745            0 :                 sub_event_->SetDTCMAC(DTCID);
     746            0 :                 sub_event_->SetSourceDTC(DTCID, DTCLib::DTC_Subsystem_CRV);
     747              : 
     748            0 :                 for (auto link : DTCLib::DTC_ROC_Links)
     749              :                 {
     750            0 :                         TLOG(TLVL_EventSimulator) << "Generating CRV data block for DTC " << DTCID << " link " << static_cast<int>(link);
     751            0 :                         crvBlockSimulator_(ts, link, ii);
     752            0 :                         if (++generated_crv_blocks >= event_mode_num_crv_blocks_) break;
     753              :                 }
     754            0 :                 closeSubEvent_();
     755              :         }
     756              : 
     757            0 :         closeEvent_();
     758            0 : }
     759              : 
     760            0 : void mu2esim::trackerBlockSimulator_(DTCLib::DTC_EventWindowTag ts, DTCLib::DTC_Link_ID link, int DTCID)
     761              : {
     762              :         uint16_t buffer[24];
     763              : 
     764            0 :         size_t nPackets = 2;
     765            0 :         DTCLib::DTC_DataHeaderPacket header(link, nPackets, DTCLib::DTC_DataStatus_Valid, DTCID, DTCLib::DTC_Subsystem_Tracker, CURRENT_EMULATED_TRACKER_VERSION, ts, static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF));
     766            0 :         memcpy(&buffer[0], header.ConvertToDataPacket().GetData(), 16);
     767              : 
     768            0 :         uint16_t strawID = ((static_cast<int>(link) + (DTCID * 6)) << 7) + 1;
     769            0 :         buffer[8] = strawID;
     770              :         // TDC set to EventWindowTag
     771            0 :         buffer[9] = (ts.GetEventWindowTag(true) & 0xFFFF);
     772            0 :         buffer[10] = 0x1000 + 0xF00 + ((ts.GetEventWindowTag(true) & 0xFF0000) >> 16);
     773              : 
     774            0 :         buffer[11] = (ts.GetEventWindowTag(true) & 0xFFFF);
     775            0 :         buffer[12] = 0xF00 + ((ts.GetEventWindowTag(true) & 0xFF0000) >> 16);
     776              : 
     777            0 :         buffer[13] = (0x7 << 6) + 0x1;  // PMP = 7, 1 ADC packet
     778              : 
     779            0 :         buffer[14] = 0x1 + (0x2 << 10);
     780            0 :         buffer[15] = 0x3 << 4;
     781              : 
     782            0 :         buffer[16] = 0x4 + (0x5 << 10);
     783            0 :         buffer[17] = 0x6 << 4;
     784            0 :         buffer[18] = 0x7 + (0x8 << 10);
     785            0 :         buffer[19] = 0x9 << 4;
     786            0 :         buffer[20] = 0xA + (0xB << 10);
     787            0 :         buffer[21] = 0xC << 4;
     788            0 :         buffer[22] = 0xD + (0xE << 10);
     789            0 :         buffer[23] = 0xF << 4;
     790              : 
     791            0 :         DTCLib::DTC_DataBlock block(sizeof(buffer));
     792            0 :         memcpy(&(*block.allocBytes)[0], buffer, sizeof(buffer));
     793            0 :         sub_event_->AddDataBlock(block);
     794            0 : }
     795              : 
     796            0 : void mu2esim::calorimeterBlockSimulator_(DTCLib::DTC_EventWindowTag ts, DTCLib::DTC_Link_ID link, int DTCID)
     797              : {
     798            0 :         std::vector<uint16_t> buffer(9);
     799              : 
     800              :         // Index Packet
     801            0 :         buffer[8] = event_mode_num_calo_hits_;
     802              : 
     803            0 :         for (size_t idx = 0; idx < event_mode_num_calo_hits_; ++idx)
     804              :         {
     805            0 :                 buffer.push_back(2 /* num hits */ + 2 * event_mode_num_calo_hits_ /* hit offsets */ + 4 /* board ID */ + idx * 24 /* hit readout */);  // Index of hit from start of index packet
     806              :         }
     807              : 
     808              :         // Board ID
     809            0 :         uint16_t roc_id = static_cast<uint8_t>(link) + (DTCID * 6);
     810            0 :         uint8_t board_number = (roc_id) & 0x3F;  // 6 bits
     811            0 :         buffer.push_back(0xFC00 + (board_number << 3));
     812            0 :         buffer.push_back(0x3FFF);
     813              : 
     814            0 :         auto t0Step = 2000 / event_mode_num_calo_hits_;
     815              : 
     816            0 :         for (size_t idx = 0; idx < event_mode_num_calo_hits_; ++idx)
     817              :         {
     818              :                 // Hit readout
     819            0 :                 buffer.push_back(board_number);
     820            0 :                 buffer.push_back(10 * roc_id);  // DIRAC B...do we need to put something here?
     821              : 
     822            0 :                 buffer.push_back(0);                        // No error flags
     823            0 :                 buffer.push_back((idx * t0Step) & 0xFFFF);  // Time
     824            0 :                 buffer.push_back(0x0607);                   // Max sample/num samples
     825              : 
     826              :                 // Digitizer samples
     827            0 :                 buffer.push_back(0x1111);
     828            0 :                 buffer.push_back(0x2222);
     829            0 :                 buffer.push_back(0x3333);
     830            0 :                 buffer.push_back(0x4444);
     831            0 :                 buffer.push_back(0x5555);
     832            0 :                 buffer.push_back(0x6666);
     833            0 :                 buffer.push_back(0x7777);
     834              :         }
     835              : 
     836            0 :         while (buffer.size() % 8 != 0)
     837              :         {
     838            0 :                 buffer.push_back(0);
     839              :         }
     840              : 
     841            0 :         size_t nPackets = (buffer.size() / 8) - 1;
     842            0 :         DTCLib::DTC_DataHeaderPacket header(link, nPackets, DTCLib::DTC_DataStatus_Valid, DTCID, DTCLib::DTC_Subsystem_Calorimeter, CURRENT_EMULATED_CALORIMETER_VERSION, ts, static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF));
     843            0 :         memcpy(&buffer[0], header.ConvertToDataPacket().GetData(), 16);
     844              : 
     845            0 :         DTCLib::DTC_DataBlock block(buffer.size() * sizeof(uint16_t));
     846            0 :         memcpy(&(*block.allocBytes)[0], &buffer[0], buffer.size() * sizeof(uint16_t));
     847            0 :         sub_event_->AddDataBlock(block);
     848            0 : }
     849              : 
     850            0 : void mu2esim::crvBlockSimulator_(DTCLib::DTC_EventWindowTag ts, DTCLib::DTC_Link_ID link, int DTCID)
     851              : {
     852              :         uint16_t buffer[24];
     853              : 
     854            0 :         size_t nPackets = 2;
     855            0 :         DTCLib::DTC_DataHeaderPacket header(link, nPackets, DTCLib::DTC_DataStatus_Valid, DTCID, DTCLib::DTC_Subsystem_CRV, CURRENT_EMULATED_CRV_VERSION, ts, static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF));
     856            0 :         memcpy(&buffer[0], header.ConvertToDataPacket().GetData(), 16);
     857              : 
     858              :         // ROC Status packet
     859            0 :         uint8_t board_number = static_cast<uint8_t>(link) + (DTCID * 6);
     860            0 :         buffer[8] = 0x60 + (board_number << 8);
     861            0 :         buffer[9] = 28;
     862            0 :         buffer[10] = 0;
     863            0 :         buffer[11] = 1;
     864            0 :         buffer[12] = 0;
     865            0 :         buffer[13] = 1;
     866            0 :         buffer[14] = 0;
     867            0 :         buffer[15] = static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF) << 8;
     868              : 
     869              :         // Hit Readout
     870            0 :         buffer[16] = 0;
     871            0 :         buffer[17] = 0;
     872            0 :         buffer[18] = 0x2211;
     873            0 :         buffer[19] = 0x4433;
     874            0 :         buffer[20] = 0x6655;
     875            0 :         buffer[21] = 0x8877;
     876            0 :         buffer[22] = 0;  // Zero padding
     877            0 :         buffer[23] = 0;
     878              : 
     879            0 :         DTCLib::DTC_DataBlock block(sizeof(buffer));
     880            0 :         memcpy(&(*block.allocBytes)[0], buffer, sizeof(buffer));
     881            0 :         sub_event_->AddDataBlock(block);
     882            0 : }
     883              : 
     884            0 : void mu2esim::reopenDDRFile_()
     885              : {
     886            0 :         if (!ddrFile_)
     887              :         {
     888            0 :                 TLOG(TLVL_INFO) << "Going to open simulated RAM file " << ddrFileName_;
     889            0 :                 ddrFile_.reset(new std::fstream(ddrFileName_, std::fstream::binary | std::fstream::in | std::fstream::out));
     890              :         }
     891              :         else
     892              :         {
     893            0 :                 ddrFile_.reset(new std::fstream(ddrFileName_, std::fstream::trunc | std::fstream::binary | std::fstream::out | std::ios::in));
     894              :         }
     895              : 
     896            0 :         if (!ddrFile_->is_open() || ddrFile_->fail())
     897              :         {
     898            0 :                 TLOG(TLVL_INFO) << "File " << ddrFileName_ << " does not exist, creating";
     899            0 :                 ddrFile_.reset(new std::fstream(ddrFileName_, std::fstream::binary | std::fstream::trunc | std::fstream::out));
     900              :                 // Reopen with original flags
     901            0 :                 ddrFile_.reset(new std::fstream(ddrFileName_, std::fstream::binary | std::fstream::in | std::fstream::out));
     902              :         }
     903            0 : }
     904              : 
     905            0 : void mu2esim::packetSimulator_(DTCLib::DTC_EventWindowTag ts, DTCLib::DTC_Link_ID link, uint16_t packetCount)
     906              : {
     907            0 :         if (!sub_event_) return;
     908              : 
     909            0 :         TLOG(TLVL_PacketSimulator) << "mu2esim::packetSimulator_: Generating data for timestamp " << ts.GetEventWindowTag(true);
     910              : 
     911            0 :         if (mode_ == DTCLib::DTC_SimMode_Performance)
     912              :         {
     913            0 :                 std::vector<uint8_t> packet(16 + packetCount * 16);
     914              : 
     915              :                 // Add a Data Header packet to the reply
     916            0 :                 packet[0] = static_cast<uint8_t>(packet.size());
     917            0 :                 packet[1] = static_cast<uint8_t>(packet.size() >> 8);
     918            0 :                 packet[2] = 0x50;
     919            0 :                 packet[3] = 0x80 + (link & 0x0F);
     920            0 :                 packet[4] = static_cast<uint8_t>(packetCount & 0xFF);
     921            0 :                 packet[5] = static_cast<uint8_t>(packetCount >> 8);
     922            0 :                 ts.GetEventWindowTag(&packet[0], 6);
     923            0 :                 packet[12] = 0;
     924            0 :                 packet[13] = 0;
     925            0 :                 packet[14] = 0;
     926            0 :                 packet[15] = 0;
     927              : 
     928            0 :                 size_t offset = 16;
     929              : 
     930            0 :                 for (uint16_t ii = 0; ii < packetCount; ++ii)
     931              :                 {
     932            0 :                         packet[offset] = static_cast<uint8_t>(ii);
     933            0 :                         packet[offset + 1] = 0x11;
     934            0 :                         packet[offset + 2] = 0x22;
     935            0 :                         packet[offset + 3] = 0x33;
     936            0 :                         packet[offset + 4] = 0x44;
     937            0 :                         packet[offset + 5] = 0x55;
     938            0 :                         packet[offset + 6] = 0x66;
     939            0 :                         packet[offset + 7] = 0x77;
     940            0 :                         packet[offset + 8] = 0x88;
     941            0 :                         packet[offset + 9] = 0x99;
     942            0 :                         packet[offset + 10] = 0xaa;
     943            0 :                         packet[offset + 11] = 0xbb;
     944            0 :                         packet[offset + 12] = 0xcc;
     945            0 :                         packet[offset + 13] = 0xdd;
     946            0 :                         packet[offset + 14] = 0xee;
     947            0 :                         packet[offset + 15] = 0xff;
     948              : 
     949            0 :                         offset += 16;
     950              :                 }
     951              : 
     952            0 :                 DTCLib::DTC_DataBlock block(packet.size());
     953            0 :                 memcpy(&(*block.allocBytes)[0], &packet[0], packet.size());
     954            0 :                 sub_event_->AddDataBlock(block);
     955            0 :         }
     956            0 :         else if (mode_ == DTCLib::DTC_SimMode_Timeout)
     957              :         {
     958              :                 uint8_t packet[16];
     959              : 
     960            0 :                 packet[0] = 0xfe;
     961            0 :                 packet[1] = 0xca;
     962            0 :                 packet[2] = 0xfe;
     963            0 :                 packet[3] = 0xca;
     964            0 :                 packet[4] = 0xfe;
     965            0 :                 packet[5] = 0xca;
     966            0 :                 packet[6] = 0xfe;
     967            0 :                 packet[7] = 0xca;
     968            0 :                 packet[8] = 0xfe;
     969            0 :                 packet[9] = 0xca;
     970            0 :                 packet[10] = 0xfe;
     971            0 :                 packet[11] = 0xca;
     972            0 :                 packet[12] = 0xfe;
     973            0 :                 packet[13] = 0xca;
     974            0 :                 packet[14] = 0xfe;
     975            0 :                 packet[15] = 0xca;
     976              : 
     977            0 :                 TLOG(TLVL_PacketSimulator) << "mu2esim::packetSimulator_ Writing Data Header packet to memory file, chn=0, packet=" << (void *)packet;
     978              : 
     979            0 :                 DTCLib::DTC_DataBlock block(sizeof(packet));
     980            0 :                 memcpy(&(*block.allocBytes)[0], packet, sizeof(packet));
     981            0 :                 sub_event_->AddDataBlock(block);
     982            0 :         }
     983              : 
     984            0 :         ddrFile_->flush();
     985              : }
        

Generated by: LCOV version 2.0-1