File indexing completed on 2025-08-05 08:16:18
0001 #include "TpcTimeFrameBuilder.h"
0002
0003 #include <Event/oncsSubConstants.h>
0004 #include <Event/packet.h>
0005
0006 #include <ffarawobjects/TpcRawHitv2.h>
0007 #include <ffarawobjects/TpcRawHitv3.h>
0008 #include <phool/PHTimer.h> // for PHTimer
0009
0010 #include <fun4all/Fun4AllHistoManager.h>
0011 #include <fun4all/Fun4AllReturnCodes.h>
0012 #include <qautils/QAHistManagerDef.h>
0013 #include <fun4all/PHTFileServer.h>
0014
0015 #include <TAxis.h>
0016 #include <TH1.h>
0017 #include <TH2.h>
0018 #include <TNamed.h>
0019 #include <TTree.h>
0020 #include <TString.h>
0021 #include <TVector3.h>
0022
0023 #include <cassert>
0024 #include <cstdint>
0025 #include <limits>
0026 #include <memory>
0027 #include <string>
0028 #include <tuple> // For std::tie
0029
0030 using namespace std;
0031
0032 TpcTimeFrameBuilder::TpcTimeFrameBuilder(const int packet_id)
0033 : m_packet_id(packet_id)
0034 , m_HistoPrefix("TpcTimeFrameBuilder_Packet" + to_string(packet_id))
0035 {
0036 for (int fee = 0; fee < MAX_FEECOUNT; ++fee)
0037 {
0038 m_bcoMatchingInformation_vec.emplace_back(
0039 std::string("BcoMatchingInformation_Packet") + to_string(packet_id) + "_FEE" + std::to_string(fee));
0040 }
0041
0042 m_feeData.resize(MAX_FEECOUNT);
0043
0044
0045
0046 m_packetTimer = new PHTimer("TpcTimeFrameBuilder_Packet" + to_string(packet_id));
0047
0048 Fun4AllHistoManager* hm = QAHistManagerDef::getHistoManager();
0049 assert(hm);
0050
0051 m_hNorm = new TH1D(TString(m_HistoPrefix.c_str()) + "_Normalization",
0052 TString(m_HistoPrefix.c_str()) + " Normalization;Items;Count",
0053 20, .5, 20.5);
0054 int i = 1;
0055 m_hNorm->GetXaxis()->SetBinLabel(i++, "Packet");
0056 m_hNorm->GetXaxis()->SetBinLabel(i++, "Lv1-Taggers");
0057 m_hNorm->GetXaxis()->SetBinLabel(i++, "EnDat-Taggers");
0058 m_hNorm->GetXaxis()->SetBinLabel(i++, "ChannelPackets");
0059 m_hNorm->GetXaxis()->SetBinLabel(i++, "Waveforms");
0060
0061 m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_GTM");
0062 m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_FEE");
0063 m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_FEE_INVALID");
0064 m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_INVALID");
0065
0066 m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_GTM_HEARTBEAT");
0067 m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_GTM_DC_STOP_SEND");
0068
0069 m_hNorm->GetXaxis()->SetBinLabel(i++, "TimeFrameSizeLimitError");
0070
0071 m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Matched");
0072 m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Unmatched");
0073 m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Matched_Hit_Sum");
0074 m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Dropped_Hit_Sum");
0075
0076 assert(i <= 20);
0077 m_hNorm->GetXaxis()->LabelsOption("v");
0078 hm->registerHisto(m_hNorm);
0079
0080 h_PacketLength = new TH1I(TString(m_HistoPrefix.c_str()) + "_PacketLength",
0081 TString(m_HistoPrefix.c_str()) + " PacketLength;PacketLength [32bit Words];Count", 1000, .5, 5e6);
0082 hm->registerHisto(h_PacketLength);
0083
0084 h_PacketLength_Residual = new TH1I(TString(m_HistoPrefix.c_str()) + "_PacketLength_Residual",
0085 TString(m_HistoPrefix.c_str()) +
0086 " PacketLength that does not fit into DMA transfer;PacketLength [16bit Words];Count",
0087 16, -.5, 15.5);
0088 hm->registerHisto(h_PacketLength_Residual);
0089
0090 h_PacketLength_Padding = new TH1I(TString(m_HistoPrefix.c_str()) + "_PacketLength_Padding",
0091 TString(m_HistoPrefix.c_str()) +
0092 " padding within PacketLength;PacketLength [32bit Words];Count",
0093 16, -.5, 15.5);
0094 hm->registerHisto(h_PacketLength_Padding);
0095
0096 m_hFEEDataStream = new TH2I(TString(m_HistoPrefix.c_str()) + "_FEE_DataStream_WordCount",
0097 TString(m_HistoPrefix.c_str()) +
0098 " FEE Data Stream Word Count;FEE ID;Type;Count",
0099 MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5, 25, .5, 25.5);
0100 i = 1;
0101 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "WordValid");
0102 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "WordSkipped");
0103 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "WordDigitalCurrentKeyWord");
0104 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "InvalidLength");
0105 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "RawHit");
0106 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitFormatErrorOverLength");
0107 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitFormatErrorMismatchedLength");
0108 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitCRCError");
0109 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "DigitalCurrent");
0110 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "DigitalCurrentFormatErrorMismatchedLength");
0111 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "DigitalCurrentCRCError");
0112 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "ParityError");
0113 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitUnusedBeforeCleanup");
0114 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeat");
0115 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeatClockSyncUnavailable");
0116 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeatClockSyncError");
0117 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeatClockSyncOK");
0118 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketClockSyncUnavailable");
0119 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketClockSyncError");
0120 m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketClockSyncOK");
0121 assert(i <= 25);
0122 hm->registerHisto(m_hFEEDataStream);
0123
0124 m_hFEEChannelPacketCount = new TH1I(TString(m_HistoPrefix.c_str()) + "_FEEChannelPacketCount",
0125 TString(m_HistoPrefix.c_str()) +
0126 " Count of waveform packet per channel;FEE*256 + Channel;Count",
0127 MAX_FEECOUNT * MAX_CHANNELS, -.5, MAX_FEECOUNT * MAX_CHANNELS - .5);
0128 hm->registerHisto(m_hFEEChannelPacketCount);
0129
0130 m_hFEESAMPAADC = new TH2I(TString(m_HistoPrefix.c_str()) + "_FEE_SAMPA_ADC",
0131 TString(m_HistoPrefix.c_str()) +
0132 " ADC distribution in 2D;ADC Time Bin [0...1023];FEE*8+SAMPA;Sum ADC",
0133 MAX_PACKET_LENGTH, -.5, MAX_PACKET_LENGTH - .5,
0134 MAX_FEECOUNT * MAX_SAMPA, -.5, MAX_FEECOUNT * MAX_SAMPA - .5);
0135 hm->registerHisto(m_hFEESAMPAADC);
0136
0137 m_hFEESAMPAHeartBeatSync = new TH1I(TString(m_HistoPrefix.c_str()) + "_FEE_SAMPA_HEARTBEAT_SYNC",
0138 TString(m_HistoPrefix.c_str()) +
0139 " FEE/SAMPA Sync Heartbeat Count;FEE*8+SAMPA;Sync Heartbeat Count",
0140 MAX_FEECOUNT * MAX_SAMPA, -.5, MAX_FEECOUNT * MAX_SAMPA - .5);
0141 hm->registerHisto(m_hFEESAMPAHeartBeatSync);
0142
0143 h_GTMClockDiff_Matched = new TH1I(TString(m_HistoPrefix.c_str()) + "_GTMClockDiff_Matched",
0144 TString(m_HistoPrefix.c_str()) +
0145 " GTM BCO Diff for Matched Time Frame;Trigger BCO Diff [BCO];Count",
0146 1024, -512 - .5, 512 - .5);
0147 hm->registerHisto(h_GTMClockDiff_Matched);
0148 h_GTMClockDiff_Unmatched = new TH1I(TString(m_HistoPrefix.c_str()) + "_GTMClockDiff_Unmatched",
0149 TString(m_HistoPrefix.c_str()) +
0150 " GTM BCO Diff for Unmatched Time Frame;Trigger BCO Diff [BCO];Count",
0151 1024, -512 - .5, 512 - .5);
0152 hm->registerHisto(h_GTMClockDiff_Unmatched);
0153 h_GTMClockDiff_Dropped = new TH1I(TString(m_HistoPrefix.c_str()) + "_GTMClockDiff_Dropped",
0154 TString(m_HistoPrefix.c_str()) +
0155 " GTM BCO Diff for Dropped Time Frame;Trigger BCO Diff [BCO];Count",
0156 16384, -16384 - .5, 0 - .5);
0157 hm->registerHisto(h_GTMClockDiff_Dropped);
0158 h_TimeFrame_Matched_Size = new TH1I(TString(m_HistoPrefix.c_str()) + "_TimeFrame_Matched_Size",
0159 TString(m_HistoPrefix.c_str()) +
0160 " Time frame size for Matched Time Frame ;Size [TPC raw hits];Count",
0161 3328, -.5, 3328 - .5);
0162 hm->registerHisto(h_TimeFrame_Matched_Size);
0163
0164 h_ProcessPacket_Time = new TH2I(TString(m_HistoPrefix.c_str()) + "_ProcessPacket_Time",
0165 TString(m_HistoPrefix.c_str()) +
0166 " Time cost to run ProcessPacket();Call counts;Time elapsed per call [ms];Count",
0167 100, 0, 30e6, 100, 0, 10);
0168 hm->registerHisto(h_ProcessPacket_Time);
0169 }
0170
0171 TpcTimeFrameBuilder::~TpcTimeFrameBuilder()
0172 {
0173 for (auto& timeFrameEntry : m_timeFrameMap)
0174 {
0175 while (!timeFrameEntry.second.empty())
0176 {
0177 delete timeFrameEntry.second.back();
0178 timeFrameEntry.second.pop_back();
0179 }
0180 }
0181
0182 if (m_packetTimer)
0183 {
0184 delete m_packetTimer;
0185 }
0186
0187 if (m_digitalCurrentDebugTTree)
0188 {
0189 delete m_digitalCurrentDebugTTree;
0190 }
0191 }
0192
0193 void TpcTimeFrameBuilder::setVerbosity(const int i)
0194 {
0195 m_verbosity = i;
0196
0197 for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec)
0198 {
0199 bcoMatchingInformation.set_verbosity(i);
0200 }
0201 }
0202
0203 bool TpcTimeFrameBuilder::isMoreDataRequired(const uint64_t& gtm_bco) const
0204 {
0205 for (const BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec)
0206 {
0207
0208
0209
0210
0211
0212 if (bcoMatchingInformation.isMoreDataRequired(gtm_bco))
0213 {
0214 return true;
0215 }
0216 }
0217
0218 if (m_verbosity > 1)
0219 {
0220 std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id
0221 << ":PASS: All FEEs satisfied for gtm_bco: 0x" << std::hex << gtm_bco << std::dec << ". Return false."
0222 << std::endl;
0223 }
0224 return false;
0225 }
0226
0227 std::vector<TpcRawHit*>& TpcTimeFrameBuilder::getTimeFrame(const uint64_t& gtm_bco)
0228 {
0229 assert(m_hNorm);
0230 uint64_t bclk_rollover_corrected = m_bcoMatchingInformation_vec[0].get_gtm_rollover_correction(gtm_bco);
0231
0232
0233 for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec)
0234 {
0235 bcoMatchingInformation.cleanup(bclk_rollover_corrected);
0236 }
0237
0238 if (m_verbosity > 2)
0239 {
0240 std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id
0241 << ": getTimeFrame for gtm_bco: 0x" << std::hex << gtm_bco << std::dec
0242 << ": bclk_rollover_corrected: 0x" << std::hex << bclk_rollover_corrected << std::dec
0243 << std::endl;
0244 }
0245
0246 for (auto it = m_timeFrameMap.begin(); it != m_timeFrameMap.end();)
0247 {
0248 if (it->first + GL1_BCO_MATCH_WINDOW < bclk_rollover_corrected)
0249 {
0250 if (m_verbosity >= 2)
0251 {
0252 std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id
0253 << ":DROPPED: BCO " << std::hex << it->first << std::dec
0254 << " dropped for gtm_bco: 0x" << std::hex << gtm_bco << std::dec
0255 << " and bclk_rollover_corrected 0x" << std::hex
0256 << bclk_rollover_corrected << std::dec << ". m_timeFrameMap:" << std::endl;
0257
0258
0259 {
0260 for (const auto& timeframe : m_timeFrameMap)
0261 {
0262 std::cout << "- BCO in map: 0x" << std::hex << timeframe.first << std::dec
0263 << "(Diff:" << int64_t(timeframe.first) - int64_t(bclk_rollover_corrected)
0264 << ")"
0265 << " size: " << timeframe.second.size()
0266 << std::endl;
0267 }
0268 }
0269 }
0270
0271 m_hNorm->Fill("GTM_TimeFrame_Dropped_Hit_Sum", it->second.size());
0272 assert(h_GTMClockDiff_Dropped);
0273 h_GTMClockDiff_Dropped->Fill(int64_t(it->first) - int64_t(bclk_rollover_corrected));
0274 for (const auto& hit : it->second)
0275 {
0276 delete hit;
0277 }
0278 it = m_timeFrameMap.erase(it);
0279 }
0280 else if (it->first < bclk_rollover_corrected + GL1_BCO_MATCH_WINDOW)
0281 {
0282 if (m_verbosity > 1)
0283 {
0284 std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id
0285 << ":PASS: BCO " << std::hex << it->first << std::dec
0286 << " matched for gtm_bco: 0x" << std::hex << gtm_bco << std::dec
0287 << " and bclk_rollover_corrected 0x" << std::hex
0288 << bclk_rollover_corrected << std::dec << ". m_timeFrameMap:" << std::endl;
0289
0290 for (const auto& timeframe : m_timeFrameMap)
0291 {
0292 std::cout << "- BCO in map: 0x" << std::hex << timeframe.first << std::dec
0293 << "(Diff:" << int64_t(timeframe.first) - int64_t(bclk_rollover_corrected)
0294 << ")"
0295 << " size: " << timeframe.second.size()
0296 << std::endl;
0297 }
0298 }
0299
0300 m_hNorm->Fill("GTM_TimeFrame_Matched", 1);
0301 assert(h_GTMClockDiff_Matched);
0302 h_GTMClockDiff_Matched->Fill(int64_t(it->first) - int64_t(bclk_rollover_corrected));
0303 assert(h_TimeFrame_Matched_Size);
0304 h_TimeFrame_Matched_Size->Fill(it->second.size());
0305 m_hNorm->Fill("GTM_TimeFrame_Matched_Hit_Sum", it->second.size());
0306 m_UsedTimeFrameSet.push(it->first);
0307 return it->second;
0308 }
0309 else
0310 {
0311 break;
0312 }
0313 }
0314
0315 if (m_verbosity >= 1)
0316 {
0317 std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id
0318 << ":WARNING: BCO no match for gtm_bco: 0x" << std::hex << gtm_bco << std::dec
0319 << "and bclk_rollover_corrected 0x" << std::hex
0320 << bclk_rollover_corrected << std::dec << ". m_timeFrameMap:" << std::endl;
0321
0322 if (m_verbosity >= 2)
0323 {
0324 for (const auto& timeframe : m_timeFrameMap)
0325 {
0326 std::cout << "- BCO in map: 0x" << std::hex << timeframe.first << std::dec
0327 << "(Diff:" << int64_t(timeframe.first) - int64_t(bclk_rollover_corrected) << ")" << std::endl;
0328 }
0329 }
0330 }
0331
0332 m_hNorm->Fill("GTM_TimeFrame_Unmatched", 1);
0333 assert(h_GTMClockDiff_Unmatched);
0334 for (const auto& timeframe : m_timeFrameMap)
0335 {
0336 h_GTMClockDiff_Unmatched->Fill(int64_t(timeframe.first) - int64_t(bclk_rollover_corrected));
0337 }
0338 static std::vector<TpcRawHit*> empty;
0339 return empty;
0340 }
0341
0342 void TpcTimeFrameBuilder::CleanupUsedPackets(const uint64_t& bclk)
0343 {
0344 if (m_verbosity > 2)
0345 {
0346 std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id << ": cleaning up bcos < 0x" << std::hex
0347 << bclk << std::dec << std::endl;
0348 }
0349
0350 while (not m_UsedTimeFrameSet.empty())
0351 {
0352 uint64_t bco_completed = m_UsedTimeFrameSet.front();
0353 m_UsedTimeFrameSet.pop();
0354
0355 if (m_verbosity > 1)
0356 {
0357 std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id
0358 << ": cleaning up previous processed packet in m_timeFrameMap at clock 0x"
0359 << std::hex
0360 << bco_completed << std::dec
0361 << " for CleanupUsedPackets(const uint64_t& bclk) call at bclk 0x" << std::hex
0362 << bclk << std::dec
0363 << " Diff:" << int64_t(bco_completed) - int64_t(bclk) << std::endl;
0364 }
0365
0366 auto it = m_timeFrameMap.find(bco_completed);
0367
0368
0369
0370
0371 if (it != m_timeFrameMap.end())
0372 {
0373 while (!it->second.empty())
0374 {
0375 delete it->second.back();
0376 it->second.pop_back();
0377 }
0378 m_timeFrameMap.erase(it);
0379 }
0380 }
0381
0382 uint64_t bclk_rollover_corrected = m_bcoMatchingInformation_vec[0].get_gtm_rollover_correction(bclk);
0383
0384 assert(m_hFEEDataStream);
0385
0386 for (auto it = m_timeFrameMap.begin(); it != m_timeFrameMap.end();)
0387 {
0388 if (it->first <= bclk_rollover_corrected)
0389 {
0390 int count = 0;
0391 while (!it->second.empty())
0392 {
0393 m_hFEEDataStream->Fill(it->second.back()->get_fee(), "HitUnusedBeforeCleanup", 1);
0394 delete it->second.back();
0395 it->second.pop_back();
0396 ++count;
0397 }
0398
0399 if (m_verbosity >= 1)
0400 {
0401 std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id
0402 << ": cleaning up " << count << " TPC hits in m_timeFrameMap at clock 0x"
0403 << std::hex
0404 << it->first << std::dec
0405 << " for <= bclk_rollover_corrected 0x" << std::hex
0406 << bclk_rollover_corrected << std::dec
0407 << " Diff:" << int64_t(it->first) - int64_t(bclk_rollover_corrected) << std::endl;
0408 }
0409 m_timeFrameMap.erase(it++);
0410 }
0411 else
0412 {
0413 break;
0414 }
0415 }
0416 }
0417
0418 int TpcTimeFrameBuilder::ProcessPacket(Packet* packet)
0419 {
0420 static size_t call_count = 0;
0421 ++call_count;
0422
0423 if (m_verbosity > 1)
0424 {
0425 std::cout << "TpcTimeFrameBuilder::ProcessPacket: " << m_packet_id
0426 << "\t- Entry " << std::endl;
0427 }
0428
0429 if (!packet)
0430 {
0431 cout << __PRETTY_FUNCTION__ << "\t- Error : Invalid packet, doing nothing" << endl;
0432 assert(packet);
0433 return 0;
0434 }
0435
0436 if (m_hitFormat <0 )
0437 {
0438 if (packet->getHitFormat() != IDTPCFEEV4 and packet->getHitFormat() != IDTPCFEEV5 and packet->getHitFormat() != IDTPCFEEV6 )
0439 {
0440 cout << __PRETTY_FUNCTION__ << "\t- Error : expect packet format " << IDTPCFEEV4
0441 << " or "<< IDTPCFEEV5<< " or "<< IDTPCFEEV6
0442 << "\t- but received packet format " << packet->getHitFormat() << ":" << endl;
0443 packet->identify();
0444 assert(packet->getHitFormat() == IDTPCFEEV4 or packet->getHitFormat() == IDTPCFEEV5 or packet->getHitFormat() == IDTPCFEEV6);
0445 return 0;
0446 }
0447
0448 m_hitFormat = packet->getHitFormat();
0449
0450 double clock_multiplier (0);
0451 if (m_hitFormat == IDTPCFEEV4)
0452 {
0453
0454
0455 clock_multiplier = 4.262916255;
0456 }
0457 else if (m_hitFormat == IDTPCFEEV5 or packet->getHitFormat() == IDTPCFEEV6)
0458 {
0459
0460 clock_multiplier = 30./8.;
0461 }
0462 else
0463 {
0464 assert(clock_multiplier>0);
0465 }
0466
0467 if (m_verbosity >= 1)
0468 {
0469 cout << __PRETTY_FUNCTION__ << " set clock sync for hit format " << m_hitFormat
0470 <<" with clock_multiplier = "<< clock_multiplier << endl;
0471 }
0472 for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec)
0473 {
0474 bcoMatchingInformation.set_gtm_clock_multiplier(clock_multiplier);
0475 }
0476 }
0477 else
0478 {
0479 if (packet->getHitFormat() != m_hitFormat)
0480 {
0481 cout << __PRETTY_FUNCTION__ << "\t- Error : expect the last packet format " << m_hitFormat
0482 << "\t- but received packet format " << packet->getHitFormat() << ":" << endl;
0483 packet->identify();
0484 assert((packet->getHitFormat() == m_hitFormat));
0485 return 0;
0486 }
0487 }
0488 assert((packet->getHitFormat() == m_hitFormat));
0489
0490 if (m_packet_id != packet->getIdentifier())
0491 {
0492 cout << __PRETTY_FUNCTION__ << "\t- Error : mismatched packet with packet ID expectation of " << m_packet_id << ", but received";
0493 packet->identify();
0494 assert(m_packet_id == packet->getIdentifier());
0495 return 0;
0496 }
0497
0498 assert(m_packetTimer);
0499 if ((m_verbosity == 1 and (call_count % 1000) == 0) or (m_verbosity > 1))
0500 {
0501 cout << __PRETTY_FUNCTION__ << "\t- : received packet ";
0502 packet->identify();
0503
0504 m_packetTimer->print_stat();
0505 }
0506 m_packetTimer->restart();
0507
0508
0509
0510
0511
0512
0513 Fun4AllHistoManager* hm = QAHistManagerDef::getHistoManager();
0514 assert(hm);
0515 assert(m_hNorm);
0516 m_hNorm->Fill("Packet", 1);
0517
0518 int data_length = packet->getDataLength();
0519 assert(h_PacketLength);
0520 h_PacketLength->Fill(data_length);
0521
0522 int data_padding = packet->getPadding();
0523 assert(h_PacketLength_Padding);
0524 h_PacketLength_Padding->Fill(data_padding);
0525 if (data_padding != 0)
0526 {
0527 cout << __PRETTY_FUNCTION__ << "\t- : Warning : suspecious padding "
0528 << data_padding << "\t- in packet " << m_packet_id <<":" << endl;
0529 packet->identify();
0530
0531 }
0532
0533 size_t dma_words_buffer = static_cast<size_t>(data_length) * 2 / DAM_DMA_WORD_LENGTH + 1;
0534 vector<dma_word> buffer(dma_words_buffer);
0535
0536 int l2 = 0;
0537 packet->fillIntArray(reinterpret_cast<int*>(buffer.data()), data_length + DAM_DMA_WORD_LENGTH / 2, &l2, "DATA");
0538
0539 if (data_padding != 0)
0540 {
0541 cout << __PRETTY_FUNCTION__ << "\t- : data_length = " << data_length
0542 << "\t- data_padding = " << data_padding <<"\t l2 = "<<l2 << "\t- in packet " << m_packet_id <<":" << endl;
0543 }
0544
0545 assert(l2 <= data_length);
0546
0547 if(l2 < data_padding)
0548 {
0549 cout << __PRETTY_FUNCTION__ << "\t- : Error : l2 from fillIntArray() is smaller than padding suggesting an invalid data: " << l2
0550 << "\t- in packet " << m_packet_id << ". Data length: " << data_length
0551 << ", data padding: " << data_padding <<". Ignore this packet: "<< endl;
0552 packet->identify();
0553 return Fun4AllReturnCodes::DISCARDEVENT;
0554 }
0555 l2 -= data_padding;
0556
0557 assert(l2 >= 0);
0558
0559 size_t dma_words = static_cast<size_t>(l2) * 2 / DAM_DMA_WORD_LENGTH;
0560 size_t dma_residual = (static_cast<size_t>(l2) * 2) % DAM_DMA_WORD_LENGTH;
0561 assert(dma_words <= buffer.size());
0562 assert(h_PacketLength_Residual);
0563 h_PacketLength_Residual->Fill(dma_residual);
0564 if (dma_residual > 0)
0565 {
0566 cout << __PRETTY_FUNCTION__ << "\t- : Warning : mismatch of RCDAQ data to DMA transfer. Dropping mismatched data: "
0567 << dma_residual << "\t- in packet " << m_packet_id << ". Dropping residual data : " << endl;
0568
0569 assert(dma_words + 1 < buffer.size());
0570 const dma_word& last_dma_word_data = buffer[dma_words + 1];
0571 const uint16_t* last_dma_word = reinterpret_cast<const uint16_t*>(&last_dma_word_data);
0572
0573 for (size_t i = 0; i < dma_residual; ++i)
0574 {
0575 cout << "\t- 0x" << hex << last_dma_word[i] << dec;
0576 }
0577 cout << endl;
0578 }
0579
0580 if (m_verbosity > 1)
0581 {
0582 cout << __PRETTY_FUNCTION__ << "\t- : packet" << m_packet_id << endl
0583 << "\t- data_length = " << data_length << endl
0584 << "\t- data_padding = " << data_padding << endl
0585 << "\t- dma_words_buffer = " << dma_words_buffer << endl
0586 << "\t- l2 = " << l2 << endl
0587 << "\t- dma_words = " << dma_words << endl;
0588 }
0589
0590
0591 for (size_t index = 0; index < dma_words; ++index)
0592 {
0593 const dma_word& dma_word_data = buffer[index];
0594
0595 if (m_verbosity > 2)
0596 {
0597 cout << __PRETTY_FUNCTION__ << "\t- : processing DMA word "
0598 << index << "/" << dma_words << "\t- with header 0x"
0599 << hex << dma_word_data.dma_header << dec << endl;
0600 }
0601
0602 if ((dma_word_data.dma_header & 0xFF00U) == FEE_MAGIC_KEY)
0603 {
0604 unsigned int fee_id = dma_word_data.dma_header & 0xffU;
0605
0606 if (fee_id < MAX_FEECOUNT)
0607 {
0608 for (const uint16_t& i : dma_word_data.data)
0609 {
0610 m_feeData[fee_id].push_back(i);
0611 }
0612 m_hNorm->Fill("DMA_WORD_FEE", 1);
0613
0614
0615 process_fee_data(fee_id);
0616 }
0617 else
0618 {
0619 cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE ID " << fee_id << "\t- at position " << index << endl;
0620 index += DAM_DMA_WORD_LENGTH - 1;
0621 m_hNorm->Fill("DMA_WORD_FEE_INVALID", 1);
0622 }
0623 }
0624
0625 else if ((dma_word_data.dma_header & 0xFF00U) == GTM_MAGIC_KEY)
0626 {
0627 decode_gtm_data(dma_word_data);
0628 m_hNorm->Fill("DMA_WORD_GTM", 1);
0629 }
0630 else
0631 {
0632 cout << __PRETTY_FUNCTION__ << "\t- : Error : Unknown data type at position " << index << ": "
0633 << hex << buffer[index].dma_header << dec << endl;
0634
0635 m_hNorm->Fill("DMA_WORD_INVALID", 1);
0636 }
0637 }
0638
0639
0640 for (auto& timeframe : m_timeFrameMap)
0641 {
0642 if (timeframe.second.size() > kMaxRawHitLimit)
0643 {
0644 cout << __PRETTY_FUNCTION__ << "\t- : Warning : impossible amount of hits in the same timeframe at BCO "
0645 << timeframe.first << "\t- : " << timeframe.second.size() << ", limit is " << kMaxRawHitLimit
0646 << ". Dropping this time frame!"
0647 << endl;
0648 m_hNorm->Fill("TimeFrameSizeLimitError", 1);
0649
0650 while (!timeframe.second.empty())
0651 {
0652 delete timeframe.second.back();
0653 timeframe.second.pop_back();
0654 }
0655 }
0656 }
0657
0658 m_packetTimer->stop();
0659 assert(h_ProcessPacket_Time);
0660 h_ProcessPacket_Time->Fill(call_count, m_packetTimer->elapsed());
0661
0662 return Fun4AllReturnCodes::EVENT_OK;
0663 }
0664
0665 int TpcTimeFrameBuilder::process_fee_data(unsigned int fee)
0666 {
0667 assert(m_hFEEDataStream);
0668
0669 if (m_verbosity > 2)
0670 {
0671 cout << __PRETTY_FUNCTION__ << "\t- : processing FEE " << fee << "\t- with " << m_feeData[fee].size() << "\t- words" << endl;
0672 }
0673
0674 assert(fee < m_feeData.size());
0675 std::deque<uint16_t>& data_buffer = m_feeData[fee];
0676
0677 while (HEADER_LENGTH <= data_buffer.size())
0678 {
0679
0680
0681 bool is_digital_current = false;
0682
0683 if (data_buffer[3] == FEE_PACKET_MAGIC_KEY_3_DC)
0684 {
0685 if (m_verbosity > 2)
0686 {
0687 cout << __PRETTY_FUNCTION__
0688 << "\t- : processing FEE " << fee
0689 << "\t- with digital packet" << endl;
0690 }
0691
0692 m_hFEEDataStream->Fill(fee, "WordDigitalCurrentKeyWord", 1);
0693 is_digital_current = true;
0694 }
0695 else
0696 {
0697
0698 if (data_buffer[1] != FEE_PACKET_MAGIC_KEY_1)
0699 {
0700 if (m_verbosity > 1)
0701 {
0702 cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE magic key at position 1 0x" << hex << data_buffer[1] << dec << endl;
0703 }
0704 m_hFEEDataStream->Fill(fee, "WordSkipped", 1);
0705 data_buffer.pop_front();
0706 continue;
0707 }
0708 assert(data_buffer[1] == FEE_PACKET_MAGIC_KEY_1);
0709
0710 if (data_buffer[2] != FEE_PACKET_MAGIC_KEY_2)
0711 {
0712 if (m_verbosity > 1)
0713 {
0714 cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE magic key at position 2 0x" << hex << data_buffer[2] << dec << endl;
0715 }
0716 m_hFEEDataStream->Fill(fee, "WordSkipped", 1);
0717 data_buffer.pop_front();
0718 continue;
0719 }
0720 assert(data_buffer[2] == FEE_PACKET_MAGIC_KEY_2);
0721
0722 }
0723
0724
0725 const uint16_t & pkt_length = data_buffer[0];
0726 if (pkt_length > MAX_PACKET_LENGTH)
0727 {
0728 if (m_verbosity > 1)
0729 {
0730 cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE pkt_length " << pkt_length << endl;
0731 }
0732 m_hFEEDataStream->Fill(fee, "InvalidLength", 1);
0733 data_buffer.pop_front();
0734 continue;
0735 }
0736
0737 if (pkt_length + 1U > data_buffer.size())
0738 {
0739 if (m_verbosity > 2)
0740 {
0741 cout << __PRETTY_FUNCTION__ << "\t- : packet over buffer boundary for now, skip decoding and wait for more data: "
0742 " pkt_length = "
0743 << pkt_length
0744 << "\t- data_buffer.size() = " << data_buffer.size()
0745 << endl;
0746 }
0747 break;
0748 }
0749
0750 if (is_digital_current)
0751 {
0752 process_fee_data_digital_current(fee, data_buffer);
0753 }
0754 else
0755 {
0756 process_fee_data_waveform(fee, data_buffer);
0757 }
0758 data_buffer.erase(data_buffer.begin(), data_buffer.begin() + pkt_length + 1);
0759 m_hFEEDataStream->Fill(fee, "WordValid", pkt_length + 1);
0760
0761 }
0762
0763 return Fun4AllReturnCodes::EVENT_OK;
0764 }
0765
0766 void TpcTimeFrameBuilder::process_fee_data_waveform(const unsigned int & fee, std::deque<uint16_t>& data_buffer)
0767 {
0768 const uint16_t & pkt_length = data_buffer[0];
0769
0770 fee_payload payload;
0771
0772 payload.fee_id = fee;
0773 payload.adc_length = data_buffer[0] - HEADER_LENGTH;
0774 payload.data_parity = data_buffer[4] >> 9U;
0775 payload.sampa_address = static_cast<uint16_t>(data_buffer[4] >> 5U) & 0xfU;
0776 payload.sampa_channel = data_buffer[4] & 0x1fU;
0777 payload.channel = data_buffer[4] & 0x1ffU;
0778 payload.type = static_cast<uint16_t>(data_buffer[3] >> 7U) & 0x7U;
0779 payload.user_word = data_buffer[3] & 0x7fU;
0780 payload.bx_timestamp = static_cast<uint32_t>(static_cast<uint32_t>(data_buffer[6] & 0x3ffU) << 10U) | (data_buffer[5] & 0x3ffU);
0781 payload.data_crc = data_buffer[pkt_length];
0782
0783 if (not m_fastBCOSkip)
0784 {
0785 auto crc_parity = crc16_parity(fee, pkt_length);
0786 payload.calc_crc = crc_parity.first;
0787 payload.calc_parity = crc_parity.second;
0788
0789 if (payload.data_crc != payload.calc_crc)
0790 {
0791 if (m_verbosity > 2)
0792 {
0793 cout << __PRETTY_FUNCTION__ << "\t- : CRC error in FEE "
0794 << fee << "\t- at position " << pkt_length - 1
0795 << ": data_crc = " << payload.data_crc
0796 << "\t- calc_crc = " << payload.calc_crc << endl;
0797 }
0798 m_hFEEDataStream->Fill(fee, "HitCRCError", 1);
0799
0800 }
0801
0802 if (payload.data_parity != payload.calc_parity)
0803 {
0804 if (m_verbosity > 2)
0805 {
0806 cout << __PRETTY_FUNCTION__ << "\t- : parity error in FEE "
0807 << fee << "\t- at position " << pkt_length - 1
0808 << ": data_parity = " << payload.data_parity
0809 << "\t- calc_parity = " << payload.calc_parity << endl;
0810 }
0811 m_hFEEDataStream->Fill(fee, "ParityError", 1);
0812
0813 }
0814 }
0815
0816 assert(fee < m_bcoMatchingInformation_vec.size());
0817 BcoMatchingInformation& m_bcoMatchingInformation = m_bcoMatchingInformation_vec[fee];
0818
0819 if (payload.type == m_bcoMatchingInformation.HEARTBEAT_T)
0820 {
0821 if (m_verbosity > 1)
0822 {
0823 cout << __PRETTY_FUNCTION__
0824 << "\t- : received heartbeat packet from FEE " << fee << endl;
0825 }
0826
0827
0828 if (not m_bcoMatchingInformation.is_verified())
0829 {
0830 m_hFEEDataStream->Fill(fee, "PacketHeartBeatClockSyncUnavailable", 1);
0831
0832 if (m_verbosity > 1)
0833 {
0834 std::cout << "TpcTimeFrameBuilder::process_fee_data - bco_matching not verified for heart beat, dropping packet" << std::endl;
0835 m_bcoMatchingInformation.print_gtm_bco_information();
0836 }
0837 }
0838 else
0839 {
0840 const optional<uint64_t> result = m_bcoMatchingInformation.find_reference_heartbeat(payload);
0841 m_hFEEDataStream->Fill(fee, "PacketHeartBeat", 1);
0842
0843 if (result)
0844 {
0845
0846 payload.gtm_bco = result.value();
0847 m_hFEEDataStream->Fill(fee, "PacketHeartBeatClockSyncOK", 1);
0848
0849 assert(m_hFEESAMPAHeartBeatSync);
0850 m_hFEESAMPAHeartBeatSync->Fill(fee * MAX_SAMPA + payload.sampa_address, 1);
0851 }
0852 else
0853 {
0854 m_hFEEDataStream->Fill(fee, "PacketHeartBeatClockSyncError", 1);
0855
0856
0857 }
0858 if (m_verbosity > 2)
0859 {
0860 m_bcoMatchingInformation.print_gtm_bco_information();
0861 }
0862 }
0863 }
0864 else if (not m_fastBCOSkip)
0865 {
0866 m_hFEEChannelPacketCount->Fill(fee * MAX_CHANNELS + payload.channel, 1);
0867
0868
0869 if (not m_bcoMatchingInformation.is_verified())
0870 {
0871 m_hFEEDataStream->Fill(fee, "PacketClockSyncUnavailable", 1);
0872
0873 if (m_verbosity > 1)
0874 {
0875 std::cout << "TpcTimeFrameBuilder::process_fee_data - bco_matching not verified, dropping packet" << std::endl;
0876 m_bcoMatchingInformation.print_gtm_bco_information();
0877 }
0878 }
0879 else
0880 {
0881 const optional<uint64_t> result = m_bcoMatchingInformation.find_gtm_bco(payload.bx_timestamp);
0882
0883 if (result)
0884 {
0885
0886 payload.gtm_bco = result.value();
0887 m_hFEEDataStream->Fill(fee, "PacketClockSyncOK", 1);
0888 }
0889 else
0890 {
0891 if (m_verbosity > 1)
0892 {
0893 std::cout << "TpcTimeFrameBuilder::process_fee_data - WARNING: bco_matching failed!" << std::endl;
0894 m_bcoMatchingInformation.print_gtm_bco_information();
0895 }
0896 m_hFEEDataStream->Fill(fee, "PacketClockSyncError", 1);
0897
0898
0899 }
0900 }
0901 }
0902
0903 if (m_verbosity > 2)
0904 {
0905 cout << __PRETTY_FUNCTION__ << "\t- : received data packet "
0906 << "\t- from FEE " << fee << endl
0907 << "\t- pkt_length = " << pkt_length << endl
0908 << "\t- type = " << payload.type << endl
0909 << "\t- adc_length = " << payload.adc_length << endl
0910 << "\t- sampa_address = " << payload.sampa_address << endl
0911 << "\t- sampa_channel = " << payload.sampa_channel << endl
0912 << "\t- channel = " << payload.channel << endl
0913 << "\t- bx_timestamp = 0x" << hex << payload.bx_timestamp << dec << endl
0914 << "\t- bco = 0x" << hex << payload.gtm_bco << dec << endl
0915 << "\t- data_crc = 0x" << hex << payload.data_crc << dec << endl
0916 << "\t- calc_crc = 0x" << hex << payload.calc_crc << dec << endl
0917 << "\t- data_parity = 0x" << hex << payload.data_parity << dec << endl
0918 << "\t- calc_parity = 0x" << hex << payload.calc_parity << dec << endl;
0919 }
0920
0921 if ((not m_fastBCOSkip) and payload.gtm_bco > 0)
0922 {
0923 m_hFEEDataStream->Fill(fee, "RawHit", 1);
0924
0925
0926 size_t pos = HEADER_LENGTH;
0927 std::deque<uint16_t>::const_iterator data_buffer_iterator = data_buffer.cbegin();
0928 std::advance(data_buffer_iterator, pos);
0929 while (pos + 2 < pkt_length)
0930 {
0931 const uint16_t& nsamp = *data_buffer_iterator;
0932 ++pos;
0933 ++data_buffer_iterator;
0934 const uint16_t& start_t = *data_buffer_iterator;
0935 ++pos;
0936 ++data_buffer_iterator;
0937 if (m_verbosity > 3)
0938 {
0939 cout << __PRETTY_FUNCTION__ << ": nsamp: " << nsamp
0940 << "+ pos: " << pos
0941 << " pkt_length: " << pkt_length << " start_t:" << start_t << endl;
0942 }
0943
0944 if (pos + nsamp > pkt_length)
0945 {
0946 if (m_verbosity > 1)
0947 {
0948 cout << __PRETTY_FUNCTION__ << ": WARNING : nsamp: " << nsamp
0949 << "+ pos: " << pos
0950 << " > pkt_length: " << pkt_length << ", format error over length: " << endl;
0951
0952 for (int print_pos = 0; print_pos <= pkt_length; ++print_pos)
0953 {
0954 cout << "\t[" << print_pos << "]=0x" << hex << data_buffer[print_pos] << dec << "(" << data_buffer[print_pos] << ")";
0955 }
0956 cout << endl;
0957 }
0958 m_hFEEDataStream->Fill(fee, "HitFormatErrorOverLength", 1);
0959
0960 break;
0961 }
0962
0963 const unsigned int fee_sampa_address = fee * MAX_SAMPA + payload.sampa_address;
0964 std::vector<uint16_t> adc(nsamp);
0965 for (int j = 0; j < nsamp; j++)
0966 {
0967 const uint16_t& adc_value = *data_buffer_iterator;
0968
0969 adc[j] = adc_value;
0970 m_hFEESAMPAADC->Fill(start_t + j, fee_sampa_address, adc_value);
0971
0972 ++pos;
0973 ++data_buffer_iterator;
0974 }
0975 payload.waveforms.emplace_back(start_t, std::move(adc));
0976
0977
0978
0979 }
0980
0981 if (pos != pkt_length)
0982 {
0983 if (m_verbosity > 1)
0984 {
0985 cout << __PRETTY_FUNCTION__ << ": WARNING : residual data at the end of decoding:"
0986 << " pos: " << pos
0987 << " <pkt_length: " << pkt_length << ", format error under length" << endl;
0988 }
0989 m_hFEEDataStream->Fill(fee, "HitFormatErrorMismatchedLength", 1);
0990 }
0991
0992
0993 if (payload.type != m_bcoMatchingInformation.HEARTBEAT_T)
0994 {
0995 TpcRawHitv3* hit = new TpcRawHitv3();
0996 m_timeFrameMap[payload.gtm_bco].push_back(hit);
0997
0998 hit->set_bco(payload.bx_timestamp);
0999 hit->set_packetid(m_packet_id);
1000 hit->set_fee(fee);
1001 hit->set_channel(payload.channel);
1002 hit->set_type(payload.type);
1003
1004 hit->set_checksumerror(payload.data_crc != payload.calc_crc);
1005
1006 hit->set_parityerror(payload.data_parity != payload.calc_parity);
1007
1008 for (pair<uint16_t, std::vector<uint16_t>>& waveform : payload.waveforms)
1009 {
1010 hit->move_adc_waveform(waveform.first, std::move(waveform.second));
1011 }
1012 }
1013 }
1014
1015 return ;
1016 }
1017
1018 void TpcTimeFrameBuilder::process_fee_data_digital_current(const unsigned int & fee, std::deque<uint16_t>& data_buffer)
1019 {
1020 if (m_verbosity > 2)
1021 {
1022 cout << __PRETTY_FUNCTION__ << "\t- : processing digital_current data " << endl;
1023 }
1024 m_hFEEDataStream->Fill(fee, "DigitalCurrent", 1);
1025 const uint16_t & pkt_length = data_buffer[0];
1026
1027 if (pkt_length != HEADER_LENGTH + digital_current_payload::MAX_CHANNELS * 2 * 2)
1028 {
1029 if (m_verbosity > 1)
1030 {
1031 cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE pkt_length " << pkt_length
1032 << ", expected at least " << HEADER_LENGTH + digital_current_payload::MAX_CHANNELS * 2 * 2
1033 << endl;
1034 }
1035 m_hFEEDataStream->Fill(fee, "DigitalCurrentFormatErrorMismatchedLength", 1);
1036 return;
1037 }
1038
1039 digital_current_payload payload;
1040
1041 payload.fee = fee;
1042 payload.pkt_length = pkt_length;
1043 payload.sampa_address = (data_buffer[4] >> 5U) & 0xfU;
1044
1045 payload.channel = data_buffer[4] & 0x1ffU;
1046
1047 payload.bx_timestamp = ((data_buffer[6] & 0x3ffU) << 10U) | (data_buffer[5] & 0x3ff);
1048
1049 uint16_t pos = HEADER_LENGTH;
1050 for(int ich = 0; ich<digital_current_payload::MAX_CHANNELS; ich++)
1051 {
1052 payload.current[ich] = ((unsigned int)data_buffer[pos])<<16U | ((unsigned int)data_buffer[pos+1U]);
1053 pos++; pos++;
1054 payload.nsamples[ich] = ((unsigned int)data_buffer[pos])<<16U | ((unsigned int)data_buffer[pos+1U]);
1055 pos++; pos++;
1056 }
1057
1058 if (pos != pkt_length)
1059 {
1060 if (m_verbosity> 1)
1061 {
1062 cout << __PRETTY_FUNCTION__ << "\t- : Warning : residual data at the end of decoding:"
1063 << " pos: " << pos
1064 << " <pkt_length: " << pkt_length << ", format error under length" << endl;
1065 }
1066 }
1067
1068 payload.data_crc = data_buffer[pkt_length];
1069 auto crc_parity = crc16_parity(fee, pkt_length);
1070 payload.calc_crc = crc_parity.first;
1071
1072
1073 if (payload.data_crc != payload.calc_crc)
1074 {
1075 if (m_verbosity > 2)
1076 {
1077 cout << __PRETTY_FUNCTION__ << "\t- : CRC error in FEE "
1078 << fee << "\t- at position " << pkt_length - 1
1079 << ": data_crc = " << payload.data_crc
1080 << "\t- calc_crc = " << payload.calc_crc << endl;
1081 }
1082 m_hFEEDataStream->Fill(fee, "DigitalCurrentCRCError", 1);
1083
1084 }
1085
1086 assert(fee < m_bcoMatchingInformation_vec.size());
1087 BcoMatchingInformation& m_bcoMatchingInformation = m_bcoMatchingInformation_vec[fee];
1088 std::tie(payload.gtm_bco, payload.bx_timestamp_predicted) = m_bcoMatchingInformation.find_dc_read_bco();
1089
1090 if (m_verbosity>2)
1091 {
1092 cout << __PRETTY_FUNCTION__ << "\t- : received digital current packet "
1093 << "\t- from FEE " << fee << endl
1094 << "\t- pkt_length = " << pkt_length << endl
1095 << "\t- sampa_address = " << payload.sampa_address << endl
1096 << "\t- channel = " << payload.channel << endl
1097 << "\t- bx_timestamp = 0x" << hex << payload.bx_timestamp << dec << endl
1098 << "\t- gtm_bco = 0x" << hex << payload.gtm_bco << dec << endl
1099 << "\t- bx_timestamp_predicted = 0x" << hex << payload.bx_timestamp_predicted << dec << endl;
1100
1101 cout << "\t- current:" ;
1102 for (int ich = 0; ich < digital_current_payload::MAX_CHANNELS; ich++)
1103 {
1104 cout << "\t[" << ich << "] = " << payload.current[ich] ;
1105 }
1106 cout << endl;
1107 cout << "\t- nsamples:" ;
1108 for (int ich = 0; ich < digital_current_payload::MAX_CHANNELS; ich++)
1109 {
1110 cout << "\t[" << ich << "] = " << payload.nsamples[ich] ;
1111 }
1112 cout << endl;
1113 cout<< "\t- data_crc = 0x" << hex << payload.data_crc << dec << endl
1114 << "\t- calc_crc = 0x" << hex << payload.calc_crc << dec << endl;
1115 }
1116
1117 if (m_digitalCurrentDebugTTree)
1118 {
1119 m_digitalCurrentDebugTTree->fill(payload);
1120 }
1121
1122 return ;
1123 }
1124
1125 void TpcTimeFrameBuilder::SaveDigitalCurrentDebugTTree(const std::string &name)
1126 {
1127 if (m_verbosity >= 1)
1128 {
1129 cout << __PRETTY_FUNCTION__ << "\t- : Saving digital current debug TTree to " << name << endl;
1130 }
1131
1132 m_digitalCurrentDebugTTree = new TpcTimeFrameBuilder::DigitalCurrentDebugTTree(name);
1133 }
1134
1135 TpcTimeFrameBuilder::DigitalCurrentDebugTTree::DigitalCurrentDebugTTree(const std::string &name)
1136 : m_name(name)
1137 {
1138
1139 PHTFileServer::get().open(m_name, "RECREATE");
1140
1141
1142
1143 m_tDigitalCurrent = new TTree("T_DigitalCurrent", "DigitalCurrent Debug TTree");
1144 assert(m_tDigitalCurrent);
1145
1146 m_tDigitalCurrent->Branch("dc", &m_payload,
1147 "gtm_bco/l:bx_timestamp_predicted/i:fee/s:pkt_length/s:channel/s:sampa_address/s:bx_timestamp/i:current[8]/i:nsamples[8]/i:data_crc/s:calc_crc/s");
1148 }
1149
1150 TpcTimeFrameBuilder::DigitalCurrentDebugTTree::~DigitalCurrentDebugTTree()
1151 {
1152
1153 PHTFileServer::get().write(m_name);
1154 }
1155
1156 void TpcTimeFrameBuilder::DigitalCurrentDebugTTree::fill(const TpcTimeFrameBuilder::digital_current_payload &payload)
1157 {
1158 assert(m_tDigitalCurrent);
1159
1160 m_payload = payload;
1161 m_tDigitalCurrent->Fill();
1162 }
1163
1164 int TpcTimeFrameBuilder::decode_gtm_data(const TpcTimeFrameBuilder::dma_word& gtm_word)
1165 {
1166 if (m_verbosity > 2)
1167 {
1168 cout << __PRETTY_FUNCTION__ << "\t- : processing GTM data " << endl;
1169 }
1170
1171 const uint8_t* gtm = reinterpret_cast<const uint8_t*>(>m_word);
1172
1173 gtm_payload payload;
1174
1175 payload.pkt_type = gtm[0] | static_cast<uint16_t>((unsigned short) gtm[1] << 8U);
1176
1177 if (payload.pkt_type != GTM_LVL1_ACCEPT_MAGIC_KEY && payload.pkt_type != GTM_ENDAT_MAGIC_KEY && payload.pkt_type != GTM_MODEBIT_MAGIC_KEY)
1178 {
1179 return -1;
1180 }
1181
1182 payload.is_lvl1 = payload.pkt_type == GTM_LVL1_ACCEPT_MAGIC_KEY;
1183 payload.is_endat = payload.pkt_type == GTM_ENDAT_MAGIC_KEY;
1184 payload.is_modebit = payload.pkt_type == GTM_MODEBIT_MAGIC_KEY;
1185
1186 payload.bco = ((unsigned long long) gtm[2] << 0U) | ((unsigned long long) gtm[3] << 8U) | ((unsigned long long) gtm[4] << 16U) | ((unsigned long long) gtm[5] << 24U) | ((unsigned long long) gtm[6] << 32U) | (((unsigned long long) gtm[7]) << 40U);
1187 payload.lvl1_count = ((unsigned int) gtm[8] << 0U) | ((unsigned int) gtm[9] << 8U) | ((unsigned int) gtm[10] << 16U) | ((unsigned int) gtm[11] << 24U);
1188 payload.endat_count = ((unsigned int) gtm[12] << 0U) | ((unsigned int) gtm[13] << 8U) | ((unsigned int) gtm[14] << 16U) | ((unsigned int) gtm[15] << 24U);
1189 payload.last_bco = ((unsigned long long) gtm[16] << 0U) | ((unsigned long long) gtm[17] << 8U) | ((unsigned long long) gtm[18] << 16U) | ((unsigned long long) gtm[19] << 24U) | ((unsigned long long) gtm[20] << 32U) | (((unsigned long long) gtm[21]) << 40U);
1190 payload.modebits = gtm[22];
1191 payload.userbits = gtm[23];
1192
1193 if (m_verbosity >= 2)
1194 {
1195 cout << __PRETTY_FUNCTION__ << "\t- GTM data : "
1196 << "\t- pkt_type = " << payload.pkt_type << endl
1197 << "\t- is_lvl1 = " << payload.is_lvl1 << endl
1198 << "\t- is_endat = " << payload.is_endat << endl
1199 << "\t- is_modebit = " << payload.is_modebit << endl
1200 << "\t- bco = 0x" << hex << payload.bco << dec << endl
1201 << "\t- lvl1_count = " << payload.lvl1_count << endl
1202 << "\t- endat_count = " << payload.endat_count << endl
1203 << "\t- last_bco = 0x" << hex << payload.last_bco << dec << endl
1204 << "\t- modebits = 0x" << hex << (int) payload.modebits << dec << endl
1205 << "\t- userbits = 0x" << hex << (int) payload.userbits << dec << endl;
1206 }
1207
1208 if (payload.is_modebit)
1209 {
1210 if (payload.modebits == BcoMatchingInformation::ELINK_HEARTBEAT_T)
1211 {
1212 if (m_verbosity > 2)
1213 {
1214 cout << "\t- (Heartbeat modebit)" << endl;
1215 }
1216 assert(m_hNorm);
1217 m_hNorm->Fill("DMA_WORD_GTM_HEARTBEAT", 1);
1218 }
1219
1220 if (payload.modebits == BcoMatchingInformation::DC_STOP_SEND_T)
1221 {
1222 if (m_verbosity > 2)
1223 {
1224 cout << "\t- (DC stop send modebit)" << endl;
1225 }
1226 assert(m_hNorm);
1227 m_hNorm->Fill("DMA_WORD_GTM_DC_STOP_SEND", 1);
1228 }
1229 }
1230
1231 if (not(m_fastBCOSkip and (payload.is_lvl1 or payload.is_endat)))
1232 {
1233 int fee = -1;
1234 for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec)
1235 {
1236 ++fee;
1237
1238 if (m_verbosity > 2)
1239 {
1240 cout << __PRETTY_FUNCTION__ << "\t- : processing GTM data for FEE " << fee << endl;
1241 }
1242
1243 bcoMatchingInformation.save_gtm_bco_information(payload);
1244
1245 if (m_verbosity > 2)
1246 {
1247 bcoMatchingInformation.print_gtm_bco_information();
1248 }
1249 }
1250 }
1251
1252 return 0;
1253 }
1254
1255 uint16_t TpcTimeFrameBuilder::reverseBits(const uint16_t x) const
1256 {
1257 uint16_t n = x;
1258 n = (static_cast<uint16_t>(n >> 1U) & 0x55555555U) | (static_cast<uint16_t>(n << 1U) & 0xaaaaaaaaU);
1259 n = (static_cast<uint16_t>(n >> 2U) & 0x33333333U) | (static_cast<uint16_t>(n << 2U) & 0xccccccccU);
1260 n = (static_cast<uint16_t>(n >> 4U) & 0x0f0f0f0fU) | (static_cast<uint16_t>(n << 4U) & 0xf0f0f0f0U);
1261 n = (static_cast<uint16_t>(n >> 8U) & 0x00ff00ffU) | (static_cast<uint16_t>(n << 8U) & 0xff00ff00U);
1262
1263 return n;
1264 }
1265
1266 std::pair<uint16_t, uint16_t> TpcTimeFrameBuilder::crc16_parity(const uint32_t fee, const uint16_t l) const
1267 {
1268 const std::deque<uint16_t>& data_buffer = m_feeData[fee];
1269 assert(l < data_buffer.size());
1270
1271 std::deque<uint16_t>::const_iterator it = data_buffer.begin();
1272
1273 uint16_t crc = 0xffffU;
1274 uint16_t data_parity = 0U;
1275
1276 for (int i = 0; i < l; ++i, ++it)
1277 {
1278 const uint16_t& x = *it;
1279
1280 crc ^= reverseBits(x);
1281 for (uint16_t k = 0; k < 16U; k++)
1282 {
1283 crc = crc & 1U ? static_cast<uint16_t>(crc >> 1U) ^ 0xa001U : crc >> 1U;
1284 }
1285
1286
1287 if (i >= HEADER_LENGTH)
1288 {
1289
1290 uint16_t word = x & uint16_t((1U << 10U) - 1U);
1291 word = word ^ static_cast<uint16_t>(word >> 1U);
1292 word = word ^ static_cast<uint16_t>(word >> 2U);
1293 word = word ^ static_cast<uint16_t>(word >> 4U);
1294 word = word ^ static_cast<uint16_t>(word >> 8U);
1295 data_parity ^= word & 1U;
1296 }
1297 }
1298 crc = reverseBits(crc);
1299 return make_pair(crc, data_parity);
1300 }
1301
1302 namespace
1303 {
1304
1305 template <class T>
1306 std::ostream& operator<<(std::ostream& o, const std::list<T>& list)
1307 {
1308 if (list.empty())
1309 {
1310 o << "{}";
1311 }
1312 else
1313 {
1314 const bool is_hex = (o.flags() & std::ios_base::hex);
1315 o << "{ ";
1316 bool first = true;
1317 for (const auto& value : list)
1318 {
1319 if (!first)
1320 {
1321 o << ", ";
1322 }
1323 if (is_hex)
1324 {
1325 o << "0x";
1326 }
1327 o << value;
1328 first = false;
1329 }
1330 o << "\t- }";
1331 }
1332 return o;
1333 }
1334
1335 template <class T>
1336 std::ostream& operator<<(std::ostream& o, const std::vector<T>& list)
1337 {
1338 if (list.empty())
1339 {
1340 o << "{}";
1341 }
1342 else
1343 {
1344 const bool is_hex = (o.flags() & std::ios_base::hex);
1345 o << "{ ";
1346 bool first = true;
1347 for (const auto& value : list)
1348 {
1349 if (!first)
1350 {
1351 o << ", ";
1352 }
1353 if (is_hex)
1354 {
1355 o << "0x";
1356 }
1357 o << value;
1358 first = false;
1359 }
1360 o << "\t- }";
1361 }
1362 return o;
1363 }
1364
1365 }
1366
1367 TpcTimeFrameBuilder::BcoMatchingInformation::BcoMatchingInformation(const std::string& name)
1368 : m_name(name)
1369 {
1370 Fun4AllHistoManager* hm = QAHistManagerDef::getHistoManager();
1371 assert(hm);
1372
1373
1374
1375 m_hNorm = new TH1D(TString(m_name.c_str()) + "_Normalization",
1376 TString(m_name.c_str()) + " Normalization;Items;Count",
1377 20, .5, 20.5);
1378 int i = 1;
1379 m_hNorm->GetXaxis()->SetBinLabel(i++, "SyncGTM");
1380 m_hNorm->GetXaxis()->SetBinLabel(i++, "DC_STOP_SEND_GTM");
1381 m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatGTM");
1382 m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEE");
1383 m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEEMatchedReference");
1384 m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEEMatchedNew");
1385 m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEEUnMatched");
1386 m_hNorm->GetXaxis()->SetBinLabel(i++, "TriggerGTM");
1387 m_hNorm->GetXaxis()->SetBinLabel(i++, "EnDATGTM");
1388 m_hNorm->GetXaxis()->SetBinLabel(i++, "UnmatchedEnDATGTM");
1389 m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCO");
1390 m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCOMatchedExisting");
1391 m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCOMatchedNew");
1392 m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCOMatchedFailed");
1393
1394 assert(i <= 20);
1395 m_hNorm->GetXaxis()->LabelsOption("v");
1396 hm->registerHisto(m_hNorm);
1397
1398 m_hFEEClockAdjustment_MatchedReference = new TH1I(TString(m_name.c_str()) + "_FEEClockAdjustment_MatchedReference",
1399 TString(m_name.c_str()) +
1400 " FEEClockAdjustment for Matched Reference;Clock Adjustment [FEE Clock Cycle];Count",
1401 512, -256 - .5, +256 - .5);
1402 hm->registerHisto(m_hFEEClockAdjustment_MatchedReference);
1403 m_hFEEClockAdjustment_MatchedNew = new TH1I(TString(m_name.c_str()) + "_FEEClockAdjustment_MatchedNew",
1404 TString(m_name.c_str()) +
1405 " FEEClockAdjustment for Matched New;Clock Adjustment [FEE Clock Cycle];Count",
1406 512, -256 - .5, +256 - .5);
1407 hm->registerHisto(m_hFEEClockAdjustment_MatchedNew);
1408
1409 m_hFEEClockAdjustment_Unmatched = new TH1I(TString(m_name.c_str()) + "_FEEClockAdjustment_Unmatched",
1410 TString(m_name.c_str()) +
1411 " FEEClock Diff for unmatched;Clock Adjustment [FEE Clock Cycle];Count",
1412 512,
1413 -(1UL << m_FEE_CLOCK_BITS) - .5,
1414 +(1UL << m_FEE_CLOCK_BITS) - .5);
1415 hm->registerHisto(m_hFEEClockAdjustment_Unmatched);
1416
1417 m_hGTMNewEventSpacing = new TH1I(TString(m_name.c_str()) +
1418 "_GTM_NewEventSpacing",
1419 TString(m_name.c_str()) +
1420 " Spacing between two events;Clock Diff [RHIC Clock Cycle];Count",
1421 1024, -.5, +1024 - .5);
1422 hm->registerHisto(m_hGTMNewEventSpacing);
1423
1424 m_hFindGTMBCO_MatchedExisting_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedExisting_BCODiff",
1425 TString(m_name.c_str()) +
1426 " find_gtm_bco matched to existing event clock diff;Clock Difference [FEE Clock Cycle];Count",
1427 512, -256 - .5, +256 - .5);
1428 hm->registerHisto(m_hFindGTMBCO_MatchedExisting_BCODiff);
1429 m_hFindGTMBCO_MatchedNew_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedNew_BCODiff",
1430 TString(m_name.c_str()) +
1431 " find_gtm_bco matched to new event clock diff;Clock Difference [FEE Clock Cycle];Count",
1432 512, -256 - .5, +256 - .5);
1433 hm->registerHisto(m_hFindGTMBCO_MatchedNew_BCODiff);
1434 }
1435
1436
1437 bool TpcTimeFrameBuilder::BcoMatchingInformation::isMoreDataRequired(const uint64_t& gtm_bco) const
1438 {
1439 const uint64_t bco_correction = get_gtm_rollover_correction(gtm_bco);
1440
1441 if (m_verbosity>=2)
1442 {
1443 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired entry"
1444 << " at gtm_bco = 0x" << hex << gtm_bco << dec
1445 << " bco_correction = 0x" << hex << bco_correction << dec
1446 << std::endl;
1447 }
1448
1449 if (m_bco_reference)
1450 {
1451 if (m_bco_reference.value().first > bco_correction + m_max_fee_sync_time)
1452 {
1453 if (m_verbosity >= 2)
1454 {
1455 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired"
1456 << " at gtm_bco = 0x" << hex << gtm_bco << dec
1457 << ". m_bco_reference.value().first = 0x" << hex << m_bco_reference.value().first << dec
1458 << " bco_correction = 0x" << hex << bco_correction << dec
1459 << ". satisified m_max_fee_sync_time = " << m_max_fee_sync_time
1460 << std::endl;
1461 }
1462
1463 return false;
1464 }
1465 }
1466
1467 if (m_bco_reference_candidate_list.size() > 0)
1468 {
1469 if (m_bco_reference_candidate_list.back().first > bco_correction + m_max_fee_sync_time)
1470 {
1471 if (m_verbosity >= 2)
1472 {
1473 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired"
1474 << "at gtm_bco = 0x" << hex << gtm_bco << dec
1475 << ". m_bco_reference_candidate_list.back().first = 0x" << hex << m_bco_reference_candidate_list.back().first << dec
1476 << " bco_correction = 0x" << hex << bco_correction << dec
1477 << ". satisified m_max_fee_sync_time = " << m_max_fee_sync_time
1478 << std::endl;
1479 }
1480
1481 return false;
1482 }
1483 else
1484 {
1485 if (m_verbosity > 4)
1486 {
1487 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired"
1488 << "at gtm_bco = 0x" << hex << gtm_bco << dec
1489 << ". m_bco_reference_candidate_list.back().first = 0x" << hex << m_bco_reference_candidate_list.back().first << dec
1490 << " bco_correction = 0x" << hex << bco_correction << dec
1491 << ". not yet satisified m_max_fee_sync_time = " << m_max_fee_sync_time
1492 << std::endl;
1493 }
1494 }
1495 }
1496
1497 if (m_verbosity > 3)
1498 {
1499 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired"
1500 << "at gtm_bco = 0x" << hex << gtm_bco << dec
1501 << " bco_correction = 0x" << hex << bco_correction << dec << ": more data required"
1502 << " as their is NO m_bco_reference nor m_bco_reference_candidate_list"
1503 << std::endl;
1504
1505 std::cout << " m_gtm_bco_trigger_map:" << std::endl;
1506 for (const auto& trig : m_gtm_bco_trigger_map)
1507 {
1508 std::cout << " - 0x" << hex << trig.first << dec << "(Diff = " << trig.first - bco_correction << ") " << std::endl;
1509 }
1510
1511 std::cout << " m_bco_matching_list:" << std::endl;
1512 for (const auto& trig : m_bco_matching_list)
1513 {
1514 std::cout << " - 0x" << hex << trig.second << dec << "(Diff = " << trig.second - bco_correction << ") " << std::endl;
1515 }
1516 }
1517 return true;
1518 }
1519
1520
1521 std::optional<uint32_t> TpcTimeFrameBuilder::BcoMatchingInformation::get_predicted_fee_bco(uint64_t gtm_bco) const
1522 {
1523
1524 if (!is_verified())
1525 {
1526 return std::nullopt;
1527 }
1528
1529
1530 const int64_t gtm_bco_difference = int64_t(gtm_bco) - int64_t(m_bco_reference.value().first);
1531
1532 assert(m_multiplier>0);
1533
1534
1535 const int64_t fee_bco_predicted = int64_t(m_bco_reference.value().second) + int64_t(m_multiplier * gtm_bco_difference);
1536 return uint32_t(static_cast<uint64_t>(fee_bco_predicted) & 0xFFFFFU);
1537 }
1538
1539
1540 void TpcTimeFrameBuilder::BcoMatchingInformation::print_gtm_bco_information() const
1541 {
1542 if (!m_gtm_bco_trig_list.empty())
1543 {
1544 std::cout
1545 << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::print_gtm_bco_information -"
1546 << "\t- m_gtm_bco_trig_list: " << std::hex << m_gtm_bco_trig_list << std::dec
1547 << std::endl;
1548
1549
1550 if (is_verified())
1551 {
1552 std::list<uint32_t> fee_bco_predicted_list;
1553 std::transform(
1554 m_gtm_bco_trig_list.begin(),
1555 m_gtm_bco_trig_list.end(),
1556 std::back_inserter(fee_bco_predicted_list),
1557 [this](const uint64_t& gtm_bco) { return get_predicted_fee_bco(gtm_bco).value(); });
1558
1559 std::cout
1560 << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::print_gtm_bco_information -"
1561 << "\t- m_gtm_bco_trig_list fee predicted: " << std::hex << fee_bco_predicted_list << std::dec
1562 << std::endl;
1563 }
1564 }
1565
1566 std::cout <<"\t m_gtm_bco_dc_read = " << std::hex
1567 << m_gtm_bco_dc_read.first <<" -> 0x" << m_gtm_bco_dc_read.second
1568 << std::dec << std::endl;
1569 }
1570
1571 uint64_t TpcTimeFrameBuilder::BcoMatchingInformation::
1572 get_gtm_rollover_correction(const uint64_t& gtm_bco) const
1573 {
1574
1575 uint64_t gtm_bco_corrected = gtm_bco & ((uint64_t(1) << m_GTM_CLOCK_BITS) - 1);
1576
1577 if (not m_bco_reference)
1578 {
1579 return gtm_bco_corrected;
1580 }
1581
1582
1583 const uint64_t& last_bco = m_bco_reference.value().first;
1584 const uint64_t last_bco_rollover = last_bco &
1585 (std::numeric_limits<uint64_t>::max() << m_GTM_CLOCK_BITS);
1586
1587
1588 gtm_bco_corrected += last_bco_rollover;
1589
1590
1591 if (gtm_bco_corrected + (uint64_t(1) << (m_GTM_CLOCK_BITS - 1)) < last_bco)
1592 {
1593 gtm_bco_corrected += uint64_t(1) << m_GTM_CLOCK_BITS;
1594 }
1595
1596 return gtm_bco_corrected;
1597 }
1598
1599
1600 void TpcTimeFrameBuilder::BcoMatchingInformation::save_gtm_bco_information(const TpcTimeFrameBuilder::gtm_payload& gtm_tagger)
1601 {
1602
1603
1604
1605 const bool& is_lvl1 = gtm_tagger.is_lvl1;
1606 const bool& is_endat = gtm_tagger.is_endat;
1607 const bool& is_modebit = gtm_tagger.is_modebit;
1608 const uint64_t gtm_bco = get_gtm_rollover_correction(gtm_tagger.bco);
1609
1610 if (is_lvl1)
1611 {
1612 assert(m_hNorm);
1613 m_hNorm->Fill("TriggerGTM", 1);
1614
1615 assert(m_hGTMNewEventSpacing);
1616 if (not m_gtm_bco_trig_list.empty())
1617 {
1618 m_hGTMNewEventSpacing->Fill(gtm_bco - m_gtm_bco_trig_list.back());
1619 }
1620 m_gtm_bco_trig_list.push_back(gtm_bco);
1621 }
1622
1623
1624 else if (is_endat)
1625 {
1626 assert(m_hNorm);
1627 m_hNorm->Fill("EnDATGTM", 1);
1628
1629
1630 if (m_gtm_bco_trig_list.empty() || (gtm_bco - m_gtm_bco_trig_list.back()) > m_max_lv1_endat_bco_diff)
1631 {
1632 assert(m_hNorm);
1633 m_hNorm->Fill("UnmatchedEnDATGTM", 1);
1634
1635 if (not m_gtm_bco_trig_list.empty())
1636 {
1637 assert(m_hGTMNewEventSpacing);
1638 m_hGTMNewEventSpacing->Fill(gtm_bco - m_gtm_bco_trig_list.back());
1639 }
1640 m_gtm_bco_trig_list.push_back(gtm_bco);
1641 }
1642 }
1643
1644
1645 else if (is_modebit)
1646 {
1647
1648 const uint64_t& modebits = gtm_tagger.modebits;
1649 if (modebits == ELINK_HEARTBEAT_T)
1650 {
1651 assert(m_hNorm);
1652 m_hNorm->Fill("HeartBeatGTM", 1);
1653
1654 auto predicted_fee_bco = get_predicted_fee_bco(gtm_bco);
1655 if (predicted_fee_bco)
1656 {
1657 m_bco_reference_candidate_list.emplace_back(gtm_bco, predicted_fee_bco.value());
1658 }
1659 else
1660 {
1661 if (m_verbosity > 1)
1662 {
1663 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information"
1664 << "\t- Warning: predicted_fee_bco is not available for gtm_bco = 0x" << hex << gtm_bco << dec
1665 << ". Skipping heartbeat candidate." << std::endl;
1666 }
1667 }
1668
1669 if (m_verbosity > 1)
1670 {
1671 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information"
1672 << "\t- found heartbeat candidate "
1673 << "at gtm_bco = 0x" << hex << gtm_bco << dec
1674 << ". Current m_bco_reference_candidate_list:"
1675 << std::endl;
1676
1677 for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_reference_candidate_list)
1678 {
1679 std::cout << "\t- gtm_bco = 0x" << hex << bco.first << dec
1680 << "\t- fee_bco = 0x" << hex << bco.second << dec
1681 << std::endl;
1682 }
1683 }
1684
1685 while (m_bco_reference_candidate_list.size() > m_max_bco_reference_candidate_list_size)
1686 {
1687 if (m_verbosity > 1)
1688 {
1689 uint64_t bco = m_bco_reference_candidate_list.begin()->first;
1690 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_reference_from_modebits"
1691 << "Warning: m_bco_reference_candidate_list is full"
1692 << "\t- drop unprocessed heart beat in queue "
1693 << "at gtm_bco = 0x" << hex << bco
1694 << dec
1695 << ". Unprocessed heartbeats in queue with size of " << m_bco_reference_candidate_list.size()
1696 << std::endl;
1697 }
1698
1699 m_bco_reference_candidate_list.pop_front();
1700 }
1701
1702 }
1703
1704 if (modebits == BX_COUNTER_SYNC_T)
1705 {
1706 assert(m_hNorm);
1707 m_hNorm->Fill("SyncGTM", 1);
1708
1709
1710 m_verified_from_modebits = true;
1711 m_bco_reference = make_pair(gtm_bco, 0);
1712 m_bco_reference_candidate_list.clear();
1713
1714 if (m_verbosity)
1715 {
1716 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_reference_from_modebits"
1717 << "\t- found reference from modebits BX_COUNTER_SYNC_T "
1718 << "at gtm_bco = 0x" << hex << gtm_bco << dec
1719 << std::endl;
1720 }
1721 }
1722
1723 if (modebits == DC_STOP_SEND_T)
1724 {
1725 assert(m_hNorm);
1726 m_hNorm->Fill("DC_STOP_SEND_GTM", 1);
1727
1728
1729 m_gtm_bco_dc_read.first = gtm_bco;
1730 if (is_verified())
1731 {
1732 m_gtm_bco_dc_read.second = get_predicted_fee_bco(gtm_bco).value();
1733 }
1734 else
1735 {
1736 m_gtm_bco_dc_read.second = 0;
1737 }
1738
1739 if (m_verbosity > 2)
1740 {
1741 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information"
1742 << "\t- found DC stop send modebit "
1743 << "at gtm_bco = 0x" << hex << gtm_bco << dec
1744 << std::endl;
1745 }
1746 }
1747 }
1748 }
1749
1750
1751 std::optional<uint64_t> TpcTimeFrameBuilder::BcoMatchingInformation::find_reference_heartbeat(const TpcTimeFrameBuilder::fee_payload& HeartBeatPacket)
1752 {
1753 assert(m_hNorm);
1754 m_hNorm->Fill("HeartBeatFEE", 1);
1755
1756
1757 if (!is_verified())
1758 {
1759 return std::nullopt;
1760 }
1761
1762 assert(HeartBeatPacket.type == HEARTBEAT_T);
1763 const uint32_t& fee_bco = HeartBeatPacket.bx_timestamp;
1764
1765 if (m_bco_reference)
1766 {
1767 const uint64_t& gtm_bco = m_bco_reference.value().first;
1768 const uint32_t& fee_bco_predicted = m_bco_reference.value().second;
1769
1770 if (get_fee_bco_diff(fee_bco_predicted, fee_bco) < m_max_fee_bco_diff)
1771 {
1772
1773 m_bco_reference.value().second = fee_bco;
1774
1775 if (verbosity() > 1)
1776 {
1777 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found an updated reference heartbeat and updated reference clock sync: "
1778 << std::hex
1779 << "\t- fee_bco: 0x" << fee_bco
1780 << "\t- predicted: 0x" << fee_bco_predicted
1781 << "\t- gtm_bco: 0x" << gtm_bco
1782 << std::dec
1783 << std::endl;
1784 }
1785
1786 assert(m_hFEEClockAdjustment_MatchedReference);
1787 m_hFEEClockAdjustment_MatchedReference->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1);
1788
1789 m_hNorm->Fill("HeartBeatFEEMatchedReference", 1);
1790
1791 return gtm_bco;
1792 }
1793 }
1794
1795 for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_reference_candidate_list)
1796 {
1797 const uint64_t gtm_bco = bco.first;
1798 const uint32_t fee_bco_predicted = bco.second;
1799
1800
1801 if (get_fee_bco_diff(fee_bco_predicted, fee_bco) < m_max_fee_bco_diff)
1802 {
1803 if (verbosity() > 1)
1804 {
1805 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found a new reference canidate heartbeat and replaced reference clock sync: "
1806 << std::hex
1807 << "\t- fee_bco: 0x" << fee_bco
1808 << "\t- predicted: 0x" << fee_bco_predicted
1809 << "\t- gtm_bco: 0x" << gtm_bco
1810 << "\t- previous reference gtm_bco: 0x" << m_bco_reference.value().first
1811 << "\t- previous reference fee_bco: 0x" << m_bco_reference.value().second
1812 << std::dec
1813 << std::endl;
1814 }
1815
1816 m_bco_reference = make_pair(gtm_bco, fee_bco);
1817
1818 if (m_verbosity > 1)
1819 {
1820 std::cout << "\t- trimming m_bco_reference_candidate_list from size " << m_bco_reference_candidate_list.size() << std::endl;
1821
1822 for (const m_gtm_fee_bco_matching_pair_t& bco_tmp : m_bco_reference_candidate_list)
1823 {
1824 std::cout << "\t\t- gtm_bco = 0x" << hex << bco_tmp.first << dec
1825 << "\t\t- fee_bco = 0x" << hex << bco_tmp.second << dec
1826 << std::endl;
1827 }
1828 }
1829
1830
1831 while (m_bco_reference_candidate_list.begin()->first != gtm_bco)
1832 {
1833 m_bco_reference_candidate_list.pop_front();
1834 }
1835 m_bco_reference_candidate_list.pop_front();
1836
1837 if (m_verbosity > 1)
1838 {
1839 std::cout << "\t- to size " << m_bco_reference_candidate_list.size() << std::endl;
1840
1841 for (const m_gtm_fee_bco_matching_pair_t& bco_tmp : m_bco_reference_candidate_list)
1842 {
1843 std::cout << "\t\t- gtm_bco = 0x" << hex << bco_tmp.first << dec
1844 << "\t\t- fee_bco = 0x" << hex << bco_tmp.second << dec
1845 << std::endl;
1846 }
1847 }
1848
1849 assert(m_hFEEClockAdjustment_MatchedNew);
1850 m_hFEEClockAdjustment_MatchedNew->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1);
1851
1852 m_hNorm->Fill("HeartBeatFEEMatchedNew", 1);
1853 return gtm_bco;
1854 }
1855
1856 if (verbosity() > 1)
1857 {
1858 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - unmatched heartbeat: "
1859 << std::hex
1860 << "\t- fee_bco: 0x" << fee_bco
1861 << "\t- predicted: 0x" << fee_bco_predicted
1862 << "\t- gtm_bco: 0x" << gtm_bco
1863 << std::dec
1864 << std::endl;
1865 }
1866
1867 assert(m_hFEEClockAdjustment_Unmatched);
1868 m_hFEEClockAdjustment_Unmatched->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1);
1869 }
1870
1871 if (verbosity() > 1)
1872 {
1873 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - WARNING: failed match for fee_bco = 0x" << hex << fee_bco << dec << std::endl;
1874 }
1875 m_hNorm->Fill("HeartBeatFEEUnMatched", 1);
1876 return std::nullopt;
1877 }
1878
1879
1880 std::optional<uint64_t> TpcTimeFrameBuilder::BcoMatchingInformation::find_gtm_bco(uint32_t fee_bco)
1881 {
1882 if (verbosity() > 5)
1883 {
1884 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - entry: "
1885 << std::hex
1886 << "\t- fee_bco: 0x" << fee_bco
1887 << std::dec
1888 << "\t- is_verified(): " << (is_verified() ? "true" : "false")
1889 << std::endl;
1890 }
1891
1892
1893 if (!is_verified())
1894 {
1895 return std::nullopt;
1896 }
1897
1898 assert(m_hNorm);
1899 m_hNorm->Fill("FindGTMBCO", 1);
1900
1901
1902 const auto bco_matching_iter = std::find_if(
1903 m_bco_matching_list.begin(),
1904 m_bco_matching_list.end(),
1905 [fee_bco](const m_fee_gtm_bco_matching_pair_t& pair) { return get_fee_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; });
1906
1907 if (bco_matching_iter != m_bco_matching_list.end())
1908 {
1909 m_hNorm->Fill("FindGTMBCOMatchedExisting", 1);
1910 assert(m_hFindGTMBCO_MatchedExisting_BCODiff);
1911 m_hFindGTMBCO_MatchedExisting_BCODiff->Fill(int64_t(fee_bco) - int64_t(bco_matching_iter->first));
1912
1913 if (verbosity() > 3)
1914 {
1915 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - found existing FEE BCO: "
1916 << std::hex
1917 << "\t- fee_bco: 0x" << fee_bco
1918 << "\t- predicted: 0x" << bco_matching_iter->first
1919 << "\t- gtm_bco: 0x" << bco_matching_iter->second
1920 << std::dec
1921 << std::endl;
1922 }
1923
1924 return bco_matching_iter->second;
1925 }
1926 else
1927 {
1928
1929 const auto iter = std::find_if(
1930 m_gtm_bco_trig_list.begin(),
1931 m_gtm_bco_trig_list.end(),
1932 [this, fee_bco](const uint64_t& gtm_bco) { return get_fee_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; });
1933
1934
1935 if (iter != m_gtm_bco_trig_list.end())
1936 {
1937 const uint64_t gtm_bco = *iter;
1938
1939 m_hNorm->Fill("FindGTMBCOMatchedNew", 1);
1940 assert(m_hFindGTMBCO_MatchedNew_BCODiff);
1941 m_hFindGTMBCO_MatchedNew_BCODiff->Fill(int64_t(fee_bco) - int64_t(gtm_bco));
1942
1943 if (verbosity() > 2)
1944 {
1945 const uint32_t fee_bco_predicted = get_predicted_fee_bco(gtm_bco).value();
1946 const uint32_t fee_bco_diff = get_bco_diff(fee_bco_predicted, fee_bco);
1947
1948 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - new GL1 match: "
1949 << std::hex
1950 << "\t- fee_bco: 0x" << fee_bco
1951 << "\t- predicted: 0x" << fee_bco_predicted
1952 << "\t- gtm_bco: 0x" << gtm_bco
1953 << std::dec
1954 << "\t- difference: " << fee_bco_diff
1955 << std::endl;
1956 }
1957
1958
1959 m_bco_matching_list.emplace_back(fee_bco, gtm_bco);
1960
1961
1962 m_gtm_bco_trig_list.erase(iter);
1963
1964
1965
1966
1967 return gtm_bco;
1968 }
1969 else
1970 {
1971 m_hNorm->Fill("FindGTMBCOMatchedFailed", 1);
1972
1973 bool new_orphan = m_orphans.insert(fee_bco).second;
1974
1975 if ((new_orphan and verbosity()) or (verbosity() > 3))
1976 {
1977
1978 const auto iter2 = std::min_element(
1979 m_gtm_bco_trig_list.begin(),
1980 m_gtm_bco_trig_list.end(),
1981 [this, fee_bco](const uint64_t& first, const uint64_t& second) { return get_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); });
1982
1983 const int fee_bco_diff = (iter2 != m_gtm_bco_trig_list.end()) ? get_bco_diff(get_predicted_fee_bco(*iter2).value(), fee_bco) : -1;
1984
1985 if (m_verbosity >=2)
1986 {
1987 std::cout << "TpcTimeFrameBuilder[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - match failed!"
1988 << std::hex
1989 << "\t- fee_bco: 0x" << fee_bco
1990 << std::dec
1991 << "\t- gtm_bco: 0x" << *iter2
1992 << "\t- difference: " << fee_bco_diff
1993 << std::endl;
1994 }
1995 }
1996
1997 if (verbosity() > 3)
1998 {
1999 std::cout << "\t- m_gtm_bco_trig_list : " << std::endl;
2000 for (const auto& gtm_bco : m_gtm_bco_trig_list)
2001 {
2002 std::cout << "\t\t- 0x" << hex << gtm_bco << " -> 0x" << get_predicted_fee_bco(gtm_bco).value() << dec << std::endl;
2003 }
2004
2005 std::cout << "\t- m_bco_matching_list : " << std::endl;
2006 for (const auto& iter_m_bco_matching_list : m_bco_matching_list)
2007 {
2008 std::cout << "\t\t- 0x" << hex << iter_m_bco_matching_list.first << " -> 0x" << iter_m_bco_matching_list.second << dec << std::endl;
2009 }
2010
2011 }
2012
2013 return std::nullopt;
2014 }
2015 }
2016
2017
2018 return std::nullopt;
2019 }
2020
2021
2022 void TpcTimeFrameBuilder::BcoMatchingInformation::cleanup()
2023 {
2024
2025 while (m_gtm_bco_trig_list.size() > m_max_matching_data_size)
2026 {
2027 m_gtm_bco_trig_list.pop_front();
2028 }
2029 while (m_bco_matching_list.size() > m_max_matching_data_size)
2030 {
2031 m_bco_matching_list.pop_front();
2032 }
2033
2034
2035 m_orphans.clear();
2036 }
2037
2038
2039 void TpcTimeFrameBuilder::BcoMatchingInformation::cleanup(uint64_t ref_bco)
2040 {
2041
2042 m_gtm_bco_trig_list.erase(std::remove_if(m_gtm_bco_trig_list.begin(), m_gtm_bco_trig_list.end(),
2043 [ref_bco](const uint64_t& bco) { return bco <= ref_bco; }),
2044 m_gtm_bco_trig_list.end());
2045
2046
2047 m_bco_matching_list.erase(std::remove_if(m_bco_matching_list.begin(), m_bco_matching_list.end(),
2048 [ref_bco](const m_fee_gtm_bco_matching_pair_t& pair) {
2049 return pair.second <= ref_bco;
2050 }),
2051 m_bco_matching_list.end());
2052
2053
2054 m_orphans.clear();
2055 }